Compare commits
43
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e1d8756b51 | ||
|
|
83ec67dd36 | ||
|
|
de3e23dde9 | ||
|
|
446c9b8381 | ||
|
|
f78a45653d | ||
|
|
775bbe2368 | ||
|
|
35f34ad27a | ||
|
|
624507c74b | ||
|
|
77a790f43b | ||
|
|
bfd2f43b10 | ||
|
|
cb86e186dc | ||
|
|
ce8bb4d8b0 | ||
|
|
3a8e4abadb | ||
|
|
c68a29fed8 | ||
|
|
92e82469f2 | ||
|
|
8feda29eb4 | ||
|
|
bbec5e97f1 | ||
|
|
ec213e0336 | ||
|
|
78b69e1e68 | ||
|
|
48b89db33b | ||
|
|
7c8dc20335 | ||
|
|
ce0b6ed411 | ||
|
|
97cb9a7630 | ||
|
|
e908f7ffee | ||
|
|
92df71a982 | ||
|
|
0abec5d2e8 | ||
|
|
20996ecd66 | ||
|
|
78b932feb6 | ||
|
|
9e2689dffb | ||
|
|
b24d917ec9 | ||
|
|
61ebf2c34d | ||
|
|
d1f6f2b199 | ||
|
|
c65fb34ee6 | ||
|
|
94cde633e2 | ||
|
|
669cdf42c4 | ||
|
|
98614187ce | ||
|
|
c8a9bcf946 | ||
|
|
58b2bbb3a5 | ||
|
|
95d4991d20 | ||
|
|
966ee31ea8 | ||
|
|
696ea3a3af | ||
|
|
0ce22dde65 | ||
|
|
36056a5dd9 |
No files matched your search
@@ -5567,6 +5567,14 @@ claim. Receipts and limitations in agents/lena/work/queue-296/BUILD.md and run-r
|
||||
|
||||
2026-10-24 | Fethry | Row328 sage4214/Mos1599 option A GREEN on06c57a7db:8x50 M1-50 produced374 passes/26 expected library-sync-busy assertion failures, exact restore/full diff+porcelain clean, same8x50 fixed400/400, whole library-credential6/6, no skips/cancels or unexpected errors/reruns. Node nice16/19 observed after absolute19; loads and801 receipts retained. Old test staysapproved+4/-3, assertions/product unchanged. Own process sweep empty. Evidence push/slot return and owner review move next; Boyd/Dewey then Sage full bus/scripts gate pending.
|
||||
|
||||
2026-10-24T19:44:50Z | Sage | Row 257 (#1762, Q198 S1 pressure parser and rules evaluator, Morgana, Filbert) LANDED 73692e1bb, pushed 17:41:58Z 10-24. Before: refactor at 487500a16. After: Morgana's four commits cherry-picked onto 487500a16 with unchanged patches; the 9 packages/supervisor paths match Filbert's round 2 manifest b176a88f. Filbert r1 c30188 (N1/N2 fixed in r2), r2 APPROVE c30190 rev 3037, request c30189 posted by Sage. Slot result on 1261fa2d8: three files whole 15/0, 29/0, 1/0, supervisor 45/0, M1-M8 killed by assertion. Sage gate: first run RED 17:20:42Z, webui 441/1 on the old row278 sign-out test (timeout at load about 8.5, the row touches no webui path); the webui-only rerun 442/0 was not counted; the full rerun was GREEN 17:41:11Z: bus 998/0, business 283/0, webui 442/0, supervisor 45/0, cli 989 plus the allowed FED R7 skip, all 12 scripts rc 0. Correction: the row278 timing red is an old test, so any change to it goes to Mos (mos-1272). Follow-up: Morgana's carry (sage-3003, CLEAR_HELD entry and a clear-path hold test) binds the row that wires a Q198 hold into a launch refusal. Not re-pinned.
|
||||
|
||||
2026-10-24T19:44:50Z | Sage | Row 266 (#1771, C2-10c Console room view, Fethry on Codex, Boyd and Dewey) LANDED 3e5041b43, pushed 18:00:49Z 10-24. Before: refactor at 73692e1bb. After: Fethry's four commits cherry-picked, every patch-id equal to the seat branch; tree is manifest 5f816042 with no other change. Boyd APPROVE c31609 rev 3983, Dewey APPROVE c31610 rev 3985 (N1-N3 non-blocking), request c31608 posted by Sage. Sage gate GREEN first run 18:00:08Z: bus 1000/0, business 283/0, webui 458/0, supervisor 45/0, cli 989 plus the allowed FED R7 skip, all 12 scripts rc 0. Dewey's N2, the old T9 library-sync-busy race, went to Mos and became row 328. Not re-pinned.
|
||||
|
||||
2026-10-24T19:44:50Z | Sage | Row 224 (#1725, C2-05b, Della on Codex, Dewey) LANDED 5e77cdd09, pushed 19:18Z 10-24. Before: refactor at 7fe32d722. After: Della's 13 commits cherry-picked onto 7fe32d722. Sage gate GREEN 19:16:37Z on 27624aa66 (base 06f507dbc): bus 1011/0, business 283/0, harness 176/0, cli 990/0 plus the allowed FED R7 skip, webui 458/0, all scripts rc 0. Drift between the gated base and 7fe32d722 is only docs/plans/2026-10-24_model-proxy-rows.md, which no test reads (mos-1601 condition); manifest-r9 952482b4 matches the landed tree. Dewey APPROVE c31619 rev 3999. #1725 closed c31623; note rev 4015, done rev 4016. Correction: the first done move passed --evidence and was refused (rc 2, the round closes on its recorded verdicts); rerun without it. Follow-up: Dewey's N3, the old ask helper can't serve a library business, goes to a later row. Not re-pinned.
|
||||
|
||||
2026-10-24T19:44:50Z | Sage | Row 328 (#1826, Vikunja 622, old T9 timer race, Fethry on Codex, Boyd and Dewey) LANDED 8bb5b3c73, pushed 19:40Z 10-24. Before: refactor at 5e77cdd09. After: Fethry's 8 commits cherry-picked onto 5e77cdd09 (same patches); T9's second start passes intervalMs 2147483647 (mos-1594), test-only. Under 8x50 concurrent loops M1 (50 ms back) gave 26 expected failures and the fix 400/400. Boyd APPROVE c31621 rev 4002, Dewey APPROVE c31622 rev 4003. Sage gate GREEN 19:38:54Z on 8bb5b3c73 itself, no drift: bus 1011/0, business 283/0, harness 176/0, cli 990/0 plus the allowed FED R7 skip, webui 458/0, every scripts/test-*.sh rc 0 (Dewey N1). Manifest 1e010468. #1826 closed c31625, Vikunja 622 done (comment 1071), note rev 4019, done rev 4020. Not re-pinned.
|
||||
|
||||
2026-10-24 — Magica row329 P1 (#1827, Vikunja237): beginning pinned model-proxy fetch/init/client/unit build at 7fe32d722, under mos-1600/1601. Acceptance uses only fresh temp roots and unshare -rn; live instance and host proxy excluded. Evidence agents/magica/work/queue-329/BUILD.md.
|
||||
|
||||
2026-10-24 — Magica row329 P1 (#1827): final builder checks green: model-proxy61/61, bus1018/1018, CLI999pass+1listed federation skip, pinned-copy10/10, config55/55 and federation runner1/1. Final unit-config fix verified by two new tests and all direct CLI readers. Original F7 red, Mos1604 diagnostic and Mos1605 unchanged rerun are preserved; cause unknown, landing independent. Q250 drops the panel forward; PIN8.0.42/panel1.26.7 unchanged. Evidence agents/magica/work/queue-329/BUILD.md.
|
||||
@@ -5574,3 +5582,10 @@ claim. Receipts and limitations in agents/lena/work/queue-296/BUILD.md and run-r
|
||||
2026-10-24 — Magica row329 round2 (#1827): Boyd B1 tightens management keys to printable non-space ASCII before init creates state; new whole-tree refusal cases first reproduced the defect. Header check retained, no old assertions edited. N1 outer Docker count correction, N3 stale-lock recovery and N4 34-code coverage docs included. Cleared dependency-reader gate running; two stand-in over-selections disclosed and removed from the plan per sage-4277, F7 cause unknown. Evidence agents/magica/work/queue-329/BUILD.md.
|
||||
|
||||
2026-10-24 — Magica row329 R2 (#1827): B1 ASCII-only management key fix verified with complete-tree refusals and positive auth control; package66/66,30bus readers261/261,49CLI readers726/726,config55/55, no required skip/failure. N1 corrects R1 bus total to1019; N3 stale-lock guidance and N4 34-code inventory corrected. Two over-selected file runs are recorded separately, with no F7 inference; cause unknown/Vikunja625. Old502 test/helper files byte-identical, slot returned to Sage. Evidence agents/magica/work/queue-329/BUILD.md.
|
||||
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-24T22:15:07Z | Herb | row 214 #1715 C2-11a focused evidence | Before: wikilinks are ordinary editor text; raw/sig retention keeps no-edit bytes, but the model has no inert node. After: inert inline wikilink atom preserves spelling through neighbouring edits; invalid attrs share HTML/entity escaping. On herb/row214-r2 base487500a16, grant sage-4286 lane B: baseline10/10 roundTrips equal (outcome A); baseline structural0/1 expected red; four whole editor files40/0, both mutants killed0/1 and restored1/0, whole webui69 files455/0 in174.189s with MOSAIC_REQUIRE_EDITOR_BUILD=1, nice19, no skips/cancellations. A mistaken preliminary7-file subset28/0 is logged and excluded from gate evidence. CSS byte-identical, final process sweep0, scratch TMPDIR removed. Filbert candidate review and every scripts/test-*.sh gate remain pending; no click, target resolution or library save change.
|
||||
2026-10-25T04:36:47Z | Sage | Row 214 (#1715, C2-11a editor wikilink node, Herb) LANDED 3a8e4abad, pushed 04:27Z 10-25. Before: refactor at 78b69e1e6. After: Herb's six commits cherry-picked onto 78b69e1e6 and fast-forwarded. Gate GREEN 04:10:34Z: 18 package suites rc 0 (webui 471/471, cli 999 plus the allowed FED R7 skip), every scripts/test-*.sh rc 0, queue package via test-queue.sh 156. Design skips: queue 34 (not the canonical root), task 87/93 (row 244). Filbert APPROVE c31679 rev 4093. Range-diff equal except commit 5's BUILD-LOG context; 40/41 paths same blob, BUILD-LOG additions only. #1715 closed c31680. Queue note 4094, done 4095, committed ce8bb4d8b.
|
||||
2026-10-25T04:36:47Z | Sage | Row 193 (#1691, threads user roles design, Morgana) LANDED 35f34ad27, doc-only: five design commits cherry-picked onto ce8bb4d8b, adding only agents/morgana/work/queue-193/DESIGN.md (verify-commit ok, 1 path). Duckworth APPROVE c31676 rev 4088 (posted and recorded by Sage; Duckworth has no Gitea credential). No test reads queue-193. Build rows from the design: 204/#1702, 205/#1703 (landed), 275/#1780, 206/#1704, 207/#1705, 208/#1706.
|
||||
2026-10-25T04:58:30Z | Sage | Row 255 (#1760, Vikunja 458, bundled Pocket ID design for Q203, Launchpad) LANDED de3e23dde, doc-only: Launchpad's three design commits e29d8ec90, 9f60021a0 and c8f2bc723 cherry-picked onto 775bbe236 (range-diff equal), adding only agents/launchpad/work/queue-255/DESIGN.md. No test reads queue-255. Webby APPROVE round 1 c31689 rev 4103 (posted by Sage; Webby has no Gitea token). Mos rulings in mos-1666: M1 approved with conditions (rollback removes components before the pointer goes back and the STATE check confirms the key is absent; the loader stays strict inside the key; four test-config.sh cases), R1 chosen, M2 dropped. Sage gate check against Q203, O6, REQ-WEB-2 and REQ-INST-1: consistent. One PRD text gap goes to Mos: REQ-INST-2 says the stack writes the providers entry, and R1 prints it for the user to paste. Webby N1 and N2 bind P4; N3-N8 carry into the P1-P6 build rows, all post-v1.
|
||||
@@ -0,0 +1,934 @@
|
||||
# Row284 C2-05c — supporting scope and served-tree blob (#1789)
|
||||
|
||||
Owner Della; reviewer Dewey; gate Sage. Build start sage-3658/3660 (10-23).
|
||||
Branch della/row284. Original prerequisite base Honker28346bad7ea3;
|
||||
merge fc05bcbc3 carries22423816cf28 and2164f3fbc25a intact. Only conflict was
|
||||
CLI thread-launch's added footer tests: retained both full test bodies and
|
||||
assertions. No prerequisite code copied. Every prerequisite needs its own
|
||||
review/mutants/landing under mos1351; rebase after283 lands.
|
||||
|
||||
## Execution status
|
||||
|
||||
UNTESTED. No Node, node--check, test or mutant run before Sage CLEAR. First
|
||||
own commit is the authorized old-test migration; the implementation follows.
|
||||
Sage authorizes an immediate untested push. No queue write or shared-log edit.
|
||||
224 stays first;284 is critical to Bubba288. T4 for224 is not a CLEAR yet.
|
||||
|
||||
## Binding readings
|
||||
|
||||
Brief C2-05c at94c33a43c:1737-1789, Q226, sage2918 and mos1330 item3.
|
||||
get defaults canon; explicit playground/supporting opt-in; mismatch null.
|
||||
Sort full outgoing/incoming lists supporting, playground, canon before paging,
|
||||
keep cross-scope links and universe filter. Manuscript stays canon/playground.
|
||||
No all/array scope, write tool, guard, mapping or creative-name-count change.
|
||||
|
||||
## mos-1330 old-test migration (separate commit)
|
||||
|
||||
All paths below are packages/library/tests/query.test.mjs. Baseline file at
|
||||
fc05bcbc3 matches216's file. Source assertions retained; negative calls receive
|
||||
explicit scope too, so universe isolation cannot pass on default-scope denial.
|
||||
|
||||
Call/assertion 348 -> 348:
|
||||
|
||||
```js
|
||||
// OLD
|
||||
const rin = await get(s, { universe: 'idea', path: 'Drafts/New World/Characters/Rin.md' });
|
||||
// NEW
|
||||
const rin = await get(s, { universe: 'idea', path: 'Drafts/New World/Characters/Rin.md', scope: 'playground' });
|
||||
```
|
||||
|
||||
Call/assertion 350 -> 350:
|
||||
|
||||
```js
|
||||
// OLD
|
||||
assert.equal(await get(s, { universe: 'harbor', path: 'Drafts/New World/Characters/Rin.md' }), null);
|
||||
// NEW
|
||||
assert.equal(await get(s, { universe: 'harbor', path: 'Drafts/New World/Characters/Rin.md', scope: 'playground' }), null);
|
||||
```
|
||||
|
||||
Call/assertion 366 -> 366:
|
||||
|
||||
```js
|
||||
// OLD
|
||||
assert.equal(await get(src(ref, mapping(WITH_BLEND)), { universe: 'blend', path }), null);
|
||||
// NEW
|
||||
assert.equal(await get(src(ref, mapping(WITH_BLEND)), { universe: 'blend', path, scope: 'playground' }), null);
|
||||
```
|
||||
|
||||
Call/assertion 367 -> 367:
|
||||
|
||||
```js
|
||||
// OLD
|
||||
const own = await get(src(ref), { universe: 'harbor', path });
|
||||
// NEW
|
||||
const own = await get(src(ref), { universe: 'harbor', path, scope: 'playground' });
|
||||
```
|
||||
|
||||
Assertion 349 retained, OLD == NEW:
|
||||
|
||||
```js
|
||||
assert.equal(rin.scope, 'playground');
|
||||
```
|
||||
|
||||
Assertion 368 retained, OLD == NEW:
|
||||
|
||||
```js
|
||||
assert.equal(own.scope, 'playground');
|
||||
```
|
||||
|
||||
The null assertions at350 and366 are the complete OLD/NEW expressions above:
|
||||
expectation remains null. Added one separate no-scope playground-get -> null
|
||||
behavior test. It is unrun and expected to expose old get behavior until the
|
||||
new scope implementation lands. This migration is authorized by mos1330 under
|
||||
mos1272; no check removed or weakened. Dewey checks this list in manifest review.
|
||||
|
||||
## 283 surface and blob choice
|
||||
|
||||
Inspected actual46bad7ea3: optional editor.user is present. reader's parsed
|
||||
file records and index entries still discard tree oid. In owned query.mjs use
|
||||
the existing bounded listTree(repo, servedCommit) to obtain exact path oid,
|
||||
not HEAD and not a user-supplied revision expression. No reader/index edit.
|
||||
Tradeoff: one additional bounded tree listing per get; latency unmeasured.
|
||||
Recheck after rebasing to283's actual landing.
|
||||
|
||||
## Intended owned paths
|
||||
|
||||
query.mjs; broker.mjs lookup branch; tools.mjs lookup schemas/descriptions;
|
||||
library query.test.mjs/query-fixture.mjs; bus library-lookups.test.mjs;
|
||||
harness library-tools.test.mjs; this BUILD.md. Other files are prerequisites.
|
||||
|
||||
## Gate
|
||||
|
||||
Dewey manifest approval, whole library/bus/harness suites and every
|
||||
scripts/test-*.sh on Sage gate. Before review grep all package tests for enum
|
||||
pins and canon/playground pairs. Keep shared logs out; send receipts to Sage.
|
||||
No test or mutant evidence claimed. Manifest/digest follows complete code.
|
||||
|
||||
## Implementation head (UNTESTED, sage-3658)
|
||||
|
||||
- query scope accepts supporting for find/search/get. get defaults canon,
|
||||
mismatch null. Manuscript passes a separate two-value scope allowlist.
|
||||
- get returns blob from listTree(source.repo,index.commit) after scope/universe
|
||||
filtering. The same index.commit supplies the text; source HEAD is irrelevant.
|
||||
- Full outgoing and incoming link lists are stably sorted by supporting,
|
||||
playground,canon before combining/paging. All visible cross-scope links stay;
|
||||
universe/hybrid visibility still applies. Scope metadata isn't added to links.
|
||||
- Broker only adds optional scope to library.get's strict fields. No new verbs.
|
||||
- Typed scope expands find/search/get only; manuscript retains its own two-value
|
||||
enum. Names/M3 counts remain the row224 six/eight, no write tools added.
|
||||
- New tests: book/universe/draft supporting find/search/get; defaults/mismatch;
|
||||
absent supporting prefix; source HEAD advances but each scope's blob equals
|
||||
served:path; 300 outgoing plus300 incoming links ordered across bounded pages,
|
||||
retaining cross-scope links and dropping other-universe links; hybrid source
|
||||
stays canon-only; no all/array scope; manuscript rejects supporting; broker
|
||||
scope/blob forwarding; typed enums and unchanged names. All unrun.
|
||||
|
||||
## Additional old assertion pin (brief Gate)
|
||||
|
||||
harness/tests/library-tools.test.mjs:49 at23816cf28 (line49, unchanged in this head):
|
||||
OLD find scope enum ['canon','playground']; NEW ['canon','playground','supporting'].
|
||||
This is the exact scope-enum pin the brief directs updating. Existing six/eight
|
||||
name snapshots and TYPES equality assertion are unchanged. The new manuscript
|
||||
pin intentionally remains ['canon','playground']. No other two-scope test pin
|
||||
was found by rg over packages/*/tests at this build's prerequisite merge.
|
||||
|
||||
## Proposed mutation evidence (reviewer confirms final set)
|
||||
|
||||
All unrun. Require assertion failures with whole-file runs and pristine restore:
|
||||
M1 remove supporting from query SCOPES -> supporting lookup cases.
|
||||
M2 drop get's requested-scope comparison -> default/mismatch null cases.
|
||||
M3 use source HEAD for blob lookup -> served-tree/advanced-HEAD equality case.
|
||||
M4 remove link rank sort -> multi-page outgoing/incoming expected order.
|
||||
M5 restrict links to requested scope -> cross-scope link counts/order case.
|
||||
M6 drop sees() from visible/link filtering -> second-universe/hybrid cases.
|
||||
M7 allow supporting in manuscript validator -> manuscript refusal case.
|
||||
M8 omit get scope from broker fields -> real broker supporting get case.
|
||||
M9 widen typed manuscript enum -> typed-scope separation case.
|
||||
|
||||
## Inspection and pending gate
|
||||
|
||||
No production imports change in broker/tools, so no new sandbox closure file
|
||||
or mount. query.mjs is host library code and adds existing reader.listTree;
|
||||
no new package/export/copy-path file. rg found the one old find scope pin plus
|
||||
the intentional new manuscript two-scope pin. Whole library/bus/harness and
|
||||
shell gates remain required. CLI integration/merge context is prerequisite224/
|
||||
219, not this row's source delta; any changed gate expectation goes to Sage.
|
||||
Node checks, tests, mutants and elapsed-time evidence remain absent pending
|
||||
CLEAR. The first test-migration commit and this implementation are distinct.
|
||||
|
||||
Sage sweep receipt: Della row284 builds on28346bad7ea3 plus intact224 merge;
|
||||
mos1330 old-test migration separate, supporting scope/blob implementation and
|
||||
fixtures authored, completely UNTESTED. No shared-log/queue write or live action.
|
||||
|
||||
## Current assertion anchors after implementation imports
|
||||
|
||||
The separate migration commit0ed4fbab9 retains its complete OLD/NEW text
|
||||
above. Adding only the fs/path imports in the implementation shifts anchors:
|
||||
|
||||
query.test.mjs:130: `const blendCh2 = await get(src(ref, mapping(WITH_BLEND)), { universe: 'blend', path: 'Book One/Chapters/Chapter 02.md' });`
|
||||
query.test.mjs:350: `const rin = await get(s, { universe: 'idea', path: 'Drafts/New World/Characters/Rin.md', scope: 'playground' });`
|
||||
query.test.mjs:351: `assert.equal(rin.scope, 'playground');`
|
||||
query.test.mjs:352: `assert.equal(await get(s, { universe: 'harbor', path: 'Drafts/New World/Characters/Rin.md', scope: 'playground' }), null);`
|
||||
query.test.mjs:368: `assert.equal(await get(src(ref, mapping(WITH_BLEND)), { universe: 'blend', path, scope: 'playground' }), null);`
|
||||
query.test.mjs:369: `const own = await get(src(ref), { universe: 'harbor', path, scope: 'playground' });`
|
||||
query.test.mjs:370: `assert.equal(own.scope, 'playground');`
|
||||
|
||||
No result/null assertion changed; scope arguments carry the explicit opt-in.
|
||||
|
||||
## Dewey dewey-0941 static review — round2
|
||||
|
||||
Static scope fc05bcbc3..47db04eba CLEAN; not a final verdict or test evidence.
|
||||
M1-M9 accepted as the final set. Optional M10 not added to this gate.
|
||||
N2 taken: keep the existing canon-path supporting-scope mismatch assertion,
|
||||
and ADD get(Book One/Support/Notes/Helper.md,scope:supporting) -> null under
|
||||
the default mapping with no supporting prefix. The supporting-positive test
|
||||
already returns this same path under withSupporting, so the added probe
|
||||
pins the missing-prefix case directly. No assertion removed or weakened;
|
||||
mos1330's separate migration commit and its retained assertions unchanged.
|
||||
|
||||
N1 proposed DEFERRED/follow-up for Sage: retain each tree oid in reader/index
|
||||
entries so get can return blob without cat-file/whole ls-tree -r -l per page.
|
||||
Current get's result is pinned correctly, but per-page cost grows with the
|
||||
library. No performance measurement yet. This optimization needs reader/index
|
||||
ownership and separate acceptance/performance evidence; do not silently expand
|
||||
284's manifest or change its served-snapshot contract for it.
|
||||
|
||||
No Node, tests, mutants or syntax checks run in this round; hold still applies.
|
||||
|
||||
## sage-4281 — rebase onto landed 224/283, 2026-10-24
|
||||
|
||||
New worktree /mnt/storage/scratch/della-row284-r2, branch della/row284-r2,
|
||||
base refactor 95d4991d20a4ef291c824d37c886eaeaa9be7062. Cherry-picked only
|
||||
284-owned 0ed4fbab9, 47db04eba, 5d587a552. Range-diff: all three equal, no
|
||||
conflicts. The separate mos-1330 migration remains its own commit. No 216,
|
||||
224 or 283 prerequisite commits copied. Old della/row284 remains unchanged.
|
||||
|
||||
mos-1584 fixture check: new tests add no businessDoc() with a library. The
|
||||
harness role() uses landed 224's gitea reference for bean; the library-enabled
|
||||
CLI chief fixture fix is also upstream. New broker test uses the direct
|
||||
Broker fixture (no businessDoc/bootConfig), not a new validated organization.
|
||||
No new made-up credential values are introduced in this row; existing short
|
||||
fixture references are reused, so no new credential reaches 24 characters.
|
||||
No credential values were inspected or printed. No fixture edit necessary.
|
||||
|
||||
No Node, npm, syntax check, service, test, mutant or install run in this worktree.
|
||||
No canonical node_modules link. Dependency installation remains a separately
|
||||
cleared local npm ci if needed; tests wait for Sage CLEAR. For future runs use
|
||||
shell mktemp -d /mnt/storage/scratch/tmp/XXXXXX and per-child absolute nice 19.
|
||||
Shared logs unchanged; Sage owns landing receipts.
|
||||
|
||||
## Import-derived whole-file run plan (mos-1612)
|
||||
|
||||
Walked relative static import/re-export edges and literal dynamic imports
|
||||
transitively, from each packages/*/tests/**/*.test.mjs to changed query.mjs,
|
||||
broker.mjs, tools.mjs or query-fixture.mjs. This follows source import edges,
|
||||
not textual mentions. Example CLI/thread-launch -> Broker; CLI/helpers ->
|
||||
Broker; webui/serve -> webui/bus -> Broker; harness/bundle -> tools.
|
||||
Evidence generator and per-test import chains are in
|
||||
/mnt/storage/scratch/della-row284-r2-evidence/import-run-list.py and .json.
|
||||
The import-derived set has 260 files; union with the brief's whole library,
|
||||
bus and harness suites adds files that use subprocesses/source reads instead
|
||||
of direct imports. Excluded case1-accept.test.mjs by sage-4281. Any dynamic
|
||||
nonliteral loading or external shell gate is not claimed covered by import
|
||||
tracing; mandatory package suites and Sage's full script gate remain required.
|
||||
|
||||
First focused whole files: library/query.test.mjs; bus/library-lookups.test.mjs;
|
||||
harness/library-tools.test.mjs. Then the full import-derived/mandatory union
|
||||
below, each file whole (duplicates need not repeat without a change). This
|
||||
is a proposed run list for Sage's CLEAR, not authorization to run now.
|
||||
M1-M9 retain Dewey's agreed specification above; no mutant executed.
|
||||
|
||||
Whole-file union:
|
||||
|
||||
```text
|
||||
packages/bus/tests/access-revoke.test.mjs
|
||||
packages/bus/tests/account-migration.test.mjs
|
||||
packages/bus/tests/address.test.mjs
|
||||
packages/bus/tests/agents.test.mjs
|
||||
packages/bus/tests/approval-binding.test.mjs
|
||||
packages/bus/tests/broker.test.mjs
|
||||
packages/bus/tests/business.test.mjs
|
||||
packages/bus/tests/channel-proof.test.mjs
|
||||
packages/bus/tests/chief-of-staff.test.mjs
|
||||
packages/bus/tests/citation-availability.test.mjs
|
||||
packages/bus/tests/citation-guard.test.mjs
|
||||
packages/bus/tests/citation-runtime.test.mjs
|
||||
packages/bus/tests/comment-cursors.test.mjs
|
||||
packages/bus/tests/comment-migration.test.mjs
|
||||
packages/bus/tests/console-decide.test.mjs
|
||||
packages/bus/tests/creative.test.mjs
|
||||
packages/bus/tests/credential-claim.test.mjs
|
||||
packages/bus/tests/credential-status.test.mjs
|
||||
packages/bus/tests/credential-store.test.mjs
|
||||
packages/bus/tests/credential-verbs.test.mjs
|
||||
packages/bus/tests/credentials.test.mjs
|
||||
packages/bus/tests/csuite-messaging.test.mjs
|
||||
packages/bus/tests/daily-quota-runtime.test.mjs
|
||||
packages/bus/tests/decision-close.test.mjs
|
||||
packages/bus/tests/decision-route.test.mjs
|
||||
packages/bus/tests/decisions.test.mjs
|
||||
packages/bus/tests/end-launch.test.mjs
|
||||
packages/bus/tests/fire-revokes-grants.test.mjs
|
||||
packages/bus/tests/gitea-grant-docker.test.mjs
|
||||
packages/bus/tests/gitea-grant.test.mjs
|
||||
packages/bus/tests/gitea-migration.test.mjs
|
||||
packages/bus/tests/grant-enroll.test.mjs
|
||||
packages/bus/tests/grant-executor.test.mjs
|
||||
packages/bus/tests/grant-host.test.mjs
|
||||
packages/bus/tests/grant-migration.test.mjs
|
||||
packages/bus/tests/grant-scope-runtime.test.mjs
|
||||
packages/bus/tests/grant-scope.test.mjs
|
||||
packages/bus/tests/hard-waits.test.mjs
|
||||
packages/bus/tests/host-run.test.mjs
|
||||
packages/bus/tests/host-tools.test.mjs
|
||||
packages/bus/tests/human.test.mjs
|
||||
packages/bus/tests/instances-verb.test.mjs
|
||||
packages/bus/tests/interpreter.test.mjs
|
||||
packages/bus/tests/land.test.mjs
|
||||
packages/bus/tests/launch-notice.test.mjs
|
||||
packages/bus/tests/launcher-released.test.mjs
|
||||
packages/bus/tests/library-credential.test.mjs
|
||||
packages/bus/tests/library-lookups.test.mjs
|
||||
packages/bus/tests/library-sync.test.mjs
|
||||
packages/bus/tests/library.test.mjs
|
||||
packages/bus/tests/lifecycle-revoke.test.mjs
|
||||
packages/bus/tests/lifecycle-verbs.test.mjs
|
||||
packages/bus/tests/limit-checks.test.mjs
|
||||
packages/bus/tests/limit-stop.test.mjs
|
||||
packages/bus/tests/limits-runtime.test.mjs
|
||||
packages/bus/tests/limits.test.mjs
|
||||
packages/bus/tests/message-citation.test.mjs
|
||||
packages/bus/tests/message-filter.test.mjs
|
||||
packages/bus/tests/messages.test.mjs
|
||||
packages/bus/tests/messaging.test.mjs
|
||||
packages/bus/tests/name-migration.test.mjs
|
||||
packages/bus/tests/names.test.mjs
|
||||
packages/bus/tests/peer-transport.test.mjs
|
||||
packages/bus/tests/peercred.test.mjs
|
||||
packages/bus/tests/plugins-verb.test.mjs
|
||||
packages/bus/tests/principal.test.mjs
|
||||
packages/bus/tests/process.test.mjs
|
||||
packages/bus/tests/processing-runtime.test.mjs
|
||||
packages/bus/tests/processing-timeout.test.mjs
|
||||
packages/bus/tests/processing-web.test.mjs
|
||||
packages/bus/tests/processing.test.mjs
|
||||
packages/bus/tests/project-await.test.mjs
|
||||
packages/bus/tests/project-files.test.mjs
|
||||
packages/bus/tests/project-runtime.test.mjs
|
||||
packages/bus/tests/publish.test.mjs
|
||||
packages/bus/tests/reload.test.mjs
|
||||
packages/bus/tests/replies.test.mjs
|
||||
packages/bus/tests/requirements.test.mjs
|
||||
packages/bus/tests/review.test.mjs
|
||||
packages/bus/tests/revoke-window.test.mjs
|
||||
packages/bus/tests/room-check.test.mjs
|
||||
packages/bus/tests/rooms.test.mjs
|
||||
packages/bus/tests/routes-verb.test.mjs
|
||||
packages/bus/tests/schema.test.mjs
|
||||
packages/bus/tests/session-clear.test.mjs
|
||||
packages/bus/tests/session-compactions.test.mjs
|
||||
packages/bus/tests/sessions.test.mjs
|
||||
packages/bus/tests/single-use.test.mjs
|
||||
packages/bus/tests/spec-migration.test.mjs
|
||||
packages/bus/tests/spec-review.test.mjs
|
||||
packages/bus/tests/spec-socket.test.mjs
|
||||
packages/bus/tests/spec.test.mjs
|
||||
packages/bus/tests/staff-request.test.mjs
|
||||
packages/bus/tests/state.test.mjs
|
||||
packages/bus/tests/store.test.mjs
|
||||
packages/bus/tests/task-page.test.mjs
|
||||
packages/bus/tests/task-read.test.mjs
|
||||
packages/bus/tests/tasks.test.mjs
|
||||
packages/bus/tests/tester-threads.test.mjs
|
||||
packages/bus/tests/tester-writes.test.mjs
|
||||
packages/bus/tests/tester.test.mjs
|
||||
packages/bus/tests/thread-claims.test.mjs
|
||||
packages/bus/tests/thread-migration.test.mjs
|
||||
packages/bus/tests/thread-shares.test.mjs
|
||||
packages/bus/tests/threads.test.mjs
|
||||
packages/bus/tests/transport.test.mjs
|
||||
packages/bus/tests/usage-broker.test.mjs
|
||||
packages/bus/tests/usage-migration.test.mjs
|
||||
packages/bus/tests/usage-runtime.test.mjs
|
||||
packages/bus/tests/usage.test.mjs
|
||||
packages/bus/tests/user-principal.test.mjs
|
||||
packages/bus/tests/viewer.test.mjs
|
||||
packages/bus/tests/web.test.mjs
|
||||
packages/bus/tests/workflow-roles.test.mjs
|
||||
packages/business/tests/case1-business-file.test.mjs
|
||||
packages/business/tests/launch-settings.test.mjs
|
||||
packages/cli/tests/access-boot.test.mjs
|
||||
packages/cli/tests/access.test.mjs
|
||||
packages/cli/tests/app.test.mjs
|
||||
packages/cli/tests/boot-status.test.mjs
|
||||
packages/cli/tests/case1-hostcheck.test.mjs
|
||||
packages/cli/tests/case2-install.test.mjs
|
||||
packages/cli/tests/case2-persona-import.test.mjs
|
||||
packages/cli/tests/case2-unit.test.mjs
|
||||
packages/cli/tests/channel-cli.test.mjs
|
||||
packages/cli/tests/channel-recovery.test.mjs
|
||||
packages/cli/tests/cli.test.mjs
|
||||
packages/cli/tests/compactions-launch.test.mjs
|
||||
packages/cli/tests/config.test.mjs
|
||||
packages/cli/tests/credentials.test.mjs
|
||||
packages/cli/tests/federation-acceptance.test.mjs
|
||||
packages/cli/tests/follow.test.mjs
|
||||
packages/cli/tests/git-socket.test.mjs
|
||||
packages/cli/tests/grants-scope.test.mjs
|
||||
packages/cli/tests/grants.test.mjs
|
||||
packages/cli/tests/host.test.mjs
|
||||
packages/cli/tests/hosts.test.mjs
|
||||
packages/cli/tests/idle-stop-race.test.mjs
|
||||
packages/cli/tests/instances.test.mjs
|
||||
packages/cli/tests/launch-account.test.mjs
|
||||
packages/cli/tests/launch-limit-checks.test.mjs
|
||||
packages/cli/tests/launch-limits.test.mjs
|
||||
packages/cli/tests/launch-routes.test.mjs
|
||||
packages/cli/tests/launcher.test.mjs
|
||||
packages/cli/tests/lifecycle.test.mjs
|
||||
packages/cli/tests/limits-tokens.test.mjs
|
||||
packages/cli/tests/limits.test.mjs
|
||||
packages/cli/tests/mark-read.test.mjs
|
||||
packages/cli/tests/names.test.mjs
|
||||
packages/cli/tests/notifier.test.mjs
|
||||
packages/cli/tests/optional-tracker.test.mjs
|
||||
packages/cli/tests/other-tree.test.mjs
|
||||
packages/cli/tests/processing-cli.test.mjs
|
||||
packages/cli/tests/project-name-repo.test.mjs
|
||||
packages/cli/tests/project.test.mjs
|
||||
packages/cli/tests/publish-socket.test.mjs
|
||||
packages/cli/tests/reply-limits.test.mjs
|
||||
packages/cli/tests/revoke-window.test.mjs
|
||||
packages/cli/tests/session-clear.test.mjs
|
||||
packages/cli/tests/session-cli.test.mjs
|
||||
packages/cli/tests/session-launch.test.mjs
|
||||
packages/cli/tests/stack-copy.test.mjs
|
||||
packages/cli/tests/stack-instances.test.mjs
|
||||
packages/cli/tests/tester-http.test.mjs
|
||||
packages/cli/tests/tester-reads.test.mjs
|
||||
packages/cli/tests/tester-threads.test.mjs
|
||||
packages/cli/tests/tester.test.mjs
|
||||
packages/cli/tests/thread-cli.test.mjs
|
||||
packages/cli/tests/thread-launch.test.mjs
|
||||
packages/cli/tests/thread-revoke.test.mjs
|
||||
packages/cli/tests/trackers-boot.test.mjs
|
||||
packages/cli/tests/transport.test.mjs
|
||||
packages/cli/tests/usage.test.mjs
|
||||
packages/cli/tests/verbs.test.mjs
|
||||
packages/harness/tests/bundle.test.mjs
|
||||
packages/harness/tests/citation-runner.test.mjs
|
||||
packages/harness/tests/claude-gate.test.mjs
|
||||
packages/harness/tests/claude-session.test.mjs
|
||||
packages/harness/tests/creative.test.mjs
|
||||
packages/harness/tests/gate.test.mjs
|
||||
packages/harness/tests/git-tools.test.mjs
|
||||
packages/harness/tests/library-tools.test.mjs
|
||||
packages/harness/tests/mcp-server.test.mjs
|
||||
packages/harness/tests/pi-session.test.mjs
|
||||
packages/harness/tests/raise-domain.test.mjs
|
||||
packages/harness/tests/runner.test.mjs
|
||||
packages/harness/tests/skills.test.mjs
|
||||
packages/harness/tests/spec-tools.test.mjs
|
||||
packages/harness/tests/tools.test.mjs
|
||||
packages/library/tests/guard.test.mjs
|
||||
packages/library/tests/index-build.test.mjs
|
||||
packages/library/tests/links.test.mjs
|
||||
packages/library/tests/mapping.test.mjs
|
||||
packages/library/tests/mirror.test.mjs
|
||||
packages/library/tests/query.test.mjs
|
||||
packages/library/tests/reader.test.mjs
|
||||
packages/library/tests/render.test.mjs
|
||||
packages/library/tests/scope.test.mjs
|
||||
packages/library/tests/supporting.test.mjs
|
||||
packages/library/tests/survey.test.mjs
|
||||
packages/library/tests/sync.test.mjs
|
||||
packages/processing-control/tests/task.test.mjs
|
||||
packages/seat/tests/sandbox.test.mjs
|
||||
packages/seat/tests/session.test.mjs
|
||||
packages/tasks/tests/adapter.test.mjs
|
||||
packages/tasks/tests/comment-restart.test.mjs
|
||||
packages/tasks/tests/fields.test.mjs
|
||||
packages/tasks/tests/processing.test.mjs
|
||||
packages/tasks/tests/shapes.test.mjs
|
||||
packages/tasks/tests/startup.test.mjs
|
||||
packages/tasks/tests/sync.test.mjs
|
||||
packages/tasks/tests/tree.test.mjs
|
||||
packages/tasks/tests/verbs.test.mjs
|
||||
packages/webui/tests/agents-browser.test.mjs
|
||||
packages/webui/tests/agents.test.mjs
|
||||
packages/webui/tests/assistant.test.mjs
|
||||
packages/webui/tests/board-held.test.mjs
|
||||
packages/webui/tests/browser-edge.test.mjs
|
||||
packages/webui/tests/browser.test.mjs
|
||||
packages/webui/tests/bus-browser.test.mjs
|
||||
packages/webui/tests/bus.test.mjs
|
||||
packages/webui/tests/channel-chat.test.mjs
|
||||
packages/webui/tests/chat-browser.test.mjs
|
||||
packages/webui/tests/chat-instances.test.mjs
|
||||
packages/webui/tests/chat-replies-browser.test.mjs
|
||||
packages/webui/tests/chat-sessions-access.test.mjs
|
||||
packages/webui/tests/chat.test.mjs
|
||||
packages/webui/tests/conversation.test.mjs
|
||||
packages/webui/tests/decide-browser.test.mjs
|
||||
packages/webui/tests/decide-sso.test.mjs
|
||||
packages/webui/tests/decision-http.test.mjs
|
||||
packages/webui/tests/discord.test.mjs
|
||||
packages/webui/tests/docs-browser.test.mjs
|
||||
packages/webui/tests/editor-browser.test.mjs
|
||||
packages/webui/tests/editor.test.mjs
|
||||
packages/webui/tests/granted-user.test.mjs
|
||||
packages/webui/tests/history-return-flow.test.mjs
|
||||
packages/webui/tests/instances-browser.test.mjs
|
||||
packages/webui/tests/instances.test.mjs
|
||||
packages/webui/tests/library-cli.test.mjs
|
||||
packages/webui/tests/library-routes.test.mjs
|
||||
packages/webui/tests/library-status.test.mjs
|
||||
packages/webui/tests/limits-browser.test.mjs
|
||||
packages/webui/tests/limits-route.test.mjs
|
||||
packages/webui/tests/messages.test.mjs
|
||||
packages/webui/tests/pinned-copy.test.mjs
|
||||
packages/webui/tests/preview.test.mjs
|
||||
packages/webui/tests/processing-browser.test.mjs
|
||||
packages/webui/tests/processing.test.mjs
|
||||
packages/webui/tests/project-file.test.mjs
|
||||
packages/webui/tests/project-name-repo.test.mjs
|
||||
packages/webui/tests/proof-cli.test.mjs
|
||||
packages/webui/tests/proof.test.mjs
|
||||
packages/webui/tests/reads.test.mjs
|
||||
packages/webui/tests/relaunch.test.mjs
|
||||
packages/webui/tests/return-flow.test.mjs
|
||||
packages/webui/tests/room-browser.test.mjs
|
||||
packages/webui/tests/room-http.test.mjs
|
||||
packages/webui/tests/routes-browser.test.mjs
|
||||
packages/webui/tests/routes.test.mjs
|
||||
packages/webui/tests/send-browser.test.mjs
|
||||
packages/webui/tests/send.test.mjs
|
||||
packages/webui/tests/serve.test.mjs
|
||||
packages/webui/tests/settings-form.test.mjs
|
||||
packages/webui/tests/settings-write.test.mjs
|
||||
packages/webui/tests/shell.test.mjs
|
||||
packages/webui/tests/sso-browser.test.mjs
|
||||
packages/webui/tests/sso.test.mjs
|
||||
packages/webui/tests/tester-browser.test.mjs
|
||||
packages/webui/tests/tester-cli.test.mjs
|
||||
packages/webui/tests/tester-listener.test.mjs
|
||||
packages/webui/tests/tester-socket.test.mjs
|
||||
packages/webui/tests/thread-claims-browser.test.mjs
|
||||
packages/webui/tests/thread-claims.test.mjs
|
||||
packages/webui/tests/thread-sharing.test.mjs
|
||||
packages/webui/tests/usage-browser.test.mjs
|
||||
packages/webui/tests/usage.test.mjs
|
||||
packages/webui/tests/user-option-swap.test.mjs
|
||||
packages/webui/tests/views.test.mjs
|
||||
```
|
||||
|
||||
Queue next on 2026-10-24 names row284 but reports the whole brief differs
|
||||
from its queue pin and asks the lead to re-pin. Sage-4281 names 5e8a720b and
|
||||
says the section is unchanged; awaiting lead resolution of the queue pin
|
||||
before the start move. No queue policy refusal is bypassed.
|
||||
|
||||
## sage-4289 lane B — completed verification, 2026-10-24
|
||||
|
||||
Current reviewer is Webby under mos-1614 / sage-4284, replacing Dewey.
|
||||
Dewey's earlier static readings and agreed M1-M9 remain historical evidence.
|
||||
Row284 claimed in-progress rev4038, op della-284-start-1 after lead re-pin.
|
||||
Candidate tested: 2f1a6bd93e5fc602c46ee5f770d19adecde5fc11. No code,
|
||||
fixture or assertion change during verification. Local npm ci used the exact
|
||||
lockfile, ignore-scripts/no-audit/no-fund, rc0,128 packages; no canonical
|
||||
node_modules link. Installer receipt and log are in the evidence directory.
|
||||
|
||||
Run list sent in full to Sage before starting (della-0058); source is the
|
||||
import walk documented above, union mandatory package suites,279 whole files.
|
||||
Three targeted files first, then M1-M9 with byte-exact restore after each,
|
||||
then remaining276 whole files. Already-passed unchanged targeted files are
|
||||
not repeated. Every Node invocation used fresh shell gXXX TMPDIR,29 bytes,
|
||||
absolute nice19 set in the child before exec, timeout -k10 (900-second cap,
|
||||
shortened automatically near23:45Z hardstop). All timeout nice observations
|
||||
were19. Normal run total1067.962s; mutant total19.485s. Completed22:34Z.
|
||||
|
||||
| Package | Whole files | Pass | Fail | Skip |
|
||||
| --- | ---: | ---: | ---: | ---: |
|
||||
| bus | 114 | 1012 | 0 | 0 |
|
||||
| business | 2 | 25 | 0 | 0 |
|
||||
| cli | 58 | 610 | 0 | 1 |
|
||||
| harness | 15 | 177 | 0 | 0 |
|
||||
| library | 12 | 156 | 0 | 0 |
|
||||
| processing-control | 1 | 7 | 0 | 0 |
|
||||
| seat | 2 | 23 | 0 | 0 |
|
||||
| tasks | 9 | 95 | 0 | 0 |
|
||||
| webui | 66 | 396 | 0 | 0 |
|
||||
|
||||
Totals:279 whole files,2501 passed,0 failed,1 skipped,0 cancelled.
|
||||
Sole skip: packages/cli/tests/federation-acceptance.test.mjs,
|
||||
FED R7 scratch two-instance acceptance, directs running
|
||||
scripts/test-federation-acceptance.sh. That acceptance was not exercised;
|
||||
Sage's full shell landing gate is separate. case1-accept.test.mjs excluded
|
||||
as ordered. No unlisted run or extra mutant. Targeted counts: query34/34,
|
||||
broker12/12,typed tools5/5,zero skips.
|
||||
|
||||
M1-M9 all killed with exit1, no syntax/setup failures. M1 and M8 are expected
|
||||
behavior errors when a required capability is removed; the others fail
|
||||
assertions/refusal checks. Killing named tests are recorded below. Each
|
||||
restored original bytes in finally; git diff --stat and status --porcelain
|
||||
empty after every mutant and again after all normal runs, before receipts.
|
||||
No extra post-restore test rerun.
|
||||
|
||||
| Mutant | Killing behavior oracle | Restored |
|
||||
| --- | --- | --- |
|
||||
| M1 | supporting find/search/get | byte-exact, clean |
|
||||
| M2 | get without scope returns null | byte-exact, clean |
|
||||
| M3 | each get blob equals its served tree object | byte-exact, clean |
|
||||
| M4 | full outgoing and incoming links stay in scope order | byte-exact, clean |
|
||||
| M5 | full outgoing and incoming links stay in scope order | byte-exact, clean |
|
||||
| M6 | full outgoing and incoming links stay in scope order | byte-exact, clean |
|
||||
| M7 | manuscript still refuses supporting | byte-exact, clean |
|
||||
| M8 | broker forwards supporting scope | byte-exact, clean |
|
||||
| M9 | scope schemas expand only find/search/get | byte-exact, clean |
|
||||
|
||||
Post-run sweep: current OS user's executable names node/nodejs/chromium/
|
||||
chrome, matching cwd or argv paths under this worktree or any run TMPDIR.
|
||||
Checked289 unique roots;0 matching live processes. No signals sent, no
|
||||
other seat's process inspected beyond process identity/path matching.
|
||||
No full argv, environment or credential values printed. Slot returned to
|
||||
Sage in della-0059 at22:34Z. No further tests.
|
||||
|
||||
Evidence: /mnt/storage/scratch/della-row284-r2-evidence/run-4289 contains
|
||||
install receipt, exact commands, stdout/stderr per whole-file run, mutant
|
||||
edits/restores, summaries and hashed logs. The following plain-text ledger
|
||||
freezes commands and results; raw logs remain available for reviewer checks.
|
||||
Each normal test path below was run whole; hashes are SHA256 of raw logs.
|
||||
|
||||
```text
|
||||
{"label":"target-query","command":["timeout","-k","10","900","node","--test","packages/library/tests/query.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gUgw","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":2.889,"mutant":false,"tests":34,"pass":34,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"dc2575e2c597b099c94b7cf254b0cb4d009a0ddb14c0cbd572f93e5ad15f8f72"}
|
||||
{"label":"target-broker","command":["timeout","-k","10","900","node","--test","packages/bus/tests/library-lookups.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gDd2","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.431,"mutant":false,"tests":12,"pass":12,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"6729e92f2241a2c2d0b725cb9c6ed4fe4d8b50352fd179cf30f905182eac9160"}
|
||||
{"label":"target-tools","command":["timeout","-k","10","900","node","--test","packages/harness/tests/library-tools.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gmPG","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.169,"mutant":false,"tests":5,"pass":5,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"532de351eef39478011d7f84b3b506711c3bafc71676716f623fa29573fc4dec"}
|
||||
{"label":"M1","command":["timeout","-k","10","900","node","--test","packages/library/tests/query.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gIGt","start_nice":19,"observed_timeout_nice":19,"exit":1,"seconds":2.683,"mutant":true,"tests":34,"pass":30,"fail":4,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"ec36434e918ee16c7639ec0ec4259be66e0381e2684bac7c6ee5755756bded78"}
|
||||
{"label":"M2","command":["timeout","-k","10","900","node","--test","packages/library/tests/query.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/geid","start_nice":19,"observed_timeout_nice":19,"exit":1,"seconds":2.587,"mutant":true,"tests":34,"pass":31,"fail":3,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"e08eadfd606fc685faed21edb06b1d7d00fd11e7942051fddc0b48b83c6bef90"}
|
||||
{"label":"M3","command":["timeout","-k","10","900","node","--test","packages/library/tests/query.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gs4j","start_nice":19,"observed_timeout_nice":19,"exit":1,"seconds":2.538,"mutant":true,"tests":34,"pass":33,"fail":1,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"8abb79847deb7a05940c7b48d5407dde6baaf394fef31334f6ac266d65b3c02f"}
|
||||
{"label":"M4","command":["timeout","-k","10","900","node","--test","packages/library/tests/query.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gvmZ","start_nice":19,"observed_timeout_nice":19,"exit":1,"seconds":2.674,"mutant":true,"tests":34,"pass":33,"fail":1,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"8b8386b876fb85e12335be27216dc5c6a8d5c311c03db0bf49ffbe0639a8693c"}
|
||||
{"label":"M5","command":["timeout","-k","10","900","node","--test","packages/library/tests/query.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gG6o","start_nice":19,"observed_timeout_nice":19,"exit":1,"seconds":2.633,"mutant":true,"tests":34,"pass":32,"fail":2,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"08ff976a29e42f593dce3262e596e75c43da2ae2e3dfe48945989fe98c3061cf"}
|
||||
{"label":"M6","command":["timeout","-k","10","900","node","--test","packages/library/tests/query.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gWpu","start_nice":19,"observed_timeout_nice":19,"exit":1,"seconds":2.347,"mutant":true,"tests":34,"pass":23,"fail":11,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"4cd149d0f74e402d2294c2d9ef05aac440ec4c3dc379acad7b9624b7402528bb"}
|
||||
{"label":"M7","command":["timeout","-k","10","900","node","--test","packages/library/tests/query.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g65B","start_nice":19,"observed_timeout_nice":19,"exit":1,"seconds":2.403,"mutant":true,"tests":34,"pass":33,"fail":1,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"541100f0937dd2e592ed9bee7c48f27ae4e13634d3c0dcf53fc3e8b2f632a000"}
|
||||
{"label":"M8","command":["timeout","-k","10","900","node","--test","packages/bus/tests/library-lookups.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gtX5","start_nice":19,"observed_timeout_nice":19,"exit":1,"seconds":1.421,"mutant":true,"tests":12,"pass":11,"fail":1,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"2adc93e5aaa663621caa9fd762faded3a975f62de918d7c46a1b5b0469001955"}
|
||||
{"label":"M9","command":["timeout","-k","10","900","node","--test","packages/harness/tests/library-tools.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gMtM","start_nice":19,"observed_timeout_nice":19,"exit":1,"seconds":0.199,"mutant":true,"tests":5,"pass":4,"fail":1,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"da8c8c2094732b36526dc803e567d4bce18ff964bf70ff406e1981bb7dd313de"}
|
||||
{"label":"import-001","command":["timeout","-k","10","900","node","--test","packages/bus/tests/access-revoke.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gGcs","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.728,"mutant":false,"tests":10,"pass":10,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"ee78177b9385025df0b0ce154e9f92f3d84a01920da94eb2b95df7aee533721a"}
|
||||
{"label":"import-002","command":["timeout","-k","10","900","node","--test","packages/bus/tests/account-migration.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/giJX","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.456,"mutant":false,"tests":3,"pass":3,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"04456ac702b53d59e127eb7ae2d9828b79acbbcc99c8845cc226e88e4569ffb2"}
|
||||
{"label":"import-003","command":["timeout","-k","10","900","node","--test","packages/bus/tests/address.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gLUL","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.102,"mutant":false,"tests":15,"pass":15,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"c4ff31db588ac88b6492416d3850b123492e29dbd7c6b2aa283dd736e6caa8cc"}
|
||||
{"label":"import-004","command":["timeout","-k","10","900","node","--test","packages/bus/tests/agents.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gDuh","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.493,"mutant":false,"tests":11,"pass":11,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"424001894b865c63405976f7facc9a9c93c2ac018b6c97f17ebf87001d071d52"}
|
||||
{"label":"import-005","command":["timeout","-k","10","900","node","--test","packages/bus/tests/approval-binding.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gsfL","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.305,"mutant":false,"tests":6,"pass":6,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"f8029477d12d0acbd774ec6fa82d9af47ae93c575e0ada16c31130248280431d"}
|
||||
{"label":"import-006","command":["timeout","-k","10","900","node","--test","packages/bus/tests/broker.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gwdO","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.532,"mutant":false,"tests":16,"pass":16,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"b02528f749bc8367149451f2118cf612f7d46ee6269ad05d9a894d6ef893b727"}
|
||||
{"label":"import-007","command":["timeout","-k","10","900","node","--test","packages/bus/tests/business.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gX5H","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.102,"mutant":false,"tests":1,"pass":1,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"3246c77a5431fda5ee0ef798b9850ee8bf05297c7afa272fc88d148582dc14d8"}
|
||||
{"label":"import-008","command":["timeout","-k","10","900","node","--test","packages/bus/tests/channel-proof.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g0t2","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.644,"mutant":false,"tests":2,"pass":2,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"d3dc7af8bd80c5cd391a42468cec38fa2cdf4d7bb8d758e84094a255cf2e8626"}
|
||||
{"label":"import-009","command":["timeout","-k","10","900","node","--test","packages/bus/tests/chief-of-staff.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gAXk","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":2.744,"mutant":false,"tests":42,"pass":42,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"6e355388daee3b3cfe0251abd3f1f1fc56744e26354b8489d8113e4cb4033847"}
|
||||
{"label":"import-010","command":["timeout","-k","10","900","node","--test","packages/bus/tests/citation-availability.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gNQV","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":5.391,"mutant":false,"tests":3,"pass":3,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"fe32f9423c7317c53d0946d6422fb4ea58bcbb0795730b80cba7b5daae47b8ef"}
|
||||
{"label":"import-011","command":["timeout","-k","10","900","node","--test","packages/bus/tests/citation-guard.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gilj","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.258,"mutant":false,"tests":13,"pass":13,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"1f6c35c535a407a121ec4ee9bb4e9acdc12b5e16e3f8ccf75bcb94a66511b820"}
|
||||
{"label":"import-012","command":["timeout","-k","10","900","node","--test","packages/bus/tests/citation-runtime.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gjTW","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.331,"mutant":false,"tests":1,"pass":1,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"9cb0ab5a64b667f563c827239c242ee77475acb8744e515d8472d839d7190e2e"}
|
||||
{"label":"import-013","command":["timeout","-k","10","900","node","--test","packages/bus/tests/comment-cursors.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gQvO","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.162,"mutant":false,"tests":2,"pass":2,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"898a7bcc0f68f8a54748a9da6c75b702738b07230a48ff4f939206b1c2dccfdf"}
|
||||
{"label":"import-014","command":["timeout","-k","10","900","node","--test","packages/bus/tests/comment-migration.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g4nL","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.609,"mutant":false,"tests":5,"pass":5,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"ade667dca625e36750417b46f3156be89ec5d40fff78511722c3fa671f3bcd25"}
|
||||
{"label":"import-015","command":["timeout","-k","10","900","node","--test","packages/bus/tests/console-decide.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/girM","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.893,"mutant":false,"tests":12,"pass":12,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"11a0ac7147f0164542442a9fc6e9224e5d36305cd3e999fc03733e289dfc8f4e"}
|
||||
{"label":"import-016","command":["timeout","-k","10","900","node","--test","packages/bus/tests/creative.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gXAL","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.447,"mutant":false,"tests":4,"pass":4,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"13b107465c7ddecb4fba573b58d4ff42f8807221d1956325b2a0e54eec4581d2"}
|
||||
{"label":"import-017","command":["timeout","-k","10","900","node","--test","packages/bus/tests/credential-claim.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g8Cy","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.157,"mutant":false,"tests":8,"pass":8,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"a66956b56367cb240de84571fc79e4297bf4bf49c06ce92ac3dd9c5d155b26a5"}
|
||||
{"label":"import-018","command":["timeout","-k","10","900","node","--test","packages/bus/tests/credential-status.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gEDT","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.401,"mutant":false,"tests":4,"pass":4,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"8812b6b0962c7b15e437a9c9b5741d502ab81001d9e17c9b5b14729db8f6033d"}
|
||||
{"label":"import-019","command":["timeout","-k","10","900","node","--test","packages/bus/tests/credential-store.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gPQx","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.158,"mutant":false,"tests":12,"pass":12,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"2ead3ac9725024e493121f7aaa8e7cf71a35616ffd57c901d3f425ac50b4a8b7"}
|
||||
{"label":"import-020","command":["timeout","-k","10","900","node","--test","packages/bus/tests/credential-verbs.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g1Wz","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.328,"mutant":false,"tests":2,"pass":2,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"bf447a8e6566816992f48a92e6821441ec1acd86960251aeee4b03b6e4b6dee3"}
|
||||
{"label":"import-021","command":["timeout","-k","10","900","node","--test","packages/bus/tests/credentials.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/grcF","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.105,"mutant":false,"tests":5,"pass":5,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"f3f807e470c8ec40f6c1aea188308a1ca183c8f0e98a0eaea996c96577ab471a"}
|
||||
{"label":"import-022","command":["timeout","-k","10","900","node","--test","packages/bus/tests/csuite-messaging.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gFHk","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.779,"mutant":false,"tests":16,"pass":16,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"1034823ca51c040db2f0bb18416c67761580ed55df0e60636883bc217878afd5"}
|
||||
{"label":"import-023","command":["timeout","-k","10","900","node","--test","packages/bus/tests/daily-quota-runtime.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gl0H","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.401,"mutant":false,"tests":4,"pass":4,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"95472c3d6b012d38f3db4c790fdd48b710535beee03274c0ea44a2cbd97ed095"}
|
||||
{"label":"import-024","command":["timeout","-k","10","900","node","--test","packages/bus/tests/decision-close.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g2Iz","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.34,"mutant":false,"tests":8,"pass":8,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"5c855717b19f203797db5b4f2789dd8f8df7d49cbdfee62ae0ffa220e4ed1a4a"}
|
||||
{"label":"import-025","command":["timeout","-k","10","900","node","--test","packages/bus/tests/decision-route.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gDI5","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.286,"mutant":false,"tests":5,"pass":5,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"485577231e6e797c256db8a832d98aca4bf856e47459e0c30a1940598c60b8aa"}
|
||||
{"label":"import-026","command":["timeout","-k","10","900","node","--test","packages/bus/tests/decisions.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/geqP","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.474,"mutant":false,"tests":7,"pass":7,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"aa887a5b2b30390fab4906cbd2f6ffa4ec37cc9e794478b18e7cd47eb354063b"}
|
||||
{"label":"import-027","command":["timeout","-k","10","900","node","--test","packages/bus/tests/end-launch.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g5u4","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.414,"mutant":false,"tests":7,"pass":7,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"e3aced744c09beda07405cba691c54a8c8dca973b7718285f67612cbfdad4ac1"}
|
||||
{"label":"import-028","command":["timeout","-k","10","900","node","--test","packages/bus/tests/fire-revokes-grants.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gD7b","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":4.034,"mutant":false,"tests":24,"pass":24,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"0e79b5a7c00f0701c84b76f3e9fd73f1bac2c9343594039df1e8a667e42d6ea4"}
|
||||
{"label":"import-029","command":["timeout","-k","10","900","node","--test","packages/bus/tests/gitea-grant-docker.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gcCX","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":25.371,"mutant":false,"tests":2,"pass":2,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"5720e4fc3d58350dc4192c7ceb5dff76aba9bf1aff1ac917e016e7295380b325"}
|
||||
{"label":"import-030","command":["timeout","-k","10","900","node","--test","packages/bus/tests/gitea-grant.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gIPd","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":12.386,"mutant":false,"tests":66,"pass":66,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"142962fbea6f3602701e4bcc5e0248cb06b98a2fad8bfafb92143a593e535ee6"}
|
||||
{"label":"import-031","command":["timeout","-k","10","900","node","--test","packages/bus/tests/gitea-migration.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gPFr","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.443,"mutant":false,"tests":5,"pass":5,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"2a3d38fa696805a193460d33bfec2461778463b7087e368b738700c583ad23c3"}
|
||||
{"label":"import-032","command":["timeout","-k","10","900","node","--test","packages/bus/tests/grant-enroll.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gAeL","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.838,"mutant":false,"tests":24,"pass":24,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"fc5d1d86af5c0689eb5a92d94ee1dc7a0143299523fc010d4a119c34b30ff768"}
|
||||
{"label":"import-033","command":["timeout","-k","10","900","node","--test","packages/bus/tests/grant-executor.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gEJ1","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":22.682,"mutant":false,"tests":42,"pass":42,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"97a66205b109952a7704ff9d5d63efbb0277922a0bf1510a677284f9ccbc9831"}
|
||||
{"label":"import-034","command":["timeout","-k","10","900","node","--test","packages/bus/tests/grant-host.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gYeV","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.433,"mutant":false,"tests":10,"pass":10,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"0ab7ed5613f9c353c5e6f786ceffc6112c4f851debb799cf60ff73ae2f2bf65d"}
|
||||
{"label":"import-035","command":["timeout","-k","10","900","node","--test","packages/bus/tests/grant-migration.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gcHz","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.495,"mutant":false,"tests":6,"pass":6,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"690a9c67e3426b8f6dc94c34f1b34ae5e502c0f8fb9ce67c5beab7cf5122557e"}
|
||||
{"label":"import-036","command":["timeout","-k","10","900","node","--test","packages/bus/tests/grant-scope-runtime.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gVjH","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.228,"mutant":false,"tests":1,"pass":1,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"c013731042ef37735fe6648ec299831b127d3ddb351c613d95efd4bc610d6ff2"}
|
||||
{"label":"import-037","command":["timeout","-k","10","900","node","--test","packages/bus/tests/grant-scope.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gwvw","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.35,"mutant":false,"tests":14,"pass":14,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"1b48fba6570d0dcef4666725bde8b8c8f95e75eb8abb517d15b226a6ae5b0ea4"}
|
||||
{"label":"import-038","command":["timeout","-k","10","900","node","--test","packages/bus/tests/hard-waits.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gM7r","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.464,"mutant":false,"tests":13,"pass":13,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"41d7bdf1b5276a7205b6b3e61ff4ac2f7982d60f5f190c3475e75c1ff4cebefd"}
|
||||
{"label":"import-039","command":["timeout","-k","10","900","node","--test","packages/bus/tests/host-run.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gfCB","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":15.268,"mutant":false,"tests":26,"pass":26,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"7f5c5ab5e5f654c1826e84369739616606de89763879d96ffaa9cc196db05d72"}
|
||||
{"label":"import-040","command":["timeout","-k","10","900","node","--test","packages/bus/tests/host-tools.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gbtM","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":4.726,"mutant":false,"tests":6,"pass":6,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"dfd0a799f300925eb291c8047adc0f9359bf05927f0b1c129c6b420fcf0bfcc0"}
|
||||
{"label":"import-041","command":["timeout","-k","10","900","node","--test","packages/bus/tests/human.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gnLK","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.102,"mutant":false,"tests":4,"pass":4,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"09791081c562afc5c9fa6da5b6df4e37935797147fc6d4c3f4cd8be2dd3d56ae"}
|
||||
{"label":"import-042","command":["timeout","-k","10","900","node","--test","packages/bus/tests/instances-verb.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g46h","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.305,"mutant":false,"tests":3,"pass":3,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"d41d14dd33492e34f21452550fed8d0ca0d3b1847cca0fb86c53ad13f8cb4fb7"}
|
||||
{"label":"import-043","command":["timeout","-k","10","900","node","--test","packages/bus/tests/interpreter.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gTjS","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.178,"mutant":false,"tests":5,"pass":5,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"c3be5eace9c994767d451fcd0d99ddfff2a647a8f7e74f21306c95ac503c229c"}
|
||||
{"label":"import-044","command":["timeout","-k","10","900","node","--test","packages/bus/tests/land.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gOEa","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.156,"mutant":false,"tests":18,"pass":18,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"b59e6b60f597b4b1d02d4ced63344dbcb820946148a11a4ddd8e29ac422ef0f8"}
|
||||
{"label":"import-045","command":["timeout","-k","10","900","node","--test","packages/bus/tests/launch-notice.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gv3V","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.543,"mutant":false,"tests":8,"pass":8,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"4979af0184d2b8fe0cfc7048da37828e2f58a8bb433b589399be4d8a7798371d"}
|
||||
{"label":"import-046","command":["timeout","-k","10","900","node","--test","packages/bus/tests/launcher-released.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gEQl","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.365,"mutant":false,"tests":3,"pass":3,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"9e4890aeaa7e21398fb140c469c606cb8a5cec2b564826232ade66f171fed937"}
|
||||
{"label":"import-047","command":["timeout","-k","10","900","node","--test","packages/bus/tests/library-credential.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gJlk","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":3.11,"mutant":false,"tests":6,"pass":6,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"ca7c89d815a3bc281b406089a04dbaf94d04927c0b6b0ae840cae34cd8e858f5"}
|
||||
{"label":"import-049","command":["timeout","-k","10","900","node","--test","packages/bus/tests/library-sync.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/geyX","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":7.525,"mutant":false,"tests":6,"pass":6,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"835bea6e1730fb67ab7d7ef02701ace657b0b3a839d300713ca16d0a32713828"}
|
||||
{"label":"import-050","command":["timeout","-k","10","900","node","--test","packages/bus/tests/library.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gejb","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.736,"mutant":false,"tests":6,"pass":6,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"70633e1f2e5662e511239ada1bb47e1dc197b79e2c9ecf005308b270f713a41c"}
|
||||
{"label":"import-051","command":["timeout","-k","10","900","node","--test","packages/bus/tests/lifecycle-revoke.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gA7g","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.815,"mutant":false,"tests":8,"pass":8,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"190fd253cefb4d669245531043a93225d37ae66ba694635a3e8bffd86c9e4264"}
|
||||
{"label":"import-052","command":["timeout","-k","10","900","node","--test","packages/bus/tests/lifecycle-verbs.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gYLp","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.62,"mutant":false,"tests":13,"pass":13,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"071bed270aff7f251d954b557e090230ee6e224535938b85b93e8f885d3fb944"}
|
||||
{"label":"import-053","command":["timeout","-k","10","900","node","--test","packages/bus/tests/limit-checks.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gt3p","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.347,"mutant":false,"tests":16,"pass":16,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"cb634a9e2819a161ec128a250586e4086591696309f00c9e6a62d7c54c6b9382"}
|
||||
{"label":"import-054","command":["timeout","-k","10","900","node","--test","packages/bus/tests/limit-stop.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g1Vs","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.362,"mutant":false,"tests":5,"pass":5,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"93504cdb3c5a9e5295bd72b8224ec69c43bbd344529a97538376c5a09e47328e"}
|
||||
{"label":"import-055","command":["timeout","-k","10","900","node","--test","packages/bus/tests/limits-runtime.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/giXl","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.454,"mutant":false,"tests":5,"pass":5,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"a18ac489d4eaa62e0bdb40444d70722379b0f4dc172f28e71f8600307ce7c3b6"}
|
||||
{"label":"import-056","command":["timeout","-k","10","900","node","--test","packages/bus/tests/limits.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gZog","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.424,"mutant":false,"tests":3,"pass":3,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"072dfdd9f45f609d52910d3619d4253bd05b54ec36e1a8599db17e17b472e99a"}
|
||||
{"label":"import-057","command":["timeout","-k","10","900","node","--test","packages/bus/tests/message-citation.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gCEq","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.244,"mutant":false,"tests":3,"pass":3,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"d53489b437b4adc8ac10bc52d0f1e6557b6fd187786008a6ad13a264207be034"}
|
||||
{"label":"import-058","command":["timeout","-k","10","900","node","--test","packages/bus/tests/message-filter.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gsfe","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.58,"mutant":false,"tests":6,"pass":6,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"6038a839d1b12b29d8cdbc0ea341ae22197e19444be5743ca327cb188cd1af59"}
|
||||
{"label":"import-059","command":["timeout","-k","10","900","node","--test","packages/bus/tests/messages.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gkz2","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.501,"mutant":false,"tests":4,"pass":4,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"e507905469453069f469a1366bd4cbd446c6b7e2e8ba5234c3d0bee83d1172ba"}
|
||||
{"label":"import-060","command":["timeout","-k","10","900","node","--test","packages/bus/tests/messaging.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gPZR","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.502,"mutant":false,"tests":13,"pass":13,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"434390031617151891ecb63a788da353c0d43051a4ea60db2e5727b149c9de4e"}
|
||||
{"label":"import-061","command":["timeout","-k","10","900","node","--test","packages/bus/tests/name-migration.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gsLH","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.192,"mutant":false,"tests":1,"pass":1,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"1979f0b1dd32162d42acace08a4b4306249e1096f5bbadb47038681af6b375d5"}
|
||||
{"label":"import-062","command":["timeout","-k","10","900","node","--test","packages/bus/tests/names.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/grPm","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.313,"mutant":false,"tests":7,"pass":7,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"1d35ce65a08ec74388a7a65af8bfb7a87d341fab5795360fd553e65aa10d4999"}
|
||||
{"label":"import-063","command":["timeout","-k","10","900","node","--test","packages/bus/tests/peer-transport.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g2ja","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.194,"mutant":false,"tests":4,"pass":4,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"579cce4a4581e991e6cad80666cd40bfb10d1346699f1233a44dab5d17ee1583"}
|
||||
{"label":"import-064","command":["timeout","-k","10","900","node","--test","packages/bus/tests/peercred.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g35b","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.499,"mutant":false,"tests":5,"pass":5,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"c6d9c4a534f8aab5c73e6920346674eb243a19439eaaa09436ff4c2bc9b68fd7"}
|
||||
{"label":"import-065","command":["timeout","-k","10","900","node","--test","packages/bus/tests/plugins-verb.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gGrj","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.331,"mutant":false,"tests":3,"pass":3,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"4677c69292a7fe1961239e40ecd5848b1e9355e6d9326f1c935dd077605cc36b"}
|
||||
{"label":"import-066","command":["timeout","-k","10","900","node","--test","packages/bus/tests/principal.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g5U9","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.102,"mutant":false,"tests":5,"pass":5,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"efac2a82f133ae63ba26543832b6704df573f345c7699b48b928d4329467f03e"}
|
||||
{"label":"import-067","command":["timeout","-k","10","900","node","--test","packages/bus/tests/process.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/go8U","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.448,"mutant":false,"tests":8,"pass":8,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"e26c9f5eb045dd7f651f453875fc1daac5dafa5f2060a69c3edcf37c79433e24"}
|
||||
{"label":"import-068","command":["timeout","-k","10","900","node","--test","packages/bus/tests/processing-runtime.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gmrO","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.392,"mutant":false,"tests":2,"pass":2,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"624f60b78329dbf8db5b5ce17e9f218148f7e417a46bcace45666b10193ea4c4"}
|
||||
{"label":"import-069","command":["timeout","-k","10","900","node","--test","packages/bus/tests/processing-timeout.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gt14","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.263,"mutant":false,"tests":1,"pass":1,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"30a4c425941c5732bb0afa09ff8cf2229f11ec6031c7cd3ae26932cf55dc2552"}
|
||||
{"label":"import-070","command":["timeout","-k","10","900","node","--test","packages/bus/tests/processing-web.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gWj9","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.126,"mutant":false,"tests":1,"pass":1,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"dbe9bc036efc99fc38b2dea8824cb7a64fc39e49fcd3a1ef07c60298b0d8e69f"}
|
||||
{"label":"import-071","command":["timeout","-k","10","900","node","--test","packages/bus/tests/processing.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gP4m","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.381,"mutant":false,"tests":14,"pass":14,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"d2204029f1dbc5836a759b43d421f2790ca32b97a1cc1fc6cb3f098fa4d7ab5d"}
|
||||
{"label":"import-072","command":["timeout","-k","10","900","node","--test","packages/bus/tests/project-await.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/grrE","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.177,"mutant":false,"tests":4,"pass":4,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"55cb0e215ff4f1e3265322c3336b3861d37fc3ba3cac53a31aa3dcc9ee0cab46"}
|
||||
{"label":"import-073","command":["timeout","-k","10","900","node","--test","packages/bus/tests/project-files.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gZZ4","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.894,"mutant":false,"tests":8,"pass":8,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"b3395652052ccd06de8df2a1ce1aaac185dab50e854fb712a33aef8319d17fdc"}
|
||||
{"label":"import-074","command":["timeout","-k","10","900","node","--test","packages/bus/tests/project-runtime.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gYyK","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.404,"mutant":false,"tests":3,"pass":3,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"b139c3c9cea5fc9bd86ac64f33c4af23f568bee13f9271fef40a07d76ed51cf2"}
|
||||
{"label":"import-075","command":["timeout","-k","10","900","node","--test","packages/bus/tests/publish.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gUl2","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.831,"mutant":false,"tests":13,"pass":13,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"0adf717babd8ac6229a115e1c796071fd68c1524f140d4596c9f1ee8c528b69f"}
|
||||
{"label":"import-076","command":["timeout","-k","10","900","node","--test","packages/bus/tests/reload.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gZPr","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.003,"mutant":false,"tests":10,"pass":10,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"2ce6a9bd3ea3eeccf1689e1b6335b72bba2d440ae27feeec3dc727567fa140ff"}
|
||||
{"label":"import-077","command":["timeout","-k","10","900","node","--test","packages/bus/tests/replies.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gbjz","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.374,"mutant":false,"tests":7,"pass":7,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"6db5c1588c83f2df4be469f06857569df7f4cfc47c18b15a8f9e741d4d739c4f"}
|
||||
{"label":"import-078","command":["timeout","-k","10","900","node","--test","packages/bus/tests/requirements.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g1jX","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.192,"mutant":false,"tests":3,"pass":3,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"32b876110fc8a35246f6ab16343dae9ea6da42ef556a99e1e5356e077474a96f"}
|
||||
{"label":"import-079","command":["timeout","-k","10","900","node","--test","packages/bus/tests/review.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gVJz","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.427,"mutant":false,"tests":8,"pass":8,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"333b7d84cf72b95ba2cdb1d3824bcb8043623c5f0810c68ed22738210977c297"}
|
||||
{"label":"import-080","command":["timeout","-k","10","900","node","--test","packages/bus/tests/revoke-window.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gRZs","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.305,"mutant":false,"tests":3,"pass":3,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"7e759b3330537c0c566b55b2c405adc6f5f48c3b229c4450d938aaec3280fc09"}
|
||||
{"label":"import-081","command":["timeout","-k","10","900","node","--test","packages/bus/tests/room-check.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gzW9","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.225,"mutant":false,"tests":2,"pass":2,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"300f1ea96ccfa38c9405ef163e531cfeec3c7eb8f46986f077669ca95b8f72f3"}
|
||||
{"label":"import-082","command":["timeout","-k","10","900","node","--test","packages/bus/tests/rooms.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gEx0","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.033,"mutant":false,"tests":18,"pass":18,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"fbcac36a4495da1def5dd650d8aea5758bf25d3e7473148a2b8961bb97b57239"}
|
||||
{"label":"import-083","command":["timeout","-k","10","900","node","--test","packages/bus/tests/routes-verb.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g0LO","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.292,"mutant":false,"tests":4,"pass":4,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"4fef276b76a79518faa03b81d119962ab8880af3010fa33ead93f393dca89f02"}
|
||||
{"label":"import-084","command":["timeout","-k","10","900","node","--test","packages/bus/tests/schema.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gZFQ","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.169,"mutant":false,"tests":1,"pass":1,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"e71271414564fa851dbf25a155b44dcf481770c7f3d4dafe5ce44a09c49526b1"}
|
||||
{"label":"import-085","command":["timeout","-k","10","900","node","--test","packages/bus/tests/session-clear.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gfrg","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.773,"mutant":false,"tests":19,"pass":19,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"c8097880d5e9a396fb907bc1f35f342821971b545fea7f1e4ddcb2b9f2fb322a"}
|
||||
{"label":"import-086","command":["timeout","-k","10","900","node","--test","packages/bus/tests/session-compactions.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gfRL","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.179,"mutant":false,"tests":4,"pass":4,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"0a2f0ef4d7f6588e2aaeb5a5d8e200650ae573c4468640130140eb83430261b3"}
|
||||
{"label":"import-087","command":["timeout","-k","10","900","node","--test","packages/bus/tests/sessions.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gaNb","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.654,"mutant":false,"tests":7,"pass":7,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"11f26dc0d082b49ce7839d22aca75067dcc2f978d6c319da3d2800adcc0a9ffc"}
|
||||
{"label":"import-088","command":["timeout","-k","10","900","node","--test","packages/bus/tests/single-use.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gSe3","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.416,"mutant":false,"tests":12,"pass":12,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"7a0e2e7a4a6ab79b85462ad1a39955c5402dab8a9236534c857cef88d08ecc87"}
|
||||
{"label":"import-089","command":["timeout","-k","10","900","node","--test","packages/bus/tests/spec-migration.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gPmw","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.215,"mutant":false,"tests":1,"pass":1,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"b9831356a0d65a037796a66764dcf7dcc267d8512e70087b364cbe390a8c85dc"}
|
||||
{"label":"import-090","command":["timeout","-k","10","900","node","--test","packages/bus/tests/spec-review.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gqKv","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":2.034,"mutant":false,"tests":12,"pass":12,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"8a70a550b2b056c35f2e85bdd4a155bf7d02332d89596aeed40e16bec765221c"}
|
||||
{"label":"import-091","command":["timeout","-k","10","900","node","--test","packages/bus/tests/spec-socket.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gY6G","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.787,"mutant":false,"tests":6,"pass":6,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"d58670526310fa5106ab9b3d724d817910283b76cfa8bd79278b0428e42b73c3"}
|
||||
{"label":"import-092","command":["timeout","-k","10","900","node","--test","packages/bus/tests/spec.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gnTM","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.538,"mutant":false,"tests":4,"pass":4,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"d04ac45ad25906322cbbd50b703c316c4eeefad1d40f901eeaf2c34224fc5958"}
|
||||
{"label":"import-093","command":["timeout","-k","10","900","node","--test","packages/bus/tests/staff-request.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g07B","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.544,"mutant":false,"tests":10,"pass":10,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"e0e379d2e0871ecbbae9a5e92ee7217342dc31cf69c80373aeef72f78ea27fd9"}
|
||||
{"label":"import-094","command":["timeout","-k","10","900","node","--test","packages/bus/tests/state.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gx6m","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.289,"mutant":false,"tests":8,"pass":8,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"63ac32064c6220c89204a8c34f13ce45ebb76f65a6e10e4173608740e1b54887"}
|
||||
{"label":"import-095","command":["timeout","-k","10","900","node","--test","packages/bus/tests/store.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g5mj","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.286,"mutant":false,"tests":7,"pass":7,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"329377b361787f86ffb5bda9210559d3d073e8ed9cfacc43e341156de63af707"}
|
||||
{"label":"import-096","command":["timeout","-k","10","900","node","--test","packages/bus/tests/task-page.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gErK","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.203,"mutant":false,"tests":6,"pass":6,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"0e48322586d18073df7d9efbc0700b7f9e2e45a7a61eb32ffa13ab9d9695de54"}
|
||||
{"label":"import-097","command":["timeout","-k","10","900","node","--test","packages/bus/tests/task-read.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g7B0","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.237,"mutant":false,"tests":3,"pass":3,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"3aa73723d9410d5c6851352f6b3d9c0f671f9b008b8a2355021488f2a071c22b"}
|
||||
{"label":"import-098","command":["timeout","-k","10","900","node","--test","packages/bus/tests/tasks.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gqcQ","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.037,"mutant":false,"tests":9,"pass":9,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"60e43ca791f0ee0e5a91c0a112ad0d971f38d28e18d6feb7a2d33132aec934fe"}
|
||||
{"label":"import-099","command":["timeout","-k","10","900","node","--test","packages/bus/tests/tester-threads.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gbPX","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.486,"mutant":false,"tests":15,"pass":15,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"101fcf483990278f3a997ed1cff44b6191b1766147083ddf21341a4480eb602b"}
|
||||
{"label":"import-100","command":["timeout","-k","10","900","node","--test","packages/bus/tests/tester-writes.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gMT4","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.609,"mutant":false,"tests":8,"pass":8,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"d5618314574cf7e64ac877e29787712f5fd68903228e6e1001c37cdd9b54a9e4"}
|
||||
{"label":"import-101","command":["timeout","-k","10","900","node","--test","packages/bus/tests/tester.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gl5m","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":2.337,"mutant":false,"tests":14,"pass":14,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"c44885e9d43e6ed5969af2f87ecc17fe00e1f1895435d86f5ddbe399c945642e"}
|
||||
{"label":"import-102","command":["timeout","-k","10","900","node","--test","packages/bus/tests/thread-claims.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gmfF","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.354,"mutant":false,"tests":6,"pass":6,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"bd053d20e52d1859ea6ed13f316e7ed27dac3ba3a8f1be5b3b7adef2fa15e356"}
|
||||
{"label":"import-103","command":["timeout","-k","10","900","node","--test","packages/bus/tests/thread-migration.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gUt3","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.513,"mutant":false,"tests":3,"pass":3,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"ee94081c476ab12b1c1b73eb2efb6138c22deee6dda92aa015fd2b2cc4cc405e"}
|
||||
{"label":"import-104","command":["timeout","-k","10","900","node","--test","packages/bus/tests/thread-shares.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g6KY","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.966,"mutant":false,"tests":16,"pass":16,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"e2c37691510cc5acfecfcd6d5be612b701fa72a06c544c265b027a381eb577ae"}
|
||||
{"label":"import-105","command":["timeout","-k","10","900","node","--test","packages/bus/tests/threads.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gqdT","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.848,"mutant":false,"tests":20,"pass":20,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"0e25845dfd5e6c68c206ef19b6ab74b5e00d01cf2ce6cd8843b7f0abe4229d60"}
|
||||
{"label":"import-106","command":["timeout","-k","10","900","node","--test","packages/bus/tests/transport.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gG0Z","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.355,"mutant":false,"tests":5,"pass":5,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"177ad5f143bb47dc7d65ef89785b19170ed7f5a25d1dd78079c73367b7d34bb5"}
|
||||
{"label":"import-107","command":["timeout","-k","10","900","node","--test","packages/bus/tests/usage-broker.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gYVM","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.179,"mutant":false,"tests":1,"pass":1,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"91d3b9ff3e854f2afb6d635a0994a4b2d1af482804067c2e6f78930babf25378"}
|
||||
{"label":"import-108","command":["timeout","-k","10","900","node","--test","packages/bus/tests/usage-migration.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gJIX","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.232,"mutant":false,"tests":1,"pass":1,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"35dae9048409bf16982b1554b0d3bf53de51293c012b428cfa95e3876c353d1b"}
|
||||
{"label":"import-109","command":["timeout","-k","10","900","node","--test","packages/bus/tests/usage-runtime.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gzcI","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.3,"mutant":false,"tests":1,"pass":1,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"1b260c414d98caf272852cc1c6a0928a79f84b05baad356f954fabb8befed9f4"}
|
||||
{"label":"import-110","command":["timeout","-k","10","900","node","--test","packages/bus/tests/usage.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g9hD","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.341,"mutant":false,"tests":15,"pass":15,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"4b7a7719685b54f0bafcd0d6ca0eff8da3c35e8c438b69fb63826120c444646d"}
|
||||
{"label":"import-111","command":["timeout","-k","10","900","node","--test","packages/bus/tests/user-principal.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gCyo","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.843,"mutant":false,"tests":24,"pass":24,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"7e5d8e391b6d683905f7654276e74e56cd2e0bb3019d8882fb51f5e96e8bb4e2"}
|
||||
{"label":"import-112","command":["timeout","-k","10","900","node","--test","packages/bus/tests/viewer.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gckq","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.495,"mutant":false,"tests":7,"pass":7,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"0088c69c83ad21b0c09c5b74986f7d1b5609f6155d40d6230cb755914506b209"}
|
||||
{"label":"import-113","command":["timeout","-k","10","900","node","--test","packages/bus/tests/web.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gr8J","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.209,"mutant":false,"tests":19,"pass":19,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"81db5367857555ba39abf0d45a2b4837a60c796109af4039b43f3dceaaf9a3e4"}
|
||||
{"label":"import-114","command":["timeout","-k","10","900","node","--test","packages/bus/tests/workflow-roles.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gObE","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.265,"mutant":false,"tests":4,"pass":4,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"4a3d911233067a9623aacbe0f856296e7c80d616d1099a30a9ce253506791bb2"}
|
||||
{"label":"import-115","command":["timeout","-k","10","900","node","--test","packages/business/tests/case1-business-file.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gKGR","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.839,"mutant":false,"tests":7,"pass":7,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"2dd7e08774e88449fc90beffa7a1097772a4b04906e62548cd34b31f1cf541b3"}
|
||||
{"label":"import-116","command":["timeout","-k","10","900","node","--test","packages/business/tests/launch-settings.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gaiJ","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.451,"mutant":false,"tests":18,"pass":18,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"849eeebfaaf47c96f22db45752fb5f00143663fb4ed0aa2d22d74f8af9ea3905"}
|
||||
{"label":"import-117","command":["timeout","-k","10","900","node","--test","packages/cli/tests/access-boot.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gU7B","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.64,"mutant":false,"tests":4,"pass":4,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"1698f3f93b14d11b330e559f19a580edae78b4182042df0e7da1cc9d4cbb53be"}
|
||||
{"label":"import-118","command":["timeout","-k","10","900","node","--test","packages/cli/tests/access.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gHaW","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":7.364,"mutant":false,"tests":34,"pass":34,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"e42f5491e4db8370ad6f6c2f09a8008c9559ecd572f0985f766f0ca11b1d7b60"}
|
||||
{"label":"import-119","command":["timeout","-k","10","900","node","--test","packages/cli/tests/app.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gmHw","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":16.086,"mutant":false,"tests":30,"pass":30,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"d65043a7cf3a1d67b99bb47de8efa029c44b90b9fcc0cc7cb8d8ed54403bba81"}
|
||||
{"label":"import-120","command":["timeout","-k","10","900","node","--test","packages/cli/tests/boot-status.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gYv3","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.916,"mutant":false,"tests":3,"pass":3,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"f6753a454d658737099bb6da76219aeb3c6e92bce76b78c53f2d9dae29f5d777"}
|
||||
{"label":"import-121","command":["timeout","-k","10","900","node","--test","packages/cli/tests/case1-hostcheck.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gvaK","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":3.735,"mutant":false,"tests":19,"pass":19,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"aeb1e23bf951d5859d7adb54fe8f3c6464ba4bf368e9316dce8e5142e097565c"}
|
||||
{"label":"import-122","command":["timeout","-k","10","900","node","--test","packages/cli/tests/case2-install.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gLWb","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":11.37,"mutant":false,"tests":27,"pass":27,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"06166332e80fd57cd9ae5e5ef2f167260adb413cd6c799b9c1834255cbf3ed63"}
|
||||
{"label":"import-123","command":["timeout","-k","10","900","node","--test","packages/cli/tests/case2-persona-import.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g955","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":3.606,"mutant":false,"tests":14,"pass":14,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"6005b321161cba438dc94ee6f58a05a05919e099da0d5b43b16b0438214b128e"}
|
||||
{"label":"import-124","command":["timeout","-k","10","900","node","--test","packages/cli/tests/case2-unit.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gPC5","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":104.569,"mutant":false,"tests":47,"pass":47,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"b9c64e1eea4e389dfc10b9e1ddf88e47d903c7abb1f175b0f73b0a6adf5e8a3b"}
|
||||
{"label":"import-125","command":["timeout","-k","10","900","node","--test","packages/cli/tests/channel-cli.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gCxf","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.604,"mutant":false,"tests":2,"pass":2,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"69ae3003d282a5f998613498ca1a696b684a9e4c03f5b006409d1fb15402c3c6"}
|
||||
{"label":"import-126","command":["timeout","-k","10","900","node","--test","packages/cli/tests/channel-recovery.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gy7b","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":7.039,"mutant":false,"tests":1,"pass":1,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"0df2d0dce24f2c7e9e70c1db3da115d848ee778a3b77c30f50db5fa5b70b15a8"}
|
||||
{"label":"import-127","command":["timeout","-k","10","900","node","--test","packages/cli/tests/cli.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g4YA","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.986,"mutant":false,"tests":12,"pass":12,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"9e9f75b810bdce44a7e288a0f03572a824642a0e615c3912113d8882fba57f20"}
|
||||
{"label":"import-128","command":["timeout","-k","10","900","node","--test","packages/cli/tests/compactions-launch.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gH0o","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":18.141,"mutant":false,"tests":5,"pass":5,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"7ab789f5de01f4d9fb2c2933fc906d657bb3c867ebb7e8545b4ae8b2f07e348b"}
|
||||
{"label":"import-129","command":["timeout","-k","10","900","node","--test","packages/cli/tests/config.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gvdv","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.989,"mutant":false,"tests":7,"pass":7,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"46976c51d867431031baeb7dfb03518e111f88327f99f24fafa727c987037710"}
|
||||
{"label":"import-130","command":["timeout","-k","10","900","node","--test","packages/cli/tests/credentials.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gW4m","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.558,"mutant":false,"tests":5,"pass":5,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"1633748b05e927193646fd8eaeb9cc64092553734a972a33ac9b26baee4390e1"}
|
||||
{"label":"import-131","command":["timeout","-k","10","900","node","--test","packages/cli/tests/federation-acceptance.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gEeW","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.281,"mutant":false,"tests":1,"pass":0,"fail":0,"cancelled":0,"skipped":1,"todo":0,"log_sha256":"76dec3f040a21cad59757b69487247ebb3b6a8b27b015f0615585b3be477942a"}
|
||||
{"label":"import-132","command":["timeout","-k","10","900","node","--test","packages/cli/tests/follow.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gxPz","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.084,"mutant":false,"tests":6,"pass":6,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"db3463b8998634a487878c02c81b31eb196077dc45ac102de56f6f06a7bd26ee"}
|
||||
{"label":"import-133","command":["timeout","-k","10","900","node","--test","packages/cli/tests/git-socket.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gcHM","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":27.936,"mutant":false,"tests":24,"pass":24,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"c1a6247751b05dcaad81d9a42e93c923200f2971ef17622924d00a07c8292735"}
|
||||
{"label":"import-134","command":["timeout","-k","10","900","node","--test","packages/cli/tests/grants-scope.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gRr9","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.298,"mutant":false,"tests":4,"pass":4,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"2f9222ce2ac41443cb24c69bffea46fd96c53af469670f642dcc2319d162ffc5"}
|
||||
{"label":"import-135","command":["timeout","-k","10","900","node","--test","packages/cli/tests/grants.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gbr2","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.418,"mutant":false,"tests":6,"pass":6,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"018fba785221ec997b369739f1fa39ff927f7144b6276f071338a64ba331e555"}
|
||||
{"label":"import-136","command":["timeout","-k","10","900","node","--test","packages/cli/tests/host.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gIQc","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":20.522,"mutant":false,"tests":43,"pass":43,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"98d2bb8ac91e143fd16fb02b29d877b2df4397a1d8857687707d0bfebb3459be"}
|
||||
{"label":"import-137","command":["timeout","-k","10","900","node","--test","packages/cli/tests/hosts.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gB9t","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.5,"mutant":false,"tests":8,"pass":8,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"376d8a698c39bc25b9e43ee63f762718ab2d2d2dbfab36da61971e3982f98353"}
|
||||
{"label":"import-138","command":["timeout","-k","10","900","node","--test","packages/cli/tests/idle-stop-race.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gt4N","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":2.246,"mutant":false,"tests":1,"pass":1,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"4ee49db59177a6cedcc98642ad2b4215e1489c8720e3ab27c88a1d3513b4384f"}
|
||||
{"label":"import-139","command":["timeout","-k","10","900","node","--test","packages/cli/tests/instances.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/ga2n","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":4.158,"mutant":false,"tests":15,"pass":15,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"125780e39af442913bf056f71a57b663c954d8eb5a96fb245db8063237ccb1e1"}
|
||||
{"label":"import-140","command":["timeout","-k","10","900","node","--test","packages/cli/tests/launch-account.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gEgp","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.427,"mutant":false,"tests":7,"pass":7,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"1a2de9540358023f6acb51ab8cdfe0f56e21331cca06ecef672fe7e9b1e0b43a"}
|
||||
{"label":"import-141","command":["timeout","-k","10","900","node","--test","packages/cli/tests/launch-limit-checks.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gxqf","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.398,"mutant":false,"tests":5,"pass":5,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"027fb83eb3ef68f01fde4e1a272faf569516372f194e3e8404973756f9ffb974"}
|
||||
{"label":"import-142","command":["timeout","-k","10","900","node","--test","packages/cli/tests/launch-limits.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g5N5","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.255,"mutant":false,"tests":1,"pass":1,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"a3c26a3f092d8e7dd96fe1addfcd77b89d726d027e9f988340a1442823644c3c"}
|
||||
{"label":"import-143","command":["timeout","-k","10","900","node","--test","packages/cli/tests/launch-routes.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gMhQ","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.514,"mutant":false,"tests":9,"pass":9,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"ba0335e2efd7de694b51ca89b427ffb06b652f6d9757df1997f9c1c7703ac74a"}
|
||||
{"label":"import-144","command":["timeout","-k","10","900","node","--test","packages/cli/tests/launcher.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gqhv","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":45.769,"mutant":false,"tests":34,"pass":34,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"5e5374884901f29432961198070f3ede2f87fcc41a818423c3cb90c919dfd7d0"}
|
||||
{"label":"import-145","command":["timeout","-k","10","900","node","--test","packages/cli/tests/lifecycle.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g76b","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":16.885,"mutant":false,"tests":24,"pass":24,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"37c3dcc1555bc527fe0f853c1a08bae993bd541143c3b6f7edc360c0c3c26d8d"}
|
||||
{"label":"import-146","command":["timeout","-k","10","900","node","--test","packages/cli/tests/limits-tokens.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g7dV","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.224,"mutant":false,"tests":5,"pass":5,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"6dae4cd3607f44b07df6a5e6764276a2ef152b892f050340d6defd14a83b731e"}
|
||||
{"label":"import-147","command":["timeout","-k","10","900","node","--test","packages/cli/tests/limits.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gLVw","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.442,"mutant":false,"tests":5,"pass":5,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"efe051216bb6347423f556f8951c6b6c4adf9c266d8fde6fedfbebb3e678c17f"}
|
||||
{"label":"import-148","command":["timeout","-k","10","900","node","--test","packages/cli/tests/mark-read.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gVQ4","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.266,"mutant":false,"tests":6,"pass":6,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"b90e024010c9a6fbded17306d01b78b2f5748167f9dd4fee20bc5775ef72de81"}
|
||||
{"label":"import-149","command":["timeout","-k","10","900","node","--test","packages/cli/tests/names.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gJL7","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.297,"mutant":false,"tests":2,"pass":2,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"b8d4005cb4e0f1acbe89bc6427b952459b2b876f54c1ed031a558789b535e87e"}
|
||||
{"label":"import-150","command":["timeout","-k","10","900","node","--test","packages/cli/tests/notifier.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gSos","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.033,"mutant":false,"tests":27,"pass":27,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"c7156a9c99f99c3b51da2c73b728349f348dac6a0b0530bda96212a848014f7c"}
|
||||
{"label":"import-151","command":["timeout","-k","10","900","node","--test","packages/cli/tests/optional-tracker.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/ggn7","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.413,"mutant":false,"tests":4,"pass":4,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"d09457d3034c683bc98639f04d83d5348815571d46d5c30cbe055aed5ceef3a7"}
|
||||
{"label":"import-152","command":["timeout","-k","10","900","node","--test","packages/cli/tests/other-tree.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gclm","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.3,"mutant":false,"tests":4,"pass":4,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"aa7be88cd823a44c8743159006f1d9b61072ebaa04935339d4a875d0997f903e"}
|
||||
{"label":"import-153","command":["timeout","-k","10","900","node","--test","packages/cli/tests/processing-cli.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gvyI","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.367,"mutant":false,"tests":4,"pass":4,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"55d67187192edfd5c929713af6a8f40025259429f36a444eb886fd26013a3135"}
|
||||
{"label":"import-154","command":["timeout","-k","10","900","node","--test","packages/cli/tests/project-name-repo.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g3qR","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.431,"mutant":false,"tests":2,"pass":2,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"9e8364d68d732dbcb9e518ff8dc1cb957d0d254c0a3821711df20e34f6427f07"}
|
||||
{"label":"import-155","command":["timeout","-k","10","900","node","--test","packages/cli/tests/project.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gJK9","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.908,"mutant":false,"tests":4,"pass":4,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"7014e206c70053c2eaeb89fa59b38781802e65d2982fee3855772dd9721285a6"}
|
||||
{"label":"import-156","command":["timeout","-k","10","900","node","--test","packages/cli/tests/publish-socket.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gQ5m","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":11.807,"mutant":false,"tests":9,"pass":9,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"e20a380f9e0e0070d2598bd3ae85679f70f59c92e6f8cf1c7c840a0975c253b7"}
|
||||
{"label":"import-157","command":["timeout","-k","10","900","node","--test","packages/cli/tests/reply-limits.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gR4L","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.167,"mutant":false,"tests":2,"pass":2,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"9339298bbd5ebfb0e033d2b992c69f62c168e124e741bfc0de500c35b8ffc092"}
|
||||
{"label":"import-158","command":["timeout","-k","10","900","node","--test","packages/cli/tests/revoke-window.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gHpa","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.868,"mutant":false,"tests":1,"pass":1,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"774c1211e7dadeab526d34d50b143c1141ee9f85e3799b644734eeb78c8e9b6f"}
|
||||
{"label":"import-159","command":["timeout","-k","10","900","node","--test","packages/cli/tests/session-clear.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gd9q","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":13.609,"mutant":false,"tests":5,"pass":5,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"a47caf45da848c1bf1a8456eb89c213df981229dc0765362573ec82e6701b11c"}
|
||||
{"label":"import-160","command":["timeout","-k","10","900","node","--test","packages/cli/tests/session-cli.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gXLB","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.323,"mutant":false,"tests":14,"pass":14,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"3d260701a0c4afd1d21effb5ca1db6cdb47803281bde2536853926f56a236955"}
|
||||
{"label":"import-161","command":["timeout","-k","10","900","node","--test","packages/cli/tests/session-launch.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gPoX","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":12.34,"mutant":false,"tests":8,"pass":8,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"9d077d5e2956b1f40de6abba79ebed6504cc61a3821754526a032231e8697271"}
|
||||
{"label":"import-162","command":["timeout","-k","10","900","node","--test","packages/cli/tests/stack-copy.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gb3j","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":32.255,"mutant":false,"tests":18,"pass":18,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"a31fda44310b53fcbfbfb5ca037db8bf9209a0235ed951a911358c61c5f4d13b"}
|
||||
{"label":"import-163","command":["timeout","-k","10","900","node","--test","packages/cli/tests/stack-instances.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gVU0","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":5.223,"mutant":false,"tests":24,"pass":24,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"baf388164839b10a5ea8c3e019d6b5095d7951657ee638784701848b69a160cd"}
|
||||
{"label":"import-164","command":["timeout","-k","10","900","node","--test","packages/cli/tests/tester-http.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/geku","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.28,"mutant":false,"tests":2,"pass":2,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"d06f4abf2476d898d85533318fee23bdfe3fdc6012c40e809ae4f21e1d6e74bb"}
|
||||
{"label":"import-165","command":["timeout","-k","10","900","node","--test","packages/cli/tests/tester-reads.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g7PM","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":5.141,"mutant":false,"tests":6,"pass":6,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"2f293f7b23b679733870b5d5d2f666570b56fa1335d5b94590046447433225c8"}
|
||||
{"label":"import-166","command":["timeout","-k","10","900","node","--test","packages/cli/tests/tester-threads.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gAdD","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":12.373,"mutant":false,"tests":5,"pass":5,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"6505ae90432cfcf6c2b74ed4c22ebe6ee1b26055b41f3fdada4e40c54e1124f9"}
|
||||
{"label":"import-167","command":["timeout","-k","10","900","node","--test","packages/cli/tests/tester.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gx0E","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.628,"mutant":false,"tests":11,"pass":11,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"abadf2326205ea5ba1e617fd174018995de824d1552f308815e2bc9c3f71e4bc"}
|
||||
{"label":"import-168","command":["timeout","-k","10","900","node","--test","packages/cli/tests/thread-cli.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gbFa","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":5.076,"mutant":false,"tests":11,"pass":11,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"fc7f5fadded9b52bcebcf80af32a54bfcb85c2a58608e261d839e8c91d473ce4"}
|
||||
{"label":"import-169","command":["timeout","-k","10","900","node","--test","packages/cli/tests/thread-launch.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gQNn","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":36.824,"mutant":false,"tests":15,"pass":15,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"f4052bf907e300dae2a7d44f3e8b370849e879abf1de9f84e0c74138f41f2640"}
|
||||
{"label":"import-170","command":["timeout","-k","10","900","node","--test","packages/cli/tests/thread-revoke.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gNtT","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.273,"mutant":false,"tests":3,"pass":3,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"2f66b678922916e9856a6ade3a4524c420d981f39548a6687df77cb95c660d40"}
|
||||
{"label":"import-171","command":["timeout","-k","10","900","node","--test","packages/cli/tests/trackers-boot.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/giDk","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.097,"mutant":false,"tests":2,"pass":2,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"dbb78cab0545fe2d18089c4510092562aa5bc16cdc3f1f95784719d8e2dda241"}
|
||||
{"label":"import-172","command":["timeout","-k","10","900","node","--test","packages/cli/tests/transport.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g6h3","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":2.447,"mutant":false,"tests":3,"pass":3,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"7b7a41c111670e869d5156d3714a33c7a4e7a675893cff4767c505b658ac0dc8"}
|
||||
{"label":"import-173","command":["timeout","-k","10","900","node","--test","packages/cli/tests/usage.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gERb","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.44,"mutant":false,"tests":2,"pass":2,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"d39ae2e64f3e78a0d4bd7fc8d4c6f8f087ac80f0ba47d5dbd199d627d826e86f"}
|
||||
{"label":"import-174","command":["timeout","-k","10","900","node","--test","packages/cli/tests/verbs.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gaL4","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":3.562,"mutant":false,"tests":9,"pass":9,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"6eafbcea30d6c03a2f8dd925ca6b801fb7f2a8475f3b70715ad8a5060f47f0f0"}
|
||||
{"label":"import-175","command":["timeout","-k","10","900","node","--test","packages/harness/tests/bundle.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g8v2","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.276,"mutant":false,"tests":22,"pass":22,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"232cba86e5cf956c07e7ac3bce916899fd288db2ef252bf33041c54fa29f6e1b"}
|
||||
{"label":"import-176","command":["timeout","-k","10","900","node","--test","packages/harness/tests/citation-runner.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g6h4","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":6.327,"mutant":false,"tests":21,"pass":21,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"ef0a3e5f582524e0f03a3a39b518356af2d180cefcaa64439c828dbfc9ab0555"}
|
||||
{"label":"import-177","command":["timeout","-k","10","900","node","--test","packages/harness/tests/claude-gate.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gmnt","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.62,"mutant":false,"tests":3,"pass":3,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"2b7867d549382bd5943f9f828f7132743abd724b9d6a26f7e7647e5deac1086c"}
|
||||
{"label":"import-178","command":["timeout","-k","10","900","node","--test","packages/harness/tests/claude-session.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gWex","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":8.983,"mutant":false,"tests":10,"pass":10,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"e97d2c71fb63346d736d85b37e1bae38708041a7e09b15cc5d64f44d5f87e592"}
|
||||
{"label":"import-179","command":["timeout","-k","10","900","node","--test","packages/harness/tests/creative.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g7fD","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.349,"mutant":false,"tests":7,"pass":7,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"0a08749c464113ccbc5207cc63ad3cb33ccd7d7af3ebdcb614106f14a38fa8af"}
|
||||
{"label":"import-180","command":["timeout","-k","10","900","node","--test","packages/harness/tests/gate.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gLqE","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.177,"mutant":false,"tests":12,"pass":12,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"8d3cf0837ecb7d8c5be2a02c67fbe1fb1fbf0a7d75b8e79029a6a3530870353f"}
|
||||
{"label":"import-181","command":["timeout","-k","10","900","node","--test","packages/harness/tests/git-tools.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gcPM","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":2.824,"mutant":false,"tests":5,"pass":5,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"170299b738f35a5cbce8336dbf37ddd340045c9f12b0d86716dc9764ce692656"}
|
||||
{"label":"import-183","command":["timeout","-k","10","900","node","--test","packages/harness/tests/mcp-server.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gruQ","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.352,"mutant":false,"tests":5,"pass":5,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"fcbb8ff07441b7458fad73e8f0d2e8c81a37a184244403c46f0db51bcb579d6c"}
|
||||
{"label":"import-184","command":["timeout","-k","10","900","node","--test","packages/harness/tests/pi-session.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gQR8","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":7.664,"mutant":false,"tests":10,"pass":10,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"21ef864f6c0608e398001beed596c711eaa16df9830be6e9948d23adaf7ae19b"}
|
||||
{"label":"import-185","command":["timeout","-k","10","900","node","--test","packages/harness/tests/raise-domain.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gkno","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.289,"mutant":false,"tests":2,"pass":2,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"258b03d95708255aaf9c53af130e80349d3fb7a15c412f5e99a552d38d273cf4"}
|
||||
{"label":"import-186","command":["timeout","-k","10","900","node","--test","packages/harness/tests/runner.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gHpN","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":14.264,"mutant":false,"tests":40,"pass":40,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"6b2ed91f2cc0af529b15da7dd1ca38fc4f9024b8838f1ae948bb9fb61f52b1d4"}
|
||||
{"label":"import-187","command":["timeout","-k","10","900","node","--test","packages/harness/tests/skills.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/ge6l","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.322,"mutant":false,"tests":10,"pass":10,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"a5eb44bb14feab35f8afff44467dd1ab4b6ccd95f0c20e99bd8165e02ab11e94"}
|
||||
{"label":"import-188","command":["timeout","-k","10","900","node","--test","packages/harness/tests/spec-tools.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gqeF","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.392,"mutant":false,"tests":2,"pass":2,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"25bef2391ffce43b2ad8c6159fb801bf371064b48998f5212b45043b78a65ab4"}
|
||||
{"label":"import-189","command":["timeout","-k","10","900","node","--test","packages/harness/tests/tools.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gh6I","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.254,"mutant":false,"tests":23,"pass":23,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"032cd4df77581f65cc3d1e3487b542cc2568e40461f34cf345c9e3ccf224d2c0"}
|
||||
{"label":"import-190","command":["timeout","-k","10","900","node","--test","packages/library/tests/guard.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gX5T","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.7,"mutant":false,"tests":11,"pass":11,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"c5c5e1daabdcbc4830da5472dc584f3095874effa6ed00a5d752ef5a792f433a"}
|
||||
{"label":"import-191","command":["timeout","-k","10","900","node","--test","packages/library/tests/index-build.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gDCo","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":4.794,"mutant":false,"tests":6,"pass":6,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"6122712a2a10cd4fc7ad0f29e7581dc27e6d1e5daddb92dc3b9831ccd26c06b5"}
|
||||
{"label":"import-192","command":["timeout","-k","10","900","node","--test","packages/library/tests/links.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gNyj","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.128,"mutant":false,"tests":7,"pass":7,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"933818b92437600be0591b784675887f9240915167a6218d9bd5546737c0de1d"}
|
||||
{"label":"import-193","command":["timeout","-k","10","900","node","--test","packages/library/tests/mapping.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gBnG","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.16,"mutant":false,"tests":16,"pass":16,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"b97b350865814827ad8998f9a24ea1f65749b882dd10531eb79052268769f9d0"}
|
||||
{"label":"import-194","command":["timeout","-k","10","900","node","--test","packages/library/tests/mirror.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gfP9","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":6.763,"mutant":false,"tests":16,"pass":16,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"ba91652dd7daa182d771e5f8d093769fa009494d0f4080fd697a423b8c8aff4c"}
|
||||
{"label":"import-196","command":["timeout","-k","10","900","node","--test","packages/library/tests/reader.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gvmz","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.028,"mutant":false,"tests":14,"pass":14,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"5b335d4472ccc9aead596840a67909ccf96270c7ccf88e4ad2141eb5953de74c"}
|
||||
{"label":"import-197","command":["timeout","-k","10","900","node","--test","packages/library/tests/render.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gfUA","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.211,"mutant":false,"tests":9,"pass":9,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"f95a831fa8ef95d90f50861d7ebf05fdedc4d3d68d1ea3dec1e17e9392befab9"}
|
||||
{"label":"import-198","command":["timeout","-k","10","900","node","--test","packages/library/tests/scope.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gxAY","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.368,"mutant":false,"tests":6,"pass":6,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"3935e31b852d0be272395f8d2af9816e8b8ee3bf75a088be39559e413d58fd1e"}
|
||||
{"label":"import-199","command":["timeout","-k","10","900","node","--test","packages/library/tests/supporting.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gT0U","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.25,"mutant":false,"tests":6,"pass":6,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"cfd46a3aaa0167b3adda75bb69095f6328de4cfd43bdb26ae4952e6867c6bf81"}
|
||||
{"label":"import-200","command":["timeout","-k","10","900","node","--test","packages/library/tests/survey.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gQVP","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.764,"mutant":false,"tests":7,"pass":7,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"a20f9ea4cd570def995d73d389f0610621f0198499e60c8f27ada2e952b22bb8"}
|
||||
{"label":"import-201","command":["timeout","-k","10","900","node","--test","packages/library/tests/sync.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gGSr","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":6.838,"mutant":false,"tests":24,"pass":24,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"683e7b2ec581c2d72a6a3edc68913a7092a49c3ac5c15fe9dfa3062fc3d59fe9"}
|
||||
{"label":"import-202","command":["timeout","-k","10","900","node","--test","packages/processing-control/tests/task.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gAOM","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.776,"mutant":false,"tests":7,"pass":7,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"a9c5e79fa8bddcd222359c6b5fb5634ad170ad56babfe3971f22d8f1fbcaceb9"}
|
||||
{"label":"import-203","command":["timeout","-k","10","900","node","--test","packages/seat/tests/sandbox.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gcfc","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":7.076,"mutant":false,"tests":10,"pass":10,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"9d9e237b00482d14c1173fcdf2ba0770d87c2e77e0a2d7f8b3631531d1fa5da2"}
|
||||
{"label":"import-204","command":["timeout","-k","10","900","node","--test","packages/seat/tests/session.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gpBq","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.478,"mutant":false,"tests":13,"pass":13,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"2ffb0ee5961f4611d6afde99fd99270dee783b7abde51c9038ee2087dc426c22"}
|
||||
{"label":"import-205","command":["timeout","-k","10","900","node","--test","packages/tasks/tests/adapter.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/guN4","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.512,"mutant":false,"tests":8,"pass":8,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"b0441401e2ab0e9593e6d55cca661366e7ee8b51850ac934bfca23de45d2a35a"}
|
||||
{"label":"import-206","command":["timeout","-k","10","900","node","--test","packages/tasks/tests/comment-restart.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gyAw","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.45,"mutant":false,"tests":5,"pass":5,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"599ad621c9d89dc1f200ad0e87eb1573e5ae7bfcc6ff9cddb9048855a9f8613f"}
|
||||
{"label":"import-207","command":["timeout","-k","10","900","node","--test","packages/tasks/tests/fields.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gOij","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.617,"mutant":false,"tests":5,"pass":5,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"2d83b920f5f716537a69555f6bead6b99be1b3c64751305ec8de1a71cadeb56f"}
|
||||
{"label":"import-208","command":["timeout","-k","10","900","node","--test","packages/tasks/tests/processing.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g72u","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.32,"mutant":false,"tests":3,"pass":3,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"5d740844a654055345b9e7c69ed4d2a247cd932ad2a5a6fcf329c7801cbd0ad7"}
|
||||
{"label":"import-209","command":["timeout","-k","10","900","node","--test","packages/tasks/tests/shapes.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gJAm","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.518,"mutant":false,"tests":4,"pass":4,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"3811bcc866161d152d9460cb8bfef2faa9cd3e533de96f1b3f014403dd7fb51e"}
|
||||
{"label":"import-210","command":["timeout","-k","10","900","node","--test","packages/tasks/tests/startup.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gGTN","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.541,"mutant":false,"tests":9,"pass":9,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"b2c08b276e60a676346a7a7a96423939fc50fece24e84f7d31a141414ae9c65e"}
|
||||
{"label":"import-211","command":["timeout","-k","10","900","node","--test","packages/tasks/tests/sync.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gccq","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.994,"mutant":false,"tests":11,"pass":11,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"7521b57b037d5dfd35e4e7f8b3e0f772e6f09e9a7f218eaa55a95b40798fb3cb"}
|
||||
{"label":"import-212","command":["timeout","-k","10","900","node","--test","packages/tasks/tests/tree.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gKai","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.129,"mutant":false,"tests":19,"pass":19,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"035eba7993242c2797c236e2c7f5d41f9248d872984cbfd785bb596bd323721f"}
|
||||
{"label":"import-213","command":["timeout","-k","10","900","node","--test","packages/tasks/tests/verbs.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gcgn","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.767,"mutant":false,"tests":31,"pass":31,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"27cd7e0bb4607ec39ededdc89e4afcb363698eee6dd31ddd5d5a6b2cbabd847b"}
|
||||
{"label":"import-214","command":["timeout","-k","10","900","node","--test","packages/webui/tests/agents-browser.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gtNR","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":17.433,"mutant":false,"tests":2,"pass":2,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"e2c213130dbf80c125011ba8d45c016bfb347ebe1d21f1c64d1756e0db82d6f9"}
|
||||
{"label":"import-215","command":["timeout","-k","10","900","node","--test","packages/webui/tests/agents.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gQRO","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.233,"mutant":false,"tests":9,"pass":9,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"c94baa2f42b463dee93e00cf1f3b1e60b287f109debf3a5a5133a8363b992d3a"}
|
||||
{"label":"import-216","command":["timeout","-k","10","900","node","--test","packages/webui/tests/assistant.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gCyc","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.233,"mutant":false,"tests":6,"pass":6,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"1a32bdca8137c6aff24e9eee5c19dcadfef1e3a5f0aab5a45c600cf39c29e56e"}
|
||||
{"label":"import-217","command":["timeout","-k","10","900","node","--test","packages/webui/tests/board-held.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gPDU","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":10.78,"mutant":false,"tests":3,"pass":3,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"fb532481a6401e7097d1b7fd8c858885988e37529779c7e989885dd0de21f7e9"}
|
||||
{"label":"import-218","command":["timeout","-k","10","900","node","--test","packages/webui/tests/browser-edge.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gw0B","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.748,"mutant":false,"tests":1,"pass":1,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"f23507b59a89ff056564e71cda5e73b275ebc4de3130956b9cf69615af5aebe0"}
|
||||
{"label":"import-219","command":["timeout","-k","10","900","node","--test","packages/webui/tests/browser.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gZfS","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":2.398,"mutant":false,"tests":1,"pass":1,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"08f605ea6cfe1ec7b0f9d1a951a359e2e0106892dc56567152ed569548bff757"}
|
||||
{"label":"import-220","command":["timeout","-k","10","900","node","--test","packages/webui/tests/bus-browser.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gjO2","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":3.795,"mutant":false,"tests":2,"pass":2,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"c03e5eaab52ea76d3b5ac1ccfbae6c25a2fab9f592aa45cd29bc6e22f3f45c3f"}
|
||||
{"label":"import-221","command":["timeout","-k","10","900","node","--test","packages/webui/tests/bus.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g766","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":4.937,"mutant":false,"tests":10,"pass":10,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"703208aaab3751971784b6266b335c54f41048735650e92f40b6e8bd37ea9a6a"}
|
||||
{"label":"import-222","command":["timeout","-k","10","900","node","--test","packages/webui/tests/channel-chat.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gyou","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.526,"mutant":false,"tests":3,"pass":3,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"9dd425b57cb427c25265f7e1b4266cc9d9d09892d2de5ddf4c916635b66515c1"}
|
||||
{"label":"import-223","command":["timeout","-k","10","900","node","--test","packages/webui/tests/chat-browser.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g5ri","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":40.593,"mutant":false,"tests":19,"pass":19,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"4a751781c8e1b9c4e1bbe9e1767d5d897c3cbb09ac4db39ea25d13c276e947cd"}
|
||||
{"label":"import-224","command":["timeout","-k","10","900","node","--test","packages/webui/tests/chat-instances.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gypj","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.248,"mutant":false,"tests":4,"pass":4,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"c43f61b93bbf092d23c0bfe9c6e85b76e4ded17b18d973c4a37832764df71f72"}
|
||||
{"label":"import-225","command":["timeout","-k","10","900","node","--test","packages/webui/tests/chat-replies-browser.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gDNY","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":8.751,"mutant":false,"tests":11,"pass":11,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"f919fe31839c0bc40d4860c4f4412480a1016267c00b292fead32b36098031d5"}
|
||||
{"label":"import-226","command":["timeout","-k","10","900","node","--test","packages/webui/tests/chat-sessions-access.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g9LK","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":4.741,"mutant":false,"tests":7,"pass":7,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"a4c4116cfd2a752d7efd2897430a9b2b052b6acf868c1ca8ce26b81ba9585812"}
|
||||
{"label":"import-227","command":["timeout","-k","10","900","node","--test","packages/webui/tests/chat.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/go2w","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.849,"mutant":false,"tests":30,"pass":30,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"77d6c675d0a4534e84f4b2ce4eddf2135908dc5014469e74b87b6fdd3f63c130"}
|
||||
{"label":"import-228","command":["timeout","-k","10","900","node","--test","packages/webui/tests/conversation.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/ga85","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":4.852,"mutant":false,"tests":4,"pass":4,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"35d962e50a5a143e4dd8b816414c3044096d8907e807f50ca72eef81df9531ee"}
|
||||
{"label":"import-229","command":["timeout","-k","10","900","node","--test","packages/webui/tests/decide-browser.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gd1n","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":12.017,"mutant":false,"tests":3,"pass":3,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"559586deeaa79f7f28185318bf29e7ea28b4536c60bddbfdcdd337850104820a"}
|
||||
{"label":"import-230","command":["timeout","-k","10","900","node","--test","packages/webui/tests/decide-sso.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gTYk","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.998,"mutant":false,"tests":5,"pass":5,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"f277b7937f563610c111f75d55917ba1a6474b0cbf7edcc417f66ca1db9e77a8"}
|
||||
{"label":"import-231","command":["timeout","-k","10","900","node","--test","packages/webui/tests/decision-http.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gesP","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.149,"mutant":false,"tests":9,"pass":9,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"1ae4314867f3da3d96bb8bd99bb9e4bb120610e4b4f76f266a4394d2c4cdac3d"}
|
||||
{"label":"import-232","command":["timeout","-k","10","900","node","--test","packages/webui/tests/discord.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gROh","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.126,"mutant":false,"tests":1,"pass":1,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"d1da3a8a99ae68e4e2c704b993c9f4fac1502f60dc21502abadad75584e212f1"}
|
||||
{"label":"import-233","command":["timeout","-k","10","900","node","--test","packages/webui/tests/docs-browser.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gZtM","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.892,"mutant":false,"tests":1,"pass":1,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"b126c48278cbe8276b5a1459b14cf00d1047ec686a80a82dfe509169e4d8aa7c"}
|
||||
{"label":"import-234","command":["timeout","-k","10","900","node","--test","packages/webui/tests/editor-browser.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gJnO","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":23.444,"mutant":false,"tests":16,"pass":16,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"1053f032713f4a82d05003347cb02c6db54f6c554d3d549608615e3dcc835c83"}
|
||||
{"label":"import-235","command":["timeout","-k","10","900","node","--test","packages/webui/tests/editor.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gLje","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":6.017,"mutant":false,"tests":5,"pass":5,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"a1b78738684b0e0049cc5731f55b67cc21d83c0bd117a20ee094efcefbc926b9"}
|
||||
{"label":"import-236","command":["timeout","-k","10","900","node","--test","packages/webui/tests/granted-user.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gH8T","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":6.001,"mutant":false,"tests":19,"pass":19,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"7e778058c0b4dfc5a44b1c95d146e3628f1401f18e5ca68d0eb5a2af2357fe16"}
|
||||
{"label":"import-237","command":["timeout","-k","10","900","node","--test","packages/webui/tests/history-return-flow.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gOZs","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":56.725,"mutant":false,"tests":1,"pass":1,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"1e74c166baa23c019edac72a0ce2735e7804112369ef6f6d12b4b30e0ed1a7a1"}
|
||||
{"label":"import-238","command":["timeout","-k","10","900","node","--test","packages/webui/tests/instances-browser.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/goix","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":3.608,"mutant":false,"tests":1,"pass":1,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"20da30c92fc5b9149e84cd2547aceac366f5509e8efbeb346b700d6f8cacc18b"}
|
||||
{"label":"import-239","command":["timeout","-k","10","900","node","--test","packages/webui/tests/instances.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gr2y","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.265,"mutant":false,"tests":5,"pass":5,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"0b0782580df886f98f4428ad6f94d33fa2d37d89c58d12c152964b26786d48fe"}
|
||||
{"label":"import-240","command":["timeout","-k","10","900","node","--test","packages/webui/tests/library-cli.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gGV8","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.868,"mutant":false,"tests":1,"pass":1,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"1e3617d918b4d7474e1acf9b5ad32732305aa86f8ad3044d488aac21f551cb4e"}
|
||||
{"label":"import-241","command":["timeout","-k","10","900","node","--test","packages/webui/tests/library-routes.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gWxL","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.532,"mutant":false,"tests":13,"pass":13,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"d9729aef19f819e8190e6fdc9dbb1d7c4061f2311598f3785678cc81fbaea30e"}
|
||||
{"label":"import-242","command":["timeout","-k","10","900","node","--test","packages/webui/tests/library-status.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gurC","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.265,"mutant":false,"tests":1,"pass":1,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"99e68ba123769f5df8b60d9d12546d113f9f1f18f27b26a82738f4ac670fc18f"}
|
||||
{"label":"import-243","command":["timeout","-k","10","900","node","--test","packages/webui/tests/limits-browser.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gq0e","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":4.598,"mutant":false,"tests":2,"pass":2,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"4d3b961b33557106779e969bdfb9aa959e01462a521d5368d9e7e560a4bab19b"}
|
||||
{"label":"import-244","command":["timeout","-k","10","900","node","--test","packages/webui/tests/limits-route.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gK8P","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.561,"mutant":false,"tests":4,"pass":4,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"2283f78868a29c6ebf37b0aaabc2fdfd84d0a381b3fd046d27902adf2710bfae"}
|
||||
{"label":"import-245","command":["timeout","-k","10","900","node","--test","packages/webui/tests/messages.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gaaW","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":6.474,"mutant":false,"tests":3,"pass":3,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"c2e137bf0cc8d12832a07cdb1f70f95dd3cc8ce34a500e6b0479f9d94bf4b300"}
|
||||
{"label":"import-246","command":["timeout","-k","10","900","node","--test","packages/webui/tests/pinned-copy.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gG1M","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":7.925,"mutant":false,"tests":10,"pass":10,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"ebeca41fa26f042b9e877ddc3315254a60f98b947fb3eb9ccf098c4d455117b4"}
|
||||
{"label":"import-247","command":["timeout","-k","10","900","node","--test","packages/webui/tests/preview.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gHU1","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.186,"mutant":false,"tests":11,"pass":11,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"4f0064f793bb36dbdf294fe77d67530afc0aea22f01b847aa1d00c3844469119"}
|
||||
{"label":"import-248","command":["timeout","-k","10","900","node","--test","packages/webui/tests/processing-browser.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gkgO","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":8.863,"mutant":false,"tests":9,"pass":9,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"816a885bb9c45578982d7e43326cb77215e8cb29f557aa06e0efc39a26297e05"}
|
||||
{"label":"import-249","command":["timeout","-k","10","900","node","--test","packages/webui/tests/processing.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gMEO","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.36,"mutant":false,"tests":6,"pass":6,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"d0d8b5325152e1919b5838bfd1b83c4551b52d69c60f07d0921eb95af6391222"}
|
||||
{"label":"import-250","command":["timeout","-k","10","900","node","--test","packages/webui/tests/project-file.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g0K1","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.316,"mutant":false,"tests":10,"pass":10,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"52754ce30568e4d818370c3558342ab23d1292a67f692c1ded6a4d4b4121a029"}
|
||||
{"label":"import-251","command":["timeout","-k","10","900","node","--test","packages/webui/tests/project-name-repo.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gRNU","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.132,"mutant":false,"tests":1,"pass":1,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"324df0e70027674e99303723c75b02402d6ae43aefc73192e6c723644952fe98"}
|
||||
{"label":"import-252","command":["timeout","-k","10","900","node","--test","packages/webui/tests/proof-cli.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gUya","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":2.557,"mutant":false,"tests":3,"pass":3,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"9d0379c0dac670ea3b54331afee0d9da9c4c76a9c62315bd7cdf33458708b9b1"}
|
||||
{"label":"import-253","command":["timeout","-k","10","900","node","--test","packages/webui/tests/proof.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gw3P","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.23,"mutant":false,"tests":4,"pass":4,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"4b564ec494d8631518bd5e0a9dafce3492cc3655e90a82f12bc994fb0f48f017"}
|
||||
{"label":"import-254","command":["timeout","-k","10","900","node","--test","packages/webui/tests/reads.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gDRG","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":2.251,"mutant":false,"tests":11,"pass":11,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"acd0a107da0270ad86ea4e75d1af8089f2541e1aa1c1613c10c35f47fcc38dea"}
|
||||
{"label":"import-255","command":["timeout","-k","10","900","node","--test","packages/webui/tests/relaunch.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gDNA","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.062,"mutant":false,"tests":1,"pass":1,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"b717bc82d68a804092878b6f68c73d970519d5dde6d9170a5cc3f417cd108c66"}
|
||||
{"label":"import-256","command":["timeout","-k","10","900","node","--test","packages/webui/tests/return-flow.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/go3N","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":21.066,"mutant":false,"tests":1,"pass":1,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"61fa95c4b8c802668f2b144954e8785c1a5d6e5f8d511646c61ae51abfcf899c"}
|
||||
{"label":"import-257","command":["timeout","-k","10","900","node","--test","packages/webui/tests/room-browser.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/geyH","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":8.015,"mutant":false,"tests":9,"pass":9,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"65cd71916ae9b8b6a8d47a0175d5cca96ed6c3d93d65ea334338cc651c3529e7"}
|
||||
{"label":"import-258","command":["timeout","-k","10","900","node","--test","packages/webui/tests/room-http.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gfgT","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.284,"mutant":false,"tests":7,"pass":7,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"32d8f63c7cbf6a67265e3ebb08eeda185061a94d2674c9e79da3e5ec9348ffaa"}
|
||||
{"label":"import-259","command":["timeout","-k","10","900","node","--test","packages/webui/tests/routes-browser.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gqwx","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":2.226,"mutant":false,"tests":1,"pass":1,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"915d721ef9ebb84e963f021957955ce02a7603a048fde2ba61bd7f87e70137ae"}
|
||||
{"label":"import-260","command":["timeout","-k","10","900","node","--test","packages/webui/tests/routes.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gULI","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.499,"mutant":false,"tests":5,"pass":5,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"f5cb0cbb1428122e4a826ebf11a304123af5e33696dc7c3c6e9a40105a7f59b5"}
|
||||
{"label":"import-261","command":["timeout","-k","10","900","node","--test","packages/webui/tests/send-browser.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gV7T","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":14.209,"mutant":false,"tests":2,"pass":2,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"b76ab6c25710827dc2e6c7231b3aa82259cce1a88174a33f83a45c251ff4e8cf"}
|
||||
{"label":"import-262","command":["timeout","-k","10","900","node","--test","packages/webui/tests/send.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gbPv","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.077,"mutant":false,"tests":13,"pass":13,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"51a759891344d96c63d9d554c0b0a0cb541acca3d3d139170805723a90f83201"}
|
||||
{"label":"import-263","command":["timeout","-k","10","900","node","--test","packages/webui/tests/serve.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g9AU","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.835,"mutant":false,"tests":4,"pass":4,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"38c0c60b3b161bcd2cc3642f551fafd755e7ff57aa3a1f9cfc4329f0333ade9d"}
|
||||
{"label":"import-264","command":["timeout","-k","10","900","node","--test","packages/webui/tests/settings-form.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gp5I","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":5.17,"mutant":false,"tests":5,"pass":5,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"305e2081fd87ffad6bae81ef0ea0a7732f9208a0fcd6ea73c8604de13af86210"}
|
||||
{"label":"import-265","command":["timeout","-k","10","900","node","--test","packages/webui/tests/settings-write.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gQmT","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.2,"mutant":false,"tests":4,"pass":4,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"604a5dfa84401b569a004ca35182684d0aefda4da8a34c833953c15d8047c238"}
|
||||
{"label":"import-266","command":["timeout","-k","10","900","node","--test","packages/webui/tests/shell.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/goIy","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":8.597,"mutant":false,"tests":5,"pass":5,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"aa8226cc8ad92136f875f3a976de37dfc1b0ab30a3c24f2861c34fcd6355d002"}
|
||||
{"label":"import-267","command":["timeout","-k","10","900","node","--test","packages/webui/tests/sso-browser.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gxVE","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":8.875,"mutant":false,"tests":2,"pass":2,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"37b3e8ed9a38b6a66600fee9386b5a414d6179a8630349c6f695075c1fb29806"}
|
||||
{"label":"import-268","command":["timeout","-k","10","900","node","--test","packages/webui/tests/sso.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gsiS","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":8.274,"mutant":false,"tests":28,"pass":28,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"2f286ac4644f8789c2ede5261362f4c57bcf02b84671e9b6c2f5c2994368bfbe"}
|
||||
{"label":"import-269","command":["timeout","-k","10","900","node","--test","packages/webui/tests/tester-browser.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g7am","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":4.164,"mutant":false,"tests":2,"pass":2,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"92727a4aee749943dc100d1b843f848ef75bbeeda29d693217882c71368c4d42"}
|
||||
{"label":"import-270","command":["timeout","-k","10","900","node","--test","packages/webui/tests/tester-cli.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gz1T","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":11.668,"mutant":false,"tests":2,"pass":2,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"1c952ee8767467b1d1d4306e566b9b0f863d68215d30ae8ed3ab46d75ef46e8a"}
|
||||
{"label":"import-271","command":["timeout","-k","10","900","node","--test","packages/webui/tests/tester-listener.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g99a","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":2.294,"mutant":false,"tests":11,"pass":11,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"b07648c44f522c5fa789c03634f248f63e8d312e9b93b7edd90d7951145d5419"}
|
||||
{"label":"import-272","command":["timeout","-k","10","900","node","--test","packages/webui/tests/tester-socket.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gbnC","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.19,"mutant":false,"tests":3,"pass":3,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"61704160b72bcd47d1e4166371e3ff65b148b7ef02b785f9427ef133d5ecdfb6"}
|
||||
{"label":"import-273","command":["timeout","-k","10","900","node","--test","packages/webui/tests/thread-claims-browser.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gGv0","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":5.008,"mutant":false,"tests":6,"pass":6,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"9d3d03d3fc2a108a5e1da2c8e153db2a21bc1e08b207698e9c8eb242dff9905a"}
|
||||
{"label":"import-274","command":["timeout","-k","10","900","node","--test","packages/webui/tests/thread-claims.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g09J","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.423,"mutant":false,"tests":4,"pass":4,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"2b031497a6d9d4b18d215d28bc04de28fe26a800c5a7d54af8052aab35eee3be"}
|
||||
{"label":"import-275","command":["timeout","-k","10","900","node","--test","packages/webui/tests/thread-sharing.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gmhU","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":3.736,"mutant":false,"tests":7,"pass":7,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"9f7b307edc31c95fac9ce71f39ea02466a40a6d80c70d9db91f433a07e19adb7"}
|
||||
{"label":"import-276","command":["timeout","-k","10","900","node","--test","packages/webui/tests/usage-browser.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/g1rW","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":1.032,"mutant":false,"tests":1,"pass":1,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"819697b7c5cb3918c007b9fe57dd3f101c79afb9b5656905e5e1e1b0bc82de9f"}
|
||||
{"label":"import-277","command":["timeout","-k","10","900","node","--test","packages/webui/tests/usage.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gHnS","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.238,"mutant":false,"tests":2,"pass":2,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"555da950dacca5dc85db7172b50aaef5e50e726c6e30bb66c770c0c38d58ab76"}
|
||||
{"label":"import-278","command":["timeout","-k","10","900","node","--test","packages/webui/tests/user-option-swap.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gx24","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":0.38,"mutant":false,"tests":1,"pass":1,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"20bcc3985f5808a2d7f8daa02c5438fbac81c5163c117fde07bea3f46e8fa5b3"}
|
||||
{"label":"import-279","command":["timeout","-k","10","900","node","--test","packages/webui/tests/views.test.mjs"],"TMPDIR":"/mnt/storage/scratch/tmp/gHJv","start_nice":19,"observed_timeout_nice":19,"exit":0,"seconds":5.483,"mutant":false,"tests":3,"pass":3,"fail":0,"cancelled":0,"skipped":0,"todo":0,"log_sha256":"dd69767c233e8eaeeb85ddaaf274380bbb6df73ec6cc7aaaadc6336053e4ddd8"}
|
||||
```
|
||||
|
||||
Exact mutant edits (temporary only, all restored):
|
||||
|
||||
```text
|
||||
{"mutant":"M1","edits":[["const SCOPES = Object.freeze(['canon', 'playground', 'supporting']);","const SCOPES = Object.freeze(['canon', 'playground']);"]],"path":"packages/library/src/query.mjs","oracle":"supporting find/search/get","killed":true,"restored_clean":true}
|
||||
{"mutant":"M2","edits":[["file.scope !== requestedScope || ",""]],"path":"packages/library/src/query.mjs","oracle":"get without scope returns null","killed":true,"restored_clean":true}
|
||||
{"mutant":"M3","edits":[["import { listTree } from './reader.mjs';","import { listTree, headCommit } from './reader.mjs';"],["listTree(source.repo, index.commit)","listTree(source.repo, await headCommit(source.repo))"]],"path":"packages/library/src/query.mjs","oracle":"each get blob equals its served tree object","killed":true,"restored_clean":true}
|
||||
{"mutant":"M4","edits":[["}).sort((a, b) => SCOPE_RANK[index.files.get(a.path).scope] - SCOPE_RANK[index.files.get(b.path).scope]);","});"]],"path":"packages/library/src/query.mjs","oracle":"full outgoing and incoming links stay in scope order","killed":true,"restored_clean":true}
|
||||
{"mutant":"M5","edits":[["return other !== undefined && sees(index.mapping, universe, other);","return other !== undefined && other.scope === requestedScope && sees(index.mapping, universe, other);"]],"path":"packages/library/src/query.mjs","oracle":"full outgoing and incoming links stay in scope order","killed":true,"restored_clean":true}
|
||||
{"mutant":"M6","edits":[["file.scope === scope && sees(index.mapping, universe, file)","file.scope === scope"],["other !== undefined && sees(index.mapping, universe, other)","other !== undefined"]],"path":"packages/library/src/query.mjs","oracle":"full outgoing and incoming links stay in scope order","killed":true,"restored_clean":true}
|
||||
{"mutant":"M7","edits":[["scopeArg(scope, MANUSCRIPT_SCOPES)","scopeArg(scope, SCOPES)"]],"path":"packages/library/src/query.mjs","oracle":"manuscript still refuses supporting","killed":true,"restored_clean":true}
|
||||
{"mutant":"M8","edits":[["'library.get': { method: 'get', fields: ['universe', 'path', 'scope', 'from', 'links_from']","'library.get': { method: 'get', fields: ['universe', 'path', 'from', 'links_from']"]],"path":"packages/bus/src/broker.mjs","oracle":"broker forwards supporting scope","killed":true,"restored_clean":true}
|
||||
{"mutant":"M9","edits":[["const manuscriptScope = str(\"canon by default; playground is opt-in\", { enum: [\"canon\", \"playground\"] });","const manuscriptScope = str(\"canon by default; playground is opt-in\", { enum: [\"canon\", \"playground\", \"supporting\"] });"]],"path":"packages/harness/src/tools.mjs","oracle":"scope schemas expand only find/search/get","killed":true,"restored_clean":true}
|
||||
```
|
||||
|
||||
Sweep summary:
|
||||
|
||||
```text
|
||||
{
|
||||
"root_count": 289,
|
||||
"matches": []
|
||||
}
|
||||
```
|
||||
|
||||
## sage-4310 — row329 landed-base rebase, 2026-10-24
|
||||
|
||||
Branch della/row284-r4 rebased the six commits in 95d4991d2..315e9c84f
|
||||
onto origin/refactor 9e2689dffb24c9881724b67db982bc87d527157f. Old branch
|
||||
della/row284-r2 and its crash handoff remain unchanged. No conflict hunks
|
||||
occurred: Git replayed all six commits automatically; range-diff marks all
|
||||
six patches equal. Thus no manual conflict resolution was required.
|
||||
|
||||
Inspected broker.mjs against the new base: the sole row284 delta adds scope
|
||||
to library.get fields. Row329 proxy verbs and all other base broker code
|
||||
are retained unchanged. No optimization or review-note behavior change added.
|
||||
|
||||
The new eight-path seal is stored outside Git in
|
||||
/mnt/storage/scratch/della-row284-r2-evidence/manifest-r4.txt with sibling
|
||||
manifest-r4.blobs.txt and range-diff-r4.txt. Base, final candidate tip and
|
||||
manifest digest are in seal-r4.txt beside them (avoids a self-referential
|
||||
BUILD hash). Prior test/mutant results above apply to the prior base only;
|
||||
no test, mutant, Node, syntax check, dependency install or queue command
|
||||
was run for this rebase. Explicit sage-4310 authorizes this untested push.
|
||||
Worker runs and Sage landing gate wait for CLEAR after Webby delta review.
|
||||
@@ -0,0 +1,193 @@
|
||||
# Row214 C2-11a work record
|
||||
|
||||
Assignment sage-2794 at2026-10-22T16:33:20Z, Q220/mos-1301, issue#1715.
|
||||
New isolated branch herb/row214 on aca16404c. The earlier197/215 worktrees
|
||||
and their dirty/untracked historical packets are untouched. node_modules is
|
||||
the required plain symlink to /mnt/storage/src/mosaic-stack/node_modules.
|
||||
|
||||
Read C2-11a in both pinned briefs. The section is unchanged at51cc0445c;
|
||||
Q222 changes C2-06's reply-limit settings, not wikilinks. The editor model,
|
||||
entry, view, existing model/browser/provenance tests, build/toolchain and
|
||||
vendored markdown parser/serializer were read. No third_party source changes.
|
||||
|
||||
## Static finding and authored work
|
||||
|
||||
model.mjs stores a canonical sig and the raw original block, and serialise
|
||||
returns raw when the sig matches. The vendored text writer escapes brackets
|
||||
(to_markdown.ts:433-437). It is therefore possible for no-edit round-trips
|
||||
to pass while dirty-block output escapes a wikilink. This is a source-based
|
||||
hypothesis, not a measured result. Both outcomes are in DESIGN.md.
|
||||
|
||||
Authored, unrun: the pinned-bundle measurement; ten fixture round-trips;
|
||||
three browser regressions; inert wikilink schema/tokenizer/serializer. The
|
||||
schema includes headings, and front matter remains raw. The serializer
|
||||
validates its spelling before bypassing escaping. HTML/entity-like targets
|
||||
stay text under the existing escaping rules. No clicking or resolution.
|
||||
|
||||
Local static git diff --check is clean. No Node, npm, compiler, browser,
|
||||
measurement, test, Docker, HTTPS Git or push has run. The queue claim waits
|
||||
for a gap because scripts/mosaic invokes Node. No candidate or pass claim.
|
||||
Only design/path documents may be committed before the granted red/green
|
||||
checks; product, tests and measurement remain uncommitted until validated.
|
||||
|
||||
## Next granted steps
|
||||
|
||||
1. Claim from canonical during a CLEAR/gap.
|
||||
2. Run measure.mjs against aca16404c's pinned Git blobs; save JSON unchanged.
|
||||
3. Run the structural/edit regression alone on the baseline bundle (red).
|
||||
4. Install the already-pinned esbuild0.28.2 in this worktree's packages/webui
|
||||
with npm ci --ignore-scripts --no-audit --no-fund; no root install or lock edit.
|
||||
5. Build with the existing editor/build.mjs, then the whole new test file and
|
||||
existing editor, editor-browser and editor-provenance files, each singly.
|
||||
6. Kill the serializer-removal mutant, restore, rebuild, focused green.
|
||||
7. Commit only after the applicable checks, push only when Sage clears HTTPS
|
||||
Git, send Filbert and Mos the candidate SHA/hash manifest directly, cc Sage.
|
||||
8. After253 lands, new branch on its tip preserving all landed changes.
|
||||
9. Filbert and Sage's whole webui and scripts gate finish the row.
|
||||
|
||||
All runs wait for explicit Sage CLEAR. Gander's row253 run5 owns the slot.
|
||||
The whole suite gate and any unexpected failure use mos-0823's stop rule.
|
||||
|
||||
Proposed SESSIONS text for Sage's post-253 doc sweep (do not append here):
|
||||
2026-10-22 | Herb (gpt-6.1-sol, f6cf4287) | row214 C2-11a editor wikilinks authoring | On herb/row214 at aca16404c, authored baseline round-trip measurement, designs for equal/unequal results, inert inline node and regression tests under sage-2794/Q220. Claim, runs and pushes held while253 owns the slot; measurement and test results unavailable.
|
||||
|
||||
## Filbert static design/path review accepted, R1 and R2 required
|
||||
|
||||
Review at2026-10-22T16:43:35Z read dee9f3d8d's packet only, no product or
|
||||
runs. R1 is now in the plan: set MOSAIC_REQUIRE_EDITOR_BUILD=1 on focused
|
||||
provenance and whole webui runs, grep ^# skip plus TAP/spec skip directives,
|
||||
and name every skip. Missing/wrong pinned esbuild must fail, not skip.
|
||||
R2: baseline no-edit roundTrips are expected to pass. They test retention
|
||||
of raw bytes and are not red evidence for the node. Only the baseline
|
||||
same-block structural/edit regression is expected red.
|
||||
|
||||
Two added fixtures cover a reference-definition collision and an atom
|
||||
inside ordinary link text, taking the planned file to10 no-edit tests and
|
||||
3 browser tests. The explicit & exclusion preserves the existing escaped
|
||||
HTML/entity writer for dirty blocks; Q&A stays text and is a known limit.
|
||||
Measurement VM setup matches loadEditor. Browser TMPDIR must use the short
|
||||
non-/tmp scratch root. Sweep Node/Chromium after mutant/timeout and at clear.
|
||||
All remain authored and unrun while253 owns the slot.
|
||||
|
||||
Filbert follow-up at2026-10-22T16:45:34Z: the authored N3 browser fixture
|
||||
now explicitly asserts the separate reference-definition block ends in its
|
||||
original exact bytes after the same-block edit. This test change is unrun
|
||||
and uncommitted with the other product/test authoring, pending CLEAR.
|
||||
|
||||
## R2 restart on current refactor, sage-4164
|
||||
|
||||
New worktree: /home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2.
|
||||
Branch herb/row214-r2, base487500a16f4ab5902c318509fdec6acc56a543ca.
|
||||
Carried dee9f3d8d and e2710e92a as67ac3c25a andde42a59d4. Copied only
|
||||
Herb's local model, new editor test/helper, measure.mjs and pending BUILD
|
||||
note. The old worktree remains untouched. No stash or force push.
|
||||
|
||||
The current editor model/build/toolchain/BUILD.json/shipped bundle and
|
||||
loader are identical to the old base. Entry/view and package dependencies
|
||||
are unchanged. The current test fixture adds configDirectory:root; its
|
||||
landed change is retained. The C2-11a brief section is unchanged. The
|
||||
visual-mode condition now lives at public/bus.js:1054. No product behavior
|
||||
beyond the accepted inert inline node is added by the rebase.
|
||||
|
||||
Row266 overlap: none. Our paths do not touch chat*.mjs, chat.js or chat.css,
|
||||
and the intersection with origin/fethry/row266's actual diff is empty.
|
||||
HASH-PINS.json records that ref's SHA and merge base.
|
||||
|
||||
Hash audit: grepped packages/*/tests for each actual/planned changed file
|
||||
and filename, and scanned495 test/fixture files for literal prior SHA256
|
||||
or Git-blob pins. No such pins found. Existing editor-provenance checks
|
||||
read BUILD.json dynamically; regenerating it and the bundle is required.
|
||||
The loader and browser/route tests use editor.js but pin no source hash.
|
||||
No tests or pin asserts were weakened. The complete references and planned
|
||||
generated paths are in HASH-PINS.json.
|
||||
|
||||
Sage-4164 explicitly permits the unrun node/tests to be committed now. This
|
||||
supersedes the earlier packet's instruction to keep them uncommitted until
|
||||
green. Static authoring is not a tested candidate. SOURCE.json records its
|
||||
source hashes and the unbuilt generated-output status. The measurement now
|
||||
pins this current execution base, not the historical accepted-doc base.
|
||||
|
||||
No Node, npm, measurement, compiler, test, browser, Docker or mutant has
|
||||
run. Claim already succeeded at rev3234 on10-22; no new queue move is
|
||||
needed. Push authorization is only herb/row214-r2. Row257's landing gate
|
||||
and then266 own the slot; all execution remains held for Sage's CLEAR.
|
||||
|
||||
Planned focused grant: baseline measurement; the same-block structural
|
||||
red; pinned npm ci/build; whole editor-wikilink.test.mjs (10 no-edit tests
|
||||
with/without a final newline and3 browser tests), editor.test.mjs,
|
||||
editor-browser.test.mjs and editor-provenance.test.mjs singly; one
|
||||
serializer-removal mutant and restored focused green. Set
|
||||
MOSAIC_REQUIRE_EDITOR_BUILD=1 for provenance and the later whole webui
|
||||
gate. Capture all skip names, raw logs, short scratch TMPDIR and final
|
||||
Node/Chromium process sweep. Two failures stop a gate; no rerun after an
|
||||
out-of-row failure without reporting to Sage.
|
||||
|
||||
## Filbert R2 static B1 fixed before execution
|
||||
|
||||
Review at2026-10-24T17:14:55Z confirmed a defect in the authored invalid
|
||||
atom path: state.text alone lacks the text-node override's HTML/entity
|
||||
escaping. Factored that existing policy into escapedText and reused it for
|
||||
invalid atoms. Extended the test payload/assertions to cover both <img and
|
||||
©. Valid atom behavior is unchanged. Excluded backticks from atom
|
||||
recognition and added a text/code precedence fixture for N1.
|
||||
|
||||
Requested focused-grant addition: a second mutant that swaps only the
|
||||
invalid-atom escapedText call for vendored state.text, dropping the <&
|
||||
escape for this path. The existing malformed-attrs browser test must kill
|
||||
it. The original serializer-removal mutant is still required. No runs,
|
||||
checks, installation or rebuild have occurred; all remain held for CLEAR.
|
||||
|
||||
## Granted execution and candidate, sage-4286, 2026-10-24
|
||||
|
||||
Granted lane B until22:40Z. Ran on2ec3f5b5d's source in this worktree.
|
||||
Every child inherited TMPDIR=/mnt/storage/scratch/tmp/g49X, obtained by
|
||||
mktemp -d /mnt/storage/scratch/tmp/gXXX, never /tmp. Each command used
|
||||
`nice -n "$((19 - $(nice)))" timeout -k 10 ...` with pipefail and tee;
|
||||
raw logs record actual absolute nice19 and MOSAIC_REQUIRE_EDITOR_BUILD=1.
|
||||
Node test concurrency was1 for each focused whole file and2 for webui.
|
||||
|
||||
Measurement22:07:22Z: all10 baseline forms round-trip byte for byte. The
|
||||
JSON is copied unchanged to measurement.json. Adopted outcome A: no
|
||||
measured file falls to Source just because of its wikilink. The atom is
|
||||
proved by structure and same-block edits, not no-edit raw retention.
|
||||
Baseline structural case:0/1 expected red, no atom in old shipped bundle.
|
||||
|
||||
Pinned npm ci --ignore-scripts --no-audit --no-fund succeeded locally in
|
||||
packages/webui, then editor/build.mjs ran with esbuild0.28.2. The existing
|
||||
upstream sideEffects warning for mark.ts appeared; no vendored file changed.
|
||||
No package/lockfile change. Rebuild provenance ran and passed, not skipped.
|
||||
|
||||
| Whole file | Pass/fail | Wall seconds |
|
||||
| --- | ---: | ---: |
|
||||
| editor-wikilink.test.mjs | 13/0 | 2.348 |
|
||||
| editor.test.mjs | 5/0 | 2.053 |
|
||||
| editor-browser.test.mjs | 16/0 | 14.984 |
|
||||
| editor-provenance.test.mjs | 6/0 | 0.343 |
|
||||
|
||||
Two mutants, each independently restored and rebuilt: serializer removal
|
||||
failed the structural case0/1, restore1/0; invalid-path escapedText swapped
|
||||
for vendored state.text failed malformed attrs0/1, restore1/0. The model
|
||||
and generated outputs match their original good hashes after both.
|
||||
Post-mutant cwd/temp-root sweep0. Both failures are expected evidence.
|
||||
|
||||
Full webui: exactly69 files,455/0,0 skipped/cancelled,174.189s, ended
|
||||
22:12:48.880975Z. The log contains the required-build env and nice19.
|
||||
Skip scan for ^# skip, TAP # SKIP and spec skipped-test lines found none,
|
||||
so skip names are []. A preliminary command mistakenly selected7 files;
|
||||
its28/0 in17.787s is archived as webui-whole.log and explicitly NOT used
|
||||
as full gate evidence. The corrected69-file run is webui-69.log.
|
||||
|
||||
Final cwd/TMPDIR/argv sweep22:13:17.560692Z:0 processes. No owned Node or
|
||||
Chromium remains. Removed the private TMPDIR only after that zero sweep.
|
||||
Clear was sent to Sage as herb-0102 at22:13:46Z; no further execution.
|
||||
|
||||
Bundle SHA256 bd167899a551c70dc07e500fcdd1853d7fb710b23c217ba5b42daf5785c38a72.
|
||||
CSS SHA2568654ac57d1e7a561110138ecd7f701c34a074017ff8c4cd2768d8083908ee61f,
|
||||
byte-identical to2ec3f5b5d. BUILD.json outputs match those hashes. Source
|
||||
commit a530a60798bf48eb18bb9e225d099faf5c2975cf adds generated outputs and
|
||||
an append-only phase log; packet changes follow separately. No code or
|
||||
assertion changed after these results. The webui gate requirement is met
|
||||
on this tree; Filbert review and every scripts/test-*.sh remain pending.
|
||||
|
||||
Sage re-pinned the brief to case2-rows.md blob85e6fe2e under sage-4286;
|
||||
its C2-11a section is unchanged. No case1-accept file was in any run.
|
||||
@@ -0,0 +1,168 @@
|
||||
# C2-11a: an inert editor wikilink node
|
||||
|
||||
Base: aca16404c. Owner: Herb. Reviewer: Filbert. Issue: #1715.
|
||||
Authority: sage-2794, Q220/mos-1301. The assignment permits authoring the
|
||||
node and tests before the measurement slot. Runs, claim and pushes wait
|
||||
for Sage's CLEAR. After row253 lands, a new branch will carry the change
|
||||
onto its landing with every landed hunk retained.
|
||||
|
||||
## Measurement before choosing the explanation
|
||||
|
||||
Run agents/herb/work/queue-214/measure.mjs only on a granted slot. It loads
|
||||
aca16404c's editor.js and markdown-preview.js directly from local Git
|
||||
objects. It verifies the editor bundle hash against that base's BUILD.json.
|
||||
It cannot accidentally measure a candidate rebuild. Its JSON records the
|
||||
full baseline SHA, bundle hash, timestamp, input, output and equality for
|
||||
each fixture. The first five are the brief's plain, labelled, heading,
|
||||
list and front-matter cases; extra cases cover a heading block, combined
|
||||
heading/label, Unicode/spacing, adjacency and an inert embed. No result is
|
||||
available yet. Static reasoning is not a measurement.
|
||||
|
||||
Outcome A, every baseline round-trip is equal: record that wikilinks do
|
||||
not trigger Source fallback for the measured inputs. Do not claim that
|
||||
bug exists. The source's raw/sig cache explains why an unchanged block can
|
||||
keep its bytes even when its canonical serializer escapes brackets. Add
|
||||
the node for structured wikilinks and dirty-block preservation, as the
|
||||
brief requests. A baseline structural/edit regression must fail even if
|
||||
all unchanged-file checks pass.
|
||||
|
||||
Outcome B, one or more differ: record the exact differing bytes and affected
|
||||
contexts. Keep the existing Source fallback fail-closed. The node restores
|
||||
the required spellings where the block is structured. Retain the same
|
||||
no-edit and dirty-block regressions. If the mismatch comes from a separate
|
||||
block, line-ending or front-matter defect, report it before widening scope.
|
||||
|
||||
## Representation and conversion
|
||||
|
||||
The schema gains one inline atom, wikilink, with a single source attribute.
|
||||
Its source is the complete spelling, not reconstructed target/label parts.
|
||||
It has no href, navigation, fetch or click behavior. A span with data-source
|
||||
and a text child displays the spelling. Heading content includes the new
|
||||
atom; paragraphs, quotes and lists already accept inline content.
|
||||
|
||||
One markdown-it inline rule runs before ordinary links, after escapes and
|
||||
backticks. A sticky match reads a complete single-line [[...]] or ![[...]]
|
||||
without copying every suffix or crossing state.posMax. The node writer
|
||||
writes its validated spelling without bracket escaping, so editing adjacent
|
||||
text cannot rewrite a wikilink. Front matter remains a raw block. No new
|
||||
file-read, save, routing, documentPath or target-resolution behavior is added.
|
||||
|
||||
The accepted atom grammar excludes brackets within the body, line breaks,
|
||||
angle brackets and ampersands. This is an editor representation boundary,
|
||||
not a library resolver or a refusal to open such a file. Malformed,
|
||||
HTML/entity-like and code syntax stays under the existing text/raw rules.
|
||||
This preserves the existing escaping of HTML/entities when a block changes.
|
||||
DOM paste accepts only that same grammar. Invalid attributes constructed
|
||||
programmatically are flattened to one line and escaped by the text writer.
|
||||
No input string is parsed as HTML and embeds never load an image.
|
||||
|
||||
## Acceptance and review
|
||||
|
||||
The measurement JSON goes in BUILD.md and the final manifest packet.
|
||||
Ten fixture round-trips run with and without a final newline. A browser
|
||||
test inspects real ProseMirror atom types and attributes, edits the same
|
||||
block and reparses it, for each fixture. Two more browser tests cover
|
||||
code/escape/malformed/hostile syntax and DOM/programmatic-attribute safety.
|
||||
Tests use the existing fixture and Chromium harness and the shipped bundle.
|
||||
They do not export new production APIs just for testing.
|
||||
|
||||
Before rebuilding, run only the structural regression against the baseline
|
||||
bundle and observe it fail. Rebuild the candidate with the exact pinned
|
||||
esbuild0.28.2 binary, run the whole new test file, existing editor tests,
|
||||
editor browser tests and provenance test. Remove only the wikilink serializer
|
||||
handler for one mutant; the dirty-block assertion must fail. Restore, rebuild
|
||||
and rerun the focused regression. All execution needs Sage's CLEAR, including
|
||||
installation, checks, builds, browser tests and the measurement.
|
||||
|
||||
The checked-in bundle and editor/BUILD.json must be regenerated by the
|
||||
existing build script. No hand edits of generated JavaScript or provenance.
|
||||
The current shared esbuild is0.28.1 and the local webui install is absent.
|
||||
A granted npm ci --ignore-scripts --no-audit --no-fund in packages/webui is
|
||||
needed before building; the root node_modules remains its plain symlink.
|
||||
No dependency or lockfile change is planned.
|
||||
|
||||
Final gate: Filbert approves the manifest, then the whole webui suite and
|
||||
every scripts/test-*.sh on Sage's slot. Two failures stop a gate. A failure
|
||||
outside this row is reported to Sage before any rerun. Source, generated
|
||||
output, mode/hash manifest and raw granted logs identify the candidate.
|
||||
|
||||
## Static review follow-through (Filbert, 2026-10-22T16:43:35Z)
|
||||
|
||||
R1: the focused editor-provenance run and Sage's whole webui gate must set
|
||||
MOSAIC_REQUIRE_EDITOR_BUILD=1. A missing, wrong-version or unpinned binary
|
||||
then fails. Check every log for ^# skip, as well as TAP # SKIP directives
|
||||
and the spec reporter's skipped-test lines; record each skipped name and
|
||||
reason. A skipped rebuild is not proof of bundle reproducibility. The CSS
|
||||
output must stay byte-identical and match BUILD.json.
|
||||
|
||||
R2: no-edit roundTrip checks are expected to pass on the baseline because
|
||||
parse sets sig=canonical and an unchanged serialise returns lead+raw. Their
|
||||
green result is compatibility evidence, never evidence that the atom was
|
||||
needed or installed. The same-block edit/structural regression is the red
|
||||
that proves the new node. The required measurement still runs and is kept.
|
||||
|
||||
N1: bus.js checks visual mode at949 on this base and also requires
|
||||
MosaicMarkdown. The measurement uses the existing helper's bare-window VM
|
||||
shape, markdown-preview.js first, then editor.js, both from pinned Git blobs.
|
||||
|
||||
N2: the exclusion of & and angle brackets is deliberate: the existing
|
||||
text serializer escapes entities/HTML when it rewrites a block for another
|
||||
renderer. An atom's verbatim writer must not bypass that rule, including
|
||||
for pasted/programmatic values. This keeps those targets as ordinary text;
|
||||
[[Q&A]] will still be escaped if its own block changes. It is a known
|
||||
representation limit beyond the five brief cases, not a resolver change.
|
||||
It is included among the text-only cases. Unedited bytes remain intact.
|
||||
|
||||
N3: the reference-definition fixture [[a]] with [a]: u deliberately becomes
|
||||
one inert wikilink rather than a bracket around a reference link. Literal
|
||||
spelling and the separate definition block remain intact.
|
||||
|
||||
N4: [x [[a]]](u) is an explicit fixture. The atom inherits the enclosing
|
||||
ordinary link mark, whose existing target gate still applies. The atom
|
||||
itself supplies no href or new click behavior; the fixture checks its
|
||||
structure and spelling before/after a same-block edit.
|
||||
|
||||
N6: every granted browser/test process gets TMPDIR from
|
||||
mktemp -d /mnt/storage/scratch/tmp/gXXX. Never /tmp. Sweep owned Chromium
|
||||
and Node processes by cwd and the temp-root path after the mutant, after
|
||||
any timeout, and before clearing the slot. Retain/report uncertain owners.
|
||||
|
||||
## R2 current-base check, sage-4164 (2026-10-24)
|
||||
|
||||
The execution base is now487500a16, on herb/row214-r2, not the historical
|
||||
aca16404c above. The two accepted document commits were cherry-picked
|
||||
cleanly. The model, build script, toolchain, BUILD.json, editor.js, view,
|
||||
entry and editor test loader are byte-identical between those bases. The
|
||||
current fixture's new configDirectory isolation is retained; it is not
|
||||
copied from the old worktree. The visual-mode check is now bus.js:1054.
|
||||
The current C2-11a brief section is unchanged. Row266's chat modules,
|
||||
public/chat.js and public/chat.css are outside this row, with no overlap.
|
||||
|
||||
measure.mjs now pins487500a16's Git objects and BUILD.json. The baseline
|
||||
bundle still lacks the atom, and the first executed structural regression
|
||||
will use it before any rebuild. The required measurement, red/green, pinned
|
||||
rebuild, mutant kill and full gate remain unrun and required. Runtime
|
||||
validation is not inferred from the unchanged source or this static check.
|
||||
|
||||
Sage-4164 explicitly authorizes committing the preserved local node/tests
|
||||
on the new branch before execution. The authored source commit is static
|
||||
work, not a green candidate. No Node, npm, rebuild or browser starts until
|
||||
Sage sends CLEAR. HASH-PINS.json records the test-tree audit and row266
|
||||
intersection. The gate still requires MOSAIC_REQUIRE_EDITOR_BUILD=1, a
|
||||
named skip list, whole webui and every scripts/test-*.sh.
|
||||
|
||||
## R2 static follow-up, Filbert B1/N1 (2026-10-24T17:14:55Z)
|
||||
|
||||
B1: state.text(..., true) escapes Markdown punctuation, not HTML/entities.
|
||||
The invalid-atom writer now calls the same escapedText helper as ordinary
|
||||
text nodes, including the <& step. Valid atoms still preserve their source
|
||||
verbatim. The malformed-attribute regression now asserts both an escaped
|
||||
<img and an escaped ©, plus flattened line breaks. A second mutant
|
||||
will replace only the invalid atom's escapedText call with state.text,
|
||||
leaving normal text escaping intact; this browser regression must kill it.
|
||||
This additional mutant needs Sage's grant alongside the serializer-removal
|
||||
mutant. No runtime result is claimed for either.
|
||||
|
||||
N1: backticks are excluded from the atom body, preserving code-span
|
||||
precedence. The text-only fixture includes [[a`]]` and must produce no
|
||||
wikilink atom. All other malformed/HTML/entity boundaries remain as before.
|
||||
@@ -0,0 +1,572 @@
|
||||
{
|
||||
"grant": "sage-4286",
|
||||
"candidateBeforeBuild": "2ec3f5b5ddab0cb5f2716f8164c25861b741213e",
|
||||
"nice": 19,
|
||||
"tmpRoot": "/mnt/storage/scratch/tmp/g49X",
|
||||
"requireEditorBuild": "1",
|
||||
"measurement": {
|
||||
"base": "487500a16f4ab5902c318509fdec6acc56a543ca",
|
||||
"bundleSha256": "9c881b13740fae2408717ad75fa1d85bfcfe3fa8b3af0f1b3f2e706c90e80fee",
|
||||
"measuredAt": "2026-10-24T22:07:22.210Z",
|
||||
"allEqual": true,
|
||||
"results": [
|
||||
{
|
||||
"name": "plain",
|
||||
"input": "[[a]]\n",
|
||||
"output": "[[a]]\n",
|
||||
"equal": true
|
||||
},
|
||||
{
|
||||
"name": "labelled",
|
||||
"input": "[[a|b]]\n",
|
||||
"output": "[[a|b]]\n",
|
||||
"equal": true
|
||||
},
|
||||
{
|
||||
"name": "heading target",
|
||||
"input": "[[a#h]]\n",
|
||||
"output": "[[a#h]]\n",
|
||||
"equal": true
|
||||
},
|
||||
{
|
||||
"name": "list item",
|
||||
"input": "- [[a]]\n",
|
||||
"output": "- [[a]]\n",
|
||||
"equal": true
|
||||
},
|
||||
{
|
||||
"name": "next to front matter",
|
||||
"input": "---\nrelated: \"[[metadata]]\"\n---\n\n[[a]]\n",
|
||||
"output": "---\nrelated: \"[[metadata]]\"\n---\n\n[[a]]\n",
|
||||
"equal": true
|
||||
},
|
||||
{
|
||||
"name": "heading block and combined label",
|
||||
"input": "# See [[a#h|Title]]\n",
|
||||
"output": "# See [[a#h|Title]]\n",
|
||||
"equal": true
|
||||
},
|
||||
{
|
||||
"name": "spaces, Unicode and adjacent links",
|
||||
"input": "See [[ H\u00e9llo there # A heading | a label ]][[next]]\n",
|
||||
"output": "See [[ H\u00e9llo there # A heading | a label ]][[next]]\n",
|
||||
"equal": true
|
||||
},
|
||||
{
|
||||
"name": "reference-definition collision",
|
||||
"input": "[[a]]\n\n[a]: u\n",
|
||||
"output": "[[a]]\n\n[a]: u\n",
|
||||
"equal": true
|
||||
},
|
||||
{
|
||||
"name": "inside an ordinary link",
|
||||
"input": "[x [[a]]](u)\n",
|
||||
"output": "[x [[a]]](u)\n",
|
||||
"equal": true
|
||||
},
|
||||
{
|
||||
"name": "inert embed",
|
||||
"input": "![[cover.png]]\n",
|
||||
"output": "![[cover.png]]\n",
|
||||
"equal": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"results": [
|
||||
{
|
||||
"name": "measurement",
|
||||
"argv": [
|
||||
"node",
|
||||
"agents/herb/work/queue-214/measure.mjs"
|
||||
],
|
||||
"cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2",
|
||||
"rc": 0,
|
||||
"wallSeconds": 0.093,
|
||||
"counts": {},
|
||||
"nice": 19,
|
||||
"tmpRoot": "/mnt/storage/scratch/tmp/g49X",
|
||||
"requireEditorBuild": "1",
|
||||
"timeoutSeconds": 60,
|
||||
"ended": "2026-10-24T22:07:22.215700+00:00"
|
||||
},
|
||||
{
|
||||
"name": "baseline-red",
|
||||
"argv": [
|
||||
"node",
|
||||
"--test",
|
||||
"--test-concurrency=1",
|
||||
"--test-name-pattern=wikilinks are inline atoms and survive",
|
||||
"packages/webui/tests/editor-wikilink.test.mjs"
|
||||
],
|
||||
"cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2",
|
||||
"rc": 1,
|
||||
"wallSeconds": 1.151,
|
||||
"counts": {
|
||||
"tests": 1,
|
||||
"pass": 0,
|
||||
"fail": 1,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"nice": 19,
|
||||
"tmpRoot": "/mnt/storage/scratch/tmp/g49X",
|
||||
"requireEditorBuild": "1",
|
||||
"timeoutSeconds": 180,
|
||||
"ended": "2026-10-24T22:07:27.998436+00:00"
|
||||
},
|
||||
{
|
||||
"name": "npm-ci",
|
||||
"argv": [
|
||||
"npm",
|
||||
"ci",
|
||||
"--ignore-scripts",
|
||||
"--no-audit",
|
||||
"--no-fund"
|
||||
],
|
||||
"cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2/packages/webui",
|
||||
"rc": 0,
|
||||
"wallSeconds": 0.514,
|
||||
"counts": {},
|
||||
"nice": 19,
|
||||
"tmpRoot": "/mnt/storage/scratch/tmp/g49X",
|
||||
"requireEditorBuild": "1",
|
||||
"timeoutSeconds": 240,
|
||||
"ended": "2026-10-24T22:07:41.534116+00:00"
|
||||
},
|
||||
{
|
||||
"name": "build",
|
||||
"argv": [
|
||||
"node",
|
||||
"editor/build.mjs"
|
||||
],
|
||||
"cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2/packages/webui",
|
||||
"rc": 0,
|
||||
"wallSeconds": 0.108,
|
||||
"counts": {},
|
||||
"nice": 19,
|
||||
"tmpRoot": "/mnt/storage/scratch/tmp/g49X",
|
||||
"requireEditorBuild": "1",
|
||||
"timeoutSeconds": 120,
|
||||
"ended": "2026-10-24T22:07:44.654385+00:00"
|
||||
},
|
||||
{
|
||||
"name": "wikilink-green",
|
||||
"argv": [
|
||||
"node",
|
||||
"--test",
|
||||
"--test-concurrency=1",
|
||||
"packages/webui/tests/editor-wikilink.test.mjs"
|
||||
],
|
||||
"cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2",
|
||||
"rc": 0,
|
||||
"wallSeconds": 2.348,
|
||||
"counts": {
|
||||
"tests": 13,
|
||||
"pass": 13,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"nice": 19,
|
||||
"tmpRoot": "/mnt/storage/scratch/tmp/g49X",
|
||||
"requireEditorBuild": "1",
|
||||
"timeoutSeconds": 180,
|
||||
"ended": "2026-10-24T22:07:52.583345+00:00"
|
||||
},
|
||||
{
|
||||
"name": "editor-green",
|
||||
"argv": [
|
||||
"node",
|
||||
"--test",
|
||||
"--test-concurrency=1",
|
||||
"packages/webui/tests/editor.test.mjs"
|
||||
],
|
||||
"cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2",
|
||||
"rc": 0,
|
||||
"wallSeconds": 2.053,
|
||||
"counts": {
|
||||
"tests": 5,
|
||||
"pass": 5,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"nice": 19,
|
||||
"tmpRoot": "/mnt/storage/scratch/tmp/g49X",
|
||||
"requireEditorBuild": "1",
|
||||
"timeoutSeconds": 240,
|
||||
"ended": "2026-10-24T22:07:59.286086+00:00"
|
||||
},
|
||||
{
|
||||
"name": "editor-browser-green",
|
||||
"argv": [
|
||||
"node",
|
||||
"--test",
|
||||
"--test-concurrency=1",
|
||||
"packages/webui/tests/editor-browser.test.mjs"
|
||||
],
|
||||
"cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2",
|
||||
"rc": 0,
|
||||
"wallSeconds": 14.984,
|
||||
"counts": {
|
||||
"tests": 16,
|
||||
"pass": 16,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"nice": 19,
|
||||
"tmpRoot": "/mnt/storage/scratch/tmp/g49X",
|
||||
"requireEditorBuild": "1",
|
||||
"timeoutSeconds": 240,
|
||||
"ended": "2026-10-24T22:08:20.029050+00:00"
|
||||
},
|
||||
{
|
||||
"name": "provenance-green",
|
||||
"argv": [
|
||||
"node",
|
||||
"--test",
|
||||
"--test-concurrency=1",
|
||||
"packages/webui/tests/editor-provenance.test.mjs"
|
||||
],
|
||||
"cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2",
|
||||
"rc": 0,
|
||||
"wallSeconds": 0.343,
|
||||
"counts": {
|
||||
"tests": 6,
|
||||
"pass": 6,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"nice": 19,
|
||||
"tmpRoot": "/mnt/storage/scratch/tmp/g49X",
|
||||
"requireEditorBuild": "1",
|
||||
"timeoutSeconds": 180,
|
||||
"ended": "2026-10-24T22:08:39.003420+00:00"
|
||||
},
|
||||
{
|
||||
"name": "serializer-removal-build",
|
||||
"argv": [
|
||||
"node",
|
||||
"editor/build.mjs"
|
||||
],
|
||||
"cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2/packages/webui",
|
||||
"rc": 0,
|
||||
"wallSeconds": 0.093,
|
||||
"counts": {},
|
||||
"nice": 19,
|
||||
"tmpRoot": "/mnt/storage/scratch/tmp/g49X",
|
||||
"requireEditorBuild": "1",
|
||||
"timeoutSeconds": 90,
|
||||
"ended": "2026-10-24T22:08:51.422097+00:00"
|
||||
},
|
||||
{
|
||||
"name": "serializer-removal-red",
|
||||
"argv": [
|
||||
"node",
|
||||
"--test",
|
||||
"--test-concurrency=1",
|
||||
"--test-name-pattern=wikilinks are inline atoms and survive",
|
||||
"packages/webui/tests/editor-wikilink.test.mjs"
|
||||
],
|
||||
"cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2",
|
||||
"rc": 1,
|
||||
"wallSeconds": 0.887,
|
||||
"counts": {
|
||||
"tests": 1,
|
||||
"pass": 0,
|
||||
"fail": 1,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"nice": 19,
|
||||
"tmpRoot": "/mnt/storage/scratch/tmp/g49X",
|
||||
"requireEditorBuild": "1",
|
||||
"timeoutSeconds": 180,
|
||||
"ended": "2026-10-24T22:08:52.340936+00:00"
|
||||
},
|
||||
{
|
||||
"name": "serializer-removal-restore-build",
|
||||
"argv": [
|
||||
"node",
|
||||
"editor/build.mjs"
|
||||
],
|
||||
"cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2/packages/webui",
|
||||
"rc": 0,
|
||||
"wallSeconds": 0.115,
|
||||
"counts": {},
|
||||
"nice": 19,
|
||||
"tmpRoot": "/mnt/storage/scratch/tmp/g49X",
|
||||
"requireEditorBuild": "1",
|
||||
"timeoutSeconds": 90,
|
||||
"ended": "2026-10-24T22:08:52.498613+00:00"
|
||||
},
|
||||
{
|
||||
"name": "serializer-removal-restore-green",
|
||||
"argv": [
|
||||
"node",
|
||||
"--test",
|
||||
"--test-concurrency=1",
|
||||
"--test-name-pattern=wikilinks are inline atoms and survive",
|
||||
"packages/webui/tests/editor-wikilink.test.mjs"
|
||||
],
|
||||
"cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2",
|
||||
"rc": 0,
|
||||
"wallSeconds": 0.979,
|
||||
"counts": {
|
||||
"tests": 1,
|
||||
"pass": 1,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"nice": 19,
|
||||
"tmpRoot": "/mnt/storage/scratch/tmp/g49X",
|
||||
"requireEditorBuild": "1",
|
||||
"timeoutSeconds": 180,
|
||||
"ended": "2026-10-24T22:08:53.514962+00:00"
|
||||
},
|
||||
{
|
||||
"name": "invalid-escaping-build",
|
||||
"argv": [
|
||||
"node",
|
||||
"editor/build.mjs"
|
||||
],
|
||||
"cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2/packages/webui",
|
||||
"rc": 0,
|
||||
"wallSeconds": 0.102,
|
||||
"counts": {},
|
||||
"nice": 19,
|
||||
"tmpRoot": "/mnt/storage/scratch/tmp/g49X",
|
||||
"requireEditorBuild": "1",
|
||||
"timeoutSeconds": 90,
|
||||
"ended": "2026-10-24T22:08:53.655583+00:00"
|
||||
},
|
||||
{
|
||||
"name": "invalid-escaping-red",
|
||||
"argv": [
|
||||
"node",
|
||||
"--test",
|
||||
"--test-concurrency=1",
|
||||
"--test-name-pattern=wikilink DOM paste accepts",
|
||||
"packages/webui/tests/editor-wikilink.test.mjs"
|
||||
],
|
||||
"cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2",
|
||||
"rc": 1,
|
||||
"wallSeconds": 0.979,
|
||||
"counts": {
|
||||
"tests": 1,
|
||||
"pass": 0,
|
||||
"fail": 1,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"nice": 19,
|
||||
"tmpRoot": "/mnt/storage/scratch/tmp/g49X",
|
||||
"requireEditorBuild": "1",
|
||||
"timeoutSeconds": 180,
|
||||
"ended": "2026-10-24T22:08:54.668225+00:00"
|
||||
},
|
||||
{
|
||||
"name": "invalid-escaping-restore-build",
|
||||
"argv": [
|
||||
"node",
|
||||
"editor/build.mjs"
|
||||
],
|
||||
"cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2/packages/webui",
|
||||
"rc": 0,
|
||||
"wallSeconds": 0.105,
|
||||
"counts": {},
|
||||
"nice": 19,
|
||||
"tmpRoot": "/mnt/storage/scratch/tmp/g49X",
|
||||
"requireEditorBuild": "1",
|
||||
"timeoutSeconds": 90,
|
||||
"ended": "2026-10-24T22:08:54.809629+00:00"
|
||||
},
|
||||
{
|
||||
"name": "invalid-escaping-restore-green",
|
||||
"argv": [
|
||||
"node",
|
||||
"--test",
|
||||
"--test-concurrency=1",
|
||||
"--test-name-pattern=wikilink DOM paste accepts",
|
||||
"packages/webui/tests/editor-wikilink.test.mjs"
|
||||
],
|
||||
"cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2",
|
||||
"rc": 0,
|
||||
"wallSeconds": 0.985,
|
||||
"counts": {
|
||||
"tests": 1,
|
||||
"pass": 1,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"nice": 19,
|
||||
"tmpRoot": "/mnt/storage/scratch/tmp/g49X",
|
||||
"requireEditorBuild": "1",
|
||||
"timeoutSeconds": 180,
|
||||
"ended": "2026-10-24T22:08:55.831793+00:00"
|
||||
},
|
||||
{
|
||||
"name": "webui-whole",
|
||||
"argv": [
|
||||
"node",
|
||||
"--test",
|
||||
"--test-concurrency=2",
|
||||
"tests/agents-browser.test.mjs",
|
||||
"tests/agents.test.mjs",
|
||||
"tests/board-held.test.mjs",
|
||||
"tests/browser-edge.test.mjs",
|
||||
"tests/browser.test.mjs",
|
||||
"tests/bus-browser.test.mjs",
|
||||
"tests/bus.test.mjs"
|
||||
],
|
||||
"cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2/packages/webui",
|
||||
"rc": 0,
|
||||
"wallSeconds": 17.787,
|
||||
"counts": {
|
||||
"tests": 28,
|
||||
"pass": 28,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"nice": 19,
|
||||
"tmpRoot": "/mnt/storage/scratch/tmp/g49X",
|
||||
"requireEditorBuild": "1",
|
||||
"timeoutSeconds": 600,
|
||||
"ended": "2026-10-24T22:09:39.039897+00:00"
|
||||
},
|
||||
{
|
||||
"name": "webui-69",
|
||||
"argv": [
|
||||
"node",
|
||||
"--test",
|
||||
"--test-concurrency=2",
|
||||
"tests/agents-browser.test.mjs",
|
||||
"tests/agents.test.mjs",
|
||||
"tests/assistant.test.mjs",
|
||||
"tests/board-held.test.mjs",
|
||||
"tests/browser-edge.test.mjs",
|
||||
"tests/browser.test.mjs",
|
||||
"tests/bus-browser.test.mjs",
|
||||
"tests/bus.test.mjs",
|
||||
"tests/channel-chat.test.mjs",
|
||||
"tests/chat-browser.test.mjs",
|
||||
"tests/chat-instances.test.mjs",
|
||||
"tests/chat-replies-browser.test.mjs",
|
||||
"tests/chat-sessions-access.test.mjs",
|
||||
"tests/chat.test.mjs",
|
||||
"tests/conversation.test.mjs",
|
||||
"tests/decide-browser.test.mjs",
|
||||
"tests/decide-sso.test.mjs",
|
||||
"tests/decision-http.test.mjs",
|
||||
"tests/discord.test.mjs",
|
||||
"tests/docs-browser.test.mjs",
|
||||
"tests/editor-browser.test.mjs",
|
||||
"tests/editor-provenance.test.mjs",
|
||||
"tests/editor-wikilink.test.mjs",
|
||||
"tests/editor.test.mjs",
|
||||
"tests/granted-user.test.mjs",
|
||||
"tests/history-return-flow.test.mjs",
|
||||
"tests/instances-browser.test.mjs",
|
||||
"tests/instances.test.mjs",
|
||||
"tests/library-cli.test.mjs",
|
||||
"tests/library-routes.test.mjs",
|
||||
"tests/library-status.test.mjs",
|
||||
"tests/limits-browser.test.mjs",
|
||||
"tests/limits-route.test.mjs",
|
||||
"tests/markdown-preview.test.mjs",
|
||||
"tests/messages.test.mjs",
|
||||
"tests/pinned-copy.test.mjs",
|
||||
"tests/preview.test.mjs",
|
||||
"tests/processing-browser.test.mjs",
|
||||
"tests/processing-ui.test.mjs",
|
||||
"tests/processing.test.mjs",
|
||||
"tests/project-file.test.mjs",
|
||||
"tests/project-name-repo.test.mjs",
|
||||
"tests/proof-cli.test.mjs",
|
||||
"tests/proof.test.mjs",
|
||||
"tests/reads.test.mjs",
|
||||
"tests/relaunch.test.mjs",
|
||||
"tests/return-flow.test.mjs",
|
||||
"tests/routes-browser.test.mjs",
|
||||
"tests/routes.test.mjs",
|
||||
"tests/send-browser.test.mjs",
|
||||
"tests/send.test.mjs",
|
||||
"tests/serve.test.mjs",
|
||||
"tests/service.test.mjs",
|
||||
"tests/settings-form.test.mjs",
|
||||
"tests/settings-write.test.mjs",
|
||||
"tests/shell.test.mjs",
|
||||
"tests/sso-browser.test.mjs",
|
||||
"tests/sso.test.mjs",
|
||||
"tests/tester-browser.test.mjs",
|
||||
"tests/tester-cli.test.mjs",
|
||||
"tests/tester-listener.test.mjs",
|
||||
"tests/tester-socket.test.mjs",
|
||||
"tests/thread-claims-browser.test.mjs",
|
||||
"tests/thread-claims.test.mjs",
|
||||
"tests/thread-sharing.test.mjs",
|
||||
"tests/usage-browser.test.mjs",
|
||||
"tests/usage.test.mjs",
|
||||
"tests/user-option-swap.test.mjs",
|
||||
"tests/views.test.mjs"
|
||||
],
|
||||
"cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2/packages/webui",
|
||||
"rc": 0,
|
||||
"wallSeconds": 174.189,
|
||||
"counts": {
|
||||
"tests": 455,
|
||||
"pass": 455,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"nice": 19,
|
||||
"tmpRoot": "/mnt/storage/scratch/tmp/g49X",
|
||||
"requireEditorBuild": "1",
|
||||
"timeoutSeconds": 600,
|
||||
"ended": "2026-10-24T22:12:48.880975+00:00"
|
||||
}
|
||||
],
|
||||
"mutants": [
|
||||
{
|
||||
"name": "serializer-removal",
|
||||
"killed": true,
|
||||
"restored": true,
|
||||
"restoredHashesEqual": true
|
||||
},
|
||||
{
|
||||
"name": "invalid-escaping",
|
||||
"killed": true,
|
||||
"restored": true,
|
||||
"restoredHashesEqual": true
|
||||
}
|
||||
],
|
||||
"skipNames": [],
|
||||
"sweep": {
|
||||
"at": "2026-10-24T22:13:17.560692+00:00",
|
||||
"count": 0,
|
||||
"processes": []
|
||||
},
|
||||
"generated": {
|
||||
"src/public/editor.js": {
|
||||
"sha256": "bd167899a551c70dc07e500fcdd1853d7fb710b23c217ba5b42daf5785c38a72",
|
||||
"bytes": 759959
|
||||
},
|
||||
"src/public/editor.css": {
|
||||
"sha256": "8654ac57d1e7a561110138ecd7f701c34a074017ff8c4cd2768d8083908ee61f",
|
||||
"bytes": 4462
|
||||
}
|
||||
},
|
||||
"unchangedCss": true,
|
||||
"modelRestored": true,
|
||||
"notes": [
|
||||
"webui-whole was an accidental seven-file subset, 28/0, not gate evidence; superseded by webui-69 455/0",
|
||||
"no scripts/test-*.sh ran in this grant; later gate remains pending"
|
||||
],
|
||||
"tmpRemoved": true
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
{
|
||||
"base": "487500a16f4ab5902c318509fdec6acc56a543ca",
|
||||
"testFilesScanned": 495,
|
||||
"plannedPaths": [
|
||||
"packages/webui/editor/model.mjs",
|
||||
"packages/webui/tests/editor-wikilink.test.mjs",
|
||||
"packages/webui/tests/helpers/wikilink-cases.mjs",
|
||||
"agents/herb/work/queue-214/measure.mjs",
|
||||
"agents/herb/work/queue-214/DESIGN.md",
|
||||
"agents/herb/work/queue-214/MANIFEST.md",
|
||||
"agents/herb/work/queue-214/BUILD.md",
|
||||
"packages/webui/src/public/editor.js",
|
||||
"packages/webui/editor/BUILD.json",
|
||||
"agents/herb/work/queue-214/HASH-PINS.json"
|
||||
],
|
||||
"literalPriorBlobPins": [],
|
||||
"pathReferences": [
|
||||
{
|
||||
"test": "packages/webui/tests/editor-wikilink.test.mjs",
|
||||
"line": 6,
|
||||
"text": "import { WIKILINK_CASES } from './helpers/wikilink-cases.mjs';"
|
||||
},
|
||||
{
|
||||
"test": "packages/webui/tests/browser.test.mjs",
|
||||
"line": 21,
|
||||
"text": "// Rows 129, 154, 191, 194 and 294: chat.js, editor.js, processing.js, agents.js and federation.js are the scripts added, same origin; the list is the pin, so another script is a visible change."
|
||||
},
|
||||
{
|
||||
"test": "packages/webui/tests/browser.test.mjs",
|
||||
"line": 22,
|
||||
"text": "assert.deepEqual(await b.evaluate('[...document.querySelectorAll(\"script\")].map(s => s.getAttribute(\"src\"))'), ['/editor.js', '/processing.js', '/federation.js', '/brand.js', '/app.js', '/markdown-preview.js', '/chat.js', '/agents.js', '/bus.js']);"
|
||||
},
|
||||
{
|
||||
"test": "packages/webui/tests/sso.test.mjs",
|
||||
"line": 1,
|
||||
"text": "// Q175 phase 1 (#1690, design agents/sage/work/q175-sso/DESIGN.md section 9): the Console as an"
|
||||
},
|
||||
{
|
||||
"test": "packages/webui/tests/user-option-swap.test.mjs",
|
||||
"line": 133,
|
||||
"text": "['GET', '/app.js'], ['GET', '/bus.js'], ['GET', '/agents.js'], ['GET', '/editor.js'], ['GET', '/shared/app.css'], ['GET', '/index.html'],"
|
||||
},
|
||||
{
|
||||
"test": "packages/webui/tests/serve.test.mjs",
|
||||
"line": 38,
|
||||
"text": "for (const path of ['/', '/app.js', '/brand.js', '/console.css', '/live.css', '/editor.js', '/editor.css', '/shared/app.css', '/assets/fonts/manrope-400.woff2']) {"
|
||||
},
|
||||
{
|
||||
"test": "packages/webui/tests/editor-provenance.test.mjs",
|
||||
"line": 18,
|
||||
"text": "const build = JSON.parse(readFileSync(join(webui, 'editor/BUILD.json'), 'utf8'));"
|
||||
},
|
||||
{
|
||||
"test": "packages/webui/tests/editor-provenance.test.mjs",
|
||||
"line": 92,
|
||||
"text": "const bundle = readFileSync(join(webui, 'src/public/editor.js'), 'utf8');"
|
||||
},
|
||||
{
|
||||
"test": "packages/webui/tests/editor-provenance.test.mjs",
|
||||
"line": 167,
|
||||
"text": "const info = await run(out, join(out, 'BUILD.json'));"
|
||||
},
|
||||
{
|
||||
"test": "packages/webui/tests/editor-provenance.test.mjs",
|
||||
"line": 171,
|
||||
"text": "assert.equal(readFileSync(join(out, 'BUILD.json'), 'utf8'), readFileSync(join(webui, 'editor/BUILD.json'), 'utf8'));"
|
||||
},
|
||||
{
|
||||
"test": "packages/webui/tests/editor-browser.test.mjs",
|
||||
"line": 103,
|
||||
"text": "assert.equal(await h.q('typeof window.MosaicEditor.mount'), 'function', 'editor.js ran under script-src self');"
|
||||
},
|
||||
{
|
||||
"test": "packages/webui/tests/editor-browser.test.mjs",
|
||||
"line": 423,
|
||||
"text": "// (The editor's own reading of a file can give a single line break in a title or alt, never a blank line; see BUILD.md.)"
|
||||
},
|
||||
{
|
||||
"test": "packages/webui/tests/granted-user.test.mjs",
|
||||
"line": 231,
|
||||
"text": "['GET', '/app.js'], ['GET', '/bus.js'], ['GET', '/agents.js'], ['GET', '/editor.js'], ['GET', '/shared/app.css'], ['GET', '/index.html'],"
|
||||
},
|
||||
{
|
||||
"test": "packages/webui/tests/editor.test.mjs",
|
||||
"line": 20,
|
||||
"text": "for (const [path, type] of [['/editor.js', 'text/javascript'], ['/editor.css', 'text/css']]) {"
|
||||
},
|
||||
{
|
||||
"test": "packages/webui/tests/editor.test.mjs",
|
||||
"line": 29,
|
||||
"text": "assert.ok(index.indexOf('src=\"/editor.js\"') < index.indexOf('src=\"/bus.js\"'), 'the editor loads before the page script, so bus.js can mount it');"
|
||||
},
|
||||
{
|
||||
"test": "packages/webui/tests/editor.test.mjs",
|
||||
"line": 60,
|
||||
"text": "for (const file of ['entry.mjs', 'model.mjs', 'view.mjs']) {"
|
||||
},
|
||||
{
|
||||
"test": "packages/webui/tests/editor.test.mjs",
|
||||
"line": 64,
|
||||
"text": "const bundle = readFileSync(join(webui, 'src/public/editor.js'), 'utf8');"
|
||||
},
|
||||
{
|
||||
"test": "packages/webui/tests/editor.test.mjs",
|
||||
"line": 65,
|
||||
"text": "assert.doesNotMatch(bundle, /\\beval\\s*\\(|\\bnew\\s+Function\\b/, 'src/public/editor.js');"
|
||||
},
|
||||
{
|
||||
"test": "packages/webui/tests/editor.test.mjs",
|
||||
"line": 69,
|
||||
"text": "const model = readFileSync(join(webui, 'editor/model.mjs'), 'utf8');"
|
||||
},
|
||||
{
|
||||
"test": "packages/webui/tests/helpers/editor-bundle.mjs",
|
||||
"line": 1,
|
||||
"text": "// Loads src/public/editor.js (and markdown-preview.js, the link gate it needs) into a vm context with a"
|
||||
},
|
||||
{
|
||||
"test": "packages/webui/tests/helpers/editor-bundle.mjs",
|
||||
"line": 15,
|
||||
"text": "for (const f of ['markdown-preview.js', 'editor.js']) vm.runInContext(readFileSync(join(pub, f), 'utf8'), sandbox, { filename: f });"
|
||||
},
|
||||
{
|
||||
"test": "packages/plugins/tests/harness.test.mjs",
|
||||
"line": 44,
|
||||
"text": "// pi 0.85.1 --thinking and claude 2.1.302 --effort, as probed (BUILD.md); claude has no off or minimal."
|
||||
},
|
||||
{
|
||||
"test": "packages/bus/tests/revoke-window.test.mjs",
|
||||
"line": 4,
|
||||
"text": "// a limit stub and a usage stub for the limit stop. BUILD.md (agents/morgana/work/queue-306) names"
|
||||
},
|
||||
{
|
||||
"test": "packages/bus/tests/access-revoke.test.mjs",
|
||||
"line": 5,
|
||||
"text": "// lstat key; `edit` changes the document and the stamp together, as a hand edit does. BUILD.md"
|
||||
},
|
||||
{
|
||||
"test": "packages/bus/tests/land.test.mjs",
|
||||
"line": 410,
|
||||
"text": "// landHeld still counts it, so it stays listed (BUILD.md follow-up 5)."
|
||||
},
|
||||
{
|
||||
"test": "packages/bus/tests/session-clear.test.mjs",
|
||||
"line": 13,
|
||||
"text": "// docs/plans/2026-10-21_t1-sessions.md, the contract in agents/gizmoduck/work/queue-271/BUILD.md."
|
||||
},
|
||||
{
|
||||
"test": "packages/bus/tests/grant-executor.test.mjs",
|
||||
"line": 1027,
|
||||
"text": "// credential-unavailable; BUILD.md records the difference)."
|
||||
},
|
||||
{
|
||||
"test": "packages/bus/tests/host-run.test.mjs",
|
||||
"line": 343,
|
||||
"text": "// the options are checked here and the call runs with an alias no user file holds (BUILD.md)."
|
||||
},
|
||||
{
|
||||
"test": "packages/business/tests/workflow-roles.test.mjs",
|
||||
"line": 123,
|
||||
"text": "// of staff launches it. The broker and launcher states are row 137's tests (BUILD.md, round 3)."
|
||||
},
|
||||
{
|
||||
"test": "packages/business/tests/access.test.mjs",
|
||||
"line": 1,
|
||||
"text": "// FED R1 (#414, row 201): the access file loader and validator, DESIGN.md"
|
||||
},
|
||||
{
|
||||
"test": "packages/cli/tests/revoke-window.test.mjs",
|
||||
"line": 9,
|
||||
"text": "// poll, with threadsState replaced by the caller. BUILD.md (agents/morgana/work/queue-306) names the"
|
||||
},
|
||||
{
|
||||
"test": "packages/cli/tests/stack-instances.test.mjs",
|
||||
"line": 3,
|
||||
"text": "// T table: agents/darkwing/work/queue-190/DESIGN.md D7. The unit, port and release cases are T56 in"
|
||||
},
|
||||
{
|
||||
"test": "packages/cli/tests/session-launch.test.mjs",
|
||||
"line": 297,
|
||||
"text": "// Q2 (BUILD.md:177-179, t1-sessions.md:109): an earlier host's sessionless run of the instance is"
|
||||
},
|
||||
{
|
||||
"test": "packages/cli/tests/case1-accept.test.mjs",
|
||||
"line": 2,
|
||||
"text": "// (agents/darkwing/work/queue-195/DESIGN.md); deviations in agents/darkwing/work/queue-195/BUILD.md."
|
||||
},
|
||||
{
|
||||
"test": "packages/cli/tests/stack-release.test.mjs",
|
||||
"line": 4,
|
||||
"text": "// agents/darkwing/work/queue-162/BUILD.md. Every run uses a temp data root, temp units and stand-in"
|
||||
},
|
||||
{
|
||||
"test": "packages/cli/tests/stack-release.test.mjs",
|
||||
"line": 915,
|
||||
"text": "// COUNTED or dropped from it shows here. Row 181's BUILD.md names each writer."
|
||||
},
|
||||
{
|
||||
"test": "packages/cli/tests/stack-release.test.mjs",
|
||||
"line": 928,
|
||||
"text": "task_comment_cursors:'no time column; a restore drops its advances uncounted (BUILD.md)',"
|
||||
},
|
||||
{
|
||||
"test": "packages/cli/tests/stack-release.test.mjs",
|
||||
"line": 1668,
|
||||
"text": "// refusal is the guard for a file that changes after that (BUILD.md, round 2)."
|
||||
},
|
||||
{
|
||||
"test": "packages/cli/tests/stack-release.test.mjs",
|
||||
"line": 2331,
|
||||
"text": "// agents/darkwing/work/queue-190/DESIGN.md. T-I1, T-I2, T-I5, T-I10 and the loader half of T-I7 are in"
|
||||
},
|
||||
{
|
||||
"test": "packages/cli/tests/publish-socket.test.mjs",
|
||||
"line": 236,
|
||||
"text": "// sage-1440 on BUILD.md 14: a push between checkPublish and the git push refuses, with one code"
|
||||
},
|
||||
{
|
||||
"test": "packages/cli/tests/stack-upgrade.test.mjs",
|
||||
"line": 3,
|
||||
"text": "// agents/darkwing/work/queue-195/DESIGN.md, as the I3 brief changes them; deviations:"
|
||||
},
|
||||
{
|
||||
"test": "packages/cli/tests/stack-upgrade.test.mjs",
|
||||
"line": 4,
|
||||
"text": "// agents/darkwing/work/queue-233/BUILD.md. The stand-ins and the module fixture are"
|
||||
},
|
||||
{
|
||||
"test": "packages/cli/tests/stack-release-external.test.mjs",
|
||||
"line": 2,
|
||||
"text": "// test list, agents/darkwing/work/queue-195/DESIGN.md; deviations: agents/darkwing/work/queue-232/BUILD.md."
|
||||
},
|
||||
{
|
||||
"test": "packages/cli/tests/case1-hostcheck.test.mjs",
|
||||
"line": 3,
|
||||
"text": "// (agents/darkwing/work/queue-195/DESIGN.md at b7239bb66). Every case copies the script into a scratch"
|
||||
},
|
||||
{
|
||||
"test": "packages/cli/tests/thread-revoke.test.mjs",
|
||||
"line": 5,
|
||||
"text": "// The bus half is packages/bus/tests/access-revoke.test.mjs; BUILD.md"
|
||||
},
|
||||
{
|
||||
"test": "packages/cli/tests/access.test.mjs",
|
||||
"line": 308,
|
||||
"text": "// outside R5 (BUILD.md). The test pins it, and nothing is written."
|
||||
},
|
||||
{
|
||||
"test": "packages/cli/tests/access.test.mjs",
|
||||
"line": 316,
|
||||
"text": "// Row 193c (#1705): `user add` and `user remove`. BUILD.md (agents/megavolt/work/queue-207) names"
|
||||
},
|
||||
{
|
||||
"test": "packages/cli/tests/access.test.mjs",
|
||||
"line": 455,
|
||||
"text": "// refuses access.reload alone, as a bus would refuse a call it can't take. BUILD.md"
|
||||
},
|
||||
{
|
||||
"test": "packages/cli/tests/launcher.test.mjs",
|
||||
"line": 799,
|
||||
"text": "// The run directory exists by then (BUILD.md residual); the persona is read before any bundle file."
|
||||
},
|
||||
{
|
||||
"test": "packages/cli/tests/lifecycle.test.mjs",
|
||||
"line": 778,
|
||||
"text": "// N6 (sage-2246, DESIGN.md:118-120): an end signals the runs the verb named and the instance's runs"
|
||||
}
|
||||
],
|
||||
"row266": {
|
||||
"ref": "origin/fethry/row266",
|
||||
"tip": "6418ec063389728e0d8883c94812b12d2074eb43",
|
||||
"diffBase": "487500a16f4ab5902c318509fdec6acc56a543ca",
|
||||
"overlap": []
|
||||
},
|
||||
"interpretation": "No literal SHA256 or Git-blob hash pins found for planned changed files. Editor provenance compares generated output to BUILD.json and requires regeneration/rebuild, not an external fixed hash.",
|
||||
"postBuildAudit": {
|
||||
"paths": [
|
||||
"BUILD-LOG.md",
|
||||
"agents/herb/work/queue-214/BUILD.md",
|
||||
"agents/herb/work/queue-214/DESIGN.md",
|
||||
"agents/herb/work/queue-214/EVIDENCE.json",
|
||||
"agents/herb/work/queue-214/HASH-PINS.json",
|
||||
"agents/herb/work/queue-214/MANIFEST.md",
|
||||
"agents/herb/work/queue-214/SOURCE.json",
|
||||
"agents/herb/work/queue-214/granted-4286/baseline-red.log",
|
||||
"agents/herb/work/queue-214/granted-4286/build.log",
|
||||
"agents/herb/work/queue-214/granted-4286/editor-browser-green.log",
|
||||
"agents/herb/work/queue-214/granted-4286/editor-green.log",
|
||||
"agents/herb/work/queue-214/granted-4286/final-sweep.json",
|
||||
"agents/herb/work/queue-214/granted-4286/invalid-escaping-build.log",
|
||||
"agents/herb/work/queue-214/granted-4286/invalid-escaping-red.log",
|
||||
"agents/herb/work/queue-214/granted-4286/invalid-escaping-restore-build.log",
|
||||
"agents/herb/work/queue-214/granted-4286/invalid-escaping-restore-green.log",
|
||||
"agents/herb/work/queue-214/granted-4286/measurement.log",
|
||||
"agents/herb/work/queue-214/granted-4286/mutants.json",
|
||||
"agents/herb/work/queue-214/granted-4286/mutants.py",
|
||||
"agents/herb/work/queue-214/granted-4286/npm-ci.log",
|
||||
"agents/herb/work/queue-214/granted-4286/post-mutant-sweep.json",
|
||||
"agents/herb/work/queue-214/granted-4286/provenance-green.log",
|
||||
"agents/herb/work/queue-214/granted-4286/results.jsonl",
|
||||
"agents/herb/work/queue-214/granted-4286/serializer-removal-build.log",
|
||||
"agents/herb/work/queue-214/granted-4286/serializer-removal-red.log",
|
||||
"agents/herb/work/queue-214/granted-4286/serializer-removal-restore-build.log",
|
||||
"agents/herb/work/queue-214/granted-4286/serializer-removal-restore-green.log",
|
||||
"agents/herb/work/queue-214/granted-4286/settings.json",
|
||||
"agents/herb/work/queue-214/granted-4286/skips.json",
|
||||
"agents/herb/work/queue-214/granted-4286/step.py",
|
||||
"agents/herb/work/queue-214/granted-4286/webui-69.log",
|
||||
"agents/herb/work/queue-214/granted-4286/webui-files.txt",
|
||||
"agents/herb/work/queue-214/granted-4286/webui-whole.log",
|
||||
"agents/herb/work/queue-214/granted-4286/wikilink-green.log",
|
||||
"agents/herb/work/queue-214/measure.mjs",
|
||||
"agents/herb/work/queue-214/measurement.json",
|
||||
"packages/webui/editor/BUILD.json",
|
||||
"packages/webui/editor/model.mjs",
|
||||
"packages/webui/src/public/editor.js",
|
||||
"packages/webui/tests/editor-wikilink.test.mjs",
|
||||
"packages/webui/tests/helpers/wikilink-cases.mjs"
|
||||
],
|
||||
"literalCurrentOrPriorHashPins": [],
|
||||
"buildOutputsValidated": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
# Row214 candidate manifest
|
||||
|
||||
Owner: Herb. Reviewer: Filbert. Issue#1715, C2-11a. Execution base
|
||||
487500a16f4ab5902c318509fdec6acc56a543ca on herb/row214-r2. Current
|
||||
brief blob85e6fe2e has the same C2-11a section as the accepted old pin.
|
||||
Source commit a530a60798bf48eb18bb9e225d099faf5c2975cf.
|
||||
|
||||
| Path | Final change |
|
||||
| --- | --- |
|
||||
| packages/webui/editor/model.mjs | inert inline atom, heading content, tokenizer and validated serializer; invalid attrs share complete text escaping |
|
||||
| packages/webui/tests/editor-wikilink.test.mjs | ten byte round-trips and three browser regressions, including same-block edits and malformed attrs |
|
||||
| packages/webui/tests/helpers/wikilink-cases.mjs | exact fixtures shared with measurement |
|
||||
| packages/webui/src/public/editor.js | generated with pinned esbuild0.28.2 |
|
||||
| packages/webui/editor/BUILD.json | generated provenance and output hashes |
|
||||
| BUILD-LOG.md | one append-only phase receipt |
|
||||
| agents/herb/work/queue-214/measure.mjs | baseline measurement from pinned Git blobs |
|
||||
| agents/herb/work/queue-214/measurement.json | unchanged measurement JSON,10/10 equal |
|
||||
| agents/herb/work/queue-214/DESIGN.md | accepted design, both outcomes and static review follow-through |
|
||||
| agents/herb/work/queue-214/BUILD.md | rulings, actual granted commands, timings and limits |
|
||||
| agents/herb/work/queue-214/HASH-PINS.json | static hash-pin/row266 audit, repeated after build |
|
||||
| agents/herb/work/queue-214/SOURCE.json | actual source/output hashes and unchanged CSS dependency |
|
||||
| agents/herb/work/queue-214/EVIDENCE.json | grant, exact argv/counts, measurement, mutants, skips and sweeps |
|
||||
| agents/herb/work/queue-214/granted-4286/ | raw tee logs, commands, file list and sweep/skip/mutant records |
|
||||
|
||||
The CSS output is byte-identical and matches BUILD.json. No entry/view,
|
||||
third_party, dependency/lockfile, library, route, save, click or documentPath
|
||||
change. No row266 chat path changes. No test assertion changed after runs.
|
||||
|
||||
Outcome A: all ten measured no-edit cases were already preserved by the
|
||||
baseline's raw/sig behavior. Their green result is compatibility evidence,
|
||||
not proof of the node. The baseline structural case was0/1 expected red.
|
||||
|
||||
Grant sage-4286: four whole editor files40/0; whole webui69 files455/0
|
||||
in174.189s; zero skips/cancellations. Both named mutants killed0/1,
|
||||
each restored/rebuilt and focused1/0 green. Absolute nice19, required-build
|
||||
env and short scratch TMPDIR are in raw logs. Provenance rebuilt, not
|
||||
skipped. Final process sweep0, TMPDIR removed. The mistaken seven-file
|
||||
subset28/0 is archived but excluded from gate evidence.
|
||||
|
||||
The candidate hash manifest is rebuilt from the pushed tip outside its
|
||||
own path set. Filbert's candidate review and every scripts/test-*.sh gate
|
||||
remain pending. No Case1 acceptance test was run. The row is not done.
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"base": "487500a16f4ab5902c318509fdec6acc56a543ca",
|
||||
"status": "focused and 69-file webui green under sage-4286; candidate review and shell gate pending",
|
||||
"sourcePaths": [
|
||||
{
|
||||
"path": "packages/webui/editor/model.mjs",
|
||||
"mode": "100644",
|
||||
"sha256": "81ac44d852cb54213a9644ebbde26630ec49614e468f376d71b471395e3dd9f7"
|
||||
},
|
||||
{
|
||||
"path": "packages/webui/tests/editor-wikilink.test.mjs",
|
||||
"mode": "100644",
|
||||
"sha256": "e144e7dbf23c68c136eef8f0fb2e8979c27e908c7cc14ee4ab4f722220e67d77"
|
||||
},
|
||||
{
|
||||
"path": "packages/webui/tests/helpers/wikilink-cases.mjs",
|
||||
"mode": "100644",
|
||||
"sha256": "afa4dc7188548457b2d1966b9437561ba411d7bc9aaaa38bff626c235a64e19c"
|
||||
},
|
||||
{
|
||||
"path": "agents/herb/work/queue-214/measure.mjs",
|
||||
"mode": "100644",
|
||||
"sha256": "f81987cdae5c4f7e5ce353162674b3c3510e44f22d6d3beb262a5d198db4e88d"
|
||||
},
|
||||
{
|
||||
"path": "packages/webui/src/public/editor.js",
|
||||
"mode": "100644",
|
||||
"sha256": "bd167899a551c70dc07e500fcdd1853d7fb710b23c217ba5b42daf5785c38a72"
|
||||
},
|
||||
{
|
||||
"path": "packages/webui/editor/BUILD.json",
|
||||
"mode": "100644",
|
||||
"sha256": "4d73af728cea60eaa6fadb4650b9d42b663c90ef7f59bb2b787e1f3d9acd8278"
|
||||
},
|
||||
{
|
||||
"path": "BUILD-LOG.md",
|
||||
"mode": "100644",
|
||||
"sha256": "30cc179e2b76c5aceeec35d5ab20339988241a4cb04d26d1cc9b2a5437796236"
|
||||
}
|
||||
],
|
||||
"pendingGeneratedPaths": [],
|
||||
"unchangedGeneratedCss": {
|
||||
"path": "packages/webui/src/public/editor.css",
|
||||
"sha256": "8654ac57d1e7a561110138ecd7f701c34a074017ff8c4cd2768d8083908ee61f",
|
||||
"mode": "100644"
|
||||
},
|
||||
"runtimeEvidence": "agents/herb/work/queue-214/EVIDENCE.json",
|
||||
"sourceCommit": "a530a60798bf48eb18bb9e225d099faf5c2975cf"
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
# grant sage-4286; nice 19; TMPDIR /mnt/storage/scratch/tmp/g49X; MOSAIC_REQUIRE_EDITOR_BUILD 1
|
||||
✖ wikilinks are inline atoms and survive a neighbouring edit in every required context (932.607342ms)
|
||||
ℹ tests 1
|
||||
ℹ suites 0
|
||||
ℹ pass 0
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 1108.548729
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/webui/tests/editor-wikilink.test.mjs:35:1
|
||||
✖ wikilinks are inline atoms and survive a neighbouring edit in every required context (932.607342ms)
|
||||
AssertionError [ERR_ASSERTION]: plain
|
||||
+ actual - expected
|
||||
|
||||
+ []
|
||||
- [
|
||||
- {
|
||||
- atom: true,
|
||||
- inline: true,
|
||||
- source: '[[a]]'
|
||||
- }
|
||||
- ]
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2/packages/webui/tests/editor-wikilink.test.mjs:39:12)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3) {
|
||||
generatedMessage: false,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: [],
|
||||
expected: [ { source: '[[a]]', atom: true, inline: true } ],
|
||||
operator: 'deepStrictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
# grant sage-4286; nice 19; TMPDIR /mnt/storage/scratch/tmp/g49X; MOSAIC_REQUIRE_EDITOR_BUILD 1
|
||||
▲ [WARNING] Ignoring this import because "third_party/editor/prosemirror-transform/src/mark.ts" was marked as having no side effects [ignored-bare-import]
|
||||
|
||||
third_party/editor/prosemirror-transform/src/index.ts:10:7:
|
||||
10 │ import "./mark"
|
||||
╵ ~~~~~~~~
|
||||
|
||||
"sideEffects" is false in the enclosing "package.json" file:
|
||||
|
||||
third_party/editor/prosemirror-transform/package.json:13:2:
|
||||
13 │ "sideEffects": false,
|
||||
╵ ~~~~~~~~~~~~~
|
||||
|
||||
editor.js bd167899a551c70dc07e500fcdd1853d7fb710b23c217ba5b42daf5785c38a72 (133 inputs)
|
||||
editor.css 8654ac57d1e7a561110138ecd7f701c34a074017ff8c4cd2768d8083908ee61f
|
||||
@@ -0,0 +1,25 @@
|
||||
# grant sage-4286; nice 19; TMPDIR /mnt/storage/scratch/tmp/g49X; MOSAIC_REQUIRE_EDITOR_BUILD 1
|
||||
✔ the Console's CSP stands and the editor runs under it; hostile markdown on the load path runs and loads nothing (928.130513ms)
|
||||
✔ hostile content pasted into the editor runs and loads nothing, and a bad link target is refused in the link bar (803.464018ms)
|
||||
✔ a pasted image span is kept only for a target the link gate accepts, and a save writes only those (635.018754ms)
|
||||
✔ a switch of view reads nothing; a reload, and a trip away and back, each read the file exactly once (2555.185634ms)
|
||||
✔ an edit rewrites only the block touched; a save sends the rest byte for byte; the Source view carries the draft (1077.608366ms)
|
||||
✔ a file the editor cannot write back byte for byte opens as Source, says so, cannot save, and the Visual button works once it can (2053.81983ms)
|
||||
✔ a link title pasted with line breaks in it is written on one line, so no HTML block comes of it (761.717564ms)
|
||||
✔ an image alt pasted with line breaks in it is written on one line, so no HTML block comes of it (677.209658ms)
|
||||
✔ an image title pasted with line breaks in it is written on one line, so no HTML block comes of it (681.501055ms)
|
||||
✔ a code block info string pasted with line breaks in it is written on one line, so no HTML block comes of it (664.552078ms)
|
||||
✔ a link title holding a quote after a backslash then a tag is written with the backslash escaped, so the title stays closed (653.763504ms)
|
||||
✔ an image title holding a quote after a backslash then a tag is written with the backslash escaped, so the title stays closed (680.145608ms)
|
||||
✔ a link title holding a trailing backslash is written with the backslash escaped, so the title stays closed (681.870693ms)
|
||||
✔ an image title holding a trailing backslash is written with the backslash escaped, so the title stays closed (686.810545ms)
|
||||
✔ a code block info string with a backtick, pasted, is dropped on Save, so the fence stays closed (631.067849ms)
|
||||
✔ a code block info string with a backtick, as a tilde fence can have, is kept as source, not rewritten without it (631.071266ms)
|
||||
ℹ tests 16
|
||||
ℹ suites 0
|
||||
ℹ pass 16
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 14945.374491
|
||||
@@ -0,0 +1,14 @@
|
||||
# grant sage-4286; nice 19; TMPDIR /mnt/storage/scratch/tmp/g49X; MOSAIC_REQUIRE_EDITOR_BUILD 1
|
||||
✔ the editor routes serve the built files with their types and no cache (36.796766ms)
|
||||
✔ open and save with no edit writes the same bytes: the goals review and a doc with every element (16.912796ms)
|
||||
✔ open and save with no edit writes the same bytes: every repository doc under docs/ and spec/ (1791.779235ms)
|
||||
✔ the editor source builds markup only with DOM calls, and the bundle has no eval (2.568423ms)
|
||||
✔ the link gate and the image rule are the preview's (0.573105ms)
|
||||
ℹ tests 5
|
||||
ℹ suites 0
|
||||
ℹ pass 5
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 2016.291596
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"at": "2026-10-24T22:13:17.560692+00:00",
|
||||
"count": 0,
|
||||
"processes": []
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
# grant sage-4286; nice 19; TMPDIR /mnt/storage/scratch/tmp/g49X; MOSAIC_REQUIRE_EDITOR_BUILD 1
|
||||
▲ [WARNING] Ignoring this import because "third_party/editor/prosemirror-transform/src/mark.ts" was marked as having no side effects [ignored-bare-import]
|
||||
|
||||
third_party/editor/prosemirror-transform/src/index.ts:10:7:
|
||||
10 │ import "./mark"
|
||||
╵ ~~~~~~~~
|
||||
|
||||
"sideEffects" is false in the enclosing "package.json" file:
|
||||
|
||||
third_party/editor/prosemirror-transform/package.json:13:2:
|
||||
13 │ "sideEffects": false,
|
||||
╵ ~~~~~~~~~~~~~
|
||||
|
||||
editor.js 52c00310b3c32b2f5ca99243f9bbe54f8a76ef0a87f597d8a2220cf1baaa8adc (133 inputs)
|
||||
editor.css 8654ac57d1e7a561110138ecd7f701c34a074017ff8c4cd2768d8083908ee61f
|
||||
@@ -0,0 +1,30 @@
|
||||
# grant sage-4286; nice 19; TMPDIR /mnt/storage/scratch/tmp/g49X; MOSAIC_REQUIRE_EDITOR_BUILD 1
|
||||
✖ wikilink DOM paste accepts only bounded single-line inert syntax; malformed attrs serialise as escaped text (780.97333ms)
|
||||
ℹ tests 1
|
||||
ℹ suites 0
|
||||
ℹ pass 0
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 939.392901
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/webui/tests/editor-wikilink.test.mjs:65:1
|
||||
✖ wikilink DOM paste accepts only bounded single-line inert syntax; malformed attrs serialise as escaped text (780.97333ms)
|
||||
AssertionError [ERR_ASSERTION]: The input was expected to not match the regular expression /(?<!\\)<img/. Input:
|
||||
|
||||
'\\[\\[a\\]\\] <img src=x onerror=alert(1)>©\n'
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2/packages/webui/tests/editor-wikilink.test.mjs:78:10)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: '\\[\\[a\\]\\] <img src=x onerror=alert(1)>©\n',
|
||||
expected: /(?<!\\)<img/,
|
||||
operator: 'doesNotMatch',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
# grant sage-4286; nice 19; TMPDIR /mnt/storage/scratch/tmp/g49X; MOSAIC_REQUIRE_EDITOR_BUILD 1
|
||||
▲ [WARNING] Ignoring this import because "third_party/editor/prosemirror-transform/src/mark.ts" was marked as having no side effects [ignored-bare-import]
|
||||
|
||||
third_party/editor/prosemirror-transform/src/index.ts:10:7:
|
||||
10 │ import "./mark"
|
||||
╵ ~~~~~~~~
|
||||
|
||||
"sideEffects" is false in the enclosing "package.json" file:
|
||||
|
||||
third_party/editor/prosemirror-transform/package.json:13:2:
|
||||
13 │ "sideEffects": false,
|
||||
╵ ~~~~~~~~~~~~~
|
||||
|
||||
editor.js bd167899a551c70dc07e500fcdd1853d7fb710b23c217ba5b42daf5785c38a72 (133 inputs)
|
||||
editor.css 8654ac57d1e7a561110138ecd7f701c34a074017ff8c4cd2768d8083908ee61f
|
||||
@@ -0,0 +1,10 @@
|
||||
# grant sage-4286; nice 19; TMPDIR /mnt/storage/scratch/tmp/g49X; MOSAIC_REQUIRE_EDITOR_BUILD 1
|
||||
✔ wikilink DOM paste accepts only bounded single-line inert syntax; malformed attrs serialise as escaped text (752.4905ms)
|
||||
ℹ tests 1
|
||||
ℹ suites 0
|
||||
ℹ pass 1
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 941.178679
|
||||
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"base": "487500a16f4ab5902c318509fdec6acc56a543ca",
|
||||
"bundleSha256": "9c881b13740fae2408717ad75fa1d85bfcfe3fa8b3af0f1b3f2e706c90e80fee",
|
||||
"measuredAt": "2026-10-24T22:07:22.210Z",
|
||||
"allEqual": true,
|
||||
"results": [
|
||||
{
|
||||
"name": "plain",
|
||||
"input": "[[a]]\n",
|
||||
"output": "[[a]]\n",
|
||||
"equal": true
|
||||
},
|
||||
{
|
||||
"name": "labelled",
|
||||
"input": "[[a|b]]\n",
|
||||
"output": "[[a|b]]\n",
|
||||
"equal": true
|
||||
},
|
||||
{
|
||||
"name": "heading target",
|
||||
"input": "[[a#h]]\n",
|
||||
"output": "[[a#h]]\n",
|
||||
"equal": true
|
||||
},
|
||||
{
|
||||
"name": "list item",
|
||||
"input": "- [[a]]\n",
|
||||
"output": "- [[a]]\n",
|
||||
"equal": true
|
||||
},
|
||||
{
|
||||
"name": "next to front matter",
|
||||
"input": "---\nrelated: \"[[metadata]]\"\n---\n\n[[a]]\n",
|
||||
"output": "---\nrelated: \"[[metadata]]\"\n---\n\n[[a]]\n",
|
||||
"equal": true
|
||||
},
|
||||
{
|
||||
"name": "heading block and combined label",
|
||||
"input": "# See [[a#h|Title]]\n",
|
||||
"output": "# See [[a#h|Title]]\n",
|
||||
"equal": true
|
||||
},
|
||||
{
|
||||
"name": "spaces, Unicode and adjacent links",
|
||||
"input": "See [[ Héllo there # A heading | a label ]][[next]]\n",
|
||||
"output": "See [[ Héllo there # A heading | a label ]][[next]]\n",
|
||||
"equal": true
|
||||
},
|
||||
{
|
||||
"name": "reference-definition collision",
|
||||
"input": "[[a]]\n\n[a]: u\n",
|
||||
"output": "[[a]]\n\n[a]: u\n",
|
||||
"equal": true
|
||||
},
|
||||
{
|
||||
"name": "inside an ordinary link",
|
||||
"input": "[x [[a]]](u)\n",
|
||||
"output": "[x [[a]]](u)\n",
|
||||
"equal": true
|
||||
},
|
||||
{
|
||||
"name": "inert embed",
|
||||
"input": "![[cover.png]]\n",
|
||||
"output": "![[cover.png]]\n",
|
||||
"equal": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
[
|
||||
{
|
||||
"name": "serializer-removal",
|
||||
"killed": true,
|
||||
"restored": true,
|
||||
"restoredHashesEqual": true
|
||||
},
|
||||
{
|
||||
"name": "invalid-escaping",
|
||||
"killed": true,
|
||||
"restored": true,
|
||||
"restoredHashesEqual": true
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,26 @@
|
||||
from pathlib import Path
|
||||
import subprocess,sys,json,hashlib
|
||||
out=Path(__file__).parent;root=Path('/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2');model=root/'packages/webui/editor/model.mjs';good=model.read_bytes();(out/'model.good.mjs').write_bytes(good)
|
||||
initial={str(p.relative_to(root)):hashlib.sha256(p.read_bytes()).hexdigest() for p in [model,root/'packages/webui/src/public/editor.js',root/'packages/webui/editor/BUILD.json',root/'packages/webui/src/public/editor.css']}
|
||||
def step(name,cwd,cap,args):return subprocess.run([sys.executable,str(out/'step.py'),name,str(cwd),str(cap),*args]).returncode
|
||||
specs=[('serializer-removal','wikilinks are inline atoms and survive'),('invalid-escaping','wikilink DOM paste accepts')]
|
||||
results=[]
|
||||
for name,pattern in specs:
|
||||
changed=good.decode()
|
||||
if name=='serializer-removal':
|
||||
start=changed.index(' wikilink(state, node) {');end=changed.index(' raw_block(state, node)',start);changed=changed[:start]+changed[end:]
|
||||
else:
|
||||
old="else escapedText(state, oneLine(String(source ?? '')));";assert changed.count(old)==1;changed=changed.replace(old,"else state.text(oneLine(String(source ?? '')));")
|
||||
try:
|
||||
model.write_text(changed)
|
||||
assert step(name+'-build',root/'packages/webui',90,['node','editor/build.mjs'])==0
|
||||
rc=step(name+'-red',root,180,['node','--test','--test-concurrency=1','--test-name-pattern='+pattern,'packages/webui/tests/editor-wikilink.test.mjs'])
|
||||
if rc!=1:raise RuntimeError('mutant not killed or timed out: '+str(rc))
|
||||
finally:
|
||||
model.write_bytes(good)
|
||||
if step(name+'-restore-build',root/'packages/webui',90,['node','editor/build.mjs'])!=0:raise RuntimeError('restore build failed')
|
||||
assert step(name+'-restore-green',root,180,['node','--test','--test-concurrency=1','--test-name-pattern='+pattern,'packages/webui/tests/editor-wikilink.test.mjs'])==0
|
||||
for p,h in initial.items():assert hashlib.sha256((root/p).read_bytes()).hexdigest()==h,p
|
||||
results.append({'name':name,'killed':True,'restored':True,'restoredHashesEqual':True})
|
||||
(out/'mutants.json').write_text(json.dumps(results,indent=2)+'\n')
|
||||
print('MUTANT_COMPLETE',name,flush=True)
|
||||
@@ -0,0 +1,3 @@
|
||||
# grant sage-4286; nice 19; TMPDIR /mnt/storage/scratch/tmp/g49X; MOSAIC_REQUIRE_EDITOR_BUILD 1
|
||||
|
||||
added 2 packages in 425ms
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"count": 0,
|
||||
"processes": []
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
# grant sage-4286; nice 19; TMPDIR /mnt/storage/scratch/tmp/g49X; MOSAIC_REQUIRE_EDITOR_BUILD 1
|
||||
✔ the imported source is the tagged upstream source plus the recorded local changes, and nothing else (27.800323ms)
|
||||
✔ every package names its origin and license, and NOTICE lists each (0.831005ms)
|
||||
✔ the build reads only imported source and the editor's own files; the bundle is the recorded build (7.478515ms)
|
||||
✔ MOSAIC_REQUIRE_EDITOR_BUILD: a missing or wrong esbuild skips without it and fails with it; a wrong binary always fails (6.189875ms)
|
||||
✔ the toolchain check, run as a program, exits non-zero without esbuild when the build is required (143.672155ms)
|
||||
▲ [WARNING] Ignoring this import because "third_party/editor/prosemirror-transform/src/mark.ts" was marked as having no side effects [ignored-bare-import]
|
||||
|
||||
third_party/editor/prosemirror-transform/src/index.ts:10:7:
|
||||
10 │ import "./mark"
|
||||
╵ ~~~~~~~~
|
||||
|
||||
"sideEffects" is false in the enclosing "package.json" file:
|
||||
|
||||
third_party/editor/prosemirror-transform/package.json:13:2:
|
||||
13 │ "sideEffects": false,
|
||||
╵ ~~~~~~~~~~~~~
|
||||
|
||||
✔ rebuilding from the source gives the same bytes (needs the pinned esbuild; MOSAIC_REQUIRE_EDITOR_BUILD=1 makes its absence a failure) (67.600627ms)
|
||||
ℹ tests 6
|
||||
ℹ suites 0
|
||||
ℹ pass 6
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 305.965249
|
||||
@@ -0,0 +1,18 @@
|
||||
{"name": "measurement", "argv": ["node", "agents/herb/work/queue-214/measure.mjs"], "cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2", "rc": 0, "wallSeconds": 0.093, "counts": {}, "nice": 19, "tmpRoot": "/mnt/storage/scratch/tmp/g49X", "requireEditorBuild": "1", "timeoutSeconds": 60, "ended": "2026-10-24T22:07:22.215700+00:00"}
|
||||
{"name": "baseline-red", "argv": ["node", "--test", "--test-concurrency=1", "--test-name-pattern=wikilinks are inline atoms and survive", "packages/webui/tests/editor-wikilink.test.mjs"], "cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2", "rc": 1, "wallSeconds": 1.151, "counts": {"tests": 1, "pass": 0, "fail": 1, "cancelled": 0, "skipped": 0}, "nice": 19, "tmpRoot": "/mnt/storage/scratch/tmp/g49X", "requireEditorBuild": "1", "timeoutSeconds": 180, "ended": "2026-10-24T22:07:27.998436+00:00"}
|
||||
{"name": "npm-ci", "argv": ["npm", "ci", "--ignore-scripts", "--no-audit", "--no-fund"], "cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2/packages/webui", "rc": 0, "wallSeconds": 0.514, "counts": {}, "nice": 19, "tmpRoot": "/mnt/storage/scratch/tmp/g49X", "requireEditorBuild": "1", "timeoutSeconds": 240, "ended": "2026-10-24T22:07:41.534116+00:00"}
|
||||
{"name": "build", "argv": ["node", "editor/build.mjs"], "cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2/packages/webui", "rc": 0, "wallSeconds": 0.108, "counts": {}, "nice": 19, "tmpRoot": "/mnt/storage/scratch/tmp/g49X", "requireEditorBuild": "1", "timeoutSeconds": 120, "ended": "2026-10-24T22:07:44.654385+00:00"}
|
||||
{"name": "wikilink-green", "argv": ["node", "--test", "--test-concurrency=1", "packages/webui/tests/editor-wikilink.test.mjs"], "cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2", "rc": 0, "wallSeconds": 2.348, "counts": {"tests": 13, "pass": 13, "fail": 0, "cancelled": 0, "skipped": 0}, "nice": 19, "tmpRoot": "/mnt/storage/scratch/tmp/g49X", "requireEditorBuild": "1", "timeoutSeconds": 180, "ended": "2026-10-24T22:07:52.583345+00:00"}
|
||||
{"name": "editor-green", "argv": ["node", "--test", "--test-concurrency=1", "packages/webui/tests/editor.test.mjs"], "cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2", "rc": 0, "wallSeconds": 2.053, "counts": {"tests": 5, "pass": 5, "fail": 0, "cancelled": 0, "skipped": 0}, "nice": 19, "tmpRoot": "/mnt/storage/scratch/tmp/g49X", "requireEditorBuild": "1", "timeoutSeconds": 240, "ended": "2026-10-24T22:07:59.286086+00:00"}
|
||||
{"name": "editor-browser-green", "argv": ["node", "--test", "--test-concurrency=1", "packages/webui/tests/editor-browser.test.mjs"], "cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2", "rc": 0, "wallSeconds": 14.984, "counts": {"tests": 16, "pass": 16, "fail": 0, "cancelled": 0, "skipped": 0}, "nice": 19, "tmpRoot": "/mnt/storage/scratch/tmp/g49X", "requireEditorBuild": "1", "timeoutSeconds": 240, "ended": "2026-10-24T22:08:20.029050+00:00"}
|
||||
{"name": "provenance-green", "argv": ["node", "--test", "--test-concurrency=1", "packages/webui/tests/editor-provenance.test.mjs"], "cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2", "rc": 0, "wallSeconds": 0.343, "counts": {"tests": 6, "pass": 6, "fail": 0, "cancelled": 0, "skipped": 0}, "nice": 19, "tmpRoot": "/mnt/storage/scratch/tmp/g49X", "requireEditorBuild": "1", "timeoutSeconds": 180, "ended": "2026-10-24T22:08:39.003420+00:00"}
|
||||
{"name": "serializer-removal-build", "argv": ["node", "editor/build.mjs"], "cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2/packages/webui", "rc": 0, "wallSeconds": 0.093, "counts": {}, "nice": 19, "tmpRoot": "/mnt/storage/scratch/tmp/g49X", "requireEditorBuild": "1", "timeoutSeconds": 90, "ended": "2026-10-24T22:08:51.422097+00:00"}
|
||||
{"name": "serializer-removal-red", "argv": ["node", "--test", "--test-concurrency=1", "--test-name-pattern=wikilinks are inline atoms and survive", "packages/webui/tests/editor-wikilink.test.mjs"], "cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2", "rc": 1, "wallSeconds": 0.887, "counts": {"tests": 1, "pass": 0, "fail": 1, "cancelled": 0, "skipped": 0}, "nice": 19, "tmpRoot": "/mnt/storage/scratch/tmp/g49X", "requireEditorBuild": "1", "timeoutSeconds": 180, "ended": "2026-10-24T22:08:52.340936+00:00"}
|
||||
{"name": "serializer-removal-restore-build", "argv": ["node", "editor/build.mjs"], "cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2/packages/webui", "rc": 0, "wallSeconds": 0.115, "counts": {}, "nice": 19, "tmpRoot": "/mnt/storage/scratch/tmp/g49X", "requireEditorBuild": "1", "timeoutSeconds": 90, "ended": "2026-10-24T22:08:52.498613+00:00"}
|
||||
{"name": "serializer-removal-restore-green", "argv": ["node", "--test", "--test-concurrency=1", "--test-name-pattern=wikilinks are inline atoms and survive", "packages/webui/tests/editor-wikilink.test.mjs"], "cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2", "rc": 0, "wallSeconds": 0.979, "counts": {"tests": 1, "pass": 1, "fail": 0, "cancelled": 0, "skipped": 0}, "nice": 19, "tmpRoot": "/mnt/storage/scratch/tmp/g49X", "requireEditorBuild": "1", "timeoutSeconds": 180, "ended": "2026-10-24T22:08:53.514962+00:00"}
|
||||
{"name": "invalid-escaping-build", "argv": ["node", "editor/build.mjs"], "cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2/packages/webui", "rc": 0, "wallSeconds": 0.102, "counts": {}, "nice": 19, "tmpRoot": "/mnt/storage/scratch/tmp/g49X", "requireEditorBuild": "1", "timeoutSeconds": 90, "ended": "2026-10-24T22:08:53.655583+00:00"}
|
||||
{"name": "invalid-escaping-red", "argv": ["node", "--test", "--test-concurrency=1", "--test-name-pattern=wikilink DOM paste accepts", "packages/webui/tests/editor-wikilink.test.mjs"], "cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2", "rc": 1, "wallSeconds": 0.979, "counts": {"tests": 1, "pass": 0, "fail": 1, "cancelled": 0, "skipped": 0}, "nice": 19, "tmpRoot": "/mnt/storage/scratch/tmp/g49X", "requireEditorBuild": "1", "timeoutSeconds": 180, "ended": "2026-10-24T22:08:54.668225+00:00"}
|
||||
{"name": "invalid-escaping-restore-build", "argv": ["node", "editor/build.mjs"], "cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2/packages/webui", "rc": 0, "wallSeconds": 0.105, "counts": {}, "nice": 19, "tmpRoot": "/mnt/storage/scratch/tmp/g49X", "requireEditorBuild": "1", "timeoutSeconds": 90, "ended": "2026-10-24T22:08:54.809629+00:00"}
|
||||
{"name": "invalid-escaping-restore-green", "argv": ["node", "--test", "--test-concurrency=1", "--test-name-pattern=wikilink DOM paste accepts", "packages/webui/tests/editor-wikilink.test.mjs"], "cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2", "rc": 0, "wallSeconds": 0.985, "counts": {"tests": 1, "pass": 1, "fail": 0, "cancelled": 0, "skipped": 0}, "nice": 19, "tmpRoot": "/mnt/storage/scratch/tmp/g49X", "requireEditorBuild": "1", "timeoutSeconds": 180, "ended": "2026-10-24T22:08:55.831793+00:00"}
|
||||
{"name": "webui-whole", "argv": ["node", "--test", "--test-concurrency=2", "tests/agents-browser.test.mjs", "tests/agents.test.mjs", "tests/board-held.test.mjs", "tests/browser-edge.test.mjs", "tests/browser.test.mjs", "tests/bus-browser.test.mjs", "tests/bus.test.mjs"], "cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2/packages/webui", "rc": 0, "wallSeconds": 17.787, "counts": {"tests": 28, "pass": 28, "fail": 0, "cancelled": 0, "skipped": 0}, "nice": 19, "tmpRoot": "/mnt/storage/scratch/tmp/g49X", "requireEditorBuild": "1", "timeoutSeconds": 600, "ended": "2026-10-24T22:09:39.039897+00:00"}
|
||||
{"name": "webui-69", "argv": ["node", "--test", "--test-concurrency=2", "tests/agents-browser.test.mjs", "tests/agents.test.mjs", "tests/assistant.test.mjs", "tests/board-held.test.mjs", "tests/browser-edge.test.mjs", "tests/browser.test.mjs", "tests/bus-browser.test.mjs", "tests/bus.test.mjs", "tests/channel-chat.test.mjs", "tests/chat-browser.test.mjs", "tests/chat-instances.test.mjs", "tests/chat-replies-browser.test.mjs", "tests/chat-sessions-access.test.mjs", "tests/chat.test.mjs", "tests/conversation.test.mjs", "tests/decide-browser.test.mjs", "tests/decide-sso.test.mjs", "tests/decision-http.test.mjs", "tests/discord.test.mjs", "tests/docs-browser.test.mjs", "tests/editor-browser.test.mjs", "tests/editor-provenance.test.mjs", "tests/editor-wikilink.test.mjs", "tests/editor.test.mjs", "tests/granted-user.test.mjs", "tests/history-return-flow.test.mjs", "tests/instances-browser.test.mjs", "tests/instances.test.mjs", "tests/library-cli.test.mjs", "tests/library-routes.test.mjs", "tests/library-status.test.mjs", "tests/limits-browser.test.mjs", "tests/limits-route.test.mjs", "tests/markdown-preview.test.mjs", "tests/messages.test.mjs", "tests/pinned-copy.test.mjs", "tests/preview.test.mjs", "tests/processing-browser.test.mjs", "tests/processing-ui.test.mjs", "tests/processing.test.mjs", "tests/project-file.test.mjs", "tests/project-name-repo.test.mjs", "tests/proof-cli.test.mjs", "tests/proof.test.mjs", "tests/reads.test.mjs", "tests/relaunch.test.mjs", "tests/return-flow.test.mjs", "tests/routes-browser.test.mjs", "tests/routes.test.mjs", "tests/send-browser.test.mjs", "tests/send.test.mjs", "tests/serve.test.mjs", "tests/service.test.mjs", "tests/settings-form.test.mjs", "tests/settings-write.test.mjs", "tests/shell.test.mjs", "tests/sso-browser.test.mjs", "tests/sso.test.mjs", "tests/tester-browser.test.mjs", "tests/tester-cli.test.mjs", "tests/tester-listener.test.mjs", "tests/tester-socket.test.mjs", "tests/thread-claims-browser.test.mjs", "tests/thread-claims.test.mjs", "tests/thread-sharing.test.mjs", "tests/usage-browser.test.mjs", "tests/usage.test.mjs", "tests/user-option-swap.test.mjs", "tests/views.test.mjs"], "cwd": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2/packages/webui", "rc": 0, "wallSeconds": 174.189, "counts": {"tests": 455, "pass": 455, "fail": 0, "cancelled": 0, "skipped": 0}, "nice": 19, "tmpRoot": "/mnt/storage/scratch/tmp/g49X", "requireEditorBuild": "1", "timeoutSeconds": 600, "ended": "2026-10-24T22:12:48.880975+00:00"}
|
||||
@@ -0,0 +1,15 @@
|
||||
# grant sage-4286; nice 19; TMPDIR /mnt/storage/scratch/tmp/g49X; MOSAIC_REQUIRE_EDITOR_BUILD 1
|
||||
▲ [WARNING] Ignoring this import because "third_party/editor/prosemirror-transform/src/mark.ts" was marked as having no side effects [ignored-bare-import]
|
||||
|
||||
third_party/editor/prosemirror-transform/src/index.ts:10:7:
|
||||
10 │ import "./mark"
|
||||
╵ ~~~~~~~~
|
||||
|
||||
"sideEffects" is false in the enclosing "package.json" file:
|
||||
|
||||
third_party/editor/prosemirror-transform/package.json:13:2:
|
||||
13 │ "sideEffects": false,
|
||||
╵ ~~~~~~~~~~~~~
|
||||
|
||||
editor.js bf55e22b945eda1e51ecbe9185eadd9ff21a7902713b24417ed7d697c7347bba (133 inputs)
|
||||
editor.css 8654ac57d1e7a561110138ecd7f701c34a074017ff8c4cd2768d8083908ee61f
|
||||
@@ -0,0 +1,31 @@
|
||||
# grant sage-4286; nice 19; TMPDIR /mnt/storage/scratch/tmp/g49X; MOSAIC_REQUIRE_EDITOR_BUILD 1
|
||||
✖ wikilinks are inline atoms and survive a neighbouring edit in every required context (698.378144ms)
|
||||
ℹ tests 1
|
||||
ℹ suites 0
|
||||
ℹ pass 0
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 850.87157
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/webui/tests/editor-wikilink.test.mjs:35:1
|
||||
✖ wikilinks are inline atoms and survive a neighbouring edit in every required context (698.378144ms)
|
||||
Error: Uncaught: Error: Token type `wikilink` not supported by Markdown renderer
|
||||
at MarkdownSerializerState.render (http://127.0.0.1:43723/editor.js:18015:17)
|
||||
at progress (http://127.0.0.1:43723/editor.js:18096:18)
|
||||
at _Fragment.forEach (http://127.0.0.1:43723/editor.js:484:9)
|
||||
at _Node.forEach (http://127.0.0.1:43723/editor.js:1178:20)
|
||||
at MarkdownSerializerState.renderInline (http://127.0.0.1:43723/editor.js:18101:14)
|
||||
at Object.paragraph (http://127.0.0.1:43723/editor.js:17859:13)
|
||||
at MarkdownSerializerState.render (http://127.0.0.1:43723/editor.js:18012:35)
|
||||
at http://127.0.0.1:43723/editor.js:18025:44
|
||||
at _Fragment.forEach (http://127.0.0.1:43723/editor.js:484:9)
|
||||
at _Node.forEach (http://127.0.0.1:43723/editor.js:1178:20)
|
||||
at Object.evaluate (file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2/packages/webui/tests/browser.mjs:49:35)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2/packages/webui/tests/editor-wikilink.test.mjs:38:5)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3)
|
||||
@@ -0,0 +1,15 @@
|
||||
# grant sage-4286; nice 19; TMPDIR /mnt/storage/scratch/tmp/g49X; MOSAIC_REQUIRE_EDITOR_BUILD 1
|
||||
▲ [WARNING] Ignoring this import because "third_party/editor/prosemirror-transform/src/mark.ts" was marked as having no side effects [ignored-bare-import]
|
||||
|
||||
third_party/editor/prosemirror-transform/src/index.ts:10:7:
|
||||
10 │ import "./mark"
|
||||
╵ ~~~~~~~~
|
||||
|
||||
"sideEffects" is false in the enclosing "package.json" file:
|
||||
|
||||
third_party/editor/prosemirror-transform/package.json:13:2:
|
||||
13 │ "sideEffects": false,
|
||||
╵ ~~~~~~~~~~~~~
|
||||
|
||||
editor.js bd167899a551c70dc07e500fcdd1853d7fb710b23c217ba5b42daf5785c38a72 (133 inputs)
|
||||
editor.css 8654ac57d1e7a561110138ecd7f701c34a074017ff8c4cd2768d8083908ee61f
|
||||
@@ -0,0 +1,10 @@
|
||||
# grant sage-4286; nice 19; TMPDIR /mnt/storage/scratch/tmp/g49X; MOSAIC_REQUIRE_EDITOR_BUILD 1
|
||||
✔ wikilinks are inline atoms and survive a neighbouring edit in every required context (782.721982ms)
|
||||
ℹ tests 1
|
||||
ℹ suites 0
|
||||
ℹ pass 1
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 940.955124
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"root": "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row214-r2",
|
||||
"tmp": "/mnt/storage/scratch/tmp/g49X",
|
||||
"grant": "sage-4286",
|
||||
"candidate": "2ec3f5b5ddab0cb5f2716f8164c25861b741213e"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"grep": "^# skip plus # SKIP and spec skipped-test lines",
|
||||
"names": []
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import os,sys,subprocess,pathlib,json,time,datetime,shlex,re
|
||||
out=pathlib.Path(__file__).parent;s=json.loads((out/'settings.json').read_text());name=sys.argv[1];cwd=sys.argv[2];cap=int(sys.argv[3]);argv=sys.argv[4:]
|
||||
left=datetime.datetime(2026,10,24,22,40,tzinfo=datetime.timezone.utc).timestamp()-time.time()-20
|
||||
if left<15:raise SystemExit('hard-stop cleanup margin reached')
|
||||
limit=min(cap,int(left));env=os.environ.copy();env.pop('NODE_TEST_CONTEXT',None)
|
||||
env.update(TMPDIR=s['tmp'],TMP=s['tmp'],TEMP=s['tmp'],MOSAIC_REQUIRE_EDITOR_BUILD='1',MOSAIC_GATE_LANE='b',MOSAIC_GATE_STATE='/mnt/storage/scratch/mosaic-gate-lanes',NO_COLOR='1',MOSAIC_CONFIG=s['tmp']+'/missing-config.json',XDG_CACHE_HOME=s['tmp']+'/cache',JITI_FS_CACHE=s['tmp']+'/jiti')
|
||||
header='' if name=='measurement' else 'printf "# grant sage-4286; nice %s; TMPDIR %s; MOSAIC_REQUIRE_EDITOR_BUILD %s\\n" "$(nice)" "$TMPDIR" "$MOSAIC_REQUIRE_EDITOR_BUILD"; '
|
||||
inner=header+'exec "$@"'
|
||||
log=out/(name+'.log');command='nice -n "$((19 - $(nice)))" timeout -k 10 '+str(limit)+' bash -c '+shlex.quote(inner)+' gate-run '+shlex.join(argv)+' 2>&1 | tee '+shlex.quote(str(log))
|
||||
begin=time.time();print('START',name,datetime.datetime.now(datetime.timezone.utc).isoformat(),flush=True)
|
||||
r=subprocess.run(['bash','-o','pipefail','-c',command],cwd=cwd,env=env,stdout=subprocess.DEVNULL)
|
||||
text=log.read_text();counts={}
|
||||
for key in ['tests','pass','fail','cancelled','skipped']:
|
||||
hits=re.findall(r'^[ℹ#] '+key+r' (\d+)',text,re.M)
|
||||
if hits:counts[key]=int(hits[-1])
|
||||
record={'name':name,'argv':argv,'cwd':cwd,'rc':r.returncode,'wallSeconds':round(time.time()-begin,3),'counts':counts,'nice':19,'tmpRoot':s['tmp'],'requireEditorBuild':'1','timeoutSeconds':limit,'ended':datetime.datetime.now(datetime.timezone.utc).isoformat()}
|
||||
with (out/'results.jsonl').open('a') as f:f.write(json.dumps(record)+'\n')
|
||||
print(json.dumps(record),flush=True);print('\n'.join(text.splitlines()[-20:]),flush=True)
|
||||
raise SystemExit(r.returncode)
|
||||
@@ -0,0 +1,489 @@
|
||||
# grant sage-4286; nice 19; TMPDIR /mnt/storage/scratch/tmp/g49X; MOSAIC_REQUIRE_EDITOR_BUILD 1
|
||||
✔ row 194 T16 Settings Agents: unavailable read-only, launch follows its request, confirms, reason and refusal (17431.415001ms)
|
||||
✔ row 256 T7 T8 the human page offers Delete on a creative instance, the tester page never does (1196.894618ms)
|
||||
✔ row 194 T16: each agent action makes one call with only its keys, logs the user and answers the request (25.920868ms)
|
||||
✔ row 194 T16: the boundary refuses before any bus call (13.773722ms)
|
||||
✔ row 194 T16: read-only when send is off or no writer is wired; no route has a --send exception (6.006105ms)
|
||||
✔ row 194 T16: a bus refusal names its reason and nothing changed; an unknown outcome or a bad shape is never retried (4.80649ms)
|
||||
✔ row 194 T16: the request read takes one id, adds the refusal reason and refuses an unexpected shape (9.010999ms)
|
||||
✔ row 194 T16: delete joins add and change on /api/instances with only revision, instance and op (4.535523ms)
|
||||
✔ row 194 T16 D4.1: the tester listener launches, terminates and reads requests; regenerate, veto and delete are refused with no call (6.985924ms)
|
||||
✔ row 194 N5: agents.js is served as JavaScript and index.html loads it once (2.138169ms)
|
||||
✔ row 239 T6: a delete closed -revoked says the tokens may already be revoked, and outcome-unknown-revoked is an open outcome (3.807253ms)
|
||||
✔ Q169 the signed-in human names a seat and stops the assistant, one bus call each, logged with the user (20.467126ms)
|
||||
✔ Q169 the name and stop routes need send on, the public name, the user, the exact Origin and same-origin Fetch Metadata (10.75691ms)
|
||||
✔ Q169 the name and stop routes take JSON within 4 KiB and only their own keys, all text (7.456ms)
|
||||
✔ Row 167 a null body on the name and stop routes is 400 invalid-request with no write, and the next request is answered (4.218653ms)
|
||||
✔ Q169 a bus refusal says nothing changed; a lost or odd answer says the change may have been made (6.353476ms)
|
||||
✔ Q169 the names read is a bus read like the others (1.642206ms)
|
||||
✔ the Board: held roles with no machine sessions, a claim with no address, the toggle kept across a reload, and Message addressed to the role (6930.836448ms)
|
||||
✔ a Seen click while a Board read is in flight waits for that read, then posts (1178.550164ms)
|
||||
✔ a redirect answer on a Board read, a bus read, a conversation read, a board POST, a module read and a send signs the page out: one line, nothing stale, no further reads (5341.444261ms)
|
||||
✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (1618.401633ms)
|
||||
Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
|
||||
✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (1723.682265ms)
|
||||
✔ the README says a refused field table names the file or the key at fault, never a path (6.362709ms)
|
||||
✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (3554.138366ms)
|
||||
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (124.549917ms)
|
||||
✔ decisions route serves the roles and recent lists from the reader view (46.444658ms)
|
||||
✔ credentials route serves the broker credential status from the reader view (19.448846ms)
|
||||
✔ replies route serves the replies to one message from the reader view (45.806351ms)
|
||||
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (55.698955ms)
|
||||
✔ bus refusals map to statuses and never carry a path or a stack (27.537764ms)
|
||||
✔ humanCall speaks the human transport protocol without blocking the server (1707.350793ms)
|
||||
✔ busReader takes --business, else the live bus host, else refuses (257.530467ms)
|
||||
✔ humanCall kills a transport that runs past its timeout (529.025642ms)
|
||||
✔ serve refuses a --business value that is not a business id (463.414608ms)
|
||||
✔ WebUI channel off returns 503 and named recovery for every chat route without a chat operation (38.716248ms)
|
||||
✔ WebUI only selection keeps web chat enabled while retaining the old read envelope (2.635502ms)
|
||||
✔ WebUI channel-disabled recovery text is fixed and never echoes transport text (1.545115ms)
|
||||
✔ chat browser: list/create named projects and threads, hostile labels inert and no implicit writes (836.234777ms)
|
||||
✔ chat browser: thread drafts, receipts and cursor history stay isolated; refresh never writes (1150.355116ms)
|
||||
✔ chat browser: uncertain writes retain draft, ownership refusal clears it, read-only cannot send (1316.24955ms)
|
||||
✔ chat browser: a late read from A cannot paint B; sign-out clears private state and stops reads (1284.31592ms)
|
||||
✔ chat browser: page forward and deduplicate replies; pending and byte-limit submissions do not duplicate (953.60414ms)
|
||||
✔ chat browser: scrolled history stays put, New messages and an own send return to the tail (923.155974ms)
|
||||
✔ chat browser: automatic polling follows a reply without a POST or a lost draft (10953.35212ms)
|
||||
✔ chat browser: display stays bounded while every forward page remains reachable (1095.68322ms)
|
||||
✔ chat browser: a confirmed visible message replaces its pending receipt; malformed receipts stay unknown (963.350843ms)
|
||||
✔ chat browser: a refusal elsewhere forgets private chat drafts (882.872916ms)
|
||||
✔ chat browser: a late project creation receipt cannot navigate away from another thread (1050.661257ms)
|
||||
✔ C2-09a picker: no silent choice, duplicate hostile labels stay inert, selection survives refresh and reaches POST (1062.688519ms)
|
||||
✔ C2-09a picker: metadata failure, empty set and removed pick explain disabled state and recover without switching (924.988913ms)
|
||||
✔ C2-09a picker: a single instance is chosen explicitly but read-only mode cannot create a thread (781.216726ms)
|
||||
✔ 264e chooser: two sessions keep drafts, cursors, deep links and counts independent (921.256121ms)
|
||||
✔ 264e clear confirmation and status never resend, force-stop or change selection (1103.840292ms)
|
||||
✔ 264e new session keeps its operation key after an unknown response and uses no implicit open (1124.509192ms)
|
||||
✔ 264e cancel shows before/after retirement and never starts or replays work (1599.216909ms)
|
||||
✔ 272 B1: a bad-session deep link preserves the draft and lost clear operation on A (1281.091753ms)
|
||||
✔ C2-09a metadata uses the human listener bus, projects labels only and refuses unauthenticated reads (23.460794ms)
|
||||
✔ C2-09a metadata uses the private tester listener own bus and no human transport (5.122028ms)
|
||||
✔ C2-09a metadata refuses missing or malformed reads and never echoes untrusted fields (5.504868ms)
|
||||
✔ C2-09a metadata stays behind the SSO session check and a GET never refreshes session activity (4.184632ms)
|
||||
✔ chat replies: free text, cites with badges, the agent label, changed since and safe links (898.153564ms)
|
||||
✔ chat replies: a write notice reads as its line with a Revert; a refused revert shows its code (1170.744713ms)
|
||||
✔ chat replies: a read-only Console shows the notice with Revert disabled (850.32112ms)
|
||||
✔ chat status line: served commit and age, divergence, fetch error and the problems one click away (897.997997ms)
|
||||
✔ chat status line: limits when the status carries them, no problems, and refusals (1133.380317ms)
|
||||
✔ chat status line: a project with no repository link reads no library status (854.88335ms)
|
||||
✔ chat status line: unreadable reply limits show their problem and both fallback keys (882.924328ms)
|
||||
✔ chat replies: unchanged file at a different library commit and incomplete checks stay unmarked (768.120005ms)
|
||||
✔ chat status line: an invalid library mapping remains visible for diagnosis (737.619858ms)
|
||||
✔ chat replies: a checked notice-shaped agent message is plain text with no Revert (725.56059ms)
|
||||
✔ chat replies: owner-only without a sent field is a definite Revert refusal (811.129366ms)
|
||||
✔ 272 fallback: granted legacy route keeps default history, send and open without session controls (715.832685ms)
|
||||
✔ 272 fallback guard: granted explicit-session route refuses without default history or writes (631.667619ms)
|
||||
✔ 272 fallback guard: human-required catalog failure never enables default-thread access (663.54337ms)
|
||||
✔ 272 fallback guard: timeout catalog failure never enables default-thread access (537.528495ms)
|
||||
✔ 272 fallback guard: no-bus-host catalog failure never enables default-thread access (622.030953ms)
|
||||
✔ 272 fallback guard: malformed catalog failure never enables default-thread access (624.379398ms)
|
||||
✔ 272 fallback guard: owner route retains chooser and explicit default-session addressing (635.748276ms)
|
||||
✔ chat reads map only fixed verbs, strict forward paging and pure GET (40.110234ms)
|
||||
✔ chat refuses malformed and repeated query/id values before transport (7.000459ms)
|
||||
✔ chat project.create: one verified write, fixed identity/class and private log (2.986922ms)
|
||||
✔ chat project.create: each existing Console write fence makes zero bus calls (8.933369ms)
|
||||
✔ chat project.create: refusal or lost/malformed receipt never retries or invents success (5.056788ms)
|
||||
✔ chat thread.create: one verified write, fixed identity/class and private log (1.581993ms)
|
||||
✔ chat thread.create: each existing Console write fence makes zero bus calls (8.197701ms)
|
||||
✔ chat thread.create: refusal or lost/malformed receipt never retries or invents success (3.965463ms)
|
||||
✔ chat thread.send: one verified write, fixed identity/class and private log (1.353806ms)
|
||||
✔ chat thread.send: each existing Console write fence makes zero bus calls (6.740756ms)
|
||||
✔ chat thread.send: refusal or lost/malformed receipt never retries or invents success (4.970022ms)
|
||||
✔ chat thread.open: one verified write, fixed identity/class and private log (1.438093ms)
|
||||
✔ chat thread.open: each existing Console write fence makes zero bus calls (6.978012ms)
|
||||
✔ chat thread.open: refusal or lost/malformed receipt never retries or invents success (3.64445ms)
|
||||
✔ chat createThread receipt requires an instance even when its id is valid (2.535217ms)
|
||||
✔ chat write receipts expose only the fields belonging to their operation (3.886809ms)
|
||||
✔ chat validates names, body, project and strict empty open payload (5.948932ms)
|
||||
✔ chat read failures redact ownership and refuse invalid transport arrays (7.572799ms)
|
||||
✔ REQ-USER-2 real broker: owned catalog, create/name/filter, isolated history and 403/404 without mutations (108.639676ms)
|
||||
✔ chat repeats every POST boundary even when called behind an admitted request (1.210711ms)
|
||||
✔ configured Console process injects chat through its existing human transport (201.842342ms)
|
||||
✔ chat assets, GET purity, method and unknown-route refusals are explicit (15.908528ms)
|
||||
✔ the chat seam names the transport it is given: the human one and the tester one both pass, anything else is a TypeError (0.594861ms)
|
||||
✔ C2-09a createThread forwards an explicit instance through the existing channel (4.877049ms)
|
||||
✔ C2-09a malformed instance and extra thread fields refuse before the channel write (4.621594ms)
|
||||
✔ 264e session catalog/create and explicit selectors keep the human transport and strict keys (6.446ms)
|
||||
✔ 264e session writes retain Origin/identity fences and explicit selector errors (3.221617ms)
|
||||
✔ 264e clear envelope is projected, pending is preserved and GET never repeats the clear (5.920053ms)
|
||||
✔ 264e cancel is an authenticated, confirmed human write and retains retirement distinction (7.831208ms)
|
||||
✔ 272 N1: malformed clear/cancel write receipts get one redacted outcome-unknown audit line (5.831884ms)
|
||||
✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (1306.1032ms)
|
||||
✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (1836.119679ms)
|
||||
✔ conversation view: a newer session with no readable history keeps the marker (1285.484193ms)
|
||||
✔ conversation view: seats without history say so and offer no reply (1047.035848ms)
|
||||
✔ J16: no controls without sso and decide, read-only reasons, terminal lines kept, and only an eligible grant gets the panel (5771.215266ms)
|
||||
✔ J17: one POST per click, confirm then answer, cancel, refusals and an unknown outcome never retry (5272.178631ms)
|
||||
✔ a sign-in redirect at either step signs the page out and answers nothing (1989.670657ms)
|
||||
✔ a signed-in owner confirms and answers, with the session's provider, issuer and sub as the subject (213.942672ms)
|
||||
✔ the listener gates: no session, a cross-origin page, a loopback Host, a GET, and a sign-out between the steps (77.826712ms)
|
||||
✔ J16: without a decision transport the routes are read-only and /api/config says no; startServer refuses decide without sso or send (481.428976ms)
|
||||
✔ J19: a granted user's session gets decide false and the user page config, and a decision POST stops at owner-only (54.985489ms)
|
||||
✔ N4: decision.resolve has no Console route, the --send caller names no decision verb, and consoleCall takes only the two console verbs (80.240021ms)
|
||||
✔ a confirmation then a resolve answers once with the held choice and digest, and a second resolve refuses (3.814984ms)
|
||||
✔ deny resolves without a grant field (0.482281ms)
|
||||
✔ the gates before the body: method, read-only, sign-in and same origin (0.49765ms)
|
||||
✔ a bad body, id or content type refuses before the bus (0.762162ms)
|
||||
✔ a choice that is neither key is decision-stale, and a malformed preview is confirmation-unavailable (0.681931ms)
|
||||
✔ bus refusals map by code, and an unknown or missing code is unavailable at preview and outcome-unknown at resolve (2.862415ms)
|
||||
✔ a confirmation binds the session, decision and choice, and any mismatch spends it (0.81855ms)
|
||||
✔ a session that ends between the steps refuses before the bus (0.438239ms)
|
||||
✔ confirmations expire after the TTL, cap at the limit without dropping a live one, and are one use (0.323839ms)
|
||||
✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (1065.529279ms)
|
||||
✔ the editor: the list, hostile markdown that runs nothing, the draft, and each save receipt (2140.805191ms)
|
||||
✔ the Console's CSP stands and the editor runs under it; hostile markdown on the load path runs and loads nothing (1354.955091ms)
|
||||
✔ hostile content pasted into the editor runs and loads nothing, and a bad link target is refused in the link bar (1547.923208ms)
|
||||
✔ a pasted image span is kept only for a target the link gate accepts, and a save writes only those (1266.979424ms)
|
||||
✔ a switch of view reads nothing; a reload, and a trip away and back, each read the file exactly once (2940.297024ms)
|
||||
✔ an edit rewrites only the block touched; a save sends the rest byte for byte; the Source view carries the draft (1214.212642ms)
|
||||
✔ a file the editor cannot write back byte for byte opens as Source, says so, cannot save, and the Visual button works once it can (2204.177601ms)
|
||||
✔ a link title pasted with line breaks in it is written on one line, so no HTML block comes of it (954.989036ms)
|
||||
✔ an image alt pasted with line breaks in it is written on one line, so no HTML block comes of it (876.671026ms)
|
||||
✔ an image title pasted with line breaks in it is written on one line, so no HTML block comes of it (876.342459ms)
|
||||
✔ a code block info string pasted with line breaks in it is written on one line, so no HTML block comes of it (851.548483ms)
|
||||
✔ a link title holding a quote after a backslash then a tag is written with the backslash escaped, so the title stays closed (973.526659ms)
|
||||
✔ an image title holding a quote after a backslash then a tag is written with the backslash escaped, so the title stays closed (730.164235ms)
|
||||
✔ a link title holding a trailing backslash is written with the backslash escaped, so the title stays closed (705.431094ms)
|
||||
✔ an image title holding a trailing backslash is written with the backslash escaped, so the title stays closed (716.592245ms)
|
||||
✔ a code block info string with a backtick, pasted, is dropped on Save, so the fence stays closed (764.08523ms)
|
||||
✔ a code block info string with a backtick, as a tilde fence can have, is kept as source, not rewritten without it (846.538059ms)
|
||||
✔ the imported source is the tagged upstream source plus the recorded local changes, and nothing else (26.175796ms)
|
||||
✔ every package names its origin and license, and NOTICE lists each (1.097644ms)
|
||||
✔ the build reads only imported source and the editor's own files; the bundle is the recorded build (8.957963ms)
|
||||
✔ MOSAIC_REQUIRE_EDITOR_BUILD: a missing or wrong esbuild skips without it and fails with it; a wrong binary always fails (7.544758ms)
|
||||
✔ the toolchain check, run as a program, exits non-zero without esbuild when the build is required (302.664165ms)
|
||||
▲ [WARNING] Ignoring this import because "third_party/editor/prosemirror-transform/src/mark.ts" was marked as having no side effects [ignored-bare-import]
|
||||
|
||||
third_party/editor/prosemirror-transform/src/index.ts:10:7:
|
||||
10 │ import "./mark"
|
||||
╵ ~~~~~~~~
|
||||
|
||||
"sideEffects" is false in the enclosing "package.json" file:
|
||||
|
||||
third_party/editor/prosemirror-transform/package.json:13:2:
|
||||
13 │ "sideEffects": false,
|
||||
╵ ~~~~~~~~~~~~~
|
||||
|
||||
✔ rebuilding from the source gives the same bytes (needs the pinned esbuild; MOSAIC_REQUIRE_EDITOR_BUILD=1 makes its absence a failure) (172.641917ms)
|
||||
✔ wikilink round-trip: plain (9.175577ms)
|
||||
✔ wikilink round-trip: labelled (1.129295ms)
|
||||
✔ wikilink round-trip: heading target (1.25613ms)
|
||||
✔ wikilink round-trip: list item (1.645832ms)
|
||||
✔ wikilink round-trip: next to front matter (1.202128ms)
|
||||
✔ wikilink round-trip: heading block and combined label (1.18696ms)
|
||||
✔ wikilink round-trip: spaces, Unicode and adjacent links (2.377579ms)
|
||||
✔ wikilink round-trip: reference-definition collision (2.902031ms)
|
||||
✔ wikilink round-trip: inside an ordinary link (4.241793ms)
|
||||
✔ wikilink round-trip: inert embed (0.63341ms)
|
||||
✔ wikilinks are inline atoms and survive a neighbouring edit in every required context (1556.425084ms)
|
||||
✔ code, escaped openers, malformed syntax and HTML-like targets stay outside wikilink atoms (1452.825353ms)
|
||||
✔ wikilink DOM paste accepts only bounded single-line inert syntax; malformed attrs serialise as escaped text (1000.711061ms)
|
||||
✔ the editor routes serve the built files with their types and no cache (46.893995ms)
|
||||
✔ open and save with no edit writes the same bytes: the goals review and a doc with every element (21.572081ms)
|
||||
✔ open and save with no edit writes the same bytes: every repository doc under docs/ and spec/ (2160.196477ms)
|
||||
✔ the editor source builds markup only with DOM calls, and the bundle has no eval (4.311024ms)
|
||||
✔ the link gate and the image rule are the preview's (1.175245ms)
|
||||
✔ R6 G1 a granted user signs in, gets the user page and reaches the broker as itself (172.773172ms)
|
||||
▶ R6 G2 a subject with no live grant in this business is refused subject-unknown
|
||||
✔ a listed user with no grant (92.602053ms)
|
||||
✔ a grant in another business (104.491345ms)
|
||||
✔ an expired grant (114.256083ms)
|
||||
✔ another user's grant (55.98006ms)
|
||||
✔ a sub in no file (64.883816ms)
|
||||
✔ a file the loader refuses (90.210241ms)
|
||||
✔ R6 G2 a subject with no live grant in this business is refused subject-unknown (523.697455ms)
|
||||
▶ R6 G3 a revoke counts on the next request: 401 and the session is gone
|
||||
✔ grant removed (62.972504ms)
|
||||
✔ subject removed (93.888865ms)
|
||||
✔ grant expired (106.472694ms)
|
||||
✔ file now refused (112.582013ms)
|
||||
✔ R6 G3 a revoke counts on the next request: 401 and the session is gone (377.178827ms)
|
||||
✔ R6 G4 every owner route answers 403 owner-only before any bus call (127.865636ms)
|
||||
✔ R6 G5 the bus refuses every owner verb over the user transport on its own (123.119351ms)
|
||||
✔ R6 G9 a user chat sends only the plugins read over the owner transport (130.557956ms)
|
||||
✔ R6 G6 the user page holds the notice word for word (75.808533ms)
|
||||
✔ R6 G7 the hub label and plain peer links render from config on both pages (984.121102ms)
|
||||
✔ R6 G8 userCall spawns user-cli directly with the user nonce, no human nonce, and the user request (51.702992ms)
|
||||
✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (52842.755773ms)
|
||||
✔ row 165 Settings: role instances read, add with a restart named, change without one, a refusal keeps the draft (2069.883646ms)
|
||||
✔ row 165 Console: the signed-in human adds an instance through a real broker; validate exits 0, the log names the human and no restart is needed (row 194) (261.303304ms)
|
||||
✔ row 165 Console: the instance write needs send on, the public name, the user, the exact Origin and same-origin Fetch Metadata (10.054646ms)
|
||||
✔ row 165 Console: the instance write takes JSON within 16 KiB and only its own keys; holder, credentials and an actor are refused (9.747938ms)
|
||||
✔ row 165 Console: a bus refusal says nothing changed; a lost or odd answer says the change may have been made (15.879235ms)
|
||||
✔ row 165 Console: the instances read takes no arguments, needs a bus and refuses an answer without a revision (6.37516ms)
|
||||
✔ C2-04 CLI: both listener callback pairs dispatch library verbs with their own transport (208.823243ms)
|
||||
✔ a signed-in same-origin revert reaches exactly one library.revert and returns the new commit (25.090439ms)
|
||||
✔ a revert needs send, the named Host, the user, the exact Origin and same-origin Fetch Metadata (8.67138ms)
|
||||
✔ a revert takes a project and a 40-hex commit, nothing else, before the bus is asked (7.475126ms)
|
||||
✔ a bus refusal is reported as not reverted with its code; before C2-02 that is the verb refusal (9.725112ms)
|
||||
✔ a revert whose answer is lost or unusable is reported unknown and is never retried (7.701918ms)
|
||||
✔ the status read takes one project query and answers the bus result for that project (4.432751ms)
|
||||
✔ a status answer for another project or of the wrong shape is refused; a refusal keeps its status (9.479692ms)
|
||||
✔ the status read needs no send; a read-only Console still has no revert (2.316938ms)
|
||||
✔ library routes are the owner's: a granted user is refused them, and the tester never reverts (0.874467ms)
|
||||
✔ the page gets the one library renderer, byte for byte, as a JavaScript module (1.946831ms)
|
||||
✔ a revert receipt for another project is unknown and is never retried (1.698516ms)
|
||||
✔ a granted-user HTTP session cannot reach owner library callbacks (2.11729ms)
|
||||
✔ a configured revert callback remains unreachable when send is off (1.619535ms)
|
||||
✔ row 254: each library sync code maps to its status (0.875525ms)
|
||||
✔ REQ-LIMIT-3 REQ-LIMIT-4 Settings shows token limits counted, not enforced and check failed; Reset posts one path; a save keeps the token limits (1283.613274ms)
|
||||
✔ Row 167 with an assistant draft open, a token limit reset gives the assistant submit its revision (951.959609ms)
|
||||
✔ REQ-LIMIT-3 limits read returns only the token rows; no query or write is accepted (36.003397ms)
|
||||
✔ REQ-LIMIT-3 a limits answer without a token list is refused, not shown as no limits (11.374745ms)
|
||||
2026-10-24T22:11:16.186Z settings user="jason" changed
|
||||
✔ REQ-LIMIT-3 a Settings reset reaches the human write with its paths; a reset alone is enough (7.465903ms)
|
||||
✔ REQ-LIMIT-3 the Console reader asks the bus limits verb with no arguments (0.460687ms)
|
||||
✔ the preview source names none of the four string-to-markup sinks (1.2239ms)
|
||||
✔ headings, paragraphs, emphasis and inline code render (1.52146ms)
|
||||
✔ lists, block quotes and code blocks render (0.569678ms)
|
||||
✔ a link is made for http, https and relative targets, with rel and the target shown (1.167267ms)
|
||||
✔ a link with any other scheme, or an evasion of the scheme, stays source text (1.071465ms)
|
||||
✔ an image shows alt text and URL, is never an img element and never loads (0.176798ms)
|
||||
✔ raw HTML, entities and unsupported blocks show as source text, never as elements (0.390592ms)
|
||||
✔ markup inside code and inside link text stays text (0.199256ms)
|
||||
✔ hostile and pathological input stays within its look-ahead budget and under the nesting cap (48.760884ms)
|
||||
✔ trailing blanks and closing hashes are cut by a walk from the end, not a regex that retries inside a blank run (35.531804ms)
|
||||
✔ a link opener with no closer searches at most SPAN characters ahead (188.875275ms)
|
||||
✔ the look-ahead work of one render is a fixed multiple of the text, whatever the opener (848.275978ms)
|
||||
✔ past the budget an opener is source text, through the path all other text takes (17.235886ms)
|
||||
✔ a normal 200 KiB document renders exactly as it did without a budget, and spends little of it (25.044171ms)
|
||||
✔ a line separator inside a heading, a list item or a fence line does not end the marker line (0.595681ms)
|
||||
✔ a thematic-break line is a paragraph, every other marker line opens a list (0.433323ms)
|
||||
✔ every short line over space, tab, - * _ and a letter is a break exactly when the old regex said so (48.393695ms)
|
||||
✔ one line of marks does not throw, at 4 MiB, whatever the mark or the spacing (7867.726504ms)
|
||||
✔ CRLF and tabs are read like LF and spaces; empty input renders nothing (0.182135ms)
|
||||
✔ messages HTTP read pages and preserves metadata; bad arguments refuse before a read; other reads unchanged (114.721485ms)
|
||||
✔ Console Messages lists late unsolicited messages on polling with sender class time read state and trail; nav count includes beyond the page; reads never deliver (1227.204744ms)
|
||||
✔ Messages nav count polls on Tasks and Board and clears on a Board refusal; messages 403 refuses local pages (2003.078514ms)
|
||||
✔ copy writes the Console paths at the full id, read-only, and leaves an existing copy alone (1488.436066ms)
|
||||
✔ copy refuses a commit off refactor, an unknown one, a worktree and a bad copies directory (1597.975802ms)
|
||||
✔ copy writes nothing when an archived path is missing at the commit (579.510216ms)
|
||||
✔ a copy that loses the rename race leaves no read-only temp directory behind (673.135629ms)
|
||||
✔ a copy whose rename fails with no target refuses, writes no copy and leaves no temp directory (710.289827ms)
|
||||
✔ a copy that meets a target holding files says exists: and moves nothing into it (732.806597ms)
|
||||
✔ a copy that meets an empty target directory replaces it by rename, not by moving into it (612.835517ms)
|
||||
✔ serve runs from a copy: /healthz 200, the config check, roles and RELEASE from the copy, the queue from --checkout (1149.224132ms)
|
||||
✔ serve refuses a --checkout that is not an absolute directory path (375.216061ms)
|
||||
✔ consoleReads runs the queue read under queueRoot and reads RELEASE under root (69.061909ms)
|
||||
✔ preview options are all three or none, and each is checked (11.596651ms)
|
||||
✔ the CLI refuses a partial or invalid preview flag set at start (945.562554ms)
|
||||
✔ the CLI with all three flags serves the preview mode (193.560054ms)
|
||||
✔ a request for the public name needs the header equal to the user id, else 401 and nothing read (21.565508ms)
|
||||
✔ the header name matches without regard to case, and the value compare is exact (3.95808ms)
|
||||
✔ the public name with the header reads the bus views, and the Host and Origin are checked first (33.216972ms)
|
||||
✔ in preview mode every write answers 403 read-only, from the public name and loopback, and reaches nothing (13.946391ms)
|
||||
✔ loopback requests are unchanged in preview mode, and the bus views work with the board down (21.317768ms)
|
||||
✔ a proxy that rewrites Host to the loopback port gets 403 on its first request, whatever the user (20.422653ms)
|
||||
✔ a repeated Host is 400 before any other check, in preview mode and without it (11.215391ms)
|
||||
✔ without the preview flags the public name is refused and writes still reach the board (5.587922ms)
|
||||
✔ processing browser: keyboard Stop, confirmed Resume, unknown outcome and persistent banner (718.01676ms)
|
||||
✔ processing browser: Q175 read-only interim keeps both writes disabled and names CLI recovery at 320px (695.148762ms)
|
||||
✔ processing browser: sign-out from config redirect blocks later refresh and writes (824.165228ms)
|
||||
✔ processing browser: sign-out from state redirect blocks later refresh and writes (860.253673ms)
|
||||
✔ processing browser: sign-out from write redirect blocks later refresh and writes (806.441355ms)
|
||||
✔ processing browser: sign-out from config sign-in required blocks later refresh and writes (864.004948ms)
|
||||
✔ processing browser: sign-out from state sign-in required blocks later refresh and writes (886.919472ms)
|
||||
✔ processing browser: sign-out from write sign-in required blocks later refresh and writes (960.067268ms)
|
||||
ROW191_LAYOUT {"width":400,"height":1000,"controls":97,"tree":324.0625,"main":1450.703125,"top":181.5,"bottom":217.5,"barBottom":129,"projectsTop":352.59375,"order":"0","visible":true}
|
||||
ROW191_LAYOUT {"width":1440,"height":1000,"controls":127,"tree":914,"main":914,"top":135.5,"bottom":171.5,"barBottom":53,"projectsTop":636.59375,"order":"0","visible":true}
|
||||
ROW191_LAYOUT {"width":1440,"height":420,"controls":127,"tree":334,"main":907.734375,"top":135.5,"bottom":171.5,"barBottom":53,"projectsTop":636.59375,"order":"0","visible":true}
|
||||
ROW191_LAYOUT {"width":800,"height":420,"controls":127,"tree":334,"main":1131.65625,"top":135.5,"bottom":171.5,"barBottom":53,"projectsTop":618.59375,"order":"0","visible":true}
|
||||
✔ processing browser: static nav controls keep Stop visible, ordered and keyboard reachable (764.42746ms)
|
||||
✔ interim read-only controls show CLI recovery, disable both writes and retain a halted banner across views (8.191348ms)
|
||||
✔ Stop sends one empty halt and Resume confirms before sending the displayed generation (2.947603ms)
|
||||
✔ a cancelled resume never calls the writer (1.219134ms)
|
||||
✔ unknown writes are not retried or displayed as success and partial stops remain explicit (2.112188ms)
|
||||
✔ the persistent shell loads the control outside route-specific content with accessible status and native buttons (0.471441ms)
|
||||
✔ read-only Console can read processing state but neither human control writes without --send (23.636966ms)
|
||||
✔ Console halt and generation-bound resume use only the management writer and keep partial stops honest (4.923203ms)
|
||||
✔ processing write fences refuse cross-site, wrong origin, unnamed host, duplicate identity and bad payload before writer (7.499038ms)
|
||||
✔ tester cannot invoke either control writer and failures never echo backend text (5.000005ms)
|
||||
✔ processing writes use the existing SSO signer and still require --send and same-origin (5.29471ms)
|
||||
✔ processing handler independently refuses wrong origin and cross-site before its writer (0.741847ms)
|
||||
✔ a signed-in same-origin save reaches exactly one human operation and returns the new commit (22.355345ms)
|
||||
✔ a save needs send, the named Host, the user, the exact Origin and same-origin Fetch Metadata (8.492884ms)
|
||||
✔ a save validates JSON, strict keys, text values and the 1 MiB body before the bus is asked (19.453599ms)
|
||||
✔ a body that is JSON but not an object is refused 400, not thrown on (5.777613ms)
|
||||
✔ the 1 MiB limit is this route only; Settings and messages keep 16 KiB (2.581226ms)
|
||||
✔ a bus refusal is reported as not saved with its own status; stale-base tells the user to reload (6.148622ms)
|
||||
✔ a save whose answer is lost or unusable is reported unknown and is never retried (3.873987ms)
|
||||
✔ the file list and one file read take strict queries and arrive in the expected shape (4.947705ms)
|
||||
✔ reads work without --send; an unusable bus answer is a bad response, a refusal keeps its status (3.061043ms)
|
||||
✔ /api/config says edit only where a save can pass (2.093648ms)
|
||||
✔ a repository-name project refusal is an HTTP conflict (0.589542ms)
|
||||
✔ proof startup refuses partial flags non-preview and invalid fixture file metadata or bytes (1372.358151ms)
|
||||
✔ serve argv carries only fixture proof path and header; startup explicitly reports proof on or off (296.532456ms)
|
||||
✔ CLI applies proof on the main listener and rejects that header on its tester listener (281.757503ms)
|
||||
✔ proxy proof admits named reads and sends, reads its fixture once, and never exposes the value (34.129527ms)
|
||||
✔ proxy proof refuses missing wrong short or repeated proof before auth and before any read (10.977149ms)
|
||||
✔ proxy proof header is refused on other Hosts and on the tester listener (5.374102ms)
|
||||
✔ proof options reject unsafe or colliding header names without disclosing file contents (0.797857ms)
|
||||
✔ redactor: config, dataRoot, any absolute path, Discord ids and the JSON parser quote (1.703483ms)
|
||||
✔ credential state from the date alone, as the bus states it (0.208011ms)
|
||||
✔ queue: rows, one row, ids and methods, notes; no path or id from a row (414.58832ms)
|
||||
✔ queue: a refused read fails closed with the store's text, redacted (210.374206ms)
|
||||
✔ queue: a store that fails to load, or a child that dies, gives a fixed message with no path or stack (858.43953ms)
|
||||
✔ business: names, vars on the allowlist, authority, credential metadata only (17.500331ms)
|
||||
✔ business: missing or invalid file refuses with the module's text, redacted (8.383354ms)
|
||||
✔ business without --business: the live bus host, else no-bus-host; no system config: not-configured (8.244873ms)
|
||||
✔ settings: release, board, loopback address, notifier binding name only (129.222379ms)
|
||||
✔ task fields: the committed table with no reads configured, GET only; a bad table refuses with no path (18.325509ms)
|
||||
✔ bus-status: a refused boot shows reason, file and last good load; a live host or an ok boot clears it (8.620563ms)
|
||||
✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (912.269858ms)
|
||||
✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (20871.244615ms)
|
||||
organization: {"event":"reload-needs-restart","business":"acme"}
|
||||
organization: {"event":"reload-needs-restart","business":"acme"}
|
||||
✔ row 65 Settings: the routing table lists every instance, saves a harness, model, thinking and fallback to the file, and keeps the draft on each refusal (1456.057342ms)
|
||||
organization: {"event":"reload-needs-restart","business":"acme"}
|
||||
✔ row 65 Console: the signed-in human saves a route through a real broker; each refusal says nothing changed and leaves the file and the log (124.733405ms)
|
||||
✔ row 65 Console: the routes write needs send on, a writer, the public name, the user, the exact Origin and same-origin Fetch Metadata (7.984846ms)
|
||||
✔ row 65 Console: the routes write takes JSON within 16 KiB with a revision and routes only; an actor is refused and routes are never logged (9.931147ms)
|
||||
✔ row 65 Console: a bus refusal maps to its status and says nothing changed; a lost or odd answer says the change may have been made (24.176558ms)
|
||||
✔ row 65 Console: the routes read takes no arguments, needs a bus and refuses an odd answer (7.91025ms)
|
||||
✔ the send box: held roles, the draft and caret across a refresh, each receipt, one POST per Send, and the trail link; the board Reply on a 4xx and a 5xx (2577.785116ms)
|
||||
✔ a sent receipt lists its replies as the page refreshes, oldest first and capped, and marks none delivered or read (11216.600397ms)
|
||||
✔ startServer takes send only as a function and only with the preview mode (8.305533ms)
|
||||
✔ the CLI refuses --send without the preview flags, and without a configured bus (622.972543ms)
|
||||
✔ the CLI with --send and a configured bus sends through the human transport and logs one line (188.71069ms)
|
||||
✔ without --send the route is read-only like every other write, and config says no send (10.412469ms)
|
||||
✔ with --send every other write is still 403 read-only, and nothing reaches the board or bus (8.881331ms)
|
||||
✔ config says send only on the public name with --send on (4.624696ms)
|
||||
✔ a send without the signed-in user is 401 and is neither sent nor logged, loopback included (6.736458ms)
|
||||
✔ each request check refuses before anything is sent, and logs the refusal without the body (23.776724ms)
|
||||
✔ a send passes exactly to, body and in_reply_to, answers the id, and logs it (3.435425ms)
|
||||
✔ a crafted role name cannot forge a log line (2.520457ms)
|
||||
✔ a bus refusal is not sent, with its status; an outcome the bus could not confirm is unknown and never retried (8.782419ms)
|
||||
✔ through the human transport the request is exactly the business, message.send and the keys (100.281561ms)
|
||||
✔ against a real broker: the message is written once as a human send, and its refusals map (31.579317ms)
|
||||
✔ loopback host and board origin fail closed (6.349957ms)
|
||||
✔ real board fixture passes through WebUI; assets and isolated seen/reply work (85.238919ms)
|
||||
✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (49.199627ms)
|
||||
✔ unreachable board reports URL; CLI rejects unsupported options (479.978274ms)
|
||||
✔ tester service render carries the tester port alongside existing flags (134.959305ms)
|
||||
✔ tester service refuses forwarded 7332 even with another main port (111.314937ms)
|
||||
✔ tester service invalid ports refuse render and install with exit 4 and leave the unit alone (1140.951065ms)
|
||||
✔ tester service counts the digits as written before it strips leading zeros (106.037477ms)
|
||||
✔ tester service install and status show the tester port without changing send reporting (550.730447ms)
|
||||
✔ render prints the unit without the preview flags (50.043501ms)
|
||||
✔ render carries every serve flag, the preview set included (48.3057ms)
|
||||
✔ a partial preview set is refused (116.014202ms)
|
||||
✔ a value the unit cannot carry is refused, for every flag (2672.644014ms)
|
||||
✔ the rendered unit names none of the human proof agent markers and sets no agent variable (239.356908ms)
|
||||
✔ install into --dir with --no-reload writes the file whole, then reports unchanged (287.45407ms)
|
||||
✔ install without --no-reload runs daemon-reload and nothing that starts the unit (62.23267ms)
|
||||
✔ uninstall refuses while the unit is running, with or without --no-reload, and removes it once it is not (564.150662ms)
|
||||
✔ status prints the unit state and GET /healthz on the installed port (418.000891ms)
|
||||
✔ usage: an unknown verb or flag, and start or enable, exit 4 (748.152129ms)
|
||||
✔ without --send, render is the template with its placeholders filled, byte for byte (191.946387ms)
|
||||
✔ render --send with the preview set ends ExecStart with --send and changes nothing else (314.493899ms)
|
||||
✔ --send without the whole preview set is refused and writes nothing (731.918561ms)
|
||||
✔ install --send into --dir with --no-reload writes the sending unit, and status says whether it sends (513.043402ms)
|
||||
✔ uninstall and status take no --send (164.863424ms)
|
||||
✔ install refuses while the unit is running, in any state but inactive or failed, and changes nothing (697.765957ms)
|
||||
✔ when the state read fails, install and uninstall refuse with one line and change nothing (238.392922ms)
|
||||
✔ install needs --copy naming a copy that exists, and refuses outside the canonical checkout without --allow-worktree (355.132277ms)
|
||||
✔ install refuses unless the bus unit runs from the same copy, naming both paths, and changes nothing (735.389915ms)
|
||||
✔ render --copy runs the copy and reads the queue in the checkout; without --copy the unit is unchanged (114.218835ms)
|
||||
✔ the uid header takes only an Authentik uid; the username header still takes a username (2531.254234ms)
|
||||
✔ a preview value cannot start with - or . (295.955168ms)
|
||||
✔ status names the copy and whether refactor has moved past it, and says when the unit runs from no copy (877.622422ms)
|
||||
✔ proxy proof render carries both flags but never opens the fixture file (89.223556ms)
|
||||
✔ proxy proof render refuses incomplete non-preview missing unsafe-mode and repo/copy paths (565.728452ms)
|
||||
✔ proxy proof status retains send and tester reporting with both proof flags (170.319152ms)
|
||||
✔ row196 socket flag renders only for supporting targets and refuses mixed transports (114.439527ms)
|
||||
✔ Settings form shows every scope and held role; gated save, exact payload, retained draft and no automatic retry (1360.394114ms)
|
||||
✔ Q169 Assistant section: gated, changed fields only, name and stop posts, retained draft and no automatic retry (1339.787079ms)
|
||||
✔ Row 167 a refused names read gives the refused usage page; another names failure keeps the Assistant section (1001.13625ms)
|
||||
✔ Row 167 with a limits draft open, an assistant save gives the limits submit its revision and the typed limit stays (961.46178ms)
|
||||
✔ Row 167 with an assistant draft open, a launch save gives the assistant submit its revision, and reload reads the current one (919.499255ms)
|
||||
2026-10-24T22:12:18.574Z settings user="jason" changed
|
||||
✔ REQ-WEB-1 signed-in same-origin Settings write reaches exactly one human operation (20.814698ms)
|
||||
✔ REQ-WEB-1 Settings writes require enabled send, named Host, identity, exact Origin and same-origin Fetch Metadata (7.338296ms)
|
||||
✔ REQ-WEB-1 Settings validates JSON, size, revision and strict writable keys before broker call (5.704514ms)
|
||||
✔ Q169 a Console change of the assistant reaches the human operation unchanged, and the log names the signed-in user (3.12922ms)
|
||||
✔ tokens.css and icons.svg are byte copies of docs/design (2.466959ms)
|
||||
✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.202837ms)
|
||||
✔ shipped strings are unchanged, and the web keeps its write boundary (3.483166ms)
|
||||
ROW191_LAYOUT {"width":1440,"height":1000,"controls":212.5,"tree":914,"main":914}
|
||||
✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (5724.337234ms)
|
||||
✔ five states on Board, Inbox, Tasks, Agents and Trail (2781.461551ms)
|
||||
✔ a 401 sign-in required on each fetch path signs the page out with a sign-in link and stops the refresh; another 401 stays an error (5951.403032ms)
|
||||
✔ the Sign out form shows only when /api/config says sso, and posts to /auth/logout (1240.276745ms)
|
||||
✔ positive: an RS256 provider signs in and sends one message, and the session reads (144.348303ms)
|
||||
✔ positive: an ES256 provider signs in and sends (20.592669ms)
|
||||
✔ positive: two providers each sign in their own subjects, and one provider's subject is unknown to the other (61.371982ms)
|
||||
✔ 1: a forged x-authentik header without a cookie is 401 on the API and a sign-in redirect on a page (43.593455ms)
|
||||
✔ 2: an HS256 ID token keyed with the client secret and a real RSA kid is refused (73.089469ms)
|
||||
✔ 3: a wrong aud, and an aud list holding another client with no azp, are refused (33.086381ms)
|
||||
✔ 4: a token that expired 10 minutes ago is refused (63.584637ms)
|
||||
✔ 5: another issuer, and the issuer without its trailing slash, are refused (48.311745ms)
|
||||
✔ 6: a nonce mismatch and a missing nonce are refused (27.913813ms)
|
||||
✔ 7: state mismatch, no login cookie, a replay, an expired record and two login cookies are refused (67.213632ms)
|
||||
✔ 8: the token request carries the PKCE verifier, and the OP refuses a wrong one (46.450232ms)
|
||||
✔ 9: alg none, a changed payload under a real kid, and an unknown kid even after the refetch are refused (208.50079ms)
|
||||
✔ 10: a valid token for a subject not configured is 403 with one subject-unknown line (114.43639ms)
|
||||
✔ 11: start refusals: HS or none algs, reserved names, HS-only discovery, an empty JWKS, no S256, an issuer mismatch, a short RSA key (276.730279ms)
|
||||
✔ 11: slot files: a symlink, mode 0644, mode 0640 and a file under the repository are refused, and no message holds the value (2.126877ms)
|
||||
✔ 11: the CLI refuses --sso with the old flags and without console.sso, and starts with a good one (1317.326217ms)
|
||||
✔ 12: under --sso the tester listener refuses each kind of sign-in, has no /auth, and startServer refuses tester with sso (61.815926ms)
|
||||
✔ 13: idle and absolute expiry, logout then reuse, a cross-origin logout, and background reads that don't keep a session (112.338051ms)
|
||||
✔ 13: the CSP lets the Sign out form reach the provider's end-session origin, and only under --sso (136.264868ms)
|
||||
✔ 14: open redirects land on /, and a path on the Console lands there (125.077087ms)
|
||||
✔ 15: a callback for A carrying B's code and iss, and a provider= query, is refused (114.160441ms)
|
||||
✔ 16: a provider with RS256 and ES256 takes either, and refuses PS256 with a usable PS256 key in the JWKS (111.659664ms)
|
||||
✔ 17: 33 started logins leave 32 records, and the first one's callback finds none (59.820684ms)
|
||||
✔ 18: after a key rotation a sign-in works through one refetch, and the removed kid is refused (119.662583ms)
|
||||
✔ 20 and 21: the store holds no raw session id, and the cookie strings are exact (36.447359ms)
|
||||
✔ 22: a loopback Host is 403 on a page, a read and a write; /healthz on loopback is 200; a redirect_uri never comes from the Host (64.398495ms)
|
||||
✔ 23: a provider down at start leaves the Console up and 503, and the retry makes sign-in work (225.671097ms)
|
||||
✔ 19: no captured log line holds a token, code, state, nonce, verifier, client secret or session id (4.654356ms)
|
||||
✔ tester Console banner exposes only instance route and name editors and saves a route as tester (1004.885424ms)
|
||||
✔ row 177: the tester Console chat composer is enabled and a send shows in its own thread (882.644221ms)
|
||||
✔ tester-port validates range tunnel main port and requires configured bus before listening (1166.339822ms)
|
||||
✔ CLI tester listener binds a private Unix socket and spawns TESTER_CLI for every Console bus read (4245.099179ms)
|
||||
✔ main listener refuses x-mosaic-tester before any board or bus read for every Host (28.708091ms)
|
||||
✔ tester listener rejects preview binding and requires its fixed logical Host and no proxy auth header (145.683675ms)
|
||||
✔ tester listener writes only instances routes and names with tester receipts and actor (158.995936ms)
|
||||
✔ tester listener refuses every human-only write with no bus call (108.260486ms)
|
||||
✔ tester-off and tester-required reads return HTTP 403 (109.020476ms)
|
||||
✔ tester credentials routes and committed project reads keep secrets and paths bounded (194.378994ms)
|
||||
✔ row 177 W1: the tester chat makes, sends to, opens and reads its own thread as tester (30.75864ms)
|
||||
✔ row 177 W2: tester chat writes refuse a missing or foreign Origin, cross-site, text/plain and the proxy header with no bus call (16.544702ms)
|
||||
✔ row 177 W3: the human thread through the tester chat is thread-not-owned, and bus.tester off answers tester-off (38.09277ms)
|
||||
✔ row 177 W4: the main listener refuses x-mosaic-tester on chat reads and writes before the chat (3.174145ms)
|
||||
✔ Row 252: the tester listener has no decision answer routes, and its config never offers them (115.156837ms)
|
||||
✔ private tester HTTP serves on 0600 socket in 0700 parent and fixed origin (92.027264ms)
|
||||
✔ private tester refuses symlink, unsafe parent and long path without repairs (1.361981ms)
|
||||
✔ tester cleanup must leave a replacement inode untouched (1.910765ms)
|
||||
✔ row278 browser lists held claims and release preserves role rows and totals (847.359938ms)
|
||||
✔ row278 browser claims 403 stays local and role section remains byte-equal (894.870976ms)
|
||||
✔ row278 browser renders only four escaped claim fields and never instance or other extras (843.980149ms)
|
||||
✔ row278 browser sign-out removes claims and prevents reuse of cached answers (893.668522ms)
|
||||
✔ row278 tester browser keeps role rows without requesting the owner claims section (787.543169ms)
|
||||
✔ row278 browser discards a late claims answer after sign-out (921.720447ms)
|
||||
✔ row278 HTTP read returns held claims without send and refuses arguments before the bus (53.230904ms)
|
||||
✔ row278 HTTP read preserves bus refusal and rejects a malformed result (16.041697ms)
|
||||
✔ row278 tester socket refuses thread claims explicitly with zero bus calls (7.920469ms)
|
||||
✔ row278 Console adapter calls argument-free thread.claims through the normal transport (234.138591ms)
|
||||
✔ 193d HTTP shares use the caller, plain/shared lists, exact args and write fences (101.289213ms)
|
||||
✔ 193d config supplies only the signed-in user live collaborator scopes and updates on downgrade (42.033352ms)
|
||||
✔ 193d viewer UI has no composer, resume, share, session mutations or create controls (924.760539ms)
|
||||
✔ 193d mixed grants keep viewer project read-only and collaborator own thread writable; downgrade hides controls (953.979736ms)
|
||||
✔ 193d owner has share controls on own threads and shared threads remain read-only (790.551799ms)
|
||||
✔ 193d bypassed UI checks still reach a refusing bus for every viewer write (788.861611ms)
|
||||
✔ 193d collaborator shares stay read-only and never expose reshare or wake controls (581.454324ms)
|
||||
✔ REQ-LIMIT-4 Settings shows all token kinds and unknown turns beside every total, as a read-only separate section (995.953487ms)
|
||||
✔ REQ-WEB-1 usage read keeps unknown counts and each token kind; no query or write is accepted (45.120159ms)
|
||||
✔ REQ-WEB-1 malformed usage is refused instead of shown as zero (8.503528ms)
|
||||
✔ R6-N1 with the userRoute gate open, a user session reaches no owner option over HTTP (253.639899ms)
|
||||
✔ Queue, Business and Settings in their five states, with no move button (3486.52394ms)
|
||||
✔ seeded secrets, Discord ids and paths reach no response and no page; business refusals in the module's words (1584.02624ms)
|
||||
✔ the server log names no config path when the system config refuses (369.222452ms)
|
||||
ℹ tests 455
|
||||
ℹ suites 0
|
||||
ℹ pass 455
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 174122.853398
|
||||
@@ -0,0 +1,69 @@
|
||||
tests/agents-browser.test.mjs
|
||||
tests/agents.test.mjs
|
||||
tests/assistant.test.mjs
|
||||
tests/board-held.test.mjs
|
||||
tests/browser-edge.test.mjs
|
||||
tests/browser.test.mjs
|
||||
tests/bus-browser.test.mjs
|
||||
tests/bus.test.mjs
|
||||
tests/channel-chat.test.mjs
|
||||
tests/chat-browser.test.mjs
|
||||
tests/chat-instances.test.mjs
|
||||
tests/chat-replies-browser.test.mjs
|
||||
tests/chat-sessions-access.test.mjs
|
||||
tests/chat.test.mjs
|
||||
tests/conversation.test.mjs
|
||||
tests/decide-browser.test.mjs
|
||||
tests/decide-sso.test.mjs
|
||||
tests/decision-http.test.mjs
|
||||
tests/discord.test.mjs
|
||||
tests/docs-browser.test.mjs
|
||||
tests/editor-browser.test.mjs
|
||||
tests/editor-provenance.test.mjs
|
||||
tests/editor-wikilink.test.mjs
|
||||
tests/editor.test.mjs
|
||||
tests/granted-user.test.mjs
|
||||
tests/history-return-flow.test.mjs
|
||||
tests/instances-browser.test.mjs
|
||||
tests/instances.test.mjs
|
||||
tests/library-cli.test.mjs
|
||||
tests/library-routes.test.mjs
|
||||
tests/library-status.test.mjs
|
||||
tests/limits-browser.test.mjs
|
||||
tests/limits-route.test.mjs
|
||||
tests/markdown-preview.test.mjs
|
||||
tests/messages.test.mjs
|
||||
tests/pinned-copy.test.mjs
|
||||
tests/preview.test.mjs
|
||||
tests/processing-browser.test.mjs
|
||||
tests/processing-ui.test.mjs
|
||||
tests/processing.test.mjs
|
||||
tests/project-file.test.mjs
|
||||
tests/project-name-repo.test.mjs
|
||||
tests/proof-cli.test.mjs
|
||||
tests/proof.test.mjs
|
||||
tests/reads.test.mjs
|
||||
tests/relaunch.test.mjs
|
||||
tests/return-flow.test.mjs
|
||||
tests/routes-browser.test.mjs
|
||||
tests/routes.test.mjs
|
||||
tests/send-browser.test.mjs
|
||||
tests/send.test.mjs
|
||||
tests/serve.test.mjs
|
||||
tests/service.test.mjs
|
||||
tests/settings-form.test.mjs
|
||||
tests/settings-write.test.mjs
|
||||
tests/shell.test.mjs
|
||||
tests/sso-browser.test.mjs
|
||||
tests/sso.test.mjs
|
||||
tests/tester-browser.test.mjs
|
||||
tests/tester-cli.test.mjs
|
||||
tests/tester-listener.test.mjs
|
||||
tests/tester-socket.test.mjs
|
||||
tests/thread-claims-browser.test.mjs
|
||||
tests/thread-claims.test.mjs
|
||||
tests/thread-sharing.test.mjs
|
||||
tests/usage-browser.test.mjs
|
||||
tests/usage.test.mjs
|
||||
tests/user-option-swap.test.mjs
|
||||
tests/views.test.mjs
|
||||
@@ -0,0 +1,38 @@
|
||||
# grant sage-4286; nice 19; TMPDIR /mnt/storage/scratch/tmp/g49X; MOSAIC_REQUIRE_EDITOR_BUILD 1
|
||||
✔ row 194 T16 Settings Agents: unavailable read-only, launch follows its request, confirms, reason and refusal (13526.912326ms)
|
||||
✔ row 256 T7 T8 the human page offers Delete on a creative instance, the tester page never does (917.27163ms)
|
||||
✔ row 194 T16: each agent action makes one call with only its keys, logs the user and answers the request (26.28546ms)
|
||||
✔ row 194 T16: the boundary refuses before any bus call (13.102463ms)
|
||||
✔ row 194 T16: read-only when send is off or no writer is wired; no route has a --send exception (6.394437ms)
|
||||
✔ row 194 T16: a bus refusal names its reason and nothing changed; an unknown outcome or a bad shape is never retried (4.282632ms)
|
||||
✔ row 194 T16: the request read takes one id, adds the refusal reason and refuses an unexpected shape (5.922485ms)
|
||||
✔ row 194 T16: delete joins add and change on /api/instances with only revision, instance and op (2.724511ms)
|
||||
✔ row 194 T16 D4.1: the tester listener launches, terminates and reads requests; regenerate, veto and delete are refused with no call (4.723645ms)
|
||||
✔ row 194 N5: agents.js is served as JavaScript and index.html loads it once (1.551741ms)
|
||||
✔ row 239 T6: a delete closed -revoked says the tokens may already be revoked, and outcome-unknown-revoked is an open outcome (2.702385ms)
|
||||
✔ the Board: held roles with no machine sessions, a claim with no address, the toggle kept across a reload, and Message addressed to the role (3264.641316ms)
|
||||
✔ a Seen click while a Board read is in flight waits for that read, then posts (1197.183961ms)
|
||||
✔ a redirect answer on a Board read, a bus read, a conversation read, a board POST, a module read and a send signs the page out: one line, nothing stale, no further reads (5156.528249ms)
|
||||
✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (1309.276425ms)
|
||||
Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
|
||||
✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (1518.992742ms)
|
||||
✔ the README says a refused field table names the file or the key at fault, never a path (104.682461ms)
|
||||
✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (3538.625499ms)
|
||||
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (83.53196ms)
|
||||
✔ decisions route serves the roles and recent lists from the reader view (37.23684ms)
|
||||
✔ credentials route serves the broker credential status from the reader view (13.661469ms)
|
||||
✔ replies route serves the replies to one message from the reader view (37.146766ms)
|
||||
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (57.970332ms)
|
||||
✔ bus refusals map to statuses and never carry a path or a stack (25.682155ms)
|
||||
✔ humanCall speaks the human transport protocol without blocking the server (1672.176975ms)
|
||||
✔ busReader takes --business, else the live bus host, else refuses (188.376745ms)
|
||||
✔ humanCall kills a transport that runs past its timeout (527.833381ms)
|
||||
✔ serve refuses a --business value that is not a business id (331.000231ms)
|
||||
ℹ tests 28
|
||||
ℹ suites 0
|
||||
ℹ pass 28
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 17747.118568
|
||||
@@ -0,0 +1,22 @@
|
||||
# grant sage-4286; nice 19; TMPDIR /mnt/storage/scratch/tmp/g49X; MOSAIC_REQUIRE_EDITOR_BUILD 1
|
||||
✔ wikilink round-trip: plain (5.135516ms)
|
||||
✔ wikilink round-trip: labelled (0.532763ms)
|
||||
✔ wikilink round-trip: heading target (0.47601ms)
|
||||
✔ wikilink round-trip: list item (0.674052ms)
|
||||
✔ wikilink round-trip: next to front matter (0.620153ms)
|
||||
✔ wikilink round-trip: heading block and combined label (0.718517ms)
|
||||
✔ wikilink round-trip: spaces, Unicode and adjacent links (0.543729ms)
|
||||
✔ wikilink round-trip: reference-definition collision (1.267657ms)
|
||||
✔ wikilink round-trip: inside an ordinary link (0.565479ms)
|
||||
✔ wikilink round-trip: inert embed (0.373131ms)
|
||||
✔ wikilinks are inline atoms and survive a neighbouring edit in every required context (773.2922ms)
|
||||
✔ code, escaped openers, malformed syntax and HTML-like targets stay outside wikilink atoms (686.084659ms)
|
||||
✔ wikilink DOM paste accepts only bounded single-line inert syntax; malformed attrs serialise as escaped text (675.536422ms)
|
||||
ℹ tests 13
|
||||
ℹ suites 0
|
||||
ℹ pass 13
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 2305.540306
|
||||
@@ -0,0 +1,27 @@
|
||||
// Run only under Sage's explicit CLEAR. Reads the pinned baseline Git objects,
|
||||
// not the edited model or rebuilt candidate bundle. Never writes product files.
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import { createHash } from 'node:crypto';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { dirname, resolve } from 'node:path';
|
||||
import vm from 'node:vm';
|
||||
import { WIKILINK_CASES } from '../../../../packages/webui/tests/helpers/wikilink-cases.mjs';
|
||||
|
||||
const repo = resolve(dirname(fileURLToPath(import.meta.url)), '../../../..');
|
||||
const base = '487500a16f4ab5902c318509fdec6acc56a543ca';
|
||||
const git = (...args) => execFileSync('git', args, { cwd: repo, encoding: 'utf8', maxBuffer: 16 * 1024 * 1024 });
|
||||
const read = path => git('show', `${base}:${path}`);
|
||||
const source = read('packages/webui/src/public/editor.js');
|
||||
const build = JSON.parse(read('packages/webui/editor/BUILD.json'));
|
||||
const sha256 = createHash('sha256').update(source).digest('hex');
|
||||
if (sha256 !== build.outputs['src/public/editor.js'].sha256) throw Error('baseline bundle differs from its recorded build');
|
||||
const context = { console }; context.window = context; context.globalThis = context;
|
||||
vm.createContext(context);
|
||||
for (const [name, text] of [['markdown-preview.js', read('packages/webui/src/public/markdown-preview.js')], ['editor.js', source]])
|
||||
vm.runInContext(text, context, { filename: name });
|
||||
const results = WIKILINK_CASES.map(({ name, text }) => {
|
||||
const output = context.MosaicEditor.roundTrip(text);
|
||||
return { name, input: text, output, equal: output === text };
|
||||
});
|
||||
console.log(JSON.stringify({ base: git('rev-parse', base).trim(), bundleSha256: sha256,
|
||||
measuredAt: new Date().toISOString(), allEqual: results.every(r => r.equal), results }, null, 2));
|
||||
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"base": "487500a16f4ab5902c318509fdec6acc56a543ca",
|
||||
"bundleSha256": "9c881b13740fae2408717ad75fa1d85bfcfe3fa8b3af0f1b3f2e706c90e80fee",
|
||||
"measuredAt": "2026-10-24T22:07:22.210Z",
|
||||
"allEqual": true,
|
||||
"results": [
|
||||
{
|
||||
"name": "plain",
|
||||
"input": "[[a]]\n",
|
||||
"output": "[[a]]\n",
|
||||
"equal": true
|
||||
},
|
||||
{
|
||||
"name": "labelled",
|
||||
"input": "[[a|b]]\n",
|
||||
"output": "[[a|b]]\n",
|
||||
"equal": true
|
||||
},
|
||||
{
|
||||
"name": "heading target",
|
||||
"input": "[[a#h]]\n",
|
||||
"output": "[[a#h]]\n",
|
||||
"equal": true
|
||||
},
|
||||
{
|
||||
"name": "list item",
|
||||
"input": "- [[a]]\n",
|
||||
"output": "- [[a]]\n",
|
||||
"equal": true
|
||||
},
|
||||
{
|
||||
"name": "next to front matter",
|
||||
"input": "---\nrelated: \"[[metadata]]\"\n---\n\n[[a]]\n",
|
||||
"output": "---\nrelated: \"[[metadata]]\"\n---\n\n[[a]]\n",
|
||||
"equal": true
|
||||
},
|
||||
{
|
||||
"name": "heading block and combined label",
|
||||
"input": "# See [[a#h|Title]]\n",
|
||||
"output": "# See [[a#h|Title]]\n",
|
||||
"equal": true
|
||||
},
|
||||
{
|
||||
"name": "spaces, Unicode and adjacent links",
|
||||
"input": "See [[ Héllo there # A heading | a label ]][[next]]\n",
|
||||
"output": "See [[ Héllo there # A heading | a label ]][[next]]\n",
|
||||
"equal": true
|
||||
},
|
||||
{
|
||||
"name": "reference-definition collision",
|
||||
"input": "[[a]]\n\n[a]: u\n",
|
||||
"output": "[[a]]\n\n[a]: u\n",
|
||||
"equal": true
|
||||
},
|
||||
{
|
||||
"name": "inside an ordinary link",
|
||||
"input": "[x [[a]]](u)\n",
|
||||
"output": "[x [[a]]](u)\n",
|
||||
"equal": true
|
||||
},
|
||||
{
|
||||
"name": "inert embed",
|
||||
"input": "![[cover.png]]\n",
|
||||
"output": "![[cover.png]]\n",
|
||||
"equal": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,402 @@
|
||||
# Row 255 design: a bundled Pocket ID for users with no OIDC provider (Q203, Gitea #1760, Vikunja 458)
|
||||
|
||||
Launchpad, draft 1, 2026-10-25, on `launchpad/row255` off refactor 78b69e1e6. Brief
|
||||
`docs/plans/2026-10-21_bundled-pocket-id.md` (blob 26f34400). Reviewer Webby. Sage checks it against Q203, O6,
|
||||
REQ-WEB-2 and REQ-INST-1. REQ-INST-2 (PRD 1.10) is post-v1 (mos-1204), and so is everything here.
|
||||
|
||||
This is a design only. Nothing here installs, downloads or starts Pocket ID. It changes nothing on .53, .54 or
|
||||
dragon-lin, which keeps Authentik.
|
||||
|
||||
## Sources
|
||||
|
||||
- Q203 and O6 as the brief quotes them. PRD `docs/prd/mosaic-stack.md` REQ-WEB-2 (:902), REQ-INST-1 (:1509),
|
||||
REQ-INST-2 (:1513) and REQ-INST-3 (:1528). Lead decision 44 items 5 and 6
|
||||
(`docs/plans/2026-09-26_lead-decisions.md:655-663`).
|
||||
- The Q175 design `agents/sage/work/q175-sso/DESIGN.md` sections 4 and 10, and the code row 192 landed:
|
||||
`packages/webui/src/sso-config.mjs` (the `console.sso` shape), `packages/webui/src/sso.mjs` (the slot read,
|
||||
the discovery checks at :105-118, the client at :147-148, the callback at :133, the post-logout URI at :332).
|
||||
- Researcher's note `agents/researcher/work/2026-10-04_vikunja-pocketid.md` part 2 (v2.17.0).
|
||||
- A fresh read of upstream on 2026-10-25, from release metadata and source text only: no binary was fetched or
|
||||
run. The latest stable release is **v2.19.1** (2026-10-22). Source paths below are under
|
||||
`backend/internal/` at tag v2.19.1 in `github.com/pocket-id/pocket-id`, marked "P". Releases v2.18.0,
|
||||
v2.19.0 and v2.19.1 are not marked breaking.
|
||||
|
||||
## What the Console already needs from any provider
|
||||
|
||||
This design keeps the Console's sign-in and start checks exactly as row 192 built them. Pocket ID becomes one
|
||||
`console.sso.providers` entry, the same shape any compliant OP uses (Q175 section 4, "Several providers"). The
|
||||
Console gets no new sign-in path, no password and no proxy-header identity (O6, REQ-WEB-2, REQ-INST-2). The
|
||||
facts that drive the rest of the design:
|
||||
|
||||
- `publicOrigin` and every `issuer` must be https (`sso-config.mjs` `httpsURL`). A plain-http Pocket ID can't
|
||||
be a provider at all.
|
||||
- Each provider needs 1 to 64 `subjects`. A `console.sso` with no subject refuses to load. So the first
|
||||
person's subject has to exist before the Console starts with `--sso` (section 5).
|
||||
- The client authenticates with `client_secret_basic` (`sso.mjs:148`), so the client is confidential.
|
||||
- The slot is `<configDir>/secrets/mosaic-stack/<slot>`: a regular file, owned by the Console's uid, mode
|
||||
with no group or other bits, and outside the repo and every stack copy (`readSlot`).
|
||||
- `config.json` is user-authored. bootstrap.sh creates it and nothing overwrites it (canon invariant 2, Q175
|
||||
section 4). This matters for sections 1 and 5.
|
||||
|
||||
## 1. The choice
|
||||
|
||||
The installer is REQ-INST-3's install command (Vikunja #432; today `stack-upgrade.sh` and the per-case
|
||||
install scripts). It takes one sign-in option per instance:
|
||||
|
||||
- `--oidc existing`. The user points the Console at one or more OIDC providers they already have. Nothing
|
||||
is installed. The user writes `console.sso` themselves, as Q175 step 4 does today. The installer writes
|
||||
nothing into `console.sso`; it prints the entry shape and the two URIs to register
|
||||
(`<publicOrigin>/auth/callback`, `<publicOrigin>/auth/signed-out`).
|
||||
- `--oidc bundled`. The stack installs Pocket ID as an install component (section 2), and
|
||||
`console.sso.providers` holds exactly one entry, `id: "pocket-id"`, whose `issuer` is the component's
|
||||
origin.
|
||||
- No option keeps today's behaviour: no `console.sso`, and the Console runs without `--sso`.
|
||||
|
||||
How the bundled choice is recorded. REQ-INST-1 lets a component be switched on "in the organization file
|
||||
or system config". It has to be the system config. The organization file can be written by agents through
|
||||
`organizationWriter`, which is the reason Q175 B1 put `console.sso` in config.json, and the same reason
|
||||
holds for a component that issues the Console's identities. So config.json gets one new optional key:
|
||||
|
||||
```json
|
||||
"components": {
|
||||
"pocket-id": {
|
||||
"release": "v2.19.1",
|
||||
"origin": "https://id.example.internal",
|
||||
"port": 1411
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The loader (`scripts/mosaic-config.mjs`) checks the shape: `release` is a `vX.Y.Z` tag, and the component script refuses one that
|
||||
differs from the pin file (section 2), `origin` is an https origin, `port` is 1024 to 65535. It also cross-checks: when
|
||||
`components["pocket-id"]` is present, `console.sso` must have exactly one provider, `id` `pocket-id`,
|
||||
`issuer` equal to `origin`. A config with `console.sso` providers and no `components` is the existing
|
||||
choice and loads as today.
|
||||
|
||||
**M1, approved by Mos with three conditions (mos-1666 item 3).** `components` is a new top-level config key.
|
||||
The loader refuses unknown keys today, so this is a config schema change. The conditions:
|
||||
|
||||
1. **Rollback trap.** A copy older than P1 refuses a config that has the key, the same trap Q175 section 4
|
||||
names for `console.sso`. P1 documents the order. On a rollback past P1, first take `components` out of
|
||||
config.json (restore the backup made before the key went in), then roll back the pointer. The STATE check
|
||||
after the rollback reads config.json and confirms the key is absent.
|
||||
2. **Strict inside the key.** The loader refuses any name under `components` other than `pocket-id`, and any
|
||||
field under `pocket-id` other than `release`, `origin` and `port`. Each refusal names the key path and
|
||||
quotes no value, as `checkConsole` does.
|
||||
3. **test-config.sh cases:**
|
||||
- a valid `components` loads;
|
||||
- a malformed one fails, naming the bad key path;
|
||||
- a config without `components` loads;
|
||||
- the cross-check refuses a `console.sso` whose provider doesn't match `origin`.
|
||||
|
||||
What each choice writes into `console.sso` is in section 5. For the bundled choice, Pocket ID is the only
|
||||
providers entry. The design keeps it that way because REQ-INST-2 says "the Console's one providers entry".
|
||||
A user who later adds an existing provider moves to `--oidc existing` and removes the component (section 2).
|
||||
|
||||
## 2. The component, against REQ-INST-1
|
||||
|
||||
**Pinned.** A Pocket ID release is a set of raw binaries plus `checksums.txt` (sha256). From v2.16.0 there is
|
||||
an SPDX SBOM per binary, and the release workflow attests `checksums.txt` through Sigstore (`actions/attest`
|
||||
in `.github/workflows/release.yml`). The repo holds one pin file,
|
||||
`scripts/pocket-id-pins.sh`, sourced the way `scripts/case1-pins.sh` is: the tag, and for each supported platform (linux amd64 and arm64 to
|
||||
start) the asset name and its sha256. The build row copies the sha256 from `checksums.txt` at the tag and
|
||||
records the `gh attestation verify` output for each asset as its evidence. The pin is checked by hand at
|
||||
build time, not trusted at install time. No Pocket ID source and no binary goes in the repo. The binary is
|
||||
not in any image either, since the container install comes after v1 (REQ-INST-3).
|
||||
|
||||
Recommended pin: v2.19.1, the current release. The build row checks it again, because Pocket ID ships a
|
||||
minor every one to four weeks. Upgrading is a pin file change in a reviewed commit.
|
||||
|
||||
**Fetched and checked.** `scripts/component-pocket-id.sh fetch` downloads the pinned asset for the host's
|
||||
platform over https into a new 0700 staging directory, computes its sha256, and compares it with the pin.
|
||||
On a mismatch it deletes the file and refuses with `pocket-id-digest-mismatch`, naming the expected value
|
||||
and the computed one. On a match it installs the binary read-only (0555) at
|
||||
`<dataRoot>/components/pocket-id/bin/pocket-id-<tag>`. The fetch is the only network step, and the user
|
||||
runs it at install. Tests never run it against the network (section 9).
|
||||
|
||||
**Runs.** A systemd user unit, `mosaic-pocket-id.service` (`mosaic-pocket-id-NAME.service` for a named
|
||||
instance, as row 190 names the bus and webui units), as the instance's user:
|
||||
|
||||
- `ExecStart=<dataRoot>/components/pocket-id/bin/pocket-id-<tag>`.
|
||||
- `WorkingDirectory=<dataRoot>/components/pocket-id/run`, a directory the unit owns, so Pocket ID's habit of
|
||||
reading `.env` from the working directory reads nothing we didn't write. The build row checks there is no
|
||||
`.env` there at start.
|
||||
- Environment, all from the rendered unit:
|
||||
- `APP_URL=<origin>` and `HOST=127.0.0.1` (P `common/env_config.go`: HOST defaults to `0.0.0.0`).
|
||||
- `PORT=<port>`.
|
||||
- `DB_CONNECTION_STRING` and `UPLOAD_PATH` as absolute paths under `<dataRoot>/components/pocket-id/data/`
|
||||
(P defaults are `data/pocket-id.db` and `data/uploads`, relative to the working directory).
|
||||
- `ALLOW_USER_SIGNUPS=disabled` and `ALLOW_INSECURE_CALLBACK_URLS=false`.
|
||||
- `EMAIL_ONE_TIME_ACCESS_AS_UNAUTHENTICATED_ENABLED=false` and `..._AS_ADMIN_ENABLED=false`.
|
||||
- The `OUTBOUND_ALLOWED_HOSTS_*` allowlists set empty (added in 2.19.0).
|
||||
- No `TRUST_PROXY` unless section 6's proxy step sets it to the proxy's address.
|
||||
- `ENCRYPTION_KEY` (mandatory since v2.0, at least 16 bytes) never goes in the unit text. It lives in slot
|
||||
`<configDir>/secrets/mosaic-stack/pocket-id-encryption-key`, 0600. The component script generates it from
|
||||
`/dev/urandom` straight into the file and never prints it. The unit passes it with
|
||||
`LoadCredential=` and `ENCRYPTION_KEY_FILE=%d/...`. The build row confirms `ENCRYPTION_KEY_FILE` at the pinned
|
||||
tag; if it isn't there, it refuses rather than putting the key in `Environment=`.
|
||||
- The unit never carries `STATIC_API_KEY`. That key exists only during the enroll run (section 4).
|
||||
|
||||
The data directory holds the SQLite database, Pocket ID's signing key (stored encrypted with
|
||||
`ENCRYPTION_KEY`), and the passkey registrations. It is 0700. Agent sandboxes bind only an allowlist
|
||||
(`packages/seat/src/sandbox.mjs`), and `<dataRoot>/components/` is not on it. The build row adds a sandbox
|
||||
test that pins that.
|
||||
|
||||
**Health-checked.** `GET http://127.0.0.1:<port>/healthz` returns 204 (P `controller/healthz_controller.go`).
|
||||
`component-pocket-id.sh status` reports the unit state, the binary tag against the pin, the binary's sha256
|
||||
against the pin, and the health result. The Console's own `/healthz` already shows `sso: { "pocket-id": ready
|
||||
| unreachable | refused }` from its discovery retries, so an operator sees the provider from either side.
|
||||
|
||||
**Removable.** `component-pocket-id.sh remove` refuses while `console.sso` still names `pocket-id`, so the
|
||||
Console can't be left pointing at a provider that's gone. Once the user has taken the entry out (or moved to
|
||||
`--oidc existing`), the script stops and removes the unit, then moves the data directory to
|
||||
`<dataRoot>/components/pocket-id.removed-<utc>` with a receipt line in `<dataRoot>/state/components.log`
|
||||
(append-only). It never deletes the passkey database outright. Deleting the moved directory and the
|
||||
encryption key slot is a separate `purge` verb that names both paths and needs `--yes`. Removing the
|
||||
`components` key from config.json is the user's edit.
|
||||
|
||||
## 3. The Q175 start checks against the bundled instance
|
||||
|
||||
The Console checks are unchanged. Here is each one against Pocket ID, and the setting it needs:
|
||||
|
||||
| Check (row 192) | Pocket ID v2.19.1 | Default that fails | Fix |
|
||||
|---|---|---|---|
|
||||
| `issuer` is https (loader) | issuer = `APP_URL` exactly (P `controller/well_known_controller.go`) | `APP_URL` defaults to `http://localhost:1411` | `APP_URL=<https origin>`, section 6 |
|
||||
| discovery `issuer` equals config `issuer` | equal when `APP_URL` has no trailing slash; Pocket ID refuses a path | none | config `issuer` = `origin`, no trailing slash; the loader cross-check compares them |
|
||||
| `id_token_signing_alg_values_supported` overlaps `algs` | advertises only the current key's alg. RS256 (RSA-2048) by default (P `service/jwt_service.go`) | none | `algs: ["RS256"]` |
|
||||
| `code_challenge_methods_supported` has `S256` | advertises `plain` and `S256` | none | none. The Console always sends S256 (`sso.mjs:221`) |
|
||||
| JWKS has a usable key for `algs` | one key at `/.well-known/jwks.json` | none | none. The build row's fake OP pins `use`/`alg`/`kid` as Pocket ID emits them |
|
||||
| `end_session_endpoint` is https | `<APP_URL>/api/oidc/end-session` | http, if `APP_URL` is http | same fix as row 1 |
|
||||
| `redirect_uri` is registered | exact match first, then wildcard patterns; loopback callbacks match any port (P `utils/callback_url_util.go`) | `ALLOW_INSECURE_CALLBACK_URLS` defaults to true | register exactly `<publicOrigin>/auth/callback`, with no `*`; set `ALLOW_INSECURE_CALLBACK_URLS=false` |
|
||||
| post-logout URI | per-client `logoutCallbackURLs`, same matching | none | register exactly `<publicOrigin>/auth/signed-out` |
|
||||
| ID token alg in `algs`, `iss` match | as above | none | none |
|
||||
|
||||
Two points the Console doesn't check, set on the client anyway:
|
||||
|
||||
- `pkceEnabled: true`. Then Pocket ID refuses an authorize request that has no `code_challenge`. Pocket ID has
|
||||
no per-client S256-only setting (P `oidc/provider.go` turns on `plain` for the server). That doesn't relax
|
||||
anything: the Console sends S256 every time, and `plain` stays available only to other clients.
|
||||
- `isPublic: false`, which matches `client_secret_basic`.
|
||||
|
||||
Key rotation. `pocket-id key-rotate --alg ...` replaces the one signing key (P `cmds/key_rotate.go`). After a
|
||||
rotation to another alg, the Console's discovery check refuses on the next restart (no overlap with
|
||||
`algs`), and that is the intended fail-closed result. A rotation is a user step that updates `algs` in the
|
||||
same edit. The component script never rotates.
|
||||
|
||||
## 4. The client, and where its secret goes
|
||||
|
||||
The person running the install creates the client through `component-pocket-id.sh enroll`. No agent runs
|
||||
this verb. It refuses when any agent marker is in its environment: the `MARKERS` list in
|
||||
`packages/bus/src/human.mjs` (`MOSAIC_RUN_ID`, `MOSAIC_BUS_CAP`, `CLAUDECODE` and the rest) that the human
|
||||
boundary uses. A test pins the refusal.
|
||||
|
||||
Enroll needs admin rights before any person has a passkey. Pocket ID offers two ways to get them, and one of
|
||||
them is a hazard:
|
||||
|
||||
- `/setup` and its backing `POST /api/signup/setup` are unauthenticated: whoever calls first becomes admin
|
||||
(P `usersignup/service.go`). Sandboxed agents share the host's network namespace (`sandbox.mjs` unshares
|
||||
user, pid and ipc, not net), so any agent could reach a loopback Pocket ID and take that first admin.
|
||||
- `STATIC_API_KEY` is a fixed admin key with no expiry (P `apikey/service.go`). It doesn't count as
|
||||
completing setup, so `/setup` stays open while it's set.
|
||||
|
||||
So enroll never lets the real unit serve before an admin person exists. It runs the pinned binary once in a
|
||||
**private network namespace** (`unshare --user --net`, or `bwrap --unshare-net` with the binary and data
|
||||
directory bound), where only enroll's own loopback can reach it:
|
||||
|
||||
1. Generate a one-run static key into a 0600 temp file in a new 0700 directory, and start Pocket ID inside
|
||||
the namespace with `STATIC_API_KEY_FILE` pointing at it, plus the unit's environment.
|
||||
2. Wait for `/healthz` 204.
|
||||
3. Create the admin user, `POST /api/users` with `isAdmin: true` and the username and email given with
|
||||
`--admin-user` and `--admin-email`. Keep the returned `id`. That is the OIDC `sub` (P
|
||||
`oidc/claims_service.go` uses `user.ID`, a UUIDv4 set at creation, so it's stable).
|
||||
4. Create the Console client: client id `mosaic-console-<instance>`, callback and logout URLs exactly as in
|
||||
section 3, `pkceEnabled: true`, `isPublic: false`. Supply the secret instead of letting Pocket ID
|
||||
generate it. Enroll generates 48 random bytes, base64url, and writes them straight to slot
|
||||
`<configDir>/secrets/mosaic-stack/console-sso-pocket-id` (0600, `O_CREAT|O_EXCL`, not a symlink). It sends
|
||||
the same bytes in the create body over the namespace's loopback (`dto/oidc_dto.go` accepts a supplied
|
||||
secret of 16 or more characters). The value is never printed, logged or put in an argv, and a test pins
|
||||
that it appears in no output.
|
||||
5. Mint a one-time access token for the admin, `POST /api/users/<id>/one-time-access-token`.
|
||||
6. Stop the namespaced process, then shred and remove the static key file. The real unit has never had a
|
||||
static key, so no admin key survives enroll.
|
||||
7. Start the real unit and wait for `/healthz` 204.
|
||||
8. Print the sign-in link `<origin>/lc/<token>` to the user's terminal (section 5), and the `console.sso`
|
||||
entry (section 5).
|
||||
|
||||
The build row confirms each route and body against the pinned tag's source before it writes the client (the
|
||||
upstream read for this design didn't trace the create-client route). If any of steps 1 to 7 fails, enroll
|
||||
stops the process, removes the static key, leaves no slot file it created, and refuses with the step name.
|
||||
|
||||
The secret never enters the repo or an image. It sits in two places only: the slot file and Pocket ID's
|
||||
database (stored as a hash). The Console's `readSlot` reads it as it does any provider's.
|
||||
|
||||
## 5. The first person, and their subject in `console.sso`
|
||||
|
||||
Pocket ID is passkey-only for people (REQ-INST-2). The installing user enrolls like this:
|
||||
|
||||
1. Enroll prints `<origin>/lc/<token>`. The token is valid for one hour and is a credential, so it goes only
|
||||
to the terminal of the person who ran enroll. It goes in no log and no file.
|
||||
2. The user opens it in a browser that can reach `origin` (section 6). Pocket ID signs them in and asks them
|
||||
to add a passkey. Without one they can't sign in again. If the hour passes, `pocket-id
|
||||
one-time-access-token <username>` (P `cmds/one_time_access_token.go`), run by the user against the data
|
||||
directory, prints a new link. `component-pocket-id.sh relink` wraps that call.
|
||||
3. Enroll already has the subject, the `id` from step 3 of section 4. It doesn't wait for a sign-in or read a
|
||||
`subject-unknown` log line.
|
||||
|
||||
How the subject gets into `console.sso`. config.json is user-authored and never auto-written. Two ways
|
||||
to respect that; I recommend the first:
|
||||
|
||||
- **R1 (recommended).** Enroll prints the full entry and writes nothing:
|
||||
|
||||
```json
|
||||
"console": { "sso": { "publicOrigin": "<publicOrigin>", "providers": [ {
|
||||
"id": "pocket-id", "issuer": "<origin>", "clientId": "mosaic-console-<instance>",
|
||||
"clientSecret": { "slot": "console-sso-pocket-id" }, "algs": ["RS256"],
|
||||
"subjects": [ { "sub": "<id>", "name": "<admin-user>" } ] } ] } },
|
||||
"components": { "pocket-id": { "release": "<tag>", "origin": "<origin>", "port": <port> } }
|
||||
```
|
||||
|
||||
The user pastes it into config.json, as with Q175 step 4. Rerunning `scripts/bootstrap.sh` (or
|
||||
`--instance NAME`) then validates it through the loader, including the section 1 cross-check, and writes
|
||||
nothing. Nothing changes in invariant 2.
|
||||
- **R2 (rejected, Sage sage-4401: R1 chosen).** `enroll --write-config` would write those two keys itself, with a backup of config.json first, and
|
||||
refuse if `console` or `components` were already present. That would be the first tool to modify an
|
||||
existing config.json, against canon invariant 2's "never overwritten" practice. Not built.
|
||||
|
||||
Whose subject. Enroll creates one person, the one running it, and only that subject goes in the entry. On
|
||||
Jason's instances, only his subject goes into `console.sso` (mos-1197). Further people are added with
|
||||
Pocket ID's admin UI (a user plus a one-time link), and their subjects go into `console.sso` by the user's
|
||||
edit, never by an agent. Pocket ID users who aren't in `subjects` can sign in to Pocket ID, but the Console
|
||||
refuses them `subject-unknown`, so REQ-WEB-2's "must map to an authorized human" holds.
|
||||
|
||||
## 6. Reach: origin, TLS and proxy
|
||||
|
||||
WebAuthn takes its RP id from `APP_URL`'s host name, and its allowed origin is `APP_URL`
|
||||
(P `webauthn/module.go`). Browsers allow passkeys only on a secure origin. The Console also needs https for
|
||||
both `publicOrigin` and `issuer`. Pocket ID serves plain http, and I found no TLS listener setting in its
|
||||
environment config. So:
|
||||
|
||||
- Pocket ID always binds `127.0.0.1:<port>`. That is the default, and the component never binds anything
|
||||
else (`HOST=127.0.0.1`; the status verb refuses a unit whose `HOST` differs).
|
||||
- `origin` is an https origin served by a TLS front that the user already has for the Console. The Console
|
||||
needs one anyway, since `publicOrigin` is https. Pocket ID goes behind the same front under **its own host
|
||||
name**, for example `id.<console host>`. Pocket ID doesn't support a path prefix (`APP_URL` must have no
|
||||
path). A separate host name also keeps Pocket ID's cookies apart from the Console's
|
||||
`__Host-mosaic_*` cookies; the two share cookies if they sit on one host name on different ports.
|
||||
- The front reaches Pocket ID on loopback, so the front has to run on the same host. If it doesn't, Pocket
|
||||
ID would need a non-loopback bind, and that is a `network.expose` hard wait (REQ-WAIT-1), not a component
|
||||
option.
|
||||
- `TRUST_PROXY` is set to the front's address only, never `true`.
|
||||
- The Console fetches discovery and JWKS from `issuer` over https from the server side, so the Console's
|
||||
node has to trust the front's certificate. A public CA does that. A private CA needs
|
||||
`NODE_EXTRA_CA_CERTS` in the Console unit, which the build row adds as a render flag.
|
||||
|
||||
These steps are the user's, and on Jason's hosts they are Jason's, because each one changes who can reach
|
||||
the Console or Pocket ID, or who the host trusts:
|
||||
- J1: the DNS name for `origin`;
|
||||
- J2: the certificate for it, or a private CA and its trust in the browser and in `NODE_EXTRA_CA_CERTS`;
|
||||
- J3: the TLS front's route from `origin` to `127.0.0.1:<port>` (a Traefik change on Jason's hosts);
|
||||
- J4: any listener off loopback.
|
||||
|
||||
The component checks and refuses; it never does them itself. With none of them done, Pocket ID runs on
|
||||
loopback with an https `APP_URL` that nothing serves yet. Enroll's step 2 health probe goes straight to
|
||||
`127.0.0.1`, so enroll still works. The person can't add a passkey until J1 to J3 are done.
|
||||
|
||||
## 7. Agents
|
||||
|
||||
Unchanged. Agents keep their per-role service tokens (lead decision 44 item 6, REQ-INST-2). Pocket ID issues
|
||||
nothing an agent uses. The Console client is the only client enroll creates. No API, no client-credentials
|
||||
grant and no admin API key exist after enroll. Residuals, stated plainly:
|
||||
|
||||
- Agents can reach `127.0.0.1:<port>`, because the sandbox shares the host network. What they can reach there
|
||||
is the public sign-in pages, discovery and JWKS. Signup is disabled, email codes are off, `/setup` is
|
||||
closed because an admin exists, and there is no static key. A test of the rendered unit pins all four
|
||||
settings.
|
||||
- The data directory and the two slots are outside every sandbox bind (section 2).
|
||||
- A seat that ran as the same OS user outside a sandbox could read the data directory. The Console's
|
||||
existing slot has the same exposure; this design adds no new class of it.
|
||||
|
||||
## 8. Instances
|
||||
|
||||
One Pocket ID per named instance, never shared:
|
||||
|
||||
- Each instance has one system config (row 190), and `components` and `console.sso` live in it. A shared
|
||||
Pocket ID would make one instance's config depend on a unit, a data directory and an encryption key that
|
||||
belong to another instance's config and data root.
|
||||
- Unit names, ports, data directory, slots and removal are all per instance (`mosaic-pocket-id-NAME`,
|
||||
`<dataRoot of NAME>/components/pocket-id`), so removing one instance's component can't break another's
|
||||
sign-in.
|
||||
- Each instance needs its own `origin` (section 6), so passkeys are per instance too. A person enrolls once
|
||||
per instance.
|
||||
- An instance that wants to use another instance's Pocket ID can still do it with `--oidc existing`. Then it
|
||||
is just an OIDC provider, with its own client registered by that instance's owner. Nothing special-cases it.
|
||||
|
||||
Two instances on one host each need their own `port`. The loader can't see other instances' configs, so
|
||||
`component-pocket-id.sh` refuses at fetch and enroll when the port is already bound on loopback.
|
||||
|
||||
## 9. Tests, stand-ins only
|
||||
|
||||
No test downloads or starts a real Pocket ID, and no test touches auth.diversecanvas.com,
|
||||
mosaic.woltje.com or 127.0.0.1:7332. The stand-ins:
|
||||
|
||||
- **Fake Pocket ID OP**, a node server like row 192's fake OP, shaped from v2.19.1:
|
||||
- the discovery fields `well_known_controller.go` emits (issuer = origin, `plain` and `S256`,
|
||||
`end_session_endpoint` at `/api/oidc/end-session`, the three auth methods);
|
||||
- one RS256 JWK at `/.well-known/jwks.json`;
|
||||
- a token endpoint that takes only `client_secret_basic`;
|
||||
- `/healthz` 204.
|
||||
|
||||
The Console starts against it under `--sso` with the section 5 entry, with no check changed. Negative
|
||||
cases:
|
||||
- an http issuer refuses at load;
|
||||
- an ES256-only JWKS against `algs: ["RS256"]` refuses at discovery;
|
||||
- an issuer with a trailing slash refuses on the cross-check.
|
||||
- **Fake admin API** on the same stand-in: `POST /api/users`, the client create, the one-time token, and a
|
||||
static-key check. Enroll runs against it with the binary replaced by a stub script that serves the stand-in.
|
||||
The tests pin:
|
||||
- the namespace argv;
|
||||
- the slot file's mode and `O_EXCL`;
|
||||
- that the secret appears in no stdout, stderr or argv;
|
||||
- the static key file gone after success and after a failure at each step;
|
||||
- the refusal under an agent marker in the environment.
|
||||
- **Fetch**: a local file served by a test https server (self-signed, trusted only by the test) with a
|
||||
matching pin, a mismatched pin and a truncated file.
|
||||
- **Unit render**: the environment table in section 2. `HOST=127.0.0.1`, no `STATIC_API_KEY`, no
|
||||
`ENCRYPTION_KEY` value in the text, and `ALLOW_USER_SIGNUPS=disabled`.
|
||||
- **Loader**: test-config.sh cases for the `components` key and the cross-check, and the copy-rollback note.
|
||||
- **Sandbox**: `<dataRoot>/components/` is in no bind list.
|
||||
|
||||
## 10. Build rows, in landing order
|
||||
|
||||
All are post-v1 (REQ-INST-2). Each row has Webby or Sage's named reviewer and its own gate. None of them
|
||||
runs on .53, .54 or dragon-lin, and none installs Pocket ID on any host.
|
||||
|
||||
1. **P1, loader key.** `components["pocket-id"]` in `mosaic-config.mjs`, strict inside the key, and the
|
||||
cross-check against `console.sso` (section 1, M1 conditions from mos-1666 item 3). P1 also writes the
|
||||
rollback order into `docs/TOOLS.md` beside Q175's: remove `components` (restore the backup) before the
|
||||
pointer goes back, and the post-rollback STATE check confirms the key is absent from config.json. Gate:
|
||||
test-config.sh green with the four M1 cases.
|
||||
2. **P2, pin and fetch.** `scripts/pocket-id-pins.sh` with the build-time sha256 and the
|
||||
attestation evidence, and `component-pocket-id.sh fetch|verify`. Gate: the fetch tests against the local
|
||||
stand-in; the evidence file shows `gh attestation verify` output for each pinned asset.
|
||||
3. **P3, unit.** The unit template, `render|install|status|remove|purge`, and the encryption key slot. Gate:
|
||||
the render and remove tests, and the sandbox bind test.
|
||||
4. **P4, enroll.** The namespaced bootstrap, the client, the subject, `relink`, and printing the entry (R1),
|
||||
(R2 rejected). Gate: the enroll tests in section 9, and a secret-leak grep over every test log.
|
||||
5. **P5, Console against the fake Pocket ID.** The section 9 fake-OP start tests, and the
|
||||
`NODE_EXTRA_CA_CERTS` render flag for the Console unit. Gate: the webui suite, with no change to
|
||||
`sso.mjs` checks (a diff of `sso.mjs` and `sso-config.mjs` against the base shows none).
|
||||
6. **P6, installer option.** `--oidc existing|bundled` on REQ-INST-3's install command, calling P2 to P4 in
|
||||
order, and the docs: `docs/TOOLS.md`, the host run sheet's J1 to J4 steps. Gate: the installer's own
|
||||
suite against the stubs; the docs list J1 to J4 as the user's steps.
|
||||
|
||||
## Open items for review
|
||||
|
||||
- M1 approved by Mos with three conditions (mos-1666 item 3), written into section 1 and P1.
|
||||
- M2 dropped: Sage chose R1 and rejected R2 (sage-4401).
|
||||
- **Q1 (Webby):** the private network namespace for enroll (section 4). The other option is to start the
|
||||
real unit and race `/setup`, which I think is unsafe while agents share the host network.
|
||||
- **Q2 (Webby):** one-providers-entry for the bundled choice (section 1). REQ-INST-2's wording reads that
|
||||
way. Mixing a bundled Pocket ID with existing providers would need Sage's ruling.
|
||||
- Not covered: Pocket ID for Vikunja or Gitea people sign-in (the Researcher note's part 3), and
|
||||
client-credentials between Mosaic services. Neither is in Q203.
|
||||
@@ -0,0 +1,482 @@
|
||||
# Row 193 design: many humans per business, human roles, private and shared threads
|
||||
|
||||
Morgana (Opus 5.5), 2026-10-20. Revision 5: sage-1373 item 1 (mos-1023 item 2), the user sentence names every record the owner sees. Revision 4: duckworth-0011 B3 and N5. Revision 3: duckworth-0008 B1, B2 and N1-N4, sage-1368. Revision 2: sage-1354 (5.7 private from the owner, 193b split) and gizmoduck-0018 (coverage and the R4 predicate in FED r4.1). Gitea #1691, queue row 193, brief `docs/plans/2026-10-20_human-users.md`
|
||||
(blob f7472d1e47b1). Reviewer Duckworth, gate owner Sage. Base: `refactor` at 53bb59462.
|
||||
|
||||
Read for this design: COMMON.md (53bb59462), the brief, Gizmoduck's federation design r4.4 (b67bc6de9 on
|
||||
gizmoduck/federation-design, cited as FED; r3.1 a2840a6be was read first), Duckworth's federation reviews (b402197ff, 03a663cd7,
|
||||
45cbe5896 on duckworth/reviews), Sage's Q175 SSO design (`agents/sage/work/q175-sso/DESIGN.md`), the row 192
|
||||
and row 196 briefs, Darkwing's row 190 packet (uncommitted, sha256 5493c9df3ec0...), and the bus, business,
|
||||
cli and webui code at the lines cited. Messages: morgana-0001 to 0003, sage-1338, gizmoduck-0009,
|
||||
gander-0002 and gander-0005.
|
||||
|
||||
## 1. Summary
|
||||
|
||||
- Three human roles: **owner**, **collaborator**, **viewer**. The owner is the business file's one `human`,
|
||||
as today. Collaborators and viewers are access.json users, the same store federation uses (FED 3.5).
|
||||
Their role is the `level` of a grant, so a role is per project and instance, not per person.
|
||||
- Every human principal is minted by one bus verifier, owned by row 196 (Gander). Row 193 states what it
|
||||
needs from that verifier (section 6) and adds no second mechanism.
|
||||
- Threads stay private to their owner by default. A thread owner may share a thread, read-only, with a
|
||||
named user, with the owner, or with everyone granted on it. Shares live in a new append-only bus table,
|
||||
`thread_shares`. This is a deviation from brief point 4, agreed by Sage (sage-1338), for Duckworth to rule
|
||||
on (section 5.1).
|
||||
- A share never widens a grant. It counts only while the reader's live grant covers the thread's project
|
||||
and instance, and while the thread's owner still has coverage. Revocation, expiry and unsharing take
|
||||
effect on the next request.
|
||||
- Existing businesses keep working unchanged: every existing thread is already owned by the business
|
||||
human, and an instance without access.json has exactly one human, the owner.
|
||||
- The build splits so the part without a schema change can land first. `thread_shares` needs schema 3j and
|
||||
a `--migrate` window with Jason.
|
||||
|
||||
## 2. What exists today (measured at 53bb59462)
|
||||
|
||||
- One `human` per business (`packages/business/src/business.mjs:160`). `bindHuman` refuses any other name
|
||||
(`packages/bus/src/broker.mjs:532-538`).
|
||||
- The owner's CLI proof is path-bound (#225): `verifyHuman` checks uid, start time, nonce
|
||||
(`MOSAIC_BUS_CLI_NONCE`), `argv[1]` equal to the tree's `human-cli.mjs`, then walks parents and refuses
|
||||
agent markers, launch records and agent binaries (`packages/bus/src/human.mjs:64-96`).
|
||||
`authenticateHuman` binds the proof to `businesses[business].human` (`packages/bus/src/runtime.mjs:175-182`).
|
||||
- Threads: `threads(seq,id,at,business,project,instance,owner,name)`, append-only
|
||||
(`packages/bus/schema.sql:247`, triggers at :310-312). `#owner(s)` returns `tester` or `s.human`
|
||||
(broker.mjs:364-366). `#thread` refuses a non-owner with `thread-not-owned` (:357-362).
|
||||
- Thread verbs are gated `if (!s.tester) this.#human(s)`: `project.list` (:2318), `thread.create` (:2325),
|
||||
`thread.list` (:2351, owner filter), `thread.open` (:2365), `thread.send` (:2374, writes `human.input`
|
||||
for the human only), `thread.messages` (:2401).
|
||||
- Board reads are business-wide and human or reader only: `inbox`, `agents`, `tasks`, `trail` (:2143-2167),
|
||||
`decisions` (:2174), `credentials` (:2195), `messages` (:2217, `to_role='human'`), `replies` (:2422).
|
||||
`trail` and `replies` return any message in the business by id (:2679-2700, :2422-2432).
|
||||
- The Console reads threads by polling the same verbs (`packages/webui/src/chat.mjs:22-26`). It has no
|
||||
stream, so a refusal on the next poll ends access.
|
||||
- The launcher restarts a thread with pending messages as the business human
|
||||
(`packages/cli/src/launcher.mjs:533-542`).
|
||||
|
||||
## 3. The human model (brief point 1)
|
||||
|
||||
### 3.1 Who the humans are
|
||||
|
||||
| Human | Where it is declared | How many | Identity |
|
||||
|---|---|---|---|
|
||||
| owner | business file `human` (unchanged) | exactly one per business | the business human's name |
|
||||
| user (collaborator or viewer) | access.json `users[]` with `home: "local"` (or a peer id under federation) | any number | `user:<id>` |
|
||||
| tester | not a human; row 177 test principal | one | `tester` |
|
||||
|
||||
The owner stays outside access.json (FED 9 Q2). A business has no second owner and no admin level. Adding
|
||||
one is out of scope; section 9 lists it as a follow-up for Jason.
|
||||
|
||||
### 3.2 How a sign-in or a call becomes exactly one human
|
||||
|
||||
| Entry | Becomes | Checked by |
|
||||
|---|---|---|
|
||||
| Console SSO session whose `(provider, sub)` is in `console.sso.providers[].subjects` (row 192) | the owner | the Console after OIDC checks, then the bus verifier (row 196) |
|
||||
| Console SSO session whose `(provider, sub)` is a `users[].subjects` entry in access.json with a live grant | that one user | same |
|
||||
| Console SSO session matching neither | nobody: refused | the Console, and the bus refuses any later claim |
|
||||
| CLI call through `human-cli.mjs` that passes the human proof | the owner | the bus (`verifyHuman`) |
|
||||
| Any other process, including an agent | nobody | the bus |
|
||||
|
||||
Why each is exactly one:
|
||||
|
||||
- The R1 loader refuses a `(provider, sub)` pair that appears twice in access.json or also in
|
||||
`console.sso.subjects` (FED 3.5). So one subject maps to at most one human.
|
||||
- A user id can't be `human`, `tester` or any business's human (FED 3.5). So a user can't be named as the
|
||||
owner.
|
||||
- A terminal maps only to the owner. The only identity the bus can verify for a local process is the
|
||||
instance's OS user, and that is the owner's. A user has no CLI path in row 193. This follows Mos's B1 rule
|
||||
(mos-0985): the principal comes from what the bus verifies, never the process's own claim.
|
||||
- The bus never reads a user name from a request body as identity. The verifier returns the principal
|
||||
(section 6).
|
||||
|
||||
## 4. Human roles (brief point 2)
|
||||
|
||||
### 4.1 The three roles
|
||||
|
||||
- **owner**: everything the business human does today. Only the owner restructures the organization
|
||||
(business file writer, project and role changes) and only the owner manages users and grants.
|
||||
- **collaborator**: FED 3.5's level, unchanged. Creates threads in granted projects on granted instances,
|
||||
sends into and opens its own threads, and in row 193 also shares its own threads.
|
||||
- **viewer**: new. Reads threads shared with it, within its grant. It creates, opens and sends nothing, so
|
||||
it never drives an instance. FED 3.5 notes that a collaborator's message drives the instance with the
|
||||
owner's role authority (F10). A viewer has none of that.
|
||||
|
||||
The word "collaborator" stays, so FED's tests and help text need no rename. The brief's example "member" is
|
||||
this level.
|
||||
|
||||
A role is the `level` on a grant, and a grant is per business, project set and instance set. A user may
|
||||
hold a collaborator grant on one project and a viewer grant on another. Every check asks "does a live
|
||||
grant of a level that allows this verb cover this project and instance". A user has no single role.
|
||||
|
||||
### 4.2 R1 widening
|
||||
|
||||
FED R1 refuses any level but `collaborator`, because the 10-27 slice ships only that (FED 9 Q2).
|
||||
Row 193 widens R1's level check to `collaborator` or `viewer`, with its own test that each is accepted and
|
||||
anything else refuses. Nothing else in the access file changes. If R1 has not landed when row 193 builds,
|
||||
this one-line widening goes into the row 193a candidate chained on R1's candidate (Q177).
|
||||
|
||||
### 4.3 Bus verbs per role
|
||||
|
||||
Every verb not in a user's column fails `access-refused` before its own checks, as FED 3.5 requires for
|
||||
collaborators. That covers every owner verb, every board read, `message.*`, `decision.*`, project files,
|
||||
`spec.read`, `assistant.stop`, `launch.*`, `name.set`, `usage.*` and `access.reload`.
|
||||
|
||||
| Verb | owner | collaborator | viewer |
|
||||
|---|---|---|---|
|
||||
| `project.list` | all | projects covered by any live grant | projects covered by any live grant |
|
||||
| `thread.create` | yes | collaborator grant covers project and instance | refused |
|
||||
| `thread.list` | own threads | own threads still covered | own threads still covered (from an earlier collaborator grant) |
|
||||
| `thread.list {shared: true}` (new) | threads shared with the owner | threads shared with me and readable (5.4) | same |
|
||||
| `thread.open` | own | own, collaborator grant still covers | refused |
|
||||
| `thread.send` | own | own, collaborator grant still covers, no `human.input` | refused |
|
||||
| `thread.messages` | own, or shared with the owner | own (any level still covering), or shared and readable | same as collaborator |
|
||||
| `thread.share`, `thread.unshare` (new) | own threads | own threads, collaborator grant still covers | refused |
|
||||
| `thread.shares` (new) | own threads | own threads | refused |
|
||||
| `names` | all | instances covered by any live grant | instances covered by any live grant |
|
||||
| every other verb | as today | refused | refused |
|
||||
|
||||
Notes:
|
||||
|
||||
- `thread.list` keeps its response shape exactly. Shared threads come only from `thread.list {shared: true}`,
|
||||
whose rows add `owner`. The Console and existing tests read the plain list unchanged.
|
||||
- A viewer can still read its own threads when a collaborator grant is lowered to viewer, but can't send
|
||||
or open them. This is the downgrade path.
|
||||
- The tester keeps its row 177 verbs. It can't share or be shared with: `thread.share`, `thread.unshare`
|
||||
and `thread.shares` fail `tester-refused`, and a share target is never `tester`. Agent testers (Q173) test
|
||||
sharing through the bus suites, not the live 7333 listener.
|
||||
- `reader` sessions (Console read caps, broker.mjs:1303) are the owner's board view and stay owner-only.
|
||||
A user never gets a reader session.
|
||||
|
||||
### 4.4 Console per role
|
||||
|
||||
- owner: as today, plus a share control on each own thread and a "Shared with me" list.
|
||||
- collaborator: the chat view only, for granted projects (FED R6's granted-user sign-in), plus share
|
||||
controls on its own threads and "Shared with me". No board.
|
||||
- viewer: "Shared with me" and its own old threads, read-only. No composer, no open, no share control.
|
||||
- The Console hides controls a role can't use, but the bus check is authoritative. A Console bug can't
|
||||
widen a grant (FED 3.6). Each role gets a webui test with the UI check removed (mutant) that the bus still
|
||||
refuses.
|
||||
|
||||
### 4.5 Who manages humans and roles
|
||||
|
||||
Only the owner, through `mosaic access` (FED R5), which checks the human proof and refuses tester and agent
|
||||
callers. Row 193 needs from R5:
|
||||
|
||||
- `mosaic access user add <id> --home local --subject <provider>:<sub>` and `user remove <id>`;
|
||||
- `--level viewer` on `grant`;
|
||||
- the receipt line in `<dataRoot>/state/access-log.jsonl` and the `access.reload` call, as FED R5 has.
|
||||
|
||||
If R5 has no `user` verbs when row 193 builds, row 193c adds them on R5's candidate. The Console gets no
|
||||
user or grant writes in row 193: a write from the Console would need a new owner verb that writes
|
||||
access.json from the bus, and access.json is a config file only the owner's CLI writes. A read-only users
|
||||
page for the owner is a follow-up (section 9).
|
||||
|
||||
The owner keeps every restructuring power (TARGET Case 1). Users can't touch the business file, projects,
|
||||
roles or access.json.
|
||||
|
||||
## 5. Private and shared threads (brief point 3)
|
||||
|
||||
### 5.1 Deviation from brief point 4, agreed by Sage (sage-1338)
|
||||
|
||||
Brief point 4 says access.json is the one store. Users, roles and grants live there. Per-thread shares do
|
||||
not, for three reasons (morgana-0002):
|
||||
|
||||
- F1. Thread ids are bus-generated UUIDs. A hand-typed share with a typo would fail the loader, and the
|
||||
loader refuses the whole file on any failure, which revokes every user.
|
||||
- F2. Only the owner writes access.json. A collaborator could never share its own thread.
|
||||
- F3. Threads are append-only bus rows, and a share is a runtime act by a principal that wants a trail.
|
||||
|
||||
So shares go in an append-only bus table, gated by the grant. Sage agreed (sage-1338). Gizmoduck had no
|
||||
objection (gizmoduck-0009) and recorded it as FED 9 Q2. Duckworth rules on it in this review.
|
||||
|
||||
### 5.2 Schema 3j
|
||||
|
||||
```sql
|
||||
CREATE TABLE thread_shares (
|
||||
seq INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
at TEXT NOT NULL,
|
||||
business TEXT NOT NULL,
|
||||
thread TEXT NOT NULL REFERENCES threads(id),
|
||||
op TEXT NOT NULL CHECK (op IN ('share','unshare')),
|
||||
target TEXT NOT NULL,
|
||||
by TEXT NOT NULL
|
||||
) STRICT;
|
||||
CREATE INDEX thread_shares_thread ON thread_shares (thread, target, seq);
|
||||
-- no_update, no_delete and no_replace triggers, as thread_opens has (schema.sql:319-321).
|
||||
```
|
||||
|
||||
- `target` is an owner string: `user:<id>`, the business human's name, or `*`. A share whose target is a
|
||||
name that is no longer the business's `human` (after a rename) is void: rule 1 in 5.4 compares against
|
||||
the current owner string, so it matches nobody (Duckworth N4).
|
||||
- `by` is the sharer's owner string, which is always the thread's owner.
|
||||
- A share's state is its latest row per `(thread, target)` (Duckworth N12, REVIEW-r3.md:74-76). Shares
|
||||
are not assumed to only grow.
|
||||
- No existing row changes. Existing threads are already owned by the business human (`#owner` at
|
||||
broker.mjs:364-366), so they are the owner's and private. The brief's "all become the current human's"
|
||||
is already true.
|
||||
|
||||
The migration `3i-3j.sql` creates the table, index and triggers. `thread_shares` joins every table list that
|
||||
holds timed append-only tables: `timedTables` in store.mjs (:60-74), the broker's clock list
|
||||
(broker.mjs:223-235), the restore guard's counted tables (row 181) and `COUNTED` in
|
||||
`scripts/stack-release.sh:315`. The schema digest for 3j is pinned as the other versions are.
|
||||
|
||||
### 5.3 Verbs
|
||||
|
||||
- `thread.share {thread, to}`: the caller must own the thread (`thread-not-owned`). For a user, a
|
||||
collaborator grant must still cover the thread. `to` is `user:<id>`, the business human's name or `*`.
|
||||
A `user:<id>` target must have a live grant, of any level, covering the thread's project and instance,
|
||||
else `share-not-covered`. Sharing with yourself fails `invalid-request`. A share that is already in force
|
||||
fails `share-exists`. Writes one `share` row.
|
||||
- `thread.unshare {thread, to}`: the caller must own the thread. The share must be in force, else
|
||||
`share-not-found`. Writes one `unshare` row. Unsharing the owner's or `*` shares works the same way.
|
||||
- `thread.shares {thread}`: the caller must own the thread. Returns the shares in force, latest row each.
|
||||
- Both writes go through `refuse()` on failure, so each refusal records `action.refused` with `by` set
|
||||
(FED 3.6 item 6).
|
||||
|
||||
### 5.4 The read check, one function
|
||||
|
||||
`#readable(s, t)` decides whether a session may read thread `t` it doesn't own. True only when all hold:
|
||||
|
||||
1. a share for `t` is in force whose target is the caller's owner string, or `*`;
|
||||
2. the caller is the owner, or the caller has a live grant of any level covering `t.project` and
|
||||
`t.instance`;
|
||||
3. if `t.owner` is a user, that user still has a live grant covering `t` (a revoked owner hides the
|
||||
thread, sage-1338);
|
||||
4. `t.owner` is not `tester`.
|
||||
|
||||
`#thread(s, id)` keeps its owner check for `thread.open`, `thread.send`, `thread.share`, `thread.unshare`
|
||||
and `thread.shares`. A new `#threadRead(s, id)` admits the owner or `#readable`, and serves only
|
||||
`thread.messages`. A sharee fails `thread-not-owned` on every write verb.
|
||||
|
||||
### 5.5 Every read path and its filter
|
||||
|
||||
| Read path | Today | After row 193 |
|
||||
|---|---|---|
|
||||
| `thread.list` | `owner=?` | unchanged for the owner; for users also each row's thread still covered |
|
||||
| `thread.list {shared: true}` | none | rows where `#readable` holds |
|
||||
| `thread.messages` | `#thread` | `#threadRead` |
|
||||
| `thread.open`, `thread.send` | `#thread` | `#thread`, plus a collaborator grant for users |
|
||||
| `project.list`, `names` | business-wide | per FED 3.5 for users, unchanged for the owner |
|
||||
| `trail`, `replies` | human, reader or tester; any message by id | users refused (`access-refused`); for the others, messages in other users' unshared threads hidden (5.7) |
|
||||
| `messages`, `inbox`, `agents`, `tasks`, `decisions`, `credentials` | human or reader | users refused (`access-refused`); owner unchanged. A user-thread run can't send to the human (`user-thread-human`, FED 3.6), so `messages` holds none of a user's thread |
|
||||
| `message.receive` by a run | its own thread (:1933) | unchanged: runs read their own thread, never a share |
|
||||
| `threadsState` (launcher) | all threads | adds `revoked` per 5.6 |
|
||||
|
||||
### 5.6 Revocation, expiry and unsharing
|
||||
|
||||
Gizmoduck asked that a grant loss end access to threads shared with that user (gizmoduck-0009 point 2).
|
||||
|
||||
- A sharee holds no claim and no run. Its access is only reads, and every read runs `#readable` against the
|
||||
access state the broker already refreshes on each request (mtime, size, inode), on its 30 s timer, and on
|
||||
`access.reload` (FED 3.7). So a removed, expired or invalid grant ends share reads on the next request,
|
||||
with nothing to tear down. The Console polls, so a revoked sharee's next poll fails.
|
||||
- An unshare row ends access on the next request in the same way.
|
||||
- A user who loses coverage of their own thread also loses its shares: rule 3 in 5.4.
|
||||
|
||||
The downgrade case. With viewer, "no live grant covers" would be wrong for runs: a viewer grant covers the
|
||||
thread but must not let a run continue. FED puts this in R4: `revoked`, claim end and the launch check call
|
||||
`covers` with level `collaborator`, so a downgrade to viewer ends the run within one launcher tick. FED r4.4
|
||||
(b67bc6de9, mos-1020) chains R4 after row 193's viewer level (193a) and keeps the level-loss test and its
|
||||
mutant in R4. Row 193 carries neither (Duckworth N3), so the mutant has one owner.
|
||||
|
||||
### 5.7 What "private" means, stated plainly
|
||||
|
||||
Sage ruled (sage-1354): a user's thread is private from the owner on the bus too. Jason's words are "private
|
||||
agent sessions per user", and in Case 2 the owner of Melanie's hub is not the user whose thread it is.
|
||||
Duckworth's B1 asked where the line sits, since a user-thread run acts with the owner's role authority (F10).
|
||||
I took Duckworth's option (a): **the user's messages are private, and the run's governance is not.** The
|
||||
run spends the owner's authority, so its decisions, task writes and claims are the owner's to see and
|
||||
answer. Filtering them too (option b) would need a thread link on `decisions`, more schema, and would hide
|
||||
from the owner what is done in the owner's name.
|
||||
|
||||
Every read an owner or reader session has, and its side of the line:
|
||||
|
||||
| Read | Shows | Side |
|
||||
|---|---|---|
|
||||
| `thread.list`, `thread.messages`, `thread.open` | own threads only, plus shares to the owner from 193b2 | private: other users' threads never appear |
|
||||
| `trail` | events, messages, decisions and deliveries by subject | messages filtered (below); decision rows and their events stay visible |
|
||||
| `replies` | messages replying to an id | filtered (below) |
|
||||
| `messages`, `message.receive`, `message.read` | messages `to_role='human'` (broker.mjs:1931-1936, :1953) | private by construction: a user-thread run can't send to the human (`user-thread-human`, FED 3.6 item 7) |
|
||||
| `inbox` | open decisions routed to the human | governance, visible |
|
||||
| `decisions {list: roles \| recent}` | decision rows with question, options and recommendation | governance, visible |
|
||||
| `agents` | role claims and each held role's state | governance, visible |
|
||||
| `tasks`, `state` | tracker tasks and launch state | governance, visible |
|
||||
| `credentials`, `usage` | credential state, usage records | governance, visible; neither holds message text |
|
||||
| `project.files`, `project.file` | project files, including records a run writes with `record.write` (broker.mjs:1395-1407, :1441-1450) | governance, visible |
|
||||
| `project.list`, `names` | projects and instance names | business-wide for the owner, visible |
|
||||
|
||||
So a decision a user-thread run raises shows in the owner's `inbox` or `decisions`, with the free text the
|
||||
run wrote. Its role claims show in `agents`, its task writes in `tasks`, and a record it writes in
|
||||
`project.file`. Any of these can quote the user, and 5.7 doesn't call them private. The users' help text
|
||||
(R5) and the Console's share and thread pages say so in one sentence, which FED R6 reuses (mos-1023 item 2,
|
||||
duckworth-0012 N21):
|
||||
|
||||
> The business owner sees your thread's agent's decisions, inbox entries, claims, tasks and project files,
|
||||
> but not your messages.
|
||||
|
||||
The gated-raise route. A user-thread run's uncited gated raise or hard wait routes to the human (broker.mjs:1677-1680).
|
||||
FED r4.5 (acd5f1f42, B9) settled this with no guard: the tester guard at :1683 (`tester-thread-human`) is not
|
||||
copied, and the decision reaches the owner's inbox and no other (sage-1368, mos-1021, mos-1022). FED R3 tests it.
|
||||
Row 193 adds nothing here.
|
||||
|
||||
The message filter. A message is hidden from a session when it is in a thread (`message_threads`) whose owner
|
||||
is a `user:<id>` other than the caller, and `#readable(s, t)` is false. Threads owned by the business human or
|
||||
by `tester` are not affected, so row 177's behaviour is unchanged.
|
||||
|
||||
- `trail`: drops hidden messages, their `deliveries` rows, and `events` rows whose `subject` is a hidden
|
||||
message id. A `subject` that is itself a hidden message returns `message-not-found`, as an unknown id does,
|
||||
so the reply doesn't confirm the id exists.
|
||||
- `replies {id}`: a hidden `id` fails `message-not-found`, and hidden messages are dropped from the result.
|
||||
- It applies to every session that can call these verbs: the owner, reader sessions and the tester.
|
||||
- It lands in 193b1, with no schema (Duckworth B2). Before 193b2 there are no shares, so `#readable` is false
|
||||
for anyone but the thread's owner and b1 hides every message in another user's thread. 193b2 adds only the
|
||||
share exception. So no build order can put a user thread live without the filter.
|
||||
|
||||
What it does not do. The owner holds the store as the instance's OS user and can read it with sqlite. That is
|
||||
the same-uid limit in section 6, not a bus path. An owner audit verb, explicit and logged, is a follow-up row
|
||||
only if Jason asks for one (sage-1354).
|
||||
|
||||
## 6. The bus human boundary (brief point 5)
|
||||
|
||||
Row 196 (Gander, #1694, brief `docs/plans/2026-10-20_human-boundary.md` at 96f243faf) owns P19 333 and the
|
||||
verifier. Row 193 cites it and designs no boundary of its own (sage-1338: one mechanism).
|
||||
|
||||
Agreed with Gander (gander-0002, morgana-0003, gander-0005):
|
||||
|
||||
- One bus verifier, `verifyPrincipal(request, connection) -> {kind, business, id}`, kind `owner`, `user` or
|
||||
`tester`. It mints one transient principal per request. It returns no role. The broker reads the level
|
||||
from the live grant on every request, so a grant change acts without a new principal.
|
||||
- Gander recommends FED 3.6's shape for users (path-bound `user-cli.mjs`, direct parent the bus tree's
|
||||
`packages/webui/src/cli.mjs serve`) plus kernel peer PID binding, and weighs bus-side ID-token
|
||||
verification as the larger alternative.
|
||||
- Correction from Gander, accepted: the tester proof doesn't run the full agent walk, because agents bind
|
||||
tester by design (Q173). Managed runs still fail it. The tester listener moves from TCP 7333 to a private
|
||||
Unix socket, with `bus.tester` unchanged (agreed by Sage with Gander).
|
||||
|
||||
What row 193 needs from row 196:
|
||||
|
||||
- H1. Owner on the CLI keeps today's proof. Owner in the Console is a `console.sso.subjects` entry.
|
||||
- H2. A user principal comes only from an OIDC sign-in, through a path the bus verifies. No CLI path for
|
||||
users.
|
||||
- H3. The user binding fails closed on no live grant, an unknown subject, a subject also in
|
||||
`console.sso.subjects`, or a missing or invalid access.json. A broken access.json never stops the owner.
|
||||
- H4. Agent processes never get an owner or user principal.
|
||||
- H5. Revocation ends a bound user within 30 s and at once on `access.reload`, from the same access state
|
||||
row 193's share check reads.
|
||||
|
||||
The same-uid limit. Within one instance, a non-agent process on the instance's uid can claim the owner, and
|
||||
can start its own Console copy and claim any granted user (FED 3.6). An unsandboxed same-uid agent that
|
||||
detaches from its ancestry can do the same. The walk doesn't stop that, and Gander's design won't claim it
|
||||
does (gander-0005). Several humans don't make this worse: a user principal is no stronger than the owner
|
||||
principal that the same process could already take. Users themselves are not on the uid. They reach the
|
||||
bus only through the Console, so the limit is about local processes, not other humans.
|
||||
|
||||
Does row 190 narrow it? Row 190 runs several instances under one uid, so no. Row 190b puts an instance (the
|
||||
hub) under its own Linux user (mos-0986). That narrows reach across instances: another instance's uid fails
|
||||
the uid check (human.mjs:67) and can't read the hub's store or access.json. It does not narrow reach within
|
||||
one instance. Private threads are private from other humans using the bus, not from processes running as
|
||||
the instance's uid.
|
||||
|
||||
## 7. Migration and rollback (brief point 6)
|
||||
|
||||
- No access.json: the business has exactly its owner, every verb behaves as today, and the share verbs
|
||||
work for the owner only (target `*` or none). A broken access.json revokes users and leaves the owner.
|
||||
- Existing threads: already owned by the business human. Nothing is rewritten.
|
||||
- Schema: 3i to 3j adds `thread_shares` only. A re-pin past a schema bump needs a `--migrate` window with
|
||||
Jason, and row 185's backup before activate covers it.
|
||||
- Rollback before any share is written: activate the previous copy with the store restored from the
|
||||
pre-activate backup. A 3i copy refuses a 3j store, as it does for every bump.
|
||||
- Rollback after shares are written: the same restore loses shares made since the window. Grants are in
|
||||
access.json and survive. Users re-share. Row 181's restore guard counts `thread_shares`, so the loss is
|
||||
shown, not silent.
|
||||
- To keep that window small, the build splits (section 9): 193a, 193b1, 193c and 193d have no schema
|
||||
change and can go live in any window. 193b2 carries 3j.
|
||||
|
||||
## 8. Tests and mutants
|
||||
|
||||
Bus, each in `packages/bus/tests/` (193b1: viewer, mixed grants, board reads, the 5.7 message filter and governance pin; 193b2: shares, the share exception to the filter, migration):
|
||||
|
||||
- Viewer: each allowed verb works, every other verb refuses `access-refused`, including `thread.create`,
|
||||
`thread.open`, `thread.send` and `thread.share`.
|
||||
- Mixed grants: collaborator on project A and viewer on B. Create in A works, create in B refuses.
|
||||
- Downgrade: not here. FED R4 owns the level-loss test and its mutant (r4.4, mos-1020, N3).
|
||||
- Shares: owner shares with `user:<id>`, the user reads `thread.messages` and gets `thread-not-owned` on
|
||||
`thread.send` and `thread.open`. Share with `*` reaches every covered user and the owner. Share with a user
|
||||
whose grant doesn't cover the project or instance refuses `share-not-covered`.
|
||||
- A share never widens: the target's grant drops the project, the next read refuses.
|
||||
- Revoke, expiry and an invalid file each end share reads on the next request. The 30 s timer and
|
||||
`access.reload` paths each have a case.
|
||||
- A revoked thread owner hides the thread from sharees.
|
||||
- Unshare ends access. Share, unshare, share again leaves it shared (latest row wins).
|
||||
- Non-owner `thread.share`, `thread.unshare`, `thread.shares` refuse. Tester refuses on all three.
|
||||
- `thread.list` plain shape unchanged. `thread.list {shared: true}` returns only readable threads.
|
||||
- Board reads refuse users and viewers.
|
||||
- Governance pin (B1, sage-1368): a user-thread run raises a decision; it shows in the owner's
|
||||
`decisions recent` with its question text, and `inbox` lists it when routed to the human; the run's
|
||||
role claim shows in the owner's `agents`, its task write in `tasks`, and its `record.write` in
|
||||
`project.file` (B3, sage-1373); the user's message bodies stay hidden from the owner's `trail` and
|
||||
`replies`. The test names each item of the 5.7 user sentence, so the sentence and the pin match.
|
||||
- `trail`, for the owner, a reader session and the tester (193b1): a user's thread message as `subject`
|
||||
fails `message-not-found`; a decision trail that reaches such a message omits it, its deliveries and its
|
||||
events. Once the thread is shared with the owner, the owner's trail shows it.
|
||||
- `replies`, same three sessions (193b1): a hidden `id` fails `message-not-found`; hidden replies are dropped. The
|
||||
owner's own and the tester's threads are unchanged.
|
||||
- Migration: a 3i store with threads migrates to 3j, row counts unchanged, `thread_shares` empty and
|
||||
append-only (update, delete, replace each abort). Restore-guard and `COUNTED` include it.
|
||||
|
||||
Business (193a): R1 accepts `viewer`, refuses any other new level.
|
||||
|
||||
CLI (193c): `mosaic access user add/remove` and `grant --level viewer` refuse tester and agent callers,
|
||||
write a receipt line and call `access.reload`.
|
||||
|
||||
Webui (193d): a viewer has no composer or share control. With each UI check removed, the bus still refuses.
|
||||
|
||||
Mutants, each must be killed:
|
||||
|
||||
1. `#readable` rule 1 dropped (any covered user reads any thread).
|
||||
2. Rule 2 dropped (a share widens the grant).
|
||||
3. Rule 3 dropped (a revoked owner's thread stays visible).
|
||||
4. Latest-row lookup replaced by "any share row" (unshare ignored).
|
||||
5. (Moved to FED R4, N3: the level-loss mutant is R4's.)
|
||||
6. Viewer allowed `thread.send`.
|
||||
7. `#threadRead` used for `thread.send` (sharee writes).
|
||||
8. `share-not-covered` check removed.
|
||||
9. `thread.share` owner check removed (sharee re-shares).
|
||||
10. A user allowed `trail`.
|
||||
11. The `trail` filter removed (the owner reads a user's unshared message by id).
|
||||
12. The `replies` filter removed (the owner reads replies in a user's unshared thread).
|
||||
|
||||
## 9. Build rows and order
|
||||
|
||||
| Row | Work | Chains on | Schema |
|
||||
|---|---|---|---|
|
||||
| 193a | R1 level check widened to viewer | FED R1 candidate | none |
|
||||
| 193b1 | Bus: viewer verb list, per-grant level checks, users refused on board reads, the 5.7 `trail` and `replies` filter with `#readable` as owner-only | FED R3, R4 candidates, row 196 verifier | none |
|
||||
| 193b2 | Bus: `thread_shares`, share verbs, the share rules of `#readable`, `#threadRead`, the 5.5 share filters | 193b1 candidate | 3j |
|
||||
| 193c | `mosaic access` user verbs and `--level viewer`, if R5 lacks them | FED R5 candidate | none |
|
||||
| 193d | Console: shared list, share controls, viewer read-only | FED R6, row 192 candidates, 193b2 for share controls | none |
|
||||
|
||||
Sage ruled the split (sage-1354): 193b1 has no schema change and can go live first. 193b2 carries 3j, and
|
||||
Sage takes its migrate window to Mos when 193b2 is near. The 5.7 message filter is in 193b1 (Duckworth B2,
|
||||
sage-1368), so it is live before any user thread can be, whatever order FED R8 and 193b2 land in. 193b2 adds
|
||||
only the share exception. FED R4 chains on 193a (viewer level), and 193b1 chains on R4.
|
||||
|
||||
Coverage, settled in FED r4.1 (73677b87d, gizmoduck-0018, still under Duckworth's review). A grant's
|
||||
`projects` is `["*"]` or bus project UUIDs (`projects.id`, broker.mjs:2306; `threads.project` references it).
|
||||
R1 exports one pure `covers(grant, {business, project, instance}, now, {level})`. Row 193 uses only that
|
||||
function and adds no second one (Sage confirmed, sage-1354):
|
||||
|
||||
- share reads (5.4 rules 2 and 3) and `share-not-covered`: `covers(g, thread, now, {})`, any level;
|
||||
- `thread.create`, `thread.open`, `thread.send`, `thread.share`: `covers(g, thread, now, {level: 'collaborator'})`;
|
||||
- `project.list` and `names` for users: any level, as FED 3.5.
|
||||
|
||||
`covers` needs no further argument for row 193. If r4.1 changes in review, 193b1 follows it.
|
||||
|
||||
Follow-ups, not in this row:
|
||||
|
||||
- A read-only users and grants page for the owner in the Console.
|
||||
- A second owner or admin level, if Jason wants one.
|
||||
- An explicit, logged owner audit verb for user threads, only if Jason asks for one (sage-1354).
|
||||
|
||||
## 10. Gate
|
||||
|
||||
Per the brief: Duckworth approves this design, then the manifest. The bus, business, cli and webui suites and
|
||||
every `scripts/test-*.sh` pass on Sage's gate, and the section 8 mutants are killed. No test touches the live
|
||||
directories. No product code before Duckworth approves.
|
||||
@@ -0,0 +1,249 @@
|
||||
# Row 209 phase B research: one ChatGPT account, two separate sign-ins
|
||||
|
||||
Researcher seat, 2026-10-24. Request: sage-4291 (mos-1616 item 2). Public docs and public issues only.
|
||||
Nothing here read, copied or tested a token, an auth file, `<configDir>/secrets/`, `<dataRoot>/proxy/`,
|
||||
the 8317 host proxy, `~/.local/opt/EasyCLIProxyAPI` or `~/.mosaic-dev`. No sign-in was run.
|
||||
|
||||
Tags: **[R]** read on the cited page. **[S]** secondary summary (zread.ai or a search snippet), not
|
||||
checked on the primary page. **[I]** my inference, not stated by any source.
|
||||
|
||||
CLIProxyAPI v8.0.42 files were read at the tag through GitHub. Hermes pages were read at their current
|
||||
state, not at the version Chet runs. I do not know that version.
|
||||
|
||||
## Summary
|
||||
|
||||
| Question | Answer |
|
||||
|---|---|
|
||||
| 1. Do two separate grants coexist? | **Unknown, leaning coexist.** Two public tests say coexist. One field incident and Hermes's own docs say the older login dies. OpenAI says nothing either way. |
|
||||
| 2. Lifetimes, rotation | Access token about 10 days [R]. Refresh token rotates on every refresh [R]. A replaced token still works for at least 30 minutes, then fails by about 27 hours [R, one test]. Refresh-token lifetime: no public source. |
|
||||
| 3. Refresh on each side | Both sides have an on-demand refresh that needs no one to read a token. Waiting for a natural refresh would take about 6 days (CLIProxyAPI) to about 10 days (Hermes), too long for a window. |
|
||||
|
||||
## Question 1: coexist, revoke or unknown
|
||||
|
||||
**Verdict: unknown, leaning coexist.** Mos's expectation (the known failure comes from two clients
|
||||
sharing one copied auth file, not from separate grants) is **supported for the shared-file case and
|
||||
unconfirmed for the separate-grant case.**
|
||||
|
||||
### What is established: sharing one token family breaks it
|
||||
|
||||
- Refresh tokens rotate, and a spent one is refused. Codex reports "Your access token could not be
|
||||
refreshed because your refresh token was already used. Please log out and sign in again." [R]
|
||||
https://github.com/openai/codex/issues/10332
|
||||
- Every report I opened that names a cause involves several processes holding one token family: several
|
||||
Codex app-servers on one `~/.codex` [R] https://github.com/openai/codex-plugin-cc/issues/789 ;
|
||||
three app-servers on one login pair [R] https://github.com/keanji-x/neige-calm/issues/2314 ;
|
||||
Hermes and the Codex CLI each holding a copy after Hermes adopted the CLI's pair [R]
|
||||
https://github.com/NousResearch/hermes-agent/issues/113023 ; three Hermes profile stores with
|
||||
identical token fingerprints [R] https://github.com/NousResearch/hermes-agent/issues/87503
|
||||
- OpenAI's own CI guide says "Do not share the same file across concurrent jobs or multiple machines"
|
||||
and lists "another machine or concurrent job rotated the token first" as a reason to reseed. [R]
|
||||
https://learn.chatgpt.com/docs/auth/ci-cd-auth
|
||||
|
||||
### Evidence that separate sign-ins coexist
|
||||
|
||||
1. awaywork issue 190, run 2026-10-11 on Codex 0.162.1, free plan, throwaway `CODEX_HOME`s, device-auth
|
||||
logins on one account. Reported result, tagged "[V, tested]": "Coexist; a new login revokes none". Logging
|
||||
out one of three left the other two working. [R, issue and PR description; I did not see the
|
||||
`docs/providers.md` table or the exact steps]
|
||||
https://github.com/AndreaProvenzale/awaywork/issues/190 and
|
||||
https://github.com/AndreaProvenzale/awaywork/pull/194
|
||||
2. jyje/hermes-agent-helm issue 368, closed 2026-10-19. Three isolated Hermes v0.22.2 releases logged in
|
||||
to one **Plus** ChatGPT account within minutes of each other. `hermes auth refresh openai-codex` on each
|
||||
at login, about 1 hour, about 10 hours and about 24 hours. "No login was revoked, and no
|
||||
`refresh_token_reused` or `invalid_grant` error appeared." One 24-hour refresh hit a lock timeout on
|
||||
the auth store and succeeded on retry. [R] https://github.com/jyje/hermes-agent-helm/issues/368
|
||||
This is the closest match to Chet's setup (Hermes, Plus), but each login sat in its own release, not in
|
||||
one Hermes pool.
|
||||
3. A Codex Desktop report shows one "Active sessions" row per Desktop sign-in, with older rows kept. [R]
|
||||
https://github.com/openai/codex/issues/40632 . [I] This fits one grant per sign-in, but the page does not
|
||||
say so.
|
||||
4. [I] The mechanism is per refresh-token family, and a new sign-in starts a new family. No source states
|
||||
this for ChatGPT.
|
||||
|
||||
### Evidence that a second sign-in revokes the older one
|
||||
|
||||
1. Hermes issue 47096: one working `openai-codex` credential, then a second added by a separate device-code
|
||||
login (not a copied file). Credential 1 later showed status dead, HTTP 401, `token_revoked`. Its token
|
||||
fingerprints were unchanged, so Hermes did not overwrite it. [R] The reporter never said both logins
|
||||
were the same OpenAI account, there was no check between the add and the later inspection, and no
|
||||
control login. "OpenAI revoking the older token family when the same user logs in again" is the
|
||||
maintainer's reading. [R] https://github.com/NousResearch/hermes-agent/issues/47096
|
||||
2. Hermes's docs state it as fact: "two logins of the same account share one token family upstream, so
|
||||
OpenAI revokes the older one." [R]
|
||||
https://hermes-agent.nousresearch.com/docs/user-guide/features/credential-pools . PR 115895 added a
|
||||
warning at `hermes auth add` time. The PR's only cited basis is issue 47096. [R]
|
||||
https://github.com/NousResearch/hermes-agent/pull/115895
|
||||
3. neige-calm issue 2314 says "A new device login revokes every older pair" in passing. It gives no test,
|
||||
and its three holders were already sharing one pair. [R]
|
||||
4. Hermes issue 73667: both Hermes credentials got `401 token_revoked` seconds before Codex Desktop issued
|
||||
a new token. The timeline puts the revocations before the Desktop issue line, so it does not show the
|
||||
Desktop sign-in as the cause. [R] https://github.com/NousResearch/hermes-agent/issues/73667
|
||||
|
||||
### Reading the conflict
|
||||
|
||||
- The two coexistence tests were deliberate and report no revocation. The revocation claim rests on one
|
||||
uncontrolled incident that was then written into docs.
|
||||
- Neither side is vendor confirmed. OpenAI's auth docs do not address two sign-ins on one account.
|
||||
https://learn.chatgpt.com/docs/auth
|
||||
- Open gaps in the coexist evidence: the longest span tested is about a day (helm), against a 10-day access
|
||||
token; plan types tested are free and Plus; only one of the two tests used Hermes; nobody tested a
|
||||
CLIProxyAPI login next to a Hermes login.
|
||||
- Hermes issue 39236 shows Hermes can overwrite its own `manual:device_code` pool entries with the newest
|
||||
pair. [R] https://github.com/NousResearch/hermes-agent/issues/39236 . That is a local failure and was
|
||||
fixed (PR 42316), but it is another way a "second login" can break Hermes without OpenAI revoking
|
||||
anything.
|
||||
|
||||
### What this means for the plan
|
||||
|
||||
- Do not treat "they coexist" as settled. Mos's fallback (Chet's login goes in only after Hermes's Chet
|
||||
stops, inside the window with Jason present) fits the evidence.
|
||||
- Whichever order is used, the plan avoids the one proven failure if nothing is copied between the two.
|
||||
CLIProxyAPI's `/oauth/import` accepts only a Vertex service account in v8 (`provider=vertex`), so it
|
||||
cannot be used to move a Codex login. [R]
|
||||
https://raw.githubusercontent.com/router-for-me/CLIProxyAPI/v8.0.42/docs/management-api-v8.md
|
||||
- Hermes borrows a Codex CLI login by default. `auth.adopt_external_logins` defaults to `true` (PR 115586,
|
||||
merged 2026-09-19). Hermes then takes over and refreshes the CLI's pair when its own refresh fails. [R]
|
||||
https://github.com/NousResearch/hermes-agent/pull/115586 . CLIProxyAPI keeps its own `auth-dir` and
|
||||
does not read `~/.codex` [S]. The only shared-family risk is Hermes adopting a `~/.codex` file, so
|
||||
setting that key to `false` for Chet's Hermes closes it. [I] that Chet's account has a `~/.codex` at all.
|
||||
- Sage can settle the question in the window with one safe check, which needs no token read: after both
|
||||
sign-ins exist, force a refresh on one side, then on the other, then on the first again, and confirm all
|
||||
three succeed (see question 3). That proves the two grants are alive after one rotation each. It does not
|
||||
prove a 10-day cycle.
|
||||
|
||||
## Question 2: lifetimes and rotation
|
||||
|
||||
| Item | Finding | Source |
|
||||
|---|---|---|
|
||||
| Access token | About 10 days. JWT `iat` to `exp` was 2026-07-31 13:10 to 2026-08-10 13:10 in one Hermes report. | [R] https://github.com/NousResearch/hermes-agent/issues/87503 |
|
||||
| Access token, CLIProxyAPI | Issued 2026-09-26 about 14:39, expired 2026-10-06 about 14:39. | [R] https://github.com/router-for-me/CLIProxyAPI/issues/6742 |
|
||||
| Access token, Codex CLI | awaywork records "a 10-day JWT" and says refresh happens at expiry, not at 8 days after `last_refresh`. | [R] https://github.com/AndreaProvenzale/awaywork/pull/194 |
|
||||
| Codex CLI refresh trigger | OpenAI's CI guide says Codex refreshes when `last_refresh` is older than "about 8 days", "in the current open-source client". It gives no lifetime figure. The awaywork test disagrees. | [R] https://learn.chatgpt.com/docs/auth/ci-cd-auth |
|
||||
| Refresh token rotates | Every refresh issues a new refresh token. | [R] awaywork 194 above; Hermes PR 115586 ("single-use and rotate") |
|
||||
| Refresh token single-use | **Not strictly.** An OpenAI maintainer said the server accepts a reused refresh token for a limited window "on the order of an hour" before it is permanently invalidated. [R] https://github.com/openai/codex/issues/10332 . awaywork found a replaced token still worked after 8 seconds, about 6 minutes and about 30 minutes, and failed after about 27 hours. The exact window is between those. [R, one test] A failed reuse did not kill the live login. |
|
||||
| Whole family revoked on reuse | Hermes code comment, quoted in the issue, says OpenAI "revokes the whole token family on reuse". | [R, secondhand quote] https://github.com/NousResearch/hermes-agent/issues/113023 |
|
||||
| Refresh token lifetime when unused | **No public source found.** OpenAI's docs list "the refresh token was revoked or expired" as a reseed reason and give no figure. | [R] https://learn.chatgpt.com/docs/auth/ci-cd-auth |
|
||||
| Token endpoint | `https://auth.openai.com/oauth/token`, form POST, `grant_type=refresh_token`. CLIProxyAPI uses the same hard-coded public client ID as the Codex CLI. | [R] https://raw.githubusercontent.com/router-for-me/CLIProxyAPI/v8.0.42/internal/auth/codex/openai_auth.go |
|
||||
|
||||
A caution on weekly failures: CLIProxyAPI issues 3654 and 6742 report Codex credentials going invalid about
|
||||
every 7 days, three days before the access token's expiry. Maintainer fix feb6398 (the 96-hour lead
|
||||
below) closed 6742, and it gives no reason in writing. [R]
|
||||
https://github.com/router-for-me/CLIProxyAPI/issues/3654 ,
|
||||
https://github.com/router-for-me/CLIProxyAPI/issues/6742 . The cause is not established in public.
|
||||
|
||||
## Question 3: how each side refreshes
|
||||
|
||||
### CLIProxyAPI 8.0.42, Codex credential
|
||||
|
||||
- Background refresh. A loop checks every 5 seconds (`refreshCheckInterval`), up to 16 at a time, with a
|
||||
5-minute failure backoff and a 1 to 30 minute invalid-grant backoff. [R]
|
||||
https://github.com/router-for-me/CLIProxyAPI/blob/v8.0.42/sdk/cliproxy/auth/conductor_refresh.go
|
||||
- Lead time. Commit feb6398 (2026-10-18, closes issue 6742) raised the Codex outer refresh lead from 24
|
||||
hours to 96 hours. The commit message says "to prevent upstream token invalidation". The file at the
|
||||
v8.0.42 tag already refers to `CodexOuterRefreshLead`. [R]
|
||||
https://github.com/router-for-me/CLIProxyAPI/commit/feb6398456ccaed50d20dfc6353ad050ef714d31 ,
|
||||
https://raw.githubusercontent.com/router-for-me/CLIProxyAPI/v8.0.42/internal/runtime/executor/codex_executor_auth.go .
|
||||
The constant's definition was not on a page I read, so "96 hours at 8.0.42" is [I] from the commit and
|
||||
its updated test. A 401 on a request also schedules an immediate refresh. [R, same commit]
|
||||
- Release notes for v8.0.42 (2026-10-24) say nothing about Codex, OAuth or refresh. [R]
|
||||
https://github.com/router-for-me/CLIProxyAPI/releases/tag/v8.0.42
|
||||
- Concurrency inside CLIProxyAPI. Refreshes with the same token are collapsed (singleflight), and the file
|
||||
is re-read under a file lock before and after a refresh, so a rotation by another CLIProxyAPI process on
|
||||
that file is picked up. [R] `codex_executor_auth.go` above. A late caller holding a pre-rotation token
|
||||
can still send a second refresh. PR 6165 (five-minute result cache) is open, not merged, as read. [R]
|
||||
https://github.com/router-for-me/CLIProxyAPI/pull/6165 . In-flight overwrite (issue 6417) was fixed by
|
||||
commit 935aa6e on 2026-10-07, before 8.0.42. [R]
|
||||
https://github.com/router-for-me/CLIProxyAPI/issues/6417
|
||||
None of this locks against Hermes. CLIProxyAPI's lock covers its own credential file only. [I]
|
||||
- **On-demand refresh, no token read.** The management API has `POST /credentials/refresh` (under
|
||||
`/v8/management`). Auth is the management key, sent as `Authorization: Bearer <key>` or
|
||||
`X-Management-Key`. [R]
|
||||
https://raw.githubusercontent.com/router-for-me/CLIProxyAPI/v8.0.42/docs/management-api-v8.md
|
||||
A secondary summary says it refreshes one credential or, with `?all=true`, all of them. [S]
|
||||
https://zread.ai/router-for-me/CLIProxyAPI/17-management-api . The primary page lists no parameters, so
|
||||
how to name one credential is unconfirmed.
|
||||
A forced refresh sets a force flag in the context. In `refreshLocked` that flag sets `needOuter` true when
|
||||
an outer refresh token exists, so it skips the 96-hour check. [R] `codex_executor_auth.go` above. I could
|
||||
not read `ForceRefreshAuth` itself, so that these two are connected is [I].
|
||||
The call needs the management key, a secret. It is not an OAuth token, but the hard limits say nobody
|
||||
reads a token or auth file, and Sage should decide whether the key is covered.
|
||||
- Natural refresh timing. A fresh login has a 10-day access token and a 96-hour lead, so the first
|
||||
background refresh falls about 6 days after login. [I] from the two figures above. Waiting for it is not
|
||||
practical in a window.
|
||||
|
||||
### Hermes
|
||||
|
||||
- Refresh is lazy for `openai-codex`: the first attempt happens at expiry on an idle box, unlike Nous,
|
||||
which has a 6-hour keepalive. On a 401 the pool tries a refresh first and rotates entries only if that
|
||||
fails. [R] https://github.com/NousResearch/hermes-agent/issues/87503 ,
|
||||
https://hermes-agent.nousresearch.com/docs/user-guide/features/credential-pools
|
||||
I found no skew or lead figure for Codex in public docs. A Hermes run that sits idle may not refresh for
|
||||
about 10 days.
|
||||
- Storage and adoption. Hermes keeps its own login in `~/.hermes/auth.json`. It adopts a `~/.codex` login
|
||||
only to repair a failed refresh, and only when `auth.adopt_external_logins` is true (the default). [R]
|
||||
https://github.com/NousResearch/hermes-agent/pull/115586
|
||||
- **On-demand refresh, no token read.** `hermes auth refresh <provider> [target]` refreshes one OAuth
|
||||
credential and returns it to rotation. The docs say it "proves the grant is alive". The CLI reference
|
||||
example is `hermes auth refresh openai-codex work`. [R]
|
||||
https://hermes-agent.nousresearch.com/docs/user-guide/features/credential-pools ,
|
||||
https://hermes-agent.nousresearch.com/docs/reference/cli-commands . The helm test above used it on a
|
||||
Plus account. It needs no management key.
|
||||
|
||||
### How long a natural-refresh check would run
|
||||
|
||||
- CLIProxyAPI: about 6 days after the sign-in. [I]
|
||||
- Hermes: about 10 days after the sign-in, and only if it makes a request near expiry. [I]
|
||||
- Both are too long for the window. The forced refreshes above are the practical check. Each forced
|
||||
refresh rotates that side's refresh token once, and it does not wait for expiry.
|
||||
|
||||
## Open items nobody can answer from public sources
|
||||
|
||||
1. Whether a second sign-in on one ChatGPT account revokes the first. Two tests say no (free plan,
|
||||
Plus, up to about a day). One incident and Hermes's docs say yes. OpenAI has not said.
|
||||
2. The refresh-token lifetime when unused.
|
||||
3. The exact reuse grace window (between about 30 minutes and about 27 hours in one test; "on the order
|
||||
of an hour" from OpenAI's maintainer).
|
||||
4. How `POST /credentials/refresh` selects a single credential at 8.0.42.
|
||||
5. Hermes's Codex refresh skew, and whether the version Chet runs has `auth.adopt_external_logins`.
|
||||
6. Behavior over a full 10-day cycle with two grants live.
|
||||
|
||||
## Source list
|
||||
|
||||
OpenAI
|
||||
- https://learn.chatgpt.com/docs/auth (redirect target of https://developers.openai.com/codex/auth)
|
||||
- https://learn.chatgpt.com/docs/auth/ci-cd-auth
|
||||
- https://github.com/openai/codex/issues/10332
|
||||
- https://github.com/openai/codex/issues/40632
|
||||
- https://github.com/openai/codex-plugin-cc/issues/789
|
||||
|
||||
CLIProxyAPI (router-for-me)
|
||||
- https://github.com/router-for-me/CLIProxyAPI/releases/tag/v8.0.42
|
||||
- https://raw.githubusercontent.com/router-for-me/CLIProxyAPI/v8.0.42/docs/management-api-v8.md
|
||||
- https://raw.githubusercontent.com/router-for-me/CLIProxyAPI/v8.0.42/internal/auth/codex/openai_auth.go
|
||||
- https://raw.githubusercontent.com/router-for-me/CLIProxyAPI/v8.0.42/internal/auth/codex/refresh_patch.go
|
||||
- https://raw.githubusercontent.com/router-for-me/CLIProxyAPI/v8.0.42/internal/runtime/executor/codex_executor_auth.go
|
||||
- https://github.com/router-for-me/CLIProxyAPI/blob/v8.0.42/sdk/cliproxy/auth/conductor_refresh.go
|
||||
- https://github.com/router-for-me/CLIProxyAPI/commit/feb6398456ccaed50d20dfc6353ad050ef714d31
|
||||
- https://github.com/router-for-me/CLIProxyAPI/issues/1999 , /2385 , /3654 , /6417 , /6742 , /6288
|
||||
- https://github.com/router-for-me/CLIProxyAPI/pull/6165 , /6289
|
||||
- https://zread.ai/router-for-me/CLIProxyAPI/17-management-api [S]
|
||||
- https://zread.ai/router-for-me/CLIProxyAPI/11-multi-provider-auth-system [S] (stale: says a 24-hour Codex
|
||||
lead, superseded by feb6398)
|
||||
|
||||
Hermes (NousResearch)
|
||||
- https://hermes-agent.nousresearch.com/docs/user-guide/features/credential-pools
|
||||
- https://hermes-agent.nousresearch.com/docs/reference/cli-commands
|
||||
- https://github.com/NousResearch/hermes-agent/issues/113023 , /87503 , /73667 , /47096 , /39236
|
||||
- https://github.com/NousResearch/hermes-agent/pull/115586 , /115895
|
||||
|
||||
Third-party tests
|
||||
- https://github.com/AndreaProvenzale/awaywork/issues/190
|
||||
- https://github.com/AndreaProvenzale/awaywork/pull/194
|
||||
- https://github.com/jyje/hermes-agent-helm/issues/368
|
||||
|
||||
Other reports of the shared-family failure
|
||||
- https://github.com/keanji-x/neige-calm/issues/2314
|
||||
- https://github.com/musistudio/claude-code-router/issues/1879 [S, search snippet only]
|
||||
|
||||
Items in the first three search rounds (openclaw 26322 and 57107, pydantic-ai PR 10615, ai-shuffle 199,
|
||||
hermes-realtime 178, mnbf9rca/hermes-agent 3) were seen as search results only and are not relied on.
|
||||
@@ -0,0 +1,105 @@
|
||||
# Sage handoff after the T3 crash, 2026-10-24
|
||||
|
||||
Written 22:54Z by Sage (T3 1ef1e4f8-3ead-4208-beca-38f9f1add079) under Mos's mos-1628: "The T3 server
|
||||
crashed and killed your running processes. Do not restart long jobs." My processes died at 22:42:37Z. I
|
||||
started nothing long after that. The next Sage session resumes from this file, `scripts/mosaic queue next
|
||||
sage` and the message keys below. The next free key is sage-4297.
|
||||
|
||||
## Refs
|
||||
|
||||
- origin/refactor and the canonical HEAD were both c8a9bcf94 before this handoff commit.
|
||||
- The canonical checkout still has eight staged deletions under agents/rocko/work/queue-219 that belong to
|
||||
Rocko. Leave them as they are.
|
||||
- docs/plans/queue.json and QUEUE.md carry uncommitted queue revs, mine and other seats'. Committing them is
|
||||
queue-commit slot work, which sweeps every seat's pending revs, so I didn't run it during the crash stop.
|
||||
|
||||
## Row 329 (P1, #1827): gate red, held for Mos's ruling
|
||||
|
||||
- Both round 2 APPROVEs are recorded: Dewey c31643 at rev 4047 and Boyd c31642 at rev 4048, on candidate
|
||||
86cb5c221 with manifest 86718a1a.
|
||||
- Landing tree: /mnt/storage/scratch/sage-r329l/wt, detached at 8b4978887. That's Magica's four r2 commits
|
||||
(3a27990b4, 6a4f599df, 953773729, 8b4978887) cherry-picked onto c8a9bcf94. The BUILD-LOG.md and
|
||||
docs/SESSIONS.md conflicts were kept both ways, HEAD first. Nothing is pushed.
|
||||
- The gate (`bash gate.sh 8b4978887 c8a9bcf94` in /mnt/storage/scratch/sage-r329l) started 22:20:17Z on
|
||||
lane A. The crash killed it after `tasks` (22:40:20Z), so webui and every scripts/test-*.sh never
|
||||
reported. The output is in `r329-gate.out` here.
|
||||
- Red: cli went 1000 tests, 997 pass, 2 fail, 1 skip (FED R7). Both reds are in
|
||||
packages/cli/tests/case1-accept.test.mjs:421, the row253 C4 P10 loop. `inner` expected
|
||||
`reason=probe-inner-timeout` and `outer` expected `probe-outer-timeout`; both got `probe-inner-command`.
|
||||
`overflow` passed. The failure text is in `r329-cli-failures.txt`.
|
||||
- 329 doesn't touch case1-accept.test.mjs, case-sudo-fixture.mjs or scripts/case1-accept.sh (git diff
|
||||
--quiet c8a9bcf94..8b4978887). Magica's r2 gate had the file at 53/0.
|
||||
- Unverified hypothesis. `inner-command` is the catch-all in scripts/case1-accept.sh:228 (supervisor exit
|
||||
other than 81-86). The C4 loop arms fixtureGuard(t,files,7000), which SIGKILLs a recorded fixture pid
|
||||
after 7 s. A fault run longer than that would turn 81 or 82 into 87. The test asserts before its
|
||||
t.diagnostic line, so there's no per-mode timing. Della's 284 lane B run shared the host until about
|
||||
22:34Z. That's a timing fact, not a proven cause, and it isn't written up as load (mos-1603-1605).
|
||||
- I sent the red to Mos as sage-4296 twice. Both sends failed: T3 GET timed out after 30 s while the server
|
||||
was going down. So Mos has it only through this file and mos-1628 note 1.
|
||||
- Rerun request for Mos: a fresh full landing gate on 8b4978887 with lane B quiet, so the gate prints GREEN
|
||||
by itself (mos-1605). Before that, a Vikunja task for the P10 C4 timing, a sibling to 625. I don't
|
||||
recommend a case1-accept single-file rerun.
|
||||
- After GREEN, the landing steps:
|
||||
1. push-check, then push 8b4978887;
|
||||
2. comment on #1827 and close it, and close the row's Vikunja task;
|
||||
3. queue note, then done with --op only;
|
||||
4. DEFERRED append from `r329-deferred-draft.md` (N2 and R2-N1 bound to 331, N1 bound to the P7
|
||||
cutover);
|
||||
5. the BUILD-LOG and SESSIONS lines.
|
||||
|
||||
## Queue writes: what landed and what to redo
|
||||
|
||||
| Op | Write | State |
|
||||
|---|---|---|
|
||||
| sage-332-assign-1024a | assign 332 fethry | ok, rev 4054 |
|
||||
| sage-284-reviewers-1024b | set 284 reviewers webby | ok, rev 4055 |
|
||||
| sage-333-reviewers-1024b | set 333 reviewers boyd,duckworth | killed mid-write; 333 still shows boyd,dewey |
|
||||
| sage-332-after-1024b | set 332 after none | not run; 332 still after 331 |
|
||||
| sage-add-case2-proxy-unit-1024b | add the Case 2 proxy unit row (#1832) | not run |
|
||||
|
||||
- The crash left a dead lock: pid 2150897, op sage-333-reviewers-1024b. I removed it with `scripts/mosaic
|
||||
queue unlock` at about 22:50Z, after checking the pid was dead.
|
||||
- To redo the three writes, run `/mnt/storage/scratch/sage-r329l/batch-5.sh` without its first two lines.
|
||||
If the 333 op refuses as already used, give it a new op id.
|
||||
- The add's gate text is 258 characters (the limit is 300). It uses --issue 1832, --owner sage, --gate-owner
|
||||
sage, --after 329, --reviewer boyd and --reviewer webby. The brief is
|
||||
docs/plans/2026-10-24_case2-proxy-unit-brief.md#Brief: Case 2 proxy unit in case2-unit.sh and
|
||||
case2-install.sh (blob eddcec47 at c8a9bcf94).
|
||||
- Don't write batches with `pgrep -f` waiters. They deadlocked on 10-24, because the parent shell's command
|
||||
line contains the script text.
|
||||
|
||||
## Seats and lanes at the stop
|
||||
|
||||
- Lane A: the 329 gate, now dead. Lane B: Della finished 284 r2 at about 22:34Z (della-0059: 279 whole files,
|
||||
2501/0, 1 skip FED R7, M1-M9 killed, case1-accept not run) and said she'd commit BUILD receipts and then
|
||||
hand 284 in-review to Webby and me. Gyro got lane B CLEAR (sage-4294) and handed it back unused
|
||||
(gyro-0031). Fethry's 332 is next on lane B.
|
||||
- Fethry (65673bd9, row 332, P3): sage-4293 settled route encoding. Proxy entries in `launch.models` carry
|
||||
an explicit route key (Anthropic, GLM openai-completions, or GPT through the stack's own provider). A
|
||||
missing or unknown route refuses. Catalog-membership inference is out. Fethry picks the key name, and
|
||||
BUILD.md records it under P3 item 5. P2's `{ baseUrl, key }` seam doesn't change. Before CLEAR, Fethry
|
||||
owes his run list inline or pushed (IMPORT-RUN-LIST.txt, 211 entries, case1-accept off; I don't read
|
||||
worktrees) and a resend of fethry-0001..0003.
|
||||
- Herb (214): candidate 584ee1e20 is static CLEAN from Filbert. Herb needs a queue-write gap for his
|
||||
claimant in-review move. Then I post the request as jarvis for Filbert, and run the 214 landing gate on
|
||||
lane A after 329.
|
||||
- Researcher: row209-phase-b/REPORT.md (sha256 20421e52...ce017) is committed in this handoff commit. Its
|
||||
results still need to go to Mos and into row 209's record. Q1 is unknown, leaning coexist. Q2: the access
|
||||
token lasts about 10 days and the refresh token rotates. Q3: CLIProxyAPI's forced refresh needs the
|
||||
management key, so under D6 only a human can run it, through the P4 page. Researcher also suggests
|
||||
`auth.adopt_external_logins=false` for Hermes's Chet.
|
||||
|
||||
## Done before the stop
|
||||
|
||||
- mos-1618 / Vikunja #630: minted bot-faceless (user 15, key 15, expires 2027-01-07) into
|
||||
~/.config/mosaic-dev/secrets/mosaic-stack/faceless-vikunja.token, mode 600. Its scopes match key 12. The
|
||||
receipt is agents/sage/work/vikunja-setup/2026-10-24_mint-faceless.json, committed here. Mos received
|
||||
sage-4295. The ops-01 team add for project 33 waits until after the restart.
|
||||
|
||||
## Not yet sent to Mos (mos-1616 summary)
|
||||
|
||||
- The blobs 079debd5 and eddcec47 at c8a9bcf94, and #1832.
|
||||
- The `--proxy` flag choice and its tradeoff: root reads no config, and both wrong-flag cases fail closed.
|
||||
- The 329 request, hand-posted at c31641 (the manifest is over 60000 bytes), and both APPROVEs.
|
||||
- 229 blocked and 209's brief set; 284 to Webby; 333 to Boyd and Duckworth (the write is still pending).
|
||||
- Fethry on P3, and the Researcher results above.
|
||||
@@ -0,0 +1,95 @@
|
||||
✖ failing tests:
|
||||
|
||||
test at tests/case1-accept.test.mjs:421:49
|
||||
✖ row253 C4 P10 inner reason holds under both sudo models (11528.317041ms)
|
||||
AssertionError [ERR_ASSERTION]: The input did not match the regular expression /P10 tester-socket-squat unnamed boundary=failed reason=probe-inner-timeout /. Input:
|
||||
|
||||
'F1 units-user pass [email protected] and mosaic-webui.service are active as mosaic (uid 997)\n' +
|
||||
'F2 console-loopback pass healthz answers, and 732 is bound to 127.0.0.1 only, by MainPID 200\n' +
|
||||
'F3 tester-reply pass chief replied to case1-accept-ec3cc0292f48\n' +
|
||||
'F4 precheck pass case2-precheck.sh --profile factory exits 0\n' +
|
||||
"F5 bwrap-label pass bwrap 300 reads 'bwrap (enforce)' and its claude descendant 302 reads 'bwrap//&unpriv_bwrap (enforce)'\n" +
|
||||
"F6 claude-pin pass /opt/mosaic-stack/claude-2.1.0/node_modules/@anthropic-ai/claude-code/bin/claude.exe prints '2.1.0 (Claude Code)'\n" +
|
||||
'F7 pm-live pass one live launch: pm run r-0002\n' +
|
||||
"F8 credential-file pass /srv/mosaic/.config/mosaic-dev/secrets/claude-session.env is 'mosaic 600 regular file'\n" +
|
||||
'F9 autoupdater-off pass /etc/claude-code/managed-settings.json is root:root 0644 with env.DISABLE_AUTOUPDATER "1"\n' +
|
||||
'F10 node-pin pass /opt/mosaic-stack/node-v24.1.0/bin/node prints v24.1.0\n' +
|
||||
'F11 no-discord pass /srv/mosaic/.mosaic-dev/discord is absent\n' +
|
||||
'P1 mosaic-sudo closed sudo -l: User mosaic is not allowed to run sudo on dev-53.\n' +
|
||||
"P2 mosaic-groups-keys closed id -G is '997'; authorized_keys is absent\n" +
|
||||
'P3 localadmin-sudo accepted Q183 sudo -l -U localadmin lists 1 NOPASSWD lines\n' +
|
||||
"P4 pve-root-pbs accepted Q182+Q183 root on pve over VM 1008, and PBS backups that hold /srv/mosaic with the credential; this script can't see pve\n" +
|
||||
'P5 jarvis-reach closed jarvis is in none of sudo, docker and lxd (groups: jarvis)\n' +
|
||||
'P6 group-members closed sudo holds only localadmin, and docker and lxd have no members\n' +
|
||||
'P7 sudoers-d closed no file under /etc/sudoers.d names mosaic\n' +
|
||||
'P8 lan-listeners closed 732 is on 127.0.0.1 only by MainPID 200; no TCP listener on 7331 or 7333; tester uses /srv/mosaic/.mosaic-dev/console/tester.sock\n' +
|
||||
'P9 bwrap-userns accepted mos-1096 hostcheck items 1-6 ok, jarvis is denied bwrap, and group mosaic has no other member\n' +
|
||||
'P10 tester-socket-squat unnamed boundary=failed reason=probe-inner-command path=/srv/mosaic/.mosaic-dev/console/tester.sock MainPID=200; hostile same-uid substitution remains\n' +
|
||||
'P11 hostcheck-before-bus closed mosaic-hostcheck.service is enabled, and its Before= names [email protected]\n' +
|
||||
'count pass 11\n' +
|
||||
'count FAIL 0\n' +
|
||||
'count closed 7\n' +
|
||||
'count accepted Q182+Q183 1\n' +
|
||||
'count accepted Q183 1\n' +
|
||||
'count accepted mos-1096 1\n' +
|
||||
'count unnamed 1\n' +
|
||||
'case1-accept: every F check passes; send the whole output to Duckworth, and each unnamed line to Mos\n'
|
||||
|
||||
at TestContext.<anonymous> (file:///mnt/storage/scratch/sage-r329l/wt/packages/cli/tests/case1-accept.test.mjs:445:10)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: `F1 units-user pass [email protected] and mosaic-webui.service are active as mosaic (uid 997)\nF2 console-loopback pass healthz answers, and 732 is bound to 127.0.0.1 only, by MainPID 200\nF3 tester-reply pass chief replied to case1-accept-ec3cc0292f48\nF4 precheck pass case2-precheck.sh --profile factory exits 0\nF5 bwrap-label pass bwrap 300 reads 'bwrap (enforce)' and its claude descendant 302 reads 'bwrap//&unpriv_bwrap (enforce)'\nF6 claude-pin pass /opt/mosaic-stack/claude-2.1.0/node_modules/@anthropic-ai/claude-code/bin/claude.exe prints '2.1.0 (Claude Code)'\nF7 pm-live pass one live launch: pm run r-0002\nF8 credential-file pass /srv/mosaic/.config/mosaic-dev/secrets/claude-session.env is 'mosaic 600 regular file'\nF9 autoupdater-off pass /etc/claude-code/managed-settings.json is root:root 0644 with env.DISABLE_AUTOUPDATER "1"\nF10 node-pin pass /opt/mosaic-stack/node-v24.1.0/bin/node prints v24.1.0\nF11 no-discord pass /srv/mosaic/.mosaic-dev/discord is absent\nP1 mosaic-sudo closed sudo -l: User mosaic is not allowed to run sudo on dev-53.\nP2 mosaic-groups-keys closed id -G is '997'; authorized_keys is absent\nP3 localadmin-sudo accepted Q183 sudo -l -U localadmin lists 1 NOPASSWD lines\nP4 pve-root-pbs accepted Q182+Q183 root on pve over VM 1008, and PBS backups that hold /srv/mosaic with the credential; this script can't see pve\nP5 jarvis-reach closed jarvis is in none of sudo, docker and lxd (groups: jarvis)\nP6 group-members closed sudo holds only localadmin, and docker and lxd have no members\nP7 sudoers-d closed no file under /etc/sudoers.d names mosaic\nP8 lan-listeners closed 732 is on 127.0.0.1 only by MainPID 200; no TCP listener on 7331 or 7333; tester uses /srv/mosaic/.mosaic-dev/console/tester.sock\nP9 bwrap-userns accepted mos-1096 hostcheck items 1-6 ok, jarvis is denied bwrap, and group mosaic has no other member\nP10 tester-socket-squat unnamed boundary=failed reason=probe-inner-command path=/srv/mosaic/.mosaic-dev/console/tester.sock MainPID=200; hostile same-uid substitution remains\nP11 hostcheck-before-bus closed mosaic-hostcheck.service is enabled, and its Before= names [email protected]\ncount pass 11\ncount FAIL 0\ncount closed 7\ncount accepted Q182+Q183 1\ncount accepted Q183 1\ncount accepted mos-1096 1\ncount unnamed 1\ncase1-accept: every F check passes; send the whole output to Duckworth, and each unnamed line to Mos\n`,
|
||||
expected: /P10 tester-socket-squat unnamed boundary=failed reason=probe-inner-timeout /,
|
||||
operator: 'match',
|
||||
diff: 'simple'
|
||||
}
|
||||
|
||||
test at tests/case1-accept.test.mjs:421:49
|
||||
✖ row253 C4 P10 outer reason holds under both sudo models (12748.726934ms)
|
||||
AssertionError [ERR_ASSERTION]: The input did not match the regular expression /P10 tester-socket-squat unnamed boundary=failed reason=probe-outer-timeout /. Input:
|
||||
|
||||
'F1 units-user pass [email protected] and mosaic-webui.service are active as mosaic (uid 997)\n' +
|
||||
'F2 console-loopback pass healthz answers, and 732 is bound to 127.0.0.1 only, by MainPID 200\n' +
|
||||
'F3 tester-reply pass chief replied to case1-accept-d9f4f6fd8da1\n' +
|
||||
'F4 precheck pass case2-precheck.sh --profile factory exits 0\n' +
|
||||
"F5 bwrap-label pass bwrap 300 reads 'bwrap (enforce)' and its claude descendant 302 reads 'bwrap//&unpriv_bwrap (enforce)'\n" +
|
||||
"F6 claude-pin pass /opt/mosaic-stack/claude-2.1.0/node_modules/@anthropic-ai/claude-code/bin/claude.exe prints '2.1.0 (Claude Code)'\n" +
|
||||
'F7 pm-live pass one live launch: pm run r-0002\n' +
|
||||
"F8 credential-file pass /srv/mosaic/.config/mosaic-dev/secrets/claude-session.env is 'mosaic 600 regular file'\n" +
|
||||
'F9 autoupdater-off pass /etc/claude-code/managed-settings.json is root:root 0644 with env.DISABLE_AUTOUPDATER "1"\n' +
|
||||
'F10 node-pin pass /opt/mosaic-stack/node-v24.1.0/bin/node prints v24.1.0\n' +
|
||||
'F11 no-discord pass /srv/mosaic/.mosaic-dev/discord is absent\n' +
|
||||
'P1 mosaic-sudo closed sudo -l: User mosaic is not allowed to run sudo on dev-53.\n' +
|
||||
"P2 mosaic-groups-keys closed id -G is '997'; authorized_keys is absent\n" +
|
||||
'P3 localadmin-sudo accepted Q183 sudo -l -U localadmin lists 1 NOPASSWD lines\n' +
|
||||
"P4 pve-root-pbs accepted Q182+Q183 root on pve over VM 1008, and PBS backups that hold /srv/mosaic with the credential; this script can't see pve\n" +
|
||||
'P5 jarvis-reach closed jarvis is in none of sudo, docker and lxd (groups: jarvis)\n' +
|
||||
'P6 group-members closed sudo holds only localadmin, and docker and lxd have no members\n' +
|
||||
'P7 sudoers-d closed no file under /etc/sudoers.d names mosaic\n' +
|
||||
'P8 lan-listeners closed 732 is on 127.0.0.1 only by MainPID 200; no TCP listener on 7331 or 7333; tester uses /srv/mosaic/.mosaic-dev/console/tester.sock\n' +
|
||||
'P9 bwrap-userns accepted mos-1096 hostcheck items 1-6 ok, jarvis is denied bwrap, and group mosaic has no other member\n' +
|
||||
'P10 tester-socket-squat unnamed boundary=failed reason=probe-inner-command path=/srv/mosaic/.mosaic-dev/console/tester.sock MainPID=200; hostile same-uid substitution remains\n' +
|
||||
'P11 hostcheck-before-bus closed mosaic-hostcheck.service is enabled, and its Before= names [email protected]\n' +
|
||||
'count pass 11\n' +
|
||||
'count FAIL 0\n' +
|
||||
'count closed 7\n' +
|
||||
'count accepted Q182+Q183 1\n' +
|
||||
'count accepted Q183 1\n' +
|
||||
'count accepted mos-1096 1\n' +
|
||||
'count unnamed 1\n' +
|
||||
'case1-accept: every F check passes; send the whole output to Duckworth, and each unnamed line to Mos\n'
|
||||
|
||||
at TestContext.<anonymous> (file:///mnt/storage/scratch/sage-r329l/wt/packages/cli/tests/case1-accept.test.mjs:445:10)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: `F1 units-user pass [email protected] and mosaic-webui.service are active as mosaic (uid 997)\nF2 console-loopback pass healthz answers, and 732 is bound to 127.0.0.1 only, by MainPID 200\nF3 tester-reply pass chief replied to case1-accept-d9f4f6fd8da1\nF4 precheck pass case2-precheck.sh --profile factory exits 0\nF5 bwrap-label pass bwrap 300 reads 'bwrap (enforce)' and its claude descendant 302 reads 'bwrap//&unpriv_bwrap (enforce)'\nF6 claude-pin pass /opt/mosaic-stack/claude-2.1.0/node_modules/@anthropic-ai/claude-code/bin/claude.exe prints '2.1.0 (Claude Code)'\nF7 pm-live pass one live launch: pm run r-0002\nF8 credential-file pass /srv/mosaic/.config/mosaic-dev/secrets/claude-session.env is 'mosaic 600 regular file'\nF9 autoupdater-off pass /etc/claude-code/managed-settings.json is root:root 0644 with env.DISABLE_AUTOUPDATER "1"\nF10 node-pin pass /opt/mosaic-stack/node-v24.1.0/bin/node prints v24.1.0\nF11 no-discord pass /srv/mosaic/.mosaic-dev/discord is absent\nP1 mosaic-sudo closed sudo -l: User mosaic is not allowed to run sudo on dev-53.\nP2 mosaic-groups-keys closed id -G is '997'; authorized_keys is absent\nP3 localadmin-sudo accepted Q183 sudo -l -U localadmin lists 1 NOPASSWD lines\nP4 pve-root-pbs accepted Q182+Q183 root on pve over VM 1008, and PBS backups that hold /srv/mosaic with the credential; this script can't see pve\nP5 jarvis-reach closed jarvis is in none of sudo, docker and lxd (groups: jarvis)\nP6 group-members closed sudo holds only localadmin, and docker and lxd have no members\nP7 sudoers-d closed no file under /etc/sudoers.d names mosaic\nP8 lan-listeners closed 732 is on 127.0.0.1 only by MainPID 200; no TCP listener on 7331 or 7333; tester uses /srv/mosaic/.mosaic-dev/console/tester.sock\nP9 bwrap-userns accepted mos-1096 hostcheck items 1-6 ok, jarvis is denied bwrap, and group mosaic has no other member\nP10 tester-socket-squat unnamed boundary=failed reason=probe-inner-command path=/srv/mosaic/.mosaic-dev/console/tester.sock MainPID=200; hostile same-uid substitution remains\nP11 hostcheck-before-bus closed mosaic-hostcheck.service is enabled, and its Before= names [email protected]\ncount pass 11\ncount FAIL 0\ncount closed 7\ncount accepted Q182+Q183 1\ncount accepted Q183 1\ncount accepted mos-1096 1\ncount unnamed 1\ncase1-accept: every F check passes; send the whole output to Duckworth, and each unnamed line to Mos\n`,
|
||||
expected: /P10 tester-socket-squat unnamed boundary=failed reason=probe-outer-timeout /,
|
||||
operator: 'match',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
|
||||
## Row 329 N2: `mosaic proxy fetch` has no agent or human guard
|
||||
|
||||
Sage, for Dewey's round 1 N2 on row 329 (c31639, landing deferral per c31643). `mosaic proxy fetch` downloads
|
||||
the pinned CLIProxyAPI archive from GitHub and writes `<dataRoot>/opt/cliproxyapi/` for any caller that has
|
||||
the instance config. P1's brief didn't ask for a guard. The fetch is pinned and sha256-checked against
|
||||
`packages/model-proxy/PIN`, so the risk is an unasked network fetch and a disk write, not a wrong binary.
|
||||
Bound to row 331 (P2): P2 decides whether fetch needs the human or agent guard its key verbs get, and
|
||||
records the choice in its BUILD.md. If P2 leaves it, P7 decides before cutover.
|
||||
|
||||
## Row 329 R2-N1: the management-key rule lives in three places
|
||||
|
||||
Sage, for Dewey's round 2 R2-N1 on row 329 (c31643). Round 2 tightened the key rule to
|
||||
`/^[\x21-\x7e]{1,4096}$/` in `packages/model-proxy/src/common.mjs`:33, which `initializeProxy` enforces, but
|
||||
`packages/bus/src/broker.mjs`:4827 and `packages/cli/src/model-proxy.mjs`:57 still use the round 1 predicate.
|
||||
A Latin-1 or edge-space key gets past both and is refused at init with `proxy-key-invalid`, before any write,
|
||||
but only after both prompts and a bus round trip. Fix: export one predicate from the model-proxy package
|
||||
and use it in all three places, with a test at each caller. Bound to row 331 (P2), which edits the broker's
|
||||
proxy verbs.
|
||||
|
||||
## Row 329 N1: the 127.0.0.1 bind isn't observed on the real binary
|
||||
|
||||
Sage, for Dewey's round 1 N1 on row 329 (c31639). The acceptance netns had only `lo`, so P1 writes
|
||||
`server.host: 127.0.0.1` and `management.allow-remote: false`
|
||||
but never saw the real binary refuse a non-loopback client.
|
||||
Bound to P7: at cutover, with Jason present, confirm the listener is on 127.0.0.1 only (`ss -ltnp`), and
|
||||
record it in P7's receipt.
|
||||
@@ -0,0 +1,29 @@
|
||||
pi /mnt/storage/scratch/sage-r329l/wt/node_modules/@earendil-works/pi-coding-agent/dist/bundle/cli.js
|
||||
start 22:20:17Z base c8a9bcf94 cand 8b4978887 TMPDIR /mnt/storage/scratch/tmp/wCOHZ8 nice -4
|
||||
esbuild 0.28.2
|
||||
== bus rc 0 22:20:50Z ℹ tests 1 ℹ pass 1 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0 ℹ tests 1019 ℹ pass 1019 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0
|
||||
== business rc 0 22:20:54Z ℹ tests 283 ℹ pass 283 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0
|
||||
== cli rc 1 22:38:18Z ℹ tests 1000 ℹ pass 997 ℹ fail 2 ℹ cancelled 0 ℹ skipped 1 ℹ todo 0
|
||||
83:✖ row253 C4 P10 inner reason holds under both sudo models (11528.317041ms)
|
||||
84:✖ row253 C4 P10 outer reason holds under both sudo models (12748.726934ms)
|
||||
1120:✖ failing tests:
|
||||
1123:✖ row253 C4 P10 inner reason holds under both sudo models (11528.317041ms)
|
||||
1170:✖ row253 C4 P10 outer reason holds under both sudo models (12748.726934ms)
|
||||
== control-board rc 0 22:38:19Z ℹ tests 130 ℹ pass 130 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0
|
||||
== conversation rc 0 22:39:03Z ℹ tests 187 ℹ pass 187 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0
|
||||
== discord rc 0 22:39:06Z ℹ tests 200 ℹ pass 200 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0
|
||||
== harness rc 1 22:39:19Z ℹ tests 176 ℹ pass 175 ℹ fail 1 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0
|
||||
55:✖ claude: row 66 a reply with a tell gets the correction notice on the next turn, a clean reply gets none, and the counts read after (1435.593566ms)
|
||||
186:✖ failing tests:
|
||||
189:✖ claude: row 66 a reply with a tell gets the correction notice on the next turn, a clean reply gets none, and the counts read after (1435.593566ms)
|
||||
== ledger rc 0 22:39:36Z ℹ tests 89 ℹ pass 89 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0
|
||||
== library rc 0 22:39:43Z ℹ tests 149 ℹ pass 149 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0
|
||||
== model-proxy rc 0 22:39:45Z ℹ tests 66 ℹ pass 66 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0
|
||||
== mosaic rc 0 22:40:05Z ℹ tests 69 ℹ pass 69 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0
|
||||
== plugins rc 0 22:40:06Z ℹ tests 120 ℹ pass 120 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0
|
||||
== processing-control rc 0 22:40:07Z ℹ tests 62 ℹ pass 62 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0
|
||||
== project rc 0 22:40:09Z ℹ tests 41 ℹ pass 41 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0
|
||||
== runs rc 0 22:40:10Z ℹ tests 43 ℹ pass 43 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0
|
||||
== seat rc 0 22:40:18Z ℹ tests 218 ℹ pass 218 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0
|
||||
== supervisor rc 0 22:40:18Z ℹ tests 45 ℹ pass 45 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0
|
||||
== tasks rc 0 22:40:20Z ℹ tests 100 ℹ pass 100 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0
|
||||
@@ -0,0 +1,103 @@
|
||||
{
|
||||
"at": "2026-10-24T22:38:20.521Z",
|
||||
"user": "bot-faceless",
|
||||
"problems": [],
|
||||
"permissions": {
|
||||
"projects": [
|
||||
"background",
|
||||
"background_get",
|
||||
"backgrounds_upload",
|
||||
"create",
|
||||
"projectusers",
|
||||
"read_all",
|
||||
"read_one",
|
||||
"tasks_by_index",
|
||||
"update",
|
||||
"users_search",
|
||||
"views_buckets",
|
||||
"views_buckets_post",
|
||||
"views_buckets_put",
|
||||
"views_buckets_tasks",
|
||||
"views_buckets_tasks_get"
|
||||
],
|
||||
"projects_views": [
|
||||
"create",
|
||||
"read_all",
|
||||
"read_one",
|
||||
"update"
|
||||
],
|
||||
"projects_views_tasks": [
|
||||
"read_all"
|
||||
],
|
||||
"tasks": [
|
||||
"create",
|
||||
"create_bulk",
|
||||
"position",
|
||||
"read",
|
||||
"read_all",
|
||||
"read_one",
|
||||
"update",
|
||||
"update_bulk"
|
||||
],
|
||||
"tasks_assignees": [
|
||||
"create",
|
||||
"delete",
|
||||
"read_all",
|
||||
"update_bulk"
|
||||
],
|
||||
"tasks_attachments": [
|
||||
"create",
|
||||
"read_all",
|
||||
"read_one"
|
||||
],
|
||||
"tasks_comments": [
|
||||
"create",
|
||||
"read_all",
|
||||
"read_one",
|
||||
"update"
|
||||
],
|
||||
"tasks_labels": [
|
||||
"create",
|
||||
"delete",
|
||||
"read_all",
|
||||
"update_bulk"
|
||||
],
|
||||
"tasks_relations": [
|
||||
"create",
|
||||
"delete"
|
||||
],
|
||||
"labels": [
|
||||
"create",
|
||||
"read_all",
|
||||
"read_one",
|
||||
"update"
|
||||
],
|
||||
"filters": [
|
||||
"create",
|
||||
"read_one",
|
||||
"update"
|
||||
],
|
||||
"reactions": [
|
||||
"create",
|
||||
"delete",
|
||||
"read_all"
|
||||
]
|
||||
},
|
||||
"botCreate": 201,
|
||||
"botId": 15,
|
||||
"tokenCreate": 201,
|
||||
"tokenId": 15,
|
||||
"expires": "2027-01-07T00:00:00Z",
|
||||
"startsTk": true,
|
||||
"file": "/home/jwoltje/.config/mosaic-dev/secrets/mosaic-stack/faceless-vikunja.token",
|
||||
"mode": "600",
|
||||
"inverse": "svc: DELETE /api/v1/tokens/15",
|
||||
"keysNow": [
|
||||
15
|
||||
],
|
||||
"newKeyProjects": {
|
||||
"status": 200,
|
||||
"count": 0
|
||||
},
|
||||
"newKeyTask198": 403
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"at": "2026-10-24T23:07:42.645Z",
|
||||
"project": 19,
|
||||
"created": [
|
||||
{
|
||||
"status": 201,
|
||||
"id": 631,
|
||||
"readBack": 200,
|
||||
"done": false
|
||||
}
|
||||
],
|
||||
"problems": []
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// Sage, 2026-10-24: row 329 P1 (model-proxy package, Gitea 1827) landed 61ebf2c34. Comment on parent 237 only; 237 stays open for P2-P7.
|
||||
// Checks each task's title before posting. Prints no secret.
|
||||
// Usage: node comment-r329-landed.mjs https://tasks.woltje.com SAGE_TOKEN_FILE SYNC_TOKEN_FILE OUT_JSON
|
||||
import { readFileSync, writeFileSync, existsSync } from "node:fs";
|
||||
const [ORIGIN, KEY, SYNC, OUT] = process.argv.slice(2);
|
||||
if (!/^https:\/\/tasks\.woltje\.com$/.test(ORIGIN)) throw new Error("tasks.woltje.com only");
|
||||
if (!OUT || existsSync(OUT)) throw new Error("OUT_JSON missing or exists; refusing");
|
||||
const PROJECT = 19;
|
||||
const PSIG = "Posted by Sage (T3 1ef1e4f8) with Sage's own key (bot user 13).";
|
||||
const esc = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
||||
const ps = (xs) => xs.map((x) => `<p>${esc(x)}</p>`).join("") + `<p>${esc(PSIG)}</p>`;
|
||||
const POSTS = [
|
||||
{ id: 237, title: /^Programmatic agent credentials via local proxy/, body: ["Row 329, P1 of this design (the model-proxy package, pinned CLIProxyAPI fetch, proxy init and the proxy unit, Gitea #1827), landed on refactor at 61ebf2c34, pushed 23:31:27Z 2026-10-24. Magica built it. Boyd approved it in comment 31642 (rev 4048) and Dewey in comment 31643 (rev 4047). Sage's fresh landing gate went GREEN by itself at 23:29:14Z (mos-1634): every package suite except queue at 0 failures, with 1 allowed FED R7 skip, and every scripts/test-*.sh at rc 0. #1827 is closed with landing comment 31650. The earlier red run's case1-accept C4 P10 failures are task 631. Carried to docs/plans/DEFERRED.md: N2 and R2-N1 bound to row 331 (P2), and N1 (observing the 127.0.0.1 bind on the real binary) bound to the P7 cutover. This task stays open for P2 to P7. The live stack is not re-pinned."] },
|
||||
];
|
||||
if (/LANDSHA|PUSHTIME|CLOSEID|GATE\b/.test(JSON.stringify(POSTS))) throw new Error("placeholder left; refusing");
|
||||
const key = readFileSync(KEY, "utf8").trim(), sync = readFileSync(SYNC, "utf8").trim();
|
||||
async function api(method, path, body, auth) {
|
||||
const r = await fetch(ORIGIN + path, { method, headers: { Authorization: `Bearer ${auth}`, "Content-Type": "application/json" }, body: body === undefined ? undefined : JSON.stringify(body), redirect: "error" });
|
||||
const t = await r.text(); let json = null; try { json = JSON.parse(t); } catch {}
|
||||
return { status: r.status, json };
|
||||
}
|
||||
const list = (j) => j?.items ?? (Array.isArray(j) ? j : []);
|
||||
const rec = { at: new Date().toISOString(), comments: [], problems: [] };
|
||||
const save = () => {
|
||||
const out = JSON.stringify(rec, null, 1) + "\n";
|
||||
if (out.includes(key) || out.includes(sync)) throw new Error("secret in the record; not written");
|
||||
writeFileSync(OUT, out);
|
||||
};
|
||||
for (const P of POSTS) {
|
||||
const t = await api("GET", `/api/v2/tasks/${P.id}`, undefined, sync);
|
||||
if (t.status !== 200 || t.json?.project_id !== PROJECT || !P.title.test(t.json?.title ?? "")) throw new Error(`task ${P.id}: ${t.status}, title check failed; nothing posted`);
|
||||
}
|
||||
writeFileSync(OUT, "", { flag: "wx" });
|
||||
for (const P of POSTS) {
|
||||
const c = await api("PUT", `/api/v1/tasks/${P.id}/comments`, { comment: ps(P.body) }, key);
|
||||
const e = { task: P.id, status: c.status, id: c.json?.id ?? null };
|
||||
rec.comments.push(e);
|
||||
if (c.status >= 300 || !Number.isSafeInteger(c.json?.id)) { rec.problems.push(`comment ${P.id}: ${c.status} ${c.json?.message ?? ""}`); save(); continue; }
|
||||
const back = await api("GET", `/api/v2/tasks/${P.id}/comments?per_page=50`, undefined, sync);
|
||||
const found = list(back.json).find((x) => x.id === c.json.id);
|
||||
Object.assign(e, { readBack: back.status, found: Boolean(found) });
|
||||
if (back.status !== 200 || !found) rec.problems.push(`comment ${P.id} read-back: ${back.status}`);
|
||||
save();
|
||||
}
|
||||
save();
|
||||
process.stdout.write(JSON.stringify(rec, null, 1) + "\n");
|
||||
if (rec.problems.length) process.exit(2);
|
||||
@@ -0,0 +1,71 @@
|
||||
// Sage, 2026-10-25: files two follow-ups as P19 tasks (mos-1647 item 3, Q109): the CLIProxyAPI startup version refreshes
|
||||
// seen in row 332's isolated runs (a P7 cutover item) and Webby's row 284 N1 (library read path). No relation, labels,
|
||||
// assignees, due dates or bucket moves. Sage's own key (bot user 13); the sync key reads back. Refuses if a title exists.
|
||||
// Prints no secret.
|
||||
// Usage: node file-1025-followups.mjs https://tasks.woltje.com SAGE_TOKEN_FILE SYNC_TOKEN_FILE OUT_JSON
|
||||
import { readFileSync, writeFileSync, existsSync } from "node:fs";
|
||||
const [ORIGIN, KEY, SYNC, OUT] = process.argv.slice(2);
|
||||
if (!/^https:\/\/tasks\.woltje\.com$/.test(ORIGIN)) throw new Error("tasks.woltje.com only");
|
||||
if (!OUT || existsSync(OUT)) throw new Error("OUT_JSON missing or exists; refusing");
|
||||
const PROJECT = 19;
|
||||
const SIG = "Created by Sage (T3 1ef1e4f8) with Sage's own key (bot user 13).";
|
||||
const esc = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
||||
const ps = (sig, xs) => xs.map((x) => `<p>${esc(x)}</p>`).join("") + `<p>${esc(sig)}</p>`;
|
||||
const TASKS = [
|
||||
{
|
||||
title: "Stack P7 cutover: CLIProxyAPI 8.0.42 makes outbound version-refresh calls at startup (Grok CLI via npm, antigravity)",
|
||||
description: ps(SIG, [
|
||||
"Filed by Mos's ruling mos-1647 item 3. Seen by Fethry in row 332 (P3) isolated runs on 2026-10-24, pinned CLIProxyAPI 8.0.42 (commit bc064340, PIN binary sha256 74661f8c), run under unshare -rn with only lo, empty HOME and auth, panel auto-update disabled.",
|
||||
"At startup the binary logged xai_version.go:96 'failed to fetch latest Grok CLI version from npm' for https://registry.npmjs.org/@xai-official/grok/latest (network unreachable inside the namespace), then xai_version.go:79 'periodic Grok CLI version refresh started (interval=3h0m0s)'. It also logged antigravity_version.go:71 'periodic antigravity version refresh started (interval=3h0m0s)'. Evidence: origin/fethry/row332-p1 agents/fethry/work/queue-332/BUILD.md:251-252 and evidence/offline.txt.",
|
||||
"On the live host these calls would leave the machine every 3 hours, which P1's loopback-only design doesn't account for. The proxy kept working with the fallback version, so the failure is harmless to requests.",
|
||||
"Needed before or at P7 cutover, with Jason present: find whether 8.0.42 has a config switch for these refreshes; if so set it in P1's initial config with a test, otherwise decide deliberately to allow or block the egress (unit-level network policy) and record the choice in P7's receipt. Also recorded in docs/plans/DEFERRED.md. Umbrella: 237.",
|
||||
]),
|
||||
},
|
||||
{
|
||||
title: "Stack: library get lists the whole served tree per read (row 284 N1, Webby)",
|
||||
description: ps(SIG, [
|
||||
"Filed by Mos's ruling mos-1647 item 3. Webby's round 1 note N1 on row 284 (#1789, landed ce0b6ed41 on 2026-10-25), carried in c31654. Not a correctness issue.",
|
||||
"Each read that resolves one file walks the whole served tree with listTree (git ls-tree -r -l) and then finds the one entry: packages/library/src/mirror.mjs:257 and packages/library/src/query.mjs:142, both via packages/library/src/reader.mjs:28. On a large library that is one full tree listing per read.",
|
||||
"Fix options: git rev-parse <commit>:<path> for the one oid, or a per-commit listing cache. listTree also bounds and checks the tree and its object IDs, so a replacement must keep those checks.",
|
||||
"Bound to the next row that edits the library read path: that row measures a get on a library of realistic size and records the choice in its BUILD.md. Also recorded in docs/plans/DEFERRED.md.",
|
||||
]),
|
||||
},
|
||||
];
|
||||
const key = readFileSync(KEY, "utf8").trim(), sync = readFileSync(SYNC, "utf8").trim();
|
||||
async function api(method, path, body, auth) {
|
||||
const r = await fetch(ORIGIN + path, { method, headers: { Authorization: `Bearer ${auth}`, "Content-Type": "application/json" }, body: body === undefined ? undefined : JSON.stringify(body), redirect: "error" });
|
||||
const t = await r.text(); let json = null; try { json = JSON.parse(t); } catch {}
|
||||
return { status: r.status, json };
|
||||
}
|
||||
const list = (j) => j?.items ?? (Array.isArray(j) ? j : []);
|
||||
async function existing() {
|
||||
const out = [];
|
||||
for (let page = 1; page < 20; page++) {
|
||||
const r = await api("GET", `/api/v2/projects/${PROJECT}/tasks?per_page=50&page=${page}`, undefined, sync);
|
||||
if (r.status !== 200) throw new Error(`list tasks: ${r.status}`);
|
||||
out.push(...list(r.json));
|
||||
if (list(r.json).length < 50) return out;
|
||||
}
|
||||
throw new Error("more than 19 pages");
|
||||
}
|
||||
const rec = { at: new Date().toISOString(), project: PROJECT, created: null, problems: [] };
|
||||
const save = () => {
|
||||
const out = JSON.stringify(rec, null, 1) + "\n";
|
||||
if (out.includes(key) || out.includes(sync)) throw new Error("secret in the record; not written");
|
||||
writeFileSync(OUT, out);
|
||||
};
|
||||
const have = await existing();
|
||||
for (const T of TASKS) if (have.some((t) => t.title === T.title)) throw new Error("title exists; refusing");
|
||||
writeFileSync(OUT, "", { flag: "wx" });
|
||||
rec.created = [];
|
||||
for (const T of TASKS) {
|
||||
const r = await api("PUT", `/api/v1/projects/${PROJECT}/tasks`, { title: T.title, description: T.description }, key);
|
||||
const c = { status: r.status, id: r.json?.id ?? null };
|
||||
rec.created.push(c);
|
||||
if (r.status >= 300 || !Number.isSafeInteger(r.json?.id)) { rec.problems.push(`create: ${r.status} ${r.json?.message ?? ""}`); continue; }
|
||||
const back = await api("GET", `/api/v2/tasks/${r.json.id}`, undefined, sync);
|
||||
Object.assign(c, { readBack: back.status, done: back.json?.done });
|
||||
if (back.status !== 200 || back.json?.title !== T.title || back.json?.done) rec.problems.push(`read-back differs for ${r.json.id}`);
|
||||
}
|
||||
save();
|
||||
console.log(JSON.stringify(rec));
|
||||
@@ -0,0 +1,62 @@
|
||||
// Sage, 2026-10-24: files the row253 C4 P10 red seen in row 329's landing gate (mos-1634 item 2) as a P19 task,
|
||||
// a sibling of 625. No relation, labels, assignees, due dates or bucket moves. Sage's own key (bot user 13);
|
||||
// the sync key reads back. Refuses if the title exists. Prints no secret.
|
||||
// Usage: node file-c4p10.mjs https://tasks.woltje.com SAGE_TOKEN_FILE SYNC_TOKEN_FILE OUT_JSON
|
||||
import { readFileSync, writeFileSync, existsSync } from "node:fs";
|
||||
const [ORIGIN, KEY, SYNC, OUT] = process.argv.slice(2);
|
||||
if (!/^https:\/\/tasks\.woltje\.com$/.test(ORIGIN)) throw new Error("tasks.woltje.com only");
|
||||
if (!OUT || existsSync(OUT)) throw new Error("OUT_JSON missing or exists; refusing");
|
||||
const PROJECT = 19;
|
||||
const SIG = "Created by Sage (T3 1ef1e4f8) with Sage's own key (bot user 13).";
|
||||
const esc = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
||||
const ps = (sig, xs) => xs.map((x) => `<p>${esc(x)}</p>`).join("") + `<p>${esc(sig)}</p>`;
|
||||
const TASKS = [
|
||||
{
|
||||
title: "Stack: case1-accept row253 C4 P10 inner and outer timeouts reported probe-inner-command (cause unknown)",
|
||||
description: ps(SIG, [
|
||||
"Filed by Mos's ruling mos-1634 as a sibling of 625. Seen in row 329's landing gate on 8b4978887 (base c8a9bcf94), 2026-10-24 22:20-22:42Z, before the T3 crash killed the gate. The cli suite went 1000 tests, 997 pass, 2 fail, 1 skip (FED R7).",
|
||||
"Both reds are the loop at packages/cli/tests/case1-accept.test.mjs:421. 'row253 C4 P10 inner' expected reason=probe-inner-timeout and 'row253 C4 P10 outer' expected reason=probe-outer-timeout. Both got reason=probe-inner-command. 'overflow' passed. Every F check passed in both outputs. Failure text: agents/sage/work/handoff-2026-10-24/r329-cli-failures.txt (98614187c).",
|
||||
"Not row 329's code: git diff --stat c8a9bcf94 8b4978887 is empty on case1-accept.test.mjs, case-sudo-fixture.mjs and scripts/case1-accept.sh (checked by Mos). The red is on base code. Magica's r2 gate had the file at 53/0.",
|
||||
"Cause unknown. Unverified hypothesis: probe-inner-command is the catch-all in scripts/case1-accept.sh:228 for a supervisor exit other than 81-86. The C4 loop arms fixtureGuard(t,files,7000), which SIGKILLs a recorded fixture pid after 7 s; a fault run longer than that would turn exit 81 or 82 into 87. The test asserts before its t.diagnostic line, so there is no per-mode timing to confirm or refute this. This is not recorded as load.",
|
||||
"Host facts, not a cause: Della's row 284 lane B run shared the host until about 22:34Z; the 1-minute load was 7.51 at 23:03Z and 10.83 at 23:06Z. Next: the 329 rerun gate (mos-1634 item 1) reports whether it recurs; a fix that changes this old test needs Mos's OK.",
|
||||
]),
|
||||
},
|
||||
];
|
||||
const key = readFileSync(KEY, "utf8").trim(), sync = readFileSync(SYNC, "utf8").trim();
|
||||
async function api(method, path, body, auth) {
|
||||
const r = await fetch(ORIGIN + path, { method, headers: { Authorization: `Bearer ${auth}`, "Content-Type": "application/json" }, body: body === undefined ? undefined : JSON.stringify(body), redirect: "error" });
|
||||
const t = await r.text(); let json = null; try { json = JSON.parse(t); } catch {}
|
||||
return { status: r.status, json };
|
||||
}
|
||||
const list = (j) => j?.items ?? (Array.isArray(j) ? j : []);
|
||||
async function existing() {
|
||||
const out = [];
|
||||
for (let page = 1; page < 20; page++) {
|
||||
const r = await api("GET", `/api/v2/projects/${PROJECT}/tasks?per_page=50&page=${page}`, undefined, sync);
|
||||
if (r.status !== 200) throw new Error(`list tasks: ${r.status}`);
|
||||
out.push(...list(r.json));
|
||||
if (list(r.json).length < 50) return out;
|
||||
}
|
||||
throw new Error("more than 19 pages");
|
||||
}
|
||||
const rec = { at: new Date().toISOString(), project: PROJECT, created: null, problems: [] };
|
||||
const save = () => {
|
||||
const out = JSON.stringify(rec, null, 1) + "\n";
|
||||
if (out.includes(key) || out.includes(sync)) throw new Error("secret in the record; not written");
|
||||
writeFileSync(OUT, out);
|
||||
};
|
||||
const have = await existing();
|
||||
for (const T of TASKS) if (have.some((t) => t.title === T.title)) throw new Error("title exists; refusing");
|
||||
writeFileSync(OUT, "", { flag: "wx" });
|
||||
rec.created = [];
|
||||
for (const T of TASKS) {
|
||||
const r = await api("PUT", `/api/v1/projects/${PROJECT}/tasks`, { title: T.title, description: T.description }, key);
|
||||
const c = { status: r.status, id: r.json?.id ?? null };
|
||||
rec.created.push(c);
|
||||
if (r.status >= 300 || !Number.isSafeInteger(r.json?.id)) { rec.problems.push(`create: ${r.status} ${r.json?.message ?? ""}`); continue; }
|
||||
const back = await api("GET", `/api/v2/tasks/${r.json.id}`, undefined, sync);
|
||||
Object.assign(c, { readBack: back.status, done: back.json?.done });
|
||||
if (back.status !== 200 || back.json?.title !== T.title || back.json?.done) rec.problems.push(`read-back differs for ${r.json.id}`);
|
||||
}
|
||||
save();
|
||||
console.log(JSON.stringify(rec));
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"at": "2026-10-25T00:18:17.480Z",
|
||||
"project": 19,
|
||||
"created": [
|
||||
{
|
||||
"status": 201,
|
||||
"id": 633,
|
||||
"readBack": 200,
|
||||
"done": false
|
||||
},
|
||||
{
|
||||
"status": 201,
|
||||
"id": 634,
|
||||
"readBack": 200,
|
||||
"done": false
|
||||
}
|
||||
],
|
||||
"problems": []
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"at": "2026-10-24T23:32:49.768Z",
|
||||
"comments": [
|
||||
{
|
||||
"task": 237,
|
||||
"status": 201,
|
||||
"id": 1109,
|
||||
"readBack": 200,
|
||||
"found": true
|
||||
}
|
||||
],
|
||||
"problems": []
|
||||
}
|
||||
@@ -1685,7 +1685,14 @@ are never rewritten or removed; corrections are new entries.
|
||||
2026-10-24 | Fethry14f80e3c | Row328 T9 timer race (#1826) | New fethry/row328 worktree on2ce476d54, owner start rev3992 opfethry-0037. Test-only +4/-3 under Mos1594, no assertion/product changes. Local root npm ci, no links. Static-only stress/M1 preparation and untested push; waiting for Sage CLEAR, then Boyd/Dewey review.
|
||||
|
||||
2026-10-24 | Fethry14f80e3c | Row328 T9 race acceptance evidence | sage4214 on06c57a7db:400 concurrent M1 attempts yield26 expected failures, fixed400/400, whole file6/6; exact restoration/clean checks and process sweep empty. All801 receipts/nice/load preserved. Manifest1e010468 one approved+4/-3 old test, no assertion/product change. Earlier aborted and serial non-repro receipts separate. Review handoff Boyd/Dewey, Sage landing gate pending.
|
||||
|
||||
2026-10-24 | Sage 1ef1e4f8 | Landings 257, 266, 224, 328; model-proxy rows 329-333 filed | 257 73692e1bb, 266 3e5041b43, 224 5e77cdd09, 328 8bb5b3c73 landed on GREEN gates. Rows 329-333 briefed from 7fe32d722 (mos-1600/1601); 330 blocked on Jason's subdomain answer (mos-1602). Magica holds the slot for 329's builder gate.
|
||||
2026-10-24 | Sage 1ef1e4f8 | T3 crash stop (mos-1628) | Processes died 22:42:37Z mid row 329 landing gate on 8b4978887: cli 997/2 (case1-accept row253 C4 P10 inner/outer got probe-inner-command), rerun waits on Mos; nothing pushed for 329. Minted bot-faceless user 15 key 15 (#630). Queue: 332 assign rev 4054, 284 reviewers rev 4055; 333 reviewers, 332 after and the #1832 add still to run; dead lock removed. Handoff agents/sage/work/handoff-2026-10-24/HANDOFF.md.
|
||||
2026-10-24 | magica | row329 P1 #1827 | Started isolated magica/row329 at 7fe32d722; approved brief recovered, acceptance first; suites await CLEAR.
|
||||
2026-10-24 | magica | row329 P1 #1827 | Final builder checks green with the recorded Mos1605 continuation and final unit-reader gate; preparing review manifest on magica/row329, no old assertions changed, Q250 scope recorded.
|
||||
2026-10-24 | magica | row329 round2 #1827 | In-progress rev4031; B1 ASCII-only key fix/new inventory tests and N1/N3/N4 docs, cleared reader verification running, old tests byte-identical.
|
||||
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-25 | Sage 1ef1e4f8 | rows 214 and 193 landing (#1715, #1691) | 214 gate GREEN 04:10:34Z, landed 3a8e4abad, #1715 closed c31680, queue 4094/4095 (ce8bb4d8b); 193 doc-only landed 35f34ad27 after Duckworth approve 4088; 198 group A and 267 assertion diffs to Mos (sage-4397, sage-4403); CLEAR to Bubba for 288.
|
||||
2026-10-25 | Sage 1ef1e4f8 | row255 landing #1760 | Doc-only design landed de3e23dde after Webby approve 4103 (c31689); 288 r6 gate green from Bubba (2604/0, 12 scripts, 6 mutants), in-review move handed back to the claimant.
|
||||
@@ -0,0 +1,82 @@
|
||||
# Brief: the Case 2 proxy unit, so a hub installs P1's proxy unit
|
||||
|
||||
Written 2026-10-24 by Sage for Mos's mos-1616 ruling 1, which approved this row. Mos ruled that Sage
|
||||
approves the brief if it only adds P1 item 7's unit to `scripts/case2-install.sh` and
|
||||
`scripts/case2-unit.sh`: the same unit text, the same sha256 refusal and the Wants/After lines. Anything
|
||||
beyond that goes to Mos. Read the rows doc's P1 brief (`docs/plans/2026-10-24_model-proxy-rows.md`, P1
|
||||
item 7) and row 209's brief (`docs/plans/2026-10-24_row209-hub-54-window.md`, entry check 2) first. The
|
||||
rows doc's "Rules for every row" apply here unchanged. Line numbers are at origin/refactor 58b2bbb3a, and
|
||||
P1's paths are at its round 2 candidate magica/row329 86cb5c221. Check both once P1 lands.
|
||||
|
||||
## Brief: Case 2 proxy unit in case2-unit.sh and case2-install.sh
|
||||
|
||||
**Why.** A Case 2 hub (.54) installs through `scripts/case2-install.sh` (as the stack user) and
|
||||
`scripts/case2-unit.sh` (as root, system units). P1 adds `mosaic-proxy.service` only to the user-unit path
|
||||
(`scripts/instance.sh`, `scripts/proxy-service.sh`, `scripts/bus-service.sh`). `case2-unit.sh` writes the
|
||||
bus and Console units and nothing else (:3-5, :56-57), and its bus unit has no `Wants=` or `After=` on a
|
||||
proxy. Without this row, row 209 phase A can't run the proxy on .54.
|
||||
|
||||
**What ships.**
|
||||
|
||||
1. **The proxy unit, from P1's template.** `case2-unit.sh` renders a third system unit,
|
||||
`mosaic-proxy.service`, from P1's `packages/cli/systemd/mosaic-proxy.service.in`, which this row doesn't
|
||||
change.
|
||||
- It uses the same render as the bus (`render()` :435): the copy for `@REPO@`, the unit PATH, `--node`
|
||||
for `@NODE@`, and `@CONFIG_ENV@` deleted, because `case2-unit.sh` renders the default instance only.
|
||||
- It gets the same added lines as the bus: `User=`, `Group=` and the four hardening lines, with no
|
||||
capabilities and no `EnvironmentFile=`. `WantedBy=multi-user.target` replaces `default.target`, as for
|
||||
the other two units.
|
||||
- `check_unit` gets a `proxy` kind. Its fixed lines are those of P1's template: `ExecStart=` exactly
|
||||
`<node> <copy>/packages/model-proxy/src/run.mjs`, and `NoNewPrivileges=yes`. Every check that applies to
|
||||
both units today applies to this one too.
|
||||
- A new test seam `CASE2_PROXY_TEMPLATE`, like `CASE2_BUS_TEMPLATE` (:44, :54).
|
||||
2. **The sha256 refusal is P1's.** The unit starts P1's `run.mjs`, which checks the binary against PIN
|
||||
before it spawns it. This row adds no second check and no other way to start the proxy. A test runs the
|
||||
rendered `ExecStart=` in a temp root, with a made-up config and a binary that doesn't match PIN, and
|
||||
checks P1's refusal code and exit status.
|
||||
3. **Only when the instance has a proxy.** Root passes a new bare flag `--proxy` when the instance's config
|
||||
has a `proxy` section.
|
||||
- Without it, the render is byte for byte what it is today, and no proxy unit is written.
|
||||
- With it, the bus unit gets `Wants=mosaic-proxy.service` and `After=mosaic-proxy.service`, in the place
|
||||
where P1's `bus-service.sh` puts them, right after `Description=`. The Console unit doesn't change.
|
||||
- Root still never imports copy code or reads the config (:16-21). A wrong flag fails closed: with no
|
||||
proxy section, P1's runner refuses and the unit stops. With a proxy section and no flag, the proxy
|
||||
doesn't run and P2's launch preflight refuses. BUILD.md checks both against the landed P1 and P2 code
|
||||
and names the refusal codes.
|
||||
4. **Re-install and start.**
|
||||
- With `--proxy`, the three installed units must name one copy, and each must equal the render once its
|
||||
copy id is the new one, the same rule as now (:557-571).
|
||||
- Without `--proxy`, an installed `mosaic-proxy.service` refuses the run. The script never deletes a
|
||||
unit file.
|
||||
- Enable all of them, then start the proxy, then the bus, then the Console. A unit that was already
|
||||
running is reported the way the bus and Console are now (:576-610), and the message names all three as
|
||||
the units to restart together.
|
||||
5. **case2-install.sh.** Only its closing "Next:" line (:231) changes, to tell root to add `--proxy` when the
|
||||
config has a `proxy` section. If the builder finds that line needs no change, BUILD.md says why and the
|
||||
file stays as it is.
|
||||
|
||||
**Out of scope.** P1's template, runner and PIN; the user-unit path; any named-instance render; reading the
|
||||
config from root; the proxy's config or key; `mosaic proxy init`; any live host, unit or `/etc` write
|
||||
outside a test's temp root.
|
||||
|
||||
**Tests**, in `packages/cli/tests/case2-unit.test.mjs` (and `case2-install.test.mjs` if item 5 changes the
|
||||
script):
|
||||
- with no `--proxy`, the bus and Console renders equal today's, byte for byte;
|
||||
- with `--proxy`, the proxy unit's content, and the bus unit's `Wants=` and `After=` lines;
|
||||
- each `check_unit` refusal on the proxy kind, by its message;
|
||||
- P1's PIN refusal through the rendered `ExecStart=`;
|
||||
- a re-install whose three units name two copies refuses;
|
||||
- an installed proxy unit with no `--proxy` refuses and deletes nothing;
|
||||
- the start order through the `CASE2_SYSTEMCTL` seam's log.
|
||||
|
||||
**Gate.**
|
||||
- The builder is a new Codex gpt-6.1-sol thread and worktree off refactor (Q246, mos-1542). The row starts
|
||||
when P1 (row 329) lands, and the builder rebases on it before any run.
|
||||
- Boyd gives the first Codex review. Webby gives the Claude review of the root-run unit boundary and the
|
||||
landing. Sage runs the landing gate.
|
||||
- The run list for every whole-file run comes from imports and goes in the builder's report before the run.
|
||||
`packages/cli/tests/case1-accept.test.mjs` stays off unless Mos approves (mos-1612).
|
||||
- Every touched test file runs whole. Every package suite but queue, plus every `scripts/test-*.sh`, is
|
||||
green on Sage's landing gate.
|
||||
- Named mutants: the bus unit loses its `After=` line under `--proxy`; the proxy unit's `ExecStart=` skips
|
||||
`run.mjs` and starts the binary directly.
|
||||
@@ -0,0 +1,76 @@
|
||||
# Brief amendment: row 332 (P3), pi's GLM and GPT routes through the proxy
|
||||
|
||||
Written 2026-10-24 by Sage. Mos approved items 4a to 4c in mos-1616 with three conditions, which are written
|
||||
into the items below. Item 4d is settled there too. This came out of mos-1615 (DECISIONS Q253): on .54 Bean
|
||||
runs GLM through a Z.ai key and Chet runs GPT through his ChatGPT/Codex login, both through the proxy. The
|
||||
P3 brief in the rows doc (`docs/plans/2026-10-24_model-proxy-rows.md`, "Brief: P3 harness config from the
|
||||
proxy", item 4) proves only the Anthropic route. Row 96 proved only that route for pi, too
|
||||
(`agents/researcher/work/i1-proxy-test/REPORT.md`, S2-pi-A).
|
||||
|
||||
The rows doc isn't edited, because rows 329 to 333 pin its blob. This file replaces one line of P3 item 4,
|
||||
"A non-Anthropic route names that provider's base URL in the same file.", and adds to P3's Tests and Gate.
|
||||
Everything else in P3 stands. Line numbers are at origin/refactor 58b2bbb3a. Check them before you edit.
|
||||
|
||||
## Brief: P3 amendment, pi's GLM and GPT routes
|
||||
|
||||
**What pi 0.85.1 does today.** These facts come from the pinned pi's docs and its built-in provider data.
|
||||
- `models.json` providers take `baseUrl`, `api`, `apiKey` and `models`. A built-in provider can be
|
||||
overridden with a `baseUrl`.
|
||||
- `apiKey` takes a literal, a `$ENV` reference, or `!command`, which pi runs as a shell command.
|
||||
- The built-in `zai` provider is `openai-completions` at `https://api.z.ai/api/coding/paas/v4`, with z.ai
|
||||
compat fields (`thinkingFormat: "zai"`, `zaiToolStream`).
|
||||
- The built-in `openai-codex` provider speaks `openai-codex-responses` to chatgpt.com/backend-api with pi's
|
||||
own OAuth, so it can't be pointed at the proxy.
|
||||
|
||||
**4a. One entry per route.** `<run>/home/.pi/agent/models.json` gets one provider entry for each route the
|
||||
agent's `launch.models` names, each at the proxy's address from P3 item 1.
|
||||
- Anthropic: as P3 item 4 says now, `anthropic-messages` with no `/v1`.
|
||||
- GLM: `openai-completions` at `http://127.0.0.1:<port>/v1`, with the model id that the proxy's `/v1/models`
|
||||
lists for the Z.ai key.
|
||||
- GPT through the Codex login: a provider of the stack's own, never `openai-codex`, at
|
||||
`http://127.0.0.1:<port>/v1`, with the model ids that the proxy lists for the Codex credential.
|
||||
- The builder picks `openai-responses` or `openai-completions` once, at build time, from what the pinned
|
||||
proxy passes for pi's requests. The harness has no fallback at run time: it writes the one shape the
|
||||
build chose.
|
||||
- BUILD.md records the choice and its evidence: the pinned proxy version, the requests tried on each shape
|
||||
and what came back.
|
||||
|
||||
**4b. The key goes by reference.**
|
||||
- Every entry's `apiKey` is `"$ANTHROPIC_API_KEY"`, the reference P3 item 4 already sets. `ENV_ALLOW`
|
||||
(`packages/seat/src/session.mjs`:242) doesn't change.
|
||||
- In proxy mode that variable holds only the session's own proxy key, because P3 item 2 drops the instance's
|
||||
provider variables.
|
||||
- `models.json` never holds a key value, and no value in it starts with `!`.
|
||||
|
||||
**4c. Tests.** These add to P3's Tests list:
|
||||
- the `models.json` content for each of the three routes;
|
||||
- every `apiKey` in `models.json` is the `$ANTHROPIC_API_KEY` reference;
|
||||
- no key value appears anywhere in the file;
|
||||
- no value in the file starts with `!`;
|
||||
- an offline pi turn through the pinned proxy under `unshare -rn` for the GLM route, against a stand-in
|
||||
upstream, the way row 96 and P1's acceptance run did. It runs from a script outside the gate's
|
||||
`scripts/test-*.sh` set, and its output goes in BUILD.md as plain text.
|
||||
|
||||
The Codex route can't run offline without a real auth file, and no agent touches one. Its first real turn is
|
||||
row 209 phase A step 7 (`docs/plans/2026-10-24_row209-hub-54-window.md`). BUILD.md says so.
|
||||
|
||||
BUILD.md also records whether the z.ai compat fields survive through the proxy, or whether the proxy drops
|
||||
them, from the offline GLM turn.
|
||||
|
||||
**4d. One proxy per user (settled, mos-1616).** Unless P2 item 7 finds that the pinned proxy can limit a
|
||||
client key to some models, Bean's key can reach Chet's ChatGPT login through the same proxy, and Chet's key
|
||||
can reach Bean's Z.ai key. Mos accepted that for .54. Q249 sets one proxy per user and their agents, so both
|
||||
agents and both accounts on .54 are Melanie's. If P1 found no per-key model limit, the bundle's model choice
|
||||
stays the guard. If P1 found one, P2 narrows each key as P2 item 7 says. This row changes neither.
|
||||
|
||||
**Gate additions.** One more named mutant: `models.json` gets the key value instead of the
|
||||
`$ANTHROPIC_API_KEY` reference. The 4c tests must kill it. The rest of P3's Gate stands: Gladstone's first
|
||||
Codex review, Dewey's landing review, every touched test file whole, every package suite but queue plus
|
||||
every `scripts/test-*.sh` green on Sage's landing gate, and the mutant where proxy mode still passes
|
||||
`CLAUDE_CODE_OAUTH_TOKEN`.
|
||||
|
||||
**Start and landing (mos-1616 ruling 5).** P3 may start now on a new Codex gpt-6.1-sol thread and worktree,
|
||||
building against P2's interface `{ baseUrl, key }` (P3 item 1). It lands only after P1 (row 329) and P2
|
||||
(row 331) land, and after its own gate (mos-1351). It rebases on both before that gate. The run list for
|
||||
every whole-file run comes from imports and goes in the builder's report before the run.
|
||||
`packages/cli/tests/case1-accept.test.mjs` stays off unless Mos approves (mos-1612).
|
||||
@@ -0,0 +1,150 @@
|
||||
# Brief: row 330 (P4), the Console proxy page
|
||||
|
||||
Written 2026-10-24 by Sage for Mos's mos-1606, which carries Jason's Q46 and Q47 answers (DECISIONS Q250).
|
||||
Mos approved it in mos-1608, adding upstream API keys (item 4) and the account id rule (item 2).
|
||||
Read the design (`docs/plans/2026-10-24_stack-model-proxy.md`, amended for Q250) and the rows doc
|
||||
(`docs/plans/2026-10-24_model-proxy-rows.md`) first. The rows doc's "Rules for every row" apply here
|
||||
unchanged. Line numbers are at origin/refactor 0ce22dde6. Check them before you edit.
|
||||
|
||||
This brief replaces two parts of the rows doc:
|
||||
- its P4 brief (the `/proxy/` forward to the upstream panel, rows doc :118-182), which is dropped with D8;
|
||||
- P1's two panel acceptance bullets (rows doc :104-108). P1's finding on the OAuth callback URL for Claude
|
||||
and Codex still counts, and this row uses it.
|
||||
|
||||
The rows doc isn't edited, because every row from 329 to 333 pins that file's blob and row 329 is near its
|
||||
landing. The P4 brief lives here instead.
|
||||
|
||||
## Brief: P4 the Console proxy page
|
||||
|
||||
**Why.** Q250: Jason enters accounts in the Console's own proxy page, not in the upstream panel. That
|
||||
covers both his OAuth accounts and his API keys (Q248 item 1, Q249, mos-1608). The page calls bus routes,
|
||||
and the bus calls the proxy's management API (D12). The management key stays in the bus (D6). No new
|
||||
hostname is added. A panel subdomain is a fallback only if our page can't keep up with the
|
||||
management API across pinned proxy upgrades, and that call is Jason's (Q46).
|
||||
|
||||
**What ships.**
|
||||
|
||||
1. **Bus verbs.** New broker verbs for the page, for example `proxy.accounts`, `proxy.login.start`,
|
||||
`proxy.login.submit`, `proxy.login.status`, `proxy.login.cancel`, `proxy.apikey.add`,
|
||||
`proxy.priority.set` and `proxy.keys`. Settle the names in BUILD.md.
|
||||
- Every verb is human-only. A tester, agent or granted-user caller refuses `human-required`, the way
|
||||
the grants admin verbs do (`packages/bus/src/broker.mjs`:3721-3731).
|
||||
- With no proxy in the validated config (P1 item 3), every verb refuses `not-configured`.
|
||||
- Each verb calls the management client from P1 (`packages/model-proxy/src/client.mjs`). P4 adds the
|
||||
calls it needs under P1's rules: the key goes only in the `Authorization` header, only to loopback,
|
||||
and each call writes a receipt with no body and no secret.
|
||||
- A proxy that doesn't answer refuses `proxy-down`, with no retry.
|
||||
2. **Accounts.** `proxy.accounts` lists the upstream accounts from the pinned version's credentials
|
||||
endpoint (`/credentials` in the 8.0.27 doc,
|
||||
`agents/researcher/work/i1-proxy-test/docs/management-api-v8.0.27.md`:101).
|
||||
- The bus copies only allowlisted fields: provider, a display name, status and priority, plus an
|
||||
account id. Every other field is dropped, so no token can pass through even if the proxy returns one.
|
||||
- The account id is the first 12 hex of the sha256 of the proxy's own credential identifier, never of a
|
||||
token or key value (mos-1608).
|
||||
- Record in BUILD.md which endpoint and fields the pinned version has.
|
||||
3. **OAuth sign-in** through `oauth/auth-url`, `oauth/callback` and `oauth/status`
|
||||
(management-api-v8.0.27.md:108-138).
|
||||
- **Start.** The page picks a provider from an allowlist: `claude` and `codex`. Adding a provider is a
|
||||
reviewed change. The bus calls `auth-url` and returns the authorization URL and the `state`. The page
|
||||
opens the URL in a new tab with `noopener` and `noreferrer`.
|
||||
- **Return.** After Jason signs in, the provider redirects to the callback URL that the proxy named.
|
||||
P1's acceptance records that URL for each provider. If the redirect reaches the proxy directly, the
|
||||
status poll shows the result. If it doesn't, Jason pastes the full URL from the address bar into the
|
||||
page, and the bus POSTs it to `oauth/callback` as `redirect_url`.
|
||||
- **Checks on a pasted URL.** It must parse as a URL, stay under a size limit, and carry a `state` that
|
||||
this bus started and that hasn't finished. Anything else refuses `login-state-unknown` or
|
||||
`callback-url-invalid`. The URL carries the authorization code, so it is never logged, stored or
|
||||
echoed back.
|
||||
- **Status.** Only an `ok` from `oauth/status` counts as signed in. An accepted callback with status
|
||||
`wait` doesn't, because the doc says acceptance isn't completion (:136-138). The bus stops polling
|
||||
on `ok`, `error`, or after a timeout setting (default 300 s).
|
||||
- **Cancel** calls `DELETE oauth/session`.
|
||||
4. **Upstream API keys** (mos-1608). A human-only verb (for example `proxy.apikey.add`; name it in
|
||||
BUILD.md) adds one upstream API key.
|
||||
- The provider allowlist starts with z.ai only. Adding a provider is a reviewed change. BUILD.md records
|
||||
which management endpoint the pinned 8.0.42 uses for it.
|
||||
- The Console route has the same checks as the other writes (item 8). The page's input is
|
||||
`type=password` with `autocomplete=off`.
|
||||
- The value is write-only. Neither the Console nor the bus logs it, stores it, caches it, or puts it in
|
||||
a receipt or an error. No part of it is echoed, not even the last four characters. The bus passes it
|
||||
straight to the management API in the request body and then drops it.
|
||||
- After the add, the key shows in `proxy.accounts` through the same allowlisted fields, and priority
|
||||
(item 5) works on it.
|
||||
- An empty value, one over a size limit, or one outside a charset refuses `apikey-invalid`. A provider
|
||||
outside the allowlist refuses `provider-not-allowed`.
|
||||
5. **Priority.** `proxy.priority.set` sets one account's priority, an integer in a range the builder
|
||||
records. Use the pinned version's credential-field endpoint (`/credentials/fields` PATCH in the 8.0.27
|
||||
doc). Confirm it on the stand-in and record what it changes. A bad account id or value refuses
|
||||
`priority-invalid`.
|
||||
6. **Client keys, list only.** `proxy.keys` reads `GET /config/access/api-keys`, maps each value to its key
|
||||
id in memory and drops the value (D15).
|
||||
- It joins P2's record to show agent, issue time and state for each key id.
|
||||
- The sentinel is labelled. A key without this instance's prefix shows as "not stack-managed".
|
||||
- The page has no key write. Issue and revoke stay with hire and fire (P2).
|
||||
7. **Usage.** P5's Console view (rows doc P5 item 3) sits on this page. Whichever of P4 and P5 lands
|
||||
second puts it there. P4 adds no usage source.
|
||||
8. **The page and its Console routes.** An owner-only `/proxy` page in `packages/webui`, built like the
|
||||
existing pages, with routes under `/api/proxy/`.
|
||||
- Each route makes one call over the owner's human transport, the way the Agents section does
|
||||
(`AGENT_ROUTES` at `packages/webui/src/serve.mjs`:451, `agentCaller` at
|
||||
`packages/webui/src/console-bus.mjs`:12). `consoleBus` gets a `PROXY_VERBS` list, and the caller
|
||||
refuses any other verb.
|
||||
- Writes need a signed-in owner, the Console's own `Origin`, `sec-fetch-site: same-origin`, `--send`
|
||||
and a named host, as `agentSend` checks (`serve.mjs`:459-470). The routes are refused for a granted
|
||||
user (`userRoute`), on the tester listener and on a loopback Host.
|
||||
- The Console never holds the management key, never reads `proxy` from the config, and never opens a
|
||||
connection to the proxy port.
|
||||
- Logs record method, route, status and user only. They never record the authorization URL, a pasted
|
||||
callback URL, a state, an API key or a body.
|
||||
9. **Upgrade check.** An acceptance script, beside P1's and outside the gate's `scripts/test-*.sh` set,
|
||||
runs the bus verbs against the pinned binary under `unshare -rn`. It uses a made-up config, key and
|
||||
data root in a fresh temp root, the same way P1's run does.
|
||||
- With no network, it checks what can be checked offline. The account list starts empty. `auth-url`
|
||||
returns a URL and a state for `claude` and for `codex`. A callback with a made-up code never reports
|
||||
`ok`. A made-up z.ai API key added through the verb shows in the account list, and a priority set on
|
||||
it reads back. The key list returns ids only.
|
||||
- It prints the endpoints and fields the page relies on, so a version change shows up as a diff.
|
||||
- `packages/model-proxy/README.md` records the rule: a PIN change lands only with this script's output
|
||||
for the new version in that row's BUILD.md, and Sage's landing gate checks for it.
|
||||
- If the script fails on a new version and the row can't fix the page, the row stops. Sage takes Q46's
|
||||
fallback to Jason through Mos.
|
||||
|
||||
**Tests.** Cover each of these:
|
||||
- every verb against a fake management server;
|
||||
- each refusal code by its own test (mos-1590): `not-configured`, `human-required` for the tester, an
|
||||
agent and a granted user, `provider-not-allowed` for sign-in and for an API key, `login-state-unknown`,
|
||||
`callback-url-invalid`, `apikey-invalid` (empty, over the size limit and outside the charset, each its
|
||||
own case), `priority-invalid` and `proxy-down`;
|
||||
- an API-key canary: a unique made-up value goes through the Console route against the fake management
|
||||
server. Afterwards every Console and bus log, receipt, response, store file and error output from that
|
||||
run has zero matches for it, and the fake received it exactly once;
|
||||
- an added API key listed by `proxy.accounts` with allowlisted fields only, and priority set on it;
|
||||
- account ids derived from the credential identifier, with a fake whose token values never appear in an id;
|
||||
- a fake that puts token-like values in every credential field, where no value reaches a response, log or
|
||||
receipt;
|
||||
- a fake key list with full values, where only ids come back, the sentinel is labelled and a foreign key
|
||||
is marked;
|
||||
- no authorization URL, callback URL, code or state in any log or receipt;
|
||||
- an accepted callback with status `wait` not reported as signed in;
|
||||
- the Console routes: owner allowed, and a granted user, the tester listener, a loopback Host, a
|
||||
signed-out request, a cross-origin request and a request without `sec-fetch-site` each refused, and
|
||||
every write read-only without `--send`;
|
||||
- no `packages/webui` module imports the model-proxy client or reads the `proxy` config.
|
||||
|
||||
**Out of scope.**
|
||||
- Removing or disabling an account. Mos is filing a Vikunja task for a later row (mos-1608).
|
||||
- Every routing setting other than account priority.
|
||||
- Issuing or revoking client keys (P2), and any usage source (P5).
|
||||
- The upstream panel, any forward to the proxy port, and the subdomain fallback.
|
||||
- Traefik, DNS, Authentik settings, and the .54 Console's provider (Q218).
|
||||
- Any live instance, the management key, and the 8317 proxy.
|
||||
|
||||
**Order.** P4 starts when P1 lands, because it needs P1's client and config contract. It rebases on P2
|
||||
before its gate, for the key join, and lands after P2.
|
||||
|
||||
**Gate.** Gladstone gives the first Codex review, and Filbert reviews the landing candidate. The model-proxy,
|
||||
bus and webui suites run whole, webui with `MOSAIC_REQUIRE_EDITOR_BUILD=1`. Every touched test file runs
|
||||
whole. The named mutants below are killed. Every package suite but queue plus every `scripts/test-*.sh` is
|
||||
green on Sage's landing gate. BUILD.md has the upgrade-check output on the pinned version. Mutants: the
|
||||
accounts verb returns an unfiltered field; the callback verb skips the state check; a `/api/proxy/` route
|
||||
accepts a granted user; the API-key verb echoes the value in an error or a log.
|
||||
@@ -0,0 +1,109 @@
|
||||
# Brief: row 209, the .54 window with its own proxy
|
||||
|
||||
Written 2026-10-24 by Sage for Mos's mos-1615, which carries Jason's "Q54: yes" (DECISIONS Q253). Q253:
|
||||
.54 waits for its own model proxy. Bean's Z.ai key and Chet's ChatGPT/Codex login both go in through the P4
|
||||
Console proxy page. Chet runs GPT through his Codex login for 10-27, not GLM, which replaces Q186.
|
||||
|
||||
This brief replaces row 209's old brief (`docs/plans/2026-10-20_federation-r1-r2-r5.md`, "Brief: FED R8, the
|
||||
hub window on 10.1.1.54"). That section isn't edited. Phase D below runs it unchanged. Read the model-proxy
|
||||
design (`docs/plans/2026-10-24_stack-model-proxy.md`, sections 1, 5, 9 and 10), the rows doc
|
||||
(`docs/plans/2026-10-24_model-proxy-rows.md`) and the P4 brief (`docs/plans/2026-10-24_proxy-page-brief.md`)
|
||||
first. Line numbers are at origin/refactor 95d4991d2. Check them before you rely on them.
|
||||
|
||||
## Brief: row 209, the .54 window: proxy, Bean's and Chet's accounts, then FED R8
|
||||
|
||||
**What this row is.** A live window on 10.1.1.54, not a code row. Jason and Mos run it. Nothing here
|
||||
authorizes a step on any host. Each step waits for the window's go, and Console start and restart stay
|
||||
with Jason or Mos (Q173).
|
||||
|
||||
**Secrets.** The rows doc's rules apply on .54 too. No agent reads `<configDir>/secrets/proxy-management.key`
|
||||
or anything under .54's `<dataRoot>/proxy/` (`config.yaml`, `auth/`, `logs/`), and no agent reads Hermes's
|
||||
auth files or Chet's login in any form (D6, mos-1600 ruling 2). Agents read only what a command prints:
|
||||
hashes, unit state, refusal codes and the proxy page's allowlisted fields.
|
||||
|
||||
### Entry checks, all before phase A
|
||||
|
||||
1. P1 (row 329), P2 (331), P3 (332) and P4 (330) have landed and passed Sage's landing gate. P3 carries the
|
||||
amendment for pi's GLM and GPT routes that Mos rules on (sage-4285). Without it P3 proves only the
|
||||
Anthropic route.
|
||||
2. **Gap to close first.** `.54` installs through `scripts/case2-install.sh` and `scripts/case2-unit.sh`.
|
||||
P1 adds `mosaic-proxy.service` to `scripts/instance.sh` only (rows doc P1 item 7). `case2-unit.sh` writes
|
||||
no model-proxy unit today, and its bus unit has no `Wants=` or `After=` on one. A code row has to add the
|
||||
proxy unit to the Case 2 install, with the same sha256 refusal, before phase A. Sage files it once Mos
|
||||
rules (sage-4285).
|
||||
3. The .54 stack copy is re-pinned to a commit that holds rows 329 to 332 and the item 2 row.
|
||||
4. .54's Console signs Jason in through Authentik (Q218). The proxy page's writes need a signed-in owner
|
||||
(P4 item 8).
|
||||
5. Phase B has a recorded result, or Chet's login waits for phase C as phase B says.
|
||||
|
||||
### Phase A: the proxy on .54
|
||||
|
||||
Design section 9, for .54 as the `mosaic` user under `/srv/mosaic` (D1).
|
||||
|
||||
1. **Fetch.** P1's pinned fetch runs on .54. Sage compares the printed sha256 values with PIN.
|
||||
2. **Config and key.** Jason adds the `proxy` section to .54's `config.json` in an editor (J2), runs
|
||||
`mosaic proxy init` in his own terminal (J3) and starts the proxy unit.
|
||||
3. **Bean's key.** Jason pastes Bean's Z.ai API key into .54's proxy page (J4, P4 item 4) and sets its
|
||||
priority. The page never shows it again.
|
||||
4. **Chet's login.** Only after phase B passes. Jason signs the proxy in to Chet's ChatGPT/Codex account
|
||||
through the page's own OAuth flow (P4 item 3). The proxy holds a sign-in of its own. Nobody copies
|
||||
Hermes's auth file.
|
||||
5. **Business settings.** Bean's and Chet's `launch.models` name provider `proxy` (P3 item 5): Bean on his
|
||||
GLM model, Chet on his GPT model, with the model ids the proxy's `/v1/models` lists. The edit goes in
|
||||
through the human path that P3's BUILD.md names.
|
||||
6. **Restart.** Jason or Mos restarts the bus and Console. The bus reconciles, issues a key for each agent
|
||||
(P2) and runs D17's preflight for each one. Any refusal stops phase A. The fix is to remove the section
|
||||
and restart.
|
||||
7. **One real turn per route.** The tester actor launches one pi session for Bean (GLM through the Z.ai key)
|
||||
and one for Chet (GPT through the Codex login). Each makes one real turn through the proxy. Jason
|
||||
watches the proxy page's usage section and confirms each request landed on the account he expects (J5).
|
||||
The result goes into the row's record with who ran it.
|
||||
8. **Unit cleanup.** Once both turns pass, the bus unit drops the provider env file per design section 9
|
||||
step 7. The file stays for the 7-day rollback window.
|
||||
|
||||
Rollback at any point: remove the `proxy` section and restart.
|
||||
|
||||
### Phase B: two clients on one ChatGPT login
|
||||
|
||||
Hermes holds Chet's ChatGPT login until #423 step 5. Before that login goes into the .54 proxy (phase A
|
||||
step 4), a check has to show that two clients on one ChatGPT login don't revoke each other's refresh tokens
|
||||
(mos-1615 item 3). Row 229's brief named the same risk for a copied token.
|
||||
|
||||
- Two separate sign-ins, never a copied file: Hermes keeps its own, and the proxy gets its own through the
|
||||
page.
|
||||
- Pass: each client goes through at least one token refresh, and afterwards Hermes still answers on Chet's
|
||||
login and the proxy page still lists the account as active. Fail: either one drops out or needs a new
|
||||
sign-in.
|
||||
- The check is Jason's. It uses the real account, and no agent reads either client's token or auth file.
|
||||
Agents record what Jason reports and what the page lists.
|
||||
- **Open before the window.** I don't know how to make each client refresh on demand without someone reading
|
||||
a token, or how long ChatGPT's access tokens last. Researcher answers from the pinned 8.0.42 docs and
|
||||
Hermes's docs: how each side refreshes, whether either can be made to refresh, and how long the check has
|
||||
to run. The answer goes in this row's record.
|
||||
- If the check fails, or there's no safe way to run it, Chet's login goes in after #423 step 5, when Hermes
|
||||
has let go of it. Phase A step 7's GPT turn waits for that, and Chet doesn't go live on GPT until it passes.
|
||||
|
||||
### Phase C: Case 2 go-live, then Hermes stops
|
||||
|
||||
Bean and Chet go live in Case 2 on the proxy (#416). Hermes stops after that (#423 step 5, mos-1615), and
|
||||
that stays Melanie's choice (`docs/plans/2026-10-20_case2-rows.md`:1231). If phase B didn't pass, Chet's login goes into the proxy here and phase A step 7's GPT turn
|
||||
runs before Chet goes live.
|
||||
|
||||
### Phase D: FED R8
|
||||
|
||||
The old brief, unchanged: entry checks, build notes N1 and N2, and its done condition
|
||||
(`docs/plans/2026-10-20_federation-r1-r2-r5.md`, "Brief: FED R8, the hub window on 10.1.1.54").
|
||||
|
||||
### Done when
|
||||
|
||||
Phase A's two real turns are recorded, each on the account Jason expected. Phase B's result is recorded
|
||||
along with who ran it. Bean and Chet are live on the proxy. FED R8's own done condition holds.
|
||||
|
||||
### Out of scope
|
||||
|
||||
- Any code change. The item 2 gap and the P3 amendment are code rows of their own.
|
||||
- The dragon-lin default instance and .53. Their cutovers are P7 and row 246.
|
||||
- Hermes's server and profiles, beyond Jason's phase B check.
|
||||
- The 8317 host proxy and `~/.local/opt/EasyCLIProxyAPI`.
|
||||
- Row 229 (Vikunja 428). The proxy route supersedes it, and the queue parks it with that reason. Its live
|
||||
check is phase B.
|
||||
@@ -5,6 +5,12 @@ becomes the stack's credential and routing layer, with Q116 and Q127 still in fo
|
||||
Mos rules it before any code. Its build rows go to new Codex gpt-6.1-sol threads (Q246), and each gets its own
|
||||
brief once Mos has ruled. Line numbers are at origin/refactor 2ce476d54.
|
||||
|
||||
**Amendments.** Mos's mos-1600, mos-1601 and mos-1602 changes live in the row briefs
|
||||
(`docs/plans/2026-10-24_model-proxy-rows.md`), which win over this design where they differ. Jason's Q46
|
||||
and Q47 answers (DECISIONS Q250, mos-1606, 2026-10-24) are written into this file: accounts are entered in
|
||||
the Console's own proxy page, and the `/proxy/` forward to the upstream panel (D8) is dropped. The P4 brief
|
||||
for that page is `docs/plans/2026-10-24_proxy-page-brief.md`. Text marked "(Q250)" below is that change.
|
||||
|
||||
Not to be confused with queue row 237 ("one decision lands once", `2026-10-20_agent-credentials.md`). This is
|
||||
Vikunja task 237.
|
||||
|
||||
@@ -75,11 +81,13 @@ whose sha256 matches PIN. The control panel asset is pinned the same way, with
|
||||
(`config.example.v8.0.27.yaml`:94-103), and that would be unreviewed code behind Authentik. The stack never
|
||||
copies the 8317 binary. The first fetch of the release asset counts as external access, so it is Jason's
|
||||
step J1 or a row Mos approves. For containerized installs the binary and panel go into the proxy image
|
||||
(section 8).
|
||||
(section 8). Q250: nothing serves the panel to the Console now. P1 keeps the pin as built, and
|
||||
removing it is a later cleanup.
|
||||
|
||||
D5. **Initial config, then hands off.** The stack writes `config.yaml` once, when `<dataRoot>/proxy/` is
|
||||
first created, from a template in `packages/model-proxy/`, and never writes the file again. After that the
|
||||
stack changes the proxy only through the management API, and Jason changes it only through the panel.
|
||||
stack changes the proxy only through the management API, and Jason changes it only through the Console's
|
||||
proxy page, which calls the bus, which calls the management API (Q250).
|
||||
Row 96 point 2 (every management write rewrites the whole file and reorders it) then stops mattering,
|
||||
because nobody edits the file by hand. The template sets the defaults in section 3 and section 7,
|
||||
`request-retry: 0` so no hidden retries happen (as in row 96), the client-key list holding only the
|
||||
@@ -93,31 +101,23 @@ prompt doesn't echo the key. It writes the key to `<configDir>/secrets/proxy-man
|
||||
the initial `config.yaml`. The proxy hashes it in place on its first start (row 96 point 6). The stack reads
|
||||
only the secrets file, never the hashed value in config. The holder is the bus process alone (D12). The
|
||||
sandbox doesn't mount `<configDir>/secrets`, so no session can read the key, and no verb returns it. Jason
|
||||
types the same key into the panel to sign in. An agent never runs the prompt (Q173).
|
||||
types the key only at that prompt. The Console's proxy page needs only his Console sign-in, and the bus adds
|
||||
the key to its own management calls (Q250). An agent never runs the prompt (Q173).
|
||||
|
||||
D7. **Upstream credentials.** Jason adds every upstream account in the proxy's own panel: OAuth sign-ins
|
||||
(Claude, Codex and the others CLIProxyAPI supports) and API keys (for example z.ai). They live in the
|
||||
D7. **Upstream credentials.** Accounts are entered in the Console's proxy page (Q250). It covers OAuth
|
||||
sign-ins for Claude and Codex through the management API's `oauth/auth-url`, `oauth/callback` and
|
||||
`oauth/status`, upstream API keys (z.ai first, write-only and never echoed, mos-1608), and account
|
||||
priority. The page shows each account by an id, the first 12 hex of the sha256 of the proxy's own
|
||||
credential identifier, never of a token or key value (mos-1608). The credentials live in the
|
||||
proxy's `auth/` directory and config and nowhere else. There is no per-seat credential file. The stack never
|
||||
reads, copies or logs an upstream credential.
|
||||
|
||||
D8. **Panel path.** The Console forwards `https://mosaic.woltje.com/proxy/` to `127.0.0.1:<proxy.port>`, for
|
||||
the panel route and the management routes only. It forwards only after its existing auth-header and
|
||||
allowed-user check (decision 103, `packages/webui/src/serve.mjs`:453-469) passes. The Console never adds or
|
||||
stores the management key. Jason types it in the panel, and it passes through the forward. This adds no DNS
|
||||
record and no subdomain, as Q116 requires. Traefik and the tunnel already deliver mosaic.woltje.com to the
|
||||
Console (7332), so no infra change is needed. The forward gives no new authority. The management key
|
||||
is the barrier, and loopback processes can already reach the proxy port. Authentik is the outer layer. The
|
||||
#385 hole (a loopback process forging the Host and header) applies here the same way and is no worse,
|
||||
since the management key is still required.
|
||||
|
||||
A second Console (.54) forwards to its own instance's proxy, and its Authentik provider settings are Jason's
|
||||
(Q218).
|
||||
|
||||
Checks for the build row, on a stand-in under `unshare -rn` as in row 96:
|
||||
- the pinned panel works under the `/proxy/` sub-path (rewrite or base-path setting);
|
||||
- an OAuth sign-in done from the panel through the forward completes. If the callback can't return through
|
||||
the forward, the fallback is Jason running the proxy's CLI login in his own shell (`-claude-login
|
||||
-no-browser` and similar), and J3 says so.
|
||||
D8. **Dropped (Q250).** The design had the Console forward `https://mosaic.woltje.com/proxy/` to the
|
||||
proxy's own panel. Jason's Q46 and Q47 answers replace it with the Console's own proxy page (D7). The page
|
||||
calls bus routes, the bus calls the management API (D12), and the management key stays in the bus (D6). No
|
||||
new hostname is added. A panel subdomain is a fallback only if our page can't keep up with the management
|
||||
API across pinned proxy upgrades, and that call is Jason's. Each pinned upgrade runs the page's acceptance
|
||||
script against the new version (P4 brief item 9).
|
||||
|
||||
## 3. Priority routing, and how the business routing table maps onto it
|
||||
|
||||
@@ -131,10 +131,12 @@ The proxy picks which upstream account serves that model. The two don't overlap:
|
||||
- Account failover inside one model is the proxy's job. The stack doesn't model accounts per session.
|
||||
|
||||
D10. **Priority settings.** Defaults set in the template are listed below (Q222: settings with defaults).
|
||||
Jason can change all of them in the panel.
|
||||
Jason sets account priority in the Console's proxy page. The other routing settings keep the template
|
||||
defaults, and a page control for them is a later row (Q250).
|
||||
- `routing.strategy: fill-first`. A subscription account is used until it is rate-limited or out of quota, then
|
||||
the next one (`config.example`:150).
|
||||
- Each account gets a `priority` (larger first, `config.example`:480). Jason sets the order in the panel (J4).
|
||||
- Each account gets a `priority` (larger first, `config.example`:480). Jason sets the order in the Console's
|
||||
proxy page (J4).
|
||||
- `routing.session-affinity: true`, so a session stays on one account while it works and keeps its prompt
|
||||
cache (:154-171). Default `session-affinity-rebind-on: quota`, so a transient 5xx doesn't move a session.
|
||||
- No model aliases or alias pools by default. A pool that maps one name to several upstream models
|
||||
@@ -270,7 +272,7 @@ D20. **Settings and who changes them.** Every number in this design is a setting
|
||||
`rotateBy` 30 d, `proxy.rotateGraceMinutes` 120, `proxy.firstOutputSeconds` 120, `usage.cliproxyQueue.pollSeconds`
|
||||
15, routing strategy fill-first, affinity on. The per-key daily quota and the rotation period guard the human
|
||||
from agents, so only a human can change them (Q222). The routing settings live in the proxy and only Jason
|
||||
changes them, in the panel.
|
||||
changes them. Account priority is in the Console's proxy page, and the rest keep their defaults (Q250).
|
||||
|
||||
## 8. Row 157 re-scope (#1652, Vikunja 617)
|
||||
|
||||
@@ -297,7 +299,7 @@ changes. Cutover, per instance, with Jason present (Q127):
|
||||
2. Jason fetches and verifies the pinned binary and panel (J1). ops-01 or Sage checks the sha256 against PIN.
|
||||
3. Jason adds the `proxy` section to the instance config (J2), runs `mosaic proxy init` (D6), and starts
|
||||
`mosaic-proxy.service`. The bus isn't restarted yet.
|
||||
4. Jason signs in to the panel and adds the accounts (J3, J4). No session uses the proxy yet.
|
||||
4. Jason adds the accounts in the Console's proxy page (J3, J4). No session uses the proxy yet.
|
||||
5. A Console or bus restart (Jason or Mos, per Q173) picks up the section. The bus reconciles, issues a key
|
||||
for each listed agent, and runs D17's preflight for each one. Any refusal stops the cutover, and the fix
|
||||
is to remove the section and restart.
|
||||
@@ -318,15 +320,14 @@ accounts (J7). The 8317 host proxy and its clients are not part of any step.
|
||||
- **J2.** Add `"proxy": { "port": <port from the cutover note>, "binary": "<path>" }` to the instance's
|
||||
`config.json`, in an editor.
|
||||
- **J3.** In a terminal of your own, run `mosaic proxy init` and type a new management key twice. Keep it in your
|
||||
password manager. Then open `https://mosaic.woltje.com/proxy/` and sign in to Authentik as jason.woltje.
|
||||
Paste the management key into the panel's login box.
|
||||
- **J4.** In the panel's auth or OAuth page, sign in to each subscription account you want this instance to use
|
||||
(Claude, Codex, and so on). On the API keys page, paste each API key you want it to have (for example z.ai).
|
||||
Set each account's priority. The highest one is used first, and the next one only when the first is
|
||||
limited. If an OAuth sign-in doesn't return to the panel, run the CLI login the cutover note gives, in your
|
||||
own terminal.
|
||||
- **J5.** Watch the Console while the two test sessions run (cutover step 6), and confirm the panel's usage page
|
||||
shows their requests on the account you expect.
|
||||
password manager. You don't type it anywhere else (Q250).
|
||||
- **J4.** Open the Console's proxy page and sign in to Authentik as jason.woltje. Sign in to each subscription
|
||||
account you want this instance to use (Claude, Codex). If the sign-in tab doesn't return on its own, copy
|
||||
the full address from that tab and paste it into the page. Set each account's priority. The highest one is
|
||||
used first, and the next one only when the first is limited. Paste each API key you want it to have (for
|
||||
example z.ai) into the page's API-key field. The page never shows it again.
|
||||
- **J5.** Watch the Console while the two test sessions run (cutover step 6), and confirm the proxy page's usage
|
||||
section shows their requests on the account you expect.
|
||||
- **J6.** After 7 days on the proxy, delete `claude-session.env` for that instance.
|
||||
- **J7.** For Melanie's .54 hub, decide which accounts it uses: hers, yours, or new ones. Then do J2 to J4 on .54
|
||||
through its own Console's Authentik provider (Q218). Only accounts you entered for that hub go into its
|
||||
@@ -339,10 +340,10 @@ credentials, so a Claude reviewer (Dewey) gives the second review. Sage runs the
|
||||
|
||||
| Row | Piece | Depends on |
|
||||
|---|---|---|
|
||||
| P1 | `packages/model-proxy/`: PIN, template, management client, `mosaic proxy init`, the `mosaic-proxy` unit, config `proxy` section, stand-in tests (empty list, `/v1/models` local, 401 shape, panel sub-path, OAuth through the forward) | Mos's ruling on D3 |
|
||||
| P1 | `packages/model-proxy/`: PIN, template, management client, `mosaic proxy init`, the `mosaic-proxy` unit, config `proxy` section, stand-in tests (empty list, `/v1/models` local, 401 shape, OAuth callback URL; the panel checks are dropped, Q250) | Mos's ruling on D3 |
|
||||
| P2 | Per-agent keys: `model` store kind, issue, rotate, revoke, reconcile, D17 preflight | P1, rows 194 and 199 |
|
||||
| P3 | Harness config: Claude Code env, pi `models.json` and preflight, `sessionEnv` proxy mode | P2 |
|
||||
| P4 | Console `/proxy/` forward behind the existing auth check | P1 |
|
||||
| P4 | The Console proxy page and its bus verbs (Q250, `2026-10-24_proxy-page-brief.md`) | P1; lands after P2 |
|
||||
| P5 | `usage` plug-in kind and the `cliproxy-queue` module; key ids in `launch.limits.tokens` | P2 |
|
||||
| P6 | Row 157 brief amendment (section 8) | Row 157 resuming |
|
||||
| P7 | Cutover note and per-instance window (section 9) | P1 to P4 landed; Jason present |
|
||||
@@ -353,7 +354,7 @@ The Codex harness config (D16) goes with the Codex harness row, which isn't on t
|
||||
|
||||
1. D1/D3: the `proxy` section in the instance config (a schema change), and the proxy as its own user unit.
|
||||
2. D6: the management key set by Jason at a human-only prompt and held only by the bus process.
|
||||
3. D8: the Console forwards `/proxy/` rather than a new Traefik route.
|
||||
3. D8: ruled. Jason's Q46 and Q47 (Q250) drop the forward for the Console's own proxy page.
|
||||
4. D13: an implicit per-agent model key with no role-file change.
|
||||
5. D15: plaintext keys at rest accepted under those limits.
|
||||
6. D16: proxy mode drops the instance-wide provider variables from every session.
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
# PRD 1.18 brief: REQ-INST-2 prints the providers entry
|
||||
|
||||
Sage, 2026-10-25, for Mos's ruling mos-1671 on sage-4418. This follows
|
||||
`docs/plans/BRIEF-TEMPLATE.md`. Vikunja 458 (bundled Pocket ID).
|
||||
|
||||
## PRD 1.18 REQ-INST-2 prints the providers entry (mos-1671)
|
||||
|
||||
### Problem
|
||||
|
||||
REQ-INST-2's second bullet says the stack installs the bundled Pocket ID "and
|
||||
writes it as the Console's one providers entry". That sentence is Mos's reading
|
||||
(mos-1202), not Jason's words. The row 255 design, landed at de3e23dde, chose R1:
|
||||
enroll prints the entry and writes nothing, because config.json is user-authored
|
||||
and never overwritten (canon invariant 2, Q175). Mos approved R1 in mos-1666 and
|
||||
ruled the amendment in mos-1671. What the requirement allows or forbids is
|
||||
unchanged.
|
||||
|
||||
### Owner and reviewer
|
||||
|
||||
- Owner: Gosalyn.
|
||||
- Reviewer: Webby.
|
||||
- After: row 255 (landed).
|
||||
|
||||
### Files owned
|
||||
|
||||
- `docs/prd/mosaic-stack.md`.
|
||||
- `packages/tasks/requirements.json`: version 1.18 only. No id or title changes,
|
||||
so the count stays 87.
|
||||
- `packages/tasks/tests/requirements.test.mjs`: the version pin 1.18 (:24).
|
||||
|
||||
### What ships
|
||||
|
||||
- In REQ-INST-2's second bullet (PRD :1519-1520), replace
|
||||
"and writes it as the Console's one providers entry."
|
||||
with
|
||||
"and prints the Console's one providers entry for the user to add to
|
||||
config.json. The stack never writes config.json (canon invariant 2)."
|
||||
The rest of the bullet stays, and so does Jason's Q203 quote.
|
||||
- Status line: version 1.18.
|
||||
- The header gets a 1.18 sentence: Version 1.18 corrects Mos's reading in
|
||||
REQ-INST-2 to match the approved row 255 design. The stack prints the
|
||||
providers entry and never writes config.json. What the requirement allows or
|
||||
forbids is unchanged (mos-1671, sage-4418). Doc-only, so it takes the 1.11
|
||||
path: one seat drafts, a second reviews, Sage lands.
|
||||
- A "Version 1.18 source" line, placed before the 1.17 one: Mos's ruling
|
||||
mos-1671 on 2026-10-25, answering sage-4418, with the old and new text.
|
||||
|
||||
### Out of scope
|
||||
|
||||
- The P1 to P6 build rows from the row 255 design. Sage files them after this
|
||||
lands (mos-1671).
|
||||
- Any other REQ-INST-2 wording, and REQ-INST-1 and REQ-INST-3.
|
||||
|
||||
### Gate
|
||||
|
||||
- Webby checks that the PRD diff is the replacement, the Status line, the 1.18
|
||||
sentence and the source line, and nothing else.
|
||||
- On Sage's gate:
|
||||
- tasks, run whole;
|
||||
- bus, run whole, because the broker loads requirements.json;
|
||||
- cli `stack-copy.test.mjs`;
|
||||
- every `scripts/test-*.sh`, under `timeout -k 10`.
|
||||
- Mos gets the landing commit.
|
||||
|
||||
### Handoffs
|
||||
|
||||
Every seat hands off directly (DECISIONS Q210, mos-1221). When the owner pushes a
|
||||
round or the reviewer posts a verdict, that seat messages the next seat's T3
|
||||
thread and Sage's with `mcp__t3__t3_send_message`. Mos has one step here, which
|
||||
is receiving the landing commit.
|
||||
@@ -96,6 +96,12 @@ suite by design and runs through a script puts that entry in the brief's
|
||||
Gate and in BUILD.md with the row, and the lead adds it to the landing
|
||||
gate's list. Any unlisted skip stays RED.
|
||||
|
||||
A builder's list of whole test files to run for a row comes from imports,
|
||||
not from a text grep for a path, and goes in the builder's report before
|
||||
the run. A file on the mos-1592 list (`packages/cli/tests/case1-accept.test.mjs`
|
||||
for now) stays off the list unless Mos has approved that run (mos-1612,
|
||||
after row 329's round 2 grep matched fixture text and reran the F7 file).
|
||||
|
||||
Any row that builds businessDoc() with a library project sets the chief's
|
||||
gitea ref in its fixture (mos-1584, after row 285 gave the chief of staff
|
||||
a read-scoped gitea credential that the validator requires when a business
|
||||
|
||||
@@ -768,3 +768,55 @@ Sage, for Duckworth's N1 on row 208 (c31496, landed f58049de0). packages/webui/s
|
||||
re-renders the user view on a 5 s timer while the tab is visible, whether or not anything changed. That's a
|
||||
steady client and server load per open tab, not a correctness or guard issue. Fix: render on change, or poll the bus only for a change
|
||||
marker. Bound to the next row that edits user.js.
|
||||
|
||||
|
||||
## Row 329 N2: `mosaic proxy fetch` has no agent or human guard
|
||||
|
||||
Sage, for Dewey's round 1 N2 on row 329 (c31639, landing deferral per c31643). `mosaic proxy fetch` downloads
|
||||
the pinned CLIProxyAPI archive from GitHub and writes `<dataRoot>/opt/cliproxyapi/` for any caller that has
|
||||
the instance config. P1's brief didn't ask for a guard. The fetch is pinned and sha256-checked against
|
||||
`packages/model-proxy/PIN`, so the risk is an unasked network fetch and a disk write, not a wrong binary.
|
||||
Bound to row 331 (P2): P2 decides whether fetch needs the human or agent guard its key verbs get, and
|
||||
records the choice in its BUILD.md. If P2 leaves it, P7 decides before cutover.
|
||||
|
||||
## Row 329 R2-N1: the management-key rule lives in three places
|
||||
|
||||
Sage, for Dewey's round 2 R2-N1 on row 329 (c31643). Round 2 tightened the key rule to
|
||||
`/^[\x21-\x7e]{1,4096}$/` in `packages/model-proxy/src/common.mjs`:33, which `initializeProxy` enforces, but
|
||||
`packages/bus/src/broker.mjs`:4827 and `packages/cli/src/model-proxy.mjs`:57 still use the round 1 predicate.
|
||||
A Latin-1 or edge-space key gets past both and is refused at init with `proxy-key-invalid`, before any write,
|
||||
but only after both prompts and a bus round trip. Fix: export one predicate from the model-proxy package
|
||||
and use it in all three places, with a test at each caller. Bound to row 331 (P2), which edits the broker's
|
||||
proxy verbs.
|
||||
|
||||
## Row 329 N1: the 127.0.0.1 bind isn't observed on the real binary
|
||||
|
||||
Sage, for Dewey's round 1 N1 on row 329 (c31639). The acceptance netns had only `lo`, so P1 writes
|
||||
`server.host: 127.0.0.1` and `management.allow-remote: false`
|
||||
but never saw the real binary refuse a non-loopback client.
|
||||
Bound to P7: at cutover, with Jason present, confirm the listener is on 127.0.0.1 only (`ss -ltnp`), and
|
||||
record it in P7's receipt.
|
||||
|
||||
## Row 284 N1: library.get lists the whole served tree per read
|
||||
|
||||
Sage, for Webby's round 1 N1 on row 284 (c31654 carries it forward). Each library get runs `listTree`
|
||||
(`git ls-tree -r -l`) over the whole served tree to find one blob oid. On a large library that is one full
|
||||
tree listing per read. `git rev-parse <commit>:<path>`, or a per-commit cache, would avoid it. Not a
|
||||
correctness issue. Bound to the next row that edits the library read path; that row measures a get on a
|
||||
library of realistic size and records the choice in its BUILD.md.
|
||||
|
||||
## Row 284 N1: Vikunja task
|
||||
|
||||
Sage, for mos-1647 item 3 (Q109). The row 284 N1 entry above is tracked as Vikunja 634. No open task
|
||||
covered the library read path.
|
||||
|
||||
## Row 332 finding: CLIProxyAPI startup version refreshes reach outside the host
|
||||
|
||||
Sage, for Fethry's row 332 isolated runs (2026-10-24, pinned 8.0.42, `unshare -rn` with only `lo`). At
|
||||
startup the binary tried `https://registry.npmjs.org/@xai-official/grok/latest` (xai_version.go:96, blocked
|
||||
by the namespace) and then started a 3-hour Grok CLI version refresh and a 3-hour antigravity version
|
||||
refresh. The proxy kept serving with its fallback version. Evidence: origin/fethry/row332-p1
|
||||
`agents/fethry/work/queue-332/BUILD.md`:251-252 and `evidence/offline.txt`. Bound to P7: before or at
|
||||
cutover, find a config switch that turns these off and set it in P1's initial config with a test, or
|
||||
decide on purpose to allow or block that egress and record it in P7's receipt. Tracked as Vikunja 633
|
||||
(umbrella 237).
|
||||
+24
-17
@@ -33,7 +33,7 @@ Gaps found while working go to `docs/plans/DEFERRED.md`, not here.
|
||||
|
||||
<!-- mosaic-queue:begin -->
|
||||
|
||||
Generated from `docs/plans/queue.json` revision 3945 by `queue render`. Do not edit between the markers; change the queue with `scripts/mosaic queue`.
|
||||
Generated from `docs/plans/queue.json` revision 4095 by `queue render`. Do not edit between the markers; change the queue with `scripts/mosaic queue`.
|
||||
|
||||
| # | Piece | Owner | Issues | State | After | Gate | Brief | Note |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
@@ -229,7 +229,7 @@ Generated from `docs/plans/queue.json` revision 3945 by `queue render`. Do not e
|
||||
| 190 | several Mosaic Stack instances on one host: per-instance config, data root, units and ports (MVP T1.1, mos-0974, Vikunja #414) | darkwing; reviewers filbert | #1688 | done | — | Filbert approves DESIGN.md then the manifest; cli suite and every scripts/test-*.sh green on Sage's gate; the design mutants killed (sage) | `docs/plans/2026-10-20_multi-instance.md` § Brief: several Mosaic Stack instances on one host | Landed 00d4cc1f6 on refactor (base 99a406ed3). Patch-id 5ec610a7 matches git diff 176a6bf4b..df65a3d4c on the 25 manifest paths. Manifest cc0ea9e8, Filbert approve r3 29713. Gate on d0bbc5c1c: packages 2664/0, scripts 429/0. Mutants 20/20. Unpushed. |
|
||||
| 191 | one kill switch for the bus, every run, Discord and new launches, from the CLI and the Console (MVP T1.4, mos-0974, Vikunja #414) | rocko; reviewers dewey | #1689 | done | — | Dewey approves DESIGN.md then the manifest; cli, bus, discord and webui suites and every scripts/test-*.sh green on Sage's gate; the mutants killed (sage) | `docs/plans/2026-10-20_kill-switch.md` § Brief: one kill switch for the bus, every run, Discord and new launches | Landed 0fa7bf421 fast-forward on 86f95bb27 (10 commits, 89 paths; manifest 0bcbf337 = 88 paths without BUILD.md). Dewey manifest APPROVE c30359 rev 3118. Gate: 77 mutants killed (75 assert + SR08, KS54 timeout with controls), suites green on Sage's window; N7 closed by runs suite 43/0/0 on 0fa7bf421. N6, clock fix, :52 assertion, generic cause go to Vikunja 502 (mos-1267/1268). Rebase next: 205, 236, 194, 253, 274, 268. |
|
||||
| 192 | Q175 phase 1: the Console verifies SSO itself (--sso), OIDC RP with oauth4webapi 3.8.8, no live change (MVP T1.2, #412) | launchpad; reviewers webby | #1690 | done | — | Webby approves the manifest; webui and cli suites, scripts/test-config.sh and every scripts/test-*.sh green on Sage's gate; design section 9 mutants killed (sage) | `docs/plans/2026-10-20_sso-phase1.md` § Brief: Q175 phase 1, the Console verifies SSO itself (--sso) | Landed 4429a104f on refactor (squash of launchpad/row192 53bb59462..37582e820, round 2 manifest 6f8cee14...7787). patch-id 4a4869026 matches the reviewed diff on all 18 paths. Gate on 088087ac9: package suites 2758/0, scripts 429/0, mutants 22 of 23 killed (#23 equivalent, sage-1407). npm ci in canonical, oauth4webapi 3.8.8. Live re-pin is a window with Mos (mos-1099 item 3). |
|
||||
| 193 | many humans per business, human roles, private and shared threads, one access.json store (MVP T1.3, Vikunja #414/#415) | morgana; reviewers duckworth | #1691 | in-progress | — | Duckworth approves DESIGN.md then the manifest; bus, business, cli and webui suites and every scripts/test-*.sh green on Sage's gate; the mutants killed (sage) | `docs/plans/2026-10-20_human-users.md` § Brief: many humans per business, human roles, private and shared threads | — |
|
||||
| 193 | many humans per business, human roles, private and shared threads, one access.json store (MVP T1.3, Vikunja #414/#415) | morgana; reviewers duckworth | #1691 | in-review, round 1, request posted | — | Duckworth approves DESIGN.md then the manifest; bus, business, cli and webui suites and every scripts/test-*.sh green on Sage's gate; the mutants killed (sage) | `docs/plans/2026-10-20_human-users.md` § Brief: many humans per business, human roles, private and shared threads | — |
|
||||
| 194 | agent lifecycle from the Console and the CLI (create, launch, terminate, regenerate, delete) with a per-agent hire/fire veto (MVP T1.5, Vikunja #414/#415) | honker; reviewers webby | #1692 | done | — | Webby approves DESIGN.md then the manifest; bus, cli, business and webui suites and every scripts/test-*.sh green on Sage's gate; the mutants killed (sage) | `docs/plans/2026-10-20_agent-lifecycle.md` § Brief: agent lifecycle from the Console and the CLI, with a per-agent hire/fire veto | Landed fd6dd327c on refactor, a fast-forward on e122aad8e. b18 is b17 3f451772d rebased: 16 commits =, series patch-id 64303253f8e6, packages equal b17. Webby approve webby-0120 on manifest 29f131ab. Honker gate on fd6dd327c: runb8 39 files 503/0/0, mutants 17/17; gate.sh 18 packages 3668/0, ten scripts rc=0, Docker up, skips environment-only and named. Overlap with 13 and 257 clean. #1692 closed. |
|
||||
| 195 | row 195: the Case 1 install on 10.1.1.53 as mosaic under /srv/mosaic, reusing C2-13's scripts by input under row 190's canon (Q181, Q182/Q183, Q185; ops-01 root steps under #423 step 1) | darkwing; reviewers duckworth | #1693 | done | 190 done, 226 done, 233 done | Duckworth approves DESIGN.md then the manifest; cli suite and every scripts/test-*.sh green on Sage's gate; the mutants killed (sage) | `docs/plans/2026-10-20_hub-own-uid.md` § Brief: the Case 1 install on 10.1.1.53 (row 195) | LANDED b65014647 (pushed 361ba2387 tip). Patch-id 656e43ff25de = 4ced5e63d..37171f65b; verify-commit ok, 5 paths. Combined gate with 213 on 38b83ea5c+paths 09:45:52-09:57:52Z: business 200/0 bus 542/0 harness 140/0 cli 663/0, all 10 scripts green, L1 killed. N1-N3 to DEFERRED next; follow-up darkwing/row195-n1 1e3c4767c. |
|
||||
| 196 | the human boundary across uids and humans: Console, tester listener, broker.sock and the path-bound human proof (P19 333, before federation R3, mos-0989) | gander; reviewers duckworth | #1694 | done | — | Duckworth approves DESIGN.md then the manifest; bus, webui and cli suites and every scripts/test-*.sh green on Sage's gate; the mutants killed (sage) | `docs/plans/2026-10-20_human-boundary.md` § Brief: the human boundary across uids and humans (P19 333) | Landed 7247d80c7 on 666173292: 39 manifest paths of 527b9a1e6 (CANDIDATE.sha256 537d30ae), patch-id 6f3777d593e6 matches f48725cfc..527b9a1e6 on the manifest, blob diff empty, tree matches merge-tree. Gate gander-0066 2334/0/1, all 10 shells, 38/38 mutants. Approved rev 2973 and rev 2986 (Duckworth, c30156). Overlap: 202 cli README and 194 Honker branches rebase onto it. BUILD-LOG and C1 DEFERRED follow doc-only. |
|
||||
@@ -245,12 +245,12 @@ Generated from `docs/plans/queue.json` revision 3945 by `queue render`. Do not e
|
||||
| 206 | 193b2: thread shares, schema 3k-3l after the #436b build (#1691; live needs a --migrate window with Jason) | launchpad; reviewers duckworth | #1704 | done | 205 done, 234 done, 236 done, 275 done | Duckworth approves the manifest; bus suite, cli suite and every scripts/test-*.sh green on Sage's gate; the mutants killed (sage) | `docs/plans/2026-10-20_human-users-build.md` § Brief: 193b2, thread shares (schema 3l) | Landed 0cbe2e9b3 fast-forward on 17f415792 (10 commits, 22 paths), pushed 19:47Z. Duckworth APPROVE rev 3322 c30795 on 0cbe2e9b3; request rev 3320/3321 c30793 posted as jarvis. Gate (Launchpad, 9538e0fc8, tip differs in BUILD.md only): bus 850/0, cli 869/0, ten scripts/test-*.sh rc=0, touched files whole green, M2-M4 M7-M9 and Q2 killed. One placed fixture red (mos-1272). Schema 3l to 3m; live --migrate is Mos's go under Q173. |
|
||||
| 207 | 193c: mosaic access user verbs and --level viewer (#1691) | megavolt; reviewers duckworth | #1705 | done | 202 done | Duckworth approves the manifest; cli suite and every scripts/test-*.sh green on Sage's gate; the mutants killed (sage) | `docs/plans/2026-10-20_human-users-build.md` § Brief: 193c, mosaic access user verbs and --level viewer | LANDED c4f77373f 22:49Z 10-22 (fast-forward from f0e3dcdf4). Rebuild of gated 9bb406c6c: range-diff 4/4 =, patch-ids equal, 4 manifest blobs equal. Duckworth APPROVE c30849 rev 3356. Gate on 712f79c0a under sage-3041: access.test 31/31, M1-M8 killed, cli 894/894, ten scripts green. N1 DEFERRED (next access.test row). No live change. |
|
||||
| 208 | 193d: Console shared list, share controls and viewer read-only (#1691; also after FED R6 when filed) | poe; reviewers duckworth, gladstone | #1706 | done | 192 done, 206 done, 294 done | Gladstone (Codex, first review) and Duckworth approve the manifest; webui suite and every scripts/test-*.sh green on Sage's gate; the mutants killed (sage) | `docs/plans/2026-10-20_human-users-build.md` § Brief: 193d, the Console's shared list, share controls and viewer read-only | LANDED f58049de0 (build 4a4bef6c1, Duckworth note f58049de0), combined with row 326 on one full gate 04:36-04:51Z: all package suites except queue 0 fail 0 skip (webui 418, plugins 119, cli 986), every scripts/test-*.sh green. Gladstone c31495, Duckworth c31496. #1706 closed c31504. N1 user.js 5 s re-render to DEFERRED. Bundle 9fc7754a. |
|
||||
| 209 | FED R8: the hub window on 10.1.1.54, a recorded acceptance (#414, r4.11 b93f098f0; live window run by Jason and Mos, after the Case 2 install #416, Bean and Chet live and both Hermes gateways stopped) | sage; reviewers duckworth | — | queued | — | Every entry check's output is in the R8 record with who ran it; Jason signs in to the hub and sends one message, Melanie revokes, his next request is refused; Duckworth checks the record (sage) | `docs/plans/2026-10-20_federation-r1-r2-r5.md` § Brief: FED R8, the hub window on 10.1.1.54 | Stays queued until its entry gates near: Case 2 install on .54 (#416, by 2026-10-27), Bean and Chet live, both Hermes gateways on .54 stopped, R7, #412 phase 2, #419 answer. Filed per mos-1073 after duckworth-0034 (Sage) |
|
||||
| 209 | FED R8: the hub window on 10.1.1.54, a recorded acceptance (#414, r4.11 b93f098f0; live window run by Jason and Mos, after the Case 2 install #416, Bean and Chet live and both Hermes gateways stopped) | sage; reviewers duckworth | — | queued | — | Every entry check's output is in the R8 record with who ran it; Jason signs in to the hub and sends one message, Melanie revokes, his next request is refused; Duckworth checks the record (sage) | `docs/plans/2026-10-24_row209-hub-54-window.md` § Brief: row 209, the .54 window: proxy, Bean's and Chet's accounts, then FED R8 | Stays queued until its entry gates near: Case 2 install on .54 (#416, by 2026-10-27), Bean and Chet live, both Hermes gateways on .54 stopped, R7, #412 phase 2, #419 answer. Filed per mos-1073 after duckworth-0034 (Sage) |
|
||||
| 210 | Agent host access with sudo through the credential store: grant per agent and host, the stack does ssh and sudo, the agent never sees the key (#1707, Vikunja #424, Q183/Q184, due 10-27; chained on row 199's candidate) | gizmoduck; reviewers duckworth | #1707 | done | — | Duckworth approves DESIGN.md, then the manifest; bus, business, cli suites and every scripts/test-*.sh green on Sage's gate; the mutants killed (sage) | `docs/plans/2026-10-20_host-credentials.md` § Brief: agent host access with sudo through the credential store (#424) | Landed f5753c0e8 on refactor (base 9d165be8c), pushed. Patch-id 723b1c83 matches git diff ad95c888c..0485384e9 on the 23 manifest paths; landed files pass r5 manifest 688d38b9. Duckworth approve r2 rev 2592, r3 29851. Mutants 52/53, M22b equivalent (rev 2584). Gate on ad95c888c+patch: packages 2796/0, scripts 429/0; landed blobs equal the gate tree. |
|
||||
| 211 | Force-push guard: scripts/git-hooks/pre-push refuses non-fast-forward and delete pushes from every worktree, and scripts/slot-busy.sh exits 1 on BUSY (#1709, Vikunja #426, mos-1078/1083) | darkwing; reviewers dewey | #1709 | in-progress | — | Dewey approves the manifest; the new or changed scripts/test-*.sh and every other scripts/test-*.sh green on Sage's gate; the mutants killed; hook installed in the canonical checkout with a scripted refused force-push (sage) | `docs/plans/2026-10-20_force-push-guard.md` § Brief: a pre-push hook that refuses force-pushes, and a busy check that fails on BUSY (#426) | — |
|
||||
| 212 | Case 2 C2-01 packages/library: mapping, scope, reader, resolver, R-rules, renderItems, survey | gosalyn; reviewers webby | #1713 | done | — | Webby approves the manifest. The library tests and the cli suite are green on Sage's gate, along with every `scripts/test-*.sh`. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-01 packages/library: mapping, scope, reader, resolver, R-rules, renderItems, survey | Landed ee7b2f137 (pushed 09:13Z) on f6c70f944, alone per mos-1162: the 21 manifest paths from a2c72ac95. Patch-id ea84d3e35470 equals the candidate's; blobs and modes match; verify-commit ok (21 paths). No 212 path changed after c771a36f4. Gate: Sage's landing gate 08:51-09:03Z on 4ced5e63d plus 212's and 197's paths, GATE_PASSED, node 981/0, selftests 429/0. Gosalyn r3 slot 451/0, test-queue 28/0. Row 197 waits for r6 (lane proof stopped, sage-1881). |
|
||||
| 213 | Case 2 C2-08 creative roles, persona file and block, M1, M2, M6, M10, prompt passed by file | morgana; reviewers webby | #1714 | done | — | Webby approves the manifest. The business, bus and harness suites, `scripts/test-config.sh` and every `scripts/test-*.sh` are green on Sage's gate, and the `models` mutant is killed. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-08 creative roles, persona file and block, M1, M2, M6, M10, prompt passed by file | LANDED 361ba2387 (39 paths incl. 4 packet files). Patch-id f313e69b6f7e = c771a36f4..2b3e67e36; verify-commit ok, 35 manifest paths. Same combined gate as 195: business 200/0 bus 542/0 harness 140/0 cli 663/0, test-config 31/0 and all 10 scripts green, models mutant L1 killed. Webby N2 is row 235 acceptance (mos-1163). |
|
||||
| 214 | Case 2 C2-11a editor wikilink node, after measuring whether [[ round-trips | herb; reviewers filbert | #1715 | in-progress | — | Filbert approves the manifest. The webui suite is green on Sage's gate, along with every `scripts/test-*.sh`. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-11a editor wikilink node, after measuring whether [[ round-trips | — |
|
||||
| 214 | Case 2 C2-11a editor wikilink node, after measuring whether [[ round-trips | herb; reviewers filbert | #1715 | done | — | Filbert approves the manifest. The webui suite is green on Sage's gate, along with every `scripts/test-*.sh`. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-11a editor wikilink node, after measuring whether [[ round-trips | LANDED 3a8e4abad (pushed 78b69e1e6..3a8e4abad, 6 commits cherry-picked onto 78b69e1e6). Gate GREEN 04:10:34Z, all package suites and scripts; queue package runs via test-queue.sh (156). Filbert approve c31679 rev 4093. Range-diff equal except BUILD-LOG context. |
|
||||
| 215 | Case 2 C2-04 the library entry in the business file, consumer skips, M9, mirror, library.file and library.status | herb; reviewers filbert | #1716 | done | — | Filbert approves the manifest. The business, seat, cli, project, bus and webui suites are green on Sage's gate, along with every `scripts/test-*.sh`. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-04 the library entry in the business file, consumer skips, M9, mirror, library.file and library.status | LANDED e54e05463 on 6096b051b (sage-2094). Patch-id 2f68188b6c9d equals a36523713..dde3445ab; 118 paths, blobs and modes equal; tree 5b1613245 equals merge-tree. No path overlap with rows 66/243; no hash pins either way. Gate: Filbert APPROVE rev 2924; herb-0095 grant sage-2071 2634 pass 0 fail, 1 webui skip (editor rebuild needs esbuild 0.28.2, env, not a 215 path), accepted. |
|
||||
| 216 | Case 2 C2-05a lookup index and queries | researcher; reviewers filbert | #1717 | done | 268 done | Filbert approves the manifest. The library suite is green on Sage's gate, along with every `scripts/test-*.sh`. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-05a lookup index and queries | LANDED fbe57a05b (replay of r5 dae76ccc2 onto 8e2885d26, 3 commits, 0 patch-id mismatches), pushed 21:09Z with 582b86935. Sage joint gate GREEN 21:05:34Z on fbe57a05b, every package suite but queue and every scripts/test-*.sh green. Filbert APPROVE r2 c31384 rev 3697. N3 (get returns a universe own supporting files) binds the C2-05c row; N1 doc, N2 universeInfo echo and BUILD.md pronoun nit go to a later docs commit. |
|
||||
| 217 | Case 2 C2-06 the citation guard, the page store, the runner texts and the retry | beakley; reviewers webby | #1718 | done | 268 done, 283 done | Webby approves the manifest. The library, bus and harness suites are green on Sage's gate, along with every `scripts/test-*.sh`. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-06 the citation guard, the page store, the runner texts and the retry | LANDED d0a6a87cd (pushed 11:15Z 10-24, with 296): 9 cherry-picks on 296, range-diff 5 = and 4 ! (BUILD-LOG/SESSIONS append conflicts kept both), blobs equal 96659ccf4 (79 paths); Webby c31549 rev 3901; gate GREEN 11:14:53Z own npm ci, library 142 bus 974 business 270 cli 988 harness 172 0 fail, all scripts rc 0; PUSH_READY; #1718 closed c31559; Vikunja 533 comment 1054. |
|
||||
@@ -260,12 +260,12 @@ Generated from `docs/plans/queue.json` revision 3945 by `queue render`. Do not e
|
||||
| 221 | Case 2 C2-20 Bean and Chet persona import, with a count-only dry run | gosalyn; reviewers webby | #1722 | done | — | Webby approves the manifest. The test file runs green on its own and the cli suite is green on Sage's gate, along with every `scripts/test-*.sh`. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-20 Bean and Chet persona import, with a count-only dry run | LANDED 300766450, pushed. Cand 8f403d0d4, manifest 20f05e3a6ad5, 22 paths, verify-commit ok, patch-id dfbb754c6fb4 equals 62ddc96cc..8f403d0d4. Gate 11:07:50-11:19Z on b1fece6f0: test file alone 11/0, harness 140/0, cli 677/0, all scripts green. Brief Gate met: webby-0073 approve, test file alone, cli, scripts. No live run in the Gate; the import itself waits on Jason. N1 N2 N4 go to C2-20b, N3 to DEFERRED. |
|
||||
| 222 | Case 2 C2-03a fetch-only sync | megavolt; reviewers dewey | #1723 | done | — | Dewey approves the manifest. The library and bus suites are green on Sage's gate, along with every `scripts/test-*.sh`, and the mutant is killed. A search of the test run's output for the fixture token finds nothing. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-03a fetch-only sync | sage-2024 on megavolt-0089: core.createObject=rename in the fetch argv is accepted as a brief departure, since C2-04 inspectMirror refuses nlink 2. Dewey checks it. The askpass env keys, export SAFE in project/src/git.mjs, bus/tests/library-sync.test.mjs and the SURVEY-RUN user line are accepted. The 5 s client timeout residual goes in BUILD.md and Dewey rules fix or defer. Slot after 197 proof 3 and the 249 gate. |
|
||||
| 223 | Case 2 C2-07 runner retry on a guard refusal, and the runner's notices | researcher; reviewers filbert | #1724 | blocked (from briefed): Q226: C2-07 folded into C2-06 (row 217). No work here; Jason parks it. | — | Filbert approves the manifest. The harness suite is green on Sage's gate, along with every `scripts/test-*.sh`. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-07 folded into C2-06 | — |
|
||||
| 224 | Case 2 C2-05b broker lookup verbs and typed tools | della; reviewers dewey | #1725 | in-progress | 216 done | Dewey approves the manifest. The bus and harness suites are green on Sage's gate, along with every `scripts/test-*.sh`. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-05b broker lookup verbs and typed tools | — |
|
||||
| 225 | Case 2 C2-10b Console chat: replies, citations, write notices and the status line | fethry; reviewers dewey | #1726 | briefed | 217 done | Dewey approves the manifest. The webui suite is green on Sage's gate, along with every `scripts/test-*.sh`. Grep for hash pins on `bus.js` and `serve.mjs` before in-review. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-10b Console chat: replies, citations, write notices and the status line | — |
|
||||
| 224 | Case 2 C2-05b broker lookup verbs and typed tools | della; reviewers dewey | #1725 | done | 216 done | Dewey approves the manifest. The bus and harness suites are green on Sage's gate, along with every `scripts/test-*.sh`. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-05b broker lookup verbs and typed tools | LANDED 5e77cdd09 19:18Z 10-24 (13 Della commits on 7fe32d722). Gate GREEN 19:16:37Z on 27624aa66, drift docs-only. Dewey APPROVE c31619. #1725 closed c31623. |
|
||||
| 225 | Case 2 C2-10b Console chat: replies, citations, write notices and the status line | fethry; reviewers dewey | #1726 | done | 217 done | Dewey approves the manifest. The webui suite is green on Sage's gate, along with every `scripts/test-*.sh`. Grep for hash pins on `bus.js` and `serve.mjs` before in-review. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-10b Console chat: replies, citations, write notices and the status line | LANDED 9b6345466 on refactor, pushed 15:55:22Z: fethry r2 c1f9dfd3c cherry-picked onto c63801959, 8 commits equal by range-diff and 3 differ only in log hunks (both sides kept), 13 manifest paths match 517af41b. Dewey APPROVE c31599 rev 3960, request c31600. Sage gate GREEN 15:54:58Z: every package suite but queue 0 fail (webui 442, cli 988+1 allowed FED R7 skip), 12 scripts rc 0. #1726 closed c31604. |
|
||||
| 226 | Case 2 C2-13 install script and precheck for the host | gosalyn; reviewers webby | #1727 | done | 215 done, 221 done, 222 done, 230 done | Webby approves the manifest. The test file and the cli suite are green on Sage's gate, along with every `scripts/test-*.sh`. The run on the host is a separate window with Jason's go. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-13b install script and library precheck | landed 661890e90 (replay of bfed0aa6c 893b4fd25 f3fabf51b onto 8352da88c, patch-ids equal, four blobs and modes equal to f3fabf51b) and fd3d2a99f (Darkwing 8a6321790 replay, mos-1519), tree 78fc5ad21 equals merge-tree. Webby APPROVE rev 3641. Sage gate GREEN 19:56Z on f3fabf51b: 17 package suites and 10 scripts, 0 fail. Webby N1-N4 DEFERRED e2b873390. #1727 closed. |
|
||||
| 227 | Case 2 C2-14 end-to-end acceptance on a scratch root | gizmoduck; reviewers dewey | #1728 | in-progress | — | Dewey runs the script and approves. It is green on Sage's gate with every `scripts/test-*.sh`. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-14 end-to-end acceptance on a scratch root | — |
|
||||
| 227 | Case 2 C2-14 end-to-end acceptance on a scratch root | steelbeak; reviewers dewey | #1728 | in-progress | — | Dewey runs the script and approves. It is green on Sage's gate with every `scripts/test-*.sh`. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-14 end-to-end acceptance on a scratch root | — |
|
||||
| 228 | Row A: ZAI_API_KEY passes through ENV_ALLOW to sessions, README line, pass-through test (XS, Haiku high) | researcher; reviewers webby | #1729 | done | — | Webby approves the manifest. The mutant is killed. The seat suite and the cli suite are green on Sage's gate with every scripts/test-*.sh. (sage) | `docs/plans/2026-10-20_case2-rows.md` § Brief: row A, ZAI_API_KEY in the session env allowlist | Landed 86249ac55 (pushed 07:25Z) on 59f817c32: the 3 manifest paths from cf18c42b9. Patch-id b6ffe31feb0d equals the candidate's; modes and blobs match; verify-commit ok (3 paths). Sage's combined 228+238 gate on c515273db plus both rows' 6 paths, 07:11:30Z to 07:23:34Z: seat 165/0, cli 640/0, all ten scripts/test-*.sh 585/0. |
|
||||
| 229 | Row B: per-instance pi agent dir for Chet's Codex login, design only, starts after 10-27 (#428) | gosalyn; reviewers webby | #1730 | briefed | — | A live check, with Jason's or Mos's go, that two clients on one ChatGPT login don't revoke each other's refresh tokens. No build row starts before it passes. Held until after 10-27. (sage) | `docs/plans/2026-10-20_case2-rows.md` § Brief: row B, a per-instance pi agent dir for Chet's Codex login (#428) | — |
|
||||
| 229 | Row B: per-instance pi agent dir for Chet's Codex login, design only, starts after 10-27 (#428) | gosalyn; reviewers webby | #1730 | blocked (from briefed): superseded by the proxy route (Q253, mos-1615/1616): Chet's Codex login goes in through the P4 proxy page; the live check moved to row 209 phase B | — | A live check, with Jason's or Mos's go, that two clients on one ChatGPT login don't revoke each other's refresh tokens. No build row starts before it passes. Held until after 10-27. (sage) | `docs/plans/2026-10-20_case2-rows.md` § Brief: row B, a per-instance pi agent dir for Chet's Codex login (#428) | — |
|
||||
| 230 | Case 2 C2-13a unit render and host precheck (case2-unit.sh, case2-precheck.sh) | gosalyn; reviewers webby | #1732 | done | — | Webby approves the manifest. The test file and the cli suite are green on Sage's gate, along with every scripts/test-*.sh. A run on a host is a separate window with Jason's go. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-13a unit render and host precheck | Landed c8bc5cf4c on refactor (base 390ea5261), pushed. Patch-id f4b49eb68997 matches git diff 722136772..96768766c on the 5 manifest paths (manifest fbb0d7e42c67, Webby approve r2 rev 2563). packages/cli/README.md 3-way with row 199, hunks apart. Gosalyn gate on 96768766c: cli 541/0, scripts 429/0, mutants 10/10. Merged tree check: case2-unit 30/0, host 42/0. |
|
||||
| 231 | Case 2 C2-01b survey escapes, list item lines and attachment embeds (row 212 N1-N3) | gosalyn; reviewers webby | #1733 | done | 212 done | Webby approves the manifest. The library tests are green on Sage's gate, along with every scripts/test-*.sh. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-01b survey escapes, list item lines and attachment embeds | LANDED 29ce1e360 (sage gate 10:05:31-10:07:52Z GREEN on 62ddc96cc: library 45/0, every scripts/test-*.sh). verify-commit ok, 9 paths; patch-id 59b98b1b3e00 equals fefd54e13..f37a65857. Pushed. Webby N4 stays as restored (sage-1917), doc-only. |
|
||||
| 232 | Installer I1: stack-release external units and stack-copy bundle copies (MVP, Q187, Vikunja #432) | darkwing; reviewers filbert | #1734 | done | — | Filbert approves the manifest. The cli suite and every scripts/test-*.sh are green on Sage's gate, with the mutants killed. (sage) | `docs/plans/2026-10-20_installer-rows.md` § I1 stack-release external units and bundle copies | Landed e65a3ab4d on refactor (base 0444acd08), pushed. Patch-id 5adfbab9 matches git diff 8fede5fc6..da2da2f6c on the 9 manifest paths; tree entries (modes too) equal da2da2f6c, files pass manifest 7af3c943. Filbert approve r1 29829, r2 29865. Darkwing's landing gate on da2da2f6c: cli 593/0, scripts 429/0 (+156 queue node tests). Mutants 17/17. |
|
||||
@@ -291,9 +291,9 @@ Generated from `docs/plans/queue.json` revision 3945 by `queue render`. Do not e
|
||||
| 252 | Console inbox Approve and Deny for grant requests (#435, J2) | scrooge; reviewers webby | #1753 | done | — | Webby approves DESIGN.md then manifest; webui, bus, cli suites and every test-*.sh green on Sage's gate; DESIGN mutants killed; REQ-WEB-2 PRD amendment landed first (sage) | `docs/plans/2026-10-21_console-inbox-approve.md` § Gate | Landed 45ea3fa0d (replay of Scrooge 580037105 onto 30e6bb680, range-diff all =, 10 commits). Webby APPROVE c31229 rev 3612. Sage gate on 45ea3fa0d: every package suite 0 fail 0 skipped (bus 907, cli 943, webui 410), every scripts/test-*.sh rc 0, J1-J19 all killed except J11c and J18 (equivalent per BUILD.md), all restores match. Old-test numstat 1 1 vs fe4ee8c7b held. |
|
||||
| 253 | F27: case2-unit.sh and case1-accept.sh move to --tester-socket and refuse --tester-port with stack-release's migration wording; no .53/.54 copy with 196 until this lands (mos-1198 item 4) | gander; reviewers duckworth | #1758 | done | 196 done | reviewer approves DESIGN.md then the manifest; cli and webui suites whole and every scripts/test-*.sh on Sage's slot; mutants per DESIGN.md; static check covers scripts and tests (sage) | `docs/plans/2026-10-21_tester-socket-scripts.md` § Brief: case2-unit.sh and case1-accept.sh move to --tester-socket (F27) | Landed 48e450ce8 on refactor (fast-forward from aca16404c, 22 commits; landed sha = candidate, so range-diff and patch-id are identical by construction). Manifest 591020a1 (7 paths) rechecked against the commit: 0 mismatches. Gate: run 5 whole, cli 55 files, webui 58 files, all 10 scripts/test-*.sh green; M1-M40 killed 40/40. Duckworth APPROVE round 1, Gitea #1758 comment 30696. |
|
||||
| 254 | Library sync follow-up: client timeout, STATUS codes, README (222 deferrals, #1759) | megavolt; reviewers dewey | #1759 | done | 196 done | Dewey approves the manifest; bus, library and webui suites whole and every scripts/test-*.sh green on Sage's slot; the timeout and STATUS mutants killed (sage) | `docs/plans/2026-10-21_library-sync-followup.md` § Gate | Landed 331597709 (candidate b31300d79 blobs and modes on 41b0cf755; patch-id 96216216 equal, range-diff differs only in the message) plus doc eb9672c91 (Dewey N1 README sentence closed; N2 four 502 codes to DEFERRED, binding the Console library routes row). Merged-tree rerun on Sage's slot 23:44-23:55Z: library 77/0, bus 628/0, webui 305/0 with 1 skip, cli 749/0. Megavolt's gate megavolt-0102 covers scripts and both mutants. |
|
||||
| 255 | Bundled Pocket ID for users with no OIDC provider, design (Q203, #1760) | launchpad; reviewers webby | — | queued | 252 done | Webby approves DESIGN.md; design only, build rows follow after Sage checks it against Q203, O6, REQ-WEB-2 and REQ-INST-1 (sage) | `docs/plans/2026-10-21_bundled-pocket-id.md` § Gate | Vikunja 458, Gitea #1760, mos-1202 item 2. REQ-INST-2 lands in PRD 1.10 as post-v1 (mos-1204). Design only: no install, no download, no .53/.54, dragon-lin keeps Authentik. |
|
||||
| 255 | Bundled Pocket ID for users with no OIDC provider, design (Q203, #1760) | launchpad; reviewers webby | — | in-progress | 252 done | Webby approves DESIGN.md; design only, build rows follow after Sage checks it against Q203, O6, REQ-WEB-2 and REQ-INST-1 (sage) | `docs/plans/2026-10-21_bundled-pocket-id.md` § Gate | Vikunja 458, Gitea #1760, mos-1202 item 2. REQ-INST-2 lands in PRD 1.10 as post-v1 (mos-1204). Design only: no install, no download, no .53/.54, dragon-lin keeps Authentik. |
|
||||
| 256 | the human deletes a creative instance; any other actor refused, fire unchanged (REQ-COS-3, before the v1 tag) | honker; reviewers webby | #1761 | done | 194 done | Webby approves the manifest; touched test files whole plus business, bus, cli and webui suites and every scripts/test-*.sh green on Sage's slot; both mutants killed (sage) | `docs/plans/2026-10-21_creative-delete-human.md` § Brief: the human deletes a creative instance (REQ-COS-3, after row 194) | LANDED f12441d4f ff from 0165be266 (4 Honker commits, patch-id b28e6374). Webby APPROVE manifest-r3 01eb75aa (10 paths), request c30518. Gate 10:33-10:52Z: 4 touched files 31/0, 18 packages 3757/0 (bus 788, business 231, cli 832, webui 335), 10 scripts rc=0, mutants M1-M4b killed; skips named, env only (webui esbuild pin, test-queue root, test-task live x2). Overlap 13/257 clean. Lands before the 10-27 v1 tag. |
|
||||
| 257 | Q198 S1: pressure parser and pure rules evaluator (post-v1) | morgana; reviewers filbert | #1762 | in-review, round 2, request posted | — | Reviewer approves the manifest; touched test files whole plus the package suite green on Sage's slot; both brief mutants killed (post-v1, MVP keeps slot priority) (sage) | `docs/plans/2026-10-21_post-v1-row-briefs.md` § Brief: Q198 S1 pressure parser and pure rules evaluator | — |
|
||||
| 257 | Q198 S1: pressure parser and pure rules evaluator (post-v1) | morgana; reviewers filbert | #1762 | done | — | Reviewer approves the manifest; touched test files whole plus the package suite green on Sage's slot; both brief mutants killed (post-v1, MVP keeps slot priority) (sage) | `docs/plans/2026-10-21_post-v1-row-briefs.md` § Brief: Q198 S1 pressure parser and pure rules evaluator | Landed 73692e1bb, pushed 17:41:58Z 10-24: Morgana's 4 commits cherry-picked onto 487500a16, patches unchanged; 9 supervisor paths match Filbert r2 manifest b176a88f (APPROVE c30190, rev 3037). Gate RED 17:20Z (webui row278 sign-out timing, old test, row touches no webui), full rerun GREEN 17:41:11Z, cli skip FED R7 allowed. push-check clean. #1762 c31613, closed. Carry 447286192 lands doc-only. |
|
||||
| 258 | Email E01: mail PRD addendum draft and schemas (post-v1) | ludwig; reviewers della | #1763 | in-progress | — | Reviewer approves the manifest; the row's named tests whole plus the mail suite and touched suites green on Sage's slot; reviewer-named mutants killed (post-v1, MVP keeps slot priority) (sage) | `docs/plans/2026-10-21_post-v1-row-briefs.md` § Brief: E01 mail PRD addendum draft and schemas | — |
|
||||
| 259 | Email E03: mail ledger, state and quotas (post-v1) | unassigned | #1764 | queued | 258 done | Reviewer approves the manifest; the row's named tests whole plus the mail suite and touched suites green on Sage's slot; reviewer-named mutants killed (post-v1, MVP keeps slot priority) (sage) | `docs/plans/2026-10-21_post-v1-row-briefs.md` § Brief: E03 mail ledger, state and quotas | — |
|
||||
| 260 | Email E04: bounded MIME parsing and quarantine (post-v1) | unassigned | #1765 | queued | 258 done | Reviewer approves the manifest; the row's named tests whole plus the mail suite and touched suites green on Sage's slot; reviewer-named mutants killed (post-v1, MVP keeps slot priority) (sage) | `docs/plans/2026-10-21_post-v1-row-briefs.md` § Brief: E04 bounded MIME parsing and quarantine | — |
|
||||
@@ -302,8 +302,8 @@ Generated from `docs/plans/queue.json` revision 3945 by `queue render`. Do not e
|
||||
| 263 | Email E07: address and rule evaluator (post-v1) | unassigned | #1768 | queued | 258 done, 259 done, 260 done | Reviewer approves the manifest; the row's named tests whole plus the mail suite and touched suites green on Sage's slot; reviewer-named mutants killed (post-v1, MVP keeps slot priority) (sage) | `docs/plans/2026-10-21_post-v1-row-briefs.md` § Brief: E07 address and rule evaluator | — |
|
||||
| 264 | T1 item 7: independent sessions, compaction counts and clear context | gizmoduck; reviewers duckworth | #1769 | done | — | The named reviewer approves the manifest. The design's T1-T7 acceptance tests run whole plus every touched suite on Sage's slot; T3 waits on Vikunja 466 (N2, Claude's compaction count format and the managed dataRoot reader). The design's section 6 mutants are killed. (sage) | `docs/plans/2026-10-21_t1-sessions.md` § T1 item 7: independent sessions, compaction counts and clear context | LANDED 84f53540d ff on e479521d3 14:18:23Z, 21 commits = gizmoduck/row264-r13 tip (no rewrite, range-diff identity). Manifest 257408e9 approved Duckworth rev 3214 (c30640). Gate r13 2cc34aef8: 20 files, bus 827, cli 837, webui 345/1 skip, 10 shells; M1-M4 assertion kills (mos-1279 B, M2 4 files). Overlap none (13, 257). N1 actor_run binds row 269; N2 esbuild skip later gate (sage-2695). |
|
||||
| 265 | Case 2 C2-09b rooms: room.open, room.send with @tags, room.read | goldie; reviewers boyd | #1770 | done | 219 done | Boyd approves the manifest. The brief's tests run whole plus the bus suite and every touched suite on Sage's slot. Grep for hash pins on changed files before in-review. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-09b rooms: room.open, room.send with @tags, room.read | LANDED 200dd396c (cherry-pick of ef4c93853, 50 blobs equal, log appends equal) 05:13Z on full gate 04:57-05:12Z: all package suites except queue 0 fail 0 skip (bus 957, cli 986, seat 218), every scripts/test-*.sh green. Boyd c31501 incl mos-1567 mount read. 22 gzip logs scanned decompressed, clean. #1770 closed c31510. Bundle 02c3c286. |
|
||||
| 266 | Case 2 C2-10c Console room view: merged timeline and @name completion | researcher; reviewers dewey | #1771 | queued | 225 done, 265 done | Dewey approves the manifest. The webui suite is green on Sage's gate, along with every touched suite. Grep for hash pins on changed files before in-review. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-10c Console room view: merged timeline and @name completion | Haiku high subagent under decision 129. |
|
||||
| 267 | Case 2 C2-15 hybrid universes: exclusions, pins and the end-to-end crossover | morgana; reviewers filbert | #1772 | queued | 216 done, 217 done, 224 done | Filbert approves the manifest. The brief's tests and the end-to-end crossover run whole plus every touched suite on Sage's slot. Grep for hash pins on changed files before in-review. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-15 hybrid universes: exclusions, pins and the end-to-end crossover | R8 accepted (sage-2218). Webby's R8 noise note (gosalyn-0127) is for the builder. |
|
||||
| 266 | Case 2 C2-10c Console room view: merged timeline and @name completion | fethry; reviewers boyd, dewey | #1771 | done | 225 done, 265 done | Dewey approves the manifest. The webui suite is green on Sage's gate, along with every touched suite. Grep for hash pins on changed files before in-review. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-10c Console room view: merged timeline and @name completion | LANDED 3e5041b43 18:00:49Z 10-24, patch-ids equal to Fethry b8b26ae4d..6418ec063; gate GREEN 18:00:08Z first run (bus 1000/0, webui 458/0, cli 989+1 FED R7 allowed, 12 scripts rc 0); Boyd c31609, Dewey c31610; #1771 c31615 closed; Dewey N2 T9 race goes to Mos |
|
||||
| 267 | Case 2 C2-15 hybrid universes: exclusions, pins and the end-to-end crossover | morgana; reviewers filbert | #1772 | in-progress | 216 done, 217 done, 224 done | Filbert approves the manifest. The brief's tests and the end-to-end crossover run whole plus every touched suite on Sage's slot. Grep for hash pins on changed files before in-review. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-15 hybrid universes: exclusions, pins and the end-to-end crossover | R8 accepted (sage-2218). Webby's R8 noise note (gosalyn-0127) is for the builder. |
|
||||
| 268 | Case 2 C2-01c playground levels: universe-level prefixes and draft universes | gizmoduck; reviewers webby | #1773 | done | — | Webby approves the manifest. The brief's tests run whole plus the library suite and every touched suite on Sage's slot; the brief's gate grep over packages and docs/case2 finds no library-playground-outside-book. Grep for hash pins on changed files before in-review. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-01c playground levels: universe-level prefixes and draft universes | Landed c27207f6e fast-forward on ce6a96ad6 (1 commit, 9 paths, digest caa0fa4e). r4 is a carry of r3 aca53c4f0: range-diff =, patch-id 2942acc8 equal, blobs equal. Webby APPROVE round 2 on ecd9b35eb stands; carries webby-0112 (r3) and webby-0113 (r4, notes 34e1ab2bf). Gate: Gizmoduck r4 rerun brief 14/14, library 83/83, business 209/209, 0 skips; gate grep empty. 194 rebases next (business.test.mjs). |
|
||||
| 269 | 264b T1 item 7: per-session native store, workspace and single-writer fence | gizmoduck; reviewers duckworth | #1774 | done | 264 done | Duckworth approves this slice's manifest. Its design tests run whole plus every touched suite on Sage's slot, and its mutants are killed (RULINGS Q1). Tests T1 run half, T2 workspace and path mutants; whichever of 191 and 264b lands second wires 191's admission checks (Q5). (sage) | `docs/plans/2026-10-21_t1-sessions.md` § T1 item 7: independent sessions, compaction counts and clear context | Landed efcc9ea8d fast-forward on 94c33a43c (13 commits, 12 paths, manifest 455c12ee). r3 is a carry of r2 aafcc857c, range-diff = (Duckworth 0194, c30756, rev 3307). Gate r3 18:37-18:50Z all green, 0 skips: bus 834, seat 172, cli 869, case2-unit 43, singles 38. M1-M12 kills carry. Re-pin needs the Console restart by Jason or Mos right after the host. A 264a rollback refuses a v2 sessions.json, see BUILD.md Rollback. |
|
||||
| 270 | 264c T1 item 7: compaction count, exact for Pi | gizmoduck; reviewers duckworth | #1775 | done | 269 done | Duckworth approves this slice's manifest. Its design tests run whole plus every touched suite on Sage's slot, and its mutants are killed (RULINGS Q1). Test T3 Pi half; Claude shows unknown with the Vikunja 466 reason (Q6). (sage) | `docs/plans/2026-10-21_t1-sessions.md` § T1 item 7: independent sessions, compaction counts and clear context | LANDED 7328da8ca (with 271, mos-1351) 02:13Z 10-23 on 767bb62c7: 33 commits cherry-picked from gizmoduck/row270-271-r4 49cee846e (base 25c09f19f), range-diff all '=', 40 paths identical to 49cee846e. Manifest f4174458 (15 paths) matches the tip. Duckworth APPROVE c30930 rev 3389. C2 run 5 GREEN on 53406f3e4: bus 873, seat 202, cli 905, ten scripts, 38/38 mutants killed. #1775 closes. |
|
||||
@@ -320,13 +320,13 @@ Generated from `docs/plans/queue.json` revision 3945 by `queue render`. Do not e
|
||||
| 281 | A fire or a delete revokes the instance's host and Gitea grants (194/236 follow-up, MVP, mos-1271) | megavolt; reviewers dewey | #1786 | done | 236 done | Dewey approves the design, then the manifest. Bus, business, cli and every touched test file run whole, plus the Docker gitea-grant test and every scripts/test-*.sh, green on Sage's gate. M1-M4 killed. Lands before .53 Case 1 hires a granted instance. Red goes to Sage, then Mos. (sage) | `docs/plans/2026-10-22_fire-revokes-grants.md` § Brief: no grant outlives its instance | LANDED e479521d3 ff on 385a7194c (17 commits, manifest b73d4c81). Slot on 7979fb41e green: bus 819, business 231, cli 837, dewey-bus 76 with gitea-grant-docker run, shells green under 3x limits, M1-M22 killed. M1 hang fixed in b4a (mos-1273). Skips: test-task row 244 live-provider pair, test-queue canonical root. DEFERRED: N1 host-unknown hint verb, N2 fire tool text, to the follow-up row. Dewey APPROVE c30614. |
|
||||
| 282 | PRD REQ-LIB-6 rewritten to Q223 and Q226 (mos-1320 item 8) | gosalyn; reviewers webby | #1787 | done | — | Webby approves against the ruling. requirements.test.mjs and every scripts/test-*.sh that reads the PRD or requirements.json are green on Sage's gate. Jason gets a report. (sage) | `docs/plans/2026-10-20_case2-rows.md` § PRD REQ-LIB-6 rewritten to Q223 and Q226 (mos-1320 item 8) | Landed 647424442 on 86a665bdf: 1841f7d4e and 6b5b06819 rebased, patch-ids equal (4e50b4b6, 16a7a02f), range-diff =, tree 4f30ed10a = Gosalyn's gated trial tree. Webby APPROVE rev 3308 c30764 on 6b5b06819. Gate 19:06Z on the tip tree: bus+tasks requirements and tasks verbs 37/0/0, 0 skips; no scripts/test-*.sh reads the PRD (control ok). PRD 1.15. 1.16 is row 291, waits for Jason. |
|
||||
| 283 | Case 2 C2-01d supporting folders, the supporting scope, the editor field and supportingPath (M12) | honker; reviewers webby | #1788 | done | 268 done, 282 done | Webby approves the manifest. The library and business suites are green on Sage's gate, along with every scripts/test-*.sh. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-01d supporting folders, the supporting scope, the editor field and supportingPath (M12) | LANDED 8d2856ee3 (replay of 0bf308dba onto 59226f878, 13 patch-ids equal) plus DEFERRED N1 93694c518. Webby APPROVE r1 c31338 rev 3677, r2 c31342 rev 3683 (mos-1528 G1 mapping.test:52). Sage full gate GREEN 20:37:16Z: all package suites but queue plus every scripts/test-*.sh, 0 fail, library 98/0, webui npm ci, editor build required. supporting.test first-run red placed (mos-1272, 54d9e07bb). #1788 closed c31358. Live unchanged 45dca69f6. |
|
||||
| 284 | Case 2 C2-05c the supporting scope and blob in the lookups | della; reviewers dewey | #1789 | briefed | 224 done, 283 done | Dewey approves the manifest. Library, bus and harness suites and every scripts/test-*.sh green on Sage's gate. Grep packages/*/tests for the scope enum pin and ['canon', 'playground'] before in-review; update each. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-05c the supporting scope and blob in the lookups (sage-2833) | — |
|
||||
| 284 | Case 2 C2-05c the supporting scope and blob in the lookups | della; reviewers webby | #1789 | done | 224 done, 283 done | Dewey approves the manifest. Library, bus and harness suites and every scripts/test-*.sh green on Sage's gate. Grep packages/*/tests for the scope enum pin and ['canon', 'playground'] before in-review; update each. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-05c the supporting scope and blob in the lookups (sage-2833) | LANDED ce0b6ed41 (fast-forward of Della r4 on 9e2689dff), pushed 00:09:52Z 10-25. Sage gate GREEN 00:09:04Z on ce0b6ed41: every package suite but queue (cli 999/0 + allowed FED R7 skip) and every scripts/test-*.sh rc 0. Webby APPROVE r2 c31654 rev 4070 on manifest-r4 de505cfd; landed tree matches. Della whole-file runs 51/0. #1789 closed with c31655. |
|
||||
| 285 | Case 2 C2-08b role changes for agent writes and the chief's read grant | magica; reviewers poe, webby | #1790 | done | 213 done, 291 done | Webby approves the manifest. Business suite, test-config.sh and every scripts/test-*.sh green on Sage's gate. Grep for CREATIVE_KINDS and 64-hex pins of changed role files. Sage checks it against mos-1309 item 5. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-08b role changes for agent writes and the chief's read grant (mos-1309 item 5) | LANDED 1f3d0350f 13:33:42Z: candidate 2e4503dc7 (14 commits) cherry-picked onto 25874bc86. Logs kept both sides; otherwise the tree equals the candidate except on 7 base paths. Poe c31568 rev 3919, Webby c31569 rev 3920. Sage gate GREEN 13:28:46Z with its own npm ci: 4236 package tests, 0 fail, 1 allowed FED R7 skip; 12 scripts rc 0. No CREATIVE_KINDS, no role-file hash pins. Roles match mos-1309 item 5. 286 rebases as r5. |
|
||||
| 286 | Case 2 C2-03b push and per-seat credentials for the library mirror (with R4, mos-1323) | rockerduck; reviewers boyd, dewey | #1791 | done | 222 done | Dewey approves the manifest. Library and bus suites and every scripts/test-*.sh green on Sage's gate, mutant killed. A search of the run output for the fixture token finds nothing. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-03b push and per-seat credentials for the library mirror | LANDED 5d7801dc1 14:37:02Z: r6 75f6d56b1 (19 commits) picked onto d55944edb; logs kept both sides, code equals the candidate. Boyd c31587 rev 3942, Dewey c31588 rev 3943 (r2 c31584/c31585). Sage gate GREEN 14:36:42Z, own npm ci: 4251 tests, 0 fail, 1 allowed FED R7 skip; 12 scripts rc 0; fixture values in 0 of 29 outputs; B285-M1 kills T7/T9. r6 shortened two fixtures after push-check STOP secrets (sage-4112). Chief seed per sage-4100. |
|
||||
| 287 | Case 2 C2-21 the grant executor for a library project | megavolt; reviewers dewey | #1792 | briefed | 226 done, 285 done | Dewey approves the manifest. Bus suite, Gitea Docker test, install test and every scripts/test-*.sh green on Sage's gate. A search of the run output for the fixture admin and seat tokens finds nothing. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-21 the grant executor for a library project | — |
|
||||
| 288 | Case 2 C2-02 agent writes, the notice, revert and her Console saves | bubba; reviewers webby | #1793 | briefed | 215 done, 282 done, 283 done, 284 done, 285 done, 286 done | Webby approves the manifest. Library, bus and harness suites and every scripts/test-*.sh green on Sage's gate, mutants killed. A search of the run output for the fixture tokens finds nothing. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-02 agent writes, the notice, revert and her Console saves | A2 revert contract (morgana-0199, sage-3596): library.revert is a human verb. Args {project, commit}, strict keys; project is the business.projects key (the chat repo link), not a UUID. Result {project, path, reverted, commit}. Refusals: 409 stale-base, and 409 library-revert-not-agent for an agent caller. Owner Bubba under Q245 (mos-1506). |
|
||||
| 287 | Case 2 C2-21 the grant executor for a library project | steelbeak; reviewers boyd, dewey | #1792 | done | 226 done, 285 done | Dewey approves the manifest. Bus suite, Gitea Docker test, install test and every scripts/test-*.sh green on Sage's gate. A search of the run output for the fixture admin and seat tokens finds nothing. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-21 the grant executor for a library project | LANDED 0e935776e 16:12:35Z 10-24 (cand c2338ed58 + a5370b198 on 9b6345466). Boyd APPROVE c31602 rev 3967, Dewey APPROVE c31603 rev 3968. Sage gate GREEN 16:11:38Z: bus 998/0 (Gitea Docker F-A/F-B + X-G3, minted 4 hits 0), business 283/0, cli 989 +1 allowed FED R7 skip, webui 442/0, 12 scripts rc 0. F-C negative record-only follow-up. Dewey N1-N3 non-blocking. #1792 closed c31606. No P19 task. |
|
||||
| 288 | Case 2 C2-02 agent writes, the notice, revert and her Console saves | bubba; reviewers webby | #1793 | in-progress | 215 done, 282 done, 283 done, 284 done, 285 done, 286 done | Webby approves the manifest. Library, bus and harness suites and every scripts/test-*.sh green on Sage's gate, mutants killed. A search of the run output for the fixture tokens finds nothing. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-02 agent writes, the notice, revert and her Console saves | A2 revert contract (morgana-0199, sage-3596): library.revert is a human verb. Args {project, commit}, strict keys; project is the business.projects key (the chat repo link), not a UUID. Result {project, path, reverted, commit}. Refusals: 409 stale-base, and 409 library-revert-not-agent for an agent caller. Owner Bubba under Q245 (mos-1506). |
|
||||
| 289 | Case 2 C2-11b Console library pages and her saves (Haiku subagent, decision 129) | researcher; reviewers filbert | #1794 | briefed | 214 done, 288 done | Filbert approves the manifest. The webui suite and every scripts/test-*.sh are green on Sage's gate. Grep for hash pins on bus.js and serve.mjs before in-review. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-11b Console library pages and her saves | — |
|
||||
| 290 | Case 2 C2-12b the setup sheet rewrite for free chat, supporting folders and saves | louie; reviewers webby | #1795 | briefed | 217 done, 218 done, 285 done, 291 done | Doc only. Webby approves it against the ruling. Before landing, grep packages/*/tests and scripts/test-*.sh to confirm no test reads the file. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-12b the setup sheet rewrite for free chat, supporting folders and saves | — |
|
||||
| 290 | Case 2 C2-12b the setup sheet rewrite for free chat, supporting folders and saves | louie; reviewers webby | #1795 | done | 217 done, 218 done, 285 done, 291 done | Doc only. Webby approves it against the ruling. Before landing, grep packages/*/tests and scripts/test-*.sh to confirm no test reads the file. (sage) | `docs/plans/2026-10-20_case2-rows.md` § C2-12b the setup sheet rewrite for free chat, supporting folders and saves | LANDED 3d7dff345 on refactor, pushed 14:55:11Z: cherry-pick of 963303403..22510988d onto 18334d713, four commits equal by patch-id and range-diff, SETUP-SHEET.md blob 37b451c6 as approved. Gate per brief (doc only): Webby approve c31596 rev 3954; grep of packages/*/tests, scripts/test-*.sh and tests/ for SETUP-SHEET finds nothing (positive control hits). No suite run: no test reads the file (decision 137). #1795 closed c31597. |
|
||||
| 291 | PRD 1.16 library.write routes under REQ-LIB-6 (mos-1328) | gosalyn; reviewers webby | #1796 | done | 282 done | Webby approves the text. Jason says yes to the exact text (Mos asks him, mos-1328 step 3); no landing before that. requirements.test.mjs and every scripts/test-*.sh that reads the PRD or requirements.json are green on Sage's gate. Mos gets the landing commit. (sage) | `docs/plans/2026-10-22_prd-1-16-brief.md` § PRD 1.16 library.write routes under REQ-LIB-6 (mos-1328) | Landed 4874d1e83 on e909ef51a: 482e865ac replayed, patch-id equal (cef7de74), range-diff =. Webby APPROVE c30848 on 482e865ac; Jason approved the text in Q229. Gate 16:15Z on the tip tree: every package suite but queue, 0 fail 0 skipped (tasks 100, bus 891, cli 941, plugins 119, webui 392, business 231), every scripts/test-*.sh rc 0 (queue-root and row 244 skips only). PRD 1.16. 1.17 is row 308. |
|
||||
| 292 | stack-release.sh config_checks runs the target loader on any config (row 270 rollback hazard) | gizmoduck; reviewers duckworth | #1797 | done | 203 done, 270 done, 271 done | Duckworth approves the manifest. The touched test files run whole, the cli suite and every scripts/test-*.sh are green on Sage's gate, and the mutants are killed. (sage) | `docs/plans/2026-10-22_config-checks-any-key-brief.md` § stack-release.sh config_checks runs the target loader on any config (row 270 rollback hazard) | Landed 6aab979e6 (cherry-pick of c902a767d..90be6cccd, range-diff all =, patch-id a45c9ba4 equal). Tested head 0d0021454: stack-release.test 224/224, cli suite r2 red only compactions-launch:229 session-invalid 22 (idle-stop race, Vikunja 588, row 302), r3 rerun 910/910 under mos-1411, ten shells green, M1-M9 killed. Duckworth APPROVE rev 3433 on 2fa7ae17. |
|
||||
| 293 | 574: maintenance-free test fixture commits (Vikunja 574) | gander; reviewers filbert | #1805 | done | — | Filbert approves. The four whole files, then the seat and cli suites, are green on Sage's gate. (sage) | `docs/plans/2026-10-23_mvp-readiness-rows.md` § Brief: 574, maintenance-free test fixture commits (Vikunja 574) | LANDED e51d11640 03:55Z 10-23 (cherry-pick of gander b23783f39..a9cae2bd6 onto 464010fbe; range-diff 6/6 equal, range patch-id equal). Filbert APPROVE c30982 cdda41f5; run 2 4 files 153/0, seat 202/0, cli 905/0, 312 flagged/0 maintenance children. N1: lifecycle.test needs TMPDIR of 50 bytes or less. Residual: queue store.mjs, discord git.mjs, harness tools.mjs unflagged. #1805 closed c31013, P19 574 c888. |
|
||||
@@ -346,7 +346,7 @@ Generated from `docs/plans/queue.json` revision 3945 by `queue render`. Do not e
|
||||
| 307 | Row 270's pi compaction reading moves behind the harness kind (REQ-PLUG-2, Vikunja 598) | gizmoduck; reviewers duckworth | #1814 | done | — | Duckworth approves the design, then the manifest; bus, cli, plugins (0 failures), webui and business suites, every scripts/test-*.sh green and the mutants killed on Sage's gate (sage) | `docs/plans/2026-10-23_harness-kind-compactions.md` § Brief: row 270's pi compaction reading moves behind the harness kind (Vikunja 598) | LANDED d243f6b25: 6 row commits replayed onto 8dc132bec, every non-log patch-id equal, candidate paths = 6fdfe3790 (manifest 17c9f8d9). Duckworth APPROVE rev 3586 c31189 round 1, C2 met. Sage gate: bus, cli 0 skipped, plugins fully green incl harness.test.mjs:192, webui, business, seat, every scripts/test-*.sh; M1-M4 killed. P19 598 commented. DEFERRED: 307 N1 store-unreadable not sticky. N3 doc-only BUILD.md red list one short, next BUILD.md change. |
|
||||
| 308 | PRD 1.17 Case 2 story files are DOCX (Q235 to Q237, Q239) | gosalyn; reviewers webby | #1815 | done | 291 done | Webby checks the PRD diff against DRAFT-d9.md at 4607e15b8 one instruction at a time and that nothing else changed. No new Jason question (Q239 approved the text). tasks whole, bus whole, cli stack-copy.test and every scripts/test-*.sh green on Sage's gate. Mos gets the landing commit (mos-1470). (sage) | `docs/plans/2026-10-23_prd-1-17-brief.md` § PRD 1.17 Case 2 story files are DOCX (Q235 to Q237, Q239) | Landed 30e6bb680: Gosalyn 45fe7b3ce replayed onto 7defb58e9, patch-id 4658c831 equal, range-diff =, four blobs equal. Webby r1 APPROVE c31224 rev 3606, d9 at 4607e15b8 applied word for word. Sage gate 17:19Z: every package suite 0 fail 0 skipped (tasks 100, bus 894, cli 942, plugins 119, webui 392), every scripts/test-*.sh rc 0. Mos gets the sha (mos-1470). 570/571 build rows next. |
|
||||
| 309 | 571 W1: reviewed local thesaurus data (post-10-27) | glomgold; reviewers boyd, duckworth | #1823 | in-review, round 1, request posted | — | Independent Opus 5.5 reviewer, not the author, approves the manifest; the brief section's Gate and G1 pass on Sage's slot: touched test files whole, affected package suites green, named mutants killed. Post-10-27; MVP rows keep slot priority (sage) | `docs/plans/2026-10-21_q195-writing-editor.md` § W1 reviewed local thesaurus data | — |
|
||||
| 310 | 571 W2: WordCraft source import and reproducible restricted web build (post-10-27) | gyro; reviewers filbert, gladstone | #1824 | in-progress | — | Independent Opus 5.5 reviewer, not the author, approves the manifest; the brief section's Gate and G1 pass on Sage's slot: touched test files whole, affected package suites green, named mutants killed. Post-10-27; MVP rows keep slot priority (sage) | `docs/plans/2026-10-21_q195-writing-editor.md` § W2 WordCraft source import and reproducible restricted web build | — |
|
||||
| 310 | 571 W2: WordCraft source import and reproducible restricted web build (post-10-27) | gyro; reviewers filbert, gladstone | #1824 | in-progress | — | Independent Opus 5.5 reviewer, not the author, approves the manifest; the brief section's Gate and G1 pass on Sage's slot: touched test files whole, affected package suites green, named mutants killed. Post-10-27; MVP rows keep slot priority (sage) | `docs/plans/2026-10-21_q195-writing-editor.md` § W2 WordCraft source import and reproducible restricted web build | Q48 (mos-1606): W3C terms accepted for cursor-icon 1.2.0 and winit 0.30.13 only; S0 general list not widened; any other W3C occurrence comes back. W2 lands after its gate. Vikunja 621 closed. |
|
||||
| 311 | 571 W3a: bus pins and human-only editor settings (post-10-27) | unassigned | — | queued | — | Independent Opus 5.5 reviewer, not the author, approves the manifest; the brief section's Gate and G1 pass on Sage's slot: touched test files whole, affected package suites green, named mutants killed. Post-10-27; MVP rows keep slot priority (sage) | `docs/plans/2026-10-21_q195-writing-editor.md` § W3a bus pins and human-only editor settings | — |
|
||||
| 312 | 571 W3b: human DOCX store and instant commits (post-10-27) | unassigned | — | queued | 311 done | Independent Opus 5.5 reviewer, not the author, approves the manifest; the brief section's Gate and G1 pass on Sage's slot: touched test files whole, affected package suites green, named mutants killed. Post-10-27; MVP rows keep slot priority (sage) | `docs/plans/2026-10-21_q195-writing-editor.md` § W3b human DOCX store and instant commits | — |
|
||||
| 313 | 571 W6: owned browser bridge and editor-only route (post-10-27) | unassigned | — | queued | 309 done, 310 done, 312 done | Independent Opus 5.5 reviewer, not the author, approves the manifest; the brief section's Gate and G1 pass on Sage's slot: touched test files whole, affected package suites green, named mutants killed. Post-10-27; MVP rows keep slot priority (sage) | `docs/plans/2026-10-21_q195-writing-editor.md` § W6 owned browser bridge and editor-only route | — |
|
||||
@@ -364,6 +364,13 @@ Generated from `docs/plans/queue.json` revision 3945 by `queue render`. Do not e
|
||||
| 325 | Case 1 business file: re-key project to stack to match .mosaic/project.json, plus a project-file test (#414 stage 2, ops-0288, mos-1563) | goldie; reviewers gladstone | #1821 | done | — | New test file and packages/business whole on CLEAR; one key mutant killed; Gladstone review; Sage full landing gate (mos-1455) (sage) | `docs/plans/2026-10-24_case1-project-key-brief.md` § Brief: re-key the Case 1 project to stack | LANDED c5f96836d (ff from 99930362e), tip 3d2569ce2. Gladstone approve c31484 rev 3788 on c5f96836d. Sage gate green 01:31Z on c5f96836d: all package suites 0 fail (business 264, cli 986), every scripts/test-*.sh rc 0. Project key is now stack, matching .mosaic/project.json; new case1-project-key test checks the real project file. Old-test line :70 under mos-1564. |
|
||||
| 326 | Host run sheet: five operator gaps (B2-2 proof format, 323 N2, pre-install key check, failed-first-install retry, backup SHA256SUMS form) | goldie; reviewers gladstone | #1822 | done | — | Gladstone approves the manifest; every new claim cites its line; no test reads the sheet; Sage's full landing gate green (sage) | `docs/plans/2026-10-24_run-sheet-doc-brief.md` § Brief: five run-sheet gaps | LANDED 33f49f7d5 (cherry-pick of a1b13c60e, patch-id match, sheet e4c14516) in f58049de0 with row 208 on one full gate 04:36-04:51Z, all suites green. Gladstone c31489. #1822 closed c31507. B2-2 closes in DEFERRED. Bundle 9fc7754a. |
|
||||
| 327 | Push check in the repository: scripts/push-check.sh passes a binary only when an approved review candidate lists its path and sha256, plus scripts/test-push-check.sh (#1825, mos-1572 A) | bradford; reviewers dewey, poe | #1825 | done | — | Poe gives the first Codex review, Dewey reviews the landing candidate; scripts/test-push-check.sh and every other scripts/test-*.sh green on Sage's gate; the mutants killed; Sage's next push runs through scripts/push-check.sh (sage) | `docs/plans/2026-10-24_push-guard-binary-manifest.md` § Brief: push-check.sh passes a binary only when the reviewed candidate lists its path and sha256 | LANDED 68c08b4e7 (pushed 07:18:03Z 10-24): 3 commits on 6a5e12511, blobs equal round 3 d858c9f8b; Poe c31525 rev 3882, Dewey c31526 rev 3883; gate GREEN 07:15:49Z with its own npm ci (first run red on empty canonical node_modules, sage-4023); 6 push-check mutants KILLED; next push 42ba0f5bc ran through scripts/push-check.sh --fetch, PUSH_READY; #1825 closed c31530. |
|
||||
| 328 | T9 library-credential test: the second broker start passes Node's TIMEOUT_MAX interval so no timer tick overlaps the verb sync; mutant fails a 50-run stress loop (#1826, Vikunja 622, mos-1594) | fethry; reviewers boyd, dewey | #1826 | done | — | Boyd gives the first Codex review, Dewey reviews the landing candidate; touched tests run whole, the 50-run stress loop passes with the fix and M1 fails it; bus and every scripts/test-*.sh green on Sage's gate (sage) | `docs/plans/2026-10-24_t9-library-sync-race.md` § Brief: the T9 verb sync on the second start runs with no timer tick able to overlap it | LANDED 8bb5b3c73 19:40Z 10-24 (8 Fethry commits on 5e77cdd09). Gate GREEN 19:38:54Z on 8bb5b3c73, no drift. Boyd APPROVE c31621, Dewey APPROVE c31622. #1826 closed c31625; Vikunja 622 done. |
|
||||
| 329 | Model proxy P1: model-proxy package, pinned fetch with sha256 refusal, mosaic proxy init, proxy unit (237, mos-1600) | magica; reviewers boyd, dewey | #1827 | done | — | Boyd first review, re-measuring both release hashes; Dewey landing review; BUILD.md has the acceptance output. Sage's landing gate: every package suite but queue plus every scripts/test-*.sh green, touched test files whole, refusals each tested, named mutants killed (brief Gate). (sage) | `docs/plans/2026-10-24_model-proxy-rows.md` § Brief: P1 the model-proxy package, pinned fetch, proxy init and the proxy unit | Landed 61ebf2c34 (pushed 23:31:27Z 10-24); Magica r2 commits cherry-picked onto 669cdf42c. Boyd c31642 rev 4048, Dewey c31643 rev 4047. Sage fresh gate GREEN 23:29:14Z (mos-1634). #1827 closed c31650; Vikunja 237 comment 1109, stays open for P2-P7. DEFERRED: N2, R2-N1 to row 331; N1 to P7. |
|
||||
| 330 | Model proxy P4: Console proxy page (OAuth sign-in, API keys, priority, key list, usage) via bus verbs (Q250, mos-1606/1608) | poe; reviewers filbert, gladstone | #1828 | in-progress | — | Gladstone first review; Filbert landing review; starts now, lands after P1 rebased on it; webui with MOSAIC_REQUIRE_EDITOR_BUILD=1. Sage gate: all package suites but queue and every scripts/test-*.sh green; brief Gate. (sage) | `docs/plans/2026-10-24_proxy-page-brief.md` § Brief: P4 the Console proxy page | — |
|
||||
| 331 | Model proxy P2: per-agent model keys, reconcile and launch preflight (237, mos-1600) | magica; reviewers boyd, dewey | #1829 | in-progress | 329 done | Boyd first review; Dewey landing review; three named mutants killed. Sage gate: all package suites but queue and every scripts/test-*.sh green; brief Gate. (sage) | `docs/plans/2026-10-24_model-proxy-rows.md` § Brief: P2 per-agent model keys, reconcile and the launch preflight | P2 input from magica-0020 (acceptance-probe-4): 8.0.42 revocation lags ~105ms after v8 PUT (first call 200, then 401); reconcile/revoke must poll to 401, not assume instant. Per-key model objects give 422; no per-key model restriction. |
|
||||
| 332 | Model proxy P3: harness config from the proxy (237, mos-1600) | fethry; reviewers dewey, gladstone | #1830 | in-progress | — | Gladstone first review; Dewey landing review; named mutant killed. Sage gate: all package suites but queue and every scripts/test-*.sh green; brief Gate. (sage) | `docs/plans/2026-10-24_model-proxy-rows.md` § Brief: P3 harness config from the proxy | mos-1616: amendment docs/plans/2026-10-24_p3-pi-routes-amendment.md (blob 079debd5605c, c8a9bcf94) replaces P3 item 4's non-Anthropic line and adds tests and a mutant. Starts now on a new Codex thread against P2's {baseUrl, key}; lands only after 329 and 331 land and its own gate (mos-1351). |
|
||||
| 333 | Model proxy P5: usage plug-in and per-key limits, per-key count only (237, mos-1600) | sage; reviewers boyd, duckworth | #1831 | briefed | 331 done | Boyd first review; Dewey landing review; named mutant killed. Sage gate: all package suites but queue and every scripts/test-*.sh green; brief Gate. (sage) | `docs/plans/2026-10-24_model-proxy-rows.md` § Brief: P5 usage plug-in and per-key limits | — |
|
||||
| 334 | Case 2 proxy unit: case2-unit.sh renders P1's mosaic-proxy.service and the bus Wants/After under --proxy (237, mos-1616) | rockerduck; reviewers boyd, webby | #1832 | in-progress | 329 done | Codex builder after 329 lands; Boyd first review, Webby Claude review; run list from imports, case1-accept off; mutants: bus loses After= under --proxy, proxy ExecStart skips run.mjs; Sage landing gate: every package suite but queue, every scripts/test-*.sh (sage) | `docs/plans/2026-10-24_case2-proxy-unit-brief.md` § Brief: Case 2 proxy unit in case2-unit.sh and case2-install.sh | — |
|
||||
|
||||
<!-- mosaic-queue:end -->
|
||||
|
||||
|
||||
+4832
-90
File diff suppressed because it is too large.
Load diff
@@ -105,7 +105,7 @@ export const PROJECT_FILE_VERBS = Object.freeze(['project.files', 'project.file'
|
||||
// here also makes server.mjs await their host effects instead of serializing a Promise as {}.
|
||||
const LIBRARY_LOOKUPS = Object.freeze({
|
||||
'library.find': { method: 'find', fields: ['universe', 'query', 'type', 'book', 'scope', 'offset'], required: ['universe', 'query'] },
|
||||
'library.get': { method: 'get', fields: ['universe', 'path', 'from', 'links_from'], required: ['universe', 'path'] },
|
||||
'library.get': { method: 'get', fields: ['universe', 'path', 'scope', 'from', 'links_from'], required: ['universe', 'path'] },
|
||||
'library.search': { method: 'search', fields: ['universe', 'text', 'book', 'scope', 'offset'], required: ['universe', 'text'] },
|
||||
'library.manuscript': { method: 'manuscript', fields: ['universe', 'book', 'scope', 'chapter', 'from', 'to'], required: ['universe', 'book'] },
|
||||
'library.universe': { method: 'universeInfo', fields: ['universe'], required: ['universe'] },
|
||||
|
||||
@@ -27,8 +27,8 @@ const TEXTS = {
|
||||
'Second World/Characters/Elsewhere.md': note('character', 'Elsewhere', 'Other ferry.'),
|
||||
};
|
||||
|
||||
async function world(t, { projects, adapter, claimed = true, now = () => NOW } = {}) {
|
||||
const f = scratchRepo(t, TEXTS), dataRoot = join(f.root, 'data');
|
||||
async function world(t, { projects, adapter, claimed = true, now = () => NOW, files = TEXTS } = {}) {
|
||||
const f = scratchRepo(t, files), dataRoot = join(f.root, 'data');
|
||||
mkdirSync(dataRoot);
|
||||
const business = { id: 'acme', human: 'jason', vars: { 'bus.tester': true },
|
||||
projects: projects ?? { books: mappingEntry() }, arbiters: { technical: 'coder', delivery: 'coder' },
|
||||
@@ -235,3 +235,19 @@ test('runtime actually injects the lookup adapter, without exposing human librar
|
||||
await assert.rejects(runtime.broker.request(cap, { verb: 'library.file', args: { project: 'books', path: GET.path } }),
|
||||
{ code: 'human-required' });
|
||||
});
|
||||
|
||||
test('C2-05c broker forwards supporting scope and returns the served blob without adding write verbs', async t => {
|
||||
const projects = { books: mappingEntry() };
|
||||
projects.books.universes.harbor.supporting = ['Book One/Support/'];
|
||||
const path = 'Book One/Support/Helper.md';
|
||||
const f = await world(t, { projects, files: { ...TEXTS, [path]: note('summary', 'Helper', 'Supporting fixture.') } });
|
||||
assert.deepEqual((await f.call('library.find', { universe: 'harbor', query: '', scope: 'supporting' })).results.map(x => x.path), [path]);
|
||||
assert.deepEqual((await f.call('library.search', { universe: 'harbor', text: 'Supporting fixture', scope: 'supporting' })).results.map(x => x.path), [path]);
|
||||
assert.equal(await f.call('library.get', { universe: 'harbor', path }), null);
|
||||
const result = await f.call('library.get', { universe: 'harbor', path, scope: 'supporting' });
|
||||
assert.equal(result.scope, 'supporting');
|
||||
assert.equal(result.commit, f.commit);
|
||||
assert.equal(result.blob, git(f.mirror, 'rev-parse', `${f.commit}:${path}`));
|
||||
assert.equal(await f.call('library.get', { universe: 'second', path, scope: 'supporting' }), null);
|
||||
await assert.rejects(f.call('library.manuscript', { universe: 'harbor', book: 'Book One', scope: 'supporting' }), { code: 'query-argument-invalid' });
|
||||
});
|
||||
@@ -228,24 +228,25 @@ export function typedTools({ resolved, arbiter = false, tracker = false, project
|
||||
if (library) {
|
||||
const universe = str("Universe ID in the configured library", { minLength: 1 });
|
||||
const project = str("Library project ID; omit only when the business has one library");
|
||||
const scope = str("canon by default; playground is opt-in", { enum: ["canon", "playground"] });
|
||||
const scope = str("canon by default; playground and supporting are opt-in", { enum: ["canon", "playground", "supporting"] });
|
||||
const manuscriptScope = str("canon by default; playground is opt-in", { enum: ["canon", "playground"] });
|
||||
const book = str("Book folder from library_universe");
|
||||
const offset = { type: "integer", minimum: 0, description: "next from the previous page" };
|
||||
const line = { type: "integer", minimum: 1, description: "One-based line number" };
|
||||
const base = { universe, project };
|
||||
add("library_find", "library.find", null, "Find names in one universe, at the served commit. At most 50 results; continue with next as offset.", obj({
|
||||
add("library_find", "library.find", null, "Find names in one universe, at the served commit. At most 50 results; continue with next as offset. Playground and supporting are opt-in.", obj({
|
||||
...base, query: str("Case-insensitive name or filename substring; empty matches all"),
|
||||
type: str("Mapped type", { enum: ["character", "place", "research", "tracker", "summary"] }),
|
||||
book, scope, offset,
|
||||
}, ["universe", "query"]));
|
||||
add("library_get", "library.get", null, "Read a mapped note and visible links in one universe at the served commit. next pages lines; links_next pages links. An explicit own-universe playground path is readable.", obj({
|
||||
...base, path: str("Mapped note path relative to the library"), from: line, links_from: offset,
|
||||
add("library_get", "library.get", null, "Read a note and its blob at the served commit, canon by default. Playground/supporting paths need matching scope; mismatch returns null. next pages lines; links_next pages visible links in supporting/playground/canon order.", obj({
|
||||
...base, path: str("Mapped note path relative to the library"), scope, from: line, links_from: offset,
|
||||
}, ["universe", "path"]));
|
||||
add("library_search", "library.search", null, "Search text in one universe at the served commit. At most 50 hits; use next as offset. Playground is opt-in.", obj({
|
||||
add("library_search", "library.search", null, "Search text in one universe at the served commit. At most 50 hits; use next as offset. Playground and supporting are opt-in.", obj({
|
||||
...base, text: str("Nonempty case-insensitive substring", { minLength: 1 }), book, scope, offset,
|
||||
}, ["universe", "text"]));
|
||||
add("library_manuscript", "library.manuscript", null, "Read one chapter of a book at the served commit, at most 400 lines. Omit chapter for the first; continue with next or next_chapter.", obj({
|
||||
...base, book, scope, chapter: str("Chapter filename without extension"), from: line, to: line,
|
||||
...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"]));
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ test('lookup schemas require a universe even for get, include paging, and cannot
|
||||
for (const key of ['repo', 'commit', 'business', 'accept']) assert.equal(Object.hasOwn(tool.parameters.properties, key), false);
|
||||
}
|
||||
const byName = Object.fromEntries(tools.map(t => [t.name, t]));
|
||||
assert.deepEqual(byName.library_find.parameters.properties.scope.enum, ['canon', 'playground']);
|
||||
assert.deepEqual(byName.library_find.parameters.properties.scope.enum, ['canon', 'playground', 'supporting']);
|
||||
assert.deepEqual(byName.library_find.parameters.properties.type.enum, [...TYPES]);
|
||||
assert.equal(byName.library_find.parameters.properties.offset.minimum, 0);
|
||||
assert.equal(byName.library_get.parameters.properties.from.minimum, 1);
|
||||
@@ -69,3 +69,14 @@ test('bundle flag reaches both harness tool manifests and creative prompt withou
|
||||
assert.doesNotMatch(prompt, /Bus tools: [^\n]*(read_spec|list_agents|inbox|trail|write_record|raise_decision|list_tasks)/);
|
||||
}
|
||||
});
|
||||
|
||||
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]);
|
||||
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']);
|
||||
assert.ok(!tool.parameters.required.includes('scope'));
|
||||
}
|
||||
assert.deepEqual(tools.find(t => t.name === 'library_manuscript').parameters.properties.scope.enum, ['canon', 'playground']);
|
||||
});
|
||||
@@ -7,12 +7,15 @@
|
||||
import { raise } from './problems.mjs';
|
||||
import { TYPES } from './mapping.mjs';
|
||||
import { indexFor } from './index-build.mjs';
|
||||
import { listTree } from './reader.mjs';
|
||||
|
||||
// The same cap as packages/harness/src/tools.mjs REPLY_CAP. The query tests assert the two stay equal.
|
||||
export const QUERY_REPLY_CAP = 40_000;
|
||||
export const LOOKUP_LIMIT = 50;
|
||||
export const MANUSCRIPT_LINES = 400;
|
||||
const SCOPES = Object.freeze(['canon', 'playground']);
|
||||
const SCOPES = Object.freeze(['canon', 'playground', 'supporting']);
|
||||
const MANUSCRIPT_SCOPES = Object.freeze(['canon', 'playground']);
|
||||
const SCOPE_RANK = Object.freeze({ supporting: 0, playground: 1, canon: 2 });
|
||||
|
||||
const bytes = value => JSON.stringify(value).length;
|
||||
const invalid = message => raise('query-argument-invalid', message);
|
||||
@@ -22,9 +25,9 @@ function textArg(value, name) {
|
||||
if (typeof value !== 'string') invalid(`${name} must be text`);
|
||||
return value;
|
||||
}
|
||||
function scopeArg(value) {
|
||||
function scopeArg(value, allowed = SCOPES) {
|
||||
if (value === undefined) return 'canon';
|
||||
if (!SCOPES.includes(value)) invalid('scope must be "canon" or "playground"');
|
||||
if (!allowed.includes(value)) invalid(`scope must be one of ${allowed.join(", ")}`);
|
||||
return value;
|
||||
}
|
||||
function positionArg(value, name, fallback) {
|
||||
@@ -109,7 +112,8 @@ export async function find(source, { universe: name, query, type, book, scope, o
|
||||
});
|
||||
}
|
||||
|
||||
// get: one visible file, its front matter, its lines from `from`, and its visible links both ways.
|
||||
// get: one file in the requested scope (canon default), its served-tree blob, front matter,
|
||||
// lines and visible links both ways. Links keep all visible scopes, ordered supporting/playground/canon.
|
||||
// Returns null when the file is missing or not visible, so a caller cannot tell the two apart. Lines page
|
||||
// by `from` (reply `next`), links page together by `links_from` (reply `links_next`); `links_out` come
|
||||
// before `links_in`. Every page carries the front matter. Links take at most half the cap, so a hub note
|
||||
@@ -117,27 +121,33 @@ export async function find(source, { universe: name, query, type, book, scope, o
|
||||
// least one line, so links shrink when a line needs the room; read on with `from: next` and
|
||||
// `links_from: links_next`. A `from` past the last line returns links alone. Only front matter, or a
|
||||
// line that cannot fit with no links beside it, is refused.
|
||||
export async function get(source, { universe: name, path, from, links_from: linksFrom } = {}) {
|
||||
export async function get(source, { universe: name, path, scope, from, links_from: linksFrom } = {}) {
|
||||
const universe = universeArg(source.mapping, name);
|
||||
const requestedScope = scopeArg(scope);
|
||||
const startLine = positionArg(from, 'from', 1);
|
||||
const linkStart = offsetArg(linksFrom);
|
||||
if (typeof path !== 'string') invalid('path must be text');
|
||||
const index = await indexFor(source);
|
||||
const file = index.files.get(path);
|
||||
if (!file || !sees(index.mapping, universe, file)) return null;
|
||||
if (!file || file.scope !== requestedScope || !sees(index.mapping, universe, file)) return null;
|
||||
const reachable = links => links.filter(link => {
|
||||
const other = index.files.get(link.path);
|
||||
return other !== undefined && sees(index.mapping, universe, other);
|
||||
});
|
||||
}).sort((a, b) => SCOPE_RANK[index.files.get(a.path).scope] - SCOPE_RANK[index.files.get(b.path).scope]);
|
||||
const outs = reachable(index.linksOut.get(file.path) ?? []);
|
||||
const ins = reachable(index.linksIn.get(file.path) ?? []);
|
||||
const links = [...outs.map(link => ({ out: true, link })), ...ins.map(link => ({ out: false, link }))];
|
||||
// The reader/index does not keep tree oids. Resolve only in this immutable served
|
||||
// snapshot, never HEAD; listTree already checks/bounds the tree and its object IDs.
|
||||
const entry = (await listTree(source.repo, index.commit)).find(entry => entry.path === file.path);
|
||||
if (!entry || entry.mode !== '100644' || entry.type !== 'blob') raise('library-commit', 'indexed file is absent from the served tree');
|
||||
const blob = entry.oid;
|
||||
const lines = file.lines.slice(startLine - 1);
|
||||
const linkRest = Math.max(0, links.length - linkStart);
|
||||
const page = (nLines, nLinks) => {
|
||||
const taken = links.slice(linkStart, linkStart + nLinks);
|
||||
return {
|
||||
path: file.path, commit: index.commit, scope: file.scope, frontmatter: file.frontmatter,
|
||||
path: file.path, commit: index.commit, blob, scope: file.scope, frontmatter: file.frontmatter,
|
||||
lines: lines.slice(0, nLines),
|
||||
links_out: taken.filter(item => item.out).map(item => item.link),
|
||||
links_in: taken.filter(item => !item.out).map(item => item.link),
|
||||
@@ -201,7 +211,7 @@ export async function manuscript(source, { universe: name, book, scope, chapter,
|
||||
const start = positionArg(from, 'from', 1);
|
||||
const end = positionArg(to, 'to', Infinity);
|
||||
if (end < start) invalid('to must not be before from');
|
||||
const { index, files } = await visible(source, universe, { scope: scopeArg(scope), book: bookName, type: 'manuscript' });
|
||||
const { index, files } = await visible(source, universe, { scope: scopeArg(scope, MANUSCRIPT_SCOPES), book: bookName, type: 'manuscript' });
|
||||
let at = 0;
|
||||
if (chapterName !== undefined) {
|
||||
const matches = files.filter(file => file.stem === chapterName);
|
||||
|
||||
@@ -29,3 +29,22 @@ export const note = (type, name, body = '', extra = []) => ['---', `type: ${type
|
||||
// `exclude` (a path prefix today); swapping these two constants is the whole change to the tests.
|
||||
export const EXCLUSION = { exclude: 'Book One/Research' };
|
||||
export const EXCLUDED_PATHS = ['Book One/Research/Ferry Logs.md'];
|
||||
|
||||
// C2-05c: synthetic scope fixture, including same-prefix precedence and a draft.
|
||||
export const SUPPORT_FILES = {
|
||||
'Book One/Characters/Canon.md': note('character', 'Canon', 'Scope fixture canon.'),
|
||||
'Book One/Playground/Plan.md': note('summary', 'Plan', 'Scope fixture playground.'),
|
||||
'Book One/Support/Notes/Helper.md': note('summary', 'Helper', 'Scope fixture supporting.'),
|
||||
'Notes/HarborSupport/Loose.md': note('summary', 'Loose', 'Scope fixture supporting loose.'),
|
||||
'Drafts/Idea/Support/Seed.md': note('summary', 'Seed', 'Scope fixture supporting draft.'),
|
||||
};
|
||||
export const withSupporting = entry => ({
|
||||
...entry,
|
||||
universes: {
|
||||
...entry.universes,
|
||||
harbor: { ...entry.universes.harbor,
|
||||
playground: [...entry.universes.harbor.playground, 'Book One/Support/'],
|
||||
supporting: ['Book One/Support/', 'Notes/HarborSupport/'] },
|
||||
idea: { kind: 'draft', name: 'Idea', playground: ['Drafts/Idea/'], supporting: ['Drafts/Idea/Support/'] },
|
||||
},
|
||||
});
|
||||
@@ -1,11 +1,13 @@
|
||||
// Query tests for design 3 (C2-05a): universe isolation, scope labels, unmapped files, hybrids, paging
|
||||
// under the reply cap, refusals and manuscript paging. Fixtures are made up and built under the scratch area.
|
||||
import { test } from 'node:test';
|
||||
import { writeFileSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import assert from 'node:assert/strict';
|
||||
import { REPLY_CAP } from '../../harness/src/tools.mjs';
|
||||
import { find, get, search, manuscript, universeInfo, QUERY_REPLY_CAP, LOOKUP_LIMIT, MANUSCRIPT_LINES } from '../src/query.mjs';
|
||||
import { mapping, MARKER } from './helpers.mjs';
|
||||
import { scratchRepo, note, EXCLUSION, EXCLUDED_PATHS } from './query-fixture.mjs';
|
||||
import { mapping, MARKER, git } from './helpers.mjs';
|
||||
import { scratchRepo, note, EXCLUSION, EXCLUDED_PATHS, SUPPORT_FILES, withSupporting } from './query-fixture.mjs';
|
||||
|
||||
// A hybrid over harbor and second. Its one constraint is EXCLUSION (query-fixture.mjs) and it declares no
|
||||
// books or playground.
|
||||
@@ -345,9 +347,9 @@ test('PRD 1.14: a draft universe has no canon, so its lookups return files only
|
||||
assert.ok(found.results.every(r => r.scope === 'playground' && r.universe === 'idea' && r.book === null));
|
||||
const hits = (await search(s, { universe: 'idea', text: 'draft', scope: 'playground' })).results;
|
||||
assert.equal(hits.length, 2);
|
||||
const rin = await get(s, { universe: 'idea', path: 'Drafts/New World/Characters/Rin.md' });
|
||||
const rin = await get(s, { universe: 'idea', path: 'Drafts/New World/Characters/Rin.md', scope: 'playground' });
|
||||
assert.equal(rin.scope, 'playground');
|
||||
assert.equal(await get(s, { universe: 'harbor', path: 'Drafts/New World/Characters/Rin.md' }), null);
|
||||
assert.equal(await get(s, { universe: 'harbor', path: 'Drafts/New World/Characters/Rin.md', scope: 'playground' }), null);
|
||||
});
|
||||
|
||||
test('PRD 1.14: library_universe on a draft returns its kind, name and prefixes', async t => {
|
||||
@@ -363,7 +365,102 @@ test('PRD 1.14: library_universe on a draft returns its kind, name and prefixes'
|
||||
test('a hybrid gets a source playground file as null, while the source gets it with scope playground', async t => {
|
||||
const ref = scratchRepo(t, FILES);
|
||||
const path = 'Book One/Playground/What If.md';
|
||||
assert.equal(await get(src(ref, mapping(WITH_BLEND)), { universe: 'blend', path }), null);
|
||||
const own = await get(src(ref), { universe: 'harbor', path });
|
||||
assert.equal(await get(src(ref, mapping(WITH_BLEND)), { universe: 'blend', path, scope: 'playground' }), null);
|
||||
const own = await get(src(ref), { universe: 'harbor', path, scope: 'playground' });
|
||||
assert.equal(own.scope, 'playground');
|
||||
});
|
||||
|
||||
// mos-1330 item3: the new get contract defaults to canon even for an explicit playground path.
|
||||
test('C2-05c get without scope returns null for a playground path', async t => {
|
||||
const s = src(scratchRepo(t, FILES));
|
||||
assert.equal(await get(s, { universe: 'harbor', path: 'Book One/Playground/What If.md' }), null);
|
||||
});
|
||||
|
||||
// Row284: scope is explicit for get as well as lists; blob and lines share a served snapshot.
|
||||
test('C2-05c supporting find/search/get are opt-in at book, universe and draft level', async t => {
|
||||
const s = src(scratchRepo(t, SUPPORT_FILES), mapping(withSupporting));
|
||||
const expected = ['Book One/Support/Notes/Helper.md', 'Notes/HarborSupport/Loose.md'];
|
||||
assert.deepEqual(paths(await find(s, { universe: 'harbor', query: '', scope: 'supporting' })), expected);
|
||||
assert.deepEqual((await search(s, { universe: 'harbor', text: 'Scope fixture', scope: 'supporting' })).results.map(x => x.path), expected);
|
||||
assert.deepEqual(paths(await find(s, { universe: 'harbor', query: '' })), ['Book One/Characters/Canon.md']);
|
||||
assert.deepEqual((await search(s, { universe: 'harbor', text: 'Scope fixture' })).results.map(x => x.path), ['Book One/Characters/Canon.md']);
|
||||
for (const path of expected) {
|
||||
assert.equal(await get(s, { universe: 'harbor', path }), null);
|
||||
assert.equal(await get(s, { universe: 'harbor', path, scope: 'playground' }), null);
|
||||
assert.equal((await get(s, { universe: 'harbor', path, scope: 'supporting' })).scope, 'supporting');
|
||||
assert.equal(await get(s, { universe: 'second', path, scope: 'supporting' }), null);
|
||||
}
|
||||
const draftPath = 'Drafts/Idea/Support/Seed.md';
|
||||
assert.deepEqual(paths(await find(s, { universe: 'idea', query: '', scope: 'supporting' })), [draftPath]);
|
||||
assert.equal((await get(s, { universe: 'idea', path: draftPath, scope: 'supporting' })).scope, 'supporting');
|
||||
assert.equal(await get(s, { universe: 'idea', path: draftPath }), null);
|
||||
assert.equal((await find(s, { universe: 'harbor', query: '', book: 'Book One', scope: 'supporting' })).results.length, 1);
|
||||
});
|
||||
|
||||
test('C2-05c an absent supporting prefix returns nothing without refusal', async t => {
|
||||
const s = src(scratchRepo(t, SUPPORT_FILES));
|
||||
assert.deepEqual((await find(s, { universe: 'harbor', query: '', scope: 'supporting' })).results, []);
|
||||
assert.deepEqual((await search(s, { universe: 'harbor', text: 'Scope fixture', scope: 'supporting' })).results, []);
|
||||
assert.equal(await get(s, { universe: 'harbor', path: 'Book One/Characters/Canon.md', scope: 'supporting' }), null);
|
||||
assert.equal(await get(s, { universe: 'harbor', path: 'Book One/Support/Notes/Helper.md', scope: 'supporting' }), null);
|
||||
});
|
||||
|
||||
test('C2-05c each get blob equals its served tree object, even after source HEAD advances', async t => {
|
||||
const ref = scratchRepo(t, SUPPORT_FILES), s = src(ref, mapping(withSupporting));
|
||||
const canon = 'Book One/Characters/Canon.md';
|
||||
const priorBlob = git(ref.repo, 'rev-parse', `${ref.commit}:${canon}`);
|
||||
writeFileSync(join(ref.repo, canon), note('character', 'Canon changed', 'New HEAD must not be read.'));
|
||||
git(ref.repo, 'add', '-A'); git(ref.repo, 'commit', '-qm', 'advance head fixture');
|
||||
assert.notEqual(git(ref.repo, 'rev-parse', `HEAD:${canon}`), priorBlob);
|
||||
for (const [scope, path] of [['canon', canon], ['playground', 'Book One/Playground/Plan.md'], ['supporting', 'Book One/Support/Notes/Helper.md']]) {
|
||||
const result = await get(s, { universe: 'harbor', path, scope });
|
||||
assert.equal(result.commit, ref.commit);
|
||||
assert.equal(result.blob, git(ref.repo, 'rev-parse', `${ref.commit}:${path}`));
|
||||
assert.ok(!JSON.stringify(result.lines).includes('New HEAD must not be read'));
|
||||
}
|
||||
});
|
||||
|
||||
test('C2-05c full outgoing and incoming links stay in scope order across pages without losing cross-scope links', async t => {
|
||||
const files = {}, groups = { supporting: [], playground: [], canon: [] };
|
||||
for (const [scope, folder] of [['canon', 'Book One/Characters'], ['playground', 'Book One/Playground'], ['supporting', 'Book One/Support']]) {
|
||||
for (let n = 0; n < 100; n++) {
|
||||
const path = `${folder}/${scope}-${String(n).padStart(3, '0')}-${'x'.repeat(80)}.md`;
|
||||
groups[scope].push(path);
|
||||
files[path] = `[[Book One/Characters/Hub]]\n`;
|
||||
}
|
||||
}
|
||||
const all = [...groups.canon, ...groups.playground, ...groups.supporting];
|
||||
files['Book One/Characters/Hub.md'] = all.map(path => `[[${path.slice(0, -3)}]]`).join('\n');
|
||||
// Other-universe links are never returned, regardless of rank.
|
||||
files['Second World/Other.md'] = '[[Book One/Characters/Hub]]\n';
|
||||
const s = src(scratchRepo(t, files), mapping(withSupporting));
|
||||
const outs = [], ins = [];
|
||||
let offset = 0, pages = 0;
|
||||
for (; pages < 20; pages++) {
|
||||
const page = await get(s, { universe: 'harbor', path: 'Book One/Characters/Hub.md', from: 999_999, links_from: offset });
|
||||
assert.ok(JSON.stringify(page).length <= QUERY_REPLY_CAP);
|
||||
outs.push(...page.links_out.map(x => x.path)); ins.push(...page.links_in.map(x => x.path));
|
||||
if (page.links_next === null) break;
|
||||
offset = page.links_next;
|
||||
}
|
||||
const expected = [...groups.supporting, ...groups.playground, ...groups.canon];
|
||||
assert.ok(pages > 0 && pages < 20, 'links occupy multiple bounded pages');
|
||||
assert.deepEqual(outs, expected);
|
||||
assert.deepEqual(ins, expected);
|
||||
assert.equal(new Set(outs).size, 300);
|
||||
assert.equal(new Set(ins).size, 300);
|
||||
});
|
||||
|
||||
test('C2-05c manuscript still refuses supporting rather than silently widening its scope', async t => {
|
||||
const s = src(scratchRepo(t, SUPPORT_FILES), mapping(withSupporting));
|
||||
await assert.rejects(manuscript(s, { universe: 'harbor', book: 'Book One', scope: 'supporting' }), { code: 'query-argument-invalid' });
|
||||
});
|
||||
|
||||
test('C2-05c scope expansion keeps hybrid sources canon-only and refuses all/array scopes', async t => {
|
||||
const s = src(scratchRepo(t, SUPPORT_FILES), mapping(entry => withSupporting(WITH_BLEND(entry))));
|
||||
assert.deepEqual((await find(s, { universe: 'blend', query: '', scope: 'supporting' })).results, []);
|
||||
assert.equal(await get(s, { universe: 'blend', path: 'Book One/Support/Notes/Helper.md', scope: 'supporting' }), null);
|
||||
assert.equal((await get(s, { universe: 'blend', path: 'Book One/Characters/Canon.md' })).scope, 'canon');
|
||||
for (const scope of ['all', ['canon', 'supporting']])
|
||||
await assert.rejects(get(s, { universe: 'harbor', path: 'Book One/Characters/Canon.md', scope }), { code: 'query-argument-invalid' });
|
||||
});
|
||||
@@ -4,8 +4,8 @@
|
||||
"options": "bundle, iife, es2022, browser, legal-comments inline, unminified; aliases in editor/build.mjs",
|
||||
"outputs": {
|
||||
"src/public/editor.js": {
|
||||
"sha256": "9c881b13740fae2408717ad75fa1d85bfcfe3fa8b3af0f1b3f2e706c90e80fee",
|
||||
"bytes": 758420
|
||||
"sha256": "bd167899a551c70dc07e500fcdd1853d7fb710b23c217ba5b42daf5785c38a72",
|
||||
"bytes": 759959
|
||||
},
|
||||
"src/public/editor.css": {
|
||||
"sha256": "8654ac57d1e7a561110138ecd7f701c34a074017ff8c4cd2768d8083908ee61f",
|
||||
|
||||
@@ -23,6 +23,13 @@ export const linkTarget = raw => {
|
||||
return typeof gate === 'function' ? gate(raw) : null;
|
||||
};
|
||||
|
||||
// C2-11a: an inert single-line atom keeps its exact source, including labels
|
||||
// and heading fragments. HTML/entity-like targets stay ordinary text so the
|
||||
// existing escaped-text serialiser still protects rewritten blocks.
|
||||
const wikilinkSource = /^!?\[\[[^\[\]\r\n<>&`]+\]\]$/;
|
||||
const wikilinkAt = /!?\[\[[^\[\]\r\n<>&`]+\]\]/y;
|
||||
const isWikilink = value => typeof value === 'string' && wikilinkSource.test(value);
|
||||
|
||||
const kept = { raw: { default: null }, sig: { default: null }, lead: { default: '' } };
|
||||
const block = attrs => ({ ...kept, ...attrs });
|
||||
|
||||
@@ -34,7 +41,7 @@ export const schema = new Schema({
|
||||
horizontal_rule: { group: 'block', attrs: block({}), parseDOM: [{ tag: 'hr' }], toDOM() { return ['div', ['hr']]; } },
|
||||
heading: {
|
||||
attrs: block({ level: { default: 1 } }),
|
||||
content: '(text | image)*', group: 'block', defining: true,
|
||||
content: '(text | image | wikilink)*', group: 'block', defining: true,
|
||||
parseDOM: [1, 2, 3, 4, 5, 6].map(level => ({ tag: 'h' + level, attrs: { level } })),
|
||||
toDOM(node) { return ['h' + +node.attrs.level, 0]; },
|
||||
},
|
||||
@@ -79,6 +86,16 @@ export const schema = new Schema({
|
||||
return ['span', { class: 'md-image', 'data-src': a.src, 'data-alt': a.alt, 'data-title': a.title }, shown];
|
||||
},
|
||||
},
|
||||
// No href, image, target resolution or click handler. C2-11b owns opening.
|
||||
wikilink: {
|
||||
inline: true, group: 'inline', atom: true,
|
||||
attrs: { source: {} },
|
||||
parseDOM: [{ tag: 'span.md-wikilink[data-source]', getAttrs: dom => {
|
||||
const source = dom.getAttribute('data-source');
|
||||
return isWikilink(source) ? { source } : false;
|
||||
} }],
|
||||
toDOM(node) { return ['span', { class: 'md-wikilink', 'data-source': node.attrs.source }, node.attrs.source]; },
|
||||
},
|
||||
hard_break: { inline: true, group: 'inline', selectable: false, parseDOM: [{ tag: 'br' }], toDOM() { return ['br']; } },
|
||||
},
|
||||
marks: {
|
||||
@@ -118,6 +135,16 @@ export const schema = new Schema({
|
||||
// ------------------------------------------------------------------ Markdown to nodes
|
||||
const splitter = MarkdownIt('commonmark', { html: true }).enable('table').enable('strikethrough');
|
||||
const tokenizer = MarkdownIt('commonmark', { html: false }).enable('table').enable('strikethrough');
|
||||
// The escape and backtick rules run first. A sticky match avoids copying the
|
||||
// paragraph suffix at every bracket, and never crosses a link-label boundary.
|
||||
tokenizer.inline.ruler.before('link', 'wikilink', (state, silent) => {
|
||||
wikilinkAt.lastIndex = state.pos;
|
||||
const found = wikilinkAt.exec(state.src);
|
||||
if (!found || state.pos + found[0].length > state.posMax) return false;
|
||||
if (!silent) { const token = state.push('wikilink', '', 0); token.content = found[0]; }
|
||||
state.pos += found[0].length;
|
||||
return true;
|
||||
});
|
||||
|
||||
// Soft breaks stay line breaks in the text, so a wrapped paragraph keeps its wrapping. A link whose
|
||||
// target the gate refuses makes the whole block source text (`refused`), so nothing rewrites it.
|
||||
@@ -151,6 +178,7 @@ const parser = new MarkdownParser(schema, prepared, {
|
||||
hr: { node: 'horizontal_rule' },
|
||||
image: { node: 'image', getAttrs: tok => ({ src: tok.attrGet('src'), title: tok.attrGet('title') || null, alt: tok.content || null }) },
|
||||
hardbreak: { node: 'hard_break' },
|
||||
wikilink: { node: 'wikilink', getAttrs: tok => ({ source: tok.content }) },
|
||||
em: { mark: 'em' },
|
||||
strong: { mark: 'strong' },
|
||||
link: { mark: 'link', getAttrs: tok => ({ href: tok.attrGet('href'), title: tok.attrGet('title') || null }) },
|
||||
@@ -174,6 +202,13 @@ const fenceInfo = value => {
|
||||
const info = typeof value === 'string' ? value.split(/[\r\n]/, 1)[0] : '';
|
||||
return info.includes('`') ? '' : info;
|
||||
};
|
||||
// Share the complete text policy with invalid wikilink attributes. The
|
||||
// vendored state.text(..., true) alone does not escape HTML or entities.
|
||||
function escapedText(state, text, escape = true) {
|
||||
const esc = state.esc;
|
||||
state.esc = (str, start) => esc.call(state, str, start).replace(/[<&]/g, '\\$&');
|
||||
try { state.text(text, escape); } finally { delete state.esc; }
|
||||
}
|
||||
const link = defaultMarkdownSerializer.marks.link;
|
||||
const serializer = new MarkdownSerializer({
|
||||
...defaultMarkdownSerializer.nodes,
|
||||
@@ -181,17 +216,20 @@ const serializer = new MarkdownSerializer({
|
||||
const params = fenceInfo(node.attrs.params);
|
||||
defaultMarkdownSerializer.nodes.code_block(state, params === node.attrs.params ? node : node.type.create({ ...node.attrs, params }, node.content));
|
||||
},
|
||||
text(state, node) {
|
||||
const esc = state.esc;
|
||||
state.esc = (str, start) => esc.call(state, str, start).replace(/[<&]/g, '\\$&');
|
||||
try { state.text(node.text, !state.inAutolink); } finally { delete state.esc; }
|
||||
},
|
||||
text(state, node) { escapedText(state, node.text, !state.inAutolink); },
|
||||
bullet_list(state, node) { state.renderList(node, ' ', () => '- '); },
|
||||
image(state, node) {
|
||||
const a = node.attrs;
|
||||
const title = oneLine(a.title);
|
||||
state.write(']/g, '\\$&') + (title ? ' "' + title.replace(/[\\"]/g, '\\$&') + '"' : '') + ')');
|
||||
},
|
||||
wikilink(state, node) {
|
||||
const source = node.attrs.source, valid = isWikilink(source);
|
||||
// A programmatic invalid atom must not bypass the same text escaping that
|
||||
// protects pasted HTML and one-line attributes elsewhere in this model.
|
||||
if (valid) state.text(source, false);
|
||||
else escapedText(state, oneLine(String(source ?? '')));
|
||||
},
|
||||
raw_block(state, node) { state.text(node.textContent, false); state.closeBlock(node); },
|
||||
}, {
|
||||
...defaultMarkdownSerializer.marks,
|
||||
|
||||
@@ -18176,6 +18176,9 @@
|
||||
const gate = globalThis.MosaicMarkdown?.linkTarget;
|
||||
return typeof gate === "function" ? gate(raw) : null;
|
||||
};
|
||||
var wikilinkSource = /^!?\[\[[^\[\]\r\n<>&`]+\]\]$/;
|
||||
var wikilinkAt = /!?\[\[[^\[\]\r\n<>&`]+\]\]/y;
|
||||
var isWikilink = (value) => typeof value === "string" && wikilinkSource.test(value);
|
||||
var kept = { raw: { default: null }, sig: { default: null }, lead: { default: "" } };
|
||||
var block2 = (attrs2) => ({ ...kept, ...attrs2 });
|
||||
var schema2 = new Schema({
|
||||
@@ -18192,7 +18195,7 @@
|
||||
} },
|
||||
heading: {
|
||||
attrs: block2({ level: { default: 1 } }),
|
||||
content: "(text | image)*",
|
||||
content: "(text | image | wikilink)*",
|
||||
group: "block",
|
||||
defining: true,
|
||||
parseDOM: [1, 2, 3, 4, 5, 6].map((level) => ({ tag: "h" + level, attrs: { level } })),
|
||||
@@ -18266,6 +18269,20 @@
|
||||
return ["span", { class: "md-image", "data-src": a.src, "data-alt": a.alt, "data-title": a.title }, shown];
|
||||
}
|
||||
},
|
||||
// No href, image, target resolution or click handler. C2-11b owns opening.
|
||||
wikilink: {
|
||||
inline: true,
|
||||
group: "inline",
|
||||
atom: true,
|
||||
attrs: { source: {} },
|
||||
parseDOM: [{ tag: "span.md-wikilink[data-source]", getAttrs: (dom) => {
|
||||
const source = dom.getAttribute("data-source");
|
||||
return isWikilink(source) ? { source } : false;
|
||||
} }],
|
||||
toDOM(node) {
|
||||
return ["span", { class: "md-wikilink", "data-source": node.attrs.source }, node.attrs.source];
|
||||
}
|
||||
},
|
||||
hard_break: { inline: true, group: "inline", selectable: false, parseDOM: [{ tag: "br" }], toDOM() {
|
||||
return ["br"];
|
||||
} }
|
||||
@@ -18314,6 +18331,17 @@
|
||||
});
|
||||
var splitter = lib_default("commonmark", { html: true }).enable("table").enable("strikethrough");
|
||||
var tokenizer = lib_default("commonmark", { html: false }).enable("table").enable("strikethrough");
|
||||
tokenizer.inline.ruler.before("link", "wikilink", (state, silent) => {
|
||||
wikilinkAt.lastIndex = state.pos;
|
||||
const found2 = wikilinkAt.exec(state.src);
|
||||
if (!found2 || state.pos + found2[0].length > state.posMax) return false;
|
||||
if (!silent) {
|
||||
const token = state.push("wikilink", "", 0);
|
||||
token.content = found2[0];
|
||||
}
|
||||
state.pos += found2[0].length;
|
||||
return true;
|
||||
});
|
||||
var refused = false;
|
||||
var prepared = {
|
||||
parse(text2, env) {
|
||||
@@ -18349,6 +18377,7 @@
|
||||
hr: { node: "horizontal_rule" },
|
||||
image: { node: "image", getAttrs: (tok) => ({ src: tok.attrGet("src"), title: tok.attrGet("title") || null, alt: tok.content || null }) },
|
||||
hardbreak: { node: "hard_break" },
|
||||
wikilink: { node: "wikilink", getAttrs: (tok) => ({ source: tok.content }) },
|
||||
em: { mark: "em" },
|
||||
strong: { mark: "strong" },
|
||||
link: { mark: "link", getAttrs: (tok) => ({ href: tok.attrGet("href"), title: tok.attrGet("title") || null }) },
|
||||
@@ -18360,6 +18389,15 @@
|
||||
const info = typeof value === "string" ? value.split(/[\r\n]/, 1)[0] : "";
|
||||
return info.includes("`") ? "" : info;
|
||||
};
|
||||
function escapedText(state, text2, escape2 = true) {
|
||||
const esc = state.esc;
|
||||
state.esc = (str, start) => esc.call(state, str, start).replace(/[<&]/g, "\\$&");
|
||||
try {
|
||||
state.text(text2, escape2);
|
||||
} finally {
|
||||
delete state.esc;
|
||||
}
|
||||
}
|
||||
var link2 = defaultMarkdownSerializer.marks.link;
|
||||
var serializer = new MarkdownSerializer({
|
||||
...defaultMarkdownSerializer.nodes,
|
||||
@@ -18368,13 +18406,7 @@
|
||||
defaultMarkdownSerializer.nodes.code_block(state, params === node.attrs.params ? node : node.type.create({ ...node.attrs, params }, node.content));
|
||||
},
|
||||
text(state, node) {
|
||||
const esc = state.esc;
|
||||
state.esc = (str, start) => esc.call(state, str, start).replace(/[<&]/g, "\\$&");
|
||||
try {
|
||||
state.text(node.text, !state.inAutolink);
|
||||
} finally {
|
||||
delete state.esc;
|
||||
}
|
||||
escapedText(state, node.text, !state.inAutolink);
|
||||
},
|
||||
bullet_list(state, node) {
|
||||
state.renderList(node, " ", () => "- ");
|
||||
@@ -18384,6 +18416,11 @@
|
||||
const title = oneLine(a.title);
|
||||
state.write("]/g, "\\$&") + (title ? ' "' + title.replace(/[\\"]/g, "\\$&") + '"' : "") + ")");
|
||||
},
|
||||
wikilink(state, node) {
|
||||
const source = node.attrs.source, valid = isWikilink(source);
|
||||
if (valid) state.text(source, false);
|
||||
else escapedText(state, oneLine(String(source ?? "")));
|
||||
},
|
||||
raw_block(state, node) {
|
||||
state.text(node.textContent, false);
|
||||
state.closeBlock(node);
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
// C2-11a. Unchanged files alone cannot detect escaped wikilinks: the editor
|
||||
// keeps raw source. The browser checks the structured node and a dirty block.
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { loadEditor } from './helpers/editor-bundle.mjs';
|
||||
import { WIKILINK_CASES } from './helpers/wikilink-cases.mjs';
|
||||
import { fixture } from './fixture.mjs';
|
||||
import { browser } from './browser.mjs';
|
||||
|
||||
const editor = loadEditor();
|
||||
for (const { name, text } of WIKILINK_CASES) test(`wikilink round-trip: ${name}`, () => {
|
||||
assert.equal(editor.roundTrip(text), text);
|
||||
assert.equal(editor.roundTrip(text.trimEnd()), text.trimEnd(), 'no trailing newline');
|
||||
});
|
||||
|
||||
const page = async t => {
|
||||
const f = await fixture(); t.after(() => f.close());
|
||||
const b = await browser(); t.after(() => b.close());
|
||||
await b.navigate(f.base);
|
||||
return b;
|
||||
};
|
||||
const mount = text => `(() => {
|
||||
window.__wikiEditor?.destroy();
|
||||
const host = document.createElement('div'); document.body.append(host);
|
||||
window.__wikiEditor = window.MosaicEditor.mount(host, {text: ${JSON.stringify(text)}});
|
||||
return true;
|
||||
})()`;
|
||||
const atoms = `(() => {
|
||||
const result = [];
|
||||
window.__wikiEditor.view.state.doc.descendants(node => {
|
||||
if (node.type.name === 'wikilink') result.push({source: node.attrs.source, atom: node.isAtom, inline: node.isInline});
|
||||
}); return result;
|
||||
})()`;
|
||||
|
||||
test('wikilinks are inline atoms and survive a neighbouring edit in every required context', { timeout: 120000 }, async t => {
|
||||
const b = await page(t);
|
||||
for (const { name, text, sources } of WIKILINK_CASES) {
|
||||
await b.evaluate(mount(text));
|
||||
assert.deepEqual(await b.evaluate(atoms), sources.map(source => ({ source, atom: true, inline: true })), name);
|
||||
assert.equal(await b.evaluate('document.querySelectorAll(".md-wikilink a, .md-wikilink img, .md-wikilink iframe").length'), 0, 'no navigation or resource elements');
|
||||
const changed = await b.evaluate(`(() => {
|
||||
const e = window.__wikiEditor; let end;
|
||||
e.view.state.doc.descendants((node, pos) => { if (node.isTextblock && node.type.name !== 'raw_block') end = pos + node.nodeSize - 1; });
|
||||
e.view.dispatch(e.view.state.tr.insertText(' changed', end));
|
||||
const output = e.text(); e.setText(output); return output;
|
||||
})()`);
|
||||
assert.ok(changed.includes(' changed'), name);
|
||||
for (const source of sources) assert.ok(changed.includes(source), `${name}: spelling survives dirty-block serialisation`);
|
||||
assert.deepEqual(await b.evaluate(atoms), sources.map(source => ({ source, atom: true, inline: true })), `${name}: survives reparse`);
|
||||
if (text.startsWith('---')) assert.ok(changed.startsWith(text.slice(0, text.indexOf('\n\n') + 2)), 'front matter is untouched');
|
||||
if (name === 'reference-definition collision')
|
||||
assert.ok(changed.endsWith('\n\n[a]: u\n'), 'the separate reference-definition block keeps its exact bytes');
|
||||
}
|
||||
});
|
||||
|
||||
test('code, escaped openers, malformed syntax and HTML-like targets stay outside wikilink atoms', { timeout: 120000 }, async t => {
|
||||
const b = await page(t);
|
||||
const text = '\\[[escaped]] `[[inline-code]]`\n\n```\n[[fenced-code]]\n```\n\n[[open\n\n[[]]\n\n[[Q&A]]\n\n[[a`]]`\n\n[[<img src=x onerror=alert(1)>]]\n';
|
||||
assert.equal(editor.roundTrip(text), text);
|
||||
await b.evaluate(mount(text));
|
||||
assert.deepEqual(await b.evaluate(atoms), []);
|
||||
assert.equal(await b.evaluate('document.querySelector(".ProseMirror").querySelectorAll("img, iframe, script").length'), 0);
|
||||
});
|
||||
|
||||
test('wikilink DOM paste accepts only bounded single-line inert syntax; malformed attrs serialise as escaped text', { timeout: 120000 }, async t => {
|
||||
const b = await page(t); await b.evaluate(mount('[[a]]\n'));
|
||||
const result = await b.evaluate(`(() => {
|
||||
const e = window.__wikiEditor, spec = e.view.state.schema.nodes.wikilink.spec;
|
||||
const attrs = source => spec.parseDOM[0].getAttrs({getAttribute: () => source});
|
||||
const invalid = ['not a link', '[[a]]\\n\\n<script>x</script>', '[[<img src=x>]]', '[[a©]]', null].map(source => attrs(source));
|
||||
const bad = e.view.state.schema.nodes.wikilink.create({source:'[[a]]\\n\\n<img src=x onerror=alert(1)>©'});
|
||||
e.view.dispatch(e.view.state.tr.replaceWith(1, e.view.state.doc.content.size - 1, bad));
|
||||
return {valid:attrs('[[a#h|label]]'), invalid, output:e.text()};
|
||||
})()`);
|
||||
assert.deepEqual(result.valid, { source: '[[a#h|label]]' });
|
||||
assert.deepEqual(result.invalid, [false, false, false, false, false]);
|
||||
assert.ok(!result.output.includes('\n\n<img'));
|
||||
assert.doesNotMatch(result.output, /(?<!\\)<img/);
|
||||
assert.match(result.output, /\\<img/);
|
||||
assert.doesNotMatch(result.output, /(?<!\\)©/);
|
||||
assert.match(result.output, /\\©/);
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
// C2-11a byte fixtures shared by the baseline measurement and regression tests.
|
||||
export const WIKILINK_CASES = [
|
||||
{ name: 'plain', text: '[[a]]\n', sources: ['[[a]]'] },
|
||||
{ name: 'labelled', text: '[[a|b]]\n', sources: ['[[a|b]]'] },
|
||||
{ name: 'heading target', text: '[[a#h]]\n', sources: ['[[a#h]]'] },
|
||||
{ name: 'list item', text: '- [[a]]\n', sources: ['[[a]]'] },
|
||||
{ name: 'next to front matter', text: '---\nrelated: "[[metadata]]"\n---\n\n[[a]]\n', sources: ['[[a]]'] },
|
||||
{ name: 'heading block and combined label', text: '# See [[a#h|Title]]\n', sources: ['[[a#h|Title]]'] },
|
||||
{ name: 'spaces, Unicode and adjacent links', text: 'See [[ Héllo there # A heading | a label ]][[next]]\n', sources: ['[[ Héllo there # A heading | a label ]]', '[[next]]'] },
|
||||
{ name: 'reference-definition collision', text: '[[a]]\n\n[a]: u\n', sources: ['[[a]]'] },
|
||||
{ name: 'inside an ordinary link', text: '[x [[a]]](u)\n', sources: ['[[a]]'] },
|
||||
{ name: 'inert embed', text: '![[cover.png]]\n', sources: ['![[cover.png]]'] },
|
||||
];
|
||||
Reference in new issue
Block a user