Compare commits

...
Author SHA1 Message Date
jason.woltje 21bf30db67 Record row 288 whole-file gate and six killed mutants 2026-10-24 23:53:35 -05:00
jason.woltje 2848d832e1 Give row 288 creative tool fixture its required Gitea reference 2026-10-24 23:33:10 -05:00
jason.woltje 4fb11e74a3 Correct row 288 broker grant and bare mirror fixtures 2026-10-24 23:32:43 -05:00
jason.woltje 7932c979ab Fix bare library deletion with a private index-info input file 2026-10-24 23:31:19 -05:00
jason.woltje 8a47c462a4 Untested: record row 288 landed-base transplant and import run list 2026-10-24 23:01:36 -05:00
jason.woltje 234dfe3048 Untested: row 288 contract and import-list preflight (sage-4282) 2026-10-24 23:00:26 -05:00
jason.woltje 904b313831 Untested: record row 288 fresh candidate on landed row 283 (#1793) 2026-10-24 23:00:26 -05:00
jason.woltje 06bf87724a Untested: record row 283 follow-up dependency receipts (#1793) 2026-10-24 23:00:26 -05:00
jason.woltje a024b403ca Untested: clarify existing blob requirement in library delete tool (#1793) 2026-10-24 23:00:26 -05:00
jason.woltje c88344cc71 Untested: record row 288 T7 verification and landing boundaries (#1793) 2026-10-24 23:00:26 -05:00
jason.woltje b9b0bf5842 Untested: add library write tools and served blob integration (#1793) 2026-10-24 23:00:26 -05:00
jason.woltje 4b9d7b45db Untested: migrate creative tool snapshots to eight or ten names (mos-1523) 2026-10-24 23:00:26 -05:00
jason.woltje f25d1d59ac Untested: record notice-store failure publication behavior (#1793) 2026-10-24 23:00:26 -05:00
jason.woltje 2aeda82f48 Untested: retain library notice after push when publication fails (#1793) 2026-10-24 23:00:26 -05:00
jason.woltje e3a1387fbf Untested: use editor login and cover row 288 early review gaps (#1793) 2026-10-24 23:00:19 -05:00
jason.woltje 381e1001cb Untested: protect library publication state and add broker bare-repo coverage (#1793) 2026-10-24 23:00:19 -05:00
jason.woltje 99baa507dd Untested: row 288 library writes, notices, revert and human saves (#1793) 2026-10-24 23:00:19 -05:00
23 changed files with 2007 additions and 27 deletions

No files matched your search

+5
View File
@@ -5585,3 +5585,8 @@ claim. Receipts and limitations in agents/lena/work/queue-296/BUILD.md and run-r
2026-10-24T23:37:46Z | Sage | Row 329 (#1827, P1 pinned model proxy, Magica) LANDED 61ebf2c34, pushed 23:31:27Z 10-24. Before: refactor at 669cdf42c. After: Magica's 4 commits (94cde633e, c65fb34ee, d1f6f2b19, 61ebf2c34) cherry-picked onto 669cdf42c, diff vs the gated tree limited to drift paths, range-diff in scratch. Gate: one unchanged full landing gate in /mnt/storage/scratch/sage-r329l/wt (gate.sh 8b4978887 c8a9bcf94), started 23:08:12Z at load 14.35, GATE GREEN 23:29:14Z at load 8.67, no rerun, no test or timeout edit (mos-1634). Host note: two Codex workers cleaned T3 worktrees from about 23:14Z (mos-1639, Vikunja 632). Approvals: Dewey r2 c31643 rev 4047, Boyd r2 c31642 rev 4048. #1827 comment 31650, closed. Vikunja 237 comment 1109 (stays open for P2-P7); C4 P10 red filed as Vikunja 631. Queue: note rev 4063, done rev 4064, committed b24d917ec. DEFERRED: N2 and R2-N1 bound to row 331, N1 bound to P7. Overlap: row 284 (packages/bus/src/broker.mjs) and row 157 (scripts/mosaic-config.mjs) rebase onto 61ebf2c34 before their gates.
2026-10-25T00:15:48Z | Sage | Row 284 (#1789, C2-05c library.get scope, Della) LANDED ce0b6ed41, pushed 00:09:52Z 10-25. Before: refactor at 9e2689dff (row 329 landing docs). After: fast-forward to Della's 7 rebased commits 78b932feb..ce0b6ed41; 8 paths, manifest-r4 de505cfd matches the landed tree. Gate: one unchanged full landing gate in /mnt/storage/scratch/sage-r284l/wt (the 329 gate.sh with D and the compose project renamed), started 23:51:19Z at load 1.62, GATE GREEN 00:09:04Z at load 5.20, no rerun, no test or timeout edit. Counts: bus 1020/0, business 283/0, cli 999 pass 1 allowed skip (FED R7), harness 177/0, library 156/0, seat 218/0, webui 458/0, every scripts/test-*.sh rc 0; queue 34 and task 87/93 skips are the standing ones. Della's whole-file runs on ce0b6ed41: library-lookups 12/0, library-tools 5/0, query 34/0. Approval: Webby round 2 delta c31654 rev 4070 (round 1 rev 4062). Overlap sweep: rows 13, 157, 309, gyro/row310 and fethry/row332-p1 clean. #1789 comment 31655, closed. No Vikunja task for the row. Queue: note rev 4071, done rev 4072, committed 7c8dc2033. DEFERRED: Webby N1 (whole-tree listing per get) bound to the next library read-path row; N2 needs nothing; N3 is this gate.
2026-10-25T00:18:35Z | Sage | Follow-up tasks for mos-1647 item 3 (Q109): Vikunja 633 (P7 cutover, CLIProxyAPI 8.0.42 startup Grok-npm and antigravity version refreshes, from row 332 isolated runs) and 634 (row 284 Webby N1, library get lists the whole tree). DEFERRED gains the 633 entry and the 634 number for row 284 N1. Filing script and receipt in agents/sage/work/vikunja-setup/.
## 2026-10-23 — Row 288 C2-02 build starts (Bubba, #1793)
Before: agents can read the library; supporting-path and push-credential dependencies are separate unlanded heads. After intended: per-seat supporting writes/deletes with exact notices, human revert and one commit per Console save. Work is on bubba/row288, chained on original 283/285/286 commits; 284 tool base still pending. Plan and acceptance evidence: agents/bubba/work/queue-288/BUILD.md. Untested; no Node/test/build/gate run before Sage CLEAR. Landing waits for every dependency's own gate.
2026-10-25 | Bubba | Row288 #1793 gate after landed284 | Candidate2848d832e:289 whole files rc0 (2604 pass,1 covered FED skip),12 scripts rc0,6 mutants killed/restored controls rc0. Own bare-delete and fixture reds fixed with driver restarts; no pre288 red. Per-run hashes/rc in agents/bubba/work/queue-288/gate-r6-results.tsv. Slot returned Sage bubba-0034; manifest review/landing pending.
+501
View File
@@ -0,0 +1,501 @@
# Row 288 (#1793): C2-02 agent writes, notices, revert and Console saves
Owner: Bubba, Codex gpt-6.1-sol, thread 3d6672b5-5544-4b95-9e09-e79574f1aa14.
Reviewer: Webby. Gate and landing: Sage. Append-only build record.
## 2026-10-23 start and implementation plan
Base 45dca69f6 on bubba/row288. Direct mandate mos-1499 (Q245), confirmed sage-3613.
The canonical `scripts/mosaic queue next bubba` returned `nothing`; Sage owns the owner transition.
The initial worktree invocation refused linked-worktree use; retried in canonical checkout.
Spec: docs/plans/2026-10-20_case2-rows.md, C2-02; agents/gosalyn/work/case2/DESIGN.md ruling after r11.
Handoffs: Honker queue-283 BUILD.md Q4 (missing/non-100644 delete refuses); Morgana
queue-225 BUILD.md A2 at 66f7becf2 (strict revert arguments/result), confirmed by Fethry fethry-0005.
`project` is the business.projects key, never a chat UUID.
Dependencies merged with their commits intact, no amend or force-push:
- 283 origin/honker/row283-build 88ec5e8e4 (new E4 head to follow).
- 285 origin/scrooge/row285-r2 53db6b7ca.
- 286 origin/ludwig/row286-r2 573fa0be0.
- 284: no named remote branch yet. Tool changes come last.
All merge commits are marked Untested. Nothing has run under Node. Sage's latest instruction
sage-3613 reserves **all Node and test runs** for CLEAR; this supersedes the initial targeted-test
permission. Build untested now as instructed, then run RED/GREEN checks/mutants on CLEAR.
Architecture: one host-only plumbing writer under the existing library lock; broker authorizes and
selects credentials, then inserts the fixed notice directly. Human save/revert use editor +
library-human independently of seat lifecycle. No worktree, deferred push, role expansion or UI.
### Tasks and acceptance
- [ ] Plumbing: new library/src/write.mjs, mirror state publication and package exports; new
library/tests/write.test.mjs. One-parent write/delete, byte-exact content, seat identity/trailer,
stale-base, nonregular/missing deletes, retry once on an unrelated remote change, push failure
without local ref movement, human editor and revert reachability/single-path checks.
- [ ] Broker + runtime: library.doc.write/delete, library.file.save, library.revert; strict keys,
creative + library.write + live unheld project grant; direct exact notice; human-only save/revert.
New bus/tests/library-write.test.mjs covers authorization, unchanged refs, A2 contract and socket.
- [ ] Transport: only human library.file.save joins the existing large-save exception. New tests
prove >64 KiB save accepted, agent writes retain 64 KiB bound, malformed/oversize saves refuse.
- [ ] Tools after 284: library_doc_write/delete in harness tools; exact eight/ten-name snapshots
in a new harness test; cli dispatch wiring.
- [ ] Verify on CLEAR: new tests, library/bus/harness suites and all scripts/test-*.sh on Sage's
assigned slot. Mutants remove supporting guard and force push; both must fail. Fixture-token
search over captured output. No gate, landing or queue move claimed before Sage's acceptance.
Pre-flight interfaces: broker consumes library writer {project,path,commit}; revert adds reverted;
writer consumes C2-03b push {pushed} or {raced,tip} and supportingPath(mapping,universe,path,tree).
State publication must add optional lastPush while preserving old state readability. Refusals must
restore fetched remote-tracking refs as well as preserve served. Runtime must bind credential file
references itself; no file, identity, message or credential is supplied by the agent.
Necessary file-scope additions: packages/bus/src/runtime.mjs (actual adapter injection),
packages/library/src/index.mjs (exports), and CLI's existing console adapter if saves require it.
Reported to Sage in bubba-0002. Existing tests will not be edited without Mos's OK via Sage.
Review focus: remote tip races, nonregular entries and folded paths, unsafe human credential before
git, revert after revoked/fired writer, and large-request exception never extending agent writes.
### Existing-test changes
None authored by Bubba yet. Dependency test changes remain their owners' original commits.
## 2026-10-23 first static build (not a gate result)
283 E4 merged intact at 76d651dba. Honker next reports e67c27b32 (test environment only), to merge
before push. Della reports row 284 has not been built/pushed; row224's 23816cf28 is not a 284 head.
No speculative 284 pin. Typed tools and served-blob lookup integration remain pending 284.
Implemented (unrun): bare plumbing writer, one-parent commit and fixed trailer, exact-content blobs,
base comparison, supporting path guard and delete regular-blob check, one remote-race retry,
ref restoration on refusal, immediate served publication/lastPush; human save and reachable one-path
business-trailer revert; broker grants/identity/notice path; runtime adapter wiring; large-save socket
exception. New tests: library/tests/write.test.mjs and bus/tests/library-write.test.mjs. No old test edits.
### Approved scope additions, sage-3628
Every hunk outside the brief's owned list:
- `packages/bus/src/runtime.mjs`: `humanWriteOptions` checks editor before choosing the human slot;
three library adapter entries bind dataRoot, command and the host-only seat store reference. These
are needed to make actual bus calls reach the new writer without accepting agent-supplied files.
- `packages/library/src/index.mjs`: export writeLibraryDoc/saveLibraryFile/revertLibraryCommit so
runtime's existing library module adapter can call them.
- `packages/library/src/sync.mjs`: shared write guard with opaque token compared by identity;
push's race fetch recognizes only that owner and does not clear its guard; ordinary sync and a
forged token still refuse library-sync-busy. Narrow publishLibraryWrite validates ids, reads the
locked state, rebuilds the index via readLibrary, moves served/tracking and writes lastPush. The
raw writeState remains private and is not exported through index.mjs.
Ludwig ludwig-0064 reviewed the intended interface and requested the opaque token (implemented),
narrow publication (implemented), whole library + bus library-credential checks and a token mutant
(planned). His 573fa0be0 remains current and unrun. 288's additions are separate commits, not folded
into 286. Tracking restores only if the whole write refuses, not between the first race and retry.
Known tradeoff, accepted by Sage sage-3628 for MVP: the brief holds the flock through network Git;
readers can hit the existing 5-second library-sync-busy while it runs. Structural supportingPath
preflight is pure and precedes Git; served/fetched listTree checks repeat it with the real tree before
any remote write. A tree-dependent check necessarily reads the tree first (Honker honker-0184 item2).
### Mutants for CLEAR
- Remove the `pathOf` calls for agent operations: the M12 broker/bare-ref tests must fail on a
story/unsupported path while checking remote, tracking and served refs.
- Prefix the push refspec in syncCommand with `+`: write.test moved-target race must fail, because
its command seam preserves production syncCommand's refspec (only remote URL/protocol are fixture).
- Replace `writers.get(mirror) === writeToken` with `true`: write.test forged-token case must fail.
No Node, test, build or mutant has run. `git diff --check` is clean. Counts are not claimed.
### Console dispatch integration
The existing cli delegates its transport wiring to console-bus.mjs, so the save dispatch needs that
file too: one null `librarySave` option and one `--send` assignment to library.file.save. cli.mjs
threads that option into startServer; row C2-11b owns the actual route/page that consumes it. New
webui/tests/library-write-options.test.mjs covers --send and the user transport boundary. 225 owns
libraryRevert dispatch; 288 adds only librarySave to avoid overlapping that ownership. Additional
scope reported to Sage and Fethry. No changes to an existing test.
## 2026-10-23 second static pass and dependency review
First push: c867cada9 on origin/bubba/row288, reported bubba-0005 to Sage/Webby/Mos and
bubba-0006 to Fethry/Ludwig. No PR created and no review/gate requested as complete.
Ludwig ludwig-0065 checked the exact sync diff against 286 without running anything. Token identity,
ordinary-sync exclusion, 286 R1 preservation, guard key and end-of-write tracking restoration fit.
F1: state publication could fail after served moved, leaving old state/new served. Root cause is
publication order without rollback, compared against sync's existing rollback. Added an unrun
filesystem rename-failure regression, then changed the narrow helper: on failure it validates the
state under the same lock, CAS-restoring served if state has not published the new commit. If rename
succeeded but directory fsync failed and the state validates against new served, it keeps that pair.
All failure cases answer outcome-unknown; tracking remains the commit already pushed remotely.
Verification is pending CLEAR, so this is a proposed fix, not a tested resolution.
Added the actual broker-to-bare tests for each M12 path refusal (both agent verbs), unchanged remote
and all mirror refs, exact write/delete notices, and human revert after fixture grant removal/hold.
The bare fixture moved to new library/tests/write-fixture.mjs so broker tests reuse real plumbing.
Added the raw socket proof-nested-save-name case to pin the parsed-verb large-request check.
Missing editor/slot tests now make the mirror metadata invalid first: reaching Git would change the
refusal, so the tests check the pre-Git gate rather than merely count remote commands.
Additional required doc hunk: packages/library/README.md appends the four verb contracts,
lastPush shape, exact notice, lock tradeoff and publication failure behavior. No existing test from
the dependency/base has changed. All new/modified tests in this pass were authored by this row.
`git diff --check` remains clean. No Node/tests/build/mutants run; 284 and CLEAR remain pending.
## 2026-10-23 early review follow-up (Webby E1-E6; Ludwig F2)
Sage sage-3652 approves console-bus.mjs wiring (null option + --send dispatch), confirms editor.user
as the sole human login source and reserves CLEAR for T3/T4 after T2. Ordinary sync()'s separate
post-rename fsync gap stays out of 288 per that ruling; no change to sync()'s existing rollback.
Honker 283 head 46bad7ea3 merged intact: mapping editor.user is optional, and if present uses the
existing plain Gitea-user pattern. The omission at mapping level is valid; human writes refuse it.
- Ludwig F2 / Webby E6: confirmed the previous runtime used the fetch bot's mapping.user wrongly.
Runtime now passes mapping.editor.user to humanCredential, never mapping.user. Missing user gives
library-human-missing before Git. New real-runtime cases pin both save and revert with a separate
fetch-bot login, positive pushes under her-gitea-login, and no command for an absent editor login.
The broker's credential.agent is s.role, not args: added an exact assertion and strict-key refusal
cases for caller-supplied agent and credential.
- E1: replaced the business-id RegExp interpolation with a literal startsWith(business.id + '/')
check and ID_PATTERN on only the instance suffix. New acme.co vs acme-co trailer test.
- E2: new broker→bare case holds the seat in the fetch command. beforePush must refuse
library-write-no-grant with all local refs and the remote unchanged and no notice. New mutant:
remove `options.beforePush?.();` in write.mjs; the E2 test must fail.
- E3: new broker cases for expired rotate_by, fire.stopped without fire.done, missing role.publish
project, grant/identity Gitea-user mismatch, and missing identity name/email, for both agent verbs.
- E4: the exceptional publication failure currently returns outcome-unknown before the broker has
a successful result to put in a notice, so a remote agent commit can exist without a Console
notice. There is no durable notice outbox/retry in this row. The trailer commit remains human
revertible by id after sync; this is an explicit known failure-mode gap for the manifest, not
a claim that every failed publication emits a notice. A new real-push test breaks state decoding
after push admission, pins outcome-unknown, old served and no notice. It also found a local error
propagation gap: errors before publishLibraryWrite's internal try now normalize to outcome-unknown
in the writer once push has succeeded, so the caller is never told an ordinary refused-write code.
- E5: 284 still has no build. Tools/8-or-10 snapshot and served-blob integration remain pending.
librarySave is intentionally only an adapter option until C2-11b supplies its route/page.
All tests above are newly authored by row288 and remain unrun; no changes to baseline/dependency
tests. RED/GREEN and mutants await CLEAR. Proposed fixes are not claimed verified. The new host-only
library write module imports the existing pure ID_PATTERN to match the broker's accepted instance ids.
## 2026-10-23 mos-1520 ruling: post-push notice is required
Correction to the E4 interpretation above: Mos rejected the known-gap treatment. The requirement
stays: a pushed agent commit has the exact notice even if local publication then fails. This is not
an outbox or retry. The writer now calls the broker's trusted synchronous onPushed callback as soon
as push returns pushed:true, before publication. The callback records the exact library-write notice
and action.allowed in the normal Console-store transaction. Publication failure still answers
outcome-unknown. The notice's Revert can refuse library-revert-not-agent until sync makes that commit
reachable from served; README now says that explicitly and removes the rejected gap description.
The row's own real-push corruption test now pins the exact notice body with the pushed id, old
served and outcome-unknown; after restoring readable state it pins Revert's refusal before sync and
success after sync. The successful-write adapter fixture calls onPushed too, matching runtime's
writer contract. No existing baseline/dependency test changed (mos-1520 explicitly authorizes this
row's test correction without mos-1272).
Residual Console-store failure: if notice insertion/routing/its event transaction fails, the broker
calls a separate host log sink with {event:library-notice-store-failed,code:outcome-unknown,business,
instance,op,commit}. It logs no args, path content, credential, raw SQL or exception output. Runtime's
new library.log adapter writes this metadata to stderr. The caller gets outcome-unknown even if
recording action.refused in that same broken store fails. A new real-push test uses temporary SQLite
abort triggers on notice insertion and refusal evidence, checks remote advanced/served unchanged,
no message, the exact external log and outcome-unknown. It does not claim a notice can be stored in
a failed Console store. If the host log sink itself also fails, no durable log can be promised; the
caller still receives outcome-unknown. The runtime log hunk is the required residual-failure wiring.
Mutant added: move `options.onPushed?.({ project: context.project, path: change.path, commit });`
from before `await publishLibraryWrite(...)` to immediately after that await inside the same try.
Successful operations keep their notice, but the outcome-unknown publication path drops it. The
C2-02 E4 real-push corruption test must fail on its exact notice assertion. Run on CLEAR and restore.
No Node/tests/build/mutants run. Static git diff --check clean. Della's first284 head0ed4fbab9 is
explicitly incomplete and not a finished dependency; waiting for her complete-head pin before tools.
Webby webby-0253 (static, cef503cb9) closes E4 per mos-1520; no tests ran. N1: a failed notice insert throws from onPushed before publication, so served stays at the prior commit until sync; the store-failure test pins this safe direction. Only E5 (284 tools/snapshot integration) remains open in this early review.
## 2026-10-23 complete284 merge and final tool integration (unrun)
Della della-0037 supplied complete untested head47db04eba85ac3ceb7e81385603f97bb6f8c1a38,
replacing the incomplete head. Merged intact as c0ca3894c. Its22423816cf28 and2164f3fbc25a
lineage is retained. Three conflicts were in overlapping production wiring only:
- broker.mjs: keep Della's LIBRARY_LOOKUPS object and #requestLibraryLookup byte-for-byte, and
keep288 writer/notice methods; LIBRARY_VERBS contains both sets and request dispatch calls lookup.
- runtime.mjs: keep lookup adapter plus288's metadata log and write adapters.
- library/index.mjs: keep index/query exports,286's push/humanCredential exports and288's writer exports.
No dependency test body was changed in the merge. These are overlapping consumer integrations,
not rewrites of dependency commits. Every prerequisite still needs its own gate (mos-1351).
Added library_doc_write/library_doc_delete after the five lookups, only for a creative definition
with a within-role library.write grant and library enabled. Closed schemas carry exactly
{universe,path,base,content} and {universe,path,base}; base is string-or-null with 40-lowercase-hex
pattern. No project, business, author, credential, commit or message. tools.action is library.write.
New harness/tests/library-write-tools.test.mjs pins per-role eight/ten names, both schema invariants,
no repo/commit/business/accept, exact required/verb/action, nullable base, and missing library/grant
or noncreative exclusion. This satisfies sage-3678 and mos-1523's replacement coverage condition.
Publication's narrow helper now calls indexFor for the new served commit instead of only readLibrary,
so the284 lookup index is rebuilt before publication. New broker integration uses library.get's
served blob as write/delete base, independently checks served:path, reads the new text/blob immediately,
preserves default-canon null, then sees null after delete. No change to284's query behavior.
### Authorized baseline-test migration, own commit (mos-1523 via sage-3677)
File: packages/harness/tests/library-tools.test.mjs. Numstat: +4/-4, exactly.
The noncreative LOOKUPS assertion at :33 is unchanged. Every existing lookup schema assertion stays.
The four old/new lines are:
```diff
- ? ['web_search', 'web_fetch'] : []), ...LOOKUPS];
+ ? ['web_search', 'web_fetch'] : []), ...LOOKUPS, 'library_doc_write', 'library_doc_delete'];
-test('M3: per-role snapshots contain six names, or eight with the C2-08 web grant', t => {
+test('M3: per-role snapshots contain eight names, or ten with the C2-08 web grant', t => {
- for (const [i, tool] of tools.filter(t => t.name.startsWith('library_')).entries()) {
+ for (const [i, tool] of tools.filter(t => LOOKUPS.includes(t.name)).entries()) {
- assert.deepEqual(tools.map(t => t.name), ['send_message', ...LOOKUPS]);
+ assert.deepEqual(tools.map(t => t.name), ['send_message', ...LOOKUPS, 'library_doc_write', 'library_doc_delete']);
```
Additional schema mutant (mos-1523): add `commit: str("caller commit")` to writeBase in tools.mjs,
thereby adding it to either/both write schemas. The new-file schema test must fail both its exact
property set and forbidden-property assertions. Run on CLEAR and restore. No further assertion
change in library-tools.test.mjs is authorized or made.
All code/tests/mutants remain unrun. No Node, build or syntax check before Sage's named CLEAR.
Static diff --check is clean. Scope additions stay listed above, now including indexFor import and
call in the previously approved narrow publication helper. E5 implementation is present; review and
acceptance are pending evidence, not claimed complete.
## 2026-10-23 testing and landing boundary (sage-3682)
Latest complete dependency2845d587a552 (test/docs only over47db04eba) merged intact as f8f79ea2f.
Own tool implementation cd2f50dae and separate mos-1523 migration29455c0c5 are pushed; Webby reads
E5 and Dewey checks the migration. Static manifest-r1 covered21 own paths at f8f79ea2f.
Sage reserves first focused runs/RED-GREEN/mutants for T7, provisionally about22:25Z, unless he
explicitly frees an earlier lane. No Node before his CLEAR. This is a schedule, not CLEAR. Full
library/bus/harness and shell gates still need their own authorized slot; no gate result is claimed.
Before the gate, incorporate landed refactor after283/224/284 land while preserving every
prerequisite. Under the standing add-commits/no-force-push rule, update this published branch by merge
rather than rewriting its pushed history. 288 lands last in the chain; no landing is authorized here.
## 2026-10-23 E5 static closure and N2 wording
Dewey dewey-0948: the mos-1523 migration at29455c0c5 is static CLEAN, exactly+4/-4, with the
noncreative assertion unchanged and new-file schema coverage meeting every condition. Webby
webby-0263: E5 closed on29455c0c5/cd2f50dae (f8f79ea2f;98ca25ab1 only BUILD.md), nothing blocking.
Both ran nothing; Webby did not read the scratch manifest, so no manifest verification is implied.
Webby N2: delete inherited the write base description "or null to create". Delete now overrides only
that description: "The existing file's blob from library_get; a missing file cannot be deleted".
The reviewed nullable-base schema/required keys/verbs remain unchanged. The row's new schema test
pins create wording only on write and existing-file wording without create on delete. No further
assertion change in the baseline library-tools.test.mjs. No Node/tests run; still await Sage CLEAR.
## 2026-10-23 dependency283 follow-up (honker-0195)
Merged origin/honker/row283-build b2a1f4092 intact, fast-forward lineage from46bad7ea3. It changes
supporting.test's helper and Honker's BUILD receipts only; no production source changed. Honker
reports library98/98, business231/231 and14/14 mutants killed on that dependency head. Those are
his dependency receipts, not verification of288's combined branch. No288 Node/tests run; Sage's
CLEAR is still required. The dependency's own gate/landing remains Sage's responsibility.
## 2026-10-23 new candidate after283 landing (sage-3727, honker-0200)
Created bubba/row288-r2 from the preserved published bubba/row2887c53adf10, then rebased with
--rebase-merges --no-update-refs onto93694c5185d0a7f989d2fe78fb620e44599b744e. This supersedes
the earlier merge-only refresh plan for this candidate: Sage explicitly requested a fresh branch,
not a force-push. Both local and remote bubba/row288 remain7c53adf10, unchanged.
Git skipped12 duplicate283 commits already replayed upstream. Range-diff of
45dca69f6..bubba/row288 against93694c518..bubba/row288-r2 (before this receipt) has35 equal
commits,12 dropped,0 modified,0 added. Full output: scratch/bubba-row288/rebase-r2-range-diff.txt
under /mnt/storage. The other prerequisite commits retain their patches; row216/224 identities are
unchanged where Git could retain them. This is not new verification of any prerequisite.
Replayed merges had the same launcher-footer and broker/runtime/index conflicts as before. Reused
the exact previously reviewed combined file bytes, keeping both launcher test bodies and all lookup
and writer paths. Static comparison before this receipt: all21 own manifest paths byte-identical
to7c53adf10; all16 other changed paths exactly match93694c518 upstream. These include newly landed
226 and coordination/docs changes already on that base, not new288 edits. No baseline assertion or
production change was introduced by conflict resolution.
Sage's base93694c518 is an ancestor of the candidate; old283 b2a1f4092 is not. Static diff --check
clean. No Node, test, syntax, build, mutant or gate run. Named CLEAR/T7 still pending;288 lands last.
## 2026-10-24 static preflight before landed284 base (sage-4282)
No Node, npm, test, syntax, mutant, queue command or gate ran. Still on bubba/row288-r2,
b44152ac6 plus this static follow-up; await Sage's landed284 base before a fresh candidate branch.
Do not treat the earlier T7 estimate as CLEAR. Webby remains reviewer.
### Updated C2-02 brief and contract names (webby-0282 N1)
Read C2-02 on origin/refactor 95d4991d20a4ef291c824d37c886eaeaa9be7062; current brief blob 85e6fe2ecfc53ed615b7b61aade88ae0cbb222ef
(the new ruling is identified by Sage as5e8a720b). Statically checked both the candidate and current
refactor versions of all six creative contracts: roles/companion.md, research.md, ideas.md,
proofreader.md, fact-checker.md and continuity.md. Every one names library_doc_write and
library_doc_delete, exactly the two add() names in candidate harness/src/tools.mjs. No role contract
change is needed or made. Exact-name evidence is tool-contract-audit.json in the scratch dir below.
### mos-1584 fixture audit
The new row288 harness tests reach businessDoc through resolvedFor, but their callbacks add only a
creative role; they add no library business project. library:true is the typedTools option, not a
businessDoc project. The broker/runtime/bare-library tests build minimal business objects directly,
not businessDoc. The migrated baseline harness test likewise adds no library business project.
There is therefore no new row288 businessDoc-with-library fixture requiring a chief-reference edit.
The current and future landed-base imported fixtures must be rechecked after the pending rebase;
any validating businessDoc fixture that adds a library project must retain/provide chief gitea.
Shortened only two row288-authored fixture credential values: write-fixture.mjs uses fx288-write,
and the runtime test's two slots use fx288-human. Both are11 characters, below24. This corrects the
25-character runtime value and avoids an edge at the older23-character write value. No assertion
changed, no baseline test edit and no credential file was read. No live credential action occurred.
### mos-1612 whole-file run-list preparation (not run authorization)
Static lexer traversed real import/re-export/require and new-URL module-entry edges, skipping
comments/quoted fixture code; reverse closures carry a chain witness for every selected test.
Used the union of this older candidate and the current refactor source snapshots so newer importers
are visible without prematurely rebasing. It selected270 whole test files. Required whole library,
bus and harness suites add17 distinct files, making a proposed union of287 (not a narrow grep list):
bus115, business2, cli58, harness16, library13, plugins1, processing-control1, seat5, tasks9, webui67.
The brief also names all12 scripts/test-*.sh runners. No file/runner was executed.
packages/cli/tests/case1-accept.test.mjs is explicitly excluded under mos-1592/1612. The11
nonliteral-import files have a manual expression audit; all already occur in the import-selected
whole-file set. Generated programs and runtime plugin discovery are recorded static limitations,
not asserted fully resolved by the lexer. Whole suites and the named script runners retain their
brief-required coverage. Regenerate after landed284 rebase; report exact final sha/list before CLEAR.
Each approved gate later needs own root/webui npm ci, required editor build, short scratch TMPDIR,
whole files and gate skip receipts under the then-current rules. These are plans, not past evidence.
Artifacts: /mnt/storage/scratch/bubba-row288/static-2026-10-24/
- import-run-list.py SHA256 ec18031c87bf6f96b3e794e2e56747bc5e1fe37580de7ce9444c60cd5f18ddc0
- whole-files.txt SHA256 b2d6c11349268c347e51a64fe6bf9e7c4d560238a8fc5b5e10f600f1e6e8a39e
- import-witnesses.json SHA256 01702657d34c4f2c0635f38741d0a5b57cfdda63d5e96897f188d03971afd5d9
- dynamic-import-audit.txt SHA256 42b8721fde783c618e1347f2609ad6e4ae3144f563272f0bbbeb45c34f751018
- brief-required-whole-files.txt SHA256 254828414cd9b1b0a785df5c23b7f2b9ea7564d1f85e648899801e46194d135f
- proposed-whole-files.txt SHA256 bee666dce2c3f2d0bafe7e963fb443ad356b6ae8719ac3cb8ee413a329578035
- brief-script-runners.txt SHA256 02cd25af486c163189977106e055575145bffba688c7836e2a508f5ec91e76d4
- tool-contract-audit.json SHA256 bf07865d796b8b0aed85d84c015430ea03468c5331bcaae9eb80efafe1a182be
- fixture-audit.json SHA256 436a69a6b8548d8426390e867ed4b0f83693a3116d825c26c6f8a3e788f477d6
## 2026-10-25 landed-base transplant (sage-4338), UNTESTED
Named base: 78b69e1e68b2b8a9dc4c02564381a0792c0c7549, including landed284 ce0b6ed41.
New branch bubba/row288-r3-landed; published r2 e7c31a90d is untouched.
The initial --rebase-merges replay tried to reapply already-landed285 and conflicted;
aborted without resolving those conflicts. Transplanted only the twelve Bubba nonmerge
commits, in order, onto the named base using cherry-pick. No dependency commits replayed.
Conflict resolutions (no test conflicts, no assertion changes):
- BUILD-LOG.md and docs/SESSIONS.md: preserve the entire upstream side, append Bubba entries.
- broker.mjs: retain landed LIBRARY_LOOKUPS and lookup dispatch, add writer verbs/methods;
retain the complete landed library.status replyLimits branch after writer/save/revert dispatch.
- server.mjs: retain landed refusal envelope including reason, combine project/library save detection.
- library/index.mjs: retain every landed export, append the writer exports.
- webui cli.mjs and console-bus.mjs: preserve landed libraryRevert and add librarySave alongside it.
- runtime.mjs (notice follow-up): retain landed lookup adapter, add metadata-only log sink.
All other changes merged automatically. No business role/vocabulary file or dependency packet changed.
Baseline test migration remains packages/harness/tests/library-tools.test.mjs +4/-4 (mos-1523).
Only additional own-test edit removes a trailing blank EOF line in write-fixture.mjs.
Line-reference recheck: the sole explicit source-line citation in this append-only packet,
noncreative LOOKUPS :33, is still exactly line33 of library-tools.test.mjs and unchanged.
Historical fired-chief path4308 described an older broker; current fire.stopped/fire.done are
broker.mjs5126/5147 (firing detection863-865). Those historical receipts remain historical.
Old head/brief identifiers and T7 times above are historical, not the present base or CLEAR.
Final import-list audit uses candidate + exact named-base import graphs, eleven changed source
modules as roots, and all touched tests; no text grep selects a test. 272 whole files selected,
plus17 brief-required library/bus/harness files =289 files. Package counts: bus116, business2,
cli59, harness16, library13, plugins1, processing-control1, seat5, tasks9, webui67.
All12 current scripts/test-*.sh runners retained. case1-accept.test.mjs excluded explicitly.
The eleven nonliteral import expression sites were rechecked; whole parent tests already selected.
Generated programs/runtime plugin discovery remain documented static limitations.
Artifacts and chain witnesses: /mnt/storage/scratch/bubba-row288/static-r3/.
No Node, npm, test, syntax check, build, mutant or gate run. Pending Sage CLEAR.
## 2026-10-25 first CLEAR and delete-path RED/GREEN (sage-4396/4398)
Own root npm ci rc0; own webui npm ci rc0; editor build rc0. Fresh TMPDIR from mktemp
under /mnt/storage/scratch/tmp. All Node whole-file runs nice19, timeout600 kill-after10.
Initial own write.test.mjs rc1,10 pass/2 fail: delete and revert-to-absent hit library-git.
Isolated bare Git confirms update-index --force-remove rc128 (requires worktree), while
--index-info rc0. First replacement and two delimiter-investigation reruns still rc1,
10/2: runGit's stdin argument names an input FILE, not input text. No pre-existing test
ran or was edited. Final correction writes a private NUL-delimited removal record in the
already-cleaned staging dir and supplies that file to update-index -z --index-info.
Whole write.test.mjs now rc0,12/12,0 skipped/cancelled. Source-only fix in owned write.mjs.
Logs remain /mnt/storage/scratch/bubba-row288/gate-r3/ (write-fixed through write-fixed4).
Sage4398 authorizes this fix and requires committed new candidate + driver restart from
first whole file. Focused green is not the complete gate; remaining acceptance pending.
## 2026-10-25 new broker-fixture RED/GREEN, driver restart pending
Candidate7932c979a driver first library file rc0,12/12; second own bus library-write rc1,
0/14 (fixture FK and undefined dataRoot). Own fixture lacked gitea_users parent; insert
with valid16-hex nonce, consistent with landed credential tests. First attempted fixture
nonce was invalid and INSERT OR IGNORE hid it; corrected nonce, no product/schema changes.
Every bare.dataRoot reference was undefined: use bare.context.dataRoot. After these fixes,
whole file rc1,13/14, last assertion assumed lines were strings; query returns [line,text].
Corrected this row's new assertion to exact [1,'new served text']; whole file rc0,14/14,
0 skipped/cancelled. Intermediate logs bus-fixture-fixed{,2,3} under gate-r4 retained.
Only owned new bus/tests/library-write.test.mjs changes (+14/-12); no pre288 test changed
or failed. Commit this fixture correction, then restart all289 whole files from the start.
## 2026-10-25 creative typed-tool fixture RED/GREEN
Candidate4fb11e74a restart: library write12/12 rc0; bus write14/14 rc0; own harness
library-write-tools rc1,0/3 before assertions: new creative role fixture omitted the
Gitea credential reference required by landed285. Added the same fixture reference copy
as landed library-tools.test.mjs (no credential file read); no assertion changes. Whole
own harness file now3/3 rc0. Only new owned test+BUILD changed. No pre288 test failed.
Commit and restart driver from first whole file again; gate still not claimed green.
## 2026-10-25 completed candidate gate (sage-4396), SLOT RETURNED
Tested candidate2848d832e (three additive fix commits after requested8a47c462a).
Driver restarted from first whole file after EACH fix. Positive gate-r6: all289 whole
files rc0,2604 pass/0 fail/0 cancelled/1 deliberate FED R7 skip. Full required suites:
library168/168 (13 files), bus1035/1035 (116), harness180/180 (16). Other selected:
business25/25, cli619 pass/1 skip, plugins8/8, processing-control7/7, seat69/69,
tasks95/95, webui398/398. Case1 acceptance excluded. Final import graph regenerated on
2848d832e in static-r6: whole-files.txt byte-identical to static-r3 selection.
All12 scripts rc0: test-auth,conductor,config,discord,extension-package,
federation-acceptance,foundation,land-work,push-check,queue,release,task.
FED R7 dedicated runner covers ordinary-suite skip. Queue wrapper28/0 and node156/156;
canonical-root verify/render check deliberately skipped in this linked worktree.
Root/webui own npm ci and editor build rc0 before runs. All tests nice19, sequential,
whole-file timeout600/kill-after10; scripts timeout1800/kill-after10. Fresh mktemp TMPDIR
/mnt/storage/scratch/tmp/ for each restarted driver; no /tmp test root.
Six mutants killed (each rc1), restored positive whole files each rc0:
- M1 supporting checks removed: broker M12 refusal assertion.
- M2 forced push refspec: unrelated-blob retry/new-parent and guard assertions.
- M3 forged owner token: missing expected rejection in exact-token test.
- M4 beforePush grant recheck removed: held-during-fetch expected rejection.
- M5 notice after publication: E4 exact notice and failed-store assertions.
- M6 caller commit in schema: exact property-set schema assertion.
Source SHA256 restored after every mutant; git status clean afterward.
Captured logs across all four run attempts scanned for both fixture credentials:0 hits.
No pre288 test failed; no pre288 assertion changed beyond approved mos-1523 +4/-4.
Per-run rc and log hashes: gate-r6-results.tsv; counts: gate-r6-summary.json in this
packet. Full logs, mutant diffs, drivers and JSONL receipts under
/mnt/storage/scratch/bubba-row288/gate-r6/. Earlier RED/intermediate logs retained in r3-r5.
Slot-returned report sent to Sage as bubba-0034; no further tests after slot return.
Review notes to carry into request (webby-0296): N1 baseline library-tools.test.mjs73
still says tool names unchanged while the pin gains writer names; retained to honor the
narrow +4/-4 permission. N2 librarySave is dispatch plumbing only; C2-11b owns the route
that consumes it. N3 sync comment omission is cosmetic and unchanged from reviewed r2.
Commit-count correction: r3 initial head8a47c462a had13 commits, twelve transplants plus
receipt (BUILD +36, SESSIONS +2, fixture EOF -1). Current tested head adds three fix commits.
Formal manifest review/gate acceptance and landing remain Sage/Webby stages, not claimed.
@@ -0,0 +1,308 @@
kind name rc restored_rc log_sha256
whole-file packages/library/tests/write.test.mjs 0 e0f6a09b70316beebbf33966b35bfd05b4a12b587744dadc9239bd28de1b976c
whole-file packages/bus/tests/library-write.test.mjs 0 e0e9e609b20ea0564a7611046026cbdfd007832e0eb13507798e958d8d106ef0
whole-file packages/harness/tests/library-write-tools.test.mjs 0 c8a3a493d1d2abce785e94fdda5b1732e8d4a5e6eb19767af1b7e8b5e560cf3b
whole-file packages/webui/tests/library-write-options.test.mjs 0 2491eb6a01a0b4b2127bcb6a87a5dc778d079b7d1ea445509a1dffc49dea9051
whole-file packages/bus/tests/access-revoke.test.mjs 0 a1b317bb687e8c369440f5481b4ef309615afb5a5922fa306980d2024019e544
whole-file packages/bus/tests/account-migration.test.mjs 0 e697b58a1bb9b37c609b441fe786e557c7f0279e7a31eea791483ce4567db318
whole-file packages/bus/tests/address.test.mjs 0 977f755d29a8e75578d0bef48ec40b7045736014b2e53e15a03cdb6dd39696d8
whole-file packages/bus/tests/agents.test.mjs 0 3e8116bad1ab5594e627ba3e9f5403414885959935bcd9e6f75f1af4c625d4b0
whole-file packages/bus/tests/approval-binding.test.mjs 0 d2fbee516b57857f3a6562427d2a08bd7fdb772aacabd33ebd9d2990f01ec7fa
whole-file packages/bus/tests/broker.test.mjs 0 400e7f0616bc7432d8cb2a9efbae3c84d5b44ef59ce7f8fbebd4c802e2a9f44e
whole-file packages/bus/tests/business.test.mjs 0 f42502884a158ed1d190b37b3884e19d44547ececf068f91765b8ad15faffba3
whole-file packages/bus/tests/channel-proof.test.mjs 0 3984a7e2da2a60e60d0309f719a45a3ef04bca767bac34e00a760e19e941d732
whole-file packages/bus/tests/chief-of-staff.test.mjs 0 8dd57acf0101d4c92ada92f4c33f68061d4e2cb430179a8ab99a0b7fc9a19997
whole-file packages/bus/tests/citation-availability.test.mjs 0 d34d84d44b5949024ce6b32708c68e10b00a84600bb03598bf9538b358750455
whole-file packages/bus/tests/citation-guard.test.mjs 0 acab66e65fd41f1fbfd9524f80456553fc033d8bfc18a9bec7a813bd0d4552d8
whole-file packages/bus/tests/citation-runtime.test.mjs 0 ce33310d333c7a0af7451c3a3b610f5178961b80b6b63a839909b67657fd161e
whole-file packages/bus/tests/comment-cursors.test.mjs 0 cd4de90a070faf2bdb776a96a6ba43aa4854f6f5f1b2b7459740bd7bdc0ffb7e
whole-file packages/bus/tests/comment-migration.test.mjs 0 773659855873805b5bd950101d950945213658fde42d8012211e742ba9ddcc09
whole-file packages/bus/tests/console-decide.test.mjs 0 275fc0a24a03f2f27210a65e2bd21ce615ec9b6b400c4e4177ddb97a9e8e85be
whole-file packages/bus/tests/creative.test.mjs 0 eb950d5680ff7e4e09a9c11b1c169d4a740011ea72bb75921d35571ef5373df2
whole-file packages/bus/tests/credential-claim.test.mjs 0 b2d40e4d2a353f4154af4974d5779f7b20c652a8110da3183f95959ae2540941
whole-file packages/bus/tests/credential-status.test.mjs 0 ed367e3d123c9629b7d3d22f6fa60f48c74e71b36982c54ad2b3e8419f515431
whole-file packages/bus/tests/credential-store.test.mjs 0 0fd528ba27757393973cba5b21da573bc681659416962bf7d3a3dff3018414af
whole-file packages/bus/tests/credential-verbs.test.mjs 0 154b123af420abf08c6ab8b7bc6439052e7ab65c772abb0caac5e9b9cd3608e9
whole-file packages/bus/tests/credentials.test.mjs 0 6474b45c076f474a6881d0dddd0cd3b4cd385d52ac4c55ef1a9f8c10e0028277
whole-file packages/bus/tests/csuite-messaging.test.mjs 0 c0229df65240be8ad014d83def48dbd64a952b701f46e40ff01efdebb5644d6a
whole-file packages/bus/tests/daily-quota-runtime.test.mjs 0 62d686aa1852088af569cd3b921194db6873311f2ba04e55b15a93900b1615cd
whole-file packages/bus/tests/decision-close.test.mjs 0 9599744860a4e6e330ce50b8e93c478546edce5545a9171bed068743a266ae5c
whole-file packages/bus/tests/decision-route.test.mjs 0 2b2a9570dab83b1d454f56c1311cb41103a14bcff49e207cbb4ac5d4c73d6f0f
whole-file packages/bus/tests/decisions.test.mjs 0 a753df7d939155adf13c7177926728b2760cf61770117dd1655f29fe2c88a26f
whole-file packages/bus/tests/end-launch.test.mjs 0 ff7a27c35e35be424cbefa799e219ffc073c494214642b4ce56ceed6b359335e
whole-file packages/bus/tests/fire-revokes-grants.test.mjs 0 8e6bee9421480af8a1326d65903f258d5ea0a79df6188bf18301f32a5260547e
whole-file packages/bus/tests/gitea-grant-docker.test.mjs 0 8b639ee86d1a7d2ef267e1d36264f4ce1b5beed2c8ce084c39c0de1d699ca8a0
whole-file packages/bus/tests/gitea-grant.test.mjs 0 8fa39b3e58cfac4ec97f02ff876fde1a40a1894c826306c0b77d45c73586f753
whole-file packages/bus/tests/gitea-migration.test.mjs 0 689fb43a38718f5f5d00ffb3b6d998d5d454854d5e77a936b56d7c4192ee12e9
whole-file packages/bus/tests/grant-enroll.test.mjs 0 a8be59931d37a5c787c2087d29d766d6b701bbe34f8343134148292cd29d345c
whole-file packages/bus/tests/grant-executor.test.mjs 0 0a7f5be29b28140c9f8e7f67c6a897eb455677fba4459952a83982f2b23c87e0
whole-file packages/bus/tests/grant-host.test.mjs 0 54c4ed722116914221e9320fd41723e32aad59284e98d8e177130b0f4c4fe6c4
whole-file packages/bus/tests/grant-migration.test.mjs 0 7cfaa3f24d1dc070d7bdb8de76b08fabcdb6877d3367c59f7601e08f683d658b
whole-file packages/bus/tests/grant-scope-runtime.test.mjs 0 f8bccf5324f1e10282dfb4f4fd0f63c76c8e9481ae6cc0845a1d9028e3d9633e
whole-file packages/bus/tests/grant-scope.test.mjs 0 e30a8ced066ad214a6f70dd4a39c75bacf296032a3201e4605fa3c8df23e0159
whole-file packages/bus/tests/hard-waits.test.mjs 0 78d92a14781286d3ca11989786a8698a2b796ad1db78769fd5b3c7653ad7639e
whole-file packages/bus/tests/host-run.test.mjs 0 51d231611940444d2c2a37fbb7b14267c705c1b5e453b02367d0a6def214dc93
whole-file packages/bus/tests/host-tools.test.mjs 0 3bc5b5413661edd2026bca1721055ec7dce8d115918cc10c8f334e527176d23b
whole-file packages/bus/tests/human.test.mjs 0 5c8f3fd402ae4e130029b3203ed41b3cb45b8781417d31dec1f47ebddd516349
whole-file packages/bus/tests/instances-verb.test.mjs 0 940ca3884930f539272a2c39ca7e1c7fa3e51b3a4ea6fdcfb21719c652152257
whole-file packages/bus/tests/interpreter.test.mjs 0 d0c6190a428005b7750b59e665968657b242b322af05ca7bdd4cd7e815b7f4ab
whole-file packages/bus/tests/land.test.mjs 0 e9ecd1d8011ab6789fc3254bb069e76631b68b20ad65ae844ee12e0dc3b97cb0
whole-file packages/bus/tests/launch-notice.test.mjs 0 750a54d4c40559c7fb5414071bace8056d6bfa71dfdbec4de12c94c90299c3c5
whole-file packages/bus/tests/launcher-released.test.mjs 0 4d59486ca3077a4b2f51141ab79df635feb6b7bca2d6c0cfe5839a6a93715de6
whole-file packages/bus/tests/library-credential.test.mjs 0 db7e2dc4afe23f74c49795e4dcd3d28414435519029a837641cbb35bd3f4fcef
whole-file packages/bus/tests/library-lookups.test.mjs 0 fa18b5d4c829ec35ebbf519c4346a2ac38cff7538d58ea663acbbdd7930a6015
whole-file packages/bus/tests/library-sync.test.mjs 0 ee0ab1ad2549d3e6ae6d8123fa99d697d9be6c629e09131da82f0ab6d58a60e2
whole-file packages/bus/tests/library.test.mjs 0 62b663034a5de8d6d1abfaf3f94327d7aae435e3350874b424eefdb28bca1bd1
whole-file packages/bus/tests/lifecycle-revoke.test.mjs 0 c0810c743b5108773b6cfbc2d108fa09ea274c437433355277ce2b1295fbf692
whole-file packages/bus/tests/lifecycle-verbs.test.mjs 0 926bcfb20ab58a4ecbe85b4f8feb915f72adcdc6d6aee84f814187d0ac998efd
whole-file packages/bus/tests/limit-checks.test.mjs 0 919d745dc570172716b1e06d0ea1e8f16ae7b05dbadba77fe92dbbcc8eb4cba7
whole-file packages/bus/tests/limit-stop.test.mjs 0 2fc1ebee4e4d4862a100ed9ba97ace1e6d3fb3c608abea63b1ff634a04d5649a
whole-file packages/bus/tests/limits-runtime.test.mjs 0 5845176b73f98a499d92096ce0d22a3987ada664a529bdbb26230c2d00b9e65c
whole-file packages/bus/tests/limits.test.mjs 0 333f6757d9d00eda74e7d4641af660c9a0ce3d978e6a8550139d3a461c1d5866
whole-file packages/bus/tests/message-citation.test.mjs 0 38422c1d6faf076c750c3fccb7e927e38fe955cc28778511acccf5704df5b191
whole-file packages/bus/tests/message-filter.test.mjs 0 2ba52728df27756ac19ba65fe0705e7cf7a2a786a3b4df77a4eb4eec8072604c
whole-file packages/bus/tests/messages.test.mjs 0 b87de4ab04682d59a2faa7b3fc64751247454e628e9c1ebd4c07b1df2acbf11c
whole-file packages/bus/tests/messaging.test.mjs 0 831b48a9de594e17e8fc47f16ab8c2d722e8d57068a7d39deeaf4c0fa8d136bb
whole-file packages/bus/tests/model-proxy.test.mjs 0 99c5128733ae5bb16489171513c158ec1e34dfce1d07c60f6bccb0f84ab7afb9
whole-file packages/bus/tests/name-migration.test.mjs 0 bb8f92a17f6a022c7ec63161cccc0bb49a26c2a591fc369375cbebfa93a277a2
whole-file packages/bus/tests/names.test.mjs 0 0fcf60cc8c7dee3e85548c759f03e1792de92b59131bb9fe4282a3b07859366c
whole-file packages/bus/tests/peer-transport.test.mjs 0 3cb547003e50695ec2a25c950819b304f15203302281c00758a12c9b89b60f40
whole-file packages/bus/tests/peercred.test.mjs 0 e75c700a68ba0c1013c8f36178d6554f0321dc331b2198fd5ffc1a684df76c3e
whole-file packages/bus/tests/plugins-verb.test.mjs 0 359fef350befd1d743bcca89a96ebd0757346fd7c0622ba364039ba827620d26
whole-file packages/bus/tests/principal.test.mjs 0 732724e6bb2bb953e7dbbbae5c23cc0a1c33a7b7b202f5cb8b46be9363bcb392
whole-file packages/bus/tests/process.test.mjs 0 9c5883ea2ca858131317fa9be66d2a51a5d86dbe03c515b0544f4db56b2456a1
whole-file packages/bus/tests/processing-runtime.test.mjs 0 bb6b94ac654d069abd6e484031893e649e239d933c135b226d1cb2fbd5a94ca9
whole-file packages/bus/tests/processing-timeout.test.mjs 0 323036aa7f32f7aa324f61595531a29f3d5ef0ae2c24aec029842f2783d6be76
whole-file packages/bus/tests/processing-web.test.mjs 0 dbd1543498fbc8d0625990436ae668b3a382eedeecd098b929c13d2bb61939ff
whole-file packages/bus/tests/processing.test.mjs 0 529ec93e767444970ff03acb1ba719b45033daac239256c9cbd587c39f926a71
whole-file packages/bus/tests/project-await.test.mjs 0 e948d721ef06ce95f909880942f7e7ebd73b2f42563e1faedacc7b403b8ebedf
whole-file packages/bus/tests/project-files.test.mjs 0 3691b04705c17d4ef7218bc15771560aca5586c00ba0fd3fdf2a80f63d8dc659
whole-file packages/bus/tests/project-runtime.test.mjs 0 9d8d6cedeb2044f19e548dda0e32cae1e997b75a6d89072f7367b6e0ce17a44f
whole-file packages/bus/tests/publish.test.mjs 0 87f7a382580432646ca89d1228377719cb177bfdbb4f74ad617f6a70dbfb4b33
whole-file packages/bus/tests/reload.test.mjs 0 25aa45aca6ba24d72e9e5ad66dfc8c049375c8df121dd748dde09af52f16f853
whole-file packages/bus/tests/replies.test.mjs 0 0f05dc2194896540a1488310107e31b7e779cc02c381c201d0c95f69ab39fc51
whole-file packages/bus/tests/requirements.test.mjs 0 29569dc30659dbecf359117cc9a59ff37927c60f5514b8ceb8d3796c2c3e53d1
whole-file packages/bus/tests/review.test.mjs 0 a8daea8602be9429a8044ad636a438c18eee8ec77b6fa272dce606116d01de8c
whole-file packages/bus/tests/revoke-window.test.mjs 0 1435c543c9367204f4ae6d25c2cb97145e762cb18e78ea90a15eb1672a220353
whole-file packages/bus/tests/room-check.test.mjs 0 bbe5ac7abfb7e1b30f6fc8f9a247cd28aca82a8783753434339b790dd9857e1c
whole-file packages/bus/tests/rooms.test.mjs 0 506fad116ab1d9bb2520fe691adc91ca26e64faa96ced35c193cb11da4e07ccb
whole-file packages/bus/tests/routes-verb.test.mjs 0 c09fef3cb022bf7713cde4e1c512feefe67090eff05451fda9f55272140c916e
whole-file packages/bus/tests/schema.test.mjs 0 2a1a668dc408aaebe6f604ec5c3b8858211edc52930e1a552173cecedf806d72
whole-file packages/bus/tests/session-clear.test.mjs 0 1fce03f1d2a41f5ba294e9d406980a1d3251bc9a5dd4a02897413d6be3d9681c
whole-file packages/bus/tests/session-compactions.test.mjs 0 745510273a9eaaf61de4c6453c5dcc70e4a6020c0bcec69673621eefa593dab7
whole-file packages/bus/tests/sessions.test.mjs 0 d6c0337e0981ecb9aae2e912c27145bbd831e196828b2d59029666ceae5f605c
whole-file packages/bus/tests/single-use.test.mjs 0 6f5cf7d47716ce94eccb069f9b7e5625c3587737921231649fc74e8bfd3aad3c
whole-file packages/bus/tests/spec-migration.test.mjs 0 ede4ca62a772261bc868f4dfcb4861c9c3670110ba2afd39cc44183398c2eafd
whole-file packages/bus/tests/spec-review.test.mjs 0 951aa2a54cfe4bf0960dd3d2180874cb8183ff9b0aee7b7251b05df11385e1a5
whole-file packages/bus/tests/spec-socket.test.mjs 0 65735a2557e19b3d63a3ce7198c80fb5059f1974acd0708a89f192857b43b095
whole-file packages/bus/tests/spec.test.mjs 0 488ab443b41b06b6ae4434f5b2ee8904169aa08ab3527f3ae4c3f438e54f9909
whole-file packages/bus/tests/staff-request.test.mjs 0 edeb4ceffae3af33e330e1fac5d74c4fb1861d52ec5ac5005689791ab74da555
whole-file packages/bus/tests/state.test.mjs 0 3b5f916c494563fc7c18f89450e0cecbbdad8e24680b373e897253b9ea6064fe
whole-file packages/bus/tests/store.test.mjs 0 39d0a4033b89eff9b29ea6dcf6e56696a1d20a41e0e14b4bc8efbfae7962ecf4
whole-file packages/bus/tests/task-page.test.mjs 0 6446cfc1a43cb4206b4130f316251d3d9a820f929a6efc59dc74e7cbe1fbd258
whole-file packages/bus/tests/task-read.test.mjs 0 37134ced43ad5ada4291ad5e3474dcf7063892443b06d54a7456cd4cddb9cf2f
whole-file packages/bus/tests/tasks.test.mjs 0 9d91ee510a7447545c2cf93ae6779544a05e01bb70346e595b91a4800fa42d7b
whole-file packages/bus/tests/tester-threads.test.mjs 0 ff843610e02f20c5e1ab19de27b131ae7cbc3fd87b16d85e68336b5e914ffd77
whole-file packages/bus/tests/tester-writes.test.mjs 0 517c41e666d2c59b7ffb6ddb22898ef58b816bb26eaa47e1ce7508087b607df5
whole-file packages/bus/tests/tester.test.mjs 0 19eff6ddb3aca05ad5c006ac15e7860311f56941055850e86b8075cd39eff0d1
whole-file packages/bus/tests/thread-claims.test.mjs 0 ee146e984bb3ae82ad60f90c83035053ff2966ffea91015b6c3c4f93b7e019bd
whole-file packages/bus/tests/thread-migration.test.mjs 0 1dc2ae4e920d40a6fc2b1033f43ac0a2f766bfb86f07a596a983b9c1bccf87d5
whole-file packages/bus/tests/thread-shares.test.mjs 0 3f99a82e9e4a43fa788ebb231c5e712969809fa83b6ca66f04b8cad13f411235
whole-file packages/bus/tests/threads.test.mjs 0 2e5ba2be69a34c71f41a819c7a5e8615fcd085f847f9aa6d16095b9c8d742552
whole-file packages/bus/tests/transport.test.mjs 0 c9d28b9acfc0c2213838df0d960506156ef6fffec24a0cee7336324f105fac0e
whole-file packages/bus/tests/usage-broker.test.mjs 0 26fc080c6ffcb7c64cca39a07f302b59c21d1425ca3c90120eb3d3bb751c49da
whole-file packages/bus/tests/usage-migration.test.mjs 0 cfc65c4233aedb325293170e782ccb83fcfdd85cc4afed1e913e91785fa4b7cf
whole-file packages/bus/tests/usage-runtime.test.mjs 0 faa5fce30cbd7002137acfca3cde68b49b74321fb27b8a190736b35601430866
whole-file packages/bus/tests/usage.test.mjs 0 d36d21e0b3f5c9621b50e8b71ff6d8daa341f5954f3612b7cc93cb6c734215c0
whole-file packages/bus/tests/user-principal.test.mjs 0 1b56d881de2975ec4e3bc27fa15bc495ae0600709457da579337f0c9c98651e5
whole-file packages/bus/tests/viewer.test.mjs 0 942ba4fd96c3bb4c527eb129e69ddb5cb7660915e8458cfee47661d268db0e24
whole-file packages/bus/tests/web.test.mjs 0 048e3ef2840934f95d7e00de6502b19342215cfe5d00d1b8ada7c1bc6e87cfa1
whole-file packages/bus/tests/workflow-roles.test.mjs 0 1bed1351ec3c50ddce65f9b8108f93a5c4061ef5cf36f3d09706d85b13e085ed
whole-file packages/business/tests/case1-business-file.test.mjs 0 4481abbce73eae119fbedc5edf65120fa494931913aac6f0273b04263c251cc9
whole-file packages/business/tests/launch-settings.test.mjs 0 540f5170ddc7e79a8abd9584c4586eade3ecc1f7544489060db99552c75e4685
whole-file packages/cli/tests/access-boot.test.mjs 0 e41e1f1949d3568f8845234d573282c18a185578389d6947140cf540d7f99dc8
whole-file packages/cli/tests/access.test.mjs 0 9e2a813092ad4b60cd89443424eb4142f217265e52ff7b769b7f16d247d5a367
whole-file packages/cli/tests/app.test.mjs 0 5f5244ba0061dc4ffd1565c4abd3168d7cb2e6398625b69c841a54544b9a35a7
whole-file packages/cli/tests/boot-status.test.mjs 0 ca090577e20ea46315cb377668e309571380e2323c867a8b90d0537022e681b7
whole-file packages/cli/tests/case1-hostcheck.test.mjs 0 403e1127da5637904e8fe1c1eed5a7865c5bd5ee1c5d0fe684837a7370c41de4
whole-file packages/cli/tests/case2-install.test.mjs 0 df8edefe13297ced929d09f01eec5c7ecf38c355d9871368cb19f2f392ae057a
whole-file packages/cli/tests/case2-persona-import.test.mjs 0 5dc7a93c03567ec0e85e43bcafe07109881c30b2e83b4c4eab4631a155daece0
whole-file packages/cli/tests/case2-unit.test.mjs 0 39b349dfd3125e74b780ce28e9ec24465a6a8c2bb9e431c819864f4eff1fdb77
whole-file packages/cli/tests/channel-cli.test.mjs 0 9fd9c30aa604f77b7a069912cb987293af36f2f138cce850f8d26946f5ce42cd
whole-file packages/cli/tests/channel-recovery.test.mjs 0 52c6bd980cd54ef22b9e6c78260a1e389e8177526340129ac64fbafa7f2e01ab
whole-file packages/cli/tests/cli.test.mjs 0 59327fd89e3fb8f927210df6a2c62afe4522e59f59129b1967be2a238c498f26
whole-file packages/cli/tests/compactions-launch.test.mjs 0 c9006b3039a6616be1816f5ce85bf68ba4fb54dadf10447e52fc92f7ed57bbe5
whole-file packages/cli/tests/config.test.mjs 0 35e39fb0551e23f5738d0c30d66bd233f2290040885c511e526f0f0468b31cad
whole-file packages/cli/tests/credentials.test.mjs 0 2b55cde2318a034ec4152e712863ac54f07f1b4db752c6282507d7f621bde67d
whole-file packages/cli/tests/federation-acceptance.test.mjs 0 cca971a93a5dfd20e603b45cc2158b58ea0638e8bb7a33e6e0c5e12178ffa3df
whole-file packages/cli/tests/follow.test.mjs 0 26a3ad0dbc124aff48a5f4908e3d8b78cb871e5560c0e389de457f58aea2dfe3
whole-file packages/cli/tests/git-socket.test.mjs 0 10c21c34a79ebd5f89f6ed9182a492e9f42f0512a68f758c0566a763a84abeb9
whole-file packages/cli/tests/grants-scope.test.mjs 0 37967ca8e82a89a0e88ed872fa562b5c094282cc759853b6dc31c292204bef3c
whole-file packages/cli/tests/grants.test.mjs 0 687af745932625ea1d439a8139c760f14b4a327bf9b15c5b5b1cdbc7ea6be09f
whole-file packages/cli/tests/host.test.mjs 0 50010e97e44392f28006bbd4127146b8aa1712ff4a016ca10864923701213dce
whole-file packages/cli/tests/hosts.test.mjs 0 d5d507c3968c45b2aa25067d6bbb1eedd69785c0aa1bb51177c63b6ad64fcb53
whole-file packages/cli/tests/idle-stop-race.test.mjs 0 8e6171855003b0f40921863430dc89cf20f8bbf14a9ce3c115f90486f08232b5
whole-file packages/cli/tests/instances.test.mjs 0 c6b4d59443baa4af029af76a846a8093669a7593490f21408a2c40ad027acccf
whole-file packages/cli/tests/launch-account.test.mjs 0 6cb63446fc8dbb6217e6d925caabb37a28bcf1ea5c27cf8d515d67c7842553b8
whole-file packages/cli/tests/launch-limit-checks.test.mjs 0 fae971d715a90d1dbbeb3c054932a02d253e0a0d036d3b0db4e0c9edcd5ad7ef
whole-file packages/cli/tests/launch-limits.test.mjs 0 d3f4b2c57e776bf6bbcafba6dbd9c4728918b0d81fc606dcd7d2dffefdad4001
whole-file packages/cli/tests/launch-routes.test.mjs 0 e2bec020f96238079908c03537366c64800de0913a83f3a2877606d0266548d6
whole-file packages/cli/tests/launcher.test.mjs 0 beafda99d34a532f3a1d6f96565b7a780e03924939b6c30b01a8169cceaa792a
whole-file packages/cli/tests/lifecycle.test.mjs 0 014a2cea6d3f2a9f21f7fc16dc68b34740b03726612851047b877f8c1194ebe0
whole-file packages/cli/tests/limits-tokens.test.mjs 0 6fdf9e6946dfb579cde42ec500d8cb8473a9d8318f43caecee7561a5e40fdec1
whole-file packages/cli/tests/limits.test.mjs 0 bc2f13959d087ccaf6977c4cf1294e6fcee21f968677ab169580ce79643add18
whole-file packages/cli/tests/mark-read.test.mjs 0 64864c54ab910488d55136b88f351771489cf744ba1c21e5c479121694dd88ab
whole-file packages/cli/tests/model-proxy.test.mjs 0 119a5d02870a4062992efba7f44ee9dfe69ecf8a7076f121aa24a8c7edf24cf0
whole-file packages/cli/tests/names.test.mjs 0 c2160aeb0c68855f59b5d97dc3b6101b7800028df708f5f42430ae5854eb23e2
whole-file packages/cli/tests/notifier.test.mjs 0 18e62f48de18cc4d57916a556adeb3befb13921d5d7b036ef5a7f2bfa460cdc1
whole-file packages/cli/tests/optional-tracker.test.mjs 0 e5adddfee06b2f1cbd2ec50caf84b5acbc58d4ff4ec4c1bc539a4535a3991827
whole-file packages/cli/tests/other-tree.test.mjs 0 2dae57af2b8d508f2792ce37191aebf0cd28ad75f7621d4ab9f8d6daa60b748f
whole-file packages/cli/tests/processing-cli.test.mjs 0 44b2854ba03810cdda3ccf0c6de883f953089d532bfcdc8f4bdd3faffac80fe9
whole-file packages/cli/tests/project-name-repo.test.mjs 0 0468b9ecde6189d1398eef2e7e8043e870aa867a8a9d22b20b2ded26dc1543b5
whole-file packages/cli/tests/project.test.mjs 0 79e648106151ca220d9535b16c416dfdcffffaed41e3c211e4325c151f0775f7
whole-file packages/cli/tests/publish-socket.test.mjs 0 59a02b1fcc284407b06d0d2df8e6e1e5323059daa2e47c690f30a718d1e7c682
whole-file packages/cli/tests/reply-limits.test.mjs 0 554a353d61891c3cbe8da01062025dcb0756ba4f4e7ab3fb8d7b56ceccf64437
whole-file packages/cli/tests/revoke-window.test.mjs 0 743fdb0135e507dea5b968265907e5ac9228284b130feb0057d91e70ad561c02
whole-file packages/cli/tests/session-clear.test.mjs 0 5abbd894dee9cfcb3464a40e5045f9062402d5ffe567972113715cc9e24c6ce3
whole-file packages/cli/tests/session-cli.test.mjs 0 c469aed70c1ae408e176189f23a849f3acf0bfc7dc3ba1132c101a931359a462
whole-file packages/cli/tests/session-launch.test.mjs 0 cde78f9dcee9afa243692fb0493697104425b61589bd7be6c4cbdb0f4bfbd5e5
whole-file packages/cli/tests/stack-copy.test.mjs 0 3b92b3772c060378cd2ec0c1bf7fe6662721721a11d99d83c9debe3e3aa929c2
whole-file packages/cli/tests/stack-instances.test.mjs 0 2839e390f564a6e58cd514ce4061ec0b741ed07b4e2b755a337439737601d97e
whole-file packages/cli/tests/tester-http.test.mjs 0 bd9c598c84dd0be3b9873176c63e418ccc004265153be68e0cbe51c40b1ff91f
whole-file packages/cli/tests/tester-reads.test.mjs 0 50a71ffd9093c4d51d8ad07bc9edbbd76306922f290d28194d656cd78f8528c5
whole-file packages/cli/tests/tester-threads.test.mjs 0 cd3dd0020472c269d61934ddb32d77f6dc297090d63e819288f4038fe9edf096
whole-file packages/cli/tests/tester.test.mjs 0 437498258b4ea5c2f2bfa8fe66114106ac10944911bd40bca944f2078b34e45f
whole-file packages/cli/tests/thread-cli.test.mjs 0 c29897119f279434bec0248c12beb5ce97f6214b8b0bec995061000f047b1600
whole-file packages/cli/tests/thread-launch.test.mjs 0 459ef35e2b4f9cb87151577f252282a716ddbd4985f26e9e26c01b08af13a7f2
whole-file packages/cli/tests/thread-revoke.test.mjs 0 b8a72080a9624ce4bbc1b23b8903be1b74a8a6ced35b0b60f503d92a22d1028c
whole-file packages/cli/tests/trackers-boot.test.mjs 0 f83d72dac4eec7369d62b495745e1fdeeb4ff1ba2e1efb376c9b583da1765a1d
whole-file packages/cli/tests/transport.test.mjs 0 e0ae6c26b5669d4b955deffe941a3c4314be12297e72d6c099de750170688d9c
whole-file packages/cli/tests/usage.test.mjs 0 639ebccda23e0e094d62cb0e7e5c80c403b74b284ac5189fb0d92e63387c92f8
whole-file packages/cli/tests/verbs.test.mjs 0 43eefd242a987efe42d145d7863372a2b0a397031baec12ecd4c9e0644daff12
whole-file packages/harness/tests/bundle.test.mjs 0 75fd5a9a6fa0b46078952ce216348e39ce481f6fc00b89f85da9ff729d5ba100
whole-file packages/harness/tests/citation-runner.test.mjs 0 933021f114882a6c58f4071446a07d49ebc9f99c062ffe1fedc1f13b799db389
whole-file packages/harness/tests/claude-gate.test.mjs 0 f66053597c8209c5175810e33d8b878ad74eb314f4057f5b4b0b1ac625272329
whole-file packages/harness/tests/claude-session.test.mjs 0 9c4d8ffc00efd0da75d143bca1cd33f30f3e762e20086270d941170e80c962ed
whole-file packages/harness/tests/creative.test.mjs 0 3433184ced3427613d645807f0757896baf52d214c3dd6a4a12c3951bbdc50ce
whole-file packages/harness/tests/gate.test.mjs 0 991670779d9cf6f733d0060c6f1a59d122ab8e99f7e0a5f7183c9e974f1b1aaf
whole-file packages/harness/tests/git-tools.test.mjs 0 2837565ec16cd8c4d032311675a1468bc4bc756ee0696d0e57ea35ffd56eea44
whole-file packages/harness/tests/library-tools.test.mjs 0 05a8a5d8e8c4e7b3435d4a9b3f6292816356a99f7156ded2ef7873e1c84f8de7
whole-file packages/harness/tests/mcp-server.test.mjs 0 6ce4c6c39b8a1ed70fbeaca410781a62d69a6412333e03640296048b799a09b9
whole-file packages/harness/tests/pi-session.test.mjs 0 570376f798b43e82bbc1972f1d50d3915e94a8e4ca00e50076ab390df9830d7d
whole-file packages/harness/tests/raise-domain.test.mjs 0 aa6be675614d9324c3ddc01ef40347b235adbccfe6cd73081096ae9e9742d754
whole-file packages/harness/tests/runner.test.mjs 0 d3f8c752897e359e10a8e9d507c10ef3760a5ae37999f6f143cb222c42568437
whole-file packages/harness/tests/skills.test.mjs 0 2f34800387f4d7f8b8d5f6758cd197f77d11034011bf7f4f79f4d74c582e3f0f
whole-file packages/harness/tests/spec-tools.test.mjs 0 29cd1f7094266963a995f636d9575337246a9868d42a48f02231a99251261f47
whole-file packages/harness/tests/tools.test.mjs 0 f27638f1fa38fd2d15a352f6c21f7980688d48d580f5a59dab1520fd7c30b30c
whole-file packages/library/tests/guard.test.mjs 0 6529c2b48c252eeaf9c19487507a03cf46d952e7ffb3a41e640a54590e312df0
whole-file packages/library/tests/index-build.test.mjs 0 4747cb8c842cdc424db727cb3b0e36a6d35f4e9c5c31c1a3bf61314897c2cf6d
whole-file packages/library/tests/links.test.mjs 0 9b89f9275f19035c5f079b6920b248466048626c634153eba2fec165f9f6388f
whole-file packages/library/tests/mapping.test.mjs 0 9110b98f955dd71588357858b913194ccf9e04dca9aa7c4559600cbe9b9e8e71
whole-file packages/library/tests/mirror.test.mjs 0 cc2326da9796dbbbf5b3faa121180a7f00c43816a232a96faece7b58570f1227
whole-file packages/library/tests/query.test.mjs 0 f1209bc132a63cba9a7312cbed7e3098126e05c792356648f1d9ec497a11aa82
whole-file packages/library/tests/reader.test.mjs 0 3e17f34697ae65524cf7908dcc9ca1b24025bbc92989b2ba05f6e75c0f839c3b
whole-file packages/library/tests/render.test.mjs 0 5e68091a309a07e5502b9cc500c7cdfabaa9e246bb77b0c04a0dd86bb9bfcde1
whole-file packages/library/tests/scope.test.mjs 0 f55dec854adcd311d614b66959c5655cb3419d7ae7b06fe1f648b43cdecef32e
whole-file packages/library/tests/supporting.test.mjs 0 2f50bbe9c942360a5becf5bb984ed5aedb12628d4578ea85c6e433ad0ad73130
whole-file packages/library/tests/survey.test.mjs 0 72108eb8a07b990b93ca62c5fa4b55f1f89f3254ca1cf59d3de8ad194dcc3a0d
whole-file packages/library/tests/sync.test.mjs 0 a68c69492149b6e9dc7dbf24fc434ebfd3243b2db2c7654b00107b997e99ead0
whole-file packages/plugins/tests/harness-compactions.test.mjs 0 9eb9f67c06ae17b33198fbcdb443a0c73ca9cc0cd157cae2359a0647d2db3658
whole-file packages/processing-control/tests/task.test.mjs 0 8db6adda6b5d5f7437e9e4cdf961134493409d7227fde02c0b0a76aeb21186f0
whole-file packages/seat/tests/compactions-budget.test.mjs 0 1849994f45bfcccfb4ce18915887c740947a98041aa7bd66590ae7a62fa7078e
whole-file packages/seat/tests/compactions-ledger.test.mjs 0 af689c631c9d62dee11f4400112fd10df82567c1f49d9f0d423b9d19d6f860d7
whole-file packages/seat/tests/compactions.test.mjs 0 cf5e74e1211560ca47a2c13e8002635097f486e2ca06698795bc38263d889f3c
whole-file packages/seat/tests/sandbox.test.mjs 0 c09d89b8e1b22db25578f62cd4a1d3b9f441d652178fb675800efb31de33a577
whole-file packages/seat/tests/session.test.mjs 0 82171646932cddfc68f0e90ca3355f9595d32c5d228c1fdb855c06cb1d9c2feb
whole-file packages/tasks/tests/adapter.test.mjs 0 8843067c21942ae6165a7feaced2382fd9d02d0c62bd30772191393cb5d962b8
whole-file packages/tasks/tests/comment-restart.test.mjs 0 25aa6e953cf19ed3ae368581035b9d883ed924b41d593240e2b4ab5ba39f2982
whole-file packages/tasks/tests/fields.test.mjs 0 e4eafd6b17a46262dddc548263da993bc3a672adca1cadcc698b6d8374f11e2d
whole-file packages/tasks/tests/processing.test.mjs 0 0b89866cc076c43c37534dba926d492d8d334d08a6886325e3d4ac6ddbc88897
whole-file packages/tasks/tests/shapes.test.mjs 0 0b8cc660a07e048d007993d726ae5b8e1f343cb571c18ee0284c3ba0c4b41602
whole-file packages/tasks/tests/startup.test.mjs 0 5b44d779ab4ec86922dd35ce7c78096de02c0a0f2363cc6c2a5ee07816efc2ad
whole-file packages/tasks/tests/sync.test.mjs 0 513ce9f6e64a3fa0179f8cc9b27db671267a43cdc44ab93f38d21982dd2b9631
whole-file packages/tasks/tests/tree.test.mjs 0 d3c8f91f59150259b3226e9306c98efbaf2aa17b5b74cb9b376a103620f8aefe
whole-file packages/tasks/tests/verbs.test.mjs 0 47b075d01ef38a5d0228902a6f9bcfec0b78b1a958cd071e8114139af73bca53
whole-file packages/webui/tests/agents-browser.test.mjs 0 d3ae822399f58d2c4dfd90e054811a60663a66f9d3fbe69a76aa4ce7dc7260d0
whole-file packages/webui/tests/agents.test.mjs 0 be18c8fed41173900617d3b646fac1ce14c07c208e7f24d6567f61f55c5c4dc2
whole-file packages/webui/tests/assistant.test.mjs 0 056e4c2a37b7b395741ed1ba33546031a6e4ca53db843bd877b93bed764e02ad
whole-file packages/webui/tests/board-held.test.mjs 0 01a24d222092ad46c24ea94f684a018b787dfc8d26a0f7d7fda5d9df7192e695
whole-file packages/webui/tests/browser-edge.test.mjs 0 4d10b4fcefbc64cdf12bbfbd9b47f74810b3219f70624c35490cb23d66d3c4a1
whole-file packages/webui/tests/browser.test.mjs 0 d8c31b7cc16d93961d65959fa9653eaba906f81da3a34e19b3da7cc922f840c3
whole-file packages/webui/tests/bus-browser.test.mjs 0 ab1538aaabfdb02c336da61675a0d1d7f367483bc500a380e7f0ece050ab8609
whole-file packages/webui/tests/bus.test.mjs 0 fd7acdf189fef230af80c32c4c972d9bfb1564069d7c4ed649c3a49bb6636e1e
whole-file packages/webui/tests/channel-chat.test.mjs 0 678b8e3c9152662487fee1c52c8abcae95029b0672d5bbe26a824bbdb4a7ee0b
whole-file packages/webui/tests/chat-browser.test.mjs 0 ec29dd03ac7950dfa90e31f72ae74e2112718f1c02ce4dce8055194a328b5f5b
whole-file packages/webui/tests/chat-instances.test.mjs 0 72c88b1eb11397bcff524af72cfe826a276b97b58e33465c6e3334e2746e7783
whole-file packages/webui/tests/chat-replies-browser.test.mjs 0 bea9b1f9333bc913b2f01c29a792ea4b2fdbed3ebc64b42548e06f0bd75c9fc5
whole-file packages/webui/tests/chat-sessions-access.test.mjs 0 f2de41c7d1f6e246a8a13dc33e8662932964facc5b93d8f85ed5fca760c87fd8
whole-file packages/webui/tests/chat.test.mjs 0 4c6564d3565b01d68f7d16937aafddbef2ec3e04744fa9d1544ac0500a386ff7
whole-file packages/webui/tests/conversation.test.mjs 0 1c3f8811256ad82d7771a06878c3e70dc3d6f2beab82366b837780a7873ff6f1
whole-file packages/webui/tests/decide-browser.test.mjs 0 c53e1b962df99686f9739e258b2b86fe6325544ab02509833f9b1176f1303845
whole-file packages/webui/tests/decide-sso.test.mjs 0 f96f8085015a96e11aca2d94bfb9e75318c0c0dfa9659049ec7b7e31ad7bc6de
whole-file packages/webui/tests/decision-http.test.mjs 0 c89b7af200edb82f9986479199f359cf6a06c870f1bcf22b538cdf3b167f1258
whole-file packages/webui/tests/discord.test.mjs 0 1c3e6d64a370adbc6c7cb24391989e9c00d97330d393943402ff5c6a99c5f9fc
whole-file packages/webui/tests/docs-browser.test.mjs 0 f39d989ccdc561175643583b27bc19ee76fa25dec5947baa206b0c38b41c1e2a
whole-file packages/webui/tests/editor-browser.test.mjs 0 c807f81d596b3a2e3d2ea55e560f29e181a0354ce48676c6760844855acb0dd3
whole-file packages/webui/tests/editor.test.mjs 0 6953a85fe791e9087d14c3bf5075de2c4a651e1a502937da3226065c529ffd2b
whole-file packages/webui/tests/granted-user.test.mjs 0 ae3baaa0d2a1ed1ad3e9625a46a8071222dfdef4c2a70ae3ba5bf159b85dec0b
whole-file packages/webui/tests/history-return-flow.test.mjs 0 8f9ceeb41a64ec2849383a78f4997f7383c86a01eb6cf1d16747c2eb6c7448d4
whole-file packages/webui/tests/instances-browser.test.mjs 0 33b9cd4be552f89809e75f72c54f73dbe6459a5c53401a79a4d887e5a658c442
whole-file packages/webui/tests/instances.test.mjs 0 904abfc06358c99b0f646c3e728027cd7bba2b27c98c767c7da95016e531277c
whole-file packages/webui/tests/library-cli.test.mjs 0 dda07bd1b0d65058723c4d5e50f94fefb1ee103c33c8f61c13841cfedfd53f41
whole-file packages/webui/tests/library-routes.test.mjs 0 5cd1f4c6ea99cce38ce59eee085ab31f9aa8bba39cebbaf52b355c4d8fec3098
whole-file packages/webui/tests/library-status.test.mjs 0 0b4fb5a07a3d35fb2237401b460ddd3832a2f6fa357f6fbb06b8463251b77faa
whole-file packages/webui/tests/limits-browser.test.mjs 0 1a55050c92be5b93e447878feafe59e017b205d114413e6de000faf784df1dad
whole-file packages/webui/tests/limits-route.test.mjs 0 b74fe734b0ccbdde716bb52bc15791f80a0b251514a6b01d6ba59164b9639123
whole-file packages/webui/tests/messages.test.mjs 0 19bce52278091c8d37ca48c1f6f72bc400cd9a9b3038ae9f31e35444fdab05b8
whole-file packages/webui/tests/pinned-copy.test.mjs 0 a8c99249fda05c5be773c8d2231e2dd1a3f3b7d10a40a7ec3e6ca6c6cfb4c85a
whole-file packages/webui/tests/preview.test.mjs 0 7f7fbb11dd5915b3351b5086ec9b0f0bed6837a32a2e5902b707fcb54f1bf1c3
whole-file packages/webui/tests/processing-browser.test.mjs 0 ed5970f1e2b1fa393c80db5e5551523e77ad0ee107dfa686a76c5d923b7e2d8f
whole-file packages/webui/tests/processing.test.mjs 0 ac7a3a0ff51bb15c04e228186d771dd75ef515e09156cd080a8bea881e7cdd8d
whole-file packages/webui/tests/project-file.test.mjs 0 8bf04994dec5c6d6670bbae055802759588c27b04010582732cbbf32c2921487
whole-file packages/webui/tests/project-name-repo.test.mjs 0 ca773d7109f132bd099c43003a8269edfa96b2ba3a9e01e3694fa6bd12b9143e
whole-file packages/webui/tests/proof-cli.test.mjs 0 5095f1ec66a3fc153467baef2291073e27aba17fdc2757e0a3cf2a03057a6547
whole-file packages/webui/tests/proof.test.mjs 0 cdb948d261f52232c6e31e25baaf234bd0af3b6d90360a41a6142d2f34a8a797
whole-file packages/webui/tests/reads.test.mjs 0 ef69c9c1dc9a55d526a704297aa4e2802cdca8f0e1fd70ff79efad2114a071a6
whole-file packages/webui/tests/relaunch.test.mjs 0 e9f075560291cb446dabcaeb86c8800b5ea4ca0396c6a999ddbff88b245cefd1
whole-file packages/webui/tests/return-flow.test.mjs 0 bf809ee139c15e9b6b8fe7f6e0f2ce00d0860aa460f145242fc732eafe8da8de
whole-file packages/webui/tests/room-browser.test.mjs 0 23286bf46f341220f9e89cc1d229f46a579edb2eae5d688fc768f99ee343c858
whole-file packages/webui/tests/room-http.test.mjs 0 a921e1991386cb5e184475cf47a012b3020b575968268e9f3c0b396e244a1819
whole-file packages/webui/tests/routes-browser.test.mjs 0 df1283a6e1c5970b404b314b6b76dbf412e5318d76f296ec00164c932166b020
whole-file packages/webui/tests/routes.test.mjs 0 055aa274fa66910a4ff1518fea49fbbbbbc5360dc16e825a460538f312a0781d
whole-file packages/webui/tests/send-browser.test.mjs 0 da1547383522dbfd74a571b5d7625a310ae88f8adddff0c2bd33cb59df3ac137
whole-file packages/webui/tests/send.test.mjs 0 f273e78388935b5fbc18a974f50cb85789436d51c47a4d8dccaf4af4742c2392
whole-file packages/webui/tests/serve.test.mjs 0 1971344643d9cf6b4440d95c9ede42093235883ffab04fc4b614c1b7e7078f22
whole-file packages/webui/tests/settings-form.test.mjs 0 80bd949d1666f2fe1f4caa051e2c34e742bab0e4adbe5584bd534d9bad8bef53
whole-file packages/webui/tests/settings-write.test.mjs 0 7090474fff40910edb93c032feef248adc40ad21666d09c3610cf10279164f99
whole-file packages/webui/tests/shell.test.mjs 0 844287f7797201473f1fb8d97ff2355ff3ff505006723678db78f26d3e5c2a40
whole-file packages/webui/tests/sso-browser.test.mjs 0 1f70c36ce7d054ad435e52d63083c8fe19cd71e70c723518de5e58b69a426a0a
whole-file packages/webui/tests/sso.test.mjs 0 6d7b3061bdc6e22744634ddc5612ff781e5c952a120a346c29eead66a3736438
whole-file packages/webui/tests/tester-browser.test.mjs 0 425c54a84e5bf04ca91d8dc57ee83c14aff14a38159243f10f1c9114dd563967
whole-file packages/webui/tests/tester-cli.test.mjs 0 5eb7296792f16f24d4486f39101007114b3db81c6ab53ab969e925caaffaa7d9
whole-file packages/webui/tests/tester-listener.test.mjs 0 43927869c50a0e223d121e2dea2d10346a053a39fc8157c9fc4813b7c3b17e1f
whole-file packages/webui/tests/tester-socket.test.mjs 0 c05962be7f87084404c53e4f7ed2caffff3d69e98e69a3c9f3c53b150cc804e5
whole-file packages/webui/tests/thread-claims-browser.test.mjs 0 cbb2aeca0de2c64dd4c8d063d3e45140738d8f4064d38effeaec245ed7181b42
whole-file packages/webui/tests/thread-claims.test.mjs 0 164a6c927abd819218be6386e123b234dd9955b122bace699e0a12201797791c
whole-file packages/webui/tests/thread-sharing.test.mjs 0 ad64ab207702483aed6f16d13393e5f3c5a1ab0a0c2dcdf32717e8148a45078c
whole-file packages/webui/tests/usage-browser.test.mjs 0 14be967dcae157cbb0a7b9ea4e0bc67337941d91a11d789baeb3d3c8353ac0e9
whole-file packages/webui/tests/usage.test.mjs 0 4e20eee53c3eb79dc2930ca054977d06da88dba45b706a96ed94abaea6ec3e93
whole-file packages/webui/tests/user-option-swap.test.mjs 0 bd43c257ae31cad2ca6c7a0b3ee49c6e323737d236fb7ff2a2105fd5e59b9767
whole-file packages/webui/tests/views.test.mjs 0 4226ea02d33b9de8f2eaf9f93b0a551cbd9e6100560a8811eed90aa8de76974c
script scripts/test-auth.sh 0 03999aab66446a4192ea9855f5cc1bd406080d0dfa5250b45b30e118556a0d5a
script scripts/test-conductor.sh 0 79b7a689ed96792d42edd1d14796e0293e84e2e339b49476e457ad89e1c4a186
script scripts/test-config.sh 0 2c3c87fb193e82fa17428933eb69cb2b34a589e8338f7a94aaa8256729fdf08f
script scripts/test-discord.sh 0 5c6918b4415e8eabc5df31ac5ad696ec2afdfe3d498d69eae64f228a3807eddb
script scripts/test-extension-package.sh 0 1f672a73e507cc57a204f7d3806ddcb211a0a8fb3ffccefc12bbc41e299f65ac
script scripts/test-federation-acceptance.sh 0 febb0148bc1316bba3189aacf34d7c78f5f5db5d97a35aa4528dfadbec8bfbd0
script scripts/test-foundation.sh 0 3de063333ce60ef1ca1986ecdd8ac30187a2316b7ca8e3ae4b4e6c8bd435caee
script scripts/test-land-work.sh 0 ec90beab6246420982f872a4f45a7173e7a06f4aa263630d6ec4a4865176cde0
script scripts/test-push-check.sh 0 0304c110dc5cf269fd8a4bea9759e5d48895a51c9d411814ce39ca924073da79
script scripts/test-queue.sh 0 f678da9550eb6daa5268465b3a07beefd661e506ed38b8e11bf0a1b4a68cc781
script scripts/test-release.sh 0 ad0f2a6b271275003783d3ffab5520f167ea79e26683710ce92a71600037360c
script scripts/test-task.sh 0 ad511e52af4bc0a843eabbb3efcedd88c89468ccee43be9022e23880d7901f16
mutant M1-supporting 1 0 10581fdab579db4d63322eee3369a1a740266e00a7dcbaa95e7651a7e0447ab8
mutant M2-force-push 1 0 b137e8362ae3e26a090a82e8c41c3e87beeaac43183cdd6db67aba55d5e372c9
mutant M3-forged-token 1 0 bda603c18b7b2bf468a21e139f0cff0c15c22e19c9d41cf8c50f9c3ae0bd128d
mutant M4-grant-before-push 1 0 a642ef8e57a98c1488bb787da241292e6ed5446ca4117940fb0ddb9800c6a105
mutant M5-notice-after-publication 1 0 5645138c2cef5d1999948744783ff3904a78e9cefd7421674386a2d0c5fdc45a
mutant M6-commit-schema 1 0 7201f53cb976b2db1994c4e25f7f6e8b58eea323c060dbddbfa0372464adb686
1 kind name rc restored_rc log_sha256
2 whole-file packages/library/tests/write.test.mjs 0 e0f6a09b70316beebbf33966b35bfd05b4a12b587744dadc9239bd28de1b976c
3 whole-file packages/bus/tests/library-write.test.mjs 0 e0e9e609b20ea0564a7611046026cbdfd007832e0eb13507798e958d8d106ef0
4 whole-file packages/harness/tests/library-write-tools.test.mjs 0 c8a3a493d1d2abce785e94fdda5b1732e8d4a5e6eb19767af1b7e8b5e560cf3b
5 whole-file packages/webui/tests/library-write-options.test.mjs 0 2491eb6a01a0b4b2127bcb6a87a5dc778d079b7d1ea445509a1dffc49dea9051
6 whole-file packages/bus/tests/access-revoke.test.mjs 0 a1b317bb687e8c369440f5481b4ef309615afb5a5922fa306980d2024019e544
7 whole-file packages/bus/tests/account-migration.test.mjs 0 e697b58a1bb9b37c609b441fe786e557c7f0279e7a31eea791483ce4567db318
8 whole-file packages/bus/tests/address.test.mjs 0 977f755d29a8e75578d0bef48ec40b7045736014b2e53e15a03cdb6dd39696d8
9 whole-file packages/bus/tests/agents.test.mjs 0 3e8116bad1ab5594e627ba3e9f5403414885959935bcd9e6f75f1af4c625d4b0
10 whole-file packages/bus/tests/approval-binding.test.mjs 0 d2fbee516b57857f3a6562427d2a08bd7fdb772aacabd33ebd9d2990f01ec7fa
11 whole-file packages/bus/tests/broker.test.mjs 0 400e7f0616bc7432d8cb2a9efbae3c84d5b44ef59ce7f8fbebd4c802e2a9f44e
12 whole-file packages/bus/tests/business.test.mjs 0 f42502884a158ed1d190b37b3884e19d44547ececf068f91765b8ad15faffba3
13 whole-file packages/bus/tests/channel-proof.test.mjs 0 3984a7e2da2a60e60d0309f719a45a3ef04bca767bac34e00a760e19e941d732
14 whole-file packages/bus/tests/chief-of-staff.test.mjs 0 8dd57acf0101d4c92ada92f4c33f68061d4e2cb430179a8ab99a0b7fc9a19997
15 whole-file packages/bus/tests/citation-availability.test.mjs 0 d34d84d44b5949024ce6b32708c68e10b00a84600bb03598bf9538b358750455
16 whole-file packages/bus/tests/citation-guard.test.mjs 0 acab66e65fd41f1fbfd9524f80456553fc033d8bfc18a9bec7a813bd0d4552d8
17 whole-file packages/bus/tests/citation-runtime.test.mjs 0 ce33310d333c7a0af7451c3a3b610f5178961b80b6b63a839909b67657fd161e
18 whole-file packages/bus/tests/comment-cursors.test.mjs 0 cd4de90a070faf2bdb776a96a6ba43aa4854f6f5f1b2b7459740bd7bdc0ffb7e
19 whole-file packages/bus/tests/comment-migration.test.mjs 0 773659855873805b5bd950101d950945213658fde42d8012211e742ba9ddcc09
20 whole-file packages/bus/tests/console-decide.test.mjs 0 275fc0a24a03f2f27210a65e2bd21ce615ec9b6b400c4e4177ddb97a9e8e85be
21 whole-file packages/bus/tests/creative.test.mjs 0 eb950d5680ff7e4e09a9c11b1c169d4a740011ea72bb75921d35571ef5373df2
22 whole-file packages/bus/tests/credential-claim.test.mjs 0 b2d40e4d2a353f4154af4974d5779f7b20c652a8110da3183f95959ae2540941
23 whole-file packages/bus/tests/credential-status.test.mjs 0 ed367e3d123c9629b7d3d22f6fa60f48c74e71b36982c54ad2b3e8419f515431
24 whole-file packages/bus/tests/credential-store.test.mjs 0 0fd528ba27757393973cba5b21da573bc681659416962bf7d3a3dff3018414af
25 whole-file packages/bus/tests/credential-verbs.test.mjs 0 154b123af420abf08c6ab8b7bc6439052e7ab65c772abb0caac5e9b9cd3608e9
26 whole-file packages/bus/tests/credentials.test.mjs 0 6474b45c076f474a6881d0dddd0cd3b4cd385d52ac4c55ef1a9f8c10e0028277
27 whole-file packages/bus/tests/csuite-messaging.test.mjs 0 c0229df65240be8ad014d83def48dbd64a952b701f46e40ff01efdebb5644d6a
28 whole-file packages/bus/tests/daily-quota-runtime.test.mjs 0 62d686aa1852088af569cd3b921194db6873311f2ba04e55b15a93900b1615cd
29 whole-file packages/bus/tests/decision-close.test.mjs 0 9599744860a4e6e330ce50b8e93c478546edce5545a9171bed068743a266ae5c
30 whole-file packages/bus/tests/decision-route.test.mjs 0 2b2a9570dab83b1d454f56c1311cb41103a14bcff49e207cbb4ac5d4c73d6f0f
31 whole-file packages/bus/tests/decisions.test.mjs 0 a753df7d939155adf13c7177926728b2760cf61770117dd1655f29fe2c88a26f
32 whole-file packages/bus/tests/end-launch.test.mjs 0 ff7a27c35e35be424cbefa799e219ffc073c494214642b4ce56ceed6b359335e
33 whole-file packages/bus/tests/fire-revokes-grants.test.mjs 0 8e6bee9421480af8a1326d65903f258d5ea0a79df6188bf18301f32a5260547e
34 whole-file packages/bus/tests/gitea-grant-docker.test.mjs 0 8b639ee86d1a7d2ef267e1d36264f4ce1b5beed2c8ce084c39c0de1d699ca8a0
35 whole-file packages/bus/tests/gitea-grant.test.mjs 0 8fa39b3e58cfac4ec97f02ff876fde1a40a1894c826306c0b77d45c73586f753
36 whole-file packages/bus/tests/gitea-migration.test.mjs 0 689fb43a38718f5f5d00ffb3b6d998d5d454854d5e77a936b56d7c4192ee12e9
37 whole-file packages/bus/tests/grant-enroll.test.mjs 0 a8be59931d37a5c787c2087d29d766d6b701bbe34f8343134148292cd29d345c
38 whole-file packages/bus/tests/grant-executor.test.mjs 0 0a7f5be29b28140c9f8e7f67c6a897eb455677fba4459952a83982f2b23c87e0
39 whole-file packages/bus/tests/grant-host.test.mjs 0 54c4ed722116914221e9320fd41723e32aad59284e98d8e177130b0f4c4fe6c4
40 whole-file packages/bus/tests/grant-migration.test.mjs 0 7cfaa3f24d1dc070d7bdb8de76b08fabcdb6877d3367c59f7601e08f683d658b
41 whole-file packages/bus/tests/grant-scope-runtime.test.mjs 0 f8bccf5324f1e10282dfb4f4fd0f63c76c8e9481ae6cc0845a1d9028e3d9633e
42 whole-file packages/bus/tests/grant-scope.test.mjs 0 e30a8ced066ad214a6f70dd4a39c75bacf296032a3201e4605fa3c8df23e0159
43 whole-file packages/bus/tests/hard-waits.test.mjs 0 78d92a14781286d3ca11989786a8698a2b796ad1db78769fd5b3c7653ad7639e
44 whole-file packages/bus/tests/host-run.test.mjs 0 51d231611940444d2c2a37fbb7b14267c705c1b5e453b02367d0a6def214dc93
45 whole-file packages/bus/tests/host-tools.test.mjs 0 3bc5b5413661edd2026bca1721055ec7dce8d115918cc10c8f334e527176d23b
46 whole-file packages/bus/tests/human.test.mjs 0 5c8f3fd402ae4e130029b3203ed41b3cb45b8781417d31dec1f47ebddd516349
47 whole-file packages/bus/tests/instances-verb.test.mjs 0 940ca3884930f539272a2c39ca7e1c7fa3e51b3a4ea6fdcfb21719c652152257
48 whole-file packages/bus/tests/interpreter.test.mjs 0 d0c6190a428005b7750b59e665968657b242b322af05ca7bdd4cd7e815b7f4ab
49 whole-file packages/bus/tests/land.test.mjs 0 e9ecd1d8011ab6789fc3254bb069e76631b68b20ad65ae844ee12e0dc3b97cb0
50 whole-file packages/bus/tests/launch-notice.test.mjs 0 750a54d4c40559c7fb5414071bace8056d6bfa71dfdbec4de12c94c90299c3c5
51 whole-file packages/bus/tests/launcher-released.test.mjs 0 4d59486ca3077a4b2f51141ab79df635feb6b7bca2d6c0cfe5839a6a93715de6
52 whole-file packages/bus/tests/library-credential.test.mjs 0 db7e2dc4afe23f74c49795e4dcd3d28414435519029a837641cbb35bd3f4fcef
53 whole-file packages/bus/tests/library-lookups.test.mjs 0 fa18b5d4c829ec35ebbf519c4346a2ac38cff7538d58ea663acbbdd7930a6015
54 whole-file packages/bus/tests/library-sync.test.mjs 0 ee0ab1ad2549d3e6ae6d8123fa99d697d9be6c629e09131da82f0ab6d58a60e2
55 whole-file packages/bus/tests/library.test.mjs 0 62b663034a5de8d6d1abfaf3f94327d7aae435e3350874b424eefdb28bca1bd1
56 whole-file packages/bus/tests/lifecycle-revoke.test.mjs 0 c0810c743b5108773b6cfbc2d108fa09ea274c437433355277ce2b1295fbf692
57 whole-file packages/bus/tests/lifecycle-verbs.test.mjs 0 926bcfb20ab58a4ecbe85b4f8feb915f72adcdc6d6aee84f814187d0ac998efd
58 whole-file packages/bus/tests/limit-checks.test.mjs 0 919d745dc570172716b1e06d0ea1e8f16ae7b05dbadba77fe92dbbcc8eb4cba7
59 whole-file packages/bus/tests/limit-stop.test.mjs 0 2fc1ebee4e4d4862a100ed9ba97ace1e6d3fb3c608abea63b1ff634a04d5649a
60 whole-file packages/bus/tests/limits-runtime.test.mjs 0 5845176b73f98a499d92096ce0d22a3987ada664a529bdbb26230c2d00b9e65c
61 whole-file packages/bus/tests/limits.test.mjs 0 333f6757d9d00eda74e7d4641af660c9a0ce3d978e6a8550139d3a461c1d5866
62 whole-file packages/bus/tests/message-citation.test.mjs 0 38422c1d6faf076c750c3fccb7e927e38fe955cc28778511acccf5704df5b191
63 whole-file packages/bus/tests/message-filter.test.mjs 0 2ba52728df27756ac19ba65fe0705e7cf7a2a786a3b4df77a4eb4eec8072604c
64 whole-file packages/bus/tests/messages.test.mjs 0 b87de4ab04682d59a2faa7b3fc64751247454e628e9c1ebd4c07b1df2acbf11c
65 whole-file packages/bus/tests/messaging.test.mjs 0 831b48a9de594e17e8fc47f16ab8c2d722e8d57068a7d39deeaf4c0fa8d136bb
66 whole-file packages/bus/tests/model-proxy.test.mjs 0 99c5128733ae5bb16489171513c158ec1e34dfce1d07c60f6bccb0f84ab7afb9
67 whole-file packages/bus/tests/name-migration.test.mjs 0 bb8f92a17f6a022c7ec63161cccc0bb49a26c2a591fc369375cbebfa93a277a2
68 whole-file packages/bus/tests/names.test.mjs 0 0fcf60cc8c7dee3e85548c759f03e1792de92b59131bb9fe4282a3b07859366c
69 whole-file packages/bus/tests/peer-transport.test.mjs 0 3cb547003e50695ec2a25c950819b304f15203302281c00758a12c9b89b60f40
70 whole-file packages/bus/tests/peercred.test.mjs 0 e75c700a68ba0c1013c8f36178d6554f0321dc331b2198fd5ffc1a684df76c3e
71 whole-file packages/bus/tests/plugins-verb.test.mjs 0 359fef350befd1d743bcca89a96ebd0757346fd7c0622ba364039ba827620d26
72 whole-file packages/bus/tests/principal.test.mjs 0 732724e6bb2bb953e7dbbbae5c23cc0a1c33a7b7b202f5cb8b46be9363bcb392
73 whole-file packages/bus/tests/process.test.mjs 0 9c5883ea2ca858131317fa9be66d2a51a5d86dbe03c515b0544f4db56b2456a1
74 whole-file packages/bus/tests/processing-runtime.test.mjs 0 bb6b94ac654d069abd6e484031893e649e239d933c135b226d1cb2fbd5a94ca9
75 whole-file packages/bus/tests/processing-timeout.test.mjs 0 323036aa7f32f7aa324f61595531a29f3d5ef0ae2c24aec029842f2783d6be76
76 whole-file packages/bus/tests/processing-web.test.mjs 0 dbd1543498fbc8d0625990436ae668b3a382eedeecd098b929c13d2bb61939ff
77 whole-file packages/bus/tests/processing.test.mjs 0 529ec93e767444970ff03acb1ba719b45033daac239256c9cbd587c39f926a71
78 whole-file packages/bus/tests/project-await.test.mjs 0 e948d721ef06ce95f909880942f7e7ebd73b2f42563e1faedacc7b403b8ebedf
79 whole-file packages/bus/tests/project-files.test.mjs 0 3691b04705c17d4ef7218bc15771560aca5586c00ba0fd3fdf2a80f63d8dc659
80 whole-file packages/bus/tests/project-runtime.test.mjs 0 9d8d6cedeb2044f19e548dda0e32cae1e997b75a6d89072f7367b6e0ce17a44f
81 whole-file packages/bus/tests/publish.test.mjs 0 87f7a382580432646ca89d1228377719cb177bfdbb4f74ad617f6a70dbfb4b33
82 whole-file packages/bus/tests/reload.test.mjs 0 25aa45aca6ba24d72e9e5ad66dfc8c049375c8df121dd748dde09af52f16f853
83 whole-file packages/bus/tests/replies.test.mjs 0 0f05dc2194896540a1488310107e31b7e779cc02c381c201d0c95f69ab39fc51
84 whole-file packages/bus/tests/requirements.test.mjs 0 29569dc30659dbecf359117cc9a59ff37927c60f5514b8ceb8d3796c2c3e53d1
85 whole-file packages/bus/tests/review.test.mjs 0 a8daea8602be9429a8044ad636a438c18eee8ec77b6fa272dce606116d01de8c
86 whole-file packages/bus/tests/revoke-window.test.mjs 0 1435c543c9367204f4ae6d25c2cb97145e762cb18e78ea90a15eb1672a220353
87 whole-file packages/bus/tests/room-check.test.mjs 0 bbe5ac7abfb7e1b30f6fc8f9a247cd28aca82a8783753434339b790dd9857e1c
88 whole-file packages/bus/tests/rooms.test.mjs 0 506fad116ab1d9bb2520fe691adc91ca26e64faa96ced35c193cb11da4e07ccb
89 whole-file packages/bus/tests/routes-verb.test.mjs 0 c09fef3cb022bf7713cde4e1c512feefe67090eff05451fda9f55272140c916e
90 whole-file packages/bus/tests/schema.test.mjs 0 2a1a668dc408aaebe6f604ec5c3b8858211edc52930e1a552173cecedf806d72
91 whole-file packages/bus/tests/session-clear.test.mjs 0 1fce03f1d2a41f5ba294e9d406980a1d3251bc9a5dd4a02897413d6be3d9681c
92 whole-file packages/bus/tests/session-compactions.test.mjs 0 745510273a9eaaf61de4c6453c5dcc70e4a6020c0bcec69673621eefa593dab7
93 whole-file packages/bus/tests/sessions.test.mjs 0 d6c0337e0981ecb9aae2e912c27145bbd831e196828b2d59029666ceae5f605c
94 whole-file packages/bus/tests/single-use.test.mjs 0 6f5cf7d47716ce94eccb069f9b7e5625c3587737921231649fc74e8bfd3aad3c
95 whole-file packages/bus/tests/spec-migration.test.mjs 0 ede4ca62a772261bc868f4dfcb4861c9c3670110ba2afd39cc44183398c2eafd
96 whole-file packages/bus/tests/spec-review.test.mjs 0 951aa2a54cfe4bf0960dd3d2180874cb8183ff9b0aee7b7251b05df11385e1a5
97 whole-file packages/bus/tests/spec-socket.test.mjs 0 65735a2557e19b3d63a3ce7198c80fb5059f1974acd0708a89f192857b43b095
98 whole-file packages/bus/tests/spec.test.mjs 0 488ab443b41b06b6ae4434f5b2ee8904169aa08ab3527f3ae4c3f438e54f9909
99 whole-file packages/bus/tests/staff-request.test.mjs 0 edeb4ceffae3af33e330e1fac5d74c4fb1861d52ec5ac5005689791ab74da555
100 whole-file packages/bus/tests/state.test.mjs 0 3b5f916c494563fc7c18f89450e0cecbbdad8e24680b373e897253b9ea6064fe
101 whole-file packages/bus/tests/store.test.mjs 0 39d0a4033b89eff9b29ea6dcf6e56696a1d20a41e0e14b4bc8efbfae7962ecf4
102 whole-file packages/bus/tests/task-page.test.mjs 0 6446cfc1a43cb4206b4130f316251d3d9a820f929a6efc59dc74e7cbe1fbd258
103 whole-file packages/bus/tests/task-read.test.mjs 0 37134ced43ad5ada4291ad5e3474dcf7063892443b06d54a7456cd4cddb9cf2f
104 whole-file packages/bus/tests/tasks.test.mjs 0 9d91ee510a7447545c2cf93ae6779544a05e01bb70346e595b91a4800fa42d7b
105 whole-file packages/bus/tests/tester-threads.test.mjs 0 ff843610e02f20c5e1ab19de27b131ae7cbc3fd87b16d85e68336b5e914ffd77
106 whole-file packages/bus/tests/tester-writes.test.mjs 0 517c41e666d2c59b7ffb6ddb22898ef58b816bb26eaa47e1ce7508087b607df5
107 whole-file packages/bus/tests/tester.test.mjs 0 19eff6ddb3aca05ad5c006ac15e7860311f56941055850e86b8075cd39eff0d1
108 whole-file packages/bus/tests/thread-claims.test.mjs 0 ee146e984bb3ae82ad60f90c83035053ff2966ffea91015b6c3c4f93b7e019bd
109 whole-file packages/bus/tests/thread-migration.test.mjs 0 1dc2ae4e920d40a6fc2b1033f43ac0a2f766bfb86f07a596a983b9c1bccf87d5
110 whole-file packages/bus/tests/thread-shares.test.mjs 0 3f99a82e9e4a43fa788ebb231c5e712969809fa83b6ca66f04b8cad13f411235
111 whole-file packages/bus/tests/threads.test.mjs 0 2e5ba2be69a34c71f41a819c7a5e8615fcd085f847f9aa6d16095b9c8d742552
112 whole-file packages/bus/tests/transport.test.mjs 0 c9d28b9acfc0c2213838df0d960506156ef6fffec24a0cee7336324f105fac0e
113 whole-file packages/bus/tests/usage-broker.test.mjs 0 26fc080c6ffcb7c64cca39a07f302b59c21d1425ca3c90120eb3d3bb751c49da
114 whole-file packages/bus/tests/usage-migration.test.mjs 0 cfc65c4233aedb325293170e782ccb83fcfdd85cc4afed1e913e91785fa4b7cf
115 whole-file packages/bus/tests/usage-runtime.test.mjs 0 faa5fce30cbd7002137acfca3cde68b49b74321fb27b8a190736b35601430866
116 whole-file packages/bus/tests/usage.test.mjs 0 d36d21e0b3f5c9621b50e8b71ff6d8daa341f5954f3612b7cc93cb6c734215c0
117 whole-file packages/bus/tests/user-principal.test.mjs 0 1b56d881de2975ec4e3bc27fa15bc495ae0600709457da579337f0c9c98651e5
118 whole-file packages/bus/tests/viewer.test.mjs 0 942ba4fd96c3bb4c527eb129e69ddb5cb7660915e8458cfee47661d268db0e24
119 whole-file packages/bus/tests/web.test.mjs 0 048e3ef2840934f95d7e00de6502b19342215cfe5d00d1b8ada7c1bc6e87cfa1
120 whole-file packages/bus/tests/workflow-roles.test.mjs 0 1bed1351ec3c50ddce65f9b8108f93a5c4061ef5cf36f3d09706d85b13e085ed
121 whole-file packages/business/tests/case1-business-file.test.mjs 0 4481abbce73eae119fbedc5edf65120fa494931913aac6f0273b04263c251cc9
122 whole-file packages/business/tests/launch-settings.test.mjs 0 540f5170ddc7e79a8abd9584c4586eade3ecc1f7544489060db99552c75e4685
123 whole-file packages/cli/tests/access-boot.test.mjs 0 e41e1f1949d3568f8845234d573282c18a185578389d6947140cf540d7f99dc8
124 whole-file packages/cli/tests/access.test.mjs 0 9e2a813092ad4b60cd89443424eb4142f217265e52ff7b769b7f16d247d5a367
125 whole-file packages/cli/tests/app.test.mjs 0 5f5244ba0061dc4ffd1565c4abd3168d7cb2e6398625b69c841a54544b9a35a7
126 whole-file packages/cli/tests/boot-status.test.mjs 0 ca090577e20ea46315cb377668e309571380e2323c867a8b90d0537022e681b7
127 whole-file packages/cli/tests/case1-hostcheck.test.mjs 0 403e1127da5637904e8fe1c1eed5a7865c5bd5ee1c5d0fe684837a7370c41de4
128 whole-file packages/cli/tests/case2-install.test.mjs 0 df8edefe13297ced929d09f01eec5c7ecf38c355d9871368cb19f2f392ae057a
129 whole-file packages/cli/tests/case2-persona-import.test.mjs 0 5dc7a93c03567ec0e85e43bcafe07109881c30b2e83b4c4eab4631a155daece0
130 whole-file packages/cli/tests/case2-unit.test.mjs 0 39b349dfd3125e74b780ce28e9ec24465a6a8c2bb9e431c819864f4eff1fdb77
131 whole-file packages/cli/tests/channel-cli.test.mjs 0 9fd9c30aa604f77b7a069912cb987293af36f2f138cce850f8d26946f5ce42cd
132 whole-file packages/cli/tests/channel-recovery.test.mjs 0 52c6bd980cd54ef22b9e6c78260a1e389e8177526340129ac64fbafa7f2e01ab
133 whole-file packages/cli/tests/cli.test.mjs 0 59327fd89e3fb8f927210df6a2c62afe4522e59f59129b1967be2a238c498f26
134 whole-file packages/cli/tests/compactions-launch.test.mjs 0 c9006b3039a6616be1816f5ce85bf68ba4fb54dadf10447e52fc92f7ed57bbe5
135 whole-file packages/cli/tests/config.test.mjs 0 35e39fb0551e23f5738d0c30d66bd233f2290040885c511e526f0f0468b31cad
136 whole-file packages/cli/tests/credentials.test.mjs 0 2b55cde2318a034ec4152e712863ac54f07f1b4db752c6282507d7f621bde67d
137 whole-file packages/cli/tests/federation-acceptance.test.mjs 0 cca971a93a5dfd20e603b45cc2158b58ea0638e8bb7a33e6e0c5e12178ffa3df
138 whole-file packages/cli/tests/follow.test.mjs 0 26a3ad0dbc124aff48a5f4908e3d8b78cb871e5560c0e389de457f58aea2dfe3
139 whole-file packages/cli/tests/git-socket.test.mjs 0 10c21c34a79ebd5f89f6ed9182a492e9f42f0512a68f758c0566a763a84abeb9
140 whole-file packages/cli/tests/grants-scope.test.mjs 0 37967ca8e82a89a0e88ed872fa562b5c094282cc759853b6dc31c292204bef3c
141 whole-file packages/cli/tests/grants.test.mjs 0 687af745932625ea1d439a8139c760f14b4a327bf9b15c5b5b1cdbc7ea6be09f
142 whole-file packages/cli/tests/host.test.mjs 0 50010e97e44392f28006bbd4127146b8aa1712ff4a016ca10864923701213dce
143 whole-file packages/cli/tests/hosts.test.mjs 0 d5d507c3968c45b2aa25067d6bbb1eedd69785c0aa1bb51177c63b6ad64fcb53
144 whole-file packages/cli/tests/idle-stop-race.test.mjs 0 8e6171855003b0f40921863430dc89cf20f8bbf14a9ce3c115f90486f08232b5
145 whole-file packages/cli/tests/instances.test.mjs 0 c6b4d59443baa4af029af76a846a8093669a7593490f21408a2c40ad027acccf
146 whole-file packages/cli/tests/launch-account.test.mjs 0 6cb63446fc8dbb6217e6d925caabb37a28bcf1ea5c27cf8d515d67c7842553b8
147 whole-file packages/cli/tests/launch-limit-checks.test.mjs 0 fae971d715a90d1dbbeb3c054932a02d253e0a0d036d3b0db4e0c9edcd5ad7ef
148 whole-file packages/cli/tests/launch-limits.test.mjs 0 d3f4b2c57e776bf6bbcafba6dbd9c4728918b0d81fc606dcd7d2dffefdad4001
149 whole-file packages/cli/tests/launch-routes.test.mjs 0 e2bec020f96238079908c03537366c64800de0913a83f3a2877606d0266548d6
150 whole-file packages/cli/tests/launcher.test.mjs 0 beafda99d34a532f3a1d6f96565b7a780e03924939b6c30b01a8169cceaa792a
151 whole-file packages/cli/tests/lifecycle.test.mjs 0 014a2cea6d3f2a9f21f7fc16dc68b34740b03726612851047b877f8c1194ebe0
152 whole-file packages/cli/tests/limits-tokens.test.mjs 0 6fdf9e6946dfb579cde42ec500d8cb8473a9d8318f43caecee7561a5e40fdec1
153 whole-file packages/cli/tests/limits.test.mjs 0 bc2f13959d087ccaf6977c4cf1294e6fcee21f968677ab169580ce79643add18
154 whole-file packages/cli/tests/mark-read.test.mjs 0 64864c54ab910488d55136b88f351771489cf744ba1c21e5c479121694dd88ab
155 whole-file packages/cli/tests/model-proxy.test.mjs 0 119a5d02870a4062992efba7f44ee9dfe69ecf8a7076f121aa24a8c7edf24cf0
156 whole-file packages/cli/tests/names.test.mjs 0 c2160aeb0c68855f59b5d97dc3b6101b7800028df708f5f42430ae5854eb23e2
157 whole-file packages/cli/tests/notifier.test.mjs 0 18e62f48de18cc4d57916a556adeb3befb13921d5d7b036ef5a7f2bfa460cdc1
158 whole-file packages/cli/tests/optional-tracker.test.mjs 0 e5adddfee06b2f1cbd2ec50caf84b5acbc58d4ff4ec4c1bc539a4535a3991827
159 whole-file packages/cli/tests/other-tree.test.mjs 0 2dae57af2b8d508f2792ce37191aebf0cd28ad75f7621d4ab9f8d6daa60b748f
160 whole-file packages/cli/tests/processing-cli.test.mjs 0 44b2854ba03810cdda3ccf0c6de883f953089d532bfcdc8f4bdd3faffac80fe9
161 whole-file packages/cli/tests/project-name-repo.test.mjs 0 0468b9ecde6189d1398eef2e7e8043e870aa867a8a9d22b20b2ded26dc1543b5
162 whole-file packages/cli/tests/project.test.mjs 0 79e648106151ca220d9535b16c416dfdcffffaed41e3c211e4325c151f0775f7
163 whole-file packages/cli/tests/publish-socket.test.mjs 0 59a02b1fcc284407b06d0d2df8e6e1e5323059daa2e47c690f30a718d1e7c682
164 whole-file packages/cli/tests/reply-limits.test.mjs 0 554a353d61891c3cbe8da01062025dcb0756ba4f4e7ab3fb8d7b56ceccf64437
165 whole-file packages/cli/tests/revoke-window.test.mjs 0 743fdb0135e507dea5b968265907e5ac9228284b130feb0057d91e70ad561c02
166 whole-file packages/cli/tests/session-clear.test.mjs 0 5abbd894dee9cfcb3464a40e5045f9062402d5ffe567972113715cc9e24c6ce3
167 whole-file packages/cli/tests/session-cli.test.mjs 0 c469aed70c1ae408e176189f23a849f3acf0bfc7dc3ba1132c101a931359a462
168 whole-file packages/cli/tests/session-launch.test.mjs 0 cde78f9dcee9afa243692fb0493697104425b61589bd7be6c4cbdb0f4bfbd5e5
169 whole-file packages/cli/tests/stack-copy.test.mjs 0 3b92b3772c060378cd2ec0c1bf7fe6662721721a11d99d83c9debe3e3aa929c2
170 whole-file packages/cli/tests/stack-instances.test.mjs 0 2839e390f564a6e58cd514ce4061ec0b741ed07b4e2b755a337439737601d97e
171 whole-file packages/cli/tests/tester-http.test.mjs 0 bd9c598c84dd0be3b9873176c63e418ccc004265153be68e0cbe51c40b1ff91f
172 whole-file packages/cli/tests/tester-reads.test.mjs 0 50a71ffd9093c4d51d8ad07bc9edbbd76306922f290d28194d656cd78f8528c5
173 whole-file packages/cli/tests/tester-threads.test.mjs 0 cd3dd0020472c269d61934ddb32d77f6dc297090d63e819288f4038fe9edf096
174 whole-file packages/cli/tests/tester.test.mjs 0 437498258b4ea5c2f2bfa8fe66114106ac10944911bd40bca944f2078b34e45f
175 whole-file packages/cli/tests/thread-cli.test.mjs 0 c29897119f279434bec0248c12beb5ce97f6214b8b0bec995061000f047b1600
176 whole-file packages/cli/tests/thread-launch.test.mjs 0 459ef35e2b4f9cb87151577f252282a716ddbd4985f26e9e26c01b08af13a7f2
177 whole-file packages/cli/tests/thread-revoke.test.mjs 0 b8a72080a9624ce4bbc1b23b8903be1b74a8a6ced35b0b60f503d92a22d1028c
178 whole-file packages/cli/tests/trackers-boot.test.mjs 0 f83d72dac4eec7369d62b495745e1fdeeb4ff1ba2e1efb376c9b583da1765a1d
179 whole-file packages/cli/tests/transport.test.mjs 0 e0ae6c26b5669d4b955deffe941a3c4314be12297e72d6c099de750170688d9c
180 whole-file packages/cli/tests/usage.test.mjs 0 639ebccda23e0e094d62cb0e7e5c80c403b74b284ac5189fb0d92e63387c92f8
181 whole-file packages/cli/tests/verbs.test.mjs 0 43eefd242a987efe42d145d7863372a2b0a397031baec12ecd4c9e0644daff12
182 whole-file packages/harness/tests/bundle.test.mjs 0 75fd5a9a6fa0b46078952ce216348e39ce481f6fc00b89f85da9ff729d5ba100
183 whole-file packages/harness/tests/citation-runner.test.mjs 0 933021f114882a6c58f4071446a07d49ebc9f99c062ffe1fedc1f13b799db389
184 whole-file packages/harness/tests/claude-gate.test.mjs 0 f66053597c8209c5175810e33d8b878ad74eb314f4057f5b4b0b1ac625272329
185 whole-file packages/harness/tests/claude-session.test.mjs 0 9c4d8ffc00efd0da75d143bca1cd33f30f3e762e20086270d941170e80c962ed
186 whole-file packages/harness/tests/creative.test.mjs 0 3433184ced3427613d645807f0757896baf52d214c3dd6a4a12c3951bbdc50ce
187 whole-file packages/harness/tests/gate.test.mjs 0 991670779d9cf6f733d0060c6f1a59d122ab8e99f7e0a5f7183c9e974f1b1aaf
188 whole-file packages/harness/tests/git-tools.test.mjs 0 2837565ec16cd8c4d032311675a1468bc4bc756ee0696d0e57ea35ffd56eea44
189 whole-file packages/harness/tests/library-tools.test.mjs 0 05a8a5d8e8c4e7b3435d4a9b3f6292816356a99f7156ded2ef7873e1c84f8de7
190 whole-file packages/harness/tests/mcp-server.test.mjs 0 6ce4c6c39b8a1ed70fbeaca410781a62d69a6412333e03640296048b799a09b9
191 whole-file packages/harness/tests/pi-session.test.mjs 0 570376f798b43e82bbc1972f1d50d3915e94a8e4ca00e50076ab390df9830d7d
192 whole-file packages/harness/tests/raise-domain.test.mjs 0 aa6be675614d9324c3ddc01ef40347b235adbccfe6cd73081096ae9e9742d754
193 whole-file packages/harness/tests/runner.test.mjs 0 d3f8c752897e359e10a8e9d507c10ef3760a5ae37999f6f143cb222c42568437
194 whole-file packages/harness/tests/skills.test.mjs 0 2f34800387f4d7f8b8d5f6758cd197f77d11034011bf7f4f79f4d74c582e3f0f
195 whole-file packages/harness/tests/spec-tools.test.mjs 0 29cd1f7094266963a995f636d9575337246a9868d42a48f02231a99251261f47
196 whole-file packages/harness/tests/tools.test.mjs 0 f27638f1fa38fd2d15a352f6c21f7980688d48d580f5a59dab1520fd7c30b30c
197 whole-file packages/library/tests/guard.test.mjs 0 6529c2b48c252eeaf9c19487507a03cf46d952e7ffb3a41e640a54590e312df0
198 whole-file packages/library/tests/index-build.test.mjs 0 4747cb8c842cdc424db727cb3b0e36a6d35f4e9c5c31c1a3bf61314897c2cf6d
199 whole-file packages/library/tests/links.test.mjs 0 9b89f9275f19035c5f079b6920b248466048626c634153eba2fec165f9f6388f
200 whole-file packages/library/tests/mapping.test.mjs 0 9110b98f955dd71588357858b913194ccf9e04dca9aa7c4559600cbe9b9e8e71
201 whole-file packages/library/tests/mirror.test.mjs 0 cc2326da9796dbbbf5b3faa121180a7f00c43816a232a96faece7b58570f1227
202 whole-file packages/library/tests/query.test.mjs 0 f1209bc132a63cba9a7312cbed7e3098126e05c792356648f1d9ec497a11aa82
203 whole-file packages/library/tests/reader.test.mjs 0 3e17f34697ae65524cf7908dcc9ca1b24025bbc92989b2ba05f6e75c0f839c3b
204 whole-file packages/library/tests/render.test.mjs 0 5e68091a309a07e5502b9cc500c7cdfabaa9e246bb77b0c04a0dd86bb9bfcde1
205 whole-file packages/library/tests/scope.test.mjs 0 f55dec854adcd311d614b66959c5655cb3419d7ae7b06fe1f648b43cdecef32e
206 whole-file packages/library/tests/supporting.test.mjs 0 2f50bbe9c942360a5becf5bb984ed5aedb12628d4578ea85c6e433ad0ad73130
207 whole-file packages/library/tests/survey.test.mjs 0 72108eb8a07b990b93ca62c5fa4b55f1f89f3254ca1cf59d3de8ad194dcc3a0d
208 whole-file packages/library/tests/sync.test.mjs 0 a68c69492149b6e9dc7dbf24fc434ebfd3243b2db2c7654b00107b997e99ead0
209 whole-file packages/plugins/tests/harness-compactions.test.mjs 0 9eb9f67c06ae17b33198fbcdb443a0c73ca9cc0cd157cae2359a0647d2db3658
210 whole-file packages/processing-control/tests/task.test.mjs 0 8db6adda6b5d5f7437e9e4cdf961134493409d7227fde02c0b0a76aeb21186f0
211 whole-file packages/seat/tests/compactions-budget.test.mjs 0 1849994f45bfcccfb4ce18915887c740947a98041aa7bd66590ae7a62fa7078e
212 whole-file packages/seat/tests/compactions-ledger.test.mjs 0 af689c631c9d62dee11f4400112fd10df82567c1f49d9f0d423b9d19d6f860d7
213 whole-file packages/seat/tests/compactions.test.mjs 0 cf5e74e1211560ca47a2c13e8002635097f486e2ca06698795bc38263d889f3c
214 whole-file packages/seat/tests/sandbox.test.mjs 0 c09d89b8e1b22db25578f62cd4a1d3b9f441d652178fb675800efb31de33a577
215 whole-file packages/seat/tests/session.test.mjs 0 82171646932cddfc68f0e90ca3355f9595d32c5d228c1fdb855c06cb1d9c2feb
216 whole-file packages/tasks/tests/adapter.test.mjs 0 8843067c21942ae6165a7feaced2382fd9d02d0c62bd30772191393cb5d962b8
217 whole-file packages/tasks/tests/comment-restart.test.mjs 0 25aa6e953cf19ed3ae368581035b9d883ed924b41d593240e2b4ab5ba39f2982
218 whole-file packages/tasks/tests/fields.test.mjs 0 e4eafd6b17a46262dddc548263da993bc3a672adca1cadcc698b6d8374f11e2d
219 whole-file packages/tasks/tests/processing.test.mjs 0 0b89866cc076c43c37534dba926d492d8d334d08a6886325e3d4ac6ddbc88897
220 whole-file packages/tasks/tests/shapes.test.mjs 0 0b8cc660a07e048d007993d726ae5b8e1f343cb571c18ee0284c3ba0c4b41602
221 whole-file packages/tasks/tests/startup.test.mjs 0 5b44d779ab4ec86922dd35ce7c78096de02c0a0f2363cc6c2a5ee07816efc2ad
222 whole-file packages/tasks/tests/sync.test.mjs 0 513ce9f6e64a3fa0179f8cc9b27db671267a43cdc44ab93f38d21982dd2b9631
223 whole-file packages/tasks/tests/tree.test.mjs 0 d3c8f91f59150259b3226e9306c98efbaf2aa17b5b74cb9b376a103620f8aefe
224 whole-file packages/tasks/tests/verbs.test.mjs 0 47b075d01ef38a5d0228902a6f9bcfec0b78b1a958cd071e8114139af73bca53
225 whole-file packages/webui/tests/agents-browser.test.mjs 0 d3ae822399f58d2c4dfd90e054811a60663a66f9d3fbe69a76aa4ce7dc7260d0
226 whole-file packages/webui/tests/agents.test.mjs 0 be18c8fed41173900617d3b646fac1ce14c07c208e7f24d6567f61f55c5c4dc2
227 whole-file packages/webui/tests/assistant.test.mjs 0 056e4c2a37b7b395741ed1ba33546031a6e4ca53db843bd877b93bed764e02ad
228 whole-file packages/webui/tests/board-held.test.mjs 0 01a24d222092ad46c24ea94f684a018b787dfc8d26a0f7d7fda5d9df7192e695
229 whole-file packages/webui/tests/browser-edge.test.mjs 0 4d10b4fcefbc64cdf12bbfbd9b47f74810b3219f70624c35490cb23d66d3c4a1
230 whole-file packages/webui/tests/browser.test.mjs 0 d8c31b7cc16d93961d65959fa9653eaba906f81da3a34e19b3da7cc922f840c3
231 whole-file packages/webui/tests/bus-browser.test.mjs 0 ab1538aaabfdb02c336da61675a0d1d7f367483bc500a380e7f0ece050ab8609
232 whole-file packages/webui/tests/bus.test.mjs 0 fd7acdf189fef230af80c32c4c972d9bfb1564069d7c4ed649c3a49bb6636e1e
233 whole-file packages/webui/tests/channel-chat.test.mjs 0 678b8e3c9152662487fee1c52c8abcae95029b0672d5bbe26a824bbdb4a7ee0b
234 whole-file packages/webui/tests/chat-browser.test.mjs 0 ec29dd03ac7950dfa90e31f72ae74e2112718f1c02ce4dce8055194a328b5f5b
235 whole-file packages/webui/tests/chat-instances.test.mjs 0 72c88b1eb11397bcff524af72cfe826a276b97b58e33465c6e3334e2746e7783
236 whole-file packages/webui/tests/chat-replies-browser.test.mjs 0 bea9b1f9333bc913b2f01c29a792ea4b2fdbed3ebc64b42548e06f0bd75c9fc5
237 whole-file packages/webui/tests/chat-sessions-access.test.mjs 0 f2de41c7d1f6e246a8a13dc33e8662932964facc5b93d8f85ed5fca760c87fd8
238 whole-file packages/webui/tests/chat.test.mjs 0 4c6564d3565b01d68f7d16937aafddbef2ec3e04744fa9d1544ac0500a386ff7
239 whole-file packages/webui/tests/conversation.test.mjs 0 1c3f8811256ad82d7771a06878c3e70dc3d6f2beab82366b837780a7873ff6f1
240 whole-file packages/webui/tests/decide-browser.test.mjs 0 c53e1b962df99686f9739e258b2b86fe6325544ab02509833f9b1176f1303845
241 whole-file packages/webui/tests/decide-sso.test.mjs 0 f96f8085015a96e11aca2d94bfb9e75318c0c0dfa9659049ec7b7e31ad7bc6de
242 whole-file packages/webui/tests/decision-http.test.mjs 0 c89b7af200edb82f9986479199f359cf6a06c870f1bcf22b538cdf3b167f1258
243 whole-file packages/webui/tests/discord.test.mjs 0 1c3e6d64a370adbc6c7cb24391989e9c00d97330d393943402ff5c6a99c5f9fc
244 whole-file packages/webui/tests/docs-browser.test.mjs 0 f39d989ccdc561175643583b27bc19ee76fa25dec5947baa206b0c38b41c1e2a
245 whole-file packages/webui/tests/editor-browser.test.mjs 0 c807f81d596b3a2e3d2ea55e560f29e181a0354ce48676c6760844855acb0dd3
246 whole-file packages/webui/tests/editor.test.mjs 0 6953a85fe791e9087d14c3bf5075de2c4a651e1a502937da3226065c529ffd2b
247 whole-file packages/webui/tests/granted-user.test.mjs 0 ae3baaa0d2a1ed1ad3e9625a46a8071222dfdef4c2a70ae3ba5bf159b85dec0b
248 whole-file packages/webui/tests/history-return-flow.test.mjs 0 8f9ceeb41a64ec2849383a78f4997f7383c86a01eb6cf1d16747c2eb6c7448d4
249 whole-file packages/webui/tests/instances-browser.test.mjs 0 33b9cd4be552f89809e75f72c54f73dbe6459a5c53401a79a4d887e5a658c442
250 whole-file packages/webui/tests/instances.test.mjs 0 904abfc06358c99b0f646c3e728027cd7bba2b27c98c767c7da95016e531277c
251 whole-file packages/webui/tests/library-cli.test.mjs 0 dda07bd1b0d65058723c4d5e50f94fefb1ee103c33c8f61c13841cfedfd53f41
252 whole-file packages/webui/tests/library-routes.test.mjs 0 5cd1f4c6ea99cce38ce59eee085ab31f9aa8bba39cebbaf52b355c4d8fec3098
253 whole-file packages/webui/tests/library-status.test.mjs 0 0b4fb5a07a3d35fb2237401b460ddd3832a2f6fa357f6fbb06b8463251b77faa
254 whole-file packages/webui/tests/limits-browser.test.mjs 0 1a55050c92be5b93e447878feafe59e017b205d114413e6de000faf784df1dad
255 whole-file packages/webui/tests/limits-route.test.mjs 0 b74fe734b0ccbdde716bb52bc15791f80a0b251514a6b01d6ba59164b9639123
256 whole-file packages/webui/tests/messages.test.mjs 0 19bce52278091c8d37ca48c1f6f72bc400cd9a9b3038ae9f31e35444fdab05b8
257 whole-file packages/webui/tests/pinned-copy.test.mjs 0 a8c99249fda05c5be773c8d2231e2dd1a3f3b7d10a40a7ec3e6ca6c6cfb4c85a
258 whole-file packages/webui/tests/preview.test.mjs 0 7f7fbb11dd5915b3351b5086ec9b0f0bed6837a32a2e5902b707fcb54f1bf1c3
259 whole-file packages/webui/tests/processing-browser.test.mjs 0 ed5970f1e2b1fa393c80db5e5551523e77ad0ee107dfa686a76c5d923b7e2d8f
260 whole-file packages/webui/tests/processing.test.mjs 0 ac7a3a0ff51bb15c04e228186d771dd75ef515e09156cd080a8bea881e7cdd8d
261 whole-file packages/webui/tests/project-file.test.mjs 0 8bf04994dec5c6d6670bbae055802759588c27b04010582732cbbf32c2921487
262 whole-file packages/webui/tests/project-name-repo.test.mjs 0 ca773d7109f132bd099c43003a8269edfa96b2ba3a9e01e3694fa6bd12b9143e
263 whole-file packages/webui/tests/proof-cli.test.mjs 0 5095f1ec66a3fc153467baef2291073e27aba17fdc2757e0a3cf2a03057a6547
264 whole-file packages/webui/tests/proof.test.mjs 0 cdb948d261f52232c6e31e25baaf234bd0af3b6d90360a41a6142d2f34a8a797
265 whole-file packages/webui/tests/reads.test.mjs 0 ef69c9c1dc9a55d526a704297aa4e2802cdca8f0e1fd70ff79efad2114a071a6
266 whole-file packages/webui/tests/relaunch.test.mjs 0 e9f075560291cb446dabcaeb86c8800b5ea4ca0396c6a999ddbff88b245cefd1
267 whole-file packages/webui/tests/return-flow.test.mjs 0 bf809ee139c15e9b6b8fe7f6e0f2ce00d0860aa460f145242fc732eafe8da8de
268 whole-file packages/webui/tests/room-browser.test.mjs 0 23286bf46f341220f9e89cc1d229f46a579edb2eae5d688fc768f99ee343c858
269 whole-file packages/webui/tests/room-http.test.mjs 0 a921e1991386cb5e184475cf47a012b3020b575968268e9f3c0b396e244a1819
270 whole-file packages/webui/tests/routes-browser.test.mjs 0 df1283a6e1c5970b404b314b6b76dbf412e5318d76f296ec00164c932166b020
271 whole-file packages/webui/tests/routes.test.mjs 0 055aa274fa66910a4ff1518fea49fbbbbbc5360dc16e825a460538f312a0781d
272 whole-file packages/webui/tests/send-browser.test.mjs 0 da1547383522dbfd74a571b5d7625a310ae88f8adddff0c2bd33cb59df3ac137
273 whole-file packages/webui/tests/send.test.mjs 0 f273e78388935b5fbc18a974f50cb85789436d51c47a4d8dccaf4af4742c2392
274 whole-file packages/webui/tests/serve.test.mjs 0 1971344643d9cf6b4440d95c9ede42093235883ffab04fc4b614c1b7e7078f22
275 whole-file packages/webui/tests/settings-form.test.mjs 0 80bd949d1666f2fe1f4caa051e2c34e742bab0e4adbe5584bd534d9bad8bef53
276 whole-file packages/webui/tests/settings-write.test.mjs 0 7090474fff40910edb93c032feef248adc40ad21666d09c3610cf10279164f99
277 whole-file packages/webui/tests/shell.test.mjs 0 844287f7797201473f1fb8d97ff2355ff3ff505006723678db78f26d3e5c2a40
278 whole-file packages/webui/tests/sso-browser.test.mjs 0 1f70c36ce7d054ad435e52d63083c8fe19cd71e70c723518de5e58b69a426a0a
279 whole-file packages/webui/tests/sso.test.mjs 0 6d7b3061bdc6e22744634ddc5612ff781e5c952a120a346c29eead66a3736438
280 whole-file packages/webui/tests/tester-browser.test.mjs 0 425c54a84e5bf04ca91d8dc57ee83c14aff14a38159243f10f1c9114dd563967
281 whole-file packages/webui/tests/tester-cli.test.mjs 0 5eb7296792f16f24d4486f39101007114b3db81c6ab53ab969e925caaffaa7d9
282 whole-file packages/webui/tests/tester-listener.test.mjs 0 43927869c50a0e223d121e2dea2d10346a053a39fc8157c9fc4813b7c3b17e1f
283 whole-file packages/webui/tests/tester-socket.test.mjs 0 c05962be7f87084404c53e4f7ed2caffff3d69e98e69a3c9f3c53b150cc804e5
284 whole-file packages/webui/tests/thread-claims-browser.test.mjs 0 cbb2aeca0de2c64dd4c8d063d3e45140738d8f4064d38effeaec245ed7181b42
285 whole-file packages/webui/tests/thread-claims.test.mjs 0 164a6c927abd819218be6386e123b234dd9955b122bace699e0a12201797791c
286 whole-file packages/webui/tests/thread-sharing.test.mjs 0 ad64ab207702483aed6f16d13393e5f3c5a1ab0a0c2dcdf32717e8148a45078c
287 whole-file packages/webui/tests/usage-browser.test.mjs 0 14be967dcae157cbb0a7b9ea4e0bc67337941d91a11d789baeb3d3c8353ac0e9
288 whole-file packages/webui/tests/usage.test.mjs 0 4e20eee53c3eb79dc2930ca054977d06da88dba45b706a96ed94abaea6ec3e93
289 whole-file packages/webui/tests/user-option-swap.test.mjs 0 bd43c257ae31cad2ca6c7a0b3ee49c6e323737d236fb7ff2a2105fd5e59b9767
290 whole-file packages/webui/tests/views.test.mjs 0 4226ea02d33b9de8f2eaf9f93b0a551cbd9e6100560a8811eed90aa8de76974c
291 script scripts/test-auth.sh 0 03999aab66446a4192ea9855f5cc1bd406080d0dfa5250b45b30e118556a0d5a
292 script scripts/test-conductor.sh 0 79b7a689ed96792d42edd1d14796e0293e84e2e339b49476e457ad89e1c4a186
293 script scripts/test-config.sh 0 2c3c87fb193e82fa17428933eb69cb2b34a589e8338f7a94aaa8256729fdf08f
294 script scripts/test-discord.sh 0 5c6918b4415e8eabc5df31ac5ad696ec2afdfe3d498d69eae64f228a3807eddb
295 script scripts/test-extension-package.sh 0 1f672a73e507cc57a204f7d3806ddcb211a0a8fb3ffccefc12bbc41e299f65ac
296 script scripts/test-federation-acceptance.sh 0 febb0148bc1316bba3189aacf34d7c78f5f5db5d97a35aa4528dfadbec8bfbd0
297 script scripts/test-foundation.sh 0 3de063333ce60ef1ca1986ecdd8ac30187a2316b7ca8e3ae4b4e6c8bd435caee
298 script scripts/test-land-work.sh 0 ec90beab6246420982f872a4f45a7173e7a06f4aa263630d6ec4a4865176cde0
299 script scripts/test-push-check.sh 0 0304c110dc5cf269fd8a4bea9759e5d48895a51c9d411814ce39ca924073da79
300 script scripts/test-queue.sh 0 f678da9550eb6daa5268465b3a07beefd661e506ed38b8e11bf0a1b4a68cc781
301 script scripts/test-release.sh 0 ad0f2a6b271275003783d3ffab5520f167ea79e26683710ce92a71600037360c
302 script scripts/test-task.sh 0 ad511e52af4bc0a843eabbb3efcedd88c89468ccee43be9022e23880d7901f16
303 mutant M1-supporting 1 0 10581fdab579db4d63322eee3369a1a740266e00a7dcbaa95e7651a7e0447ab8
304 mutant M2-force-push 1 0 b137e8362ae3e26a090a82e8c41c3e87beeaac43183cdd6db67aba55d5e372c9
305 mutant M3-forged-token 1 0 bda603c18b7b2bf468a21e139f0cff0c15c22e19c9d41cf8c50f9c3ae0bd128d
306 mutant M4-grant-before-push 1 0 a642ef8e57a98c1488bb787da241292e6ed5446ca4117940fb0ddb9800c6a105
307 mutant M5-notice-after-publication 1 0 5645138c2cef5d1999948744783ff3904a78e9cefd7421674386a2d0c5fdc45a
308 mutant M6-commit-schema 1 0 7201f53cb976b2db1994c4e25f7f6e8b58eea323c060dbddbfa0372464adb686
@@ -0,0 +1,102 @@
{
"total": {
"tests": 2605,
"pass": 2604,
"fail": 0,
"cancelled": 0,
"skipped": 1,
"todo": 0
},
"packages": {
"library": {
"files": 13,
"tests": 168,
"pass": 168,
"fail": 0,
"cancelled": 0,
"skipped": 0,
"todo": 0
},
"bus": {
"files": 116,
"tests": 1035,
"pass": 1035,
"fail": 0,
"cancelled": 0,
"skipped": 0,
"todo": 0
},
"harness": {
"files": 16,
"tests": 180,
"pass": 180,
"fail": 0,
"cancelled": 0,
"skipped": 0,
"todo": 0
},
"webui": {
"files": 67,
"tests": 398,
"pass": 398,
"fail": 0,
"cancelled": 0,
"skipped": 0,
"todo": 0
},
"business": {
"files": 2,
"tests": 25,
"pass": 25,
"fail": 0,
"cancelled": 0,
"skipped": 0,
"todo": 0
},
"cli": {
"files": 59,
"tests": 620,
"pass": 619,
"fail": 0,
"cancelled": 0,
"skipped": 1,
"todo": 0
},
"plugins": {
"files": 1,
"tests": 8,
"pass": 8,
"fail": 0,
"cancelled": 0,
"skipped": 0,
"todo": 0
},
"processing-control": {
"files": 1,
"tests": 7,
"pass": 7,
"fail": 0,
"cancelled": 0,
"skipped": 0,
"todo": 0
},
"seat": {
"files": 5,
"tests": 69,
"pass": 69,
"fail": 0,
"cancelled": 0,
"skipped": 0,
"todo": 0
},
"tasks": {
"files": 9,
"tests": 95,
"pass": 95,
"fail": 0,
"cancelled": 0,
"skipped": 0,
"todo": 0
}
}
}
+6
View File
@@ -1694,3 +1694,9 @@ are never rewritten or removed; corrections are new entries.
2026-10-24 | magica | row329 R2 #1827 | ASCII management-key fix and docs verified: package66/66,bus readers261/261,CLI readers726/726,config55/55; no required failures/skips, slot returned. Preparing authorized ff review candidate; old tests unchanged.
2026-10-24 | Sage 1ef1e4f8 | row329 landing #1827 (mos-1634) | Gate GREEN 23:29:14Z unchanged, landed 61ebf2c34 pushed 23:31:27Z; #1827 closed c31650; queue note 4063, done 4064 (b24d917ec); DEFERRED N2/R2-N1 to 331, N1 to P7; Vikunja 631 filed, 237 c1109; 284 and 157 must rebase.
2026-10-25 | Sage 1ef1e4f8 | row284 landing #1789 | Gate GREEN 00:09:04Z unchanged, landed ce0b6ed41 pushed 00:09:52Z; #1789 closed c31655; queue note 4071, done 4072 (7c8dc2033); DEFERRED Webby N1 to the next library read-path row; row 332 PROXY_CODEX_API ruled openai-responses (sage-4331), P3 holds for row 331.
2026-10-23 | Bubba (Codex gpt-6.1-sol, 3d6672b5) | Row 288 / #1793 C2-02 in bubba/row288; mos-1499, sage-3613 | Started; 283/285/286 merged intact, static build pending Sage CLEAR; queue ownership remains with Sage.
2026-10-24 | Bubba (3d6672b5) | Row288 static preflight, sage-4282 | Creative contract/tool names match; short fixture tokens; provisional import-based whole-file run list excludes Case1; no Node/test run, awaiting landed284 base and CLEAR.
2026-10-25 | Bubba | row288 sage-4338 landed-base transplant and import audit | New bubba/row288-r3-landed on78b69e1e6; no test conflicts/assertion changes;289 whole files +12 runners proposed; UNTESTED pending CLEAR.
2026-10-25 | Bubba | row288 gate sage-4396 | Tested2848d832e:289 files/12 scripts rc0,6 mutants killed with restored controls rc0; own reds recorded/fixed; slot returned bubba-0034, review/landing pending.
+95 -11
View File
@@ -110,7 +110,7 @@ const LIBRARY_LOOKUPS = Object.freeze({
'library.manuscript': { method: 'manuscript', fields: ['universe', 'book', 'scope', 'chapter', 'from', 'to'], required: ['universe', 'book'] },
'library.universe': { method: 'universeInfo', fields: ['universe'], required: ['universe'] },
});
export const LIBRARY_VERBS = Object.freeze(['library.file', 'library.status', 'library.sync', ...Object.keys(LIBRARY_LOOKUPS)]);
export const LIBRARY_VERBS = Object.freeze(['library.file', 'library.status', 'library.sync', 'library.file.save', 'library.revert', 'library.doc.write', 'library.doc.delete', ...Object.keys(LIBRARY_LOOKUPS)]);
export const PROJECT_SAVE_VERB = 'project.file.save';
export const PROJECT_SAVE_REQUEST_MAX = 1024 * 1024 + 64 * 1024;
export const WEB_VERBS =Object.freeze(['web.search', 'web.fetch']);
@@ -5411,18 +5411,99 @@ export class Broker {
}
// C2-04 M4: only a verified human reads library text or status. Host Git
// functions stay injected, preserving this module's sandbox import closure.
// C2-02: all authority and credential choice stays on the host. Neither an agent's tool
// arguments nor the human's save may supply a credential, identity or commit message.
#libraryWriter(s, project) {
if (s.tester) fail('tester-refused');
const b = this.#business(s.business), role = b.roles?.[s.role];
if (s.human || s.reader || !CREATIVE_DEFINITIONS.includes(role?.definition)
|| !role.authority?.withinRole?.includes('library.write')) fail('library-write-refused');
this.#agent(s);
const live = this.#store.get('SELECT user,projects,rotate_by FROM gitea_grants WHERE business=? AND agent=?', s.business, s.role);
if (!live || !this.#giteaKeys || this.#giteaKeys.held(s.business, s.role)
|| this.#firing(s.business, s.role) || live.rotate_by < this.#now().slice(0, 10)
|| !role.publish?.includes(project)) fail('library-write-no-grant');
let projects;
try { projects = JSON.parse(live.projects); } catch { fail('library-write-no-grant'); }
if (!Array.isArray(projects) || !projects.includes(project) || live.user !== role.identity?.gitea?.user)
fail('library-write-no-grant');
if (!role.identity?.name || !role.identity?.email) fail('library-write-refused');
return { identity: { name: role.identity.name, email: role.identity.email },
agent: `${s.business}/${s.role}`, credential: { kind: 'seat', agent: s.role, user: live.user } };
}
#libraryWriteNotice(s, op, result) {
const mid = randomUUID();
this.#store.run('INSERT INTO messages(id,at,business,from_role,from_run,to_role,class,in_reply_to,decision,corrects,body) VALUES(?,?,?,?,?,?,?,?,?,?,?)',
mid, this.#now(), s.business, s.role, s.run, 'human', 'INFO', null, null, null,
JSON.stringify({ notice: 'library-write', op, path: result.path, commit: result.commit }));
this.#route(s.business, mid, 'human', s.session);
}
async #requestLibrary(s, request) {
const { verb, args } = request;
if (Object.hasOwn(LIBRARY_LOOKUPS, verb)) return this.#requestLibraryLookup(s, request);
try {
this.#human(s);
const fields = verb === 'library.file' ? ['project', 'path'] : verb === 'library.sync' ? ['project', 'accept'] : ['project'];
keys(args, fields, verb === 'library.sync' ? ['project'] : fields);
if (!this.#library?.readFile || !this.#library?.status) fail('project-not-configured');
if (verb === 'library.sync' && !this.#library.sync) fail('project-not-configured');
const context = { business: this.#business(s.business), project: args.project };
const agent = verb === 'library.doc.write' || verb === 'library.doc.delete';
const b = this.#business(s.business);
let project = args.project, writer;
if (agent) {
// The caller gate precedes argument checks, including human and tester refusals.
if (s.tester) fail('tester-refused');
if (s.human || s.reader || !CREATIVE_DEFINITIONS.includes(b.roles?.[s.role]?.definition)
|| !b.roles[s.role].authority?.withinRole?.includes('library.write')) fail('library-write-refused');
this.#agent(s);
const fields = ['universe', 'path', 'base', ...(verb === 'library.doc.write' ? ['content'] : [])];
keys(args, fields, fields);
if (typeof args.universe !== 'string') fail('invalid-request');
const matches = Object.entries(b.projects ?? {}).filter(([, e]) => e.kind === 'library'
&& Object.hasOwn(e.universes ?? {}, args.universe));
if (matches.length !== 1) fail('project-not-configured');
project = matches[0][0];
writer = this.#libraryWriter(s, project);
} else {
this.#human(s);
const fields = verb === 'library.file' ? ['project', 'path'] : verb === 'library.sync' ? ['project', 'accept']
: verb === 'library.file.save' ? ['project', 'path', 'base', 'content']
: verb === 'library.revert' ? ['project', 'commit'] : ['project'];
keys(args, fields, verb === 'library.sync' ? ['project'] : fields);
}
if (typeof project !== 'string' || b.projects?.[project]?.kind !== 'library') fail('project-not-configured');
if (verb === 'library.revert' && (typeof args.commit !== 'string' || !/^[a-f0-9]{40}$/.test(args.commit))) fail('invalid-request');
if (agent || verb === 'library.file.save') {
if (args.base !== null && (typeof args.base !== 'string' || !/^[a-f0-9]{40}$/.test(args.base))) fail('invalid-request');
if (verb !== 'library.doc.delete' && (typeof args.content !== 'string' || args.content.includes('\0')
|| Buffer.byteLength(args.content, 'utf8') > 1024 * 1024
|| Buffer.from(args.content, 'utf8').toString('utf8') !== args.content)) fail('invalid-request');
}
const context = { business: b, project };
let result;
if (verb === 'library.file') result = await this.#library.readFile({ ...context, path: args.path });
const method = agent ? 'writeDoc' : verb === 'library.file.save' ? 'saveFile'
: verb === 'library.revert' ? 'revert' : verb === 'library.file' ? 'readFile' : verb === 'library.status' ? 'status' : 'sync';
if (typeof this.#library?.[method] !== 'function') fail('project-not-configured');
if (agent) {
const op = verb === 'library.doc.delete' ? 'delete' : 'write';
result = await this.#library.writeDoc({ ...context, ...args }, { ...writer, op,
beforePush: () => { this.#processingWork(); this.#libraryWriter(s, project); },
onPushed: saved => {
try {
this.#store.transaction(() => {
this.#libraryWriteNotice(s, op, saved);
this.#event(s, 'action.allowed', { action: 'library.write', class: 'within-role', project, path: saved.path, commit: saved.commit });
});
} catch {
// A separate metadata-only sink survives a Console store failure. Never log args,
// file text, credentials or raw SQL/exception output.
try { this.#library.log?.({ event: 'library-notice-store-failed', code: 'outcome-unknown',
business: s.business, instance: s.role, op, commit: saved.commit }); } catch {}
fail('outcome-unknown');
}
} });
} else if (verb === 'library.file.save') {
this.#processingWork();
result = await this.#library.saveFile({ ...context, path: args.path, base: args.base, content: args.content });
} else if (verb === 'library.revert') {
this.#processingWork();
result = await this.#library.revert({ ...context, commit: args.commit });
} else if (verb === 'library.file') result = await this.#library.readFile({ ...context, path: args.path });
else if (verb === 'library.status') {
result = await this.#library.status(context);
// C2-06: the reply limits in force, read from the file now, and the keys that fell back.
@@ -5432,16 +5513,19 @@ export class Broker {
}
}
else {
// A fetch that did not move served still answers with the code, so the refusal is recorded.
const { state, code } = await this.#library.sync(context, { accept: args.accept ?? null });
if (code !== null) fail(code);
result = { project: args.project, ...state };
result = { project, ...state };
}
this.#secretCheck(result);
return result;
} catch (error) {
const Failure = this.#library?.LibraryError;
throw this.#refused(s, Failure && error instanceof Failure ? new BusError(error.code) : error, request);
const mapped = Failure && error instanceof Failure ? new BusError(error.code) : error;
const refused = this.#refused(s, mapped, request);
// Once a push succeeded the remote effect is uncertain to the caller even if the store
// cannot record refusal evidence. Do not replace that with an ordinary storage refusal.
throw mapped instanceof BusError && mapped.code === 'outcome-unknown' ? mapped : refused;
}
}
// C2-06: the business's library project, the first in file order, or null.
+1 -1
View File
@@ -17,7 +17,7 @@ export class Client {
verb,
args,
}) + '\n';
if (Buffer.byteLength(request) > (verb === PROJECT_SAVE_VERB ? PROJECT_SAVE_REQUEST_MAX : 65536))
if (Buffer.byteLength(request) > ([PROJECT_SAVE_VERB, 'library.file.save'].includes(verb) ? PROJECT_SAVE_REQUEST_MAX : 65536))
return Promise.reject(new BusError('request-too-large'));
return new Promise((resolve, reject) => {
const socket = connect(this.path);
+15
View File
@@ -281,6 +281,12 @@ export async function startBroker({
credential: fetchCredential(business),
...(librarySync ? { command: librarySync.command } : {}),
});
const humanWriteOptions = context => {
const mapping = libraryModule.checkMapping(context.business.projects[context.project]);
if (!mapping.editor) throw new libraryModule.LibraryError('library-mapping-invalid', 'editor is required');
return { credential: libraryModule.humanCredential(context, { user: mapping.editor.user, configDir: slotDir }),
...(librarySync ? { command: librarySync.command } : {}) };
};
// Row 194 (#1692, D3): after every write that commits, the broker takes the business as a restart
// would load it. The credential references, the project roots the Credentials store protects
// and the tracker bots are fixed at start (the Credentials store, the tasks adapter), so a file
@@ -356,9 +362,18 @@ export async function startBroker({
library: {
lookup: createLibraryLookup({ dataRoot, sync: context =>
processing.work(() => libraryModule.sync(context, syncOptions(context.business))) }),
log: entry => process.stderr.write(`library: ${JSON.stringify(entry)}\n`),
readFile: context => libraryModule.readLibraryFile({ ...context, dataRoot }),
status: context => libraryModule.libraryStatus({ ...context, dataRoot }),
sync: (context, { accept }) => processing.work(() => libraryModule.sync({ ...context, dataRoot }, { ...syncOptions(context.business), accept })),
// C2-02: trusted references only. The askpass helper alone opens a credential file.
writeDoc: (context, options) => processing.work(() => libraryModule.writeLibraryDoc({ ...context, dataRoot }, {
...options, credential: { ...options.credential,
file: storeRoot ? giteaReference(storeRoot, context.business.id, options.credential.agent).file : null },
...(librarySync ? { command: librarySync.command } : {}),
})),
saveFile: context => processing.work(() => libraryModule.saveLibraryFile({ ...context, dataRoot }, humanWriteOptions(context))),
revert: context => processing.work(() => libraryModule.revertLibraryCommit({ ...context, dataRoot }, humanWriteOptions(context))),
LibraryError: libraryModule.LibraryError,
// C2-06: the citation guard, the reply limits read from the business file at each check (none
// configured reads as unreadable, so requireCitation is true), and thread.messages' `last`.
+4 -2
View File
@@ -6,7 +6,9 @@ import { createPeerReader } from './peercred.mjs';
const LIMIT = 65536;
// Row 148: a document save may carry up to 1 MiB of text. Only a request that names that verb near
// its start (the proof object comes first) may pass LIMIT; the parsed verb is checked again below.
const SAVE_VERB_AT_START = new RegExp(`"verb":"${PROJECT_SAVE_VERB.replaceAll('.', '\\.')}"`);
const PROJECT_SAVE_AT_START = new RegExp(`"verb":"${PROJECT_SAVE_VERB.replaceAll('.', '\\.')}"`);
const LIBRARY_SAVE_AT_START = /"verb":"library\.file\.save"/;
const SAVE_VERB_AT_START = { test: text => PROJECT_SAVE_AT_START.test(text) || LIBRARY_SAVE_AT_START.test(text) };
// The refusal envelope. C2-06 (sage-3599): `reason` is added only when the error carries one, which
// only the citation guard's refusals do, so every other envelope is byte-identical to before.
const refusal = (e, other) => e instanceof BusError
@@ -66,7 +68,7 @@ export async function serve({ broker, path, authenticateHuman = null, authentica
try {
if (end !== input.length - 1) throw new BusError('invalid-envelope');
const r = JSON.parse(input.subarray(0, end).toString('utf8'));
if (input.length > LIMIT && r?.verb !== PROJECT_SAVE_VERB) throw new BusError('request-too-large');
if (input.length > LIMIT && ![PROJECT_SAVE_VERB, 'library.file.save'].includes(r?.verb)) throw new BusError('request-too-large');
if (
!r ||
Array.isArray(r) ||
+334
View File
@@ -0,0 +1,334 @@
// Row 288: broker authority, exact notice and strict Console revert API. Fixture grant rows only.
import test from 'node:test';
import assert from 'node:assert/strict';
import { mkdtempSync, rmSync, mkdirSync, writeFileSync, readFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { connect } from 'node:net';
import { startBroker, createLibraryLookup } from '../src/runtime.mjs';
import { Store } from '../src/store.mjs';
import { Broker } from '../src/broker.mjs';
import { Client } from '../src/client.mjs';
import { serve } from '../src/server.mjs';
import { mappingEntry } from '../../library/tests/helpers.mjs';
import { LibraryError } from '../../library/src/problems.mjs';
import { grantDecision } from './host-fixtures.mjs';
import { world as bareWorld } from '../../library/tests/write-fixture.mjs';
import { sync } from '../../library/src/sync.mjs';
import { SYNC_STATE_FILE, servedCommit } from '../../library/src/mirror.mjs';
import { writeLibraryDoc, saveLibraryFile, revertLibraryCommit } from '../../library/src/write.mjs';
import { git } from '../../library/tests/helpers.mjs';
const SHA = 'a'.repeat(40), NEXT = 'b'.repeat(40), PATH = 'Book One/Notes/Agent.md';
function world(t, options = {}) {
const root = mkdtempSync(join(tmpdir(), 'bus-library-write-')), store = new Store(root);
t.after(() => { store.close(); rmSync(root, { recursive: true, force: true }); });
const projects = options.projects ?? { books: mappingEntry() }; projects.books.universes.harbor.supporting = ['Book One/Notes/'];
const authority = { withinRole: ['message.send', 'library.write'], crossRole: [] };
const roles = { bean: { definition: 'companion', authority, identity: { name: 'Bean', email: '[email protected]', gitea: { user: 'bean', url: 'https://git.example.invalid' } }, publish: ['books'] },
chief: { definition: 'chief-of-staff', authority }, quill: { definition: 'proofreader', authority: { withinRole: ['message.send'], crossRole: [] } } };
options.changeRole?.(roles.bean);
const business = { id: 'acme', human: 'jason', vars: { 'bus.tester': true }, projects, roles,
arbiters: { technical: 'chief', delivery: 'chief' }, definitions: { companion: {}, 'chief-of-staff': {}, proofreader: {} } };
const seen = [], held = new Set(), logs = [];
const result = { project: 'books', path: PATH, commit: NEXT };
const library = { LibraryError, log: entry => logs.push(entry), readFile: async () => ({}), status: async () => ({}),
writeDoc: async (context, options) => { seen.push({ context, options }); options.beforePush(); options.onPushed(result); return result; },
saveFile: async context => { seen.push({ context }); return result; },
revert: async context => { seen.push({ context }); return { ...result, reverted: context.commit }; } };
const broker = new Broker({ store, businesses: { acme: business }, library, giteaKeys: { held: (b, a) => held.has(a) } });
const caps = { human: broker.bindHuman({ business: 'acme', human: 'jason', via: 'cli', outsideAgent: true }),
tester: broker.bindTester({ business: 'acme' }) };
const p = broker.request(caps.human, { verb: 'project.create', args: { name: 'Library chat', repo: 'books' } }).id;
for (const role of ['bean', 'quill', 'chief']) {
const thread = role === 'chief' ? null : broker.request(caps.human,
{ verb: 'thread.create', args: { project: p, name: role, instance: role } }).id;
caps[role] = broker.bindLaunch({ business: 'acme', role, run: role + '-run', harness: 'pi', ...(thread ? { thread } : {}) });
broker.request(caps[role], { verb: 'role.claim' });
}
const grant = (project = 'books') => {
const decision = grantDecision(store, { business: 'acme', grant: { method: 'gitea', agent: 'bean', target: { projects: [project] }, rotateBy: '2099-01-01' } });
store.run('INSERT OR IGNORE INTO gitea_users(business,agent,user,id,nonce,decision) VALUES(?,?,?,?,?,?)',
'acme', 'bean', 'bean', 7, '0123456789abcdef', decision);
store.run('INSERT OR REPLACE INTO gitea_grants(business,agent,user,token_id,token_name,projects,rotate_by,decision) VALUES(?,?,?,?,?,?,?,?)',
'acme', 'bean', 'bean', 7, 'fixture', JSON.stringify([project]), '2099-01-01', decision);
};
grant();
const call = (who, verb, args = {}) => Promise.resolve().then(() => broker.request(caps[who], { verb, args }));
return { root, store, broker, caps, call, seen, held, business, grant, library, logs };
}
const args = () => ({ universe: 'harbor', path: PATH, base: SHA, content: 'fixture\n' });
test('C2-02: agent verbs require creative holder, action and live unheld project grant', async t => {
const f = world(t);
for (const verb of ['library.doc.write', 'library.doc.delete']) {
const a = args(); if (verb.endsWith('delete')) delete a.content;
for (const [who, code] of [['human', 'library-write-refused'], ['tester', 'tester-refused'], ['chief', 'library-write-refused'], ['quill', 'library-write-refused']])
await assert.rejects(f.call(who, verb, a), { code });
f.held.add('bean'); await assert.rejects(f.call('bean', verb, a), { code: 'library-write-no-grant' }); f.held.clear();
f.store.run('DELETE FROM gitea_grants');
await assert.rejects(f.call('bean', verb, a), { code: 'library-write-no-grant' });
f.grant('other'); await assert.rejects(f.call('bean', verb, a), { code: 'library-write-no-grant' });
f.store.run('DELETE FROM gitea_grants'); f.grant();
}
assert.equal(f.seen.length, 0);
});
test('C2-02: writing instance supplies neither ident nor notice text; broker inserts exact notice', async t => {
const f = world(t);
const result = await f.call('bean', 'library.doc.write', args());
assert.equal(result.commit, NEXT);
const m = f.store.get("SELECT * FROM messages WHERE from_role='bean' AND to_role='human'");
assert.equal(m.body, JSON.stringify({ notice: 'library-write', op: 'write', path: PATH, commit: NEXT }));
assert.equal(m.from_run, 'bean-run');
assert.ok(f.store.get('SELECT 1 FROM message_threads WHERE message=?', m.id));
assert.equal(f.seen[0].options.identity.name, 'Bean');
assert.equal(f.seen[0].options.credential.user, 'bean');
assert.equal(f.seen[0].options.credential.agent, 'bean');
for (const extra of [{ author: 'other' }, { agent: 'chief' }, { credential: { agent: 'chief' } }])
await assert.rejects(f.call('bean', 'library.doc.write', { ...args(), ...extra }), { code: 'invalid-request' });
});
test('C2-02 A2: strict human revert args/result and agent human-required refusal', async t => {
const f = world(t);
for (const who of ['bean', 'quill', 'chief', 'tester'])
for (const verb of ['library.revert', 'library.file.save'])
await assert.rejects(f.call(who, verb, {}), { code: 'human-required' });
for (const a of [{ commit: SHA }, { project: 'books' }, { project: 'books', commit: 'A'.repeat(40) },
{ project: 'books', commit: SHA, editor: {} }, { project: 'books', commit: SHA + 'a' }])
await assert.rejects(f.call('human', 'library.revert', a), { code: 'invalid-request' });
assert.deepEqual(await f.call('human', 'library.revert', { project: 'books', commit: SHA }),
{ project: 'books', path: PATH, reverted: SHA, commit: NEXT });
await assert.rejects(f.call('human', 'library.revert', { project: 'missing', commit: SHA }), { code: 'project-not-configured' });
});
test('C2-02: human revert independent of revoked seat and LibraryError codes survive', async t => {
const f = world(t); f.store.run('DELETE FROM gitea_grants'); f.held.add('bean');
assert.equal((await f.call('human', 'library.revert', { project: 'books', commit: SHA })).reverted, SHA);
for (const code of ['library-revert-not-agent', 'stale-base', 'library-mapping-invalid', 'library-human-missing']) {
f.library.revert = async () => { throw new LibraryError(code, 'fixture'); };
await assert.rejects(f.call('human', 'library.revert', { project: 'books', commit: SHA }), { code });
}
});
test('C2-02 transport: human library.file.save exceeds 64 KiB; agent write remains bounded', async t => {
const f = world(t), path = join(f.root, 'bus.sock');
const server = await serve({ broker: f.broker, path, authenticateHuman: () => f.broker.bindHuman({ business: 'acme', human: 'jason', via: 'cli', outsideAgent: true }) });
t.after(() => server.close());
const human = new Client({ path, human: { fixture: true } }), agent = new Client({ path, cap: f.caps.bean });
const content = 'x'.repeat(70000);
assert.equal((await human.call('library.file.save', { project: 'books', path: PATH, base: SHA, content })).commit, NEXT);
assert.equal(f.seen.at(-1).context.content, content);
await assert.rejects(agent.call('library.doc.write', { ...args(), content }), { code: 'request-too-large' });
await assert.rejects(human.call('library.file.save', { project: 'books', path: PATH, base: SHA, content: 'x'.repeat(2 * 1024 * 1024) }), { code: 'request-too-large' });
});
test('C2-02 M12 through broker: every refusal preserves remote, served and all mirror refs', async t => {
const bare = await bareWorld(t), f = world(t, { projects: bare.context.business.projects });
f.library.writeDoc = (context, options) => writeLibraryDoc({ ...context, dataRoot: bare.context.dataRoot },
{ ...options, credential: { ...options.credential, file: bare.file }, command: bare.command });
for (const path of ['Book One/Chapters/Chapter 01.md', 'Inbox Note.md', 'Book One/Playground/What If.md',
'Book One/Notes/X.canvas', 'Book One/Notes/X.base', 'Book One/Notes/X.png', 'Second World/Chapters/01.md',
'/Book One/Notes/X.md', 'Book One/Notes/../X.md', 'Book One/./Notes/X.md', 'Book One//Notes/X.md',
'Book One/Notes/X\\Y.md', 'Book One/Notes/X\nY.md', 'Book One/Notes/Link.md', 'Book One/Notes/Submodule.md',
'Book One/Notes/agent.md', `Book One/Notes/${'é'.repeat(512)}.md`]) {
for (const verb of ['library.doc.write', 'library.doc.delete']) {
const before = bare.refs(), head = bare.remoteHead(), a = { ...args(), path, base: null };
if (verb.endsWith('delete')) delete a.content;
await assert.rejects(f.call('bean', verb, a), { code: 'library-write-story-path' }, path);
assert.equal(bare.refs(), before); assert.equal(bare.remoteHead(), head);
}
}
assert.equal(f.store.get("SELECT count(*) n FROM messages WHERE from_role='bean'").n, 0);
});
test('C2-02 broker + bare: exact write/delete notices, then human revert with revoked seat grant', async t => {
const bare = await bareWorld(t), f = world(t, { projects: bare.context.business.projects });
f.library.writeDoc = (context, options) => writeLibraryDoc({ ...context, dataRoot: bare.context.dataRoot },
{ ...options, credential: { ...options.credential, file: bare.file }, command: bare.command });
f.library.revert = context => revertLibraryCommit({ ...context, dataRoot: bare.context.dataRoot },
{ credential: { ...bare.credential, kind: 'human' }, command: bare.command });
f.library.saveFile = context => saveLibraryFile({ ...context, dataRoot: bare.context.dataRoot },
{ credential: { ...bare.credential, kind: 'human' }, command: bare.command });
const base = git(bare.mirror, 'rev-parse', `served:${PATH}`);
const saved = await f.call('bean', 'library.doc.write', { ...args(), base });
assert.equal(saved.commit, bare.remoteHead());
f.store.run('DELETE FROM gitea_grants'); f.held.add('bean');
const reverted = await f.call('human', 'library.revert', { project: 'books', commit: saved.commit });
assert.equal(reverted.reverted, saved.commit);
assert.equal(git(bare.remote, 'show', `main:${PATH}`), 'before');
assert.equal(git(bare.remote, 'show', '-s', '--format=%an <%ae>', reverted.commit), 'Human Fixture <[email protected]>');
f.held.clear(); f.grant();
const deleted = await f.call('bean', 'library.doc.delete', { universe: 'harbor', path: PATH, base });
const messages = f.store.all("SELECT body FROM messages WHERE from_role='bean' AND to_role='human' ORDER BY seq");
assert.deepEqual(messages.map(m => JSON.parse(m.body)), [
{ notice: 'library-write', op: 'write', path: PATH, commit: saved.commit },
{ notice: 'library-write', op: 'delete', path: PATH, commit: deleted.commit }]);
assert.equal(git(bare.remote, 'ls-tree', '-r', deleted.commit, '--', PATH), '');
});
test('C2-02 socket: a save name nested in proof cannot enlarge an agent envelope', async t => {
const f = world(t), path = join(f.root, 'raw-bus.sock');
const server = await serve({ broker: f.broker, path, authenticateHuman: () => f.caps.human });
t.after(() => server.close());
const request = JSON.stringify({ human: { verb: 'library.file.save' }, verb: 'library.doc.write',
args: { ...args(), content: 'x'.repeat(70000) } }) + '\n';
const response = await new Promise((resolve, reject) => {
const socket = connect(path); let result = '';
socket.on('error', reject); socket.on('connect', () => socket.write(request));
socket.on('data', bytes => { result += bytes; if (result.includes('\n')) { socket.destroy(); resolve(JSON.parse(result)); } });
});
assert.deepEqual(response, { ok: false, error: 'request-too-large' });
assert.equal(f.seen.length, 0);
});
test('C2-02 E2: held grant during fetch refuses at beforePush and preserves every ref', async t => {
const bare = await bareWorld(t), f = world(t, { projects: bare.context.business.projects });
const before = bare.refs(), head = bare.remoteHead();
const command = (kind, url, options) => {
if (kind === 'fetch') f.held.add('bean');
return bare.command(kind, url, options);
};
f.library.writeDoc = (context, options) => writeLibraryDoc({ ...context, dataRoot: bare.context.dataRoot },
{ ...options, credential: { ...options.credential, file: bare.file }, command });
await assert.rejects(f.call('bean', 'library.doc.write', { ...args(), base: git(bare.mirror, 'rev-parse', `served:${PATH}`) }),
{ code: 'library-write-no-grant' });
assert.equal(bare.refs(), before); assert.equal(bare.remoteHead(), head);
assert.equal(f.store.get("SELECT count(*) n FROM messages WHERE from_role='bean'").n, 0);
});
test('C2-02 E3: expired, firing, missing publish, wrong grant user and missing ident refuse', async t => {
const cases = [
{ name: 'expired', prepare: f => f.store.run("UPDATE gitea_grants SET rotate_by='2000-01-01'"), code: 'library-write-no-grant' },
{ name: 'firing', prepare: f => f.store.run("INSERT INTO events(id,at,business,kind,actor_role,actor_run,subject,body) VALUES('fire-bean',?,'acme','action.allowed','chief','run','bean',?)",
new Date().toISOString(), JSON.stringify({ action: 'fire.stopped' })), code: 'library-write-no-grant' },
{ name: 'publish', changeRole: r => { r.publish = []; }, code: 'library-write-no-grant' },
{ name: 'grant user', prepare: f => f.store.run("UPDATE gitea_grants SET user='other-seat'"), code: 'library-write-no-grant' },
{ name: 'identity name', changeRole: r => { delete r.identity.name; }, code: 'library-write-refused' },
{ name: 'identity email', changeRole: r => { delete r.identity.email; }, code: 'library-write-refused' },
];
for (const c of cases) {
const f = world(t, { changeRole: c.changeRole }); c.prepare?.(f);
for (const verb of ['library.doc.write', 'library.doc.delete']) {
const a = args(); if (verb.endsWith('delete')) delete a.content;
await assert.rejects(f.call('bean', verb, a), { code: c.code }, c.name);
}
assert.equal(f.seen.length, 0);
}
});
test('C2-02 F2/E6 runtime: human saves/reverts use editor.user; no login never uses the fetch bot', { timeout: 30000 }, async t => {
for (const user of [undefined, 'her-gitea-login']) {
const bare = await bareWorld(t);
const agent = await writeLibraryDoc(bare.args(), bare.opts);
bare.entry.user = 'fetch-bot';
if (user) bare.entry.editor.user = user;
const configDir = join(bare.root, 'config'), slots = join(configDir, 'secrets', 'acme');
mkdirSync(slots, { recursive: true, mode: 0o700 });
for (const slot of ['library-human', 'library-gitea'])
writeFileSync(join(slots, slot), 'fx288-human\n', { mode: 0o600 });
const pushes = [];
const command = (kind, url, options) => { if (kind === 'push') pushes.push(options.user); return bare.command(kind, url, options); };
const initial = (await bare.state()).lastFetch;
const business = { ...bare.context.business, human: 'jason', roles: { coder: { authority: { withinRole: [], crossRole: [] } } },
arbiters: { technical: 'coder', delivery: 'coder' } };
const runtime = await startBroker({ dataRoot: bare.context.dataRoot, businesses: { acme: business },
librarySync: { configDir, command, intervalMs: 60000 } });
try {
const human = runtime.broker.bindHuman({ business: 'acme', human: 'jason', via: 'cli', outsideAgent: true });
const call = (verb, args) => Promise.resolve().then(() => runtime.broker.request(human, { verb, args }));
// Let the boot fetch finish before inspecting only the human operation's command count.
const deadline = Date.now() + 10000;
while (true) {
const state = await call('library.status', { project: 'books' });
if (state.lastFetch !== initial) break;
if (Date.now() > deadline) throw Error('boot fetch did not complete');
await new Promise(resolve => setTimeout(resolve, 10));
}
const path = 'Book One/Chapters/Chapter 01.md';
const saves = [
['library.file.save', { project: 'books', path, base: git(bare.mirror, 'rev-parse', `served:${path}`), content: 'her edit\n' }],
['library.revert', { project: 'books', commit: agent.commit }],
];
const before = bare.commands.length;
for (const [verb, args] of saves) {
if (user) assert.match((await call(verb, args)).commit, /^[a-f0-9]{40}$/);
else await assert.rejects(call(verb, args), { code: 'library-human-missing' });
}
assert.deepEqual(pushes, user ? [user, user] : []);
if (!user) assert.equal(bare.commands.length, before);
} finally { await runtime.close(); }
}
});
test('C2-02 E4: post-push publication failure stores the exact notice and returns outcome-unknown', async t => {
const bare = await bareWorld(t), f = world(t, { projects: bare.context.business.projects });
const state = join(bare.mirror, SYNC_STATE_FILE), original = readFileSync(state);
const previous = await servedCommit(bare.mirror), head = bare.remoteHead();
const command = (kind, url, options) => {
// Break only state decoding after push admission; the real remote push still executes.
if (kind === 'push') writeFileSync(state, 'invalid state\n');
return bare.command(kind, url, options);
};
f.library.writeDoc = (context, options) => writeLibraryDoc({ ...context, dataRoot: bare.context.dataRoot },
{ ...options, credential: { ...options.credential, file: bare.file }, command });
try {
await assert.rejects(f.call('bean', 'library.doc.write', { ...args(), base: git(bare.mirror, 'rev-parse', `served:${PATH}`) }),
{ code: 'outcome-unknown' });
assert.notEqual(bare.remoteHead(), head);
assert.equal(git(bare.mirror, 'rev-parse', 'served'), previous);
const messages = f.store.all("SELECT body FROM messages WHERE from_role='bean' AND to_role='human'");
assert.deepEqual(messages.map(m => JSON.parse(m.body)), [
{ notice: 'library-write', op: 'write', path: PATH, commit: bare.remoteHead() }]);
} finally { writeFileSync(state, original); }
const commit = bare.remoteHead();
const human = { credential: { ...bare.credential, kind: 'human' }, command: bare.command };
await assert.rejects(revertLibraryCommit({ ...bare.context, commit }, human), { code: 'library-revert-not-agent' });
await sync(bare.context, { credential: bare.credential, command: bare.command });
assert.equal((await revertLibraryCommit({ ...bare.context, commit }, human)).reverted, commit);
});
test('C2-02 mos-1520: failed notice insert logs metadata and returns outcome-unknown even if refusal evidence fails', async t => {
const bare = await bareWorld(t), f = world(t, { projects: bare.context.business.projects });
const previous = await servedCommit(bare.mirror), head = bare.remoteHead();
f.library.writeDoc = (context, options) => writeLibraryDoc({ ...context, dataRoot: bare.context.dataRoot },
{ ...options, credential: { ...options.credential, file: bare.file }, command: bare.command });
f.store.run(`CREATE TEMP TRIGGER fail_library_notice BEFORE INSERT ON messages
WHEN NEW.from_role='bean' BEGIN SELECT RAISE(ABORT, 'fixture store failure'); END;`);
f.store.run(`CREATE TEMP TRIGGER fail_refusal_log BEFORE INSERT ON events
WHEN NEW.kind='action.refused' BEGIN SELECT RAISE(ABORT, 'fixture evidence failure'); END;`);
await assert.rejects(f.call('bean', 'library.doc.write', { ...args(), base: git(bare.mirror, 'rev-parse', `served:${PATH}`) }),
{ code: 'outcome-unknown' });
assert.notEqual(bare.remoteHead(), head);
assert.equal(await servedCommit(bare.mirror), previous);
assert.equal(f.store.get("SELECT count(*) n FROM messages WHERE from_role='bean'").n, 0);
assert.deepEqual(f.logs, [{ event: 'library-notice-store-failed', code: 'outcome-unknown', business: 'acme',
instance: 'bean', op: 'write', commit: bare.remoteHead() }]);
});
test('C2-02 + C2-05c: broker get blob feeds write/delete and new served lookups immediately', async t => {
const bare = await bareWorld(t), f = world(t, { projects: bare.context.business.projects });
f.library.lookup = createLibraryLookup({ dataRoot: bare.context.dataRoot,
sync: context => sync({ ...context, dataRoot: bare.context.dataRoot }, { credential: bare.credential, command: bare.command }) });
f.library.writeDoc = (context, options) => writeLibraryDoc({ ...context, dataRoot: bare.context.dataRoot },
{ ...options, credential: { ...options.credential, file: bare.file }, command: bare.command });
const query = { universe: 'harbor', path: PATH, scope: 'supporting' };
const before = await f.call('bean', 'library.get', query);
assert.equal(before.blob, git(bare.mirror, 'rev-parse', `served:${PATH}`));
const saved = await f.call('bean', 'library.doc.write', { ...args(), base: before.blob, content: 'new served text\n' });
const after = await f.call('bean', 'library.get', query);
assert.equal(after.commit, saved.commit);
assert.equal(after.blob, git(bare.mirror, 'rev-parse', `${saved.commit}:${PATH}`));
assert.notEqual(after.blob, before.blob);
assert.deepEqual(after.lines[0], [1, 'new served text']);
assert.equal(await f.call('bean', 'library.get', { universe: 'harbor', path: PATH }), null);
await f.call('bean', 'library.doc.delete', { universe: 'harbor', path: PATH, base: after.blob });
assert.equal(await f.call('bean', 'library.get', query), null);
});
+15
View File
@@ -249,6 +249,21 @@ export function typedTools({ resolved, arbiter = false, tracker = false, project
...base, book, scope: manuscriptScope, chapter: str("Chapter filename without extension"), from: line, to: line,
}, ["universe", "book"]));
add("library_universe", "library.universe", null, "Read a universe's mapping at the served commit: books, types, playground prefixes, and hybrid sources/constraints/notes or draft metadata.", obj(base, ["universe"]));
// C2-02: write tools carry only the note/base/content. The broker supplies the writer,
// credential and fixed commit message; a creative within-role grant is required.
if (CREATIVE_DEFINITIONS.includes(resolved.definition) && resolved.limits.authority.withinRole.includes("library.write")) {
const writeBase = {
universe,
path: str("A .md path under this universe's human-marked supporting folder"),
base: { type: ["string", "null"], pattern: "^[a-f0-9]{40}$", description: "The blob from library_get, or null to create; never the commit id" },
};
add("library_doc_write", "library.doc.write", "library.write", "Create or edit one supporting .md note using the blob from library_get. One commit by your identity, with a fixed human notice. A stale base refuses; agent requests retain the 64 KiB envelope limit.", obj({
...writeBase, content: str("UTF-8 note text without NUL; at most 1 MiB and bounded by the agent socket envelope"),
}, ["universe", "path", "base", "content"]));
add("library_doc_delete", "library.doc.delete", "library.write", "Delete one existing regular supporting .md note using the blob from library_get. One commit and a fixed human notice. A stale base or nonregular/missing target refuses.", obj({ ...writeBase,
base: { ...writeBase.base, description: "The existing file's blob from library_get; a missing file cannot be deleted" },
}, ["universe", "path", "base"]));
}
}
add("read_spec", "spec.read", null, "Read a project's committed north-star spec and its file history. commit is an optional full reachable commit ID. The file commit, rather than HEAD, is what a decision cites. confirmed says the file commit was authored by the business's human.", obj({
project: str("Project ID from the business file"),
@@ -14,9 +14,9 @@ const role = (t, definition, harness = 'pi') => resolvedFor(t, 'bean', d => {
d.roles.bean = { definition, credentials: { gitea: { ...d.roles.coder.credentials.gitea } }, vars: { harness, model: 'claude-sonnet-5-5', thinking: 'high' } };
});
const expected = definition => ['send_message', ...(['companion', 'research'].includes(definition)
? ['web_search', 'web_fetch'] : []), ...LOOKUPS];
? ['web_search', 'web_fetch'] : []), ...LOOKUPS, 'library_doc_write', 'library_doc_delete'];
test('M3: per-role snapshots contain six names, or eight with the C2-08 web grant', t => {
test('M3: per-role snapshots contain eight names, or ten with the C2-08 web grant', t => {
for (const definition of CREATIVE) {
const tools = typedTools({ resolved: role(t, definition), library: true, tracker: true, arbiter: true });
assert.deepEqual(tools.map(t => t.name), expected(definition), definition);
@@ -38,7 +38,7 @@ test('every noncreative role gets lookups when a library is configured, not othe
test('lookup schemas require a universe even for get, include paging, and cannot select repo or commit', t => {
const tools = typedTools({ resolved: role(t, 'ideas'), library: true });
const required = [ ['universe', 'query'], ['universe', 'path'], ['universe', 'text'], ['universe', 'book'], ['universe'] ];
for (const [i, tool] of tools.filter(t => t.name.startsWith('library_')).entries()) {
for (const [i, tool] of tools.filter(t => LOOKUPS.includes(t.name)).entries()) {
assert.deepEqual(tool.parameters.required, required[i]);
assert.equal(tool.verb, LOOKUPS[i].replace('_', '.'));
assert.equal(tool.action, null);
@@ -72,7 +72,7 @@ test('bundle flag reaches both harness tool manifests and creative prompt withou
test('C2-05c scope schemas expand only find/search/get, keeping manuscript and tool names unchanged', t => {
const tools = typedTools({ resolved: role(t, 'ideas'), library: true });
assert.deepEqual(tools.map(t => t.name), ['send_message', ...LOOKUPS]);
assert.deepEqual(tools.map(t => t.name), ['send_message', ...LOOKUPS, 'library_doc_write', 'library_doc_delete']);
for (const name of ['library_find', 'library_search', 'library_get']) {
const tool = tools.find(t => t.name === name);
assert.deepEqual(tool.parameters.properties.scope.enum, ['canon', 'playground', 'supporting']);
@@ -0,0 +1,60 @@
// Row 288 M3: creative write tools and independent closed-schema coverage.
import test from 'node:test';
import assert from 'node:assert/strict';
import { typedTools, untypedActions } from '../src/tools.mjs';
import { resolvedFor } from './helpers.mjs';
const LOOKUPS = ['library_find', 'library_get', 'library_search', 'library_manuscript', 'library_universe'];
const WRITES = ['library_doc_write', 'library_doc_delete'];
const CREATIVE = ['companion', 'research', 'ideas', 'proofreader', 'fact-checker', 'continuity'];
const role = (t, definition) => resolvedFor(t, 'bean', doc => {
doc.roles.bean = { definition, credentials: { gitea: { ...doc.roles.coder.credentials.gitea } }, vars: { harness: 'pi', model: 'claude-sonnet-5-5', thinking: 'high' } };
});
test('C2-02 M3: each creative role has eight tools, or ten with its web grant', t => {
for (const definition of CREATIVE) {
const resolved = role(t, definition), tools = typedTools({ resolved, library: true, tracker: true, arbiter: true });
const expected = ['send_message', ...(['companion', 'research'].includes(definition) ? ['web_search', 'web_fetch'] : []), ...LOOKUPS, ...WRITES];
assert.deepEqual(tools.map(tool => tool.name), expected, definition);
assert.equal(tools.length, ['companion', 'research'].includes(definition) ? 10 : 8);
assert.equal(untypedActions(resolved, tools).includes('library.write'), false);
}
});
test('C2-02 schemas: both write tools require universe/path/base, close keys, map verb and action', t => {
const tools = typedTools({ resolved: role(t, 'ideas'), library: true });
for (const [name, verb, required] of [
['library_doc_write', 'library.doc.write', ['universe', 'path', 'base', 'content']],
['library_doc_delete', 'library.doc.delete', ['universe', 'path', 'base']],
]) {
const tool = tools.find(tool => tool.name === name);
assert.ok(tool, name); assert.equal(tool.verb, verb); assert.equal(tool.action, 'library.write');
assert.equal(tool.parameters.type, 'object'); assert.equal(tool.parameters.additionalProperties, false);
assert.deepEqual(tool.parameters.required, required);
assert.deepEqual(Object.keys(tool.parameters.properties).sort(), [...required].sort());
assert.equal(tool.parameters.properties.universe.type, 'string');
assert.equal(tool.parameters.properties.path.type, 'string');
assert.deepEqual(tool.parameters.properties.base.type, ['string', 'null']);
assert.equal(tool.parameters.properties.base.pattern, '^[a-f0-9]{40}$');
if (name === 'library_doc_write') {
assert.equal(tool.parameters.properties.content.type, 'string');
assert.match(tool.parameters.properties.base.description, /null to create/);
} else {
assert.match(tool.parameters.properties.base.description, /existing file/);
assert.doesNotMatch(tool.parameters.properties.base.description, /create/);
}
for (const field of ['repo', 'commit', 'business', 'accept', 'project', 'identity', 'author', 'credential', 'agent', 'message'])
assert.equal(Object.hasOwn(tool.parameters.properties, field), false, `${name} ${field}`);
}
});
test('C2-02 tools: no library, noncreative or no within-role write grant exposes neither write tool', t => {
const creative = role(t, 'ideas');
assert.equal(typedTools({ resolved: creative }).some(tool => WRITES.includes(tool.name)), false);
for (const instance of ['coder', 'reviewer', 'pm', 'chief'])
assert.equal(typedTools({ resolved: resolvedFor(t, instance), library: true }).some(tool => WRITES.includes(tool.name)), false);
const narrowed = structuredClone(creative);
narrowed.limits.authority.withinRole = narrowed.limits.authority.withinRole.filter(action => action !== 'library.write');
narrowed.limits.authority.crossRole.push('library.write');
assert.deepEqual(typedTools({ resolved: narrowed, library: true }).map(tool => tool.name), ['send_message', ...LOOKUPS]);
});
+57
View File
@@ -276,3 +276,60 @@ node --test packages/library/tests/
Fixtures are made-up repos built per test in a temp dir. A marker string stands in for her text, and
the survey tests check that it never appears in output.
### C2-02 supporting writes and human saves
The host exposes `library.doc.write {universe,path,base,content}` and
`library.doc.delete {universe,path,base}` only to a creative session holding
`library.write` and a live, unheld Gitea grant for the library project. The
broker chooses the project from the universe mapping, the author/committer
from the instance identity, and the credential from its grant store. `base`
is the served-tree blob id, or `null` to create. Supporting-path checks run
before remote effects and against each fetched tip; deletes require an
existing `100644` blob. Content is UTF-8 without NUL and at most 1 MiB;
agent requests still have the ordinary 64 KiB socket envelope limit.
Each operation is one plumbing commit with one parent, a fixed
`Mosaic: write <path>` or `Mosaic: delete <path>` message, and the trailer
`Mosaic-Agent: <business>/<instance>`. Pushes are fast-forward only. A moved
remote tip retries once when the target blob still equals `base`; otherwise
it refuses `stale-base`. A failed push leaves no queued work or local ref
change. A successful push updates served/tracking, rebuilds the index and
records `lastPush: {commit,at}`. The broker inserts the exact fixed notice
`{notice:"library-write",op,path,commit}` from the writer to the human in
that thread, independently of the agent-message citation guard.
`library.file.save {project,path,base,content}` and
`library.revert {project,commit}` are human-only. Project is the business
project key. A save reaches any mapped `.md` file under the structural path
rules, uses the mapping's `editor` as author and committer, and pushes with
slot `library-human`. Revert accepts only a reachable, one-parent,
one-path commit with this business's agent trailer, and restores its
parent's blob with the agent commit's blob as `base`. The result is
`{project,path,reverted,commit}`. Revoking/firing the original writer does
not prevent a human revert. Missing editor refuses
`library-mapping-invalid`; missing/unsafe human slot refuses
`library-human-missing`, before Git. An agent calling either human verb
gets `human-required`. Only `library.file.save` joins the larger Console
save envelope exception; agent writes retain 64 KiB.
The write guard excludes concurrent sync and admits a race fetch only for
its opaque owner token. The library flock spans fetch/build/push as the
brief requires, so readers can receive `library-sync-busy` after the
existing five-second lock wait while network Git runs (MVP tradeoff,
sage-3628). Publication errors return `outcome-unknown`: served is restored
to match old state unless the new state was already published. The remote
commit remains; callers must inspect status rather than retry blindly.
The human push login is `editor.user` (optional in the mapping, required
for save/revert), distinct from `user`, which names the fetch bot.
An absent editor login refuses `library-human-missing`; no fallback uses
the bot's login. Once an agent push succeeds, the broker stores the exact
write notice with that pushed commit id before local publication. If
publication then fails, the agent receives `outcome-unknown` and the
notice remains. Revert can refuse `library-revert-not-agent` until a sync
makes the commit reachable from served. No notice outbox or retry is
needed. If the Console store itself refuses the notice insert, the caller
still receives `outcome-unknown` and a separate metadata-only host log
records `library-notice-store-failed` with the business, instance, operation
and pushed commit id; it contains no file text or credential.
+2
View File
@@ -13,3 +13,5 @@ export { buildIndex, indexFor, clearIndexCache, indexCacheSize } from './index-b
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';
export { writeLibraryDoc, saveLibraryFile, revertLibraryCommit } from './write.mjs';
+3 -1
View File
@@ -221,7 +221,9 @@ async function readStateHeld(mirror, { branch } = {}) {
finally { if (fd !== undefined) closeSync(fd); }
// C2-03b adds `credential`, { kind, user } or null. It is optional, so a state from before it reads.
const listed = ['version', 'branch', 'served', 'lastFetch', 'lastError', 'diverged', 'problems'];
if (!keys(value, Object.hasOwn(value ?? {}, 'credential') ? [...listed, 'credential'] : listed)
const expected = [...listed, ...['credential', 'lastPush'].filter(key => Object.hasOwn(value ?? {}, key))];
if (!keys(value, expected)
|| !optional(value.lastPush ?? null, v => keys(v, ['commit', 'at']) && SHA.test(v.commit) && utc(v.at))
|| !optional(value.credential ?? null, v => keys(v, ['kind', 'user']) && ['slot', 'chief', 'seat', 'human'].includes(v.kind)
&& typeof v.user === 'string' && /^[A-Za-z0-9_.-]{1,100}$/.test(v.user))
|| value.version !== 1 || value.branch !== branch || value.served !== served
+52 -4
View File
@@ -14,6 +14,7 @@ import { SAFE, git } from '../../project/src/git.mjs';
import { checkMapping } from './mapping.mjs';
import { LibraryError } from './problems.mjs';
import { readLibrary } from './reader.mjs';
import { indexFor } from './index-build.mjs';
import { SYNC_STATE_FILE, ensureMirror, withLibraryLock, servedCommit } from './mirror.mjs';
export const ASKPASS = fileURLToPath(new URL('../bin/askpass', import.meta.url));
@@ -32,6 +33,15 @@ const fail = (code, message = code) => { throw new LibraryError(code, message);
// One sync per mirror in this process. The library lock covers publication only, so a second
// fetch into the same mirror is refused here rather than racing the first.
const running = new Set();
// C2-02: opaque identity lets only the owning write re-enter push's race fetch.
const writers = new Map();
export async function withLibraryWriteGuard(mirror, operation) {
if (running.has(mirror)) fail('library-sync-busy');
const token = Object.freeze({});
running.add(mirror); writers.set(mirror, token);
try { return await operation(token); }
finally { writers.delete(mirror); running.delete(mirror); }
}
// The one command builder for her remote. `kind` is 'fetch' or 'push'. A push sends `commit` to the
// branch with no '+', so the remote takes a fast-forward only (D6). `slot` is the file the helper reads.
@@ -210,7 +220,7 @@ export async function sync(context, { slot, credential = null, accept = null, co
// mirror runs. A hook refusal ([remote rejected]) or any other failure
// refuses library-push-failed, and git's output is never kept. It moves no local ref: C2-02 moves the
// remote-tracking and served refs after a push.
export async function push(context, { commit, credential, retried = false, command = syncCommand, limits = GIT_LIMITS } = {}) {
export async function push(context, { commit, credential, retried = false, writeToken = null, command = syncCommand, limits = GIT_LIMITS } = {}) {
const mirror = await ensureMirror(context);
const mapping = checkMapping(context.business.projects[context.project]);
const { branch } = mapping;
@@ -233,8 +243,9 @@ export async function push(context, { commit, credential, retried = false, comma
if (retried) fail('stale-base', 'her branch moved again during the write');
// The race fetch writes the mirror, so it takes sync's guard (dewey-0864 R1). A held guard refuses
// library-sync-busy and the caller tries the write again.
if (running.has(mirror)) fail('library-sync-busy', 'a sync of this library is running');
running.add(mirror);
const owned = writeToken !== null && writers.get(mirror) === writeToken;
if (running.has(mirror) && !owned) fail('library-sync-busy', 'a sync of this library is running');
if (!owned) running.add(mirror);
try {
const fetch = command('fetch', mapping.remote, opts);
if (!(await runGit(fetch.argv, fetch.env, limits)).ok) fail('library-push-failed', 'fetch after a moved tip failed');
@@ -243,5 +254,42 @@ export async function push(context, { commit, credential, retried = false, comma
catch { fail('library-push-failed', 'fetch after a moved tip found no branch'); }
if (!SHA.test(tip)) fail('library-push-failed', 'fetch after a moved tip found no branch');
return { pushed: false, raced: true, tip };
} finally { running.delete(mirror); }
} finally { if (!owned) running.delete(mirror); }
}
// Called under the publication lock by C2-02; the raw state writer stays private.
export async function publishLibraryWrite(mirror, { mapping, commit, previous, readSyncState, now = () => new Date() }) {
if (!SHA.test(commit) || (previous !== null && !SHA.test(previous))) fail('library-state-invalid');
const state = await readSyncState({ branch: mapping.branch });
if (state.diverged !== null) fail('library-diverged');
if (state.served !== previous) fail('library-state-invalid');
const read = await indexFor({ repo: mirror, commit, mapping });
const at = now().toISOString();
const next = { ...state, served: commit, lastPush: { commit, at }, lastError: null,
problems: read.problems.map(p => ({ ...p })) };
const tracking = `refs/remotes/library/${mapping.branch}`;
// The remote push already succeeded. A local publication failure is outcome-unknown to the
// caller; it must never encourage an automatic second push.
let moved = false;
try {
await git(mirror, ['update-ref', 'refs/heads/served', commit, previous ?? ZERO]);
moved = true;
await git(mirror, ['update-ref', tracking, commit]);
writeState(mirror, next);
} catch {
if (moved) {
// A rename may have succeeded before directory fsync failed. Keep the new ref when the
// validated state already matches it; otherwise restore served by compare-and-swap.
let published = false;
try { published = (await readSyncState({ branch: mapping.branch })).served === commit; } catch {}
if (!published) {
try {
await git(mirror, ['update-ref', ...(previous === null
? ['-d', 'refs/heads/served', commit] : ['refs/heads/served', previous, commit])]);
} catch { fail('outcome-unknown'); }
}
}
fail('outcome-unknown');
}
return next;
}
+190
View File
@@ -0,0 +1,190 @@
// C2-02: one-path plumbing commits on the private bare mirror. No checkout and no pending push.
import { lstatSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { SAFE, git, gitBytes } from '../../project/src/git.mjs';
import { gitEnv, runGit, GIT_LIMITS } from '../../seat/src/checkout.mjs';
import { ID_PATTERN } from '../../business/src/vocabulary.mjs';
import { checkMapping } from './mapping.mjs';
import { classify } from './scope.mjs';
import { supportingPath } from './supporting.mjs';
import { LibraryError } from './problems.mjs';
import { listTree, MAX_BLOB } from './reader.mjs';
import { mirrorPath, ensureMirror, withLibraryLock } from './mirror.mjs';
import { syncCommand, push, withLibraryWriteGuard, publishLibraryWrite } from './sync.mjs';
const SHA = /^[a-f0-9]{40}$/;
const fail = code => { throw new LibraryError(code, code); };
const ident = identity => ({ GIT_AUTHOR_NAME: identity.name, GIT_AUTHOR_EMAIL: identity.email,
GIT_COMMITTER_NAME: identity.name, GIT_COMMITTER_EMAIL: identity.email });
function mappingOf(context) {
if (!Object.hasOwn(context.business?.projects ?? {}, context.project)) fail('project-not-configured');
return checkMapping(context.business.projects[context.project]);
}
function contentOf(value) {
if (typeof value !== 'string' || value.includes('\0') || Buffer.byteLength(value, 'utf8') > MAX_BLOB
|| Buffer.from(value, 'utf8').toString('utf8') !== value) fail('invalid-request');
return value;
}
function credentialOf(credential, human) {
const code = human ? 'library-human-missing' : 'library-write-no-grant';
if (!credential || credential.kind !== (human ? 'human' : 'seat')
|| typeof credential.user !== 'string' || !/^[A-Za-z0-9_.-]{1,100}$/.test(credential.user)
|| typeof credential.file !== 'string') fail(code);
try {
const st = lstatSync(credential.file);
if (!st.isFile() || st.uid !== process.getuid() || st.nlink !== 1 || (st.mode & 0o777) !== 0o600 || st.size > 16384) fail(code);
} catch { fail(code); }
return credential;
}
// Her save uses the same structural and folded-tree checks; only the supporting rule changes.
function pathOf(mapping, universe, path, tree, human) {
if (!human) return supportingPath(mapping, universe, path, tree);
if (typeof path !== 'string' || classify(mapping, path).scope === 'unmapped') fail('library-write-story-path');
const place = classify(mapping, path);
const universes = Object.fromEntries(Object.keys(mapping.universes).map(id => [id,
{ ...mapping.universes[id], supporting: id === place.universe ? [path.slice(0, path.lastIndexOf('/') + 1)] : [] }]));
return supportingPath({ ...mapping, universes }, place.universe, path, tree);
}
async function ref(mirror, name) {
const rows = await git(mirror, ['for-each-ref', '--format=%(refname) %(objectname)', name]);
const line = rows.split('\n').find(row => row.startsWith(name + ' '));
return line ? line.slice(name.length + 1) : null;
}
async function ancestor(mirror, older, newer) {
const result = await runGit([...SAFE, '-C', mirror, 'merge-base', '--is-ancestor', older, newer], gitEnv());
if (result.ok) return true;
if (result.why === 'exit 1') return false;
fail('library-git');
}
async function fetchTip(mirror, mapping, credential, command) {
const c = command('fetch', mapping.remote, { mirror, branch: mapping.branch, user: credential.user, slot: credential.file });
if (!(await runGit(c.argv, c.env)).ok) fail('library-push-failed');
const tip = await ref(mirror, `refs/remotes/library/${mapping.branch}`);
if (!tip || !SHA.test(tip)) fail('library-push-failed');
return tip;
}
async function plumbing(mirror, tip, path, content, identity, message, stage) {
const env = { ...gitEnv(), ...ident(identity), GIT_INDEX_FILE: join(stage, 'index'), GIT_CEILING_DIRECTORIES: dirname(mirror) };
const run = async (args, input = null) => {
const result = await runGit([...SAFE, '-c', 'core.createObject=rename', '-C', mirror, ...args], env, GIT_LIMITS, { stdin: input });
if (!result.ok) fail('library-git');
return result.out.trimEnd();
};
rmSync(env.GIT_INDEX_FILE, { force: true });
await run(['read-tree', tip]);
// --force-remove requires a worktree. Feed a NUL-delimited removal to the bare index.
if (content === null) {
const removal = join(stage, 'removal');
writeFileSync(removal, `0 ${'0'.repeat(40)}\t${path}\0`, { mode: 0o600 });
await run(['update-index', '-z', '--index-info'], removal);
}
else {
const file = join(stage, 'content'); writeFileSync(file, content, { mode: 0o600 });
const blob = await run(['hash-object', '-w', '--no-filters', file]);
// --cacheinfo keeps the path a separate argv item; no pathspec expansion or filters.
await run(['update-index', '--add', '--cacheinfo', '100644', blob, path]);
}
const tree = await run(['write-tree']);
return run(['commit-tree', tree, '-p', tip, '-m', message]);
}
async function revertChange(mirror, served, context, mapping) {
const commit = context.commit;
const refuse = () => fail('library-revert-not-agent');
if (!served || !SHA.test(commit)) refuse();
let text, parents;
try {
if (!await ancestor(mirror, commit, served)) refuse();
text = await git(mirror, ['show', '-s', '--format=%(trailers:key=Mosaic-Agent,valueonly)', commit]);
parents = (await git(mirror, ['show', '-s', '--format=%P', commit])).split(' ');
} catch { refuse(); }
if (parents.length !== 1 || !SHA.test(parents[0])
|| !text.startsWith(context.business.id + '/')
|| !ID_PATTERN.test(text.slice(context.business.id.length + 1))) refuse();
const before = await listTree(mirror, parents[0]), after = await listTree(mirror, commit);
const old = new Map(before.map(e => [e.path, e])), current = new Map(after.map(e => [e.path, e]));
const changed = [...new Set([...old.keys(), ...current.keys()])].filter(path =>
old.get(path)?.oid !== current.get(path)?.oid || old.get(path)?.mode !== current.get(path)?.mode);
if (changed.length !== 1) refuse();
const path = changed[0], was = old.get(path), made = current.get(path);
if ((was && (was.mode !== '100644' || was.type !== 'blob' || was.size > MAX_BLOB))
|| (made && (made.mode !== '100644' || made.type !== 'blob'))) refuse();
pathOf(mapping, null, path, after, true);
const bytes = was ? await gitBytes(mirror, ['cat-file', 'blob', was.oid], MAX_BLOB) : null;
let content = null;
if (bytes !== null) {
try { content = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode(bytes); } catch { refuse(); }
contentOf(content);
}
return { path, base: made?.oid ?? null, content, reverted: commit };
}
async function write(context, options, human, revert = false) {
const mapping = mappingOf(context);
if (human && !mapping.editor) fail('library-mapping-invalid');
const credential = credentialOf(options.credential, human);
const identity = human ? mapping.editor : options.identity;
if (!identity || typeof identity.name !== 'string' || typeof identity.email !== 'string') fail('library-write-refused');
if (!human && (typeof options.agent !== 'string' || !options.agent.startsWith(context.business.id + '/'))) fail('library-write-refused');
const op = options.op ?? 'write';
if (!['write', 'delete'].includes(op)) fail('invalid-request');
let change = revert ? null : { path: context.path, base: context.base, content: op === 'delete' ? null : contentOf(context.content) };
if (change) {
if (change.base !== null && (typeof change.base !== 'string' || !SHA.test(change.base))) fail('invalid-request');
pathOf(mapping, context.universe, change.path, [], human);
}
const mirror = mirrorPath(context);
return withLibraryWriteGuard(mirror, writeToken => withLibraryLock(mirror, async lock => {
await ensureMirror(context);
const state = await lock.readSyncState({ branch: mapping.branch });
if (state.diverged !== null) fail('library-diverged');
const served = state.served;
if (!served) fail('library-commit');
if (revert) change = await revertChange(mirror, served, context, mapping);
// Check the served tree before any remote effect, then recheck against every fetched tip.
pathOf(mapping, context.universe, change.path, await listTree(mirror, served), human);
const tracking = `refs/remotes/library/${mapping.branch}`, previous = await ref(mirror, tracking);
let pushed = false;
const stage = mkdtempSync(join(dirname(mirror), '.library-write-'));
try {
let tip = await fetchTip(mirror, mapping, credential, options.command ?? syncCommand);
for (let attempt = 0; attempt < 2; attempt++) {
if (!await ancestor(mirror, served, tip)) fail('library-diverged');
const tree = await listTree(mirror, tip);
pathOf(mapping, context.universe, change.path, tree, human);
const entry = tree.find(e => e.path === change.path);
if ((!human && op === 'delete' && (!entry || entry.mode !== '100644' || entry.type !== 'blob'))
|| (entry && (entry.mode !== '100644' || entry.type !== 'blob'))
|| tree.some(e => e.path.startsWith(change.path + '/') || change.path.startsWith(e.path + '/')))
fail('library-write-story-path');
if ((entry?.oid ?? null) !== change.base) fail('stale-base');
const action = change.content === null ? 'delete' : 'write';
const message = `Mosaic: ${action} ${change.path}` + (human ? '' : `\n\nMosaic-Agent: ${options.agent}`);
const commit = await plumbing(mirror, tip, change.path, change.content, identity, message, stage);
// Broker rechecks live grants/holder immediately before each push.
options.beforePush?.();
const result = await push(context, { commit, credential, retried: attempt === 1, writeToken, command: options.command ?? syncCommand });
if (!result.pushed) { tip = result.tip; continue; }
pushed = true;
try {
// The broker records the pushed commit even if publication fails next (mos-1520).
options.onPushed?.({ project: context.project, path: change.path, commit });
await publishLibraryWrite(mirror, { mapping, commit, previous: served, readSyncState: lock.readSyncState, now: options.now });
} catch { fail('outcome-unknown'); }
return { project: context.project, path: change.path, ...(revert ? { reverted: change.reverted } : {}), commit };
}
fail('stale-base');
} finally {
rmSync(stage, { recursive: true, force: true });
if (!pushed) {
if (previous === null) await git(mirror, ['update-ref', '-d', tracking]);
else await git(mirror, ['update-ref', tracking, previous]);
}
}
}));
}
export const writeLibraryDoc = (context, options = {}) => write(context, options, false);
export const saveLibraryFile = (context, options = {}) => write(context, options, true);
export const revertLibraryCommit = (context, options = {}) => write(context, options, true, true);
+55
View File
@@ -0,0 +1,55 @@
// Shared scratch bare-repository fixture for row 288 library and broker tests.
import assert from 'node:assert/strict';
import { mkdirSync, writeFileSync } from 'node:fs';
import { join } from 'node:path';
import { repo, git, mappingEntry, BASE } from './helpers.mjs';
import { sync, syncCommand } from '../src/sync.mjs';
import { mirrorPath, readSyncState } from '../src/mirror.mjs';
export const PATH = 'Book One/Notes/Agent.md';
export const IDENTITY = { name: 'Bean Fixture', email: '[email protected]' };
export const EDITOR = { name: 'Human Fixture', email: '[email protected]' };
export async function world(t, { business = 'acme' } = {}) {
const f = repo(t, { ...BASE, [PATH]: 'before\n',
'Book One/Notes/Executable.md': { text: 'exec\n', mode: 0o755 },
'Book One/Notes/Link.md': { link: 'Agent.md' } });
git(f.repo, 'update-index', '--add', '--cacheinfo', '160000', f.commit, 'Book One/Notes/Submodule.md');
git(f.repo, 'commit', '-qm', 'gitlink fixture');
const remote = join(f.root, 'remote.git');
git(f.root, 'clone', '-q', '--bare', '--no-local', f.repo, remote);
const dataRoot = join(f.root, 'data'); mkdirSync(dataRoot, { mode: 0o700 });
const entry = { ...mappingEntry(), user: 'human-fixture', editor: { ...EDITOR } };
entry.universes.harbor.supporting = ['Book One/Notes/'];
const context = { business: { id: business, projects: { books: entry } }, project: 'books', dataRoot };
const file = join(f.root, 'fixture-slot'); writeFileSync(file, 'fx288-write\n', { mode: 0o600 });
const credential = { kind: 'seat', user: 'bean-fixture', file };
// Keep the production refspec exactly: a '+' mutant on push would overwrite the racing remote.
let beforePush = null, reject = false;
const commands = [];
const command = (kind, url, opts) => {
commands.push(kind);
if (kind === 'push' && beforePush) { const fn = beforePush; beforePush = null; fn(); }
const c = syncCommand(kind, url, opts);
const argv = [...c.argv];
argv.splice(0, 0, '-c', 'protocol.file.allow=always');
const at = argv.indexOf(url);
assert.ok(at >= 0);
argv[at] = kind === 'push' && reject ? join(f.root, 'missing.git') : remote;
return { argv, env: c.env };
};
await sync(context, { credential, command });
const mirror = mirrorPath(context);
const refs = () => git(mirror, 'for-each-ref', '--format=%(refname) %(objectname)');
const remoteHead = () => git(remote, 'rev-parse', 'main');
const state = () => readSyncState(mirror, { branch: 'main' });
const external = (path, content) => {
writeFileSync(join(f.repo, path), content); git(f.repo, 'add', '-A'); git(f.repo, 'commit', '-qm', 'external');
git(f.repo, 'push', '-q', remote, 'HEAD:main');
};
const args = (extra = {}) => ({ ...context, universe: 'harbor', path: PATH,
base: git(mirror, 'rev-parse', `served:${PATH}`), content: 'after\n', ...extra });
const opts = { credential, identity: IDENTITY, agent: `${business}/bean`, command };
return { ...f, remote, context, entry, file, credential, command, mirror, refs, remoteHead, state, external, args, opts,
race: fn => { beforePush = fn; }, reject: () => { reject = true; }, commands };
}
+171
View File
@@ -0,0 +1,171 @@
// Row 288: real bare-repository plumbing and remote effects. All text and credentials are fixtures.
import test from 'node:test';
import assert from 'node:assert/strict';
import { writeFileSync, existsSync, renameSync, mkdirSync, rmSync } from 'node:fs';
import { join } from 'node:path';
import { git } from './helpers.mjs';
import { sync, push, withLibraryWriteGuard } from '../src/sync.mjs';
import { servedCommit, withLibraryLock, readSyncState, SYNC_STATE_FILE } from '../src/mirror.mjs';
import { publishLibraryWrite } from '../src/sync.mjs';
import { checkMapping } from '../src/mapping.mjs';
import { writeLibraryDoc, saveLibraryFile, revertLibraryCommit } from '../src/write.mjs';
import { world, PATH, EDITOR } from './write-fixture.mjs';
test('C2-02: write/delete each publish one parent, seat ident, fixed trailer, index and lastPush', async t => {
const f = await world(t), parent = f.remoteHead();
const saved = await writeLibraryDoc(f.args(), f.opts);
assert.deepEqual(saved, { project: 'books', path: PATH, commit: f.remoteHead() });
assert.equal(git(f.remote, 'show', `${saved.commit}:${PATH}`), 'after');
assert.equal(git(f.remote, 'show', '-s', '--format=%P', saved.commit), parent);
assert.equal(git(f.remote, 'show', '-s', '--format=%an <%ae>|%cn <%ce>', saved.commit),
'Bean Fixture <[email protected]>|Bean Fixture <[email protected]>');
assert.equal(git(f.remote, 'show', '-s', '--format=%B', saved.commit), `Mosaic: write ${PATH}\n\nMosaic-Agent: acme/bean`);
assert.equal(await servedCommit(f.mirror), saved.commit);
assert.equal((await f.state()).lastPush.commit, saved.commit);
assert.equal(existsSync(join(f.mirror, 'index')), false);
const gone = await writeLibraryDoc(f.args({ content: undefined }), { ...f.opts, op: 'delete' });
assert.equal(git(f.remote, 'show', '-s', '--format=%P', gone.commit), saved.commit);
assert.equal(git(f.remote, 'ls-tree', '-r', gone.commit, '--', PATH), '');
assert.equal(git(f.remote, 'show', '-s', '--format=%B', gone.commit), `Mosaic: delete ${PATH}\n\nMosaic-Agent: acme/bean`);
});
test('C2-02 M12: each path refusal leaves every ref and remote unchanged', async t => {
const f = await world(t);
const paths = ['Book One/Chapters/Chapter 01.md', 'Book One/Playground/What If.md', 'Inbox Note.md',
'Book One/Notes/X.canvas', 'Book One/Notes/X.base', 'Book One/Notes/X.png', 'Second World/Chapters/01.md',
'/Book One/Notes/X.md', 'Book One/Notes/../X.md', 'Book One/./Notes/X.md', 'Book One//Notes/X.md',
'Book One/Notes/X\\Y.md', 'Book One/Notes/X\nY.md', 'Book One/Notes/Link.md',
'Book One/Notes/agent.md', `Book One/Notes/${'é'.repeat(512)}.md`];
for (const path of paths) {
const before = f.refs(), head = f.remoteHead();
await assert.rejects(writeLibraryDoc(f.args({ path, base: null }), f.opts), { code: 'library-write-story-path' }, path);
assert.equal(f.refs(), before); assert.equal(f.remoteHead(), head);
}
});
test('C2-02 Q4: delete requires an existing 100644 blob; null base never deletes a missing path', async t => {
const f = await world(t);
for (const path of ['Book One/Notes/Missing.md', 'Book One/Notes/Executable.md', 'Book One/Notes/Link.md', 'Book One/Notes/Submodule.md']) {
const before = f.refs();
await assert.rejects(writeLibraryDoc(f.args({ path, base: null, content: undefined }), { ...f.opts, op: 'delete' }),
{ code: 'library-write-story-path' });
assert.equal(f.refs(), before);
}
});
test('C2-02: stale base and failed push keep remote/served/tracking refs unchanged', async t => {
const f = await world(t), refs = f.refs(), head = f.remoteHead();
await assert.rejects(writeLibraryDoc(f.args({ base: 'a'.repeat(40) }), f.opts), { code: 'stale-base' });
assert.equal(f.refs(), refs); assert.equal(f.remoteHead(), head);
f.reject();
await assert.rejects(writeLibraryDoc(f.args(), f.opts), { code: 'library-push-failed' });
assert.equal(f.refs(), refs); assert.equal(f.remoteHead(), head);
});
test('C2-02: a moved unrelated blob retries once on the new parent, changed target refuses', async t => {
const f = await world(t);
const args = f.args(); let raced;
f.race(() => { f.external('Inbox Note.md', 'another\n'); raced = f.remoteHead(); });
const saved = await writeLibraryDoc(args, f.opts);
assert.equal(git(f.remote, 'show', '-s', '--format=%P', saved.commit), raced);
assert.equal(git(f.remote, 'show', `${saved.commit}:Inbox Note.md`), 'another');
const g = await world(t), before = g.refs();
g.race(() => g.external(PATH, 'raced target\n'));
await assert.rejects(writeLibraryDoc(g.args(), g.opts), { code: 'stale-base' });
assert.equal(g.refs(), before); assert.equal(git(g.remote, 'show', `main:${PATH}`), 'raced target');
});
test('C2-02: create with null base; human revert restores parent and does not require seat credentials', async t => {
const f = await world(t);
const made = await writeLibraryDoc(f.args({ path: 'Book One/Notes/New.md', base: null, content: 'new\n' }), f.opts);
const options = { credential: { ...f.credential, kind: 'human' }, command: f.command };
const reverted = await revertLibraryCommit({ ...f.context, commit: made.commit }, options);
assert.deepEqual(reverted, { project: 'books', path: 'Book One/Notes/New.md', reverted: made.commit, commit: f.remoteHead() });
assert.equal(git(f.remote, 'ls-tree', '-r', reverted.commit, '--', reverted.path), '');
assert.equal(git(f.remote, 'show', '-s', '--format=%an <%ae>|%cn <%ce>', reverted.commit),
'Human Fixture <[email protected]>|Human Fixture <[email protected]>');
assert.equal(git(f.remote, 'show', '-s', '--format=%(trailers:key=Mosaic-Agent,valueonly)', reverted.commit), '');
});
test('C2-02: revert requires reachable business trailer and refuses a later path change', async t => {
const f = await world(t), options = { credential: { ...f.credential, kind: 'human' }, command: f.command };
await assert.rejects(revertLibraryCommit({ ...f.context, commit: f.commit }, options), { code: 'library-revert-not-agent' });
const saved = await writeLibraryDoc(f.args(), f.opts);
await saveLibraryFile({ ...f.context, path: PATH, base: git(f.mirror, 'rev-parse', `served:${PATH}`), content: 'human later\n' }, options);
await assert.rejects(revertLibraryCommit({ ...f.context, commit: saved.commit }, options), { code: 'stale-base' });
});
test('C2-02: human save reaches story, preserves UTF-8 bytes and uses editor without a trailer', async t => {
const f = await world(t), path = 'Book One/Chapters/Chapter 01.md';
const content = '# Her text\n' + 'é'.repeat(40000) + '\n\n';
const saved = await saveLibraryFile({ ...f.context, path, base: git(f.mirror, 'rev-parse', `served:${path}`), content },
{ credential: { ...f.credential, kind: 'human' }, command: f.command });
assert.equal(git(f.remote, 'show', '-s', '--format=%an <%ae>', saved.commit), 'Human Fixture <[email protected]>');
// git helper trims; compare the stored blob byte count separately.
assert.equal(Number(git(f.remote, 'cat-file', '-s', `${saved.commit}:${path}`)), Buffer.byteLength(content));
});
test('C2-02: invalid content/editor/human credential refuse before any git command', async t => {
const f = await world(t), before = f.refs();
for (const content of ['nul\0', '\ud800', 'x'.repeat(1024 * 1024 + 1)])
await assert.rejects(writeLibraryDoc(f.args({ content }), f.opts), { code: 'invalid-request' });
const args = { ...f.context, path: PATH, base: null, content: 'x' };
writeFileSync(join(f.mirror, 'unexpected'), 'any local git inspection must refuse\n');
delete f.entry.editor;
await assert.rejects(saveLibraryFile(args, { credential: { ...f.credential, kind: 'human' }, command: f.command }), { code: 'library-mapping-invalid' });
await assert.rejects(revertLibraryCommit({ ...f.context, commit: f.commit }, { credential: { ...f.credential, kind: 'human' }, command: f.command }), { code: 'library-mapping-invalid' });
f.entry.editor = EDITOR;
const n = f.commands.length;
await assert.rejects(saveLibraryFile(args, { credential: { kind: 'human', user: 'human', file: '/absent' }, command: f.command }), { code: 'library-human-missing' });
await assert.rejects(revertLibraryCommit({ ...f.context, commit: f.commit }, { credential: { kind: 'human', user: 'human', file: '/absent' }, command: f.command }), { code: 'library-human-missing' });
assert.equal(f.commands.length, n); assert.equal(f.refs(), before);
});
test('C2-02 guard: only the exact owning token permits a push race fetch; sync refuses busy', async t => {
const f = await world(t), commit = f.remoteHead();
f.external('Inbox Note.md', 'remote moved\n');
await withLibraryWriteGuard(f.mirror, async token => {
await assert.rejects(sync(f.context, { credential: f.credential, command: f.command }), { code: 'library-sync-busy' });
for (const writeToken of [null, {}, Object.freeze({})])
await assert.rejects(push(f.context, { commit, credential: f.credential, command: f.command, writeToken }), { code: 'library-sync-busy' });
const raced = await push(f.context, { commit, credential: f.credential, command: f.command, writeToken: token });
assert.equal(raced.raced, true); assert.equal(raced.tip, f.remoteHead());
});
});
test('C2-02 publication F1: failed state rename restores served to match prior state', async t => {
const f = await world(t), previous = await servedCommit(f.mirror);
const commit = git(f.mirror, 'commit-tree', git(f.mirror, 'rev-parse', `${previous}^{tree}`), '-p', previous, '-m', 'candidate');
const statePath = join(f.mirror, SYNC_STATE_FILE), backup = join(f.root, 'state-backup');
await withLibraryLock(f.mirror, async lock => {
// A filesystem failure after the locked state read, before state publication. The original
// state is saved outside the mirror and restored after the failed rename.
const read = async options => {
const state = await lock.readSyncState(options);
renameSync(statePath, backup); mkdirSync(statePath, { mode: 0o700 });
return state;
};
try {
await assert.rejects(publishLibraryWrite(f.mirror, { mapping: checkMapping(f.entry), commit, previous, readSyncState: read }),
{ code: 'outcome-unknown' });
assert.equal(git(f.mirror, 'rev-parse', 'served'), previous);
} finally { rmSync(statePath, { recursive: true, force: true }); renameSync(backup, statePath); }
});
assert.equal((await readSyncState(f.mirror, { branch: 'main' })).served, previous);
});
test('C2-02 E1: a dotted business id never matches another business trailer', async t => {
const f = await world(t, { business: 'acme.co' });
writeFileSync(join(f.repo, PATH), 'foreign seat change\n');
git(f.repo, 'add', '-A'); git(f.repo, 'commit', '-qm', 'Foreign\n\nMosaic-Agent: acme-co/bean');
const foreign = git(f.repo, 'rev-parse', 'HEAD');
git(f.repo, 'push', '-q', f.remote, 'HEAD:main');
await sync(f.context, { credential: f.credential, command: f.command });
const before = f.refs();
await assert.rejects(revertLibraryCommit({ ...f.context, commit: foreign },
{ credential: { ...f.credential, kind: 'human' }, command: f.command }), { code: 'library-revert-not-agent' });
assert.equal(f.refs(), before); assert.equal(f.remoteHead(), foreign);
});
+3 -3
View File
@@ -68,14 +68,14 @@ try {
// the system config, Business can't resolve authority and Settings has
// no notifier. A refusal printed here names no path (redactor).
// --send without a bus refuses to start rather than serve a composer that can't send.
let bus = null, send = null, settingsWrite = null, projectFiles = null, projectFile = null, libraryFile = null, libraryStatus = null, librarySync = null, libraryRevert = null, projectSave = null, chat = null, nameWrite = null, assistantStop = null, instancesWrite = null, routesWrite = null, agentWrite = null, decisionWrite = null, busLine, system = null;
let bus = null, send = null, settingsWrite = null, projectFiles = null, projectFile = null, libraryFile = null, libraryStatus = null, librarySync = null, libraryRevert = null, librarySave = null, projectSave = null, chat = null, nameWrite = null, assistantStop = null, instancesWrite = null, routesWrite = null, agentWrite = null, decisionWrite = null, busLine, system = null;
let processing = null, ownerCall = null;
try {
system = loadSystem();
const { dataRoot } = system;
const call = ownerCall = busCaller({ dataRoot, socket: socketPath(dataRoot), business: options.business ?? null });
// FED R6 (#1800): the bus-backed options, shared with each granted user's session (console-bus.mjs).
({ processing, chat, bus, projectFiles, projectFile, libraryFile, libraryStatus, send, librarySync, libraryRevert, settingsWrite, projectSave, nameWrite, assistantStop, instancesWrite, routesWrite, agentWrite } = consoleBus(call, { send: sendOn }));
({ processing, chat, bus, projectFiles, projectFile, libraryFile, libraryStatus, send, librarySync, libraryRevert, librarySave, settingsWrite, projectSave, nameWrite, assistantStop, instancesWrite, routesWrite, agentWrite } = consoleBus(call, { send: sendOn }));
// Row 252 (#1753): Approve and Deny on grant requests, through the console wrapper, only with
// --sso and --send.
if (ssoOn && sendOn) decisionWrite = consoleCall({ dataRoot, socket: socketPath(dataRoot), business: options.business ?? null });
@@ -107,7 +107,7 @@ try {
}
let server;
try {
server = await startServer({ board: options.board, port: options.port, bus, reads, preview: options.preview, sso, proof, send, settingsWrite, projectFiles, projectFile, libraryFile, libraryStatus, librarySync, libraryRevert, projectSave, chat, nameWrite, assistantStop, instancesWrite, routesWrite, agentWrite, processing, decisionWrite, userOptions, federation: system?.federation ?? null });
server = await startServer({ board: options.board, port: options.port, bus, reads, preview: options.preview, sso, proof, send, settingsWrite, projectFiles, projectFile, libraryFile, libraryStatus, librarySync, libraryRevert, librarySave, projectSave, chat, nameWrite, assistantStop, instancesWrite, routesWrite, agentWrite, processing, decisionWrite, userOptions, federation: system?.federation ?? null });
} catch (err) { sso?.close(); throw err; }
let testerServer = null;
if (testerSocket) {
+2 -1
View File
@@ -30,10 +30,11 @@ export function consoleBus(call, { send: sendOn = false, owner = null } = {}) {
projectFiles: args => call('project.files', args),
projectFile: args => call('project.file', args),
libraryFile: args => call('library.file', args), libraryStatus: args => call('library.status', args),
send: null, librarySync: null, libraryRevert: null, settingsWrite: null, projectSave: null, nameWrite: null, assistantStop: null, instancesWrite: null, routesWrite: null, agentWrite: null,
send: null, librarySync: null, libraryRevert: null, librarySave: null, settingsWrite: null, projectSave: null, nameWrite: null, assistantStop: null, instancesWrite: null, routesWrite: null, agentWrite: null,
};
if (sendOn) {
o.send = args => call('message.send', args); o.librarySync = args => call('library.sync', args); o.libraryRevert = args => call('library.revert', args); o.settingsWrite = args => call('limits.set', args);
o.librarySave = args => call('library.file.save', args);
o.projectSave = args => call('project.file.save', args); o.nameWrite = args => call('name.set', args); o.assistantStop = args => call('assistant.stop', args);
o.instancesWrite = args => call('instances.set', args); o.routesWrite = args => call('routes.set', args); o.agentWrite = agentCaller(call, AGENT_VERBS);
}
@@ -0,0 +1,22 @@
// Row 288: the Console's save option carries only the caller's args over its own transport.
import test from 'node:test';
import assert from 'node:assert/strict';
import { consoleBus, userOptionsFor } from '../src/console-bus.mjs';
test('C2-02: library save option is absent without --send and forwards no editor or identity', async () => {
const calls = [], call = async (verb, args) => { calls.push({ verb, args }); return { commit: 'a'.repeat(40) }; };
assert.equal(consoleBus(call).librarySave, null);
const args = { project: 'books', path: 'Book One/Chapters/01.md', base: 'b'.repeat(40), content: 'her text\n' };
assert.equal((await consoleBus(call, { send: true }).librarySave(args)).commit, 'a'.repeat(40));
assert.deepEqual(calls, [{ verb: 'library.file.save', args }]);
assert.deepEqual(Object.keys(calls[0].args).sort(), ['base', 'content', 'path', 'project']);
});
test('C2-02: user save option uses that user transport; owner transport is never called', async () => {
const calls = [];
const options = userOptionsFor({ owner: () => { throw Error('owner transport touched'); }, send: true,
transport: user => async (verb, args) => { calls.push({ user, verb, args }); } });
const args = { project: 'books', path: 'Book One/Chapters/01.md', base: null, content: 'fixture' };
await options({ user: 'reader' }).librarySave(args);
assert.deepEqual(calls, [{ user: 'reader', verb: 'library.file.save', args }]);
});