diff --git a/BUILD-LOG.md b/BUILD-LOG.md index d57570f63..e06927829 100644 --- a/BUILD-LOG.md +++ b/BUILD-LOG.md @@ -5497,3 +5497,5 @@ claim. Receipts and limitations in agents/lena/work/queue-296/BUILD.md and run-r 2026-10-23 | Beakley (88b97f65) | Row 217 #1718 untested draft checkpoint | Continued Launchpad e25ef0373; added runner retry/text/note implementation, pure protocol constants and sage-3640 approved single read-only mount, CLI documentation and new acceptance test files. Static checks caught missing projects compatibility, async request mutation and Git pathspec matching; bounded fixes and regression tests authored. git diff --check clean. No Node/test/mutant executed; Sage holds CLEAR. 283/216/285 dependency checks and all acceptance execution remain open. Packet agents/beakley/work/queue-217/MANIFEST.md. 2026-10-23 | Beakley (88b97f65) | Row 217 early-look follow-up, Untested | Webby 0939c0682 E1 adds ordinary mallory human-swap test; E2 adds stored trailer-derived agent/file event evidence; E6 creative-sender matrix and E7 runtime readRaw tests authored. Sage-3668/3670 accepts direct writer substitution because setter keys exclude replyLimits (organization.set exists, correcting review premise), and requires distinct availability refusal for E4. Real held-lock/socket and runner-reason regressions plus M5 authored before that production fix; expected RED awaits Sage CLEAR. No Node/tests/mutants, no old-test edits, no green claim. + +2026-10-24 | Beakley (88b97f65) | Row 217 round 2, sage-4037 | Rebased published dde5b8496 onto e0c6142f3 on new beakley/row217-r2; both append-log histories retained. Conflicts preserve landed grant dispatch, revocation hook and lookup exports. Added E4 citation-unavailable product path and real supporting-scope/index comparison tests after row283 8d2856ee3. Untested: no Node/npm/tests/mutants/build; ready for Sage CLEAR after Lena296. Full range-diff and honest discarded local rebase correction in agents/beakley/work/queue-217/BUILD.md. diff --git a/agents/beakley/work/queue-217/BUILD.md b/agents/beakley/work/queue-217/BUILD.md index af94ba327..ef6af55c8 100644 --- a/agents/beakley/work/queue-217/BUILD.md +++ b/agents/beakley/work/queue-217/BUILD.md @@ -155,3 +155,69 @@ No Node, tests or mutants ran. No test that predated row 217 changed. ## Webby follow-up 192049c98 / webby-0258 E1, E2, E6 and E7 closed statically; no executed acceptance claimed. E3 correction and E5 limitation accepted. E4 tests accepted statically; real RED then production fix/green remain on hold for Sage CLEAR, with supporting scope waiting on 283. F1: citation-helpers status now uses its mutable served value, matching guard/last after setServed instead of reporting the original fixture commit. Test-only fixture correction, unrun. manifest.r3.sha256 records the updated helper; no production or old-test changes. + + +## Round 2 / sage-4037 — 2026-10-24, Untested + +New branch `beakley/row217-r2` from published `dde5b8496`, rebased exactly onto +`origin/refactor` at `e0c6142f3` (109 upstream commits since `45dca69f6`). The +published original branch is unchanged; no amend or force-push. The replayed +four commits are b9ef816ff, 7400509ba, a447880cb, 2655ec010. Full range-diff: +`rebase-r2.range-diff.txt`. Last commit is `=`, the first three are `!` from +conflict context/indentation and append-log placement described below. + +Conflict resolutions: +- broker.mjs: retained landed grants.scope/grants.scope.set dispatch and added + library.limits.set to the organization verb dispatch; neither path removed. +- runtime.mjs: retained grants.scope.set and added library.limits.set alongside + it; retained query/sync wiring and all new base lifecycle behavior. +- organization.mjs: retained row 239's beforeWrite/revoked wrapper, placing both + M11 fences before validations/revocation as on the old candidate. A refused + reply-limit write cannot invoke beforeWrite. +- library/index.mjs: retained C2-05a buildIndex/query exports and added the guard + and reply-limits exports. +- BUILD-LOG.md and docs/SESSIONS.md: retained upstream appends followed by all + Beakley appends. Static byte-prefix checks prove the entire e0c6142f3 log + histories survive; all original Beakley entries also survive. +- business.mjs, cli README and sandbox.mjs auto-merged. Static diff against the + target confirms only this row's TOP_KEYS addition, README paragraph and one + import-free protocol mount; landed supporting scope and room-address mount + remain intact. runtime diff contains only the approved import, injected + guard/limits/last adapters and setter dispatch, now beside grants.scope.set. + +Correction recorded honestly: the first unpublished rebase attempt used an +unbounded marker regex that removed code after a conflict. The diff stat caught +it immediately; aborted the rebase and repeated with bounded markers. No result +from that discarded attempt was pushed. The successful first replay matches the +original 589 insertions/20 deletions; no broad deletions remain. + +Implemented E4 under sage-4037's explicit direction to make the product fix +while keeping all tests unrun. This supersedes the earlier planned RED-first +execution order; no RED or green has been observed. The existing regression +cases predate the fix. GUARD_CODES now includes citation-unavailable. Only a +mirror confirmed absent by lstat, or readSyncState's legitimate empty state, +yields no served commit. Other read/lock/metadata errors give the fixed safe +reason: "The library is busy or unavailable. Retry the answer when the library +is available." The runner receives it through BusError.reason and includes it +in its one retry request. The existing four fallback bodies remain. Plain, +web-only and fixed replies require no mirror read, so a busy mirror cannot +block the runner's fixed fallback. M5's real production anchor now exists. + +Supporting scope after row 283 (`8d2856ee3`): added two broker tests using real +mapping/reader classification, not a scope stub. A path in both supporting and +playground refuses as canon; an agent-committed supporting path stores +scope=supporting, agent=acme/scribe and its file commit in message.checked. + +C2-05a comparison: index-build.mjs builds its file map directly from readLibrary +files; indexFor calls that same reader at the requested commit. Added a real +fixture test comparing the index set, readLibrary set and libraryReader.lines +admission, including supporting, unmapped Markdown and .canvas. This comparison +is authored and statically traced, not executed; numerical results wait on CLEAR. + +Current packet: manifest.r4.sha256, relative to e0c6142f3. No test file already +present at that base was edited. No Node, npm, tests, mutants or webui build run. +Ready for CLEAR after Lena's row 296. On CLEAR, install with npm ci +--ignore-scripts --no-audit --no-fund in THIS worktree root and packages/webui; +never link to canonical node_modules or run npm/rm in the canonical checkout. +Use short mktemp TMPDIR and timeout -k 10. Any old-test red goes to Sage before +an edit. Full green gate, mutants and Webby verdict remain outstanding. diff --git a/agents/beakley/work/queue-217/MANIFEST.md b/agents/beakley/work/queue-217/MANIFEST.md index b5a6670b5..03f03399e 100644 --- a/agents/beakley/work/queue-217/MANIFEST.md +++ b/agents/beakley/work/queue-217/MANIFEST.md @@ -66,3 +66,22 @@ availability case are intentionally unrun regressions for E4/sage-3668/3670. Production availability handling is not implemented yet: run that targeted RED on CLEAR before applying its fix, then rerun the same cases. M5 restores the catch-all. This packet is not ready for a green gate or manifest approval. + + +## Round 2 on e0c6142f3 (manifest.r4.sha256) — Untested + +New branch beakley/row217-r2 preserves the old published branch. Conflict +resolutions and complete range-diff are in BUILD.md/rebase-r2.range-diff.txt. +The E4 fix adds citation-unavailable for non-absence mirror/state/lock failures; +the runner gets the fixed safe reason through the existing optional reason field +and uses its single retry. No fifth fallback body or SQL change. Replies without +library cites bypass mirror reads, preserving fallback delivery during contention. +The prior E4 regressions and M5 have not run. Sage-4037 explicitly authorizes +this untested implementation before the test window. + +Supporting tests now use row 283's real supporting classification and assert +canon refusal plus stored supporting/agent evidence. An index-set comparison +test now uses the landed C2-05a index. No base test was edited. Before acceptance, +run the approved new tests and required suites/mutants under Sage CLEAR. npm ci +must create worktree-local installs at root and packages/webui, never canonical +links. The candidate is ready for CLEAR; no passing behavior is claimed. diff --git a/agents/beakley/work/queue-217/manifest.r4.sha256 b/agents/beakley/work/queue-217/manifest.r4.sha256 new file mode 100644 index 000000000..86d0ce048 --- /dev/null +++ b/agents/beakley/work/queue-217/manifest.r4.sha256 @@ -0,0 +1,23 @@ +eeca81ab965f9e94f930ee5f51d16f019af6368bc6c3994895e204f7a54ec8d2 packages/bus/src/broker.mjs +ad3c686a089f67f3c89610937c6fc9b32367cea5d9735125d89bef042082d4e8 packages/bus/src/client.mjs +36b05dd3119e5929211aa1cc5d45c5043f5a1c34567ddc7cac8f002835d44abe packages/bus/src/runtime.mjs +66b26d131a19f4f411686427274936850c1ff0aed11e9b281ae4aadcf4b289fc packages/bus/src/server.mjs +cdd0304ec25ef1ad3e31c52502fa46f2c80bd77c8d3c2e13f8ed4b5328f342c9 packages/bus/tests/citation-availability.test.mjs +2e05074cd9d15d810103658af3858161cee2af78b0a2e1ba910222fab3e84401 packages/bus/tests/citation-guard.test.mjs +2c7a2102e2e0244876e41b664f4f706baefe3375100b956655551db1230f5da3 packages/bus/tests/citation-helpers.mjs +168dcac99d9bfdfdf5ff0eaa2c0fff91595b351b4d0092dc299532c9c32869f0 packages/bus/tests/citation-runtime.test.mjs +abaeac64f2c3bf8ba83c9a4488edd9105c4707a6564560c5333d5421445653af packages/business/src/business.mjs +3a6044de5d1ca2cc35c5285b460c3e402b4274837e5d88b97f489797f6004903 packages/business/src/organization.mjs +4d2eb11beaa80175e524af1b95c81e7164990fba1d3e1754f5ba06eee390a14f packages/business/tests/reply-limits.test.mjs +a2bb98734bcc2556f8b2168f0faf8a89f7064c3f0aa49feb7d1975d596192f09 packages/cli/README.md +2f291a71f490f2741edada7a3e3788500f8976a08eb8ab1411f6c5982f778260 packages/cli/src/limits.mjs +f38af2d46d5f5f6388f599912507b94b87a0bf9dcc2104bb2187c38ee35118d5 packages/cli/tests/reply-limits.test.mjs +6ad72b4245e0a66e32725941900c1ece64c2e5de2fb73d65c8e042b4f3a691a6 packages/harness/src/runner.mjs +a5ef1b65230239a7baf6d0e8f2b8a51c0516348c7c4339a55b3f0a1a6ff531ba packages/harness/tests/citation-runner.test.mjs +330bc71bf6c7e64d3ddb70440903d2d9acf7878d44a49d7e30c2352ee4c807ec packages/harness/tests/fixtures/citation-adapter.mjs +f710d9600a17f6e2989a289cfe84e58f161d86c7306605946ce05fa71b364eb2 packages/library/src/guard.mjs +c0d630798914e300e461c247340533328e97119e54909c6a9406340e61fed8b7 packages/library/src/index.mjs +3e04fa25a64334d33ffbec704205b32cd01992f2d341e908f933a345199beee0 packages/library/src/limits.mjs +7b46f47b5e9d6b554b5d39bce2cd95c4610f5f35b8ab8fdc5a2864b3214be809 packages/library/src/reply-protocol.mjs +406146ebbce3710f308243b684a1c17e7626c1b65a4468489364317e31537a48 packages/library/tests/guard.test.mjs +39c8e6c8250a13fa43015fb2c407195e30ee642f729a9f6a644c38b4ea758a72 packages/seat/src/sandbox.mjs diff --git a/agents/beakley/work/queue-217/rebase-r2.range-diff.txt b/agents/beakley/work/queue-217/rebase-r2.range-diff.txt new file mode 100644 index 000000000..d3ce95ff8 --- /dev/null +++ b/agents/beakley/work/queue-217/rebase-r2.range-diff.txt @@ -0,0 +1,112 @@ +1: e25ef0373 ! 1: b9ef816ff launchpad: row 217 C2-06 work in progress, UNTESTED, handed to Beakley (mos-1500) + @@ packages/bus/src/broker.mjs: export class Broker { + if (CREDENTIAL_VERBS.includes(request.verb)) return this.#requestCredential(s, request.verb, structuredClone(args)); + if (request.verb === 'instance.hire' || request.verb === 'instance.fire') + return this.#chiefLifecycle(s, request.verb, structuredClone(args)); + + if (request.verb === 'grants.scope' || request.verb === 'grants.scope.set') + + return this.#grantScopeVerb(s, request.verb, structuredClone(args)); + - if (["limits", "limits.set", "organization.set", "organization.revision", "plugins", "plugins.set", "instances", "instances.set", "routes", "routes.set", "veto.set"].includes(request.verb)) { + + if (["limits", "limits.set", "organization.set", "organization.revision", "plugins", "plugins.set", "instances", "instances.set", "routes", "routes.set", "veto.set", "library.limits.set"].includes(request.verb)) { + // Row 123 (#1617, REQ-COS-1, REQ-LIMIT-1): organization.set is limits.set for a role whose + @@ packages/bus/src/runtime.mjs: export async function startBroker({ + project: { + readSpec: context => projectModule.readSpec({ ...context, dataRoot }), + @@ packages/bus/src/runtime.mjs: export async function startBroker({ + - else if(verb==='plugins.set')result=plugins.set(id,args,actor); + - // Row 194 (#1692, V6): the human's keep and noHire lists, through the instance writer. + else if(verb==='veto.set')result=instances.veto(id,args,actor); + + // Row 298: the human's grant scope, through the instance writer. + + else if(verb==='grants.scope.set')result=instances.grantScope(id,args,actor); + + // C2-06 M11: the human's replyLimits, through the organization writer's fence. + + else if(verb==='library.limits.set')result=setReplyLimits(organizationWriter({dir:organization.dir,rolesDir:organization.rolesDir}),id,args,actor); + // Row 194 (D2.1, D2.2): the chief's hire and fire, with the reason in the change context. + @@ packages/business/src/organization.mjs: export function organizationWriter({ dir + const parent = join(dir, "businesses"); + directory(evidence); + @@ packages/business/src/organization.mjs: export function organizationWriter({ dir, rolesDir, barrier = () => {} }) { + - // mapping, including library playgrounds and hybrid universes. + - if (canonicalJson(document?.projects) !== canonicalJson(old.projects)) + - fail('organization-projects-protected'); + -+ replyLimitsFence(old, document, actor); + - validateBusinessDocument(document, file, { rolesDir }); + - const bytes = JSON.stringify(document, null, 2) + "\n"; + - // Check and log exactly what lands on disk, for every setter: a value JSON + + // mapping, including library playgrounds and hybrid universes. + + if (canonicalJson(document?.projects) !== canonicalJson(old.projects)) + + fail('organization-projects-protected'); + ++ replyLimitsFence(old, document, actor); + + validateBusinessDocument(document, file, { rolesDir }); + + const bytes = JSON.stringify(document, null, 2) + "\n"; + + // Check and log exactly what lands on disk, for every setter: a value JSON + @@ packages/business/src/organization.mjs: export function organizationWriter({ dir, rolesDir, barrier = () => {} }) { + - const written = JSON.parse(bytes); + - if (canonicalJson(written.projects) !== canonicalJson(old.projects)) + - fail('organization-projects-protected'); + -+ replyLimitsFence(old, written, actor); + - validateBusinessDocument(written, file, { rolesDir }); + - const after = sha256(bytes); + - const transaction = randomUUID(); + + const written = JSON.parse(bytes); + + if (canonicalJson(written.projects) !== canonicalJson(old.projects)) + + fail('organization-projects-protected'); + ++ replyLimitsFence(old, written, actor); + + validateBusinessDocument(written, file, { rolesDir }); + + if (beforeWrite) { + + beforeWrite(); + @@ packages/business/src/organization.mjs: export function organizationWriter({ dir, rolesDir, barrier = () => {} }) { + }); + } + @@ packages/library/src/guard.mjs (new) + +} + + ## packages/library/src/index.mjs ## + -@@ packages/library/src/index.mjs: export { renderItems, KINDS, NOTICES, UNREADABLE } from './render.mjs'; + - export { survey, formatSurvey, surveyMain } from './survey.mjs'; + - export { SYNC_STATE_FILE, mirrorPath, ensureMirror, withLibraryLock, servedCommit, readSyncState, libraryStatus, readLibraryFile } from './mirror.mjs'; + +@@ packages/library/src/index.mjs: export { SYNC_STATE_FILE, mirrorPath, ensureMirror, withLibraryLock, servedCommi + export { syncCommand, sync, ASKPASS, SLOT, SYNC_INTERVAL_MS } from './sync.mjs'; + + export { buildIndex, indexFor, clearIndexCache, indexCacheSize } from './index-build.mjs'; + + export { sees, find, get, search, manuscript, universeInfo, QUERY_REPLY_CAP, LOOKUP_LIMIT, MANUSCRIPT_LINES } from './query.mjs'; + +export { REPLY_LIMITS, resolveReplyLimits, checkReplyLimits } from './limits.mjs'; + +export { GUARD_CODES, FIXED_TEXTS, WEB_CITE_DEFINITIONS, REASON_MAX, GuardError, parseReply, checkReply, libraryReader, guardReply, lastCommits } from './guard.mjs'; + +2: c25f5b8da ! 2: 7400509ba row 217: citation runner retry and acceptance draft (Untested) + @@ Commit message + row 217: citation runner retry and acceptance draft (Untested) + + ## BUILD-LOG.md ## + -@@ BUILD-LOG.md: Row 299 (573, #1806, Gander, Filbert): before, the P10 band test timed a fault r + - 2026-10-23T17:29:46Z | Gyro Vikunja571 sage-3542 Connections amendment | Branch gyro/editor-connections-design cut exactly from landed PRD1.17 30e6bb680; read REQ-LIB-5 in that PRD. Replaced stale J-b waits in parent and W4. Proposed W8 owns current authorized Markdown/DOCX links/backlinks list, labels, versioned refresh, leakage refusals and fixture tests. Build order under mos-1470/comment961 is W7 closed routing candidate, W8 landing, then W7 human first-real-import opening. No REQ-LIB-8 condition or acceptance change. Q234/mos-1363/S0 M1-M14 and post-10-27/MVP priority fixed. Static diff, twelve brief sections and append-only checks pass. No repo Node, tests, build, browser, queue mutation or live action. Fenton reviews after authorized docs branch push; Sage lands on approval. + +@@ BUILD-LOG.md: remain; no live state, schema or bus policy change. + + - 2026-10-23T17:32:37Z | Gyro sage-3544 fenton-0016 N1/N2 delta | Before: W7 Gate/final real-conversion list omit the W8 build-order cross-reference and W8 human-view filtering cites agent settings. After: both locations explicitly put W8 landing before human opening as mos-1470 build order, not acceptance; comment/tracked-deletion links are not current story links and never appear in the human Connections view regardless of agent settings. New commit atop approved 5af060fb5, no amend. Static diff and append-only checks pass. Docs only, no repo Node/tests/live action. Fenton checks only this delta. + -+ + + 2026-10-24 | Goldie | Row265 / #1770 verified (mos-1567, sage-3942) | Approved correction adds solely address import pin + Row265 comment to project-runtime.test and one pure-source RUNNER_FILES mount; new block checks parser has no imports. Serialized fresh-short-TMP timeout-k10: unchanged sandbox10/10, parser15/15, rooms18/18, full bus957/957, twelve named refusal mutants killed (each Node1, driver0), restored parser15/15 + rooms18/18. All positives zero fail/skip/cancel; every mutation restored full broker SHA71b32ee4. Old first-red evidence retained, no other old-test change. Slot returned goldie-0034; Boyd packet explicitly includes mount-list review, candidate push next. + + 2026-10-24T07:18:53Z | Sage | Row 327 (#1825, Bradford, Poe and Dewey) LANDED 68c08b4e7. Before: refactor at 94d9e90a6; the push guard was a scratch script with no reviewed-binary check. After: scripts/push-check.sh and scripts/test-push-check.sh on refactor, 3 commits cherry-picked onto 6a5e12511 with blobs equal to the round 3 tip d858c9f8b, plus doc commits 76f84465f and 68c08b4e7. Binaries are found by numstat or a NUL in the first 8000 committed bytes, regardless of attributes; each needs its sha256 and path in an approved latest-round candidate; an unconfirmed queue tail exits 2. Reviews: Poe c31525 rev 3882, Dewey c31526 rev 3883. Gate: 1st run 06:57Z RED, not the candidate: canonical node_modules was empty from 05:45:15Z (sage-4023). Rerun with its own root npm ci GREEN 07:15:49Z: 17 package suites 0 failures (cli 986, plugins 119, webui 418), 11 scripts exit 0, push-check 6 mutants KILLED; skips are the queue canonical-root check and the row 244 live provider cases. The landed push-check.sh passed its own push (NO_BINARY, NO_ATTRIBUTION, PUSH_READY). mos-1575: gates install their own node_modules; canonical restored with npm ci (128 packages). + +2026-10-23 | Beakley (88b97f65) | Row 217 #1718 takeover, before implementation | Clean base 45dca69f6 on beakley/row217. Recovering Launchpad handoff for citation guard, live settings, page store and runner retry. Acceptance is C2-06/design 5.2 plus sage-3595/3599/3602. Tracking agents/beakley/work/queue-217/BUILD.md; no product changes or Node/tests; Sage CLEAR required. + + + +2026-10-23 | Beakley (88b97f65) | Row 217 #1718 untested draft checkpoint | Continued Launchpad e25ef0373; added runner retry/text/note implementation, pure protocol constants and sage-3640 approved single read-only mount, CLI documentation and new acceptance test files. Static checks caught missing projects compatibility, async request mutation and Git pathspec matching; bounded fixes and regression tests authored. git diff --check clean. No Node/test/mutant executed; Sage holds CLEAR. 283/216/285 dependency checks and all acceptance execution remain open. Packet agents/beakley/work/queue-217/MANIFEST.md. + @@ agents/beakley/work/queue-217/mutants.py (new) + + ## docs/SESSIONS.md ## + @@ docs/SESSIONS.md: are never rewritten or removed; corrections are new entries. + - 2026-10-23T17:48:43Z | Scrooge (629b6cd3) | Row 252 Console inbox Approve and Deny (#1753) | Rebased onto 306 landing as 580037105 (range-diff all =), slot run bus 907/0 webui 410/0 cli 943/0, in-review revs 3608/3609, Webby r1 APPROVE, J1-J19 specs to Sage; Sage landed 45ea3fa0d (done rev 3616). Part 1 mutant results were never in BUILD.md; they went to Sage by T3 (scrooge-0252-mutant-specs). + - 2026-10-23 | Sage (1ef1e4f8) | Rows 308 and 252 landings, 571 Connections design amendment, Vikunja 597 | 308 (PRD 1.17, #1815) landed 30e6bb680 and 252 (#1753) landed 45ea3fa0d (replay of 580037105 onto 30e6bb680, range-diff all =), each after a full gate on the landed tree (252 also J1-J19, J11c and J18 equivalent); Gyro's 571 amendment (Fenton APPROVE) landed e8bb13df8; Vikunja 570, 435 and 597 done, canonical webui esbuild 0.28.2; queue revs 3589-3616 committed 59f013247 + - 2026-10-23 | Sage (1ef1e4f8) | Vikunja 571 W build rows; rows 13, 42, 257 and 289 check | Filed the design's ten W rows as queue rows 309-318 (revs 3617-3626, owners set to unassigned 3627-3636, queue commit 293b42fee pushed); Vikunja 571 done (comment 994). Row 13's candidate fd72d2689 is on refactor, gate is Monday's row 7 ledger run; 42 paused under mos-1184; 257 post-v1; 289 waits on 214 and 288. Slot released 17:56Z. + + 2026-10-24T04:27Z | Goldie (a13dd6d5-5e73-4b7d-8318-02abeff24940) | Row265 / #1770 C2-09b rooms | Goldie owns build, Boyd reviews under sage-3915. New goldie/row265 worktree at ec86f2c84, claim rev3814; room verbs/parser/new tests prepared, no old tests changed. Sage-3932 slot: new parser14/14 and rooms18/18 passed; whole bus in progress before refusal mutants, stop rule active. + + 2026-10-24T04:35Z | Goldie (a13dd6d5-5e73-4b7d-8318-02abeff24940) | Row265 / #1770 verified | First slot stopped at project-runtime import pin. mos-1567 narrowly authorizes pin and pure-source mount correction. sage-3942 rerun: sandbox10/10, parser15/15, rooms18/18, bus957/957, twelve refusal mutants killed/restored SHA71b32ee4, parser15/15 + rooms18/18 again. Slot returned goldie-0034; no further test runs. Boyd reviews RUNNER_FILES alongside rooms; own-branch push/claimant in-review next. + + 2026-10-24T07:18:53Z | Sage (1ef1e4f8) | Row 327 / #1825 push guard landed (mos-1572 option A, mos-1575) | Gate went red 06:57Z on an empty canonical node_modules (Glomgold's webui npm ci through a link to canonical, glomgold-0011); rerun with its own npm ci GREEN 07:15:49Z on 1bd214e38; pushed 68c08b4e7 07:18:03Z; #1825 closed c31530; canonical restored (128 packages); brief template rule 4db23a51f | landed + + + +2026-10-23 | Beakley (88b97f65, Codex gpt-6.1-sol) | Row 217 #1718 takeover under Q245 | Registered beakley/row217; read brief/design and standing Sage rulings; awaiting Launchpad ref before implementation. Queue next refused linked worktree; reported to Sage. Untested, no Node/test run pending CLEAR. + +3: b6c3129d2 ! 3: a447880cb row 217: early-review coverage and availability RED cases (Untested) + @@ Commit message + row 217: early-review coverage and availability RED cases (Untested) + + ## BUILD-LOG.md ## + -@@ BUILD-LOG.md: Row 299 (573, #1806, Gander, Filbert): before, the P10 band test timed a fault r + +@@ BUILD-LOG.md: remain; no live state, schema or bus policy change. + 2026-10-23 | Beakley (88b97f65) | Row 217 #1718 takeover, before implementation | Clean base 45dca69f6 on beakley/row217. Recovering Launchpad handoff for citation guard, live settings, page store and runner retry. Acceptance is C2-06/design 5.2 plus sage-3595/3599/3602. Tracking agents/beakley/work/queue-217/BUILD.md; no product changes or Node/tests; Sage CLEAR required. + + 2026-10-23 | Beakley (88b97f65) | Row 217 #1718 untested draft checkpoint | Continued Launchpad e25ef0373; added runner retry/text/note implementation, pure protocol constants and sage-3640 approved single read-only mount, CLI documentation and new acceptance test files. Static checks caught missing projects compatibility, async request mutation and Git pathspec matching; bounded fixes and regression tests authored. git diff --check clean. No Node/test/mutant executed; Sage holds CLEAR. 283/216/285 dependency checks and all acceptance execution remain open. Packet agents/beakley/work/queue-217/MANIFEST.md. +4: dde5b8496 = 4: 2655ec010 row 217: keep fixture status on its current served tip (Untested) diff --git a/docs/SESSIONS.md b/docs/SESSIONS.md index 0d413e459..8ecce1c9e 100644 --- a/docs/SESSIONS.md +++ b/docs/SESSIONS.md @@ -1630,3 +1630,5 @@ are never rewritten or removed; corrections are new entries. - 2026-10-24 — lena (db27faca), row 296 / #1802: r2 rebased onto e0c6142f3; scoped acceptance plain 1/1, killed-driver cleanup verified, M1/M2 assertion kills/restored, dedicated-file skip verified; own dependency installs, no old tests/live changes; reviewer and Sage gate pending. 2026-10-23 | Beakley (88b97f65, Codex gpt-6.1-sol) | Row 217 #1718 takeover under Q245 | Registered beakley/row217; read brief/design and standing Sage rulings; awaiting Launchpad ref before implementation. Queue next refused linked worktree; reported to Sage. Untested, no Node/test run pending CLEAR. + +2026-10-24 | Beakley (88b97f65) | Row 217 round 2 under sage-4037 | New beakley/row217-r2 rebased onto e0c6142f3, retained both log histories, E4 product fix and supporting/index tests drafted. No Node/npm/tests/mutants run; ready for CLEAR; local-only dependency installs required on CLEAR, old-test red goes to Sage. diff --git a/packages/bus/tests/citation-guard.test.mjs b/packages/bus/tests/citation-guard.test.mjs index f19421ca4..77137c8d3 100644 --- a/packages/bus/tests/citation-guard.test.mjs +++ b/packages/bus/tests/citation-guard.test.mjs @@ -43,6 +43,31 @@ test('C2-06 stored check carries the file author trailer at an unrelated cited t assert.deepEqual(row.check.citations, [{ scope: 'canon', agent: 'acme/scribe', file, last: file }]); }); +const supportingMapping = entry => { + entry.universes.harbor.supporting = ['Book One/Playground/']; + return entry; +}; + +test('C2-06 supporting cite cannot state canon, including a folder also marked playground', async t => { + const f = citationWorld(t, { definition: 'research', mapChange: supportingMapping }); f.call(f.agent, 'role.claim'); + const count = f.store.get('SELECT count(*) n FROM messages').n; + await assert.rejects(f.call(f.agent, 'message.send', { to: 'human', body: citedBody([fixtureCite(f.commit, { + path: 'Book One/Playground/What If.md', lines: [4, 4], quote: 'Mara Vell', as: 'canon', + })]) }), { code: 'playground-cited-as-canon' }); + assert.equal(f.store.get('SELECT count(*) n FROM messages').n, count); +}); + +test('C2-06 supporting file stores supporting scope and its real agent trailer', async t => { + const f = citationWorld(t, { definition: 'research', mapChange: supportingMapping }); f.call(f.agent, 'role.claim'); + const path = 'Book One/Playground/What If.md'; + writeFileSync(join(f.repo, path), readFileSync(join(f.repo, path), 'utf8') + 'Agent fixture note.\n'); + git(f.repo, 'add', '-A'); git(f.repo, 'commit', '-qm', 'Supporting note\n\nMosaic-Agent: acme/scribe'); + const file = git(f.repo, 'rev-parse', 'HEAD'); f.setServed(file); + const sent = await f.call(f.agent, 'message.send', { to: 'human', body: citedBody([fixtureCite(file, { path, lines: [4, 4], quote: 'Mara Vell' })]) }); + const event = f.store.get("SELECT body FROM events WHERE subject=? AND json_extract(body,'$.action')='message.checked'", sent.id); + assert.deepEqual(JSON.parse(event.body).check, { citations: [{ scope: 'supporting', agent: 'acme/scribe', file }] }); +}); + test('C2-06 check evidence and insert are atomic when storing evidence fails', async t => { const f = citationWorld(t); f.call(f.agent, 'role.claim'); f.store.run(`CREATE TRIGGER fixture_check_refused BEFORE INSERT ON events diff --git a/packages/bus/tests/citation-helpers.mjs b/packages/bus/tests/citation-helpers.mjs index aa38a565e..1ffdfc046 100644 --- a/packages/bus/tests/citation-helpers.mjs +++ b/packages/bus/tests/citation-helpers.mjs @@ -11,10 +11,10 @@ import { mapping, repo, MARKER } from '../../library/tests/helpers.mjs'; export const citedBody = citations => JSON.stringify({ text: 'A fixture answer.', citations }); export const fixtureCite = (commit, extra = {}) => ({ path: 'Book One/Characters/Mara Vell.md', commit, lines: [9, 9], quote: 'Grey eyes.', ...extra }); -export function citationWorld(t, { definition = 'coder', library = true, guard: overrideGuard, organization = null, sendAuthority = true } = {}) { +export function citationWorld(t, { definition = 'coder', library = true, guard: overrideGuard, organization = null, sendAuthority = true, mapChange } = {}) { const r = repo(t), root = r.root, state = join(root, 'bus'); mkdirSync(state, { mode: 0o700 }); const store = new Store(state); t.after(() => store.close()); - const map = mapping(), settings = join(root, 'business.json'); + const map = mapping(mapChange), settings = join(root, 'business.json'); writeFileSync(settings, JSON.stringify({ replyLimits: { requireCitation: false, citationsPerReply: 20 } })); const business = { id: 'acme', human: 'jason', vars: { 'bus.tester': true }, ...(library ? { projects: { books: map } } : {}), diff --git a/packages/library/src/guard.mjs b/packages/library/src/guard.mjs index a5a89572b..f2558d7c0 100644 --- a/packages/library/src/guard.mjs +++ b/packages/library/src/guard.mjs @@ -1,6 +1,7 @@ // C2-06 (design 5.2, rulings after r11 Q222, Q223 and Q226): the citation guard. The broker runs it // before it stores an agent's message to the human in a business with a library project. It reads // only the citations, never what the text says. Codes are design 5.2's table. +import { lstatSync } from 'node:fs'; import { git } from '../../project/src/git.mjs'; import { classify } from './scope.mjs'; import { listTree, readLibrary, readTexts, splitLines } from './reader.mjs'; @@ -166,15 +167,22 @@ export async function lastCommits(context, paths) { return out; } -// The library project's bare mirror and its served commit. Either is null when there is none yet, so -// a plain reply still passes and any library cite refuses citation-invalid. +// Only an absent mirror or a legitimate empty sync state means there is no served commit. +// A lock timeout or unsafe/unreadable state is availability failure, not evidence of an invalid cite. async function servedMirror(context) { const mapping = context.business.projects[context.project]; let mirror = null, served = null; try { mirror = mirrorPath(context); + try { lstatSync(mirror); } + catch (error) { + if (error.code === 'ENOENT') return { mapping, mirror: null, served: null }; + throw error; + } served = (await readSyncState(mirror, { branch: mapping.branch })).served ?? null; - } catch { served = null; } + } catch { + refuse('citation-unavailable', 'The library is busy or unavailable. Retry the answer when the library is available.'); + } return { mapping, mirror, served }; } @@ -182,7 +190,12 @@ async function servedMirror(context) { // is { business, project, dataRoot }. `definition` is the sender's role definition, which decides only // whether a url cite may pass; `pages` is the broker's page store for the sender's session. export async function guardReply(context, body, { limits, definition, pages }) { - const { mapping, mirror, served } = await servedMirror(context); const web = { allowed: WEB_CITE_DEFINITIONS.includes(definition), pages }; + // Plain replies, web-only replies and the runner's exact fallback texts don't read Git. + // In particular, a busy mirror must not prevent the fixed fallback from being delivered. + const reply = parseReply(body); + if (!reply.citations.some(c => Object.hasOwn(c, 'path'))) + return checkReply(body, { limits, mapping: context.business.projects[context.project], library: null, web }); + const { mapping, mirror, served } = await servedMirror(context); return checkReply(body, { limits, mapping, library: libraryReader(mirror, served, mapping), web }); } diff --git a/packages/library/src/reply-protocol.mjs b/packages/library/src/reply-protocol.mjs index 72e8cc307..0e5a752a4 100644 --- a/packages/library/src/reply-protocol.mjs +++ b/packages/library/src/reply-protocol.mjs @@ -1,6 +1,6 @@ // C2-06: shared pure protocol constants for the host guard and sandboxed runner. export const GUARD_CODES = Object.freeze(['reply-invalid', 'citation-missing', 'citations-over-limit', 'citation-invalid', - 'playground-cited-as-canon', 'citation-cross-universe', 'citation-unfetched']); + 'playground-cited-as-canon', 'citation-cross-universe', 'citation-unfetched', 'citation-unavailable']); // The runner's four fixed texts in a library business. The guard accepts exactly these bodies when // requireCitation is true; an agent that sends one gains nothing it couldn't say anyway. diff --git a/packages/library/tests/guard.test.mjs b/packages/library/tests/guard.test.mjs index a88791000..fcf8050b1 100644 --- a/packages/library/tests/guard.test.mjs +++ b/packages/library/tests/guard.test.mjs @@ -4,6 +4,8 @@ import { writeFileSync } from 'node:fs'; import { join } from 'node:path'; import { checkReply, GuardError, libraryReader, parseReply, FIXED_TEXTS } from '../src/guard.mjs'; import { resolveReplyLimits, checkReplyLimits } from '../src/limits.mjs'; +import { readLibrary, listTree } from '../src/reader.mjs'; +import { indexFor } from '../src/index-build.mjs'; import { BASE, MARKER, mapping, repo, git } from './helpers.mjs'; const defaults = resolveReplyLimits({ readable: true, document: {} }); @@ -108,6 +110,25 @@ test('C2-06 origin uses literal paths even when a filename contains a glob', asy assert.equal(await reader.last(path), original); }); +// C2-05a landed: compare the real lookup index with the guard's cited-commit reader. +// A guard that admits unmapped files, or excludes a supporting file, breaks this fixture. +test('C2-06 cited-commit guard reads exactly the C2-05a indexed file set with supporting scope', async t => { + const r = repo(t), map = mapping(entry => { + entry.universes.harbor.supporting = ['Book One/Playground/']; return entry; + }); + const read = await readLibrary({ repo: r.repo, commit: r.commit, mapping: map }); + const index = await indexFor({ repo: r.repo, commit: r.commit, mapping: map }); + const reader = libraryReader(r.repo, r.commit, map), admitted = []; + for (const entry of await listTree(r.repo, r.commit)) { + if (await reader.lines(r.commit, entry.path) !== null) admitted.push(entry.path); + } + assert.deepEqual(admitted.sort(), [...index.files.keys()].sort()); + assert.deepEqual(admitted, read.files.map(f => f.path).sort()); + assert.equal(index.files.get('Book One/Playground/What If.md').scope, 'supporting'); + assert.equal(index.files.has('Inbox Note.md'), false); + assert.equal(index.files.has('Book One/Board.canvas'), false); +}); + test('C2-06 reply limits fall back independently without coercion or inherited keys', () => { for (const value of ['true', 1, null, [true], {}]) { const r = resolveReplyLimits({ readable: true, document: { replyLimits: { requireCitation: value, citationsPerReply: 5 } } });