From a9e86811fee4d92880d7007ceb179cb29eaf8bdd Mon Sep 17 00:00:00 2001 From: Bacsystem Solutions EIRL Date: Tue, 21 Jul 2026 07:35:25 -0500 Subject: [PATCH 01/11] fix(review-package): raise git execFileSync maxBuffer to 1GB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Default Node execFileSync buffer (1MB) is too small for a real diff package spanning many files (hit during the bs-inventory pilot's Task 13, a 207-file MUI Premium/Pro removal) — git commands would throw ENOBUFS/maxBuffer exceeded instead of returning the diff. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_0145sjAtP5b5kvhR1XCgg3K3 --- bin/review-package.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/review-package.js b/bin/review-package.js index a0dc66f..5719d75 100644 --- a/bin/review-package.js +++ b/bin/review-package.js @@ -12,7 +12,7 @@ if (!repoPath || !baseSha || !headSha || !outDir) { // execFile (sin shell) con -C: los SHAs y rutas llegan de otros agentes — nada se // interpola en una línea de shell. function git(...args) { - return execFileSync('git', ['-C', repoPath, ...args], { encoding: 'utf8' }); + return execFileSync('git', ['-C', repoPath, ...args], { encoding: 'utf8', maxBuffer: 1024 * 1024 * 1024 }); } let commits, stat, diff; From c30f69dee5e64380380608b999863934c251d58b Mon Sep 17 00:00:00 2001 From: Bacsystem Solutions EIRL Date: Tue, 21 Jul 2026 07:35:46 -0500 Subject: [PATCH 02/11] fix(state): ask the state/ledger agents to verify, not just assert MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 2026-07-18 fix for the safety-classifier blocking state-write calls ("frame the content as already-verified bookkeeping") turned out not to resolve the problem — it's exactly that framing that kept getting flagged as Instruction Poisoning across two real bs-inventory pilot runs (2026-07-20/21). An isolated agent with no memory of the run has no way to confirm "trust me, this already happened," which reads exactly like an injection attempt. Evidence from those same runs: agents that independently verified against real repo state (git log, task reports) before writing passed the classifier without issue. So writeState()/deleteState()/ appendLedger() now instruct the agent to verify the content against the actual repo (git log, git merge-base, .cys/task--report.md) before writing, with an explicit "don't write, report the discrepancy instead" escape hatch if verification fails — turning the task from "copy this claim" into "verify and record," which is the pattern that already worked in practice. Full context in .cys/pending.md (reopened the 2026-07-18 entry rather than filing a new one). Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_0145sjAtP5b5kvhR1XCgg3K3 --- tests/build-workflow.test.js | 23 +++++++++-- .../parallel-plan-executor.template.js | 41 ++++++++++++------- workflows/parallel-plan-executor.js | 41 ++++++++++++------- 3 files changed, 74 insertions(+), 31 deletions(-) diff --git a/tests/build-workflow.test.js b/tests/build-workflow.test.js index fa62159..cd90ce9 100644 --- a/tests/build-workflow.test.js +++ b/tests/build-workflow.test.js @@ -315,10 +315,27 @@ test('built workflow tags .cys/state.json writes with their own phase, not Merge ); }); -test('built workflow frames the state-write prompt as verified bookkeeping, not new claims (safety-classifier block, pending.md bug)', () => { +test('built workflow instructs the state-write agent to verify against real repo state, not just assert the content is true (safety-classifier block, pending.md bug reopened 2026-07-21)', () => { + const writeStateIndex = output.indexOf('function writeState()'); + assert.ok(writeStateIndex >= 0, 'debe existir writeState()'); + const writeStateBody = output.slice(writeStateIndex, writeStateIndex + 1600); + assert.ok( + writeStateBody.includes('independently verify') && writeStateBody.includes('git log') && writeStateBody.includes('git merge-base'), + 'la primera corrección (afirmarle al agente "esto ya es verdad, escríbelo") seguía siendo bloqueada por el clasificador en corridas reales — el prompt debe pedirle al agente que verifique el contenido contra el repo real antes de escribir, no solo confiar en la afirmación' + ); + assert.ok( + writeStateBody.includes('do not write the file') || writeStateBody.includes("don't write the file"), + 'el agente debe tener una salida explícita para cuando la verificación falla, en vez de escribir igual' + ); +}); + +test('built workflow instructs the ledger-append agent to spot-check the line against real evidence before appending (safety-classifier block, pending.md bug reopened 2026-07-21)', () => { + const appendLedgerIndex = output.indexOf('function appendLedger('); + assert.ok(appendLedgerIndex >= 0, 'debe existir appendLedger()'); + const appendLedgerBody = output.slice(appendLedgerIndex, appendLedgerIndex + 1200); assert.ok( - output.includes('bookkeeping snapshot') && output.includes('already completed and verified earlier in this same run'), - 'sin este framing, el clasificador de seguridad puede leer un JSON con status "done" y SHAs reales como una fabricación en vez de un registro legítimo de resultados ya verificados' + appendLedgerBody.includes('spot-check') && appendLedgerBody.includes('git log'), + 'el agente de ledger debe verificar las afirmaciones de la línea contra evidencia real (git log, reportes) antes de agregarla, no solo confiar en el texto que le pasaron' ); }); diff --git a/workflows-src/parallel-plan-executor.template.js b/workflows-src/parallel-plan-executor.template.js index 2902501..c71b71c 100644 --- a/workflows-src/parallel-plan-executor.template.js +++ b/workflows-src/parallel-plan-executor.template.js @@ -39,23 +39,29 @@ function stateJson() { function writeState() { return enqueueMainRepo(() => agent( - `Run \`date +%H:%M:%S\` first to get the current time. In repo ${repoPath}, write to ` + - `.cys/state.json (create the file and its directory if missing, overwriting anything ` + - `already there) the content between the tags below, but with ` + - `"updatedAt": "