diff --git a/BUILD-LOG.md b/BUILD-LOG.md index 85e690be0..6ab227bd0 100644 --- a/BUILD-LOG.md +++ b/BUILD-LOG.md @@ -6298,3 +6298,4 @@ R5 quote fallback room (#797 D3, 2026-11-06, MVP3 lead): r4 review P2 found that 2026-11-06 UTC | #797 stall-guard review fix round | Before: managed stdout added or omitted bytes relative to adapter text mode, a signalled child lost its exit-137/stderr receipt, and no-route incurred the instance-running cooldown. After: adapter-specific byte rendering, a fixed signal-name diagnostic and signal exit status, and a 30-second cooldown only for instance-running; no-route can be retried after the route is set. New regression controls fail on 3e754c96a; real local-API adapter comparisons and owned-child death receipts match base behavior. Node 26 harness rerun 270/270; CLI whole-file coverage 1,197 pass and one existing federation skip after two whole-file reruns (one known timing flake and one interim stdout-fallback regression, both rerun green); isolated release 251/251 and gate-lane 61/61. The managed-session copies pass 20/20; all six real guard scenarios pass. Bus project-files independently reproduces the reviewed base hang under an external timeout. Initial namespace-only project-files attempt hit interpreter-unsafe; corrected ordinary-user run retained. Queue refused linked worktree; no push, deploy, model calls, live host, secret, policy, role, contract or schema changes. Exact evidence and remaining review boundary: /mnt/storage/scratch/mosaic-lead/mvp3/stall-guard-r2-report.md. 2026-11-06 UTC | #797 stall-guard integration merge | Before: stall-guard tip 6b2c925b9 and integration 5255e4e74 each supplied a Claude activity route; managed Pi also had two potential marker producers. After: BASE's Claude stream helper is authoritative, the Pi monitor is retained and its extension duplicate is disabled for managed turns, runner metadata suppression and newline filtering coexist, instance-running-only cooldown remains, and known/unknown child-signal receipts survive on both paths. Claude empty-delta handling follows BASE's selected helper; helper SHA pin updated. Node 26 final harness 309 pass, CLI main/lane/release 885/61/251 pass with one FED R7 skip, separately verified guard E2Es 11 pass, bus excluding project-files 1615 pass. Bus project-files had 5 pass then timeout/cancellation on both candidate and exact BASE; gate is not green. One earlier harness run failed the known Claude row-66 timing assertion (exact BASE full harness 277/277 and two file runs 14/14; older-base reproduction recorded by prior review); final rerun passed. An initial signal test invoked the removed Claude monitor and was adapted. Queue refused linked worktree; canonical queue read returned nothing. Local merge candidate only, no push or deployment. Full counts, caveats and evidence: /mnt/storage/scratch/mosaic-lead/mvp3/stall-guard-int-report.md and stall-guard-int-evidence/. +2026-11-06 UTC | #797 supervisor schema guard implementation | Before: the 3s-only accounting guard refused the 3t archive store. After: the lead-authorized closed 3s/3t fallback preserves 3s compatibility and accepts 3t; store.mjs performs load-time file reads and in-memory schema/migration execution, so it is not imported into the supervisor. The real-Store current-version regression failed on BASE with test-store-schema-refused; synthetic 3s accepts, 3r/3u/missing refuse. DDL diff adds only project_archives objects. README documents owner diagnosis and restoration or campaign end without reset. Sequential Node 26 whole-file gates: budget 102/0, isolated identity 8/0, browser 13/0, lifecycle 2/0; no skips. Evidence: /mnt/storage/scratch/mosaic-lead/mvp3/supervisor-3t-evidence/; local candidate for independent review, no push or deployment. diff --git a/docs/SESSIONS.md b/docs/SESSIONS.md index 0976dbb0e..bac378c2a 100644 --- a/docs/SESSIONS.md +++ b/docs/SESSIONS.md @@ -2095,3 +2095,4 @@ are never rewritten or removed; corrections are new entries. 2026-11-06 UTC | ui797 stall-guard implementation sub-agent | #797 two fixes on feat/ui797-stall-guard from 5df42478b | Adapter event monitoring for first model output and typed launch refusal backoff, with base/fix evidence and package gates under /mnt/storage/scratch/mosaic-lead/mvp3/stall-guard-evidence/; linked-worktree queue refused. Local commits authorized; independent review pending. No push, stash, protected host, live-instance, role, policy, schema or config change. Report: /mnt/storage/scratch/mosaic-lead/mvp3/stall-guard-report.md. 2026-11-06 UTC | ui797 stall-guard review-fix implementation sub-agent | #797 three corrections on feat/ui797-stall-guard-r2 from 3e754c96a | Adapter stdout parity, signal-specific child-death receipts, instance-running-only cooldown; Node 26 gates and negative controls recorded in /mnt/storage/scratch/mosaic-lead/mvp3/stall-guard-r2-report.md. Local commits only; queue refused linked worktree; independent review pending. No push, merge, deployment, live-host contact, model call, secret, role, policy, contract or schema changes. 2026-11-06 UTC | ui797 stall-guard integration implementation sub-agent | #797 integration of 5255e4e74 into 6b2c925b9 | Reconciled Claude/Pi activity sources, retained cooldown and signal receipts; final Node 26 harness 309 pass, CLI 1197 pass/1 base-reproduced skip, six guard E2Es within 11 pass, bus 1615 pass plus project-files 5 pass/1 timeout also on exact BASE; earlier row-66 timing failure and all comparisons retained. Local merge candidate for independent review; no push, deployment, real model call or protected-host contact. Report: /mnt/storage/scratch/mosaic-lead/mvp3/stall-guard-int-report.md. +2026-11-06 UTC | supervisor-3t implementation sub-agent | #797 closed 3s/3t supervisor guard and recovery guidance above 37f38d8e1 | Real-store regression red on BASE; sequential whole-file gates 125 pass, 0 fail/skip, evidence in /mnt/storage/scratch/mosaic-lead/mvp3/supervisor-3t-evidence/. Queue refused linked worktree; one local commit for independent review, no push, deployment or live access. diff --git a/packages/cli/live/README.md b/packages/cli/live/README.md index cde44c01f..8d53c7a87 100644 --- a/packages/cli/live/README.md +++ b/packages/cli/live/README.md @@ -296,6 +296,12 @@ An existing or uncreatable lock prevents accounting and still asserts the sticky halt against the verified ui797 binding on every check/serve tick. The lock is preserved, including when a stop was already latched. A changed target config refuses rather than halting an unverified data root. +On `campaign-instance-changed`, the owner must diagnose the campaign's pin, +binding (including root and store identity), config bytes and ledger target against +the original evidence. Restore the original files and target identities if they +can be verified, or end the campaign; there is no supported retarget or recovery +command. Never reinitialize, reset or raise the existing campaign, or auto-reclaim +its lock. A refused target is not proof of a halt or quiescence. At any cap, deadline or accounting refusal, the supervisor fsyncs `stop.json` before invoking the existing `mosaic halt --business ... --json` production CLI diff --git a/packages/cli/live/budget-supervisor.mjs b/packages/cli/live/budget-supervisor.mjs index 554c983ef..e09bdac9f 100644 --- a/packages/cli/live/budget-supervisor.mjs +++ b/packages/cli/live/budget-supervisor.mjs @@ -74,7 +74,7 @@ export function readAccounting({ dataRoot,business,start,end }) { const db = new DatabaseSync(join(dataRoot,'bus/bus.sqlite'),{readOnly:true}); try { db.exec('BEGIN'); - if (db.prepare("SELECT value FROM meta WHERE key='schema_version'").get()?.value !== '3s') fail('test-store-schema-refused'); + if (!['3s','3t'].includes(db.prepare("SELECT value FROM meta WHERE key='schema_version'").get()?.value)) fail('test-store-schema-refused'); const store = { all:(sql,...args) => db.prepare(sql).all(...args) }; const records = turnRecords(store,business); const raw = store.all("SELECT * FROM usage_records WHERE business=? AND source<>'@proxy/cliproxy-queue' ORDER BY seq",business); diff --git a/packages/cli/live/budget-supervisor.test.mjs b/packages/cli/live/budget-supervisor.test.mjs index 2eed97167..85e128023 100644 --- a/packages/cli/live/budget-supervisor.test.mjs +++ b/packages/cli/live/budget-supervisor.test.mjs @@ -7,7 +7,7 @@ import { once } from 'node:events'; import { join } from 'node:path'; import { initialize,check,status,readAccounting,supportedHalt,main,serveBudget,CUTOFF } from './budget-supervisor.mjs'; import { fixture,closeChild } from './test-support.mjs'; -import { Store } from '../../bus/src/store.mjs'; +import { Store,SCHEMA_VERSION } from '../../bus/src/store.mjs'; const NOW=Date.parse('2026-11-06T02:30:00.000Z'); const row=(extra={})=>({at:'2026-11-06T02:29:00.000Z',run:'r123456789abc',turn:'t1',source:'transcript',instance:'assistant',provider:'proxy',route:'glm',model:'glm-5.3-flash',status:'known',input:1,output:1,cacheWrite:1,cacheRead:1,...extra}); function setup(t,tokens=5,changes={}) { @@ -73,6 +73,22 @@ function insert(f,phase='end',status='known',source='transcript') { const manifest=join(f.dataRoot,'launches',f.c.business,row().run,'bundle');mkdirSync(manifest,{recursive:true,mode:0o700}); writeFileSync(join(manifest,'manifest.json'),JSON.stringify({business:f.c.business,run:row().run,instance:'assistant',provider:'proxy',model:'glm-5.3-flash',proxyRoute:'glm',route:'primary'}),{mode:0o600}); } +test('accounting reads a real store at the current bus schema version',t=>{ + const f=setup(t,100);insert(f); + assert.equal(f.store.get("SELECT value FROM meta WHERE key='schema_version'").value,SCHEMA_VERSION); + const records=readAccounting({dataRoot:f.dataRoot,business:f.c.business,start:f.c.start,end:f.c.end}); + assert.equal(records.length,1);assert.equal(records[0].input,1); +}); +for(const version of ['3s','3r','3u',null]) test(`accounting ${version==='3s'?'accepts':'refuses'} schema ${version??'missing'}`,t=>{ + const f=setup(t,100); + // Only this disposable fixture is altered; the production meta table is append-only. + f.store.run('DROP TRIGGER meta_no_update');f.store.run('DROP TRIGGER meta_no_delete'); + if(version===null) f.store.run("DELETE FROM meta WHERE key='schema_version'"); + else f.store.run("UPDATE meta SET value=? WHERE key='schema_version'",version); + const read=()=>readAccounting({dataRoot:f.dataRoot,business:f.c.business,start:f.c.start,end:f.c.end}); + if(version==='3s') assert.deepEqual(read(),[]); + else assert.throws(read,/^Error: test-store-schema-refused$/); +}); test('actual read-only bus store source matches token-limit records and excludes proxy telemetry',async t=>{ const f=setup(t,100);insert(f);insert(f,'end','known','@proxy/cliproxy-queue'); const r=readAccounting({dataRoot:f.dataRoot,business:f.c.business,start:f.c.start,end:f.c.end});assert.equal(r.length,1);assert.equal(r[0].route,'glm');