Compare commits
27
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0844a5ce7 | ||
|
|
b096a16cce | ||
|
|
9182134e59 | ||
|
|
191dff32fb | ||
|
|
c3d88840c5 | ||
|
|
7247d80c7a | ||
|
|
6661732925 | ||
|
|
21def28502 | ||
|
|
add0f1aae5 | ||
|
|
7d08237e17 | ||
|
|
f48725cfc1 | ||
|
|
0de97f429d | ||
|
|
0b33f5e9db | ||
|
|
3586955286 | ||
|
|
a54a17f3d8 | ||
|
|
0cdead66cd | ||
|
|
1b6158ce26 | ||
|
|
081ff6b128 | ||
|
|
be86adbff2 | ||
|
|
d163afc47f | ||
|
|
e54e054632 | ||
|
|
6096b051b1 | ||
|
|
9a8c8860d3 | ||
|
|
6195a00f8d | ||
|
|
3b0aef9952 | ||
|
|
2c38325eca | ||
|
|
640aa03f27 |
@@ -5177,3 +5177,25 @@ Before: managed project/thread verbs had no Console conversation area. After: fi
|
||||
2026-10-21T01:28:05Z | Darkwing | row 232 #1734 installer I1 build, round 1 in review | Before: stack-release.sh managed only user units (systemctl --user), and stack-copy.sh had no bundle copy. After: --units external (adopt, activate, rollback --to, status, confirm, revert, gate --since, AWAITING-UNITS, stale-start, external-pm, --plan --expect-from) and stack-copy check --units external, copy --bundle FILE SHA, wrapper ID --create; user mode byte-identical to the base by test. First build 0af0c73c6 on 00d4cc1f6; rebased onto row 200 (cb5fdb064) as a0ffabc3f on darkwing/row232-r1; --sso refused under external (D9), row 200 config_checks run under external (D10). Gate on Sage's slot (sage-1618): cli 561/0, every scripts/test-*.sh green; 17/17 mutants killed. Results commit 84f1a91e6 (pushed, seat branch only). Manifest 7a3b4ea1 (9 paths), queue revs 2595-2596, request comment 29825, reviewer Filbert. Packet agents/darkwing/work/queue-232/BUILD.md.
|
||||
2026-10-21T04:50:44Z | Darkwing | row 233 #1735 installer I3 build, round 1 in review | Before: root had no upgrade driver for root-owned units and no host run sheet; stack-release.sh had no rehearse --backup last and no external plan refusals. After: scripts/stack-upgrade.sh upgrade and rollback (r6 A1-A5, A2f, R1-R4) with 20 tests, docs/guides/host-run-sheet.md, TOOLS.md lines, and on Sage's rulings stack-release.sh --backup last, BACKUP_STORE and the --plan refusals open-activation and migrate-required (3 tests). Base e65a3ab4d (row 232's landing). Gate on Sage's slot (sage-1704) on d99166ade: cli 616/0, every scripts/test-*.sh green, 1201/0 summed by awk; m1-m8 8/8 killed. Correction: the process sweep after the gate found an orphaned sleep 60 from the lock test's flock holder (N1); 08db6ac3f fixes it test only, Sage ruled the gate stands (sage-1707), rerun c0 20/0 and m1 killed with 0 left (sage-1708). Tip 1a1dc80ca (pushed, seat branch only). Manifest 464ce9eb (7 paths), queue revs 2644 and 2647, request comment 29901, reviewer Filbert. Packet agents/darkwing/work/queue-233/BUILD.md.
|
||||
2026-10-21T06:37:41Z | Darkwing | row 240 #1746 installer I4 build, round 1 in review | Before: root had no host check for the bwrap AppArmor profile, its pins or a boot unit, and stack-upgrade.sh exited 1 args-failed when the args move after A5 failed, while exit 1 means the old copy runs. After: scripts/case1-hostcheck.sh (seven items, --check, --enforce, --upstream), scripts/case1-pins.sh, mosaic-hostcheck.service and 16 tests; the args move failure exits 5 args-failed, documented in TOOLS.md and run sheet section 6 and tested; run sheet section 3 puts the pinned npm on PATH and names the bin/claude.exe --claude path; sections 8 and 10 have precheck lines. Verification: slot run r1 on 47ec9fe2f failed at the singles (the new N1 test's after hook threw ENOENT after the fixture cleanup removed the root); b45852daa drops the hook; r2 on b45852daa green: singles 16/0 and 21/0, c0 plus M1-M8 8/8 killed, cli 639/0, scripts 585/0. Candidate darkwing/row240-r3 ad1b23ab2 on c771a36f4, manifest 573ece95 (9 paths), revs 2694 and 2695, comment 29943.
|
||||
2026-10-21T09:00Z | Herb | row 215 C2-04 implementation started | Before: business files reject library entries and root consumers assume code projects; the organization writer can change all project mappings. Plan: approved manifest 2522025af on C2-01 a2c72ac95, Filbert reply to herb-0056, scope sage-1848/1852/1860. Focused slot sage-1869 observed expected red mapping and M9 cases, then 14/0 green for new T1/T2 cases, no skips; clear herb-0062 with empty test/fixture process scan. After that clear, T3/T4 tests and host-only mirror/bus implementation continue under sage-1874, unrun while Sage holds the slot. Full singles, suites and implementation review remain pending. No source commit, push or live change.
|
||||
2026-10-21T13:29Z | Herb | row 215 C2-04 source verified for candidate review | Before: business code assumed every project had a root and organization writes could replace project mappings. After: library mappings load without agent checkouts or publish grants, project mappings are protected before and after serialization, host-only bare mirrors share a bounded publication lock with sync, and library.file/library.status are human-only async bus reads. Base f8276c5eb preserves all nine landed overlaps. Granted sage-2008 whole singles: 16 files, 451/0, no skips or cancellations, ended 13:27:27.279728Z; all source hashes unchanged, process scan empty, no own-path drift through 8a04f4aa4. Full landing gate and implementation review remain pending; no HTTP, sync writer or live change.
|
||||
|
||||
2026-10-20 19:09:44 UTC | Gander row 196 #1694 design phase | Before: tester TCP reaches every local uid and human proofs do not bind the socket peer. After: design draft at agents/gander/work/queue-196/DESIGN.md inventories listeners, proposes private tester HTTP and SO_PEERCRED binding, aligns the per-request principal contract with Morgana and Gizmoduck, and lists migration, tests, mutants and same-uid limits. Python versus other credential options and Console provenance require Duckworth ruling. Documentation only. No product code, suite, live probe, secret access or deployment.
|
||||
|
||||
2026-10-20 19:16:20 UTC | Gander row 196 #1694 design r2 | Before: Duckworth r1 requested concurrent helper-fd evidence (B1) and selected O1 with interpreter, proof-only and image conditions. After: design adds eight concurrent genuine proof processes plus a racing copier, M20 swapped socket and post-helper socket survival, root-owned system ELF pinning and activation evidence, safe gid validation, cap traffic without helpers, and unchanged P19 R2 text. Mos accepted socket-only tester access (mos-1015 via sage-1363); any authenticated browser relay is a separate row. Documentation coverage checks passed. No product code, suites or live action.
|
||||
|
||||
2026-10-20 19:21:19 UTC | Gander row 196 #1694 design approval and N5 | Before: Duckworth approved r2 (duckworth-0009, cb6d840df) with a nonblocking interpreter-upgrade note. After: r3 chooses startup safety revalidation, appends actual interpreter identity to bus/peercred-starts.jsonl and retains old activation evidence. Operator re-pin uses the next reviewed copy, respecting already-active refusal. Added task-by-task PLAN.md for inline implementation and independent manifest review. Documentation checks passed. No product code, suites or live action.
|
||||
|
||||
2026-10-20 19:34:28 UTC | Gander row 196 build paused at design mismatch | Before: approved design promised Unix tester cleanup only for the owned inode. After: scratch test shows Node/libuv close unlinks a replacement inode before JS close handlers. Evidence agents/gander/work/queue-196/evidence/tester-cleanup-blocker.txt. Sent Sage/Duckworth gander-0016/0017, recommending explicit same-uid residual with private 0700 parent retained. Interpreter, concurrent peer, principal, human, peer-transport, transport, tester and process single files passed. Partial code uncommitted, tester transport not wired. No suites, mutant batches or live actions.
|
||||
|
||||
2026-10-21 18:45 UTC | Gander row 196 preservation before rebase | Sage-2051, Mos order mos-1193, explicitly authorizes commit and fast-forward push of the current build before deferred full verification. Product and evidence preserved together; prior focused checks and stopped gates are recorded in the row196 packet, with no claim of full acceptance. Next: rebase onto a36523713 on new gander/row196-r2, report range-diff/patch-id/conflicts, then await Sage's clear for M1-M29 and all requested suites. No live action, force push, branch deletion or tests during hold.
|
||||
|
||||
2026-10-21T21:11:44Z | Della mos-1213 / Vikunja 460 planning phase | Before: PRD 1.10 has no email feature; MP 95b0298 and EP 7a64921 are read-only prior inputs. Scope: independent post-v1 email plan on della/email-plan, no implementation/live access/MVP or queue changes. Gitea issue enrollment belongs to Mos/Sage because this seat has no API credential.
|
||||
|
||||
2026-10-21T21:12:18Z | Della mos-1213 / Vikunja 460 planning verification | After: docs/plans/2026-10-21_email-plan-della.md is 341 lines, with 13 post-v1 rows and six Jason questions. Verified 42 pinned citation anchors, ten requested coverage areas, identical prior src trees, append-only records, clean whitespace and repository queue guard. No configured CI pipeline or CI-queue wrapper found in the current foundation; documentation-only validation applies, no product suites or live tests run. Phase B/C and Gitea issue/queue enrollment remain with Mos/Sage. Only della/email-plan is authorized for push.
|
||||
|
||||
2026-10-21T21:37:07Z | Della mos-1220 / Vikunja 460 phase B cross-review | Before: independent plans Della 191dff32f and Ludwig 4a27b73ac delivered. After: docs/plans/2026-10-21_email-review-by-della.md reviews all 218 Ludwig plan lines, records ten findings, five grafts, six retained strengths, nine disagreements and eleven merged Jason questions. Ludwig review 143415779 read in full after ludwig-0002 arrived; reconciliation records new mail-access action, no agent reroute and correction of Della dataRoot credential example. Original plan unchanged. Planning only, no product/MVP/queue/live change.
|
||||
|
||||
2026-10-21T21:43:02Z | Della mos-1223 / Vikunja 460 phase C synthesis | Before: independent plans/reviews complete, Mos selected Della base. After: docs/plans/2026-10-21_email-plan.md merges Ludwig grafts and accepted corrections, with 16 post-v1 rows (eight READY, eight WAIT/optional), eleven deduplicated Jason questions, per-row test paths and explicit Q210 non-v1 scheduling. Original Della plan/review preserved; Ludwig originals remain on their branch. Static checks cover graft/row/question/citation anchors and original blobs. No source code, suite, mailbox, secret file, service, MVP or queue change. Candidate goes to Ludwig before Sage landing/queue handoff, copying Mos.
|
||||
|
||||
2026-10-21T21:45:20Z | Della mos-1223 / ludwig-0004 focused corrections | Before: b096a16cc left content-key location implicit and E05 core registration marked ready. After: merged plan 399 lines fixes external configDir secret key/lifecycle namespace outside dataRoot backup/restore, E01 schema and E03 missing/expired-key restore tests, and E05/E06 test-local registry readiness with core kinds.mjs registration gated on approved E01/Q4. Sixteen rows and eleven questions retained; originals unchanged. Focused static checks and queue guard apply, no product/live changes. Reviewer will check changed lines only.
|
||||
|
||||
+17
-1
@@ -75,7 +75,8 @@ session's workspace and its own process group. Same contract, plus:
|
||||
| `MOSAIC_POLICY_FILE`, `MOSAIC_TOOLS_FILE` | The bundle's gate policy and typed tools. |
|
||||
| `MOSAIC_TOOL_SOCKET` | The runner's tool socket, which the typed tools call. |
|
||||
| `MOSAIC_TURN_MARKER` | `pi`: the extension writes it at `agent_end`; a pi turn that exits 0 without it failed. |
|
||||
| `MOSAIC_EXTENSIONS` | `pi` only: extension files loaded with `-e`; a missing one exits 2. |
|
||||
| `MOSAIC_EXTENSIONS` | `pi` only: extension files loaded with `-e`; a missing one exits 2. The pi module names two: the gate and typed tools extension, then the unslop check's `tools/unslop-hook/extension.ts` (row 66). |
|
||||
| `MOSAIC_UNSLOP_LOG` | The unslop check's JSONL log, `<run>/unslop.jsonl`, which the runner sets for both adapters and reads after each turn (row 66). |
|
||||
| `MOSAIC_CLAUDE_SETTINGS`, `MOSAIC_CLAUDE_MCP_CONFIG` | `claude` only: the bundle's gate hook and MCP server; required. |
|
||||
| `MOSAIC_THINKING` | The route's thinking level (row 65), which the harness module's `levels()` already checked. `pi` passes `--thinking` (`off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`) and omits it when unset, as for `run-task.sh` workers. `claude` passes `--effort` (`low`, `medium`, `high`, `xhigh`, `max`) and requires it; unset exits 2. |
|
||||
| `MOSAIC_CLAUDE_BIN` | `claude` only: absolute path of the CLI to run, from the host's environment (the bus unit pins it). Unset or empty runs `claude` from `PATH`; a relative path or a non-executable file exits 2. |
|
||||
@@ -110,3 +111,18 @@ argument, which Linux caps at 128 KiB; row 213 passes the file instead, so no
|
||||
local user reads the prompt in `/proc/<pid>/cmdline`. Pi 0.85.1 uses the path
|
||||
string itself as the prompt when the file is missing or can't be read, so the
|
||||
pi adapter exits 2 unless the path is a readable regular file.
|
||||
|
||||
### The unslop check (row 66)
|
||||
|
||||
Both adapters run the mechanical writing check from `tools/unslop-hook`,
|
||||
driven by one `lists.json`. `pi` loads it as its second `-e` extension.
|
||||
`claude` runs `claude-hook.js` from the bundle's `settings.json`: the Stop
|
||||
hook checks the turn's replies, and the UserPromptSubmit hook adds the
|
||||
correction notice as context on the next turn when the last reply had
|
||||
tells. Each hook command ends `; exit 0`, so neither blocks. Both log to
|
||||
`MOSAIC_UNSLOP_LOG`, and the runner adds a note for the operator to the
|
||||
next RESULT it sends (`packages/harness/README.md`, the runner). The
|
||||
harness modules mount the three files read-only at their own paths, and
|
||||
the manifest records their digests. `MOSAIC_UNSLOP_HOOK` and `UNSLOP_LISTS`
|
||||
aren't in the session environment's allowlist, so a managed session can't
|
||||
switch the check off or swap its lists.
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
# Row 250 build notes (Gizmoduck)
|
||||
|
||||
Vikunja #450, Mos ruling mos-1182 item 3. Brief: docs/plans/2026-10-21_k12-cohort-events.md. Reviewer
|
||||
Filbert, gate owner Sage. Branch gizmoduck/row250 from origin/refactor 3b0aef995. Line numbers below are on
|
||||
this branch unless a commit is named.
|
||||
|
||||
## Step 1
|
||||
|
||||
cbba6ff07 changes only the K12 assertion (packages/conversation/tests/cohort.test.mjs:292 on 3b0aef995).
|
||||
On failure it prints the shim's answer, with `ok` and `unavailable`, and `h.ctrl.evidence.releases`.
|
||||
|
||||
## Step 2: the cause
|
||||
|
||||
K12 reads the shim after the controller has started to release it.
|
||||
|
||||
- The force stop sets the binding `stopped` (packages/conversation/src/controller.mjs:1615). Then it pauses at
|
||||
`scope-release` (:1623) and calls `#releaseScope` (:1624).
|
||||
- `#releaseScope` calls `releaseCohort` (:1639). That sends `hello`, then `release`
|
||||
(packages/conversation/src/cohort.mjs:261-265).
|
||||
- The shim answers `release` and exits 10 ms later. It unlinks its socket first (shim.mjs:165-176). systemd
|
||||
then collects the empty scope, `engine` included.
|
||||
- K12's `forceStop` helper returns once it sees `stopped` (cohort.test.mjs:148, polling every 10 ms). The
|
||||
test then reads `engine/cgroup.freeze` (:281 on 3b0aef995) and asks the shim for `events` (:291).
|
||||
|
||||
Nothing in K12 orders those reads before the release. Unloaded, the test usually sends its `events` request
|
||||
within the 10 ms before the shim exits, so it passes. Under load the release wins. `shimRequest` then
|
||||
returns `{ ok: false, unavailable: "the shim socket is gone" }` (cohort.mjs:46), or "unreachable" or
|
||||
"closed the connection" (:62-63), and `ev.populated` is undefined. Both recorded failures fit this
|
||||
pattern:
|
||||
|
||||
- Row 197 proof 4, pair1-b: K12 failed in 339 ms on `undefined !== 0` at :292. 339 ms is far below the
|
||||
3 s `shimRequest` timeout (cohort.mjs:56), so the request didn't time out. The `cgroup.freeze` read at
|
||||
:281 passed, so the scope still existed then.
|
||||
- BUILD-LOG.md:4092, row 56's gate: "`populated` undefined with load around 12".
|
||||
|
||||
Row 50 (a9cc522a0, #1536) added the release after a proven stop. K12 is older. Its comment still says
|
||||
"the shim holds the scope", and that stopped being true in row 50. E1 (cohort.test.mjs:923-925) already
|
||||
holds `scope-release` so it can read the shim while the shim still answers. K12 never got the hold. No
|
||||
other test reads the shim after a proven stop and expects an answer. R1 expects the shim gone, R3 is an
|
||||
uncertain stop, and K15 reads before its stop.
|
||||
|
||||
The cgroup read itself has no race. The kill's `waitFor` (shim.mjs:117-126) had already read `populated 0`
|
||||
for the stop to be proven. The read is the shim's call to `events()` (shim.mjs:83-96), and it reads one
|
||||
kernel file. So the brief's allowance for a bounded retry doesn't apply, and there is none.
|
||||
|
||||
The fix goes in the test's setup, which the brief allows ("Use the shim, the cohort controller or the
|
||||
test's setup and teardown, whichever the evidence points to"). The controller's release is correct and
|
||||
specified (README "Scope release", R1). Delaying it for a reader would change row 50's behavior.
|
||||
|
||||
## Step 2: the change
|
||||
|
||||
packages/conversation/tests/cohort.test.mjs, K12:
|
||||
|
||||
- It runs with `gate()`, holds `scope-release` before the stop, and waits until the hold is reached. Then it
|
||||
does every read that needs the scope: `cgroup.freeze`, `events` and `members`.
|
||||
- After the reads it lets the release go and asserts one entry, `["force-stop", "released"]`. This is new
|
||||
coverage: K12 now also shows the forking cohort's scope released.
|
||||
- The assertions are unchanged. `populated` must be 0 and the member list must be empty. The step 1 message
|
||||
stays.
|
||||
|
||||
packages/conversation/src/shim.mjs:167-168, `release` (:167 on 3b0aef995). It answered a failed `events()` with "the engine
|
||||
cgroup is not empty", so it reported unavailable as not empty. The refusal was already safe, but the reason
|
||||
was false. Now an `events()` answer that isn't `ok` is returned as it is, with the read's own reason. Only
|
||||
`populated` 1 gives "not empty". Nothing else matched that string (grep of packages/).
|
||||
|
||||
## Tests
|
||||
|
||||
- K12 as above.
|
||||
- R13, the brief's new case, placed after R3. After a proven stop, with `scope-release` held, the test makes
|
||||
`engine/cgroup.events` mode 000. Then:
|
||||
- `events` returns `ok: false`, has no `populated`, and the reason is "engine/cgroup.events unreadable
|
||||
(EACCES)".
|
||||
- On release, the controller records one entry `["force-stop", "unavailable", <that reason>]`.
|
||||
- The unit stays active, and the shim still answers `hello`.
|
||||
|
||||
Then `close()` reuses the stop's release, so there is still one entry. The `finally` closes the
|
||||
controller again (a second close is a no-op), restores mode 444, the kernel's mode for cgroup.events,
|
||||
and releases the scope. On
|
||||
3b0aef995's shim.mjs, R13 fails on the reason, because it reads "the engine cgroup is not empty".
|
||||
- K15 already covers a stop, as opposed to a release, with `events` unavailable: the shim gone, the file
|
||||
mode 000, or `engine` missing, each ending `uncertain` with its reason.
|
||||
|
||||
## File added beyond the brief
|
||||
|
||||
packages/conversation/README.md:599 listed "R1–R3, R5–R12" for cohort.test.mjs. With R13 it now reads
|
||||
"R1–R3, R5–R13". The brief's files don't include the README. Sage added it to this row in sage-2082.
|
||||
|
||||
## Runs
|
||||
|
||||
None yet. They need Sage's slot. Sage's sage-2082 says the run is on the pushed candidate in a clean
|
||||
worktree, and that it adds the control-board suite whole, so it counts as the gate run.
|
||||
|
||||
## Round 2
|
||||
|
||||
Filbert's C1 (#1755 comment 30125): R13 never closed its in-process controller, so the controller's
|
||||
socket server (controller.mjs:548) stayed open, and `reap` only kills units and engines. Only `close()`
|
||||
closes it (:1789). R13 now calls `h.ctrl.close()` after its checks and asserts one release entry, as R2
|
||||
does. Its `finally` also closes the controller, for a failure partway through. The second close is safe:
|
||||
`server` is null by then (:1791), and `#releaseScope` returns the cached release (:1634-1648). Branch
|
||||
gizmoduck/row250-r2, on e9cfd92f8.
|
||||
@@ -0,0 +1,399 @@
|
||||
# Row 215 build record
|
||||
|
||||
Owner: Herb. Reviewer: Filbert. Claim: herb-215-start, rev 2753.
|
||||
Brief: docs/plans/2026-10-20_case2-rows.md, C2-04, pin
|
||||
16847e94ae1768881711318fe81cbb5e6c66b971. Design: Gosalyn r11,
|
||||
sections 1.1, 1.3, 2.1, M4, M9 and 7.2.
|
||||
|
||||
Base: a2c72ac952df94ecab7e391d5042f49b7f88b816, row 212's reviewed
|
||||
candidate, under Q177. Branch: herb/row215. Rebuild on the combined 212+197
|
||||
landing when Sage names it. Do not replay or revert landed changes.
|
||||
|
||||
## Scope rulings (sage-1848)
|
||||
|
||||
1. Add packages/bus/src/runtime.mjs for library adapter injection and the
|
||||
library skip in protectedRoots. The skip has its own consumer test. Change
|
||||
nothing else there.
|
||||
2. Add packages/library/src/mirror.mjs, named mirror rather than store. It
|
||||
creates a bare mirror without a remote, reads at the served commit and
|
||||
reads sync state. Export one state filename constant, and export this
|
||||
module through packages/library/src/index.mjs. Row 222 imports the constant.
|
||||
3. Add packages/bus/src/server.mjs only to await library.file and
|
||||
library.status, with socket tests proving their replies are results, not {}.
|
||||
4. HTTP exposure is deferred. Row 225 owns the library.status route;
|
||||
C2-11b owns library pages. Leave serve.mjs alone. webui/src/cli.mjs gets
|
||||
only callback wiring next to the project-file callbacks on both listeners.
|
||||
5. Reuse existing refusal codes where possible.
|
||||
6. Build on a2c72ac95 until Sage supplies the 212 landing SHA.
|
||||
|
||||
Additional ruling, sage-1852: library-state-invalid is approved for malformed,
|
||||
unsafe or mismatched state, including a missing file while the served ref
|
||||
exists. The version-1 shared contract below is approved. Row 222 also owns
|
||||
runtime.mjs for its sync and timer wiring, recorded in that row's manifest.
|
||||
|
||||
Additional rulings, sage-1860, after Filbert's CHANGES on 6a508804f:
|
||||
|
||||
- B1 adds packages/cli/src/config.mjs and cli/tests/trackers-boot.test.mjs.
|
||||
trackerFor skips library entries. A real bus boot with tracker.baseUrl and
|
||||
a library entry succeeds and gets no tracker from that entry.
|
||||
- B2 refuses a role publish grant naming a library project in the loader.
|
||||
- B3 readers use the sync lock. mirror.mjs exports withLibraryLock, with a
|
||||
5000 ms wait bound and library-sync-busy on timeout. Sync locks only the
|
||||
served-ref move and state publication, never the fetch.
|
||||
- N3, git-socket doPush/recordPush accepting a library ID, is a later row.
|
||||
Sage records it in DEFERRED.md when 215 lands. No fix here.
|
||||
|
||||
## Shared contract with row 222
|
||||
|
||||
Agreed in herb-0048, megavolt-0081/0082 and sage-1852. This section is the
|
||||
contract Filbert reviews and Megavolt cites for Dewey. It is not a sync writer.
|
||||
|
||||
Module: packages/library/src/mirror.mjs. Export
|
||||
`SYNC_STATE_FILE = 'mosaic-library-sync.json'`. The full path is
|
||||
`join(mirror, SYNC_STATE_FILE)`, inside the bare repository. Only sync.mjs
|
||||
writes it, using a sibling temp file, fsync, rename, and directory fsync.
|
||||
|
||||
Version 1 has exactly these keys:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": 1,
|
||||
"branch": "main",
|
||||
"served": null,
|
||||
"lastFetch": null,
|
||||
"lastError": null,
|
||||
"diverged": null,
|
||||
"problems": []
|
||||
}
|
||||
```
|
||||
|
||||
- branch is the configured mapping branch and must match the reader's branch.
|
||||
- served is null or a full lowercase 40-hex commit ID. refs/heads/served is
|
||||
authority. The state value must equal that ref, which must name a commit.
|
||||
- lastFetch is null or a canonical ISO UTC timestamp.
|
||||
- lastError is null or exactly {code, at}. code matches [a-z-]{1,64}; at is
|
||||
canonical ISO UTC. It never holds stderr, prose or a credential value.
|
||||
- diverged is null or exactly {commit, at}, with the same commit/time rules.
|
||||
- problems uses C2-01's exact {code, path, message, line?}. code is R1-R7,
|
||||
message is that code's fixed RULES text, line is a positive safe integer
|
||||
when present. No file body or arbitrary message is accepted.
|
||||
- An absent file and absent served ref return the empty object above with
|
||||
the configured branch. An absent file with an existing served ref refuses.
|
||||
- Unknown keys, bad types, unsafe filesystem metadata, invalid JSON and a
|
||||
mismatch refuse library-state-invalid. Reads use a bounded regular owned
|
||||
private file without following links. The read never repairs state.
|
||||
- refs/remotes/library/<branch> is not duplicated in this file. Row 222 may
|
||||
read it when it needs the fetched tip.
|
||||
|
||||
Exports consumed by row 222:
|
||||
|
||||
| Export | Contract |
|
||||
| --- | --- |
|
||||
| mirrorPath({business, project, dataRoot}) | Require a library entry; return projectRepo's checked path |
|
||||
| ensureMirror(context) | Promise of the mirror path; race-safe idempotent bare init; no remote or fetch |
|
||||
| servedCommit(mirror) | Promise of full commit ID or null; refs/heads/served only |
|
||||
| readSyncState(mirror, {branch}) | Promise of checked version-1 state; compare with served ref |
|
||||
| withLibraryLock(mirror, operation) | Await the same exclusive lock as readers, then await operation({readSyncState}); always release |
|
||||
|
||||
The lock is a stable private regular file, mosaic-library-sync.lock inside
|
||||
the mirror. It is never unlinked. A kernel flock is held by the caller's
|
||||
file descriptor. Acquisition waits at most 5000 ms and refuses
|
||||
library-sync-busy on timeout. Unsafe lock metadata refuses library-state-invalid.
|
||||
|
||||
There is no fs.flock API. The exact protocol is: open the stable file with
|
||||
O_NOFOLLOW, check regular/private/owned/single-link metadata, pass its fd as
|
||||
child FD 3 to `flock --exclusive --wait 5 --conflict-exit-code 75 3` using
|
||||
asynchronous spawn, await
|
||||
that child's exit 0, then run the callback while the parent still holds its
|
||||
original descriptor. Both descriptors share the open file description, so
|
||||
the lock survives acquisition-child exit. Finally close the parent's fd.
|
||||
Process death also closes it. No holder child stays alive in the callback,
|
||||
no stale file is deleted, and unrelated operation children inherit only 0-2.
|
||||
Acquisition never uses spawnSync: the bus must serve other calls while a
|
||||
library reader waits (megavolt-0087).
|
||||
|
||||
A scratch-only probe on node v26.8.1 at 2026-10-21T08:34:00Z confirmed this:
|
||||
acquisition child exited 0; a second flock -n returned 1 while the parent fd
|
||||
stayed open; after closeSync it returned 0. The probe removed its own root.
|
||||
This was a design probe, not a package test, suite, Docker command or proof.
|
||||
|
||||
readSyncState takes that lock around reading the served ref and state file.
|
||||
The callback-scoped readSyncState({branch}) supplied by withLibraryLock reads
|
||||
under the already-held lock and does not reacquire it. The helper awaits
|
||||
asynchronous callbacks and releases in finally. A callback-scoped reader
|
||||
used after its callback ends refuses; it cannot escape its lock lifetime.
|
||||
|
||||
Row 222 fetches without this lock, then calls withLibraryLock across the
|
||||
served-ref move and atomic state write. Its tests hold publication between
|
||||
those steps and prove a concurrent reader waits, then sees the new consistent
|
||||
pair, including first sync. Row 215 tests that publication shape and timeout.
|
||||
A file read releases the lock after snapshotting a consistent served SHA,
|
||||
then reads that immutable commit. Row 222's separate outer sync lock spans
|
||||
fetch to prevent two sync operations interleaving (megavolt-0086).
|
||||
|
||||
Host adapter exports for this row:
|
||||
|
||||
- libraryStatus(context): return {project, ...state}, with no repository path
|
||||
or content. Do not fetch or rebuild on this read.
|
||||
- readLibraryFile({...context, path}): read a mapped, readable file at the
|
||||
served commit, returning {project, path, commit, content}. No caller-picked
|
||||
commit, working-tree fallback, fetch or write. C2-01's R1/R2/R7 exclusions
|
||||
apply. A never-synced mirror refuses library-commit for a file read.
|
||||
|
||||
Row 222 owns syncCommand, sync, writeSyncState, its outer sync lock, the timer
|
||||
and state publication. Row 215 owns the shared publication/read lock per
|
||||
sage-1860. Sync rebuilds problems with existing readLibrary({repo, commit,
|
||||
mapping}). It does not need a second rebuild function from this row.
|
||||
|
||||
## Root consumer audit and reviewer notes
|
||||
|
||||
On a2c72ac95, ran exactly the sage-1860 audit:
|
||||
`git grep -n 'entry\.root\|\.root)' -- 'packages/*/src/*.mjs'`.
|
||||
It has 14 hits. runtime.mjs:95, business/cli.mjs:61,72,78,118,
|
||||
instance-settings.mjs:142-143, resolve.mjs:44, cli/config.mjs:62-63 and
|
||||
project/paths.mjs:42 all get the library guard in this row. business.mjs:233
|
||||
and :242 are code-project validation after the library dispatch, not an
|
||||
unguarded consumer. queue.mjs:1144 compares queue genesis roots and never
|
||||
iterates business.projects; it is safe and unchanged. A second search for
|
||||
projectFilePath/business.projects/b.projects found no additional root reader.
|
||||
ensureCheckouts destructures root rather than spelling .root; its guard and
|
||||
the launcher's filter remain in T1. Bare projectFilePath/loadProject remain
|
||||
strict and unchanged.
|
||||
|
||||
Filbert N1 is handled at the existing owned paths.mjs boundary: projectRepo
|
||||
defaults to record-project use and refuses a library entry with project-invalid.
|
||||
Only mirrorPath's internal call opts into allowLibrary. Thus ordinary human
|
||||
and tester project init cannot occupy an uninitialized library mirror path.
|
||||
No record API or bus argument exposes that internal option.
|
||||
|
||||
Filbert N2: ensureMirror failure refuses bus boot. No socket becomes ready.
|
||||
The runtime closes resources it opened, following its existing failure path.
|
||||
A T4 test uses an unsafe/pre-existing mirror and proves the refusal, rather
|
||||
than serving a half-configured library adapter.
|
||||
|
||||
## Verification record
|
||||
|
||||
Planning stage. No product code, package test, suite, image build, live operation
|
||||
or push for row 215 has happened. Product implementation awaits Filbert's
|
||||
manifest approval. Sage owns suite and full-gate grants. Row 197's proof
|
||||
commit is separate and is not part of this row's changes.
|
||||
|
||||
## Implementation ledger
|
||||
|
||||
Plan: agents/herb/work/queue-215/MANIFEST.md at 2522025af, approved by
|
||||
Filbert in the reply to herb-0056. Execution is inline by Herb under the
|
||||
executing-plans and test-driven-development skills. No agent delegation.
|
||||
|
||||
Pre-flight: T1's validated mapping feeds T2's protected document and T3's
|
||||
mirror context; T3's lock/state helpers feed T4's injected host adapter.
|
||||
The shared contract is pinned above, with no interface conflict found.
|
||||
|
||||
Sage-1867 overrides COMMON's singles allowance: every test and executable
|
||||
probe needs an explicit slot grant. No further probe/test has run since
|
||||
that reminder. Read-only inspection and test authoring continue while the
|
||||
slot is held. The first red execution is pending; product code is unchanged.
|
||||
|
||||
Filbert's approved-manifest build notes: ensureMirror creates the lock in
|
||||
its staged directory before publication; a missing lock in an existing
|
||||
mirror refuses library-state-invalid. The top-level metadata allowlist
|
||||
permits only normal bare Git entries plus the state and stable lock files.
|
||||
Tests cover an unknown entry. The host needs /usr/bin/flock; ENOENT yields
|
||||
a handled library-state-invalid refusal, never an unhandled child error.
|
||||
Lock acquisition uses /usr/bin/flock directly and asynchronous spawn.
|
||||
|
||||
T1: consumer and loader regression tests authored, not run. T2: direct M9
|
||||
write and serialization regression tests authored, not run. No completion
|
||||
or passing claim is made for either task.
|
||||
|
||||
Update, sage-1869 focused slot, 2026-10-21T08:47:48Z to 08:51:07Z:
|
||||
the busy check was CLEAR before the first test. T1's mapping regression
|
||||
failed 0/1 on unsupported kind as expected, then passed 2/0 with the publish
|
||||
refusal included. Other focused greens: business CLI 1/0, resolver 1/0,
|
||||
instance settings 1/0, seat checkout 1/0, project paths 1/0, sandboxed launcher
|
||||
1/0, and trackers-boot whole 2/0. T2's direct writer case failed 0/1 on the
|
||||
missing refusal, then its whole new file passed 4/0. Green total 14/0 with
|
||||
no skips or cancellations. Logs and counts: granted-t1/. The final /proc
|
||||
scan found no test process or fixture cwd/argv reference; its private root
|
||||
was removed. Clear sent as herb-0062. Existing files' other cases have not
|
||||
been run yet, so T1/T2's full-file acceptance is still pending.
|
||||
|
||||
Sage-1874 directs continued authoring and implementation while the landing
|
||||
gate/proof holds the slot. T3/T4 tests were written first. Their initial
|
||||
red runs cannot execute during that hold; implementation proceeds under
|
||||
that owner direction, with no claim of a witnessed red or green for T3/T4.
|
||||
Their baseline red and candidate checks need a later explicit grant.
|
||||
|
||||
Implementation ruling: initialization uses GNU /usr/bin/mv --no-clobber
|
||||
--no-target-directory for its bounded staging rename, rather than Node's
|
||||
renameSync, which could replace an empty directory made by a competing
|
||||
actor. This preserves pre-existing directories and needs no new package on
|
||||
the Linux/coreutils bus host. The host also needs /usr/bin/flock. Neither
|
||||
command has been executed for T3/T4 yet. Publication errors fail closed.
|
||||
Sync-state reads are capped at 8 MiB, including a checked extra byte; an
|
||||
oversized or concurrently changed file refuses library-state-invalid.
|
||||
|
||||
T5 static dependency audit found two partial pinned-copy fixtures that copy
|
||||
business/src but not its newly imported library mapping validator:
|
||||
cli/tests/stack-release.test.mjs:1772 and stack-release-fixture.mjs:309 on
|
||||
the base. Each now includes packages/library/src in the existing copy list.
|
||||
This changes fixture closure only, no assertion or timeout. The complete
|
||||
stack-release file and each test file importing that shared fixture require
|
||||
a later granted single-file run. They are outside the four-file T3/T4 slot.
|
||||
|
||||
Sage-1879 places the four-file T3/T4 focused run after their 212+197 proof,
|
||||
before Gizmoduck, and requires their explicit clear before starting. No run
|
||||
has occurred after herb-0062. Row 197's N7 base-image-tag finding is left to
|
||||
Sage's DEFERRED entry; no row 197 source change is made here.
|
||||
|
||||
|
||||
Focused T3/T4 grant sage-1882, 2026-10-21 09:13-09:18Z: busy check
|
||||
CLEAR. Final whole-file results: mirror 16/0, bus library 6/0, WebUI
|
||||
library-cli 1/0, project-runtime 3/0, all with zero skips/cancellations.
|
||||
Syntax checks passed for the four files and five changed host modules.
|
||||
Logs, all intermediate failures, counts and empty /proc cleanup scan are
|
||||
in granted-t34/. Baseline a2c72ac95: three focused bus cases 0/3
|
||||
(unknown-verb), CLI 0/1 (missing callbacks). Mirror baseline 0/1 is an
|
||||
import refusal for the new module, not a witnessed behavioral red.
|
||||
An initial whole baseline bus attempt left a runtime after its expected
|
||||
failure; its exact runner was stopped, no process remained, and the
|
||||
baseline was narrowed to the three bounded broker/socket cases.
|
||||
Candidate fixture setup errors and a mock-child timeout were corrected
|
||||
before the final whole-file passes. No suite or Docker/image/proof ran.
|
||||
|
||||
Filbert's 09:09 publication note: no dependence on mv -n's skipped-rename
|
||||
exit status across coreutils versions. Save staging dev/ino before mv;
|
||||
only its disappearance plus the same dev/ino at the mirror proves a win.
|
||||
A remaining original staging inode means a loss, requiring a valid winner.
|
||||
Only that owned original staging inode is removed. Numeric no-clobber
|
||||
statuses 0 and 1, including a diagnostic, are tested with a competing
|
||||
winner. Spawn errors, signals/timeouts and inconsistent outcomes refuse.
|
||||
Coreutils must provide atomic --no-clobber --no-target-directory semantics;
|
||||
it need not use any particular skipped-rename status convention.
|
||||
|
||||
|
||||
Landing update: prepared herb/row215-on212 on fefd54e13 (includes row 212
|
||||
landing ee7b2f137), without history replay or stash. Only BUILD-LOG.md and
|
||||
cli/tests/stack-release.test.mjs overlap the a2c72ac95-to-landing change
|
||||
set. BUILD-LOG preserves all landed entries and appends the existing Herb
|
||||
entry. stack-release preserves the landing plus only the library/src copy
|
||||
list addition. No test has run on this landing yet. All further execution
|
||||
requires a Sage grant (supersedes the original COMMON singles rule).
|
||||
|
||||
|
||||
Sage-1979 early singles on fefd54e13, stopped after file10 per sage-1983:
|
||||
- packages/bus/tests/library.test.mjs: 6/0
|
||||
- packages/bus/tests/project-runtime.test.mjs: 3/0
|
||||
- packages/business/tests/business.test.mjs: 18/0
|
||||
- packages/business/tests/cli.test.mjs: 10/0
|
||||
- packages/business/tests/instance-settings.test.mjs: 12/0
|
||||
- packages/business/tests/library-projects-protected.test.mjs: 4/0
|
||||
- packages/business/tests/resolve.test.mjs: 11/0
|
||||
- packages/cli/tests/launcher.test.mjs: 30/0
|
||||
- packages/cli/tests/stack-release-external.test.mjs: 25/0
|
||||
- packages/cli/tests/stack-release.test.mjs: 196/0
|
||||
|
||||
Total315/0, zero skips/cancellations. This is an early read only, not gate
|
||||
evidence for a merged candidate. The sequential driver was paused during
|
||||
file10 so it could not start file11, then terminated after file10 exited0.
|
||||
No file11 log exists. Results/logs are in granted-singles/. Later landed
|
||||
overlaps require a new branch and all16 singles again after their merge.
|
||||
|
||||
|
||||
Current merge preparation per sage-1983/1987: new branch
|
||||
herb/row215-on-f827 on f8276c5eb3ecb0aad353ee65e3dd8f7faac5dd87.
|
||||
Nine landed overlaps are recorded in current-MERGE.json and the exact
|
||||
candidate deltas against the landing are in current-merge-only.patch.
|
||||
Two textual conflicts were resolved manually: Broker keeps hostKeys and
|
||||
adds library; business.mjs keeps CREATIVE_DEFINITIONS and adds checkMapping.
|
||||
The other seven merges preserve the landing plus the original C2-04 edits.
|
||||
All other product/test paths match the early215 tree byte for byte. The
|
||||
landing's BUILD-LOG is preserved and the existing Herb entry is appended.
|
||||
No history replay, stash, force push, branch deletion or source commit.
|
||||
No test/probe/syntax check ran on the merged tree after the slot was cleared.
|
||||
All16 whole singles need a new Sage grant before candidate commit/review.
|
||||
The10 old-base315/0 results are early reads only, never merged gate evidence.
|
||||
|
||||
|
||||
## Source candidate and sage-2008 receipts
|
||||
|
||||
Source commit: e333af4dc7af3a9d3789c8c0db26a0df8bdddfee, on
|
||||
f8276c5eb3ecb0aad353ee65e3dd8f7faac5dd87. SOURCE.json records all30
|
||||
changed source/phase-log paths with blob SHA256 and Git mode. The next
|
||||
commit contains only this packet. No product change follows the tests.
|
||||
|
||||
Sage-2008: start13:15:15.548943Z; end13:27:27.279728Z, 2026-10-21.
|
||||
Each of the16 TEST-FILES.txt files ran whole, sequentially. All451 passed,
|
||||
with0 failed/skipped/cancelled. Per-file outputs are in granted-2008/;
|
||||
EVIDENCE.json records their counts, Node durations and log hashes.
|
||||
|
||||
| File | Pass/fail |
|
||||
| --- | ---: |
|
||||
| packages/bus/tests/library.test.mjs | 6/0 |
|
||||
| packages/bus/tests/project-runtime.test.mjs | 3/0 |
|
||||
| packages/business/tests/business.test.mjs | 19/0 |
|
||||
| packages/business/tests/cli.test.mjs | 10/0 |
|
||||
| packages/business/tests/instance-settings.test.mjs | 13/0 |
|
||||
| packages/business/tests/library-projects-protected.test.mjs | 4/0 |
|
||||
| packages/business/tests/resolve.test.mjs | 11/0 |
|
||||
| packages/cli/tests/launcher.test.mjs | 31/0 |
|
||||
| packages/cli/tests/stack-release-external.test.mjs | 25/0 |
|
||||
| packages/cli/tests/stack-release.test.mjs | 196/0 |
|
||||
| packages/cli/tests/stack-upgrade.test.mjs | 21/0 |
|
||||
| packages/cli/tests/trackers-boot.test.mjs | 2/0 |
|
||||
| packages/library/tests/mirror.test.mjs | 16/0 |
|
||||
| packages/project/tests/project.test.mjs | 15/0 |
|
||||
| packages/seat/tests/checkout.test.mjs | 78/0 |
|
||||
| packages/webui/tests/library-cli.test.mjs | 1/0 |
|
||||
|
||||
All29 product/test hashes equal their pre-run values. The final /proc cwd
|
||||
and argv scan was empty; the private test root was removed. Clear sent
|
||||
as herb-0082 at13:28:38Z. No further runs occurred. No image, Docker,
|
||||
lane, proof or full suite was part of this grant.
|
||||
|
||||
Before commit, checked f8276c5eb..8a04f4aa4 on every215 source path and
|
||||
all16 test paths: no overlap. Row248's grant-executor test is outside them.
|
||||
The current root-consumer grep still returns14 sites, all classified by
|
||||
the earlier audit: business code roots after dispatch, guarded library
|
||||
skips at consumers, and queue's unrelated genesis-root invariant.
|
||||
|
||||
Sage-2016 authorizes the source commit, packet receipts and seat-only push,
|
||||
then Filbert's candidate review. The landing gate stays with Sage. Earlier
|
||||
focused and old-base receipts are archived in granted-t1/, granted-t34/
|
||||
and granted-singles/, with their limits kept above. Full package/shell
|
||||
landing checks and implementation approval remain pending. No HTTP route,
|
||||
remote fetch, sync writer, timer or live operation was added.
|
||||
|
||||
Raw Node error logs retain their original space-only lines. Packet whitespace
|
||||
checks exclude *.log so the recorded output bytes stay unchanged; source and
|
||||
other packet files pass the ordinary diff check.
|
||||
|
||||
## Merge-scoped round 2 after rows 249 and 197 (sage-2054)
|
||||
|
||||
Row197 landed as a36523713 after proof6 passed 8/8 gates. Row249's
|
||||
broker fix is also in this base. Source a6101e21c596e2972ab5a7e3087736075899505e, single parent a3652371338e60187d4e95cee4a0f30f3c8a8f06,
|
||||
is on the new herb/row215-on197 branch. The old branch stays untouched.
|
||||
No force push, branch deletion or stash was used. The merge was clean.
|
||||
|
||||
Only broker.mjs and stack-release.test.mjs changed upstream among the30
|
||||
source/phase-log paths. Both retain every landed hunk. The broker keeps
|
||||
row249's installed flag and hostLineLeft handling. The stack-release test
|
||||
keeps row197's leasePort import, after hook and closed-port lease helper;
|
||||
215 adds only its library fixture copy. The other28 blobs and all modes
|
||||
match the prior source. All30 paths have exactly the same -U0 added and
|
||||
removed lines as f8276c5eb..e333af4dc. BUILD-LOG.md is append-only.
|
||||
|
||||
Stable patch-id, old and new: d191e7e9586cd3b7c18310daacdf0c1fdbc8be01.
|
||||
r2-range-diff.txt reports only the commit message changed (!); its patch
|
||||
is unchanged.
|
||||
r2-MERGE.json records every path; r2-merge-only.patch contains both merged
|
||||
source diffs against the new base. SOURCE.json names the new source.
|
||||
|
||||
Filbert approved round1 in comment30071, rev2897. This round requests
|
||||
merge-only review. The earlier451/0 receipts belong to the prior base;
|
||||
no test, probe, syntax check, Docker command or lane ran in this round.
|
||||
Merged-tree evidence remains pending Sage's explicit clear.
|
||||
r2-TEST-FILES.txt proposes all16 original whole singles plus all66
|
||||
bus test files whose local import closure reaches broker.mjs, deduplicated
|
||||
to80 whole files. This includes shared fixture and runtime imports.
|
||||
Sage's slot and row196 landing gate come first. The full landing gate
|
||||
remains Sage's. No library behavior, assertion or timeout changed.
|
||||
@@ -0,0 +1,261 @@
|
||||
{
|
||||
"grant": "sage-2008",
|
||||
"sourceCommit": "e333af4dc7af3a9d3789c8c0db26a0df8bdddfee",
|
||||
"base": "f8276c5eb3ecb0aad353ee65e3dd8f7faac5dd87",
|
||||
"start": "2026-10-21T13:15:15.548778+00:00",
|
||||
"end": "2026-10-21T13:27:27.279728+00:00",
|
||||
"summary": {
|
||||
"tests": 451,
|
||||
"pass": 451,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"results": [
|
||||
{
|
||||
"file": "packages/bus/tests/library.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 6,
|
||||
"pass": 6,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "01-packages_bus_tests_library.test.mjs.log",
|
||||
"sha256": "c19016583abc936534f41bde26eb39e095496eda944622142b1d18ffd5018bc0",
|
||||
"nodeDurationMs": 359.869493
|
||||
},
|
||||
{
|
||||
"file": "packages/bus/tests/project-runtime.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 3,
|
||||
"pass": 3,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "02-packages_bus_tests_project-runtime.test.mjs.log",
|
||||
"sha256": "f123231042d1562fee6dad3d885ac587967e0287f63603c861d04c1907363530",
|
||||
"nodeDurationMs": 312.717335
|
||||
},
|
||||
{
|
||||
"file": "packages/business/tests/business.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 19,
|
||||
"pass": 19,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "03-packages_business_tests_business.test.mjs.log",
|
||||
"sha256": "ae990ebccf7f21b9b32fd9c25fdd637873251c078e17dd95471b82b548322980",
|
||||
"nodeDurationMs": 199.91256
|
||||
},
|
||||
{
|
||||
"file": "packages/business/tests/cli.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 10,
|
||||
"pass": 10,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "04-packages_business_tests_cli.test.mjs.log",
|
||||
"sha256": "28512dc38e2bce04294048a2f1c7dc7cf0c322028f874d1d35aa83b87570ea54",
|
||||
"nodeDurationMs": 2381.258516
|
||||
},
|
||||
{
|
||||
"file": "packages/business/tests/instance-settings.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 13,
|
||||
"pass": 13,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "05-packages_business_tests_instance-settings.test.mjs.log",
|
||||
"sha256": "146623624012da1399fb4ee3de4c0e13df1af28caae81f4870315a67ac368f8f",
|
||||
"nodeDurationMs": 608.08011
|
||||
},
|
||||
{
|
||||
"file": "packages/business/tests/library-projects-protected.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 4,
|
||||
"pass": 4,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "06-packages_business_tests_library-projects-protected.test.mjs.log",
|
||||
"sha256": "675ae18523218ab70a4addee039f41df6ae08ee414f20527f975a2004dde65b2",
|
||||
"nodeDurationMs": 118.54831
|
||||
},
|
||||
{
|
||||
"file": "packages/business/tests/resolve.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 11,
|
||||
"pass": 11,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "07-packages_business_tests_resolve.test.mjs.log",
|
||||
"sha256": "6557938cb8e6d79617c0ea911a6e0ad7303cf5a4f9dd5a5631c70d093e6b06fe",
|
||||
"nodeDurationMs": 94.022587
|
||||
},
|
||||
{
|
||||
"file": "packages/cli/tests/launcher.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 31,
|
||||
"pass": 31,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "08-packages_cli_tests_launcher.test.mjs.log",
|
||||
"sha256": "c3404f1931595914d469cb00a951a5e1648f7792733c86bddbfa099552e5791c",
|
||||
"nodeDurationMs": 24989.261794
|
||||
},
|
||||
{
|
||||
"file": "packages/cli/tests/stack-release-external.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 25,
|
||||
"pass": 25,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "09-packages_cli_tests_stack-release-external.test.mjs.log",
|
||||
"sha256": "55224b6204d4d05a4cb669fb2845aa4168ab868223c3f341ab026032c47458b4",
|
||||
"nodeDurationMs": 96332.465778
|
||||
},
|
||||
{
|
||||
"file": "packages/cli/tests/stack-release.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 196,
|
||||
"pass": 196,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "10-packages_cli_tests_stack-release.test.mjs.log",
|
||||
"sha256": "3f7430ce1f28482a5b66fc0e7db76969298f0dd32c3793e242bc10110dc44e6e",
|
||||
"nodeDurationMs": 533493.817869
|
||||
},
|
||||
{
|
||||
"file": "packages/cli/tests/stack-upgrade.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 21,
|
||||
"pass": 21,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "11-packages_cli_tests_stack-upgrade.test.mjs.log",
|
||||
"sha256": "d18a3eff64b39a5128ab7e842721748b214dc3037ecc9d2c93c58f023859d695",
|
||||
"nodeDurationMs": 60456.446459
|
||||
},
|
||||
{
|
||||
"file": "packages/cli/tests/trackers-boot.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 2,
|
||||
"pass": 2,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "12-packages_cli_tests_trackers-boot.test.mjs.log",
|
||||
"sha256": "22e56455a6a56c98b02f942ed3d38504e4f8486343235c4035c88b967625bce5",
|
||||
"nodeDurationMs": 502.723687
|
||||
},
|
||||
{
|
||||
"file": "packages/library/tests/mirror.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 16,
|
||||
"pass": 16,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "13-packages_library_tests_mirror.test.mjs.log",
|
||||
"sha256": "def30105a3d561118e360535d9d3129226361f2e7902f316e47c74f65f1c0e47",
|
||||
"nodeDurationMs": 5963.543966
|
||||
},
|
||||
{
|
||||
"file": "packages/project/tests/project.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 15,
|
||||
"pass": 15,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "14-packages_project_tests_project.test.mjs.log",
|
||||
"sha256": "e63ab0d23ab24aa1f1f2c1ea8017e8541f415dcb20dff697a37bb7a6368e174d",
|
||||
"nodeDurationMs": 355.86586
|
||||
},
|
||||
{
|
||||
"file": "packages/seat/tests/checkout.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 78,
|
||||
"pass": 78,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "15-packages_seat_tests_checkout.test.mjs.log",
|
||||
"sha256": "c9e7168f589047b8176ec4ee8d2f03adb9fb68f692b363ba6d0036f670811ede",
|
||||
"nodeDurationMs": 4880.907448
|
||||
},
|
||||
{
|
||||
"file": "packages/webui/tests/library-cli.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 1,
|
||||
"pass": 1,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "16-packages_webui_tests_library-cli.test.mjs.log",
|
||||
"sha256": "1ca5b92bc4f2de9ef6aa7156cdea62742fb9ddf054ebfb56a9548431e0cfec0d",
|
||||
"nodeDurationMs": 191.536271
|
||||
}
|
||||
],
|
||||
"cleanup": {
|
||||
"processes": [],
|
||||
"removed": "/mnt/storage/scratch/gt-j5nm6iqn",
|
||||
"sourceHashesUnchanged": 29
|
||||
},
|
||||
"drift": {
|
||||
"base": "f8276c5eb",
|
||||
"tip": "8a04f4aa4aba493eb89e92aa9e0c34084be7058e",
|
||||
"overlap": []
|
||||
},
|
||||
"earlierRuns": {
|
||||
"granted-t1": "focused T1/T2 red/green on a2c72ac95",
|
||||
"granted-t34": "focused T3/T4 with baseline import refusal and corrected fixture errors recorded",
|
||||
"granted-singles": "old fefd54e13 early315/0, not merged gate evidence"
|
||||
},
|
||||
"mergeRound": {
|
||||
"sourceCommit": "a6101e21c596e2972ab5a7e3087736075899505e",
|
||||
"base": "a3652371338e60187d4e95cee4a0f30f3c8a8f06",
|
||||
"status": "not-run; awaiting Sage clear",
|
||||
"priorReceipts": "sage-2008 receipts apply to e333af4dc on f8276c5eb only"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
# C2-04 library business entry implementation plan
|
||||
|
||||
> Execution: Herb implements in this session using the executing-plans skill.
|
||||
> Filbert approves this manifest before any product implementation.
|
||||
|
||||
**Goal:** Load a library mapping without giving an agent a checkout, protect
|
||||
all project mappings from organization writes, and expose human-only bus
|
||||
reads of the bare mirror's served commit and sync status.
|
||||
|
||||
**Architecture:** C2-01 checks mappings and reads commits. Business consumers
|
||||
skip library entries. A host-only mirror module owns local mirror reads and
|
||||
initialization. runtime.mjs injects that module into the broker, preserving
|
||||
the broker's sandbox import closure. Sync and HTTP routes belong to later rows.
|
||||
|
||||
**Tech stack:** Existing Node ESM, node:test and bounded local Git helpers.
|
||||
No dependencies. node_modules remains the plain canonical symlink.
|
||||
|
||||
**Spec:** Pinned C2-04 brief; Gosalyn's approved design 1.1, 1.3, 2.1,
|
||||
M4/M9 and 7.2; BUILD.md's sage-1848/1852/1860 scope and shared-state contract.
|
||||
|
||||
## Constraints and review focus
|
||||
|
||||
- Base a2c72ac95; rebase only onto Sage's named 212 landing on a new branch.
|
||||
- Existing code-project entries retain root/repo/remote behavior. Library
|
||||
entries have no root or repo override and use C2-01 checkMapping.
|
||||
- Preserve the broker's pinned imports. No library import in broker.mjs and
|
||||
no new runner mount. Do not edit serve.mjs or add an HTTP route.
|
||||
- No fetch, remote config, credential read, timer, sync writer, bus write or
|
||||
live operation. All tests use made-up content and local repositories.
|
||||
- All test/probe runs require Sage's grant (sage-1867), including singles.
|
||||
Stop and report two failures in one gate. Do not push without authorization.
|
||||
|
||||
Review focus, with owning tasks below: library-first iteration must not
|
||||
break a later code project (T1); serialized documents cannot bypass M9
|
||||
(T2); racing initialization must not replace another mirror (T3); stale or
|
||||
unsafe state must not leak content (T3); async socket replies must preserve
|
||||
the result and human-only admission (T4).
|
||||
|
||||
## Paths and evidence from the base
|
||||
|
||||
| Product path | Allowed change |
|
||||
| --- | --- |
|
||||
| packages/business/src/business.mjs | Dispatch kind:library to checkMapping before code-root validation (:228-244) |
|
||||
| packages/business/src/organization.mjs | Compare canonical projects in write before publication (:177 onward) |
|
||||
| packages/business/src/cli.mjs | Skip library roots in validate, resolve --project and credential exclusion roots (:60-61, :71-79, :118) |
|
||||
| packages/business/src/resolve.mjs | Skip library entries while matching a project file (:44) |
|
||||
| packages/business/src/instance-settings.mjs | Skip library before projectFilePath (:142), nothing else |
|
||||
| packages/seat/src/checkout.mjs | Skip library entries in ensureCheckouts (:315-327) |
|
||||
| packages/cli/src/launcher.mjs | Pass only code entries to ensureCheckouts (:354) |
|
||||
| packages/cli/src/config.mjs | Skip library entries in trackerFor's root loop (:61-63), per sage-1860 |
|
||||
| packages/project/src/paths.mjs | Skip library entries in overlap loop (:41-44); default record use refuses library, mirrorPath internally opts into allowLibrary |
|
||||
| packages/library/src/mirror.mjs | New bare init, checked state and served-commit file read module |
|
||||
| packages/library/src/index.mjs | Export mirror module interface and SYNC_STATE_FILE |
|
||||
| packages/bus/src/broker.mjs | New injected library adapter, human-only admission and two async verbs |
|
||||
| packages/bus/src/runtime.mjs | Library adapter wiring, mirror initialization and protectedRoots skip only |
|
||||
| packages/bus/src/server.mjs | Await the two library verbs only |
|
||||
| packages/webui/src/cli.mjs | Two library read callbacks beside project callbacks on main and tester listener; no routes |
|
||||
|
||||
packages/business/src/project.mjs need not change: callers skip a library
|
||||
before projectFilePath or loadProject. Do not weaken their code-root checks.
|
||||
scripts/stack-copy.sh already copies packages/library/src and needs no edit.
|
||||
|
||||
Test paths to modify: business/tests/business.test.mjs, cli.test.mjs,
|
||||
resolve.test.mjs, instance-settings.test.mjs; seat/tests/checkout.test.mjs;
|
||||
cli/tests/launcher.test.mjs, trackers-boot.test.mjs; project/tests/project.test.mjs;
|
||||
bus/tests/project-runtime.test.mjs. All paths are under packages/.
|
||||
|
||||
T5 dependency-audit addition: cli/tests/stack-release.test.mjs and its
|
||||
stack-release-fixture.mjs helper copy packages/library/src alongside
|
||||
business/src, whose validator now imports the mapping checker. No assertions
|
||||
or timeouts change. Whole-file dependent singles require a later Sage slot.
|
||||
|
||||
New tests: packages/business/tests/library-projects-protected.test.mjs;
|
||||
packages/library/tests/mirror.test.mjs; packages/bus/tests/library.test.mjs;
|
||||
packages/webui/tests/library-cli.test.mjs. Reuse existing made-up fixtures.
|
||||
If a new fixture is needed, define it within the corresponding new test file.
|
||||
No unrelated test assertion or timeout changes.
|
||||
|
||||
Record paths: agents/herb/work/queue-215/{MANIFEST.md,BUILD.md}, later source
|
||||
manifest and test receipts there; one append-only BUILD-LOG.md phase for this
|
||||
row when implementation begins. Sage owns docs/SESSIONS.md.
|
||||
|
||||
## T1. Mapping and consumer skips
|
||||
|
||||
- [ ] Add failing business tests: accept a frozen library mapping without a
|
||||
root, retain mixed/only-library documents, and propagate C2-01's mapping
|
||||
and playground refusal codes. A role publish naming a library project
|
||||
refuses at load, even with an otherwise valid fork identity and remote.
|
||||
Existing code validation remains unchanged.
|
||||
- [ ] Add a separate regression for each consumer: CLI validate and its
|
||||
credential exclusion roots; CLI resolve --project books has no project
|
||||
layer; resolveInstance finds a later real project; instance settings still
|
||||
writes an unrelated setting; ensureCheckouts returns no library checkout;
|
||||
launcher creates no books workspace clone; projectRepo skips a library
|
||||
while still rejecting overlap with a real code root. Put books first.
|
||||
- [ ] Add the real bus boot regression in cli/tests/trackers-boot.test.mjs:
|
||||
tracker.baseUrl is set and books is a library entry; boot succeeds, books
|
||||
produces no tracker, and a later real tracker project still works.
|
||||
- [ ] projectRepo(context, {allowLibrary = false} = {}) refuses a library
|
||||
entry by default with project-invalid. Only mirrorPath opts in. Test that
|
||||
ordinary human and tester record initialization leave no directory at the
|
||||
future mirror path; no public verb can supply allowLibrary.
|
||||
- [ ] Add runtime's protectedRoots consumer regression in T4's real runtime
|
||||
fixture. A valid credential outside code/data roots still loads with a
|
||||
library entry, and existing credential protections still refuse unsafe files.
|
||||
- [ ] Run each changed test singly, confirm the new cases fail for the
|
||||
intended root assumption, then implement only the table's guards and
|
||||
checkMapping dispatch. Re-run the same files singly.
|
||||
|
||||
CLI validate reports a library entry as library, without an absent-project
|
||||
warning. CLI resolve --project books resolves without loading a project file,
|
||||
as the design's skip requires. It does not fabricate project vars or a root.
|
||||
|
||||
## T2. M9 at the organization writer
|
||||
|
||||
- [ ] In the new business test file, call organizationWriter.write directly
|
||||
with a changed playground prefix and, separately, a changed hybrid entry.
|
||||
Both refuse organization-projects-protected. Snapshot business bytes and
|
||||
changes.jsonl before each call; assert both remain identical afterward.
|
||||
- [ ] Cover addition, deletion and changes to code projects too, since M9
|
||||
protects all projects. Reordered object keys are allowed; array changes
|
||||
are changes. An ordinary non-project write still succeeds and logs.
|
||||
- [ ] Add a serialization regression so a proposed object's serialized
|
||||
projects cannot differ from those checked before publication.
|
||||
- [ ] Run the file singly to see the missing refusal, compare canonical
|
||||
projects against old disk JSON and the document that actually lands,
|
||||
before any publication/receipt, then re-run it singly.
|
||||
|
||||
## T3. Bare mirror, served file and read-only state
|
||||
|
||||
- [ ] Add failing tests for mirrorPath and ensureMirror: exact projectRepo
|
||||
default, no checkout/remote, retained no-links/overlap protections,
|
||||
idempotence, simultaneous creators and preservation of a pre-existing
|
||||
non-mirror directory or unsafe Git metadata.
|
||||
- [ ] Add failing state tests for BUILD.md's full version-1 contract: missing
|
||||
state/ref, valid state, malformed JSON, unknown keys/types, branch mismatch,
|
||||
invalid times/IDs/problem shape, symlink/hardlink/non-private file and
|
||||
missing or mismatched served ref. Assert reads change no bytes.
|
||||
- [ ] Add shared-lock tests: withLibraryLock(mirror, operation) waits at most
|
||||
5000 ms, refuses library-sync-busy on timeout and releases after a throw.
|
||||
A reader arriving between the publisher's served move and state write
|
||||
waits, then reads the consistent pair. Cover first sync and fast-forward
|
||||
in independent processes, same-process independent acquisitions and
|
||||
release after owner death. A callback-scoped reader expires on release.
|
||||
- [ ] Implement the lock by async spawn of flock on the parent's inherited
|
||||
fd 3, as pinned in BUILD.md. Await acquisition-child exit before calling
|
||||
operation. Never spawnSync during acquisition, which could freeze the bus
|
||||
for 5 s. A parallel ordinary bus read remains responsive while a library
|
||||
read waits. Only the publication/read lock is shared; fetch is outside it.
|
||||
- [ ] Add served-read tests against local fixtures containing spaces,
|
||||
capitals, a .canvas and unmapped top-level note. Seed a served ref and state
|
||||
without fetching. A newer unrelated HEAD does not change the returned
|
||||
file. R1/R2/R7 exclusions, traversal, a missing path, a caller commit and a
|
||||
never-synced mirror refuse. Status contains no fixture body marker.
|
||||
- [ ] Implement mirror.mjs and index exports using the shared contract.
|
||||
Initialization stages into an owned private sibling directory and renames
|
||||
atomically; a losing creator validates the winner and removes only its own
|
||||
staging directory. Git uses existing bounded safe helpers, no remote.
|
||||
- [ ] Run mirror.test.mjs singly, red then green. Re-run C2-01 reader.test.mjs
|
||||
singly if a reader assumption changes. Do not change C2-01 reader rules.
|
||||
|
||||
mirror.mjs validates a bare mirror's metadata before Git reads it, including
|
||||
no remote/include/indirection. It does not apply inspectGit's working-tree
|
||||
.git assumption to a bare repository. Failures reuse library-git or the
|
||||
approved library-state-invalid code. State reads are bounded and private.
|
||||
|
||||
## T4. Human-only bus reads and deferred Console callbacks
|
||||
|
||||
- [ ] Add broker tests for library.file and library.status using injected
|
||||
adapters. Each agent session refuses human-required before adapter access,
|
||||
including bad arguments and an absent adapter. A reader or tester does not
|
||||
gain a human capability. Human calls validate keys, then use checked
|
||||
library context. Secret checking and bounded refusal evidence remain.
|
||||
- [ ] Add real startBroker/socket tests for both verbs. Seed only local
|
||||
fixture mirror data. Assert result shape/content and an actual status
|
||||
field, not merely successful transport or {}. Cover never-synced status
|
||||
and runtime's protectedRoots skip. Keep the pinned import-closure test.
|
||||
- [ ] Inject a separate library adapter via runtime, initialize only library
|
||||
mirrors, add the two async request paths, and include them in server's
|
||||
awaited list. Do not import library or fs into broker.
|
||||
- [ ] Unsafe or pre-existing non-mirror initialization refuses bus boot,
|
||||
closes opened resources and never publishes a ready socket. Add that
|
||||
runtime regression in library.test.mjs.
|
||||
- [ ] Wire main and tester Console callbacks beside project-file callbacks.
|
||||
No HTTP route is shipped. The new CLI test captures the startServer
|
||||
options with a test-only module loader and calls the supplied callbacks
|
||||
against a fixture bus, checking the verb and transport identity. No
|
||||
product test seam, UI page, endpoint or serve.mjs change is needed.
|
||||
- [ ] Run library.test.mjs, project-runtime.test.mjs and library-cli.test.mjs
|
||||
individually, red then green. Human admission may use the existing
|
||||
fixture authentication seam; do not forge or bypass a live identity.
|
||||
|
||||
## T5. Review packet and Sage's gate
|
||||
|
||||
- [ ] Search packages/*/tests and scripts/test-*.sh for each changed source
|
||||
path, imports and 64-hex pins. Record the resulting test-file list and run
|
||||
each changed/touched test singly. Stop and report a scope error.
|
||||
- [ ] Self-review the diff against this manifest and all acceptance cases.
|
||||
Record results, commands, skips, source hashes and remaining limits in
|
||||
BUILD.md. Request Sage's slot for the required business, seat, cli, project,
|
||||
bus and webui suites and every scripts/test-*.sh. Do not run them ungranted.
|
||||
- [ ] After applicable tests are green, make the source commit, build the
|
||||
candidate manifest from the authorized pushed tip, and move the row with
|
||||
scripts/mosaic. Sage posts token-requiring requests; Filbert reviews the
|
||||
candidate. Push only when authorized. No merge or live change by Herb.
|
||||
|
||||
## Self-review
|
||||
|
||||
Every brief acceptance item is in T1-T4. Added host support paths match
|
||||
sage-1848/1860. BUILD.md records the complete 14-hit root audit. State shape
|
||||
and authority match sage-1852; the shared read/publication lock follows
|
||||
sage-1860 and Megavolt's agreement. Fetch, timers, outer sync serialization
|
||||
and HTTP stay with their later rows.
|
||||
This is a plan only; no product edits or test execution precede approval.
|
||||
|
||||
|
||||
Landing update: prepared herb/row215-on212 on fefd54e13 (includes row 212
|
||||
landing ee7b2f137), without history replay or stash. Only BUILD-LOG.md and
|
||||
cli/tests/stack-release.test.mjs overlap the a2c72ac95-to-landing change
|
||||
set. BUILD-LOG preserves all landed entries and appends the existing Herb
|
||||
entry. stack-release preserves the landing plus only the library/src copy
|
||||
list addition. No test has run on this landing yet. All further execution
|
||||
requires a Sage grant (supersedes the original COMMON singles rule).
|
||||
|
||||
|
||||
Current merge preparation per sage-1983/1987: new branch
|
||||
herb/row215-on-f827 on f8276c5eb3ecb0aad353ee65e3dd8f7faac5dd87.
|
||||
Nine landed overlaps are recorded in current-MERGE.json and the exact
|
||||
candidate deltas against the landing are in current-merge-only.patch.
|
||||
Two textual conflicts were resolved manually: Broker keeps hostKeys and
|
||||
adds library; business.mjs keeps CREATIVE_DEFINITIONS and adds checkMapping.
|
||||
The other seven merges preserve the landing plus the original C2-04 edits.
|
||||
All other product/test paths match the early215 tree byte for byte. The
|
||||
landing's BUILD-LOG is preserved and the existing Herb entry is appended.
|
||||
No history replay, stash, force push, branch deletion or source commit.
|
||||
No test/probe/syntax check ran on the merged tree after the slot was cleared.
|
||||
All16 whole singles need a new Sage grant before candidate commit/review.
|
||||
The10 old-base315/0 results are early reads only, never merged gate evidence.
|
||||
|
||||
|
||||
Candidate status: source commit e333af4dc7af3a9d3789c8c0db26a0df8bdddfee. The16 whole
|
||||
singles passed451/0 under sage-2008 with zero skips/cancellations; raw
|
||||
outputs and merge receipts are in this packet, indexed by EVIDENCE.json
|
||||
and SOURCE.json. Sage keeps the landing gate. Filbert's implementation
|
||||
review and that gate remain pending. Prior315/0 on fefd54e13 is early
|
||||
read evidence only. Sage-2016 authorizes the seat-only source/packet push.
|
||||
@@ -0,0 +1,157 @@
|
||||
{
|
||||
"sourceCommit": "a6101e21c596e2972ab5a7e3087736075899505e",
|
||||
"base": "a3652371338e60187d4e95cee4a0f30f3c8a8f06",
|
||||
"paths": [
|
||||
{
|
||||
"path": "BUILD-LOG.md",
|
||||
"sha256": "b7c8f906f2db095dfe02d29b4064836af83ae877a87b38c09466b8c9a327e019",
|
||||
"mode": "100644"
|
||||
},
|
||||
{
|
||||
"path": "packages/bus/src/broker.mjs",
|
||||
"sha256": "762234259d72db87aff510751fe14003099759ae37bc8eaf14f1ea1de61d2005",
|
||||
"mode": "100644"
|
||||
},
|
||||
{
|
||||
"path": "packages/bus/src/runtime.mjs",
|
||||
"sha256": "c759e665514a5bcad40536bc9f979837187fe6523462b3c0a0687182885c3ac6",
|
||||
"mode": "100644"
|
||||
},
|
||||
{
|
||||
"path": "packages/bus/src/server.mjs",
|
||||
"sha256": "207c7a76752c753ef7380f18f9ce1a4f23e8fa35142973b6358aaf0c45f44899",
|
||||
"mode": "100644"
|
||||
},
|
||||
{
|
||||
"path": "packages/bus/tests/library.test.mjs",
|
||||
"sha256": "58d839709e005571b398a11abda5a50f542bab0e37bd97b72f43cde926434301",
|
||||
"mode": "100644"
|
||||
},
|
||||
{
|
||||
"path": "packages/business/src/business.mjs",
|
||||
"sha256": "5fd3fee664d3e70153d988b4c1a42406f888a31b3927fa52375e66619d8cec59",
|
||||
"mode": "100644"
|
||||
},
|
||||
{
|
||||
"path": "packages/business/src/cli.mjs",
|
||||
"sha256": "31cfe9090900169416e1207dc6db865b046439273917e9de442add4159c89eb3",
|
||||
"mode": "100644"
|
||||
},
|
||||
{
|
||||
"path": "packages/business/src/instance-settings.mjs",
|
||||
"sha256": "3873411688d927336a909d0299acddeba92a653102c660d276471f5a0f6eebd3",
|
||||
"mode": "100644"
|
||||
},
|
||||
{
|
||||
"path": "packages/business/src/organization.mjs",
|
||||
"sha256": "eaa650499d2d078552a2c0e5b13a6126e0aca02f73160032a7325b3f5aa90964",
|
||||
"mode": "100644"
|
||||
},
|
||||
{
|
||||
"path": "packages/business/src/resolve.mjs",
|
||||
"sha256": "712183465fee099606223d84423afc54e3386a0c8e468c68d5ac39c1e676d109",
|
||||
"mode": "100644"
|
||||
},
|
||||
{
|
||||
"path": "packages/business/tests/business.test.mjs",
|
||||
"sha256": "910f924d90b6f9b18c1f36d97cebd0b7a0a15a080b73530c4fb847bfd435fb3f",
|
||||
"mode": "100644"
|
||||
},
|
||||
{
|
||||
"path": "packages/business/tests/cli.test.mjs",
|
||||
"sha256": "d54ba2338bcdfec22764030cf3ec9e3464ab275b15321d6d1b039169ea37fd85",
|
||||
"mode": "100644"
|
||||
},
|
||||
{
|
||||
"path": "packages/business/tests/instance-settings.test.mjs",
|
||||
"sha256": "072e25c5237e1be4294c7a4a95daa2ab593832786013e1283b19725c330647c1",
|
||||
"mode": "100644"
|
||||
},
|
||||
{
|
||||
"path": "packages/business/tests/library-projects-protected.test.mjs",
|
||||
"sha256": "cfc726ec7bf73c1dc9fc6395cba85e374b7a006bac45bd8c47c969550557147f",
|
||||
"mode": "100644"
|
||||
},
|
||||
{
|
||||
"path": "packages/business/tests/resolve.test.mjs",
|
||||
"sha256": "c74af44a83ee918196e2c1016b62786e757c0ae774c9b1613280d3fbbf3ffb22",
|
||||
"mode": "100644"
|
||||
},
|
||||
{
|
||||
"path": "packages/cli/src/config.mjs",
|
||||
"sha256": "ab7b9f452123b6f7e98f4f59cbb3cc4483fd296e4af5522412410ee53d1b20e0",
|
||||
"mode": "100644"
|
||||
},
|
||||
{
|
||||
"path": "packages/cli/src/launcher.mjs",
|
||||
"sha256": "d8a870d8eb8254adfd576688696705359fefbf517b40e5d7482500bf27941022",
|
||||
"mode": "100644"
|
||||
},
|
||||
{
|
||||
"path": "packages/cli/tests/launcher.test.mjs",
|
||||
"sha256": "99234f247e8414120d2fd214efd590e9d573eca86180d7b775cb506ac1c12c78",
|
||||
"mode": "100644"
|
||||
},
|
||||
{
|
||||
"path": "packages/cli/tests/stack-release-fixture.mjs",
|
||||
"sha256": "86a3c15446d4c119206097c754cd15f5bef7b7e93c9f16e9d8696ec8c475eea9",
|
||||
"mode": "100644"
|
||||
},
|
||||
{
|
||||
"path": "packages/cli/tests/stack-release.test.mjs",
|
||||
"sha256": "46cc95a6e75a89b907cdd5e9bd03853e1d1f75f1ced81084d968c5476466822e",
|
||||
"mode": "100644"
|
||||
},
|
||||
{
|
||||
"path": "packages/cli/tests/trackers-boot.test.mjs",
|
||||
"sha256": "c90493e45bfa09bf0b01600aaf04d6ecd79d939357beacc1a9cd65f958bb7c22",
|
||||
"mode": "100644"
|
||||
},
|
||||
{
|
||||
"path": "packages/library/src/index.mjs",
|
||||
"sha256": "ecda99dea46390b81fffa6f414d56a13737233e01d883b82cd186e0e21b6c4d1",
|
||||
"mode": "100644"
|
||||
},
|
||||
{
|
||||
"path": "packages/library/src/mirror.mjs",
|
||||
"sha256": "75ce08fba0956c846f2ca9ab1b565974657925f94ac952c720e7308783946480",
|
||||
"mode": "100644"
|
||||
},
|
||||
{
|
||||
"path": "packages/library/tests/mirror.test.mjs",
|
||||
"sha256": "e96473be70ece8c8232ce5325822244b593f273371b74b4126920654cde9d72c",
|
||||
"mode": "100644"
|
||||
},
|
||||
{
|
||||
"path": "packages/project/src/paths.mjs",
|
||||
"sha256": "bd9debcf3f9bb92560e74f220a0b108dfe24154bc6d1fb03c5ec414356d451f9",
|
||||
"mode": "100644"
|
||||
},
|
||||
{
|
||||
"path": "packages/project/tests/project.test.mjs",
|
||||
"sha256": "0ebe1862ce70f26c4a6a44304182327f9a6944d16cc87f674fbb1d32e08ac602",
|
||||
"mode": "100644"
|
||||
},
|
||||
{
|
||||
"path": "packages/seat/src/checkout.mjs",
|
||||
"sha256": "859201bd192522e51c33b86ef45f73487b27cdfc48ea7e4e09870e26d056048a",
|
||||
"mode": "100644"
|
||||
},
|
||||
{
|
||||
"path": "packages/seat/tests/checkout.test.mjs",
|
||||
"sha256": "663040d7c737aba6403e6397bacf1325b558cc14df3e5677f0a28f9499c45127",
|
||||
"mode": "100644"
|
||||
},
|
||||
{
|
||||
"path": "packages/webui/src/cli.mjs",
|
||||
"sha256": "e98fd2fe4e621d5b4fa1ed95c4d4585469e7ab7a11dd379dc541dddb1b1a1f02",
|
||||
"mode": "100644"
|
||||
},
|
||||
{
|
||||
"path": "packages/webui/tests/library-cli.test.mjs",
|
||||
"sha256": "1983912b76f01f8e6d0c564e3bbcd763c0b2c44044988b192ef827446f98556c",
|
||||
"mode": "100644"
|
||||
}
|
||||
],
|
||||
"priorSourceCommit": "e333af4dc7af3a9d3789c8c0db26a0df8bdddfee"
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
packages/bus/tests/library.test.mjs
|
||||
packages/bus/tests/project-runtime.test.mjs
|
||||
packages/business/tests/business.test.mjs
|
||||
packages/business/tests/cli.test.mjs
|
||||
packages/business/tests/instance-settings.test.mjs
|
||||
packages/business/tests/library-projects-protected.test.mjs
|
||||
packages/business/tests/resolve.test.mjs
|
||||
packages/cli/tests/launcher.test.mjs
|
||||
packages/cli/tests/stack-release-external.test.mjs
|
||||
packages/cli/tests/stack-release.test.mjs
|
||||
packages/cli/tests/stack-upgrade.test.mjs
|
||||
packages/cli/tests/trackers-boot.test.mjs
|
||||
packages/library/tests/mirror.test.mjs
|
||||
packages/project/tests/project.test.mjs
|
||||
packages/seat/tests/checkout.test.mjs
|
||||
packages/webui/tests/library-cli.test.mjs
|
||||
@@ -0,0 +1,229 @@
|
||||
{
|
||||
"base": "fefd54e13",
|
||||
"landing": "f8276c5eb3ecb0aad353ee65e3dd8f7faac5dd87",
|
||||
"overlaps": [
|
||||
"packages/bus/src/broker.mjs",
|
||||
"packages/bus/src/runtime.mjs",
|
||||
"packages/business/src/business.mjs",
|
||||
"packages/business/src/instance-settings.mjs",
|
||||
"packages/business/tests/business.test.mjs",
|
||||
"packages/business/tests/instance-settings.test.mjs",
|
||||
"packages/cli/src/launcher.mjs",
|
||||
"packages/cli/tests/launcher.test.mjs",
|
||||
"packages/library/src/index.mjs"
|
||||
],
|
||||
"initialConflicts": [
|
||||
"packages/bus/src/broker.mjs",
|
||||
"packages/business/src/business.mjs"
|
||||
],
|
||||
"remainingConflicts": [],
|
||||
"resolutions": {
|
||||
"packages/bus/src/broker.mjs": "retain landed hostKeys constructor parameter and add library parameter",
|
||||
"packages/business/src/business.mjs": "retain landed CREATIVE_DEFINITIONS import and add checkMapping import"
|
||||
},
|
||||
"sourcePaths": [
|
||||
{
|
||||
"path": "packages/bus/src/broker.mjs",
|
||||
"merged": true,
|
||||
"sameAsEarlyTree": false,
|
||||
"earlySha256": "dca11dd58561bf3f399d18d7521aefa93f43e0ee3de9c532c1da073ce5a17466",
|
||||
"sha256": "925b3dd6744565349ec421a58b3374ce3d21181e6c2d3d32ffb99c79271b9450"
|
||||
},
|
||||
{
|
||||
"path": "packages/bus/src/runtime.mjs",
|
||||
"merged": true,
|
||||
"sameAsEarlyTree": false,
|
||||
"earlySha256": "6f69e9fb838cf1d8ee60d1b7090395193d3dbfdc6492a401a4b72c356c371ca9",
|
||||
"sha256": "c759e665514a5bcad40536bc9f979837187fe6523462b3c0a0687182885c3ac6"
|
||||
},
|
||||
{
|
||||
"path": "packages/bus/src/server.mjs",
|
||||
"merged": false,
|
||||
"sameAsEarlyTree": true,
|
||||
"earlySha256": "207c7a76752c753ef7380f18f9ce1a4f23e8fa35142973b6358aaf0c45f44899",
|
||||
"sha256": "207c7a76752c753ef7380f18f9ce1a4f23e8fa35142973b6358aaf0c45f44899"
|
||||
},
|
||||
{
|
||||
"path": "packages/bus/tests/library.test.mjs",
|
||||
"merged": false,
|
||||
"sameAsEarlyTree": true,
|
||||
"earlySha256": "58d839709e005571b398a11abda5a50f542bab0e37bd97b72f43cde926434301",
|
||||
"sha256": "58d839709e005571b398a11abda5a50f542bab0e37bd97b72f43cde926434301"
|
||||
},
|
||||
{
|
||||
"path": "packages/business/src/business.mjs",
|
||||
"merged": true,
|
||||
"sameAsEarlyTree": false,
|
||||
"earlySha256": "e132f92211cd35f951e85ff5e90471a2316755cb35ad7eabf516e780ce6c13ad",
|
||||
"sha256": "5fd3fee664d3e70153d988b4c1a42406f888a31b3927fa52375e66619d8cec59"
|
||||
},
|
||||
{
|
||||
"path": "packages/business/src/cli.mjs",
|
||||
"merged": false,
|
||||
"sameAsEarlyTree": true,
|
||||
"earlySha256": "31cfe9090900169416e1207dc6db865b046439273917e9de442add4159c89eb3",
|
||||
"sha256": "31cfe9090900169416e1207dc6db865b046439273917e9de442add4159c89eb3"
|
||||
},
|
||||
{
|
||||
"path": "packages/business/src/instance-settings.mjs",
|
||||
"merged": true,
|
||||
"sameAsEarlyTree": false,
|
||||
"earlySha256": "04d61c1ec89a5d67da75aede46c3a8e2197aadd63b11bef8e4fc37d90e8862cf",
|
||||
"sha256": "3873411688d927336a909d0299acddeba92a653102c660d276471f5a0f6eebd3"
|
||||
},
|
||||
{
|
||||
"path": "packages/business/src/organization.mjs",
|
||||
"merged": false,
|
||||
"sameAsEarlyTree": true,
|
||||
"earlySha256": "eaa650499d2d078552a2c0e5b13a6126e0aca02f73160032a7325b3f5aa90964",
|
||||
"sha256": "eaa650499d2d078552a2c0e5b13a6126e0aca02f73160032a7325b3f5aa90964"
|
||||
},
|
||||
{
|
||||
"path": "packages/business/src/resolve.mjs",
|
||||
"merged": false,
|
||||
"sameAsEarlyTree": true,
|
||||
"earlySha256": "712183465fee099606223d84423afc54e3386a0c8e468c68d5ac39c1e676d109",
|
||||
"sha256": "712183465fee099606223d84423afc54e3386a0c8e468c68d5ac39c1e676d109"
|
||||
},
|
||||
{
|
||||
"path": "packages/business/tests/business.test.mjs",
|
||||
"merged": true,
|
||||
"sameAsEarlyTree": false,
|
||||
"earlySha256": "55aafd3f0eea816d5f42283b7b74323dd32a698d7b95dd9cc54529dbf7b16058",
|
||||
"sha256": "910f924d90b6f9b18c1f36d97cebd0b7a0a15a080b73530c4fb847bfd435fb3f"
|
||||
},
|
||||
{
|
||||
"path": "packages/business/tests/cli.test.mjs",
|
||||
"merged": false,
|
||||
"sameAsEarlyTree": true,
|
||||
"earlySha256": "d54ba2338bcdfec22764030cf3ec9e3464ab275b15321d6d1b039169ea37fd85",
|
||||
"sha256": "d54ba2338bcdfec22764030cf3ec9e3464ab275b15321d6d1b039169ea37fd85"
|
||||
},
|
||||
{
|
||||
"path": "packages/business/tests/instance-settings.test.mjs",
|
||||
"merged": true,
|
||||
"sameAsEarlyTree": false,
|
||||
"earlySha256": "c0959f3af3df653bbf469471d3bbe3f28bc4478cba8ba57910af7f09498c4c3f",
|
||||
"sha256": "072e25c5237e1be4294c7a4a95daa2ab593832786013e1283b19725c330647c1"
|
||||
},
|
||||
{
|
||||
"path": "packages/business/tests/library-projects-protected.test.mjs",
|
||||
"merged": false,
|
||||
"sameAsEarlyTree": true,
|
||||
"earlySha256": "cfc726ec7bf73c1dc9fc6395cba85e374b7a006bac45bd8c47c969550557147f",
|
||||
"sha256": "cfc726ec7bf73c1dc9fc6395cba85e374b7a006bac45bd8c47c969550557147f"
|
||||
},
|
||||
{
|
||||
"path": "packages/business/tests/resolve.test.mjs",
|
||||
"merged": false,
|
||||
"sameAsEarlyTree": true,
|
||||
"earlySha256": "c74af44a83ee918196e2c1016b62786e757c0ae774c9b1613280d3fbbf3ffb22",
|
||||
"sha256": "c74af44a83ee918196e2c1016b62786e757c0ae774c9b1613280d3fbbf3ffb22"
|
||||
},
|
||||
{
|
||||
"path": "packages/cli/src/config.mjs",
|
||||
"merged": false,
|
||||
"sameAsEarlyTree": true,
|
||||
"earlySha256": "ab7b9f452123b6f7e98f4f59cbb3cc4483fd296e4af5522412410ee53d1b20e0",
|
||||
"sha256": "ab7b9f452123b6f7e98f4f59cbb3cc4483fd296e4af5522412410ee53d1b20e0"
|
||||
},
|
||||
{
|
||||
"path": "packages/cli/src/launcher.mjs",
|
||||
"merged": true,
|
||||
"sameAsEarlyTree": false,
|
||||
"earlySha256": "2272232dbe6c362eddb23ad903987fd4b8e0ca1eb94dbe93b66b3e785e7d0712",
|
||||
"sha256": "d8a870d8eb8254adfd576688696705359fefbf517b40e5d7482500bf27941022"
|
||||
},
|
||||
{
|
||||
"path": "packages/cli/tests/launcher.test.mjs",
|
||||
"merged": true,
|
||||
"sameAsEarlyTree": false,
|
||||
"earlySha256": "38fb51c15764333642d75db7fb358d611e448049cf894b24686ea6cf2cf169c4",
|
||||
"sha256": "99234f247e8414120d2fd214efd590e9d573eca86180d7b775cb506ac1c12c78"
|
||||
},
|
||||
{
|
||||
"path": "packages/cli/tests/stack-release-fixture.mjs",
|
||||
"merged": false,
|
||||
"sameAsEarlyTree": true,
|
||||
"earlySha256": "86a3c15446d4c119206097c754cd15f5bef7b7e93c9f16e9d8696ec8c475eea9",
|
||||
"sha256": "86a3c15446d4c119206097c754cd15f5bef7b7e93c9f16e9d8696ec8c475eea9"
|
||||
},
|
||||
{
|
||||
"path": "packages/cli/tests/stack-release.test.mjs",
|
||||
"merged": false,
|
||||
"sameAsEarlyTree": true,
|
||||
"earlySha256": "aa63fadca8b3a51e7af1ff7560fd2645f3ef56bf4e5625b2d5a5f6946db40996",
|
||||
"sha256": "aa63fadca8b3a51e7af1ff7560fd2645f3ef56bf4e5625b2d5a5f6946db40996"
|
||||
},
|
||||
{
|
||||
"path": "packages/cli/tests/trackers-boot.test.mjs",
|
||||
"merged": false,
|
||||
"sameAsEarlyTree": true,
|
||||
"earlySha256": "c90493e45bfa09bf0b01600aaf04d6ecd79d939357beacc1a9cd65f958bb7c22",
|
||||
"sha256": "c90493e45bfa09bf0b01600aaf04d6ecd79d939357beacc1a9cd65f958bb7c22"
|
||||
},
|
||||
{
|
||||
"path": "packages/library/src/index.mjs",
|
||||
"merged": true,
|
||||
"sameAsEarlyTree": false,
|
||||
"earlySha256": "b80e6c27daf908a0e71fcc1e5e8c91d05e857790bd77d92e06ff086ab3623306",
|
||||
"sha256": "ecda99dea46390b81fffa6f414d56a13737233e01d883b82cd186e0e21b6c4d1"
|
||||
},
|
||||
{
|
||||
"path": "packages/library/src/mirror.mjs",
|
||||
"merged": false,
|
||||
"sameAsEarlyTree": true,
|
||||
"earlySha256": "75ce08fba0956c846f2ca9ab1b565974657925f94ac952c720e7308783946480",
|
||||
"sha256": "75ce08fba0956c846f2ca9ab1b565974657925f94ac952c720e7308783946480"
|
||||
},
|
||||
{
|
||||
"path": "packages/library/tests/mirror.test.mjs",
|
||||
"merged": false,
|
||||
"sameAsEarlyTree": true,
|
||||
"earlySha256": "e96473be70ece8c8232ce5325822244b593f273371b74b4126920654cde9d72c",
|
||||
"sha256": "e96473be70ece8c8232ce5325822244b593f273371b74b4126920654cde9d72c"
|
||||
},
|
||||
{
|
||||
"path": "packages/project/src/paths.mjs",
|
||||
"merged": false,
|
||||
"sameAsEarlyTree": true,
|
||||
"earlySha256": "bd9debcf3f9bb92560e74f220a0b108dfe24154bc6d1fb03c5ec414356d451f9",
|
||||
"sha256": "bd9debcf3f9bb92560e74f220a0b108dfe24154bc6d1fb03c5ec414356d451f9"
|
||||
},
|
||||
{
|
||||
"path": "packages/project/tests/project.test.mjs",
|
||||
"merged": false,
|
||||
"sameAsEarlyTree": true,
|
||||
"earlySha256": "0ebe1862ce70f26c4a6a44304182327f9a6944d16cc87f674fbb1d32e08ac602",
|
||||
"sha256": "0ebe1862ce70f26c4a6a44304182327f9a6944d16cc87f674fbb1d32e08ac602"
|
||||
},
|
||||
{
|
||||
"path": "packages/seat/src/checkout.mjs",
|
||||
"merged": false,
|
||||
"sameAsEarlyTree": true,
|
||||
"earlySha256": "859201bd192522e51c33b86ef45f73487b27cdfc48ea7e4e09870e26d056048a",
|
||||
"sha256": "859201bd192522e51c33b86ef45f73487b27cdfc48ea7e4e09870e26d056048a"
|
||||
},
|
||||
{
|
||||
"path": "packages/seat/tests/checkout.test.mjs",
|
||||
"merged": false,
|
||||
"sameAsEarlyTree": true,
|
||||
"earlySha256": "663040d7c737aba6403e6397bacf1325b558cc14df3e5677f0a28f9499c45127",
|
||||
"sha256": "663040d7c737aba6403e6397bacf1325b558cc14df3e5677f0a28f9499c45127"
|
||||
},
|
||||
{
|
||||
"path": "packages/webui/src/cli.mjs",
|
||||
"merged": false,
|
||||
"sameAsEarlyTree": true,
|
||||
"earlySha256": "e98fd2fe4e621d5b4fa1ed95c4d4585469e7ab7a11dd379dc541dddb1b1a1f02",
|
||||
"sha256": "e98fd2fe4e621d5b4fa1ed95c4d4585469e7ab7a11dd379dc541dddb1b1a1f02"
|
||||
},
|
||||
{
|
||||
"path": "packages/webui/tests/library-cli.test.mjs",
|
||||
"merged": false,
|
||||
"sameAsEarlyTree": true,
|
||||
"earlySha256": "1983912b76f01f8e6d0c564e3bbcd763c0b2c44044988b192ef827446f98556c",
|
||||
"sha256": "1983912b76f01f8e6d0c564e3bbcd763c0b2c44044988b192ef827446f98556c"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
diff --git a/packages/bus/src/broker.mjs b/packages/bus/src/broker.mjs
|
||||
index 3baa709f9..512d57519 100644
|
||||
--- a/packages/bus/src/broker.mjs
|
||||
+++ b/packages/bus/src/broker.mjs
|
||||
@@ -90,0 +91 @@ export const PROJECT_FILE_VERBS = Object.freeze(['project.files', 'project.file'
|
||||
+export const LIBRARY_VERBS = Object.freeze(['library.file', 'library.status']);
|
||||
@@ -281,0 +283 @@ export class Broker {
|
||||
+ #library;
|
||||
@@ -297 +299 @@ export class Broker {
|
||||
- constructor({ store, businesses, secretCheck = () => {}, credentialStatus = () => [], organization = null, project = null, usage = null, limits = null, harnessOn = null, credentialVerbs = null, hostGrant = null, hostKeys = null }) {
|
||||
+ constructor({ store, businesses, secretCheck = () => {}, credentialStatus = () => [], organization = null, project = null, library = null, usage = null, limits = null, harnessOn = null, credentialVerbs = null, hostGrant = null, hostKeys = null }) {
|
||||
@@ -308,0 +311 @@ export class Broker {
|
||||
+ this.#library = library;
|
||||
@@ -2189,0 +2193,2 @@ export class Broker {
|
||||
+ if (LIBRARY_VERBS.includes(request.verb))
|
||||
+ return this.#requestLibrary(s, { verb: request.verb, args: structuredClone(args) });
|
||||
@@ -2438,0 +2444,20 @@ export class Broker {
|
||||
+ // C2-04 M4: only a verified human reads library text or status. Host Git
|
||||
+ // functions stay injected, preserving this module's sandbox import closure.
|
||||
+ async #requestLibrary(s, request) {
|
||||
+ const { verb, args } = request;
|
||||
+ try {
|
||||
+ this.#human(s);
|
||||
+ const fields = verb === 'library.file' ? ['project', 'path'] : ['project'];
|
||||
+ keys(args, fields, fields);
|
||||
+ if (!this.#library?.readFile || !this.#library?.status) fail('project-not-configured');
|
||||
+ const context = { business: this.#business(s.business), project: args.project };
|
||||
+ const result = verb === 'library.file'
|
||||
+ ? await this.#library.readFile({ ...context, path: args.path })
|
||||
+ : await this.#library.status(context);
|
||||
+ this.#secretCheck(result);
|
||||
+ return result;
|
||||
+ } catch (error) {
|
||||
+ const Failure = this.#library?.LibraryError;
|
||||
+ throw this.#refused(s, Failure && error instanceof Failure ? new BusError(error.code) : error, request);
|
||||
+ }
|
||||
+ }
|
||||
diff --git a/packages/bus/src/runtime.mjs b/packages/bus/src/runtime.mjs
|
||||
index f81f956f2..e265ff5d1 100644
|
||||
--- a/packages/bus/src/runtime.mjs
|
||||
+++ b/packages/bus/src/runtime.mjs
|
||||
@@ -5,0 +6 @@ import * as projectModule from '../../project/src/index.mjs';
|
||||
+import * as libraryModule from '../../library/src/index.mjs';
|
||||
@@ -95 +96 @@ export async function startBroker({
|
||||
- ...Object.values(businesses).flatMap((b) => Object.values(b.projects ?? {}).map((p) => p.root)),
|
||||
+ ...Object.values(businesses).flatMap((b) => Object.values(b.projects ?? {}).filter(p => p.kind !== 'library').map((p) => p.root)),
|
||||
@@ -130,0 +132,5 @@ export async function startBroker({
|
||||
+ // C2-04: mirrors are host state, never session checkouts. An unsafe
|
||||
+ // existing mirror refuses startup before a socket can become ready.
|
||||
+ for (const business of Object.values(businesses))
|
||||
+ for (const [project, entry] of Object.entries(business.projects ?? {}))
|
||||
+ if (entry.kind === 'library') await libraryModule.ensureMirror({ business, project, dataRoot });
|
||||
@@ -138,0 +145,5 @@ export async function startBroker({
|
||||
+ library: {
|
||||
+ readFile: context => libraryModule.readLibraryFile({ ...context, dataRoot }),
|
||||
+ status: context => libraryModule.libraryStatus({ ...context, dataRoot }),
|
||||
+ LibraryError: libraryModule.LibraryError,
|
||||
+ },
|
||||
diff --git a/packages/business/src/business.mjs b/packages/business/src/business.mjs
|
||||
index d08a4f52e..e8337ea2b 100644
|
||||
--- a/packages/business/src/business.mjs
|
||||
+++ b/packages/business/src/business.mjs
|
||||
@@ -12,0 +13 @@ import { checkPlugins } from "../../plugins/src/kinds.mjs";
|
||||
+import { checkMapping } from "../../library/src/mapping.mjs";
|
||||
@@ -241,0 +243,4 @@ export function validateBusinessDocument(document, file, { rolesDir }) {
|
||||
+ if (entry.kind === 'library') {
|
||||
+ projects[id] = checkMapping(entry, `${file} projects.${id}`, { fail: (code, message) => refuse(`${code}: ${message}`) });
|
||||
+ continue;
|
||||
+ }
|
||||
@@ -257,0 +263 @@ export function validateBusinessDocument(document, file, { rolesDir }) {
|
||||
+ if (projects[project].kind === 'library') refuse(`${file} roles.${instance}.publish names library project ${project}; library repositories cannot be published by agents`);
|
||||
diff --git a/packages/business/src/instance-settings.mjs b/packages/business/src/instance-settings.mjs
|
||||
index ff3a6d9d3..50cc36edc 100644
|
||||
--- a/packages/business/src/instance-settings.mjs
|
||||
+++ b/packages/business/src/instance-settings.mjs
|
||||
@@ -149,0 +150 @@ export function instanceSettings({ dir, rolesDir, system, levels = () => null })
|
||||
+ if (entry.kind === 'library') continue;
|
||||
diff --git a/packages/business/tests/business.test.mjs b/packages/business/tests/business.test.mjs
|
||||
index b64659fa1..0f214a005 100644
|
||||
--- a/packages/business/tests/business.test.mjs
|
||||
+++ b/packages/business/tests/business.test.mjs
|
||||
@@ -10,0 +11,30 @@ import { launchDoc, businessDoc, REPO, REPO_ROLES, rolesCopy, tmp, writeJson } f
|
||||
+test('C2-04: library mappings load without roots, remain frozen, and retain mapping refusals', async t => {
|
||||
+ const { mappingEntry } = await import('../../library/tests/helpers.mjs');
|
||||
+ const { rmSync } = await import('node:fs');
|
||||
+ const root = tmp(); t.after(() => rmSync(root, { recursive: true, force: true }));
|
||||
+ const doc = businessDoc(root), file = join(root, 'businesses/acme.json');
|
||||
+ doc.projects = { books: mappingEntry(), ...doc.projects };
|
||||
+ const loaded = validateBusinessDocument(doc, file, { rolesDir: REPO_ROLES });
|
||||
+ const { checkMapping } = await import('../../library/src/mapping.mjs');
|
||||
+ assert.deepEqual(loaded.projects.books, checkMapping(mappingEntry()));
|
||||
+ assert.equal(loaded.projects.books.root, undefined);
|
||||
+ assert.ok(Object.isFrozen(loaded.projects.books.universes.harbor.books));
|
||||
+ const only = structuredClone(doc); delete only.projects.stack;
|
||||
+ assert.deepEqual(Object.keys(validateBusinessDocument(only, file, { rolesDir: REPO_ROLES }).projects), ['books']);
|
||||
+ doc.projects.books.universes.harbor.playground = ['Elsewhere/Playground/'];
|
||||
+ refuses(() => validateBusinessDocument(doc, file, { rolesDir: REPO_ROLES }), /library-playground-outside-book/);
|
||||
+ doc.projects.books = { ...mappingEntry(), root: '/forbidden' };
|
||||
+ refuses(() => validateBusinessDocument(doc, file, { rolesDir: REPO_ROLES }), /library-mapping-invalid/);
|
||||
+});
|
||||
+
|
||||
+test('C2-04: an otherwise valid publish grant cannot name a library repo', async t => {
|
||||
+ const { mappingEntry } = await import('../../library/tests/helpers.mjs');
|
||||
+ const { rmSync } = await import('node:fs');
|
||||
+ const root = tmp(); t.after(() => rmSync(root, { recursive: true, force: true }));
|
||||
+ const doc = businessDoc(root);
|
||||
+ doc.projects.books = { ...mappingEntry(), remote: 'https://git.example/writer/books' };
|
||||
+ doc.roles.coder.identity = { name: 'Coder', email: '[email protected]', gitea: { url: 'https://git.example', user: 'acme-coder' } };
|
||||
+ doc.roles.coder.publish = ['books'];
|
||||
+ refuses(() => validateBusinessDocument(doc, join(root, 'businesses/acme.json'), { rolesDir: REPO_ROLES }), /publish.*library/);
|
||||
+});
|
||||
+
|
||||
diff --git a/packages/business/tests/instance-settings.test.mjs b/packages/business/tests/instance-settings.test.mjs
|
||||
index 6b19f9e89..a6c8fe665 100644
|
||||
--- a/packages/business/tests/instance-settings.test.mjs
|
||||
+++ b/packages/business/tests/instance-settings.test.mjs
|
||||
@@ -22,0 +23,10 @@ const LEVELS = { pi: ["off", "minimal", "low", "medium", "high", "xhigh", "max"]
|
||||
+test('C2-04: instance settings skip a library while checking a later code project', async () => {
|
||||
+ const { mappingEntry } = await import('../../library/tests/helpers.mjs');
|
||||
+ const f = fixture(doc => { doc.projects = { books: mappingEntry(), ...doc.projects }; });
|
||||
+ writeJson(projectFilePath(f.doc.projects.stack.root), { projectVersion: 1, id: 'stack', vars: { 'tracker.project': 3 } });
|
||||
+ const before = f.settings.read('acme');
|
||||
+ f.settings.set('acme', { revision: before.revision, instance: 'gate-215', op: 'add', definition: 'merge-gate' }, 'jason');
|
||||
+ assert.deepEqual(JSON.parse(readFileSync(f.file, 'utf8')).projects.books, mappingEntry());
|
||||
+ assert.ok(f.settings.read('acme').instances['gate-215']);
|
||||
+});
|
||||
+
|
||||
diff --git a/packages/cli/src/launcher.mjs b/packages/cli/src/launcher.mjs
|
||||
index 604cef203..c721ee9e8 100644
|
||||
--- a/packages/cli/src/launcher.mjs
|
||||
+++ b/packages/cli/src/launcher.mjs
|
||||
@@ -354 +354 @@ export function createLauncher({
|
||||
- checkouts = await ensureCheckouts({ workspace, projects: b.projects, env });
|
||||
+ checkouts = await ensureCheckouts({ workspace, projects: Object.fromEntries(Object.entries(b.projects).filter(([, entry]) => entry.kind !== 'library')), env });
|
||||
diff --git a/packages/cli/tests/launcher.test.mjs b/packages/cli/tests/launcher.test.mjs
|
||||
index 3b663ba94..4636df3de 100644
|
||||
--- a/packages/cli/tests/launcher.test.mjs
|
||||
+++ b/packages/cli/tests/launcher.test.mjs
|
||||
@@ -32,0 +33,10 @@ const skip = sandboxProblem() ?? false;
|
||||
+test('C2-04: launcher workspace clones code but never the library', { skip, timeout: 30000 }, async t => {
|
||||
+ const { mappingEntry } = await import('../../library/tests/helpers.mjs');
|
||||
+ const f = await setup(t, doc => { doc.projects = { books: mappingEntry(), ...doc.projects }; return doc; });
|
||||
+ await f.launcher.launchPm();
|
||||
+ const workspace = workspaceDir(f.f.dataRoot, 'acme', 'chief');
|
||||
+ assert.equal(existsSync(join(workspace, 'stack', '.git')), true);
|
||||
+ assert.equal(existsSync(join(workspace, 'books')), false);
|
||||
+ assert.equal(await f.close(), 0);
|
||||
+});
|
||||
+
|
||||
diff --git a/packages/library/src/index.mjs b/packages/library/src/index.mjs
|
||||
index f64d77860..53ce5cb43 100644
|
||||
--- a/packages/library/src/index.mjs
|
||||
+++ b/packages/library/src/index.mjs
|
||||
@@ -8,0 +9 @@ export { survey, formatSurvey, surveyMain } from './survey.mjs';
|
||||
+export { SYNC_STATE_FILE, mirrorPath, ensureMirror, withLibraryLock, servedCommit, readSyncState, libraryStatus, readLibraryFile } from './mirror.mjs';
|
||||
@@ -0,0 +1,14 @@
|
||||
✔ C2-04 M4: both verbs reject every agent before arguments or adapter access (30.144386ms)
|
||||
✔ C2-04 bus: human reads validate keys and return adapter results without path leakage (11.434614ms)
|
||||
✔ C2-04 socket: each async library verb resolves its result rather than serializing {} (17.684117ms)
|
||||
✔ C2-04 runtime: protectedRoots skips library but retains real code-root credential protection (45.253455ms)
|
||||
✔ C2-04 runtime: unsafe existing mirror refuses boot and never publishes a socket (23.246812ms)
|
||||
✔ C2-04 runtime: real library adapters reach the socket and lock waits leave other bus reads responsive (107.052077ms)
|
||||
ℹ tests 6
|
||||
ℹ suites 0
|
||||
ℹ pass 6
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 359.869493
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
✔ Broker keeps the sandbox client import closure: only the listed imports, no lazy project import (2.265255ms)
|
||||
✔ without a trusted project adapter all three async paths refuse project-not-configured (57.448982ms)
|
||||
✔ real startBroker injects the project adapter for socket reads and bound-author record writes (102.784823ms)
|
||||
ℹ tests 3
|
||||
ℹ suites 0
|
||||
ℹ pass 3
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 312.717335
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
✔ C2-04: library mappings load without roots, remain frozen, and retain mapping refusals (12.852402ms)
|
||||
✔ C2-04: an otherwise valid publish grant cannot name a library repo (2.693014ms)
|
||||
✔ config directory and file path follow MOSAIC_CONFIG (0.229245ms)
|
||||
✔ the fixture business validates and comes back frozen (1.006969ms)
|
||||
✔ two instances may share a definition (0.94271ms)
|
||||
✔ top-level refusals (3.474817ms)
|
||||
✔ arbiters and projects (5.543282ms)
|
||||
✔ role instances (2.7386ms)
|
||||
✔ Vikunja bots (6.181044ms)
|
||||
✔ a role without Vikunja takes no tracker block (5.900981ms)
|
||||
✔ credential references match the definition's services (3.012597ms)
|
||||
✔ launch (8.561546ms)
|
||||
✔ REQ-THREAD-2 REQ-LAUNCH-1 launch.threadIdleSeconds: absent is the default, a positive integer is used, anything else refuses (6.420869ms)
|
||||
✔ loadBusiness: file checks (2.241353ms)
|
||||
✔ loadBusiness: not a regular file (46.573969ms)
|
||||
✔ loading writes nothing (2.802338ms)
|
||||
✔ names that are Object.prototype properties don't count as declared (3.291238ms)
|
||||
✔ the shipped example refuses as written and validates once filled in (1.195924ms)
|
||||
✔ persona vars: agent layer, creative definition only, both or neither (9.0736ms)
|
||||
ℹ tests 19
|
||||
ℹ suites 0
|
||||
ℹ pass 19
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 199.91256
|
||||
@@ -0,0 +1,18 @@
|
||||
✔ C2-04: business validate and resolve skip a library before code projects and credential checks (235.663956ms)
|
||||
✔ usage errors exit 4 (325.805811ms)
|
||||
✔ validate: a good business exits 0 and prints instance digests (69.331646ms)
|
||||
✔ validate: project files (344.919464ms)
|
||||
✔ validate: missing files and a broken system config (252.779029ms)
|
||||
✔ validate: credential reference problems exit 2 and name each one (66.663076ms)
|
||||
✔ validate: a token file inside the repository is refused (78.714732ms)
|
||||
✔ validate: role definitions come from MOSAIC_ROLES_DIR (201.487424ms)
|
||||
✔ resolve: prints one instance's record (281.684478ms)
|
||||
✔ resolve: refusals (454.610462ms)
|
||||
ℹ tests 10
|
||||
ℹ suites 0
|
||||
ℹ pass 10
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 2381.258516
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
✔ C2-04: instance settings skip a library while checking a later code project (32.527878ms)
|
||||
✔ row 165 read lists each instance and the definitions add accepts (3.218296ms)
|
||||
✔ row 165 add: two instances join, validate exits 0, the log names the human, and the bus restart is reported (93.702292ms)
|
||||
✔ row 165 change: definition, vars and launch membership log before and after; only a definition change asks for a restart (99.793939ms)
|
||||
✔ row 165 refuses each validation failure and leaves the file's bytes alone (33.820979ms)
|
||||
✔ row 165 refuses an added instance whose definition declares credentials, and says why (5.999086ms)
|
||||
✔ row 165 refuses a definition change to or from one that declares credentials (6.767714ms)
|
||||
✔ row 165 a vars or launch change on an instance with its binding succeeds and keeps the binding (89.83786ms)
|
||||
✔ row 165 refuses an END_PROTECTED definition and every change to a protected instance (9.793219ms)
|
||||
✔ row 165 refuses while a project file doesn't resolve, as validate would (15.487298ms)
|
||||
✔ row 165 refuses a stale revision and leaves the file's bytes alone (10.871014ms)
|
||||
✔ row 65 an instance write refuses harness-off, thinking-unsupported, an unknown model and a partial fallback (38.02395ms)
|
||||
✔ row 213 a creative instance is the human's: add, vars and definition changes, persona digest only (90.045141ms)
|
||||
ℹ tests 13
|
||||
ℹ suites 0
|
||||
ℹ pass 13
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 608.08011
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
✔ C2-04 M9: changed playground and hybrid entries leave business and changes.jsonl byte-identical (23.242034ms)
|
||||
✔ C2-04 M9: code projects, additions, deletions and array changes are protected too (15.756145ms)
|
||||
✔ C2-04 M9: canonical key order is allowed and a non-project setter still records its change (17.060499ms)
|
||||
✔ C2-04 M9: a serialization hook cannot change projects after the canonical comparison (9.833495ms)
|
||||
ℹ tests 4
|
||||
ℹ suites 0
|
||||
ℹ pass 4
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 118.54831
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
✔ C2-04: a library first in projects does not hide a later project layer (9.584516ms)
|
||||
✔ systemVars flattens the validated config (1.063324ms)
|
||||
✔ precedence: system, business, project, project role, agent (2.001802ms)
|
||||
✔ limits narrow the definition and never widen it (2.563505ms)
|
||||
✔ role.launch stays within-role only for the instance the launch block names (5.04696ms)
|
||||
✔ limits.authority without role.launch leaves the launcher with no launch block (2.106162ms)
|
||||
✔ limits.authority narrows cross-role actions too (1.098761ms)
|
||||
✔ classify (1.065895ms)
|
||||
✔ the record carries what the broker and launcher need (0.966677ms)
|
||||
✔ digest: key order doesn't matter, any value change does (7.43546ms)
|
||||
✔ refusals (2.150825ms)
|
||||
ℹ tests 11
|
||||
ℹ suites 0
|
||||
ℹ pass 11
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 94.022587
|
||||
@@ -0,0 +1,54 @@
|
||||
✔ C2-04: launcher workspace clones code but never the library (1298.398732ms)
|
||||
✔ bus start --pm: the launcher instance (the chief of staff) runs under its own PID namespace, registered, with a manifest (1264.618734ms)
|
||||
usage: {"event":"usage-unknown","business":"acme","run":"r4accc4841d41","instance":"chief","turn":"81814ac7-9330-484a-95f8-cc2f80a9aeef","source":"@none","code":"baseline-unknown"}
|
||||
usage: {"event":"usage-unknown","business":"acme","run":"r0719029c31b1","instance":"coder","turn":"fd2dfc33-9ab6-4d4d-9eef-ba46b6d7a510","source":"@none","code":"baseline-unknown"}
|
||||
✔ the chief of staff launches a coder through its launch tool; the coder answers; refusals name their code (657.713119ms)
|
||||
usage: {"event":"usage-unknown","business":"acme","run":"r4b37f983290f","instance":"chief","turn":"6c8768d3-4742-4ae2-87c6-4653182c8520","source":"@none","code":"baseline-unknown"}
|
||||
usage: {"event":"usage-unknown","business":"acme","run":"r7bc8dc8db66c","instance":"pm","turn":"4b196787-1bf9-4702-82d2-397c84ab1e3c","source":"@none","code":"baseline-unknown"}
|
||||
usage: {"event":"usage-unknown","business":"acme","run":"r4b37f983290f","instance":"chief","turn":"1c6ec26d-97da-43b6-8cd8-91994e6c7c7b","source":"@none","code":"baseline-unknown"}
|
||||
usage: {"event":"usage-unknown","business":"acme","run":"r7bc8dc8db66c","instance":"pm","turn":"a12fdeb9-e25d-45a4-bd25-e048621a3557","source":"@none","code":"baseline-unknown"}
|
||||
usage: {"event":"usage-unknown","business":"acme","run":"r7bc8dc8db66c","instance":"pm","turn":"ad419687-0675-48a8-9932-90b2da5333ef","source":"@none","code":"baseline-unknown"}
|
||||
usage: {"event":"usage-unknown","business":"acme","run":"r4b37f983290f","instance":"chief","turn":"0d54926f-f5b8-4dbb-b38a-8ea23fdd5cb5","source":"@none","code":"baseline-unknown"}
|
||||
usage: {"event":"usage-unknown","business":"acme","run":"r7bc8dc8db66c","instance":"pm","turn":"6891e20c-472e-4e67-815e-88728024acf4","source":"@none","code":"baseline-unknown"}
|
||||
usage: {"event":"usage-unknown","business":"acme","run":"r4b37f983290f","instance":"chief","turn":"9ac6fe37-9044-4f54-bae0-826a6c84c15b","source":"@none","code":"baseline-unknown"}
|
||||
✔ a launched pm's request_staff reaches the chief of staff; no other session has the tool and the launch limits still hold (1202.248105ms)
|
||||
✔ each launch makes sure the workspace has a clone of the project: cloned, fast-forwarded, or fetched and logged (3926.301471ms)
|
||||
✔ a role the broker says holds a merge decision gets land_work, its prompt line, its landing and the git socket; without it, none (593.731622ms)
|
||||
✔ REQ-LAUNCH-1 the tick starts a listed merge decision holder once, with land_work, the Landing line and its landing turn; an unlisted holder starts nothing (755.589469ms)
|
||||
usage: {"event":"usage-unknown","business":"acme","run":"rf7ecf1ef2b65","instance":"coder","turn":"744cb116-e163-4b18-831e-556df7e7bfd9","source":"@none","code":"baseline-unknown"}
|
||||
✔ a holder running since before the resolution is stopped once the broker releases it, land-relaunch, and the next tick starts it: landing turn first, then the message that waited (739.551352ms)
|
||||
✔ a landing run that ended isn't started again for its decision, a spent decision starts nothing, and a new decision starts the holder (564.790867ms)
|
||||
✔ after a restart, the new host's first tick starts a holder whose decision is still held (883.94802ms)
|
||||
✔ a refused landing start is logged once per code with its decision, isn't a start, and the next tick with room starts the holder (595.491854ms)
|
||||
✔ a project clone that can't be made refuses checkout-failed, from --chief and from a session, with no run and no clone left (250.651304ms)
|
||||
✔ a runner that stops at once ends its launch with the runner's reason (336.620423ms)
|
||||
✔ a Claude Code launch with no session credential refuses before it starts (172.971844ms)
|
||||
✔ a pi launch needs no session credential: pi logs in through its own ENV_ALLOW variables (287.021469ms)
|
||||
usage: {"event":"plugin-refused","kind":"harness","name":"down","code":"missing","message":"/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row215-on-f827/packages/plugins/harness/down is missing","kept":[]}
|
||||
plugins: {"event":"plugin-refused","kind":"harness","name":"down","code":"missing","message":"/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row215-on-f827/packages/plugins/harness/down is missing","kept":[]}
|
||||
✔ row 65 a failed primary preflight launches the fallback on a fixture harness module, recording the route and the reason (327.373038ms)
|
||||
✔ a runner killed from the host ends its launch as killed, not failed (381.927989ms)
|
||||
✔ a missing or failing bwrap refuses sandbox-unavailable before anything starts; there is no unconfined fallback (198.778768ms)
|
||||
✔ row 64 a role skill that isn't enabled refuses skill-not-enabled, and one that isn't a plain directory skill-refused, before anything starts (184.44803ms)
|
||||
✔ row 213 a creative instance's persona is read from <configDir>/personas: off its digest the launch fails with the mismatch as its reason (239.197527ms)
|
||||
✔ row 64 on Claude Code a role skill that isn't enabled refuses the same way, before anything starts (230.64829ms)
|
||||
usage: {"event":"usage-unknown","business":"acme","run":"r800039251a09","instance":"chief","turn":"f2e6a1ad-767e-4316-be90-6194b840e2ef","source":"@none","code":"baseline-unknown"}
|
||||
usage: {"event":"usage-unknown","business":"acme","run":"rfeeb081c2983","instance":"coder","turn":"1abdb906-521d-4100-897b-f5eba12663cf","source":"@none","code":"baseline-unknown"}
|
||||
✔ a real Claude Code coder's shell can't read a stand-in secret or anything else its sandbox doesn't hold (1612.164523ms)
|
||||
✔ a host that died hard leaves its sessions to the next host, which kills them and ends their runs so the role can be launched again (909.716449ms)
|
||||
✔ a host that died hard leaves its sessions to the next host, which finds one already exited (23) and ends their runs so the role can be launched again (3844.434582ms)
|
||||
✔ bus start --no-launch leaves an earlier host's live session alone: no signal, no end, sessions.json as it was (224.265713ms)
|
||||
✔ bus start --no-launch refuses every launch: the PM launch and a session's request, each logged, nothing spawned (193.925449ms)
|
||||
✔ bus start --no-launch starts no thread tick; the same host with launches runs it (1181.783938ms)
|
||||
✔ a malformed sessions.json refuses the host start with exit 3 and stays as it was (166.842635ms)
|
||||
✔ an over-long launch request is refused at once, not at the 10 s idle timeout (171.101521ms)
|
||||
✔ a launch client that never closes its side doesn't hold the host's close (170.266667ms)
|
||||
✔ a runner that ignores SIGTERM is killed when the host closes (1305.753454ms)
|
||||
ℹ tests 31
|
||||
ℹ suites 0
|
||||
ℹ pass 31
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 24989.261794
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
✔ row 232: confirm, revert, gate, --to and --expect-from need --units external; the user-only flags are usage under it (1129.148785ms)
|
||||
✔ row 232: pm-on and activate --pm-after-harness refuse external-pm (1112.631619ms)
|
||||
✔ row 232: units-running (N4) refuses while a unit is active and leaves the store, the log and TAKEN; failed counts as down (2301.278572ms)
|
||||
✔ row 232: activate stages: the pointer stays, AWAITING-UNITS names TO, a backup of the stopped store, no directory in the set, no --user, no journal (2229.906955ms)
|
||||
✔ row 232: A3 order: capture-failed and marker-failed refuse with exit 3 and leave no marker or FAILED (1913.7476ms)
|
||||
✔ row 232: confirm and revert refuse open-activation with no marker, two, the wrong copy, or one the log holds closed; refusals name no activation (3892.845676ms)
|
||||
✔ row 232: confirm polls: bus status good after 3 s fails with --timeout 1, writes FAILED and leaves the rest; FAILED then refuses activation-failed (3703.021367ms)
|
||||
✔ row 232: confirm polls to a pass with --timeout 10: the pointer, an ok line that reads as the started run, no marker (6350.955178ms)
|
||||
✔ row 232: stale-start: @1792540799 fails a start floor of 1792540800 with stale-start (3365.187863ms)
|
||||
✔ row 232: stale-start is a gate code: an enter time that turns to @1792540800 after 2 s passes with --timeout 10 (4713.287991ms)
|
||||
✔ row 232: gate (N2, A2f): --since 1792540800 passes @1792540800 and fails @1792540799; it writes nothing (3014.18649ms)
|
||||
✔ row 232: the external PM check reads launches list: one live run of launch.by since the start passes (7715.019003ms)
|
||||
✔ row 232: revert puts the wrapper back and leaves the store when nothing migrated (1540.240269ms)
|
||||
✔ row 232: confirm --rollback refuses rollback-mismatch, and logs rollback-failed with exit 2 when OLD fails its gate (3838.859298ms)
|
||||
✔ row 232: confirm --rollback after a --restore swap logs rollbackCode not-attempted; rollback --restore finds an external backup (4385.316411ms)
|
||||
✔ row 232: sequence 1: activate, confirm times out, revert, confirm --rollback --cause A5: gate-failed rollback ok (5668.17255ms)
|
||||
✔ row 232: sequence 2: activate --migrate, the wrapper install fails, revert restores TAKEN, confirm --rollback --cause A3 (3356.512703ms)
|
||||
✔ row 232: sequence 3: activate, root's A4 fails, revert, confirm --rollback --cause A4: failed code units-start (3090.998502ms)
|
||||
✔ row 232: sequence 4: a capture failure leaves nothing open, then A2f's gate OLD writes nothing (2006.820211ms)
|
||||
✔ row 232: sequence 5: a confirm of the wrong copy is refused, and revert and confirm --rollback still close the activation (3716.790879ms)
|
||||
✔ row 232: sequence 6: a revert that fails leaves the activation open, and the next --plan refuses interrupted-run (2084.865556ms)
|
||||
✔ row 232: sequence 7: adopt, two confirmed activates, rollback --to the previous copy, confirmed, logs op rollback (8859.407093ms)
|
||||
✔ row 232: sequence 8: a migration that writes and fails: revert restores the backup byte for byte, confirm --rollback --cause A3 (4066.89509ms)
|
||||
✔ row 232: user mode: every systemctl call carries --user, and activate, rollback and check make the base's calls (8472.325246ms)
|
||||
✔ row 232: user mode: a default activate --plan prints the base's bytes (2725.266801ms)
|
||||
ℹ tests 25
|
||||
ℹ suites 0
|
||||
ℹ pass 25
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 96332.465778
|
||||
+227
@@ -0,0 +1,227 @@
|
||||
✔ T1 adopt writes the pointer from the units once; a failing check refuses check-failed (1604.406515ms)
|
||||
✔ T2 activate installs exactly the pointer's pm, claude and Console flags (2285.234425ms)
|
||||
▶ T3 a hand-edited unit refuses unit-flags-drift, names the difference and changes nothing
|
||||
✔ pm (1074.84155ms)
|
||||
✔ claude (1048.597035ms)
|
||||
✔ console (1069.472197ms)
|
||||
✔ T3 a hand-edited unit refuses unit-flags-drift, names the difference and changes nothing (3193.872973ms)
|
||||
▶ T4 each item 3 refusal changes nothing and logs one line with its code
|
||||
✔ copy-missing (970.101799ms)
|
||||
✔ copy-unreachable (976.867501ms)
|
||||
✔ copy-schema-unknown (942.411453ms)
|
||||
✔ already-active (966.01391ms)
|
||||
✔ instance-busy (another business active) (1033.865857ms)
|
||||
✔ instance-busy (this business activating) (989.106934ms)
|
||||
✔ drop-in-override (1051.252734ms)
|
||||
✔ no-pointer (535.256184ms)
|
||||
✔ T4 each item 3 refusal changes nothing and logs one line with its code (7466.71817ms)
|
||||
✔ T5 an activate with no migration stops the Console then the bus, installs, starts the bus then the Console (2298.616234ms)
|
||||
✔ T6 a migration without --migrate rolls back with migration-needs-flag (2085.91559ms)
|
||||
✔ T7 --migrate takes the backup before the migration runs (2415.592569ms)
|
||||
✔ T8 a failed migration restores the backup and keeps the store it replaced (2571.261148ms)
|
||||
✔ T9 a store outside the target's chain rolls back with store-newer (2405.058696ms)
|
||||
▶ T10 each gate check failing alone rolls back and puts every file back
|
||||
✔ units-inactive (5907.690999ms)
|
||||
✔ bus-status (6093.058453ms)
|
||||
✔ healthz (6393.330472ms)
|
||||
✔ copy-check (5442.480521ms)
|
||||
✔ pm-launch-unconfirmed (5607.705975ms)
|
||||
✔ T10 each gate check failing alone rolls back and puts every file back (29445.44482ms)
|
||||
▶ T10b the PM check needs exactly one launched line for a live run of this start
|
||||
✔ no launched line (5534.978468ms)
|
||||
✔ two lines (5372.975087ms)
|
||||
✔ a changed word (5420.826895ms)
|
||||
✔ run not in launches list (5601.520776ms)
|
||||
✔ run started before the start (5448.208485ms)
|
||||
✔ a human launch with no journal line (5346.70067ms)
|
||||
✔ run for another business (5684.948726ms)
|
||||
✔ run not live (5860.307931ms)
|
||||
✔ one well-formed line and a live run pass (2078.4402ms)
|
||||
✔ T10b the PM check needs exactly one launched line for a live run of this start (46350.52861ms)
|
||||
✔ T11 a rollback whose gate fails too: rollback-failed, exit 2, both units stopped, no retry (7145.208417ms)
|
||||
✔ T12 rollback takes the previous copy from the log (3164.021139ms)
|
||||
✔ T13 a rollback across a migration needs --restore, then restores and goes live (3796.056873ms)
|
||||
✔ T14 events written after the backup need --events N with the right N (4384.802883ms)
|
||||
✔ T14b a rollback --restore whose gate fails stops both units and skips item 6 (5813.087127ms)
|
||||
✔ T14c a rollback without --restore whose gate fails runs item 6 (6237.609182ms)
|
||||
✔ T15 --plan names the migration and the restore and changes nothing (2849.139286ms)
|
||||
✔ T26 --plan lists the commits an activate adds, after the migration lines (1481.868533ms)
|
||||
✔ T27 --plan names each migration step, or says the steps cannot be read (1173.748951ms)
|
||||
✔ T25 --plan refuses copies-unrelated when neither copy is an ancestor of the other (569.344968ms)
|
||||
▶ T23 --plan reads the store without changing a file, stopped or held
|
||||
✔ stopped store (721.626407ms)
|
||||
✔ held store (690.820461ms)
|
||||
✔ T23 --plan reads the store without changing a file, stopped or held (1413.175682ms)
|
||||
✔ T24 business-mismatch and capture-failed refuse with exit 3; a short id is a usage error (1463.46361ms)
|
||||
✔ T16 status prints the pointer, the log, the check, bus status and drift, and writes nothing (910.07629ms)
|
||||
✔ T19 a started line with no final line: status shows it and every changing verb refuses (1271.59212ms)
|
||||
✔ T20 a held run lock refuses run-locked without a log line; status and --plan still run (1515.929929ms)
|
||||
✔ T21 a bus unit with no MOSAIC_CLAUDE_BIN: adopt and activate refuse no-claude-pin (1789.2511ms)
|
||||
▶ T22 the stopped store read: a -wal or -shm refuses store-unclean and is left alone; a clean read adds no file
|
||||
✔ bus.sqlite-wal (1954.988144ms)
|
||||
✔ bus.sqlite-shm (2042.456191ms)
|
||||
✔ clean (2209.768749ms)
|
||||
✔ T22 the stopped store read: a -wal or -shm refuses store-unclean and is left alone; a clean read adds no file (6208.13226ms)
|
||||
▶ T28 a unit path, drop-in directory or drop-in file that cannot be read, or a relative unit path, refuses drop-in-override before any stop
|
||||
✔ unit path (938.058563ms)
|
||||
✔ drop-in directory (934.896589ms)
|
||||
✔ drop-in file (958.129787ms)
|
||||
✔ relative unit path (943.563721ms)
|
||||
✔ T28 a unit path, drop-in directory or drop-in file that cannot be read, or a relative unit path, refuses drop-in-override before any stop (3775.662901ms)
|
||||
▶ T29 a bus that stops during the held-store read: --plan says so, rollback --restore refuses restore-mismatch
|
||||
✔ --plan (932.393863ms)
|
||||
✔ rollback --restore (2879.958858ms)
|
||||
✔ T29 a bus that stops during the held-store read: --plan says so, rollback --restore refuses restore-mismatch (3812.923223ms)
|
||||
✔ T30 a copy check that agrees on another copy fails the gate with copy-check and rolls back (6646.085499ms)
|
||||
▶ T31 a quoted or escaped Environment= or ExecStart= is unreadable: refusals by name, nothing read from /a
|
||||
✔ Environment double quotes (1976.227811ms)
|
||||
✔ Environment single quotes (2063.211816ms)
|
||||
✔ Environment backslash (2038.183771ms)
|
||||
✔ ExecStart quotes (1984.451614ms)
|
||||
✔ Console ExecStart quotes (1980.466835ms)
|
||||
✔ T31 a quoted or escaped Environment= or ExecStart= is unreadable: refusals by name, nothing read from /a (10043.710809ms)
|
||||
▶ T32 item 1: --pm-after-harness refuses a target without harness or a file that sets it, and passes without the PM
|
||||
✔ usage: not with --pm, and only for activate (721.955423ms)
|
||||
✔ pm-after-harness-target (1015.757752ms)
|
||||
✔ pm-after-harness-set (1371.242025ms)
|
||||
✔ a pointer without pm (841.537689ms)
|
||||
✔ phase 1 installs without --pm, skips pm_launched and writes the pending pointer (1915.010297ms)
|
||||
✔ T32 item 1: --pm-after-harness refuses a target without harness or a file that sets it, and passes without the PM (5866.555622ms)
|
||||
▶ T33 item 2: read_pointer takes pmPending only as true beside pm false; a pending pointer refuses activate and shows in status
|
||||
✔ read_pointer (1570.154285ms)
|
||||
✔ pm-pending, already-adopted and the status line (3037.065347ms)
|
||||
✔ T33 item 2: read_pointer takes pmPending only as true beside pm false; a pending pointer refuses activate and shows in status (4607.778248ms)
|
||||
▶ T34 item 3: pm-on refuses before any stop, passes with the PM, or puts the phase-1 bus back
|
||||
✔ not-pending (719.010856ms)
|
||||
✔ harness-unset (2272.485716ms)
|
||||
✔ a launched line passes: the bus alone restarts with --pm (3276.598137ms)
|
||||
✔ a failed pm_launched puts the phase-1 unit back: exit 1, still pending (6693.543553ms)
|
||||
✔ a failed phase-1 gate too: pm-on-down, exit 2, both units stopped (8141.636634ms)
|
||||
✔ T34 item 3: pm-on refuses before any stop, passes with the PM, or puts the phase-1 bus back (21104.286659ms)
|
||||
▶ T35 item 4: rollback from pending installs --pm; a plug-in kind the target lacks refuses by name
|
||||
✔ rollback from pending gates pm_launched on the old copy (3372.092831ms)
|
||||
✔ after the harness set, rollback refuses until harness is gone (5046.857905ms)
|
||||
✔ activate names every kind the target lacks (1244.308621ms)
|
||||
✔ T35 item 4: rollback from pending installs --pm; a plug-in kind the target lacks refuses by name (9663.997607ms)
|
||||
✔ T36 --plan shows the pending state and lists the row 169 refusals it can see (3695.067003ms)
|
||||
✔ T37 tester-port activate writes pointer and unit, replaces the port, and supported re-pin and rollback keep it (6897.072525ms)
|
||||
✔ T38 tester-port rollback to unsupported target drops flag in plan, steps, unit and pointer (3812.546819ms)
|
||||
✔ T39 tester-port explicit unsupported target reads target copy and refuses before stopping either unit (904.276249ms)
|
||||
✔ T40 tester-port invalid values refuse exit 4 before stopping, including tunnel and main ports (819.160889ms)
|
||||
✔ T41 tester-port inherited activate to unsupported target drops it and retains drift refusal and failed-run recovery (8462.827367ms)
|
||||
✔ T42 tester-port pm-on preserves pointer Console flags (3200.83272ms)
|
||||
▶ T43 row 180 item 1: runs in one second get distinct activation ids, rollback sets and post-attempt stores
|
||||
✔ activate then pm-on on the same copy (3520.417628ms)
|
||||
✔ two restores: an old-form id and a suffixed one, each with its own post-attempt store (6507.524064ms)
|
||||
✔ adopt takes the next free id too (703.050442ms)
|
||||
✔ all ten names taken: capture-failed before anything stops, and the log line names no activation (956.29941ms)
|
||||
✔ --restore takes an id with or without -1 to -9 and nothing else (971.565868ms)
|
||||
✔ T43 row 180 item 1: runs in one second get distinct activation ids, rollback sets and post-attempt stores (12659.952034ms)
|
||||
▶ T44 row 180 item 2: --plan lists tester-port-invalid and tester-port-target with its other refusals
|
||||
✔ a bad tester port (1970.260005ms)
|
||||
✔ without --plan a bad port is usage before any pointer read (650.605696ms)
|
||||
✔ a target Console without --tester-port (1005.8136ms)
|
||||
✔ T44 row 180 item 2: --plan lists tester-port-invalid and tester-port-target with its other refusals (3627.354723ms)
|
||||
▶ T45 row 181 items 2 and 3: the restore guard counts events and every COUNTED table
|
||||
✔ both modes count events and each listed table, and a table the store lacks counts 0 (817.850391ms)
|
||||
✔ one instance_names row and no event refuses before any stop; --events 1 restores (4258.491111ms)
|
||||
✔ one usage_records row and no event refuses before any stop; --events 1 restores (4200.77682ms)
|
||||
✔ a listed table that cannot be read refuses restore-mismatch before any stop (2308.610496ms)
|
||||
✔ the in-run recount counts the listed tables too (3113.596786ms)
|
||||
✔ T45 row 181 items 2 and 3: the restore guard counts events and every COUNTED table (14700.29833ms)
|
||||
✔ T46 row 181 item 4: every table in the bus schema is in exactly one of four lists (3.037176ms)
|
||||
✔ T47 row 185 test 1: a same-schema activate leaves a whole backup and the log line names it (1868.973993ms)
|
||||
✔ T48 row 185 test 2: a gate failure on a same-schema activate rolls back without a restore (5804.760552ms)
|
||||
▶ T49 row 185 test 3: a same-schema rollback --restore restores, or refuses rows written after STAMP
|
||||
✔ no rows after STAMP: restores and goes live (3320.288695ms)
|
||||
✔ one instance_names row after STAMP refuses post-backup-events; --events 1 restores (3651.108762ms)
|
||||
✔ T49 row 185 test 3: a same-schema rollback --restore restores, or refuses rows written after STAMP (6972.06843ms)
|
||||
✔ T50 row 185 test 4: activate --plan prints the backup line and writes nothing (2352.202566ms)
|
||||
✔ T51 row 185 test 5: an activate with no store file takes no backup (2180.71818ms)
|
||||
▶ T52 row 186: the activate plan's backup line says what the run will do
|
||||
✔ same schema (2482.119077ms)
|
||||
✔ same schema with --migrate (2194.383877ms)
|
||||
✔ in chain with --migrate (2161.378827ms)
|
||||
✔ in chain without --migrate (1945.096692ms)
|
||||
✔ outside the chain (1933.991036ms)
|
||||
✔ outside the chain with --migrate (1982.219098ms)
|
||||
✔ T52 row 186: the activate plan's backup line says what the run will do (12700.35568ms)
|
||||
✔ T178 proxy proof header and path survive re-pin and rollback unchanged in the pointer and unit (3084.56264ms)
|
||||
✔ T178 proxy proof pair survives a tester-port replacement as well (1871.352274ms)
|
||||
▶ T53 row 187: activate sets, carries and drops the proof pair
|
||||
✔ tests 1 and 9: the pair goes after the preview flags, before --send and the kept --tester-port, as the unit renders it; a new pair replaces it (5957.458612ms)
|
||||
✔ tests 2 and 3: an activate of the live copy writes the pair; a later activate and a rollback carry it (4748.919152ms)
|
||||
✔ test 2: only a pair change may name the live copy; the log keeps from and to, and rollback still goes to the earlier copy (6348.550383ms)
|
||||
✔ test 2: a live-copy activate says only the Console flags change, and backs up the stopped store before it installs (3766.45236ms)
|
||||
✔ test 3: pm-on keeps the pair (2959.180793ms)
|
||||
✔ test 4: --no-proof drops the pair from the pointer and the unit and says so; with no pair it says so and passes (5233.036939ms)
|
||||
✔ test 5: each refusal exits 3 before anything stops (3649.68534ms)
|
||||
✔ tests 5 and 9: --plan lists every proof refusal with the others and writes nothing (836.025341ms)
|
||||
✔ test 6: usage errors (773.25631ms)
|
||||
✔ test 7: a rollback to a copy without proof support drops the pair and says so (3311.183201ms)
|
||||
✔ test 7: an activate to a copy without proof support refuses proof-target without --no-proof and passes with it (3616.1202ms)
|
||||
✔ T53 row 187: activate sets, carries and drops the proof pair (41201.876404ms)
|
||||
▶ T54 row 188: a carried pair gets the proof file checks, and a proof file inside the repository refuses
|
||||
✔ test 1: an activate that carries the pair refuses after chmod 644, in the plan and the run, before anything stops (2194.421439ms)
|
||||
✔ test 1: an activate that carries the pair refuses after a symlink to a mode-600 file, in the plan and the run, before anything stops (2189.529552ms)
|
||||
✔ test 1: an activate that carries the pair refuses after removal, in the plan and the run, before anything stops (2243.035352ms)
|
||||
✔ test 2: a rollback that carries the pair refuses after chmod 644, in the plan and the run, before anything stops (2336.000835ms)
|
||||
✔ test 3: a proof file inside the repository refuses, in the plan and the run, before anything stops (1105.046097ms)
|
||||
✔ test 4: a path outside the repository through a directory symlink into it refuses on its realpath (1150.666433ms)
|
||||
✔ T54 row 188: a carried pair gets the proof file checks, and a proof file inside the repository refuses (11219.876632ms)
|
||||
▶ T55 row 189: activate --no-send drops --send, and rollback and pm-on carry it off
|
||||
✔ test 1: a live-copy --no-send drops --send from the pointer and the unit, keeps the rest in order, logs the step and backs up the stopped store (2274.3857ms)
|
||||
✔ test 2: a plain live-copy activate still refuses already-active, and so does --no-send once --send is gone (3110.763383ms)
|
||||
✔ test 3: --plan prints one send: line in each case, with the live-copy note on a same-copy run (4485.563548ms)
|
||||
✔ test 4: after --no-send, a rollback to the earlier copy leaves --send out of the pointer and the unit (3260.741012ms)
|
||||
✔ test 4: pm-on after --no-send keeps --send off (3151.996202ms)
|
||||
✔ test 5: --no-send on rollback, pm-on, status, adopt or rehearse is a usage error (654.253174ms)
|
||||
✔ test 6: with both a pair and --send in the pointer, --no-send and --no-proof each drop what they name and keep the rest (9881.189087ms)
|
||||
✔ T55 row 189: activate --no-send drops --send, and rollback and pm-on carry it off (26820.278319ms)
|
||||
▶ T57 row 200: activate --sso, its refusals before any stop, and the rollback to a Console without --sso
|
||||
✔ item 1: --sso drops the preview set and the pair, puts --sso before --send and the tester port, and the plan names what it drops and carries (3703.052075ms)
|
||||
✔ item 1: --sso may re-pin the live copy once; later activates carry it; --no-send still drops --send (8819.731338ms)
|
||||
✔ item 1: --sso with a pair or --no-proof, or on any verb but activate, is a usage error (692.195455ms)
|
||||
✔ item 2: a target without --sso, a missing or bad console.sso, and each slot problem refuse before any stop (5662.393194ms)
|
||||
✔ item 3: a config whose console key the target loader refuses stops an activate or a rollback before any stop, naming the first step (4284.150525ms)
|
||||
✔ item 3: a rollback from --sso to a Console without it takes the flags from the set of the activation onto the copy, past a same-copy re-pin (sage-1389) (11448.283647ms)
|
||||
✔ item 3: a rollback set that is missing, fails its sums, holds no argv or already ran --sso refuses sso-rollback-flags (4548.577973ms)
|
||||
✔ round 2 (webby-0028 N1): run through a symlinked repository path, a slot or a proof file inside the repository still refuses (2401.295904ms)
|
||||
✔ round 2 (webby-0028 N2): a config.json that does not parse stops the run before anything is read or stopped (2172.272961ms)
|
||||
✔ round 3 (sage-1556): a named instance turns --sso on with its own config, slot and Console unit, and rolls back from its own set (4291.803296ms)
|
||||
✔ row 238 (#1744): on a named instance the sso-config first step names --instance NAME in both commands (1134.427878ms)
|
||||
✔ T57 row 200: activate --sso, its refusals before any stop, and the rollback to a Console without --sso (49160.357454ms)
|
||||
✔ R1 rehearse passes on the same schema; the scratch root holds its files and the live files stay byte-identical (3480.635997ms)
|
||||
✔ R2 rehearse runs the migration checks when the schema differs; the live store stays at 3g (3538.664935ms)
|
||||
✔ R3 a failing migration gives REHEARSAL_FAIL migrate and starts nothing (352.394887ms)
|
||||
✔ R4 a host that does not start, does not answer status, reports another pid, launches anyway, makes a launches directory or keeps its lock each fails by name (22497.071985ms)
|
||||
✔ R5 a host that ignores SIGTERM gets SIGKILL and FAIL host-stopped (4425.852712ms)
|
||||
✔ R6 a Console that does not answer /healthz gives REHEARSAL_FAIL healthz (5628.652507ms)
|
||||
✔ R7 a host on another copy fails copy-match (5626.942239ms)
|
||||
✔ R8 a scratch port in use or reserved refuses, and the rehearsal takes no other port (483.876429ms)
|
||||
✔ R9 mos-0963: a role reference left outside placeholders/, or left on an env variable, fails credential-ref-live before the host starts (737.183647ms)
|
||||
✔ R10 mos-0962: a scratch business that still sets a tracker fails tracker-configured (336.641991ms)
|
||||
✔ R11 mos-0961: a scratch config on the live data root or on any root but the scratch one, or a sessions.json naming a running pid, refuses by name (1329.146892ms)
|
||||
✔ R12 mos-0962: a notifier config with a binding fails notify-off (322.530573ms)
|
||||
✔ R13 the pre-checks: an old copy, a backup that fails its sums, a missing backup or pointer, and usage (467.892209ms)
|
||||
✔ R14 a host that writes the live config, the live business file or the backup fails the end check by name (9332.612807ms)
|
||||
✔ R15 a rehearsal stopped by TERM, INT or HUP fails signal and still stops the host and Console and runs the end checks (9980.867141ms)
|
||||
✔ row 233: --backup last takes the newest backup the log records; a later line with backup null does not hide it, and the store line names it (3438.884089ms)
|
||||
✔ row 233: --backup last with no backup in the log, or no log, exits 3 with no-backup and makes no rehearsal directory (190.873827ms)
|
||||
✔ row 233: --backup last refuses a newest backup that is not an activation id, with exit 1 (117.903969ms)
|
||||
▶ T56 row 190: named instances side by side on one unit directory, $BIN and set of stand-ins
|
||||
✔ T-I3 each instance renders its own config, session env and Description, and nothing of another (1497.847969ms)
|
||||
✔ T-I4 a Console port another installed Console takes refuses port-claimed, and a named instance keeps off the default ports (1995.198242ms)
|
||||
✔ T-I6 alpha's activate and rollback reach nothing of beta's (3765.448219ms)
|
||||
✔ T-I6 swapped: beta's reach nothing of alpha's (3738.069466ms)
|
||||
✔ T-I7 MOSAIC_CONFIG naming alpha's config with no flag refuses instance-root-mismatch and changes nothing (672.561735ms)
|
||||
✔ T-I9 another instance's bus active refuses nothing; one of this instance's does (5819.537565ms)
|
||||
✔ T56 row 190: named instances side by side on one unit directory, $BIN and set of stand-ins (17490.000329ms)
|
||||
ℹ tests 196
|
||||
ℹ suites 0
|
||||
ℹ pass 196
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 533493.817869
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
✔ row 233: sequence 1: confirm fails healthz, the driver reverts, renders the old copy and confirm --rollback --cause A5 passes: exit 1 (6210.373434ms)
|
||||
✔ row 233: sequence 2: activate --migrate fails at the wrapper, revert restores the store, confirm --rollback --cause A3: exit 1 (3236.556603ms)
|
||||
✔ row 233: sequence 3: root's render of the new copy fails, the driver rolls back with --cause A4, and holds the lock to the end: exit 1 (3088.506825ms)
|
||||
✔ row 233: sequence 4: a capture failure is exit 3 from the stage, and A2f restarts the old units and gates them: exit 1 (2296.722984ms)
|
||||
✔ row 233: N1: a bus that outlives A2's timeout keeps its old start, so A2f's gate fails stale-start: exit 2, both units stopped (7977.855045ms)
|
||||
✔ row 233: sequence 5: confirm of the wrong copy is refused, and the driver rolls back with --cause A5: exit 1 (3484.271196ms)
|
||||
✔ row 233: sequence 6: a revert that fails stops both units at exit 2, and the next run refuses at its --plan with nothing stopped (2709.834241ms)
|
||||
✔ row 233: sequence 7: two upgrades and a rollback --to the previous copy with --restore, the args file following each confirm (7481.097653ms)
|
||||
✔ row 240: I3 N1: a failed args move after A5 exits 5 args-failed, the new copy live and confirmed and both args files kept (2791.714439ms)
|
||||
✔ row 233: sequence 8: a migration that writes and fails: the driver reverts to the backup byte for byte, --cause A3: exit 1 (3155.287145ms)
|
||||
✔ row 233: a second run while the lock is held refuses upgrade-running with one log line and no call (659.849042ms)
|
||||
✔ row 233: A1 refuses open-activation on any AWAITING-UNITS file, through the stack's user's --plan, with nothing stopped (1064.03698ms)
|
||||
✔ row 233: a target that migrates refuses migrate-required without --migrate, with nothing stopped (1067.011634ms)
|
||||
✔ row 233: the rehearsal runs after the plan and before A2; a failed one refuses rehearsal-failed with nothing stopped (1099.022074ms)
|
||||
✔ row 233: the rehearsal's BACKUP_STORE line goes to the step log after a match, a malformed one as none, the rest of its output never (2918.095196ms)
|
||||
✔ row 233: a real rehearsal with no backup in the log refuses no-backup, and goes on only with --no-rehearsal, which logs the skip (3400.448853ms)
|
||||
✔ row 233: a real rehearsal after an upgrade names the log's newest backup; --no-rehearsal with a backup refuses rehearsal-required (3795.598553ms)
|
||||
✔ row 233: the args file must be the running user's, with no group or other write, one --copy, and the copy the units run (839.804685ms)
|
||||
✔ row 233: hostcheck (row 240): a nonzero --check or a missing file refuses profile-drift before the plan (962.315692ms)
|
||||
✔ row 233: the checkout must be at --sha (head-mismatch), and a commit the clone can't fast-forward to refuses fetch-failed (936.914531ms)
|
||||
✔ row 233: usage exits 4 before any log or lock (685.887579ms)
|
||||
ℹ tests 21
|
||||
ℹ suites 0
|
||||
ℹ pass 21
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 60456.446459
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
✔ C2-04: a library-only business with tracker.baseUrl boots without a project tracker (143.257728ms)
|
||||
task.close {} answered: invalid-request; fake saw 18 requests, first GET /info 200, GET /projects/1 200, GET /projects/1/views 200
|
||||
task.close on a missing task answered: task-not-found; it made GET /tasks/999 404
|
||||
✔ bootConfig trackers reach the S3 adapter in the real broker child, which goes ready against a fake Vikunja (274.054339ms)
|
||||
ℹ tests 2
|
||||
ℹ suites 0
|
||||
ℹ pass 2
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 502.723687
|
||||
@@ -0,0 +1,24 @@
|
||||
✔ C2-04 mirror: exact default path, bare without checkout or remote, and idempotent initialization (35.180686ms)
|
||||
✔ C2-04 mirror: simultaneous creators publish one intact mirror and leave no staging paths (28.575775ms)
|
||||
✔ C2-04 mirror: skipped publication accepts both coreutils statuses without removing the winner (100.935123ms)
|
||||
✔ C2-04 mirror: preserve occupied directories and reject symlink ancestors and code overlaps (11.206477ms)
|
||||
✔ C2-04 mirror: existing metadata accepts only bare Git plus state and the precreated lock (20.077192ms)
|
||||
✔ C2-04 state: missing state is empty only while the served ref is absent (32.816347ms)
|
||||
✔ C2-04 state: valid problems and sync metadata return no content and change no state bytes (34.864084ms)
|
||||
✔ C2-04 state: strict keys, types, times, branch, commit and fixed R messages fail closed (97.291867ms)
|
||||
✔ C2-04 state: symlink, hardlink, non-private state and missing lock refuse without replacement (29.030379ms)
|
||||
✔ C2-04 file: served commit, not HEAD or a caller commit, owns the exact returned text (71.409306ms)
|
||||
✔ C2-04 file: R1, R2 and R7 exclusions and never-synced mirrors cannot return file bodies (78.061049ms)
|
||||
✔ C2-04 lock: a first-sync and fast-forward reader wait for a consistent pair across processes (230.30816ms)
|
||||
✔ C2-04 lock: same-process waits, timeout code, callback expiry and throw release (5027.25259ms)
|
||||
✔ C2-04 lock: owner death releases the kernel lock without replacing its file (52.471475ms)
|
||||
✔ C2-04 lock: a missing flock binary becomes a handled refusal (44.850141ms)
|
||||
✔ C2-04 lock: an unawaited scoped read drains before the lock is released (19.645975ms)
|
||||
ℹ tests 16
|
||||
ℹ suites 0
|
||||
ℹ pass 16
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 5963.543966
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
✔ C2-04: record APIs refuse a library before creating a repository (2.136303ms)
|
||||
✔ init creates a checked versioned layout, valid templates and human-authored local history (25.282114ms)
|
||||
✔ init honors repo, refuses a non-empty directory and an undeclared project without touching files (13.067957ms)
|
||||
✔ check reports every bad record, filename mismatch and unknown top-level path (11.851979ms)
|
||||
✔ one writer commits validated docs, requirements and decisions with the bound agent author (66.653ms)
|
||||
✔ writer refuses spec paths, bad schemas, mismatched IDs and invalid actor metadata before changing history (14.848593ms)
|
||||
✔ writer refuses human pending edits and remotes instead of absorbing or contacting them (18.544136ms)
|
||||
✔ links, repo/code overlap, identity mismatch and a busy writer refuse safely (17.705717ms)
|
||||
✔ schemas remain package-owned and reject invalid nested data and dates (0.249795ms)
|
||||
✔ git commit failure restores only the attempted record and leaves human history unchanged (36.217826ms)
|
||||
✔ git hooks and ambient git identity cannot alter the record writer or execute outside actions (25.483658ms)
|
||||
✔ project-local schemas cannot weaken checks; invalid UTF-8 and linked git directories refuse (14.206204ms)
|
||||
✔ schema constraints and layout omissions are reported independently (12.868115ms)
|
||||
✔ unsupported schema keywords, malformed contexts, ignored local config and nonempty markers refuse (18.523225ms)
|
||||
✔ a linked git directory is refused before a writer lock can touch its target (30.574055ms)
|
||||
ℹ tests 15
|
||||
ℹ suites 0
|
||||
ℹ pass 15
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 355.86586
|
||||
@@ -0,0 +1,91 @@
|
||||
✔ C2-04: ensureCheckouts skips a library before a real clone and leaves no books path (22.355495ms)
|
||||
✔ a first launch clones the root at its branch, with the root's path as origin (23.522928ms)
|
||||
✔ the clone is not at its place until git clone has finished (19.304369ms)
|
||||
✔ a later launch fast-forwards a clean clone after a commit to the root, then finds it current (56.365259ms)
|
||||
✔ a clone ahead of the root keeps its commits and counts as current (35.573942ms)
|
||||
▶ a dirty clone and one on another branch are fetched, and nothing but refs/remotes moves
|
||||
✔ a modified file (41.519272ms)
|
||||
✔ an untracked file (42.31579ms)
|
||||
✔ a staged file (42.328417ms)
|
||||
✔ another branch (40.470049ms)
|
||||
✔ a detached HEAD (40.702516ms)
|
||||
✔ a dirty clone and one on another branch are fetched, and nothing but refs/remotes moves (208.344457ms)
|
||||
✔ a diverged clone gets the fetch into refs/remotes and is kept, not-fast-forward (42.026437ms)
|
||||
▶ a clone kept before the branch check, or for a failed status, gets no fetch
|
||||
✔ not-a-clone (22.404264ms)
|
||||
✔ hooks-present (23.073574ms)
|
||||
✔ submodule (30.027272ms)
|
||||
✔ config-changed (26.84014ms)
|
||||
✔ root-unreadable (27.464656ms)
|
||||
✔ root-detached (32.242501ms)
|
||||
✔ status-failed, on the root's branch and clean (35.760734ms)
|
||||
✔ status-failed, dirty (35.340017ms)
|
||||
✔ a clone kept before the branch check, or for a failed status, gets no fetch (234.251087ms)
|
||||
✔ a dirty clone whose fetch fails is kept, fetch-failed, exactly as it was (37.035833ms)
|
||||
✔ every git call the host makes, for a new clone and an existing one, carries maintenance.auto=false and gc.auto=0 (44.392371ms)
|
||||
✔ a clone with loose objects enough for gc --auto gets no maintenance or gc from the fetch and the merge (71.033894ms)
|
||||
▶ a clone with user.name or user.email in its config is kept, and git runs nothing in it
|
||||
✔ user.name (25.544784ms)
|
||||
✔ user.email (25.14754ms)
|
||||
✔ a clone with user.name or user.email in its config is kept, and git runs nothing in it (51.146879ms)
|
||||
✔ a commit git can't read after the fast-forward is null (45.746486ms)
|
||||
✔ a new clone whose commit can't be read refuses the launch and leaves nothing behind (18.576825ms)
|
||||
▶ a clone the session rigged is kept, and git runs nothing and writes nothing outside it
|
||||
✔ core.fsmonitor (33.120199ms)
|
||||
✔ core.hooksPath (33.027016ms)
|
||||
✔ a hook file (30.549575ms)
|
||||
✔ include.path (33.355749ms)
|
||||
✔ includeIf (33.915275ms)
|
||||
✔ a filter driver (34.236367ms)
|
||||
✔ origin moved (34.552998ms)
|
||||
✔ a second origin url (33.217597ms)
|
||||
✔ the origin url twice, both the root (34.870837ms)
|
||||
✔ an ext:: origin (33.6526ms)
|
||||
✔ a branch tracking another remote (33.582081ms)
|
||||
✔ a branch merging a tag (33.08648ms)
|
||||
✔ a fetch line onto local branches (34.366694ms)
|
||||
✔ no origin (33.938644ms)
|
||||
✔ a config file over the size cap (31.285987ms)
|
||||
✔ config a symlink to /dev/zero (31.094858ms)
|
||||
✔ the clone a symlink to the bait (32.754738ms)
|
||||
✔ the clone a file (31.24085ms)
|
||||
✔ the clone a plain directory (30.973366ms)
|
||||
✔ .git a gitdir: file (31.404094ms)
|
||||
✔ .git a symlink (30.769522ms)
|
||||
✔ .git/logs a symlink (30.883317ms)
|
||||
✔ .git/refs/heads a symlink (31.770074ms)
|
||||
✔ .git/objects a symlink (30.840803ms)
|
||||
✔ a reflog hard-linked to a file outside (30.322982ms)
|
||||
✔ HEAD a fifo (31.496048ms)
|
||||
✔ a commondir file (30.352537ms)
|
||||
✔ an alternates file (30.782307ms)
|
||||
✔ a gitlink staged, no .gitmodules (43.468245ms)
|
||||
✔ a gitlink and .gitmodules staged (44.893483ms)
|
||||
✔ a gitlink to a repository with its own gitlink (51.849481ms)
|
||||
✔ a gitlink and .gitmodules committed (47.718755ms)
|
||||
✔ a gitlink and submodule.active in config (44.861481ms)
|
||||
✔ a .git/modules with no gitlink (33.279554ms)
|
||||
✔ a clone the session rigged is kept, and git runs nothing and writes nothing outside it (1175.645437ms)
|
||||
▶ a root that can't be cloned refuses with the project id and leaves nothing behind
|
||||
✔ missing (10.161685ms)
|
||||
✔ not a repository (9.929001ms)
|
||||
✔ a plain directory inside another repository (14.613067ms)
|
||||
✔ unreadable (9.85915ms)
|
||||
✔ on no branch (11.8808ms)
|
||||
✔ missing an object (15.129485ms)
|
||||
✔ a root that can't be cloned refuses with the project id and leaves nothing behind (72.336456ms)
|
||||
✔ a clone whose root is on no branch, or gone, is kept and named (28.236024ms)
|
||||
✔ no credential or forge remote of the root reaches a clone (47.533999ms)
|
||||
✔ every project in the business file gets its own clone at its own branch (36.497038ms)
|
||||
✔ a clone past its time gets SIGTERM and refuses the launch, with nothing left in the workspace (513.397369ms)
|
||||
✔ a clone that ignores SIGTERM gets SIGKILL once the grace period is over (1018.126958ms)
|
||||
✔ a timeout signals git's process group, so a process git started dies with it (515.579592ms)
|
||||
✔ once a signalled git has closed, its group gets SIGKILL, so a process that ignored SIGTERM dies too (515.62296ms)
|
||||
ℹ tests 78
|
||||
ℹ suites 0
|
||||
ℹ pass 78
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 4880.907448
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
✔ C2-04 CLI: both listener callback pairs dispatch library verbs with their own transport (109.519835ms)
|
||||
ℹ tests 1
|
||||
ℹ suites 0
|
||||
ℹ pass 1
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 191.536271
|
||||
@@ -0,0 +1 @@
|
||||
{"processes": [], "removed": "/mnt/storage/scratch/gt-j5nm6iqn", "sourceHashesUnchanged": 29}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"base": "f8276c5eb",
|
||||
"tip": "8a04f4aa4aba493eb89e92aa9e0c34084be7058e",
|
||||
"overlap": []
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
2026-10-21T13:27:27.279728+00:00
|
||||
@@ -0,0 +1,194 @@
|
||||
[
|
||||
{
|
||||
"file": "packages/bus/tests/library.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 6,
|
||||
"pass": 6,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "01-packages_bus_tests_library.test.mjs.log"
|
||||
},
|
||||
{
|
||||
"file": "packages/bus/tests/project-runtime.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 3,
|
||||
"pass": 3,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "02-packages_bus_tests_project-runtime.test.mjs.log"
|
||||
},
|
||||
{
|
||||
"file": "packages/business/tests/business.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 19,
|
||||
"pass": 19,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "03-packages_business_tests_business.test.mjs.log"
|
||||
},
|
||||
{
|
||||
"file": "packages/business/tests/cli.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 10,
|
||||
"pass": 10,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "04-packages_business_tests_cli.test.mjs.log"
|
||||
},
|
||||
{
|
||||
"file": "packages/business/tests/instance-settings.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 13,
|
||||
"pass": 13,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "05-packages_business_tests_instance-settings.test.mjs.log"
|
||||
},
|
||||
{
|
||||
"file": "packages/business/tests/library-projects-protected.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 4,
|
||||
"pass": 4,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "06-packages_business_tests_library-projects-protected.test.mjs.log"
|
||||
},
|
||||
{
|
||||
"file": "packages/business/tests/resolve.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 11,
|
||||
"pass": 11,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "07-packages_business_tests_resolve.test.mjs.log"
|
||||
},
|
||||
{
|
||||
"file": "packages/cli/tests/launcher.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 31,
|
||||
"pass": 31,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "08-packages_cli_tests_launcher.test.mjs.log"
|
||||
},
|
||||
{
|
||||
"file": "packages/cli/tests/stack-release-external.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 25,
|
||||
"pass": 25,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "09-packages_cli_tests_stack-release-external.test.mjs.log"
|
||||
},
|
||||
{
|
||||
"file": "packages/cli/tests/stack-release.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 196,
|
||||
"pass": 196,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "10-packages_cli_tests_stack-release.test.mjs.log"
|
||||
},
|
||||
{
|
||||
"file": "packages/cli/tests/stack-upgrade.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 21,
|
||||
"pass": 21,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "11-packages_cli_tests_stack-upgrade.test.mjs.log"
|
||||
},
|
||||
{
|
||||
"file": "packages/cli/tests/trackers-boot.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 2,
|
||||
"pass": 2,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "12-packages_cli_tests_trackers-boot.test.mjs.log"
|
||||
},
|
||||
{
|
||||
"file": "packages/library/tests/mirror.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 16,
|
||||
"pass": 16,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "13-packages_library_tests_mirror.test.mjs.log"
|
||||
},
|
||||
{
|
||||
"file": "packages/project/tests/project.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 15,
|
||||
"pass": 15,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "14-packages_project_tests_project.test.mjs.log"
|
||||
},
|
||||
{
|
||||
"file": "packages/seat/tests/checkout.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 78,
|
||||
"pass": 78,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "15-packages_seat_tests_checkout.test.mjs.log"
|
||||
},
|
||||
{
|
||||
"file": "packages/webui/tests/library-cli.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 1,
|
||||
"pass": 1,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "16-packages_webui_tests_library-cli.test.mjs.log"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
/mnt/storage/scratch/gt-j5nm6iqn
|
||||
@@ -0,0 +1 @@
|
||||
2026-10-21T13:15:15.548778+00:00
|
||||
@@ -0,0 +1 @@
|
||||
{"tests": 451, "pass": 451, "fail": 0, "cancelled": 0, "skipped": 0}
|
||||
@@ -0,0 +1,14 @@
|
||||
✔ C2-04 M4: both verbs reject every agent before arguments or adapter access (31.111616ms)
|
||||
✔ C2-04 bus: human reads validate keys and return adapter results without path leakage (12.907709ms)
|
||||
✔ C2-04 socket: each async library verb resolves its result rather than serializing {} (14.631614ms)
|
||||
✔ C2-04 runtime: protectedRoots skips library but retains real code-root credential protection (42.32493ms)
|
||||
✔ C2-04 runtime: unsafe existing mirror refuses boot and never publishes a socket (20.701022ms)
|
||||
✔ C2-04 runtime: real library adapters reach the socket and lock waits leave other bus reads responsive (82.322654ms)
|
||||
ℹ tests 6
|
||||
ℹ suites 0
|
||||
ℹ pass 6
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 342.882774
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
✔ Broker keeps the sandbox client import closure: only the listed imports, no lazy project import (1.629219ms)
|
||||
✔ without a trusted project adapter all three async paths refuse project-not-configured (43.976856ms)
|
||||
✔ real startBroker injects the project adapter for socket reads and bound-author record writes (68.038516ms)
|
||||
ℹ tests 3
|
||||
ℹ suites 0
|
||||
ℹ pass 3
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 209.393305
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
✔ C2-04: library mappings load without roots, remain frozen, and retain mapping refusals (9.717487ms)
|
||||
✔ C2-04: an otherwise valid publish grant cannot name a library repo (1.932435ms)
|
||||
✔ config directory and file path follow MOSAIC_CONFIG (0.219374ms)
|
||||
✔ the fixture business validates and comes back frozen (0.988926ms)
|
||||
✔ two instances may share a definition (0.940973ms)
|
||||
✔ top-level refusals (3.202519ms)
|
||||
✔ arbiters and projects (4.893652ms)
|
||||
✔ role instances (2.749701ms)
|
||||
✔ Vikunja bots (5.88131ms)
|
||||
✔ a role without Vikunja takes no tracker block (4.097438ms)
|
||||
✔ credential references match the definition's services (2.14689ms)
|
||||
✔ launch (7.492201ms)
|
||||
✔ REQ-THREAD-2 REQ-LAUNCH-1 launch.threadIdleSeconds: absent is the default, a positive integer is used, anything else refuses (4.633228ms)
|
||||
✔ loadBusiness: file checks (1.761847ms)
|
||||
✔ loadBusiness: not a regular file (36.320112ms)
|
||||
✔ loading writes nothing (1.117059ms)
|
||||
✔ names that are Object.prototype properties don't count as declared (2.898886ms)
|
||||
✔ the shipped example refuses as written and validates once filled in (0.943369ms)
|
||||
ℹ tests 18
|
||||
ℹ suites 0
|
||||
ℹ pass 18
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 152.091247
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
✔ C2-04: business validate and resolve skip a library before code projects and credential checks (219.31729ms)
|
||||
✔ usage errors exit 4 (321.939555ms)
|
||||
✔ validate: a good business exits 0 and prints instance digests (76.14497ms)
|
||||
✔ validate: project files (353.409636ms)
|
||||
✔ validate: missing files and a broken system config (238.885921ms)
|
||||
✔ validate: credential reference problems exit 2 and name each one (72.187146ms)
|
||||
✔ validate: a token file inside the repository is refused (66.603163ms)
|
||||
✔ validate: role definitions come from MOSAIC_ROLES_DIR (212.341091ms)
|
||||
✔ resolve: prints one instance's record (340.865306ms)
|
||||
✔ resolve: refusals (526.732262ms)
|
||||
ℹ tests 10
|
||||
ℹ suites 0
|
||||
ℹ pass 10
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 2493.367293
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
✔ C2-04: instance settings skip a library while checking a later code project (33.384562ms)
|
||||
✔ row 165 read lists each instance and the definitions add accepts (2.667885ms)
|
||||
✔ row 165 add: two instances join, validate exits 0, the log names the human, and the bus restart is reported (87.186598ms)
|
||||
✔ row 165 change: definition, vars and launch membership log before and after; only a definition change asks for a restart (92.493768ms)
|
||||
✔ row 165 refuses each validation failure and leaves the file's bytes alone (29.566007ms)
|
||||
✔ row 165 refuses an added instance whose definition declares credentials, and says why (3.207564ms)
|
||||
✔ row 165 refuses a definition change to or from one that declares credentials (4.215516ms)
|
||||
✔ row 165 a vars or launch change on an instance with its binding succeeds and keeps the binding (72.107052ms)
|
||||
✔ row 165 refuses an END_PROTECTED definition and every change to a protected instance (7.281711ms)
|
||||
✔ row 165 refuses while a project file doesn't resolve, as validate would (13.645202ms)
|
||||
✔ row 165 refuses a stale revision and leaves the file's bytes alone (10.119096ms)
|
||||
✔ row 65 an instance write refuses harness-off, thinking-unsupported, an unknown model and a partial fallback (29.171515ms)
|
||||
ℹ tests 12
|
||||
ℹ suites 0
|
||||
ℹ pass 12
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 450.444507
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
✔ C2-04 M9: changed playground and hybrid entries leave business and changes.jsonl byte-identical (20.276877ms)
|
||||
✔ C2-04 M9: code projects, additions, deletions and array changes are protected too (16.209877ms)
|
||||
✔ C2-04 M9: canonical key order is allowed and a non-project setter still records its change (13.103686ms)
|
||||
✔ C2-04 M9: a serialization hook cannot change projects after the canonical comparison (12.598611ms)
|
||||
ℹ tests 4
|
||||
ℹ suites 0
|
||||
ℹ pass 4
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 112.92317
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
✔ C2-04: a library first in projects does not hide a later project layer (6.304379ms)
|
||||
✔ systemVars flattens the validated config (0.828852ms)
|
||||
✔ precedence: system, business, project, project role, agent (1.532829ms)
|
||||
✔ limits narrow the definition and never widen it (2.353655ms)
|
||||
✔ role.launch stays within-role only for the instance the launch block names (4.439921ms)
|
||||
✔ limits.authority without role.launch leaves the launcher with no launch block (1.815884ms)
|
||||
✔ limits.authority narrows cross-role actions too (0.827532ms)
|
||||
✔ classify (0.829892ms)
|
||||
✔ the record carries what the broker and launcher need (0.755977ms)
|
||||
✔ digest: key order doesn't matter, any value change does (5.452ms)
|
||||
✔ refusals (1.724971ms)
|
||||
ℹ tests 11
|
||||
ℹ suites 0
|
||||
ℹ pass 11
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 79.941483
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
✔ C2-04: launcher workspace clones code but never the library (1262.341325ms)
|
||||
✔ bus start --pm: the launcher instance (the chief of staff) runs under its own PID namespace, registered, with a manifest (1237.473965ms)
|
||||
usage: {"event":"usage-unknown","business":"acme","run":"r4414332d2ef5","instance":"chief","turn":"382a782c-719a-48e8-a249-ec24caf5ad1e","source":"@none","code":"baseline-unknown"}
|
||||
usage: {"event":"usage-unknown","business":"acme","run":"reaca93954ae7","instance":"coder","turn":"70bcac05-fbc1-41b2-85cb-725c15884a94","source":"@none","code":"baseline-unknown"}
|
||||
✔ the chief of staff launches a coder through its launch tool; the coder answers; refusals name their code (579.516254ms)
|
||||
usage: {"event":"usage-unknown","business":"acme","run":"rb21267233555","instance":"chief","turn":"c228faeb-6e3c-4453-ba9b-b9a27b9790af","source":"@none","code":"baseline-unknown"}
|
||||
usage: {"event":"usage-unknown","business":"acme","run":"r1fc01260daa7","instance":"pm","turn":"a5d09ce0-4208-4eb4-8178-6e06a1792ab9","source":"@none","code":"baseline-unknown"}
|
||||
usage: {"event":"usage-unknown","business":"acme","run":"rb21267233555","instance":"chief","turn":"25722023-5270-4c50-a8a0-7c3645d08bd7","source":"@none","code":"baseline-unknown"}
|
||||
usage: {"event":"usage-unknown","business":"acme","run":"r1fc01260daa7","instance":"pm","turn":"f4a76756-4300-4cdf-a64b-542fc075c137","source":"@none","code":"baseline-unknown"}
|
||||
usage: {"event":"usage-unknown","business":"acme","run":"r1fc01260daa7","instance":"pm","turn":"99ea9441-ce4e-4aab-a56c-614a30c9f0da","source":"@none","code":"baseline-unknown"}
|
||||
usage: {"event":"usage-unknown","business":"acme","run":"rb21267233555","instance":"chief","turn":"d85fa6e4-7557-4adf-b1f6-5e76455a1e51","source":"@none","code":"baseline-unknown"}
|
||||
usage: {"event":"usage-unknown","business":"acme","run":"r1fc01260daa7","instance":"pm","turn":"87f4bf91-2ef2-4fe7-8e99-09fc8b14887e","source":"@none","code":"baseline-unknown"}
|
||||
usage: {"event":"usage-unknown","business":"acme","run":"rb21267233555","instance":"chief","turn":"6db9d009-2cb9-41ba-a07e-da13d92b8182","source":"@none","code":"baseline-unknown"}
|
||||
✔ a launched pm's request_staff reaches the chief of staff; no other session has the tool and the launch limits still hold (917.244851ms)
|
||||
✔ each launch makes sure the workspace has a clone of the project: cloned, fast-forwarded, or fetched and logged (3692.977114ms)
|
||||
✔ a role the broker says holds a merge decision gets land_work, its prompt line, its landing and the git socket; without it, none (439.559581ms)
|
||||
✔ REQ-LAUNCH-1 the tick starts a listed merge decision holder once, with land_work, the Landing line and its landing turn; an unlisted holder starts nothing (324.77099ms)
|
||||
usage: {"event":"usage-unknown","business":"acme","run":"rd33ea739f0c8","instance":"coder","turn":"434622cc-98ff-44b4-99c9-58a8c92f32af","source":"@none","code":"baseline-unknown"}
|
||||
✔ a holder running since before the resolution is stopped once the broker releases it, land-relaunch, and the next tick starts it: landing turn first, then the message that waited (502.385034ms)
|
||||
✔ a landing run that ended isn't started again for its decision, a spent decision starts nothing, and a new decision starts the holder (453.667705ms)
|
||||
✔ after a restart, the new host's first tick starts a holder whose decision is still held (654.880099ms)
|
||||
✔ a refused landing start is logged once per code with its decision, isn't a start, and the next tick with room starts the holder (498.662638ms)
|
||||
✔ a project clone that can't be made refuses checkout-failed, from --chief and from a session, with no run and no clone left (208.782448ms)
|
||||
✔ a runner that stops at once ends its launch with the runner's reason (261.153743ms)
|
||||
✔ a Claude Code launch with no session credential refuses before it starts (143.737058ms)
|
||||
✔ a pi launch needs no session credential: pi logs in through its own ENV_ALLOW variables (239.874115ms)
|
||||
usage: {"event":"plugin-refused","kind":"harness","name":"down","code":"missing","message":"/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row215-on212/packages/plugins/harness/down is missing","kept":[]}
|
||||
plugins: {"event":"plugin-refused","kind":"harness","name":"down","code":"missing","message":"/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row215-on212/packages/plugins/harness/down is missing","kept":[]}
|
||||
✔ row 65 a failed primary preflight launches the fallback on a fixture harness module, recording the route and the reason (281.577833ms)
|
||||
✔ a runner killed from the host ends its launch as killed, not failed (297.263791ms)
|
||||
✔ a missing or failing bwrap refuses sandbox-unavailable before anything starts; there is no unconfined fallback (151.327191ms)
|
||||
✔ row 64 a role skill that isn't enabled refuses skill-not-enabled, and one that isn't a plain directory skill-refused, before anything starts (151.537445ms)
|
||||
✔ row 64 on Claude Code a role skill that isn't enabled refuses the same way, before anything starts (166.552674ms)
|
||||
usage: {"event":"usage-unknown","business":"acme","run":"rc42c73baf400","instance":"chief","turn":"e62acc78-0ddd-4cd3-bb90-c828cf5dc76e","source":"@none","code":"baseline-unknown"}
|
||||
usage: {"event":"usage-unknown","business":"acme","run":"r9fac1139247f","instance":"coder","turn":"e634dd74-b64a-4c8d-8e8d-90244a1070d4","source":"@none","code":"baseline-unknown"}
|
||||
✔ a real Claude Code coder's shell can't read a stand-in secret or anything else its sandbox doesn't hold (1685.572916ms)
|
||||
✔ a host that died hard leaves its sessions to the next host, which kills them and ends their runs so the role can be launched again (791.200293ms)
|
||||
✔ a host that died hard leaves its sessions to the next host, which finds one already exited (23) and ends their runs so the role can be launched again (3731.707174ms)
|
||||
✔ bus start --no-launch leaves an earlier host's live session alone: no signal, no end, sessions.json as it was (196.993732ms)
|
||||
✔ bus start --no-launch refuses every launch: the PM launch and a session's request, each logged, nothing spawned (159.584006ms)
|
||||
✔ bus start --no-launch starts no thread tick; the same host with launches runs it (1086.093241ms)
|
||||
✔ a malformed sessions.json refuses the host start with exit 3 and stays as it was (132.916552ms)
|
||||
✔ an over-long launch request is refused at once, not at the 10 s idle timeout (143.651083ms)
|
||||
✔ a launch client that never closes its side doesn't hold the host's close (144.715063ms)
|
||||
✔ a runner that ignores SIGTERM is killed when the host closes (1275.914847ms)
|
||||
ℹ tests 30
|
||||
ℹ suites 0
|
||||
ℹ pass 30
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 21918.233853
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
✔ row 232: confirm, revert, gate, --to and --expect-from need --units external; the user-only flags are usage under it (832.842347ms)
|
||||
✔ row 232: pm-on and activate --pm-after-harness refuse external-pm (934.889182ms)
|
||||
✔ row 232: units-running (N4) refuses while a unit is active and leaves the store, the log and TAKEN; failed counts as down (2121.604528ms)
|
||||
✔ row 232: activate stages: the pointer stays, AWAITING-UNITS names TO, a backup of the stopped store, no directory in the set, no --user, no journal (1777.227274ms)
|
||||
✔ row 232: A3 order: capture-failed and marker-failed refuse with exit 3 and leave no marker or FAILED (1712.692045ms)
|
||||
✔ row 232: confirm and revert refuse open-activation with no marker, two, the wrong copy, or one the log holds closed; refusals name no activation (3642.165244ms)
|
||||
✔ row 232: confirm polls: bus status good after 3 s fails with --timeout 1, writes FAILED and leaves the rest; FAILED then refuses activation-failed (3522.196896ms)
|
||||
✔ row 232: confirm polls to a pass with --timeout 10: the pointer, an ok line that reads as the started run, no marker (5641.501857ms)
|
||||
✔ row 232: stale-start: @1792540799 fails a start floor of 1792540800 with stale-start (3076.294408ms)
|
||||
✔ row 232: stale-start is a gate code: an enter time that turns to @1792540800 after 2 s passes with --timeout 10 (4471.752137ms)
|
||||
✔ row 232: gate (N2, A2f): --since 1792540800 passes @1792540800 and fails @1792540799; it writes nothing (2692.190142ms)
|
||||
✔ row 232: the external PM check reads launches list: one live run of launch.by since the start passes (9781.807961ms)
|
||||
✔ row 232: revert puts the wrapper back and leaves the store when nothing migrated (1409.775029ms)
|
||||
✔ row 232: confirm --rollback refuses rollback-mismatch, and logs rollback-failed with exit 2 when OLD fails its gate (3556.739549ms)
|
||||
✔ row 232: confirm --rollback after a --restore swap logs rollbackCode not-attempted; rollback --restore finds an external backup (3258.873111ms)
|
||||
✔ row 232: sequence 1: activate, confirm times out, revert, confirm --rollback --cause A5: gate-failed rollback ok (4878.560819ms)
|
||||
✔ row 232: sequence 2: activate --migrate, the wrapper install fails, revert restores TAKEN, confirm --rollback --cause A3 (3203.155908ms)
|
||||
✔ row 232: sequence 3: activate, root's A4 fails, revert, confirm --rollback --cause A4: failed code units-start (2844.170694ms)
|
||||
✔ row 232: sequence 4: a capture failure leaves nothing open, then A2f's gate OLD writes nothing (1940.493148ms)
|
||||
✔ row 232: sequence 5: a confirm of the wrong copy is refused, and revert and confirm --rollback still close the activation (3423.561744ms)
|
||||
✔ row 232: sequence 6: a revert that fails leaves the activation open, and the next --plan refuses interrupted-run (1732.106092ms)
|
||||
✔ row 232: sequence 7: adopt, two confirmed activates, rollback --to the previous copy, confirmed, logs op rollback (8298.40004ms)
|
||||
✔ row 232: sequence 8: a migration that writes and fails: revert restores the backup byte for byte, confirm --rollback --cause A3 (3658.849346ms)
|
||||
✔ row 232: user mode: every systemctl call carries --user, and activate, rollback and check make the base's calls (7450.661653ms)
|
||||
✔ row 232: user mode: a default activate --plan prints the base's bytes (2572.062595ms)
|
||||
ℹ tests 25
|
||||
ℹ suites 0
|
||||
ℹ pass 25
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 89317.249955
|
||||
+227
@@ -0,0 +1,227 @@
|
||||
✔ T1 adopt writes the pointer from the units once; a failing check refuses check-failed (1372.806902ms)
|
||||
✔ T2 activate installs exactly the pointer's pm, claude and Console flags (2175.278069ms)
|
||||
▶ T3 a hand-edited unit refuses unit-flags-drift, names the difference and changes nothing
|
||||
✔ pm (940.434448ms)
|
||||
✔ claude (905.331444ms)
|
||||
✔ console (953.801488ms)
|
||||
✔ T3 a hand-edited unit refuses unit-flags-drift, names the difference and changes nothing (2800.414725ms)
|
||||
▶ T4 each item 3 refusal changes nothing and logs one line with its code
|
||||
✔ copy-missing (828.258816ms)
|
||||
✔ copy-unreachable (750.040135ms)
|
||||
✔ copy-schema-unknown (804.784952ms)
|
||||
✔ already-active (767.83377ms)
|
||||
✔ instance-busy (another business active) (836.742584ms)
|
||||
✔ instance-busy (this business activating) (824.181046ms)
|
||||
✔ drop-in-override (819.802212ms)
|
||||
✔ no-pointer (432.597537ms)
|
||||
✔ T4 each item 3 refusal changes nothing and logs one line with its code (6065.707472ms)
|
||||
✔ T5 an activate with no migration stops the Console then the bus, installs, starts the bus then the Console (1974.205406ms)
|
||||
✔ T6 a migration without --migrate rolls back with migration-needs-flag (1689.71261ms)
|
||||
✔ T7 --migrate takes the backup before the migration runs (1874.080499ms)
|
||||
✔ T8 a failed migration restores the backup and keeps the store it replaced (1879.088438ms)
|
||||
✔ T9 a store outside the target's chain rolls back with store-newer (1695.743767ms)
|
||||
▶ T10 each gate check failing alone rolls back and puts every file back
|
||||
✔ units-inactive (5145.320966ms)
|
||||
✔ bus-status (5504.739824ms)
|
||||
✔ healthz (4630.494167ms)
|
||||
✔ copy-check (4953.814776ms)
|
||||
✔ pm-launch-unconfirmed (5175.714883ms)
|
||||
✔ T10 each gate check failing alone rolls back and puts every file back (25411.164743ms)
|
||||
▶ T10b the PM check needs exactly one launched line for a live run of this start
|
||||
✔ no launched line (5309.620588ms)
|
||||
✔ two lines (5271.450965ms)
|
||||
✔ a changed word (5207.189363ms)
|
||||
✔ run not in launches list (5249.94294ms)
|
||||
✔ run started before the start (5297.104798ms)
|
||||
✔ a human launch with no journal line (5012.384828ms)
|
||||
✔ run for another business (5255.258408ms)
|
||||
✔ run not live (5155.194619ms)
|
||||
✔ one well-formed line and a live run pass (1936.667118ms)
|
||||
✔ T10b the PM check needs exactly one launched line for a live run of this start (43696.539474ms)
|
||||
✔ T11 a rollback whose gate fails too: rollback-failed, exit 2, both units stopped, no retry (9445.48752ms)
|
||||
✔ T12 rollback takes the previous copy from the log (3164.86878ms)
|
||||
✔ T13 a rollback across a migration needs --restore, then restores and goes live (3832.433037ms)
|
||||
✔ T14 events written after the backup need --events N with the right N (4300.182861ms)
|
||||
✔ T14b a rollback --restore whose gate fails stops both units and skips item 6 (5706.078353ms)
|
||||
✔ T14c a rollback without --restore whose gate fails runs item 6 (7364.684709ms)
|
||||
✔ T15 --plan names the migration and the restore and changes nothing (2976.558ms)
|
||||
✔ T26 --plan lists the commits an activate adds, after the migration lines (1448.921448ms)
|
||||
✔ T27 --plan names each migration step, or says the steps cannot be read (1074.961775ms)
|
||||
✔ T25 --plan refuses copies-unrelated when neither copy is an ancestor of the other (504.611631ms)
|
||||
▶ T23 --plan reads the store without changing a file, stopped or held
|
||||
✔ stopped store (612.654192ms)
|
||||
✔ held store (615.45405ms)
|
||||
✔ T23 --plan reads the store without changing a file, stopped or held (1228.613968ms)
|
||||
✔ T24 business-mismatch and capture-failed refuse with exit 3; a short id is a usage error (1504.453363ms)
|
||||
✔ T16 status prints the pointer, the log, the check, bus status and drift, and writes nothing (969.540282ms)
|
||||
✔ T19 a started line with no final line: status shows it and every changing verb refuses (1272.112268ms)
|
||||
✔ T20 a held run lock refuses run-locked without a log line; status and --plan still run (1363.537596ms)
|
||||
✔ T21 a bus unit with no MOSAIC_CLAUDE_BIN: adopt and activate refuse no-claude-pin (1516.277233ms)
|
||||
▶ T22 the stopped store read: a -wal or -shm refuses store-unclean and is left alone; a clean read adds no file
|
||||
✔ bus.sqlite-wal (1776.498328ms)
|
||||
✔ bus.sqlite-shm (1805.948894ms)
|
||||
✔ clean (1860.970301ms)
|
||||
✔ T22 the stopped store read: a -wal or -shm refuses store-unclean and is left alone; a clean read adds no file (5444.145497ms)
|
||||
▶ T28 a unit path, drop-in directory or drop-in file that cannot be read, or a relative unit path, refuses drop-in-override before any stop
|
||||
✔ unit path (838.2428ms)
|
||||
✔ drop-in directory (770.669306ms)
|
||||
✔ drop-in file (787.861386ms)
|
||||
✔ relative unit path (799.918614ms)
|
||||
✔ T28 a unit path, drop-in directory or drop-in file that cannot be read, or a relative unit path, refuses drop-in-override before any stop (3197.49908ms)
|
||||
▶ T29 a bus that stops during the held-store read: --plan says so, rollback --restore refuses restore-mismatch
|
||||
✔ --plan (842.842612ms)
|
||||
✔ rollback --restore (2383.664939ms)
|
||||
✔ T29 a bus that stops during the held-store read: --plan says so, rollback --restore refuses restore-mismatch (3227.016275ms)
|
||||
✔ T30 a copy check that agrees on another copy fails the gate with copy-check and rolls back (4822.028878ms)
|
||||
▶ T31 a quoted or escaped Environment= or ExecStart= is unreadable: refusals by name, nothing read from /a
|
||||
✔ Environment double quotes (1747.115914ms)
|
||||
✔ Environment single quotes (1747.871141ms)
|
||||
✔ Environment backslash (1718.42505ms)
|
||||
✔ ExecStart quotes (1733.916441ms)
|
||||
✔ Console ExecStart quotes (1805.192313ms)
|
||||
✔ T31 a quoted or escaped Environment= or ExecStart= is unreadable: refusals by name, nothing read from /a (8753.514814ms)
|
||||
▶ T32 item 1: --pm-after-harness refuses a target without harness or a file that sets it, and passes without the PM
|
||||
✔ usage: not with --pm, and only for activate (630.81989ms)
|
||||
✔ pm-after-harness-target (949.989597ms)
|
||||
✔ pm-after-harness-set (1400.026643ms)
|
||||
✔ a pointer without pm (849.389257ms)
|
||||
✔ phase 1 installs without --pm, skips pm_launched and writes the pending pointer (2037.948918ms)
|
||||
✔ T32 item 1: --pm-after-harness refuses a target without harness or a file that sets it, and passes without the PM (5869.092521ms)
|
||||
▶ T33 item 2: read_pointer takes pmPending only as true beside pm false; a pending pointer refuses activate and shows in status
|
||||
✔ read_pointer (1646.25297ms)
|
||||
✔ pm-pending, already-adopted and the status line (2899.447167ms)
|
||||
✔ T33 item 2: read_pointer takes pmPending only as true beside pm false; a pending pointer refuses activate and shows in status (4546.229216ms)
|
||||
▶ T34 item 3: pm-on refuses before any stop, passes with the PM, or puts the phase-1 bus back
|
||||
✔ not-pending (781.816005ms)
|
||||
✔ harness-unset (2528.770078ms)
|
||||
✔ a launched line passes: the bus alone restarts with --pm (3635.97518ms)
|
||||
✔ a failed pm_launched puts the phase-1 unit back: exit 1, still pending (6129.763508ms)
|
||||
✔ a failed phase-1 gate too: pm-on-down, exit 2, both units stopped (10681.440065ms)
|
||||
✔ T34 item 3: pm-on refuses before any stop, passes with the PM, or puts the phase-1 bus back (23758.959718ms)
|
||||
▶ T35 item 4: rollback from pending installs --pm; a plug-in kind the target lacks refuses by name
|
||||
✔ rollback from pending gates pm_launched on the old copy (3432.493856ms)
|
||||
✔ after the harness set, rollback refuses until harness is gone (4814.40527ms)
|
||||
✔ activate names every kind the target lacks (1278.267995ms)
|
||||
✔ T35 item 4: rollback from pending installs --pm; a plug-in kind the target lacks refuses by name (9525.935986ms)
|
||||
✔ T36 --plan shows the pending state and lists the row 169 refusals it can see (3442.637109ms)
|
||||
✔ T37 tester-port activate writes pointer and unit, replaces the port, and supported re-pin and rollback keep it (6713.755862ms)
|
||||
✔ T38 tester-port rollback to unsupported target drops flag in plan, steps, unit and pointer (3556.909655ms)
|
||||
✔ T39 tester-port explicit unsupported target reads target copy and refuses before stopping either unit (816.518752ms)
|
||||
✔ T40 tester-port invalid values refuse exit 4 before stopping, including tunnel and main ports (798.151327ms)
|
||||
✔ T41 tester-port inherited activate to unsupported target drops it and retains drift refusal and failed-run recovery (8335.191178ms)
|
||||
✔ T42 tester-port pm-on preserves pointer Console flags (3045.995877ms)
|
||||
▶ T43 row 180 item 1: runs in one second get distinct activation ids, rollback sets and post-attempt stores
|
||||
✔ activate then pm-on on the same copy (3077.866023ms)
|
||||
✔ two restores: an old-form id and a suffixed one, each with its own post-attempt store (6478.022663ms)
|
||||
✔ adopt takes the next free id too (676.463788ms)
|
||||
✔ all ten names taken: capture-failed before anything stops, and the log line names no activation (927.509173ms)
|
||||
✔ --restore takes an id with or without -1 to -9 and nothing else (1026.017549ms)
|
||||
✔ T43 row 180 item 1: runs in one second get distinct activation ids, rollback sets and post-attempt stores (12186.978758ms)
|
||||
▶ T44 row 180 item 2: --plan lists tester-port-invalid and tester-port-target with its other refusals
|
||||
✔ a bad tester port (2101.036117ms)
|
||||
✔ without --plan a bad port is usage before any pointer read (417.577025ms)
|
||||
✔ a target Console without --tester-port (1050.997021ms)
|
||||
✔ T44 row 180 item 2: --plan lists tester-port-invalid and tester-port-target with its other refusals (3570.568101ms)
|
||||
▶ T45 row 181 items 2 and 3: the restore guard counts events and every COUNTED table
|
||||
✔ both modes count events and each listed table, and a table the store lacks counts 0 (819.811738ms)
|
||||
✔ one instance_names row and no event refuses before any stop; --events 1 restores (4281.220981ms)
|
||||
✔ one usage_records row and no event refuses before any stop; --events 1 restores (4339.553222ms)
|
||||
✔ a listed table that cannot be read refuses restore-mismatch before any stop (3011.194623ms)
|
||||
✔ the in-run recount counts the listed tables too (3456.814799ms)
|
||||
✔ T45 row 181 items 2 and 3: the restore guard counts events and every COUNTED table (15910.111456ms)
|
||||
✔ T46 row 181 item 4: every table in the bus schema is in exactly one of four lists (2.96277ms)
|
||||
✔ T47 row 185 test 1: a same-schema activate leaves a whole backup and the log line names it (1839.922479ms)
|
||||
✔ T48 row 185 test 2: a gate failure on a same-schema activate rolls back without a restore (5782.007105ms)
|
||||
▶ T49 row 185 test 3: a same-schema rollback --restore restores, or refuses rows written after STAMP
|
||||
✔ no rows after STAMP: restores and goes live (3276.614244ms)
|
||||
✔ one instance_names row after STAMP refuses post-backup-events; --events 1 restores (3603.193575ms)
|
||||
✔ T49 row 185 test 3: a same-schema rollback --restore restores, or refuses rows written after STAMP (6880.328466ms)
|
||||
✔ T50 row 185 test 4: activate --plan prints the backup line and writes nothing (2392.362463ms)
|
||||
✔ T51 row 185 test 5: an activate with no store file takes no backup (2055.74343ms)
|
||||
▶ T52 row 186: the activate plan's backup line says what the run will do
|
||||
✔ same schema (2076.652498ms)
|
||||
✔ same schema with --migrate (2103.728264ms)
|
||||
✔ in chain with --migrate (2343.740358ms)
|
||||
✔ in chain without --migrate (2172.44891ms)
|
||||
✔ outside the chain (2018.610199ms)
|
||||
✔ outside the chain with --migrate (2286.782735ms)
|
||||
✔ T52 row 186: the activate plan's backup line says what the run will do (13003.221353ms)
|
||||
✔ T178 proxy proof header and path survive re-pin and rollback unchanged in the pointer and unit (3428.609169ms)
|
||||
✔ T178 proxy proof pair survives a tester-port replacement as well (2005.665148ms)
|
||||
▶ T53 row 187: activate sets, carries and drops the proof pair
|
||||
✔ tests 1 and 9: the pair goes after the preview flags, before --send and the kept --tester-port, as the unit renders it; a new pair replaces it (5369.617405ms)
|
||||
✔ tests 2 and 3: an activate of the live copy writes the pair; a later activate and a rollback carry it (4877.926077ms)
|
||||
✔ test 2: only a pair change may name the live copy; the log keeps from and to, and rollback still goes to the earlier copy (6411.791056ms)
|
||||
✔ test 2: a live-copy activate says only the Console flags change, and backs up the stopped store before it installs (3823.440479ms)
|
||||
✔ test 3: pm-on keeps the pair (2929.528358ms)
|
||||
✔ test 4: --no-proof drops the pair from the pointer and the unit and says so; with no pair it says so and passes (6134.571168ms)
|
||||
✔ test 5: each refusal exits 3 before anything stops (4080.818538ms)
|
||||
✔ tests 5 and 9: --plan lists every proof refusal with the others and writes nothing (921.495619ms)
|
||||
✔ test 6: usage errors (791.940368ms)
|
||||
✔ test 7: a rollback to a copy without proof support drops the pair and says so (3569.742095ms)
|
||||
✔ test 7: an activate to a copy without proof support refuses proof-target without --no-proof and passes with it (4102.029003ms)
|
||||
✔ T53 row 187: activate sets, carries and drops the proof pair (43015.196531ms)
|
||||
▶ T54 row 188: a carried pair gets the proof file checks, and a proof file inside the repository refuses
|
||||
✔ test 1: an activate that carries the pair refuses after chmod 644, in the plan and the run, before anything stops (2443.927487ms)
|
||||
✔ test 1: an activate that carries the pair refuses after a symlink to a mode-600 file, in the plan and the run, before anything stops (2451.543098ms)
|
||||
✔ test 1: an activate that carries the pair refuses after removal, in the plan and the run, before anything stops (2371.886229ms)
|
||||
✔ test 2: a rollback that carries the pair refuses after chmod 644, in the plan and the run, before anything stops (2440.808004ms)
|
||||
✔ test 3: a proof file inside the repository refuses, in the plan and the run, before anything stops (1028.022624ms)
|
||||
✔ test 4: a path outside the repository through a directory symlink into it refuses on its realpath (1092.396277ms)
|
||||
✔ T54 row 188: a carried pair gets the proof file checks, and a proof file inside the repository refuses (11829.775747ms)
|
||||
▶ T55 row 189: activate --no-send drops --send, and rollback and pm-on carry it off
|
||||
✔ test 1: a live-copy --no-send drops --send from the pointer and the unit, keeps the rest in order, logs the step and backs up the stopped store (2297.315751ms)
|
||||
✔ test 2: a plain live-copy activate still refuses already-active, and so does --no-send once --send is gone (3372.219555ms)
|
||||
✔ test 3: --plan prints one send: line in each case, with the live-copy note on a same-copy run (4822.032599ms)
|
||||
✔ test 4: after --no-send, a rollback to the earlier copy leaves --send out of the pointer and the unit (3681.502406ms)
|
||||
✔ test 4: pm-on after --no-send keeps --send off (3384.224907ms)
|
||||
✔ test 5: --no-send on rollback, pm-on, status, adopt or rehearse is a usage error (646.332677ms)
|
||||
✔ test 6: with both a pair and --send in the pointer, --no-send and --no-proof each drop what they name and keep the rest (10576.556687ms)
|
||||
✔ T55 row 189: activate --no-send drops --send, and rollback and pm-on carry it off (28781.800109ms)
|
||||
▶ T57 row 200: activate --sso, its refusals before any stop, and the rollback to a Console without --sso
|
||||
✔ item 1: --sso drops the preview set and the pair, puts --sso before --send and the tester port, and the plan names what it drops and carries (3731.038851ms)
|
||||
✔ item 1: --sso may re-pin the live copy once; later activates carry it; --no-send still drops --send (9441.965146ms)
|
||||
✔ item 1: --sso with a pair or --no-proof, or on any verb but activate, is a usage error (804.681755ms)
|
||||
✔ item 2: a target without --sso, a missing or bad console.sso, and each slot problem refuse before any stop (6340.571003ms)
|
||||
✔ item 3: a config whose console key the target loader refuses stops an activate or a rollback before any stop, naming the first step (4474.330517ms)
|
||||
✔ item 3: a rollback from --sso to a Console without it takes the flags from the set of the activation onto the copy, past a same-copy re-pin (sage-1389) (11258.382547ms)
|
||||
✔ item 3: a rollback set that is missing, fails its sums, holds no argv or already ran --sso refuses sso-rollback-flags (4811.481384ms)
|
||||
✔ round 2 (webby-0028 N1): run through a symlinked repository path, a slot or a proof file inside the repository still refuses (2548.588058ms)
|
||||
✔ round 2 (webby-0028 N2): a config.json that does not parse stops the run before anything is read or stopped (2148.082108ms)
|
||||
✔ round 3 (sage-1556): a named instance turns --sso on with its own config, slot and Console unit, and rolls back from its own set (4427.346674ms)
|
||||
✔ row 238 (#1744): on a named instance the sso-config first step names --instance NAME in both commands (1072.216503ms)
|
||||
✔ T57 row 200: activate --sso, its refusals before any stop, and the rollback to a Console without --sso (51060.894572ms)
|
||||
✔ R1 rehearse passes on the same schema; the scratch root holds its files and the live files stay byte-identical (3501.665564ms)
|
||||
✔ R2 rehearse runs the migration checks when the schema differs; the live store stays at 3g (2615.765886ms)
|
||||
✔ R3 a failing migration gives REHEARSAL_FAIL migrate and starts nothing (406.432761ms)
|
||||
✔ R4 a host that does not start, does not answer status, reports another pid, launches anyway, makes a launches directory or keeps its lock each fails by name (23643.921414ms)
|
||||
✔ R5 a host that ignores SIGTERM gets SIGKILL and FAIL host-stopped (4522.753011ms)
|
||||
✔ R6 a Console that does not answer /healthz gives REHEARSAL_FAIL healthz (5695.642056ms)
|
||||
✔ R7 a host on another copy fails copy-match (5707.109175ms)
|
||||
✔ R8 a scratch port in use or reserved refuses, and the rehearsal takes no other port (564.078959ms)
|
||||
✔ R9 mos-0963: a role reference left outside placeholders/, or left on an env variable, fails credential-ref-live before the host starts (739.463019ms)
|
||||
✔ R10 mos-0962: a scratch business that still sets a tracker fails tracker-configured (356.527698ms)
|
||||
✔ R11 mos-0961: a scratch config on the live data root or on any root but the scratch one, or a sessions.json naming a running pid, refuses by name (1415.617777ms)
|
||||
✔ R12 mos-0962: a notifier config with a binding fails notify-off (346.615997ms)
|
||||
✔ R13 the pre-checks: an old copy, a backup that fails its sums, a missing backup or pointer, and usage (495.179039ms)
|
||||
✔ R14 a host that writes the live config, the live business file or the backup fails the end check by name (10325.286968ms)
|
||||
✔ R15 a rehearsal stopped by TERM, INT or HUP fails signal and still stops the host and Console and runs the end checks (9991.220342ms)
|
||||
✔ row 233: --backup last takes the newest backup the log records; a later line with backup null does not hide it, and the store line names it (3454.052038ms)
|
||||
✔ row 233: --backup last with no backup in the log, or no log, exits 3 with no-backup and makes no rehearsal directory (203.934243ms)
|
||||
✔ row 233: --backup last refuses a newest backup that is not an activation id, with exit 1 (127.433768ms)
|
||||
▶ T56 row 190: named instances side by side on one unit directory, $BIN and set of stand-ins
|
||||
✔ T-I3 each instance renders its own config, session env and Description, and nothing of another (1595.173571ms)
|
||||
✔ T-I4 a Console port another installed Console takes refuses port-claimed, and a named instance keeps off the default ports (1992.011586ms)
|
||||
✔ T-I6 alpha's activate and rollback reach nothing of beta's (3927.69359ms)
|
||||
✔ T-I6 swapped: beta's reach nothing of alpha's (4046.222781ms)
|
||||
✔ T-I7 MOSAIC_CONFIG naming alpha's config with no flag refuses instance-root-mismatch and changes nothing (707.673985ms)
|
||||
✔ T-I9 another instance's bus active refuses nothing; one of this instance's does (6093.674502ms)
|
||||
✔ T56 row 190: named instances side by side on one unit directory, $BIN and set of stand-ins (18364.096442ms)
|
||||
ℹ tests 196
|
||||
ℹ suites 0
|
||||
ℹ pass 196
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 530980.947325
|
||||
@@ -0,0 +1 @@
|
||||
{"processes": [], "removed": "/mnt/storage/scratch/gt-t2e8hpyu", "trees": ["/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row215-on212", "/home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197-r8"]}
|
||||
@@ -0,0 +1 @@
|
||||
{"pid": 765123, "reason": "sage-1983 stop after file10; do not start file11"}
|
||||
@@ -0,0 +1,122 @@
|
||||
[
|
||||
{
|
||||
"file": "packages/bus/tests/library.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 6,
|
||||
"pass": 6,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "01-packages_bus_tests_library.test.mjs.log"
|
||||
},
|
||||
{
|
||||
"file": "packages/bus/tests/project-runtime.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 3,
|
||||
"pass": 3,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "02-packages_bus_tests_project-runtime.test.mjs.log"
|
||||
},
|
||||
{
|
||||
"file": "packages/business/tests/business.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 18,
|
||||
"pass": 18,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "03-packages_business_tests_business.test.mjs.log"
|
||||
},
|
||||
{
|
||||
"file": "packages/business/tests/cli.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 10,
|
||||
"pass": 10,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "04-packages_business_tests_cli.test.mjs.log"
|
||||
},
|
||||
{
|
||||
"file": "packages/business/tests/instance-settings.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 12,
|
||||
"pass": 12,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "05-packages_business_tests_instance-settings.test.mjs.log"
|
||||
},
|
||||
{
|
||||
"file": "packages/business/tests/library-projects-protected.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 4,
|
||||
"pass": 4,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "06-packages_business_tests_library-projects-protected.test.mjs.log"
|
||||
},
|
||||
{
|
||||
"file": "packages/business/tests/resolve.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 11,
|
||||
"pass": 11,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "07-packages_business_tests_resolve.test.mjs.log"
|
||||
},
|
||||
{
|
||||
"file": "packages/cli/tests/launcher.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 30,
|
||||
"pass": 30,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "08-packages_cli_tests_launcher.test.mjs.log"
|
||||
},
|
||||
{
|
||||
"file": "packages/cli/tests/stack-release-external.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 25,
|
||||
"pass": 25,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "09-packages_cli_tests_stack-release-external.test.mjs.log"
|
||||
},
|
||||
{
|
||||
"file": "packages/cli/tests/stack-release.test.mjs",
|
||||
"rc": 0,
|
||||
"counts": {
|
||||
"tests": 196,
|
||||
"pass": 196,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"log": "10-packages_cli_tests_stack-release.test.mjs.log"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
/mnt/storage/scratch/gt-t2e8hpyu
|
||||
@@ -0,0 +1 @@
|
||||
2026-10-21T11:56:56.177608+00:00
|
||||
@@ -0,0 +1,10 @@
|
||||
✔ C2-04: library mappings load without roots, remain frozen, and retain mapping refusals (9.004507ms)
|
||||
✔ C2-04: an otherwise valid publish grant cannot name a library repo (1.807264ms)
|
||||
ℹ tests 2
|
||||
ℹ suites 0
|
||||
ℹ pass 2
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 67.488189
|
||||
@@ -0,0 +1,23 @@
|
||||
✖ C2-04: library mappings load without roots, remain frozen, and retain mapping refusals (5.192384ms)
|
||||
ℹ tests 1
|
||||
ℹ suites 0
|
||||
ℹ pass 0
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 54.487487
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/business/tests/business.test.mjs:11:1
|
||||
✖ C2-04: library mappings load without roots, remain frozen, and retain mapping refusals (5.192384ms)
|
||||
Error [BusinessError]: unsupported /mnt/storage/scratch/gt-PvGtsQ/mosaic-business-4vAhxB/businesses/acme.json projects.books key: "kind"
|
||||
at refuse (file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197/packages/business/src/errors.mjs:12:9)
|
||||
at rejectUnknownKeys (file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197/packages/business/src/util.mjs:17:33)
|
||||
at validateBusinessDocument (file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197/packages/business/src/business.mjs:232:5)
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197/packages/business/tests/business.test.mjs:17:18)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3) {
|
||||
exitCode: 2
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
✔ C2-04: ensureCheckouts skips a library before a real clone and leaves no books path (24.411494ms)
|
||||
ℹ tests 1
|
||||
ℹ suites 0
|
||||
ℹ pass 1
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 72.211367
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"at": "2026-10-21T08:51:07Z",
|
||||
"tempRoot": "/mnt/storage/scratch/gt-PvGtsQ",
|
||||
"fixtureCwdOrArgv": [],
|
||||
"testProcesses": [],
|
||||
"excluded": "current scan process and its ancestors",
|
||||
"tempRootRemoved": true
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
✔ C2-04: business validate and resolve skip a library before code projects and credential checks (206.597157ms)
|
||||
ℹ tests 1
|
||||
ℹ suites 0
|
||||
ℹ pass 1
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 260.97412
|
||||
@@ -0,0 +1,9 @@
|
||||
✔ C2-04: instance settings skip a library while checking a later code project (22.656666ms)
|
||||
ℹ tests 1
|
||||
ℹ suites 0
|
||||
ℹ pass 1
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 79.494698
|
||||
@@ -0,0 +1,9 @@
|
||||
✔ C2-04: launcher workspace clones code but never the library (1241.43402ms)
|
||||
ℹ tests 1
|
||||
ℹ suites 0
|
||||
ℹ pass 1
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 1338.915726
|
||||
@@ -0,0 +1,12 @@
|
||||
✔ C2-04 M9: changed playground and hybrid entries leave business and changes.jsonl byte-identical (21.916712ms)
|
||||
✔ C2-04 M9: code projects, additions, deletions and array changes are protected too (17.081275ms)
|
||||
✔ C2-04 M9: canonical key order is allowed and a non-project setter still records its change (14.304068ms)
|
||||
✔ C2-04 M9: a serialization hook cannot change projects after the canonical comparison (9.595281ms)
|
||||
ℹ tests 4
|
||||
ℹ suites 0
|
||||
ℹ pass 4
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 116.250811
|
||||
@@ -0,0 +1,28 @@
|
||||
✖ C2-04 M9: changed playground and hybrid entries leave business and changes.jsonl byte-identical (21.728048ms)
|
||||
ℹ tests 1
|
||||
ℹ suites 0
|
||||
ℹ pass 0
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 71.097427
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/business/tests/library-projects-protected.test.mjs:35:1
|
||||
✖ C2-04 M9: changed playground and hybrid entries leave business and changes.jsonl byte-identical (21.728048ms)
|
||||
AssertionError [ERR_ASSERTION]: Missing expected exception.
|
||||
at protectedWrite (file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197/packages/business/tests/library-projects-protected.test.mjs:29:10)
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197/packages/business/tests/library-projects-protected.test.mjs:37:3)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.start (node:internal/test_runner/test:1262:17)
|
||||
at startSubtestAfterBootstrap (node:internal/test_runner/harness:387:17) {
|
||||
generatedMessage: false,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: undefined,
|
||||
expected: { code: 'organization-projects-protected' },
|
||||
operator: 'throws',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
✔ C2-04: record APIs refuse a library before creating a repository (3.426617ms)
|
||||
ℹ tests 1
|
||||
ℹ suites 0
|
||||
ℹ pass 1
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 61.266328
|
||||
@@ -0,0 +1,9 @@
|
||||
✔ C2-04: a library first in projects does not hide a later project layer (6.517821ms)
|
||||
ℹ tests 1
|
||||
ℹ suites 0
|
||||
ℹ pass 1
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 62.270511
|
||||
@@ -0,0 +1,90 @@
|
||||
[
|
||||
{
|
||||
"file": "business-green.log",
|
||||
"tests": 2,
|
||||
"pass": 2,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
{
|
||||
"file": "business-red.log",
|
||||
"tests": 1,
|
||||
"pass": 0,
|
||||
"fail": 1,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
{
|
||||
"file": "checkout-green.log",
|
||||
"tests": 1,
|
||||
"pass": 1,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
{
|
||||
"file": "cli-green.log",
|
||||
"tests": 1,
|
||||
"pass": 1,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
{
|
||||
"file": "instance-settings-green.log",
|
||||
"tests": 1,
|
||||
"pass": 1,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
{
|
||||
"file": "launcher-green.log",
|
||||
"tests": 1,
|
||||
"pass": 1,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
{
|
||||
"file": "m9-green.log",
|
||||
"tests": 4,
|
||||
"pass": 4,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
{
|
||||
"file": "m9-red.log",
|
||||
"tests": 1,
|
||||
"pass": 0,
|
||||
"fail": 1,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
{
|
||||
"file": "project-green.log",
|
||||
"tests": 1,
|
||||
"pass": 1,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
{
|
||||
"file": "resolve-green.log",
|
||||
"tests": 1,
|
||||
"pass": 1,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
{
|
||||
"file": "trackers-boot-green.log",
|
||||
"tests": 2,
|
||||
"pass": 2,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
2026-10-21T08:48:14Z
|
||||
@@ -0,0 +1 @@
|
||||
/mnt/storage/scratch/gt-PvGtsQ
|
||||
@@ -0,0 +1,12 @@
|
||||
✔ C2-04: a library-only business with tracker.baseUrl boots without a project tracker (132.133246ms)
|
||||
task.close {} answered: invalid-request; fake saw 18 requests, first GET /info 200, GET /projects/1 200, GET /projects/1/views 200
|
||||
task.close on a missing task answered: task-not-found; it made GET /tasks/999 404
|
||||
✔ bootConfig trackers reach the S3 adapter in the real broker child, which goes ready against a fake Vikunja (261.808635ms)
|
||||
ℹ tests 2
|
||||
ℹ suites 0
|
||||
ℹ pass 2
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 480.083569
|
||||
@@ -0,0 +1 @@
|
||||
{"processes": [], "removed": "/mnt/storage/scratch/gt-iwfcrf5s"}
|
||||
@@ -0,0 +1 @@
|
||||
["packages/library/tests/mirror.test.mjs", "packages/bus/tests/library.test.mjs", "packages/webui/tests/library-cli.test.mjs", "packages/bus/tests/project-runtime.test.mjs"]
|
||||
@@ -0,0 +1,31 @@
|
||||
✖ C2-04 CLI: both listener callback pairs dispatch library verbs with their own transport (140.263767ms)
|
||||
ℹ tests 1
|
||||
ℹ suites 0
|
||||
ℹ pass 0
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 244.49705
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/webui/tests/library-cli.test.mjs:10:1
|
||||
✖ C2-04 CLI: both listener callback pairs dispatch library verbs with their own transport (140.263767ms)
|
||||
AssertionError [ERR_ASSERTION]: refused: missing library callbacks
|
||||
|
||||
|
||||
2 !== 0
|
||||
|
||||
at TestContext.<anonymous> (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/webui/tests/library-cli.test.mjs:27:10)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.start (node:internal/test_runner/test:1262:17)
|
||||
at startSubtestAfterBootstrap (node:internal/test_runner/harness:387:17) {
|
||||
generatedMessage: false,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: 2,
|
||||
expected: 0,
|
||||
operator: 'strictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
✖ C2-04 CLI: both listener callback pairs dispatch library verbs with their own transport (31.496523ms)
|
||||
ℹ tests 1
|
||||
ℹ suites 0
|
||||
ℹ pass 0
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 122.065824
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/webui/tests/library-cli.test.mjs:10:1
|
||||
✖ C2-04 CLI: both listener callback pairs dispatch library verbs with their own transport (31.496523ms)
|
||||
AssertionError [ERR_ASSERTION]: file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/webui/src/bus.mjs:1
|
||||
import {appendFileSync} from 'node:fs';export class BusReadError extends Error{};export const busCaller=o=>async(verb,args)=>{appendFileSync("/mnt/storage/scratch/gt-iwfcrf5s/library-cli-1eUPUX/calls.jsonl",JSON.stringify({verb,args,cli:o.cli??"/mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/human-cli.mjs"})+'
|
||||
^
|
||||
|
||||
SyntaxError: Invalid or unexpected token
|
||||
at compileSourceTextModule (node:internal/modules/esm/utils:355:16)
|
||||
at ModuleLoader.moduleStrategy (node:internal/modules/esm/translators:93:18)
|
||||
at #translate (node:internal/modules/esm/loader:441:20)
|
||||
at afterLoad (node:internal/modules/esm/loader:509:29)
|
||||
at ModuleLoader.loadAndTranslate (node:internal/modules/esm/loader:514:12)
|
||||
at #getOrCreateModuleJobAfterResolve (node:internal/modules/esm/loader:567:36)
|
||||
at afterResolve (node:internal/modules/esm/loader:614:52)
|
||||
at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:620:12)
|
||||
at ModuleJob.syncLink (node:internal/modules/esm/module_job:277:33)
|
||||
at ModuleJob.link (node:internal/modules/esm/module_job:389:17)
|
||||
|
||||
Node.js v26.8.1
|
||||
|
||||
|
||||
1 !== 0
|
||||
|
||||
at TestContext.<anonymous> (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/webui/tests/library-cli.test.mjs:27:10)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.start (node:internal/test_runner/test:1262:17)
|
||||
at startSubtestAfterBootstrap (node:internal/test_runner/harness:387:17) {
|
||||
generatedMessage: false,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: 1,
|
||||
expected: 0,
|
||||
operator: 'strictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
✔ C2-04 CLI: both listener callback pairs dispatch library verbs with their own transport (110.620217ms)
|
||||
ℹ tests 1
|
||||
ℹ suites 0
|
||||
ℹ pass 1
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 194.067409
|
||||
@@ -0,0 +1,9 @@
|
||||
✔ C2-04 CLI: both listener callback pairs dispatch library verbs with their own transport (107.138425ms)
|
||||
ℹ tests 1
|
||||
ℹ suites 0
|
||||
ℹ pass 1
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 193.527058
|
||||
@@ -0,0 +1,71 @@
|
||||
✖ C2-04 M4: both verbs reject every agent before arguments or adapter access (14.387463ms)
|
||||
✖ C2-04 bus: human reads validate keys and return adapter results without path leakage (8.808227ms)
|
||||
✖ C2-04 socket: each async library verb resolves its result rather than serializing {} (15.107055ms)
|
||||
ℹ tests 3
|
||||
ℹ suites 0
|
||||
ℹ pass 0
|
||||
ℹ fail 3
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 125.805576
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/bus/tests/library.test.mjs:28:1
|
||||
✖ C2-04 M4: both verbs reject every agent before arguments or adapter access (14.387463ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
|
||||
Comparison {
|
||||
+ code: 'unknown-verb'
|
||||
- code: 'human-required'
|
||||
}
|
||||
|
||||
at async TestContext.<anonymous> (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/tests/library.test.mjs:32: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: Error: unknown-verb
|
||||
at fail (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/broker.mjs:145:9)
|
||||
at #dispatch (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/broker.mjs:3098:9)
|
||||
at file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/broker.mjs:1810:38
|
||||
at Store.transaction (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/store.mjs:263:22)
|
||||
at Broker.request (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/broker.mjs:1801:26)
|
||||
at file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/tests/library.test.mjs:24:78
|
||||
at async waitForActual (node:assert:615:5)
|
||||
at async strict.rejects (node:assert:738:25)
|
||||
at async TestContext.<anonymous> (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/tests/library.test.mjs:32:5)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7),
|
||||
expected: { code: 'human-required' },
|
||||
operator: 'rejects',
|
||||
diff: 'simple'
|
||||
}
|
||||
|
||||
test at packages/bus/tests/library.test.mjs:45:1
|
||||
✖ C2-04 bus: human reads validate keys and return adapter results without path leakage (8.808227ms)
|
||||
Error: unknown-verb
|
||||
at fail (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/broker.mjs:145:9)
|
||||
at #dispatch (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/broker.mjs:3098:9)
|
||||
at file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/broker.mjs:1810:38
|
||||
at Store.transaction (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/store.mjs:263:22)
|
||||
at Broker.request (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/broker.mjs:1801:26)
|
||||
at file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/tests/library.test.mjs:24:78
|
||||
at async TestContext.<anonymous> (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/tests/library.test.mjs:49:17)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
code: 'unknown-verb'
|
||||
}
|
||||
|
||||
test at packages/bus/tests/library.test.mjs:56:1
|
||||
✖ C2-04 socket: each async library verb resolves its result rather than serializing {} (15.107055ms)
|
||||
Error: unknown-verb
|
||||
at Socket.<anonymous> (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/client.mjs:42:17)
|
||||
at Socket.emit (node:events:514:20)
|
||||
at addChunk (node:internal/streams/readable:575:12)
|
||||
at readableAddChunkPushByteMode (node:internal/streams/readable:526:3)
|
||||
at Readable.push (node:internal/streams/readable:406:5)
|
||||
at Pipe.onStreamRead (node:internal/stream_base_commons:189:23) {
|
||||
code: 'unknown-verb'
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
✖ C2-04 M4: both verbs reject every agent before arguments or adapter access (16.66162ms)
|
||||
✖ C2-04 bus: human reads validate keys and return adapter results without path leakage (9.880605ms)
|
||||
✖ C2-04 socket: each async library verb resolves its result rather than serializing {} (17.417761ms)
|
||||
✖ C2-04 runtime: protectedRoots skips library but retains real code-root credential protection (27.11473ms)
|
||||
✖ C2-04 runtime: unsafe existing mirror refuses boot and never publishes a socket (21.990752ms)
|
||||
✖ C2-04 runtime: real library adapters reach the socket and lock waits leave other bus reads responsive (21.295513ms)
|
||||
|
||||
Interrupted while running:
|
||||
|
||||
⚠ packages/bus/tests/library.test.mjs (packages/bus/tests/library.test.mjs:1:1)
|
||||
✖ packages/bus/tests/library.test.mjs (34335.85978ms)
|
||||
ℹ tests 7
|
||||
ℹ suites 0
|
||||
ℹ pass 0
|
||||
ℹ fail 6
|
||||
ℹ cancelled 1
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 34341.308382
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/bus/tests/library.test.mjs:28:1
|
||||
✖ C2-04 M4: both verbs reject every agent before arguments or adapter access (16.66162ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
|
||||
Comparison {
|
||||
+ code: 'unknown-verb'
|
||||
- code: 'human-required'
|
||||
}
|
||||
|
||||
at async TestContext.<anonymous> (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/tests/library.test.mjs:32: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: Error: unknown-verb
|
||||
at fail (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/broker.mjs:145:9)
|
||||
at #dispatch (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/broker.mjs:3098:9)
|
||||
at file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/broker.mjs:1810:38
|
||||
at Store.transaction (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/store.mjs:263:22)
|
||||
at Broker.request (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/broker.mjs:1801:26)
|
||||
at file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/tests/library.test.mjs:24:78
|
||||
at async waitForActual (node:assert:615:5)
|
||||
at async strict.rejects (node:assert:738:25)
|
||||
at async TestContext.<anonymous> (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/tests/library.test.mjs:32:5)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7),
|
||||
expected: { code: 'human-required' },
|
||||
operator: 'rejects',
|
||||
diff: 'simple'
|
||||
}
|
||||
|
||||
test at packages/bus/tests/library.test.mjs:45:1
|
||||
✖ C2-04 bus: human reads validate keys and return adapter results without path leakage (9.880605ms)
|
||||
Error: unknown-verb
|
||||
at fail (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/broker.mjs:145:9)
|
||||
at #dispatch (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/broker.mjs:3098:9)
|
||||
at file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/broker.mjs:1810:38
|
||||
at Store.transaction (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/store.mjs:263:22)
|
||||
at Broker.request (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/broker.mjs:1801:26)
|
||||
at file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/tests/library.test.mjs:24:78
|
||||
at async TestContext.<anonymous> (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/tests/library.test.mjs:49:17)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
code: 'unknown-verb'
|
||||
}
|
||||
|
||||
test at packages/bus/tests/library.test.mjs:56:1
|
||||
✖ C2-04 socket: each async library verb resolves its result rather than serializing {} (17.417761ms)
|
||||
Error: unknown-verb
|
||||
at Socket.<anonymous> (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/client.mjs:42:17)
|
||||
at Socket.emit (node:events:514:20)
|
||||
at addChunk (node:internal/streams/readable:575:12)
|
||||
at readableAddChunkPushByteMode (node:internal/streams/readable:526:3)
|
||||
at Readable.push (node:internal/streams/readable:406:5)
|
||||
at Pipe.onStreamRead (node:internal/stream_base_commons:189:23) {
|
||||
code: 'unknown-verb'
|
||||
}
|
||||
|
||||
test at packages/bus/tests/library.test.mjs:67:1
|
||||
✖ C2-04 runtime: protectedRoots skips library but retains real code-root credential protection (27.11473ms)
|
||||
TypeError: library.mirrorPath is not a function
|
||||
at TestContext.<anonymous> (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/tests/library.test.mjs:74:26)
|
||||
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)
|
||||
|
||||
test at packages/bus/tests/library.test.mjs:81:1
|
||||
✖ C2-04 runtime: unsafe existing mirror refuses boot and never publishes a socket (21.990752ms)
|
||||
AssertionError [ERR_ASSERTION]: Missing expected rejection.
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async TestContext.<anonymous> (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/tests/library.test.mjs:87:3)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: false,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: undefined,
|
||||
expected: { code: 'library-git' },
|
||||
operator: 'rejects',
|
||||
diff: 'simple'
|
||||
}
|
||||
|
||||
test at packages/bus/tests/library.test.mjs:92:1
|
||||
✖ C2-04 runtime: real library adapters reach the socket and lock waits leave other bus reads responsive (21.295513ms)
|
||||
Error: unknown-verb
|
||||
at Socket.<anonymous> (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/client.mjs:42:17)
|
||||
at Socket.emit (node:events:514:20)
|
||||
at addChunk (node:internal/streams/readable:575:12)
|
||||
at readableAddChunkPushByteMode (node:internal/streams/readable:526:3)
|
||||
at Readable.push (node:internal/streams/readable:406:5)
|
||||
at Pipe.onStreamRead (node:internal/stream_base_commons:189:23) {
|
||||
code: 'unknown-verb'
|
||||
}
|
||||
|
||||
test at packages/bus/tests/library.test.mjs:1:1
|
||||
✖ packages/bus/tests/library.test.mjs (34335.85978ms)
|
||||
'Promise resolution is still pending but the event loop has already resolved'
|
||||
@@ -0,0 +1,126 @@
|
||||
✖ C2-04 M4: both verbs reject every agent before arguments or adapter access (24.976387ms)
|
||||
✖ C2-04 bus: human reads validate keys and return adapter results without path leakage (7.097425ms)
|
||||
✖ C2-04 socket: each async library verb resolves its result rather than serializing {} (6.894431ms)
|
||||
✖ C2-04 runtime: protectedRoots skips library but retains real code-root credential protection (34.318499ms)
|
||||
✖ C2-04 runtime: unsafe existing mirror refuses boot and never publishes a socket (21.188728ms)
|
||||
✖ C2-04 runtime: real library adapters reach the socket and lock waits leave other bus reads responsive (11.406264ms)
|
||||
ℹ tests 6
|
||||
ℹ suites 0
|
||||
ℹ pass 0
|
||||
ℹ fail 6
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 197.495962
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/bus/tests/library.test.mjs:28:1
|
||||
✖ C2-04 M4: both verbs reject every agent before arguments or adapter access (24.976387ms)
|
||||
Error: invalid-business
|
||||
at fail (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/broker.mjs:145:9)
|
||||
at new Broker (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/broker.mjs:322:9)
|
||||
at world (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/tests/library.test.mjs:20:18)
|
||||
at TestContext.<anonymous> (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/tests/library.test.mjs:30:13)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.start (node:internal/test_runner/test:1262:17)
|
||||
at startSubtestAfterBootstrap (node:internal/test_runner/harness:387:17) {
|
||||
code: 'invalid-business'
|
||||
}
|
||||
|
||||
test at packages/bus/tests/library.test.mjs:45:1
|
||||
✖ C2-04 bus: human reads validate keys and return adapter results without path leakage (7.097425ms)
|
||||
Error: invalid-business
|
||||
at fail (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/broker.mjs:145:9)
|
||||
at new Broker (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/broker.mjs:322:9)
|
||||
at world (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/tests/library.test.mjs:20:18)
|
||||
at TestContext.<anonymous> (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/tests/library.test.mjs:47:13)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3) {
|
||||
code: 'invalid-business'
|
||||
}
|
||||
|
||||
test at packages/bus/tests/library.test.mjs:56:1
|
||||
✖ C2-04 socket: each async library verb resolves its result rather than serializing {} (6.894431ms)
|
||||
Error: invalid-business
|
||||
at fail (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/broker.mjs:145:9)
|
||||
at new Broker (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/broker.mjs:322:9)
|
||||
at world (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/tests/library.test.mjs:20:18)
|
||||
at TestContext.<anonymous> (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/tests/library.test.mjs:57:13)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
code: 'invalid-business'
|
||||
}
|
||||
|
||||
test at packages/bus/tests/library.test.mjs:67:1
|
||||
✖ C2-04 runtime: protectedRoots skips library but retains real code-root credential protection (34.318499ms)
|
||||
Error: credential-format
|
||||
at deny (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/credentials.mjs:10:9)
|
||||
at #format (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/credentials.mjs:232:28)
|
||||
at #read (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/credentials.mjs:222:37)
|
||||
at new Credentials (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/credentials.mjs:145:35)
|
||||
at startBroker (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/runtime.mjs:108:19)
|
||||
at TestContext.<anonymous> (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/tests/library.test.mjs:72:25)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19) {
|
||||
code: 'credential-format'
|
||||
}
|
||||
|
||||
test at packages/bus/tests/library.test.mjs:81:1
|
||||
✖ C2-04 runtime: unsafe existing mirror refuses boot and never publishes a socket (21.188728ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
|
||||
Comparison {
|
||||
+ code: 'invalid-business'
|
||||
- code: 'library-git'
|
||||
}
|
||||
|
||||
at async TestContext.<anonymous> (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/tests/library.test.mjs:86:3)
|
||||
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: Error: invalid-business
|
||||
at fail (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/broker.mjs:145:9)
|
||||
at new Broker (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/broker.mjs:322:9)
|
||||
at startBroker (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/runtime.mjs:126:20)
|
||||
at async waitForActual (node:assert:615:5)
|
||||
at async strict.rejects (node:assert:738:25)
|
||||
at async TestContext.<anonymous> (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/tests/library.test.mjs:86:3)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7),
|
||||
expected: { code: 'library-git' },
|
||||
operator: 'rejects',
|
||||
diff: 'simple'
|
||||
}
|
||||
|
||||
test at packages/bus/tests/library.test.mjs:91:1
|
||||
✖ C2-04 runtime: real library adapters reach the socket and lock waits leave other bus reads responsive (11.406264ms)
|
||||
Error: ENOENT: no such file or directory, lstat '/mnt/storage/scratch/gt-iwfcrf5s/library-m65UFF/data'
|
||||
at lstatSync (node:fs:2138:25)
|
||||
at new Store (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/store.mjs:137:22)
|
||||
at startBroker (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/src/runtime.mjs:99:13)
|
||||
at TestContext.<anonymous> (file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/bus/tests/library.test.mjs:94:25)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
errno: -2,
|
||||
code: 'ENOENT',
|
||||
syscall: 'lstat',
|
||||
path: '/mnt/storage/scratch/gt-iwfcrf5s/library-m65UFF/data'
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
✔ C2-04 M4: both verbs reject every agent before arguments or adapter access (28.309128ms)
|
||||
✔ C2-04 bus: human reads validate keys and return adapter results without path leakage (11.198339ms)
|
||||
✔ C2-04 socket: each async library verb resolves its result rather than serializing {} (14.717312ms)
|
||||
✔ C2-04 runtime: protectedRoots skips library but retains real code-root credential protection (42.066656ms)
|
||||
✔ C2-04 runtime: unsafe existing mirror refuses boot and never publishes a socket (23.773967ms)
|
||||
✔ C2-04 runtime: real library adapters reach the socket and lock waits leave other bus reads responsive (89.925539ms)
|
||||
ℹ tests 6
|
||||
ℹ suites 0
|
||||
ℹ pass 6
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 301.460553
|
||||
@@ -0,0 +1,63 @@
|
||||
✔ C2-04 M4: both verbs reject every agent before arguments or adapter access (27.706148ms)
|
||||
✔ C2-04 bus: human reads validate keys and return adapter results without path leakage (10.128912ms)
|
||||
✖ C2-04 socket: each async library verb resolves its result rather than serializing {} (14.255977ms)
|
||||
✖ C2-04 runtime: protectedRoots skips library but retains real code-root credential protection (20.969978ms)
|
||||
✔ C2-04 runtime: unsafe existing mirror refuses boot and never publishes a socket (19.148653ms)
|
||||
✖ C2-04 runtime: real library adapters reach the socket and lock waits leave other bus reads responsive (10.834076ms)
|
||||
ℹ tests 6
|
||||
ℹ suites 0
|
||||
ℹ pass 3
|
||||
ℹ fail 3
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 192.486443
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/bus/tests/library.test.mjs:56:1
|
||||
✖ C2-04 socket: each async library verb resolves its result rather than serializing {} (14.255977ms)
|
||||
Error: unauthenticated
|
||||
at Socket.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197/packages/bus/src/client.mjs:42:17)
|
||||
at Socket.emit (node:events:514:20)
|
||||
at addChunk (node:internal/streams/readable:575:12)
|
||||
at readableAddChunkPushByteMode (node:internal/streams/readable:526:3)
|
||||
at Readable.push (node:internal/streams/readable:406:5)
|
||||
at Pipe.onStreamRead (node:internal/stream_base_commons:189:23) {
|
||||
code: 'unauthenticated'
|
||||
}
|
||||
|
||||
test at packages/bus/tests/library.test.mjs:67:1
|
||||
✖ C2-04 runtime: protectedRoots skips library but retains real code-root credential protection (20.969978ms)
|
||||
Error: credential-format
|
||||
at deny (file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197/packages/bus/src/credentials.mjs:10:9)
|
||||
at #format (file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197/packages/bus/src/credentials.mjs:232:28)
|
||||
at #read (file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197/packages/bus/src/credentials.mjs:222:37)
|
||||
at new Credentials (file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197/packages/bus/src/credentials.mjs:145:35)
|
||||
at startBroker (file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197/packages/bus/src/runtime.mjs:109:19)
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197/packages/bus/tests/library.test.mjs:72:25)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19) {
|
||||
code: 'credential-format'
|
||||
}
|
||||
|
||||
test at packages/bus/tests/library.test.mjs:91:1
|
||||
✖ C2-04 runtime: real library adapters reach the socket and lock waits leave other bus reads responsive (10.834076ms)
|
||||
Error: ENOENT: no such file or directory, lstat '/mnt/storage/scratch/gt-iwfcrf5s/library-rRi0EP/data'
|
||||
at lstatSync (node:fs:2138:25)
|
||||
at new Store (file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197/packages/bus/src/store.mjs:137:22)
|
||||
at startBroker (file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197/packages/bus/src/runtime.mjs:100:13)
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197/packages/bus/tests/library.test.mjs:94:25)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5) {
|
||||
errno: -2,
|
||||
code: 'ENOENT',
|
||||
syscall: 'lstat',
|
||||
path: '/mnt/storage/scratch/gt-iwfcrf5s/library-rRi0EP/data'
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
✔ C2-04 M4: both verbs reject every agent before arguments or adapter access (29.476748ms)
|
||||
✔ C2-04 bus: human reads validate keys and return adapter results without path leakage (11.765761ms)
|
||||
✔ C2-04 socket: each async library verb resolves its result rather than serializing {} (15.523467ms)
|
||||
✔ C2-04 runtime: protectedRoots skips library but retains real code-root credential protection (41.028545ms)
|
||||
✔ C2-04 runtime: unsafe existing mirror refuses boot and never publishes a socket (20.174444ms)
|
||||
✔ C2-04 runtime: real library adapters reach the socket and lock waits leave other bus reads responsive (89.276012ms)
|
||||
ℹ tests 6
|
||||
ℹ suites 0
|
||||
ℹ pass 6
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 314.116154
|
||||
@@ -0,0 +1,35 @@
|
||||
node:internal/modules/esm/resolve:272
|
||||
throw new ERR_MODULE_NOT_FOUND(
|
||||
^
|
||||
|
||||
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/mnt/storage/scratch/gt-iwfcrf5s/base/packages/library/src/mirror.mjs' imported from /mnt/storage/scratch/gt-iwfcrf5s/base/packages/library/tests/mirror.test.mjs
|
||||
at finalizeResolution (node:internal/modules/esm/resolve:272:11)
|
||||
at moduleResolve (node:internal/modules/esm/resolve:879:10)
|
||||
at defaultResolve (node:internal/modules/esm/resolve:1006:11)
|
||||
at #cachedDefaultResolve (node:internal/modules/esm/loader:708:20)
|
||||
at #resolveAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:728:38)
|
||||
at ModuleLoader.resolveSync (node:internal/modules/esm/loader:766:56)
|
||||
at #resolve (node:internal/modules/esm/loader:690:17)
|
||||
at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:610:35)
|
||||
at ModuleJob.syncLink (node:internal/modules/esm/module_job:277:33)
|
||||
at ModuleJob.link (node:internal/modules/esm/module_job:389:17) {
|
||||
code: 'ERR_MODULE_NOT_FOUND',
|
||||
url: 'file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/library/src/mirror.mjs'
|
||||
}
|
||||
|
||||
Node.js v26.8.1
|
||||
✖ packages/library/tests/mirror.test.mjs (35.196517ms)
|
||||
ℹ tests 1
|
||||
ℹ suites 0
|
||||
ℹ pass 0
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 41.636181
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/library/tests/mirror.test.mjs:1:1
|
||||
✖ packages/library/tests/mirror.test.mjs (35.196517ms)
|
||||
'test failed'
|
||||
@@ -0,0 +1,35 @@
|
||||
node:internal/modules/esm/resolve:272
|
||||
throw new ERR_MODULE_NOT_FOUND(
|
||||
^
|
||||
|
||||
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/mnt/storage/scratch/gt-iwfcrf5s/base/packages/library/src/mirror.mjs' imported from /mnt/storage/scratch/gt-iwfcrf5s/base/packages/library/tests/mirror.test.mjs
|
||||
at finalizeResolution (node:internal/modules/esm/resolve:272:11)
|
||||
at moduleResolve (node:internal/modules/esm/resolve:879:10)
|
||||
at defaultResolve (node:internal/modules/esm/resolve:1006:11)
|
||||
at #cachedDefaultResolve (node:internal/modules/esm/loader:708:20)
|
||||
at #resolveAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:728:38)
|
||||
at ModuleLoader.resolveSync (node:internal/modules/esm/loader:766:56)
|
||||
at #resolve (node:internal/modules/esm/loader:690:17)
|
||||
at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:610:35)
|
||||
at ModuleJob.syncLink (node:internal/modules/esm/module_job:277:33)
|
||||
at ModuleJob.link (node:internal/modules/esm/module_job:389:17) {
|
||||
code: 'ERR_MODULE_NOT_FOUND',
|
||||
url: 'file:///mnt/storage/scratch/gt-iwfcrf5s/base/packages/library/src/mirror.mjs'
|
||||
}
|
||||
|
||||
Node.js v26.8.1
|
||||
✖ packages/library/tests/mirror.test.mjs (29.912154ms)
|
||||
ℹ tests 1
|
||||
ℹ suites 0
|
||||
ℹ pass 0
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 35.532092
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/library/tests/mirror.test.mjs:1:1
|
||||
✖ packages/library/tests/mirror.test.mjs (29.912154ms)
|
||||
'test failed'
|
||||
@@ -0,0 +1,24 @@
|
||||
✔ C2-04 mirror: exact default path, bare without checkout or remote, and idempotent initialization (38.226069ms)
|
||||
✔ C2-04 mirror: simultaneous creators publish one intact mirror and leave no staging paths (28.230282ms)
|
||||
✔ C2-04 mirror: skipped publication accepts both coreutils statuses without removing the winner (102.534821ms)
|
||||
✔ C2-04 mirror: preserve occupied directories and reject symlink ancestors and code overlaps (13.3233ms)
|
||||
✔ C2-04 mirror: existing metadata accepts only bare Git plus state and the precreated lock (21.415494ms)
|
||||
✔ C2-04 state: missing state is empty only while the served ref is absent (35.194627ms)
|
||||
✔ C2-04 state: valid problems and sync metadata return no content and change no state bytes (37.132264ms)
|
||||
✔ C2-04 state: strict keys, types, times, branch, commit and fixed R messages fail closed (99.673047ms)
|
||||
✔ C2-04 state: symlink, hardlink, non-private state and missing lock refuse without replacement (28.715976ms)
|
||||
✔ C2-04 file: served commit, not HEAD or a caller commit, owns the exact returned text (71.638861ms)
|
||||
✔ C2-04 file: R1, R2 and R7 exclusions and never-synced mirrors cannot return file bodies (78.457144ms)
|
||||
✔ C2-04 lock: a first-sync and fast-forward reader wait for a consistent pair across processes (228.356974ms)
|
||||
✔ C2-04 lock: same-process waits, timeout code, callback expiry and throw release (5027.769608ms)
|
||||
✔ C2-04 lock: owner death releases the kernel lock without replacing its file (52.875238ms)
|
||||
✔ C2-04 lock: a missing flock binary becomes a handled refusal (49.021765ms)
|
||||
✔ C2-04 lock: an unawaited scoped read drains before the lock is released (20.779739ms)
|
||||
ℹ tests 16
|
||||
ℹ suites 0
|
||||
ℹ pass 16
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 5980.465131
|
||||
@@ -0,0 +1,30 @@
|
||||
✔ C2-04 mirror: exact default path, bare without checkout or remote, and idempotent initialization (42.294098ms)
|
||||
✔ C2-04 mirror: simultaneous creators publish one intact mirror and leave no staging paths (29.430204ms)
|
||||
✖ C2-04 mirror: skipped publication accepts both coreutils statuses without removing the winner (15050.820834ms)
|
||||
✔ C2-04 mirror: preserve occupied directories and reject symlink ancestors and code overlaps (13.507402ms)
|
||||
✔ C2-04 mirror: existing metadata accepts only bare Git plus state and the precreated lock (19.93202ms)
|
||||
✔ C2-04 state: missing state is empty only while the served ref is absent (33.088494ms)
|
||||
✔ C2-04 state: valid problems and sync metadata return no content and change no state bytes (34.798253ms)
|
||||
✔ C2-04 state: strict keys, types, times, branch, commit and fixed R messages fail closed (96.144919ms)
|
||||
✔ C2-04 state: symlink, hardlink, non-private state and missing lock refuse without replacement (28.529103ms)
|
||||
✔ C2-04 file: served commit, not HEAD or a caller commit, owns the exact returned text (71.331837ms)
|
||||
✔ C2-04 file: R1, R2 and R7 exclusions and never-synced mirrors cannot return file bodies (80.081788ms)
|
||||
✔ C2-04 lock: a first-sync and fast-forward reader wait for a consistent pair across processes (232.208946ms)
|
||||
✔ C2-04 lock: same-process waits, timeout code, callback expiry and throw release (5028.099129ms)
|
||||
✔ C2-04 lock: owner death releases the kernel lock without replacing its file (55.474555ms)
|
||||
✔ C2-04 lock: a missing flock binary becomes a handled refusal (51.152959ms)
|
||||
✔ C2-04 lock: an unawaited scoped read drains before the lock is released (21.006119ms)
|
||||
ℹ tests 16
|
||||
ℹ suites 0
|
||||
ℹ pass 15
|
||||
ℹ fail 0
|
||||
ℹ cancelled 1
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 20945.326932
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/library/tests/mirror.test.mjs:53:1
|
||||
✖ C2-04 mirror: skipped publication accepts both coreutils statuses without removing the winner (15050.820834ms)
|
||||
'test timed out after 15000ms'
|
||||
@@ -0,0 +1,23 @@
|
||||
✔ C2-04 mirror: exact default path, bare without checkout or remote, and idempotent initialization (37.162857ms)
|
||||
✔ C2-04 mirror: simultaneous creators publish one intact mirror and leave no staging paths (28.538429ms)
|
||||
✔ C2-04 mirror: preserve occupied directories and reject symlink ancestors and code overlaps (10.987669ms)
|
||||
✔ C2-04 mirror: existing metadata accepts only bare Git plus state and the precreated lock (20.080027ms)
|
||||
✔ C2-04 state: missing state is empty only while the served ref is absent (33.757482ms)
|
||||
✔ C2-04 state: valid problems and sync metadata return no content and change no state bytes (35.501927ms)
|
||||
✔ C2-04 state: strict keys, types, times, branch, commit and fixed R messages fail closed (96.276094ms)
|
||||
✔ C2-04 state: symlink, hardlink, non-private state and missing lock refuse without replacement (28.464199ms)
|
||||
✔ C2-04 file: served commit, not HEAD or a caller commit, owns the exact returned text (72.087911ms)
|
||||
✔ C2-04 file: R1, R2 and R7 exclusions and never-synced mirrors cannot return file bodies (78.120774ms)
|
||||
✔ C2-04 lock: a first-sync and fast-forward reader wait for a consistent pair across processes (230.905584ms)
|
||||
✔ C2-04 lock: same-process waits, timeout code, callback expiry and throw release (5029.743303ms)
|
||||
✔ C2-04 lock: owner death releases the kernel lock without replacing its file (51.842651ms)
|
||||
✔ C2-04 lock: a missing flock binary becomes a handled refusal (48.619585ms)
|
||||
✔ C2-04 lock: an unawaited scoped read drains before the lock is released (19.747384ms)
|
||||
ℹ tests 15
|
||||
ℹ suites 0
|
||||
ℹ pass 15
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 5872.380072
|
||||
@@ -0,0 +1,51 @@
|
||||
✔ C2-04 mirror: exact default path, bare without checkout or remote, and idempotent initialization (35.114121ms)
|
||||
✔ C2-04 mirror: simultaneous creators publish one intact mirror and leave no staging paths (28.344028ms)
|
||||
✖ C2-04 mirror: preserve occupied directories and reject symlink ancestors and code overlaps (11.29287ms)
|
||||
✔ C2-04 mirror: existing metadata accepts only bare Git plus state and the precreated lock (21.069667ms)
|
||||
✔ C2-04 state: missing state is empty only while the served ref is absent (33.576129ms)
|
||||
✔ C2-04 state: valid problems and sync metadata return no content and change no state bytes (36.355449ms)
|
||||
✔ C2-04 state: strict keys, types, times, branch, commit and fixed R messages fail closed (98.678405ms)
|
||||
✔ C2-04 state: symlink, hardlink, non-private state and missing lock refuse without replacement (28.476513ms)
|
||||
✔ C2-04 file: served commit, not HEAD or a caller commit, owns the exact returned text (72.613881ms)
|
||||
✔ C2-04 file: R1, R2 and R7 exclusions and never-synced mirrors cannot return file bodies (78.072657ms)
|
||||
✔ C2-04 lock: a first-sync and fast-forward reader wait for a consistent pair across processes (230.109966ms)
|
||||
✔ C2-04 lock: same-process waits, timeout code, callback expiry and throw release (5027.239374ms)
|
||||
✔ C2-04 lock: owner death releases the kernel lock without replacing its file (53.970224ms)
|
||||
✔ C2-04 lock: a missing flock binary becomes a handled refusal (45.088532ms)
|
||||
✔ C2-04 lock: an unawaited scoped read drains before the lock is released (19.793614ms)
|
||||
ℹ tests 15
|
||||
ℹ suites 0
|
||||
ℹ pass 14
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 5869.613351
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/library/tests/mirror.test.mjs:53:1
|
||||
✖ C2-04 mirror: preserve occupied directories and reject symlink ancestors and code overlaps (11.29287ms)
|
||||
AssertionError [ERR_ASSERTION]: The input did not match the regular expression /overlap/. Input:
|
||||
|
||||
'Error: project-path: unsafe mirror path'
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197/packages/library/tests/mirror.test.mjs:64: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: Error: project-path: unsafe mirror path
|
||||
at Module.mirrorPath (file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197/packages/library/src/mirror.mjs:40:25)
|
||||
at file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197/packages/library/tests/mirror.test.mjs:64:27
|
||||
at getActual (node:assert:580:5)
|
||||
at strict.throws (node:assert:728:24)
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197/packages/library/tests/mirror.test.mjs:64: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),
|
||||
expected: /overlap/,
|
||||
operator: 'throws',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
✖ C2-04 mirror: skipped publication accepts both coreutils statuses without removing the winner (56.393634ms)
|
||||
ℹ tests 1
|
||||
ℹ suites 0
|
||||
ℹ pass 0
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 102.30317
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/library/tests/mirror.test.mjs:53:1
|
||||
✖ C2-04 mirror: skipped publication accepts both coreutils statuses without removing the winner (56.393634ms)
|
||||
Error: {"code":1,"stderr":"file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197/packages/library/src/mirror.mjs:18\nconst fail = (code, message = code) => { throw new LibraryError(code, message); };\n ^\n\nLibraryError: library-git: expected a private owned bare mirror\n at fail (file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197/packages/library/src/mirror.mjs:18:48)\n at ownedRoot (file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197/packages/library/src/mirror.mjs:49:13)\n at inspectMirrorUnchecked (file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197/packages/library/src/mirror.mjs:57:3)\n at inspectMirror (file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197/packages/library/src/mirror.mjs:94:15)\n at ensureMirror (file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197/packages/library/src/mirror.mjs:128:11)\n at process.processTicksAndRejections (node:internal/process/task_queues:104:5)\n at async file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197/[eval1]:7:149 {\n code: 'library-git'\n}\n\nNode.js v26.8.1\n"}
|
||||
at file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197/packages/library/tests/mirror.test.mjs:65:108
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/herb-row197/packages/library/tests/mirror.test.mjs:65:22)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3)
|
||||
@@ -0,0 +1,11 @@
|
||||
✔ Broker keeps the sandbox client import closure: only the listed imports, no lazy project import (1.794155ms)
|
||||
✔ without a trusted project adapter all three async paths refuse project-not-configured (39.865453ms)
|
||||
✔ real startBroker injects the project adapter for socket reads and bound-author record writes (65.643553ms)
|
||||
ℹ tests 3
|
||||
ℹ suites 0
|
||||
ℹ pass 3
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 197.45826
|
||||
@@ -0,0 +1,11 @@
|
||||
✔ Broker keeps the sandbox client import closure: only the listed imports, no lazy project import (1.418597ms)
|
||||
✔ without a trusted project adapter all three async paths refuse project-not-configured (34.510685ms)
|
||||
✔ real startBroker injects the project adapter for socket reads and bound-author record writes (59.944824ms)
|
||||
ℹ tests 3
|
||||
ℹ suites 0
|
||||
ℹ pass 3
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 183.05447
|
||||
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"mirror.test-final-r2.log": {
|
||||
"tests": 16,
|
||||
"pass": 16,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"library.test-final.log": {
|
||||
"tests": 6,
|
||||
"pass": 6,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"library-cli.test-final.log": {
|
||||
"tests": 1,
|
||||
"pass": 1,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"project-runtime.test-final.log": {
|
||||
"tests": 3,
|
||||
"pass": 3,
|
||||
"fail": 0,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"library.test-baseline-focused.log": {
|
||||
"tests": 3,
|
||||
"pass": 0,
|
||||
"fail": 3,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"library-cli.test-baseline-r2.log": {
|
||||
"tests": 1,
|
||||
"pass": 0,
|
||||
"fail": 1,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
"mirror.test-baseline-r2.log": {
|
||||
"tests": 1,
|
||||
"pass": 0,
|
||||
"fail": 1,
|
||||
"cancelled": 0,
|
||||
"skipped": 0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
/mnt/storage/scratch/gt-iwfcrf5s
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"base": "a2c72ac95",
|
||||
"landing": "fefd54e13",
|
||||
"overlaps": [
|
||||
"BUILD-LOG.md",
|
||||
"packages/cli/tests/stack-release.test.mjs"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
{
|
||||
"oldBase": "f8276c5eb3ecb0aad353ee65e3dd8f7faac5dd87",
|
||||
"oldSource": "e333af4dc7af3a9d3789c8c0db26a0df8bdddfee",
|
||||
"newBase": "a3652371338e60187d4e95cee4a0f30f3c8a8f06",
|
||||
"paths": [
|
||||
{
|
||||
"path": "BUILD-LOG.md",
|
||||
"upstreamChanged": false,
|
||||
"matchesPriorBlob": true,
|
||||
"changeLinesIdentical": true
|
||||
},
|
||||
{
|
||||
"path": "packages/bus/src/broker.mjs",
|
||||
"upstreamChanged": true,
|
||||
"matchesPriorBlob": false,
|
||||
"changeLinesIdentical": true
|
||||
},
|
||||
{
|
||||
"path": "packages/bus/src/runtime.mjs",
|
||||
"upstreamChanged": false,
|
||||
"matchesPriorBlob": true,
|
||||
"changeLinesIdentical": true
|
||||
},
|
||||
{
|
||||
"path": "packages/bus/src/server.mjs",
|
||||
"upstreamChanged": false,
|
||||
"matchesPriorBlob": true,
|
||||
"changeLinesIdentical": true
|
||||
},
|
||||
{
|
||||
"path": "packages/bus/tests/library.test.mjs",
|
||||
"upstreamChanged": false,
|
||||
"matchesPriorBlob": true,
|
||||
"changeLinesIdentical": true
|
||||
},
|
||||
{
|
||||
"path": "packages/business/src/business.mjs",
|
||||
"upstreamChanged": false,
|
||||
"matchesPriorBlob": true,
|
||||
"changeLinesIdentical": true
|
||||
},
|
||||
{
|
||||
"path": "packages/business/src/cli.mjs",
|
||||
"upstreamChanged": false,
|
||||
"matchesPriorBlob": true,
|
||||
"changeLinesIdentical": true
|
||||
},
|
||||
{
|
||||
"path": "packages/business/src/instance-settings.mjs",
|
||||
"upstreamChanged": false,
|
||||
"matchesPriorBlob": true,
|
||||
"changeLinesIdentical": true
|
||||
},
|
||||
{
|
||||
"path": "packages/business/src/organization.mjs",
|
||||
"upstreamChanged": false,
|
||||
"matchesPriorBlob": true,
|
||||
"changeLinesIdentical": true
|
||||
},
|
||||
{
|
||||
"path": "packages/business/src/resolve.mjs",
|
||||
"upstreamChanged": false,
|
||||
"matchesPriorBlob": true,
|
||||
"changeLinesIdentical": true
|
||||
},
|
||||
{
|
||||
"path": "packages/business/tests/business.test.mjs",
|
||||
"upstreamChanged": false,
|
||||
"matchesPriorBlob": true,
|
||||
"changeLinesIdentical": true
|
||||
},
|
||||
{
|
||||
"path": "packages/business/tests/cli.test.mjs",
|
||||
"upstreamChanged": false,
|
||||
"matchesPriorBlob": true,
|
||||
"changeLinesIdentical": true
|
||||
},
|
||||
{
|
||||
"path": "packages/business/tests/instance-settings.test.mjs",
|
||||
"upstreamChanged": false,
|
||||
"matchesPriorBlob": true,
|
||||
"changeLinesIdentical": true
|
||||
},
|
||||
{
|
||||
"path": "packages/business/tests/library-projects-protected.test.mjs",
|
||||
"upstreamChanged": false,
|
||||
"matchesPriorBlob": true,
|
||||
"changeLinesIdentical": true
|
||||
},
|
||||
{
|
||||
"path": "packages/business/tests/resolve.test.mjs",
|
||||
"upstreamChanged": false,
|
||||
"matchesPriorBlob": true,
|
||||
"changeLinesIdentical": true
|
||||
},
|
||||
{
|
||||
"path": "packages/cli/src/config.mjs",
|
||||
"upstreamChanged": false,
|
||||
"matchesPriorBlob": true,
|
||||
"changeLinesIdentical": true
|
||||
},
|
||||
{
|
||||
"path": "packages/cli/src/launcher.mjs",
|
||||
"upstreamChanged": false,
|
||||
"matchesPriorBlob": true,
|
||||
"changeLinesIdentical": true
|
||||
},
|
||||
{
|
||||
"path": "packages/cli/tests/launcher.test.mjs",
|
||||
"upstreamChanged": false,
|
||||
"matchesPriorBlob": true,
|
||||
"changeLinesIdentical": true
|
||||
},
|
||||
{
|
||||
"path": "packages/cli/tests/stack-release-fixture.mjs",
|
||||
"upstreamChanged": false,
|
||||
"matchesPriorBlob": true,
|
||||
"changeLinesIdentical": true
|
||||
},
|
||||
{
|
||||
"path": "packages/cli/tests/stack-release.test.mjs",
|
||||
"upstreamChanged": true,
|
||||
"matchesPriorBlob": false,
|
||||
"changeLinesIdentical": true
|
||||
},
|
||||
{
|
||||
"path": "packages/cli/tests/trackers-boot.test.mjs",
|
||||
"upstreamChanged": false,
|
||||
"matchesPriorBlob": true,
|
||||
"changeLinesIdentical": true
|
||||
},
|
||||
{
|
||||
"path": "packages/library/src/index.mjs",
|
||||
"upstreamChanged": false,
|
||||
"matchesPriorBlob": true,
|
||||
"changeLinesIdentical": true
|
||||
},
|
||||
{
|
||||
"path": "packages/library/src/mirror.mjs",
|
||||
"upstreamChanged": false,
|
||||
"matchesPriorBlob": true,
|
||||
"changeLinesIdentical": true
|
||||
},
|
||||
{
|
||||
"path": "packages/library/tests/mirror.test.mjs",
|
||||
"upstreamChanged": false,
|
||||
"matchesPriorBlob": true,
|
||||
"changeLinesIdentical": true
|
||||
},
|
||||
{
|
||||
"path": "packages/project/src/paths.mjs",
|
||||
"upstreamChanged": false,
|
||||
"matchesPriorBlob": true,
|
||||
"changeLinesIdentical": true
|
||||
},
|
||||
{
|
||||
"path": "packages/project/tests/project.test.mjs",
|
||||
"upstreamChanged": false,
|
||||
"matchesPriorBlob": true,
|
||||
"changeLinesIdentical": true
|
||||
},
|
||||
{
|
||||
"path": "packages/seat/src/checkout.mjs",
|
||||
"upstreamChanged": false,
|
||||
"matchesPriorBlob": true,
|
||||
"changeLinesIdentical": true
|
||||
},
|
||||
{
|
||||
"path": "packages/seat/tests/checkout.test.mjs",
|
||||
"upstreamChanged": false,
|
||||
"matchesPriorBlob": true,
|
||||
"changeLinesIdentical": true
|
||||
},
|
||||
{
|
||||
"path": "packages/webui/src/cli.mjs",
|
||||
"upstreamChanged": false,
|
||||
"matchesPriorBlob": true,
|
||||
"changeLinesIdentical": true
|
||||
},
|
||||
{
|
||||
"path": "packages/webui/tests/library-cli.test.mjs",
|
||||
"upstreamChanged": false,
|
||||
"matchesPriorBlob": true,
|
||||
"changeLinesIdentical": true
|
||||
}
|
||||
],
|
||||
"newSource": "a6101e21c596e2972ab5a7e3087736075899505e",
|
||||
"stablePatchId": "d191e7e9586cd3b7c18310daacdf0c1fdbc8be01"
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
packages/bus/tests/library.test.mjs
|
||||
packages/bus/tests/project-runtime.test.mjs
|
||||
packages/business/tests/business.test.mjs
|
||||
packages/business/tests/cli.test.mjs
|
||||
packages/business/tests/instance-settings.test.mjs
|
||||
packages/business/tests/library-projects-protected.test.mjs
|
||||
packages/business/tests/resolve.test.mjs
|
||||
packages/cli/tests/launcher.test.mjs
|
||||
packages/cli/tests/stack-release-external.test.mjs
|
||||
packages/cli/tests/stack-release.test.mjs
|
||||
packages/cli/tests/stack-upgrade.test.mjs
|
||||
packages/cli/tests/trackers-boot.test.mjs
|
||||
packages/library/tests/mirror.test.mjs
|
||||
packages/project/tests/project.test.mjs
|
||||
packages/seat/tests/checkout.test.mjs
|
||||
packages/webui/tests/library-cli.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/comment-cursors.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/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/hard-waits.test.mjs
|
||||
packages/bus/tests/host-run.test.mjs
|
||||
packages/bus/tests/human.test.mjs
|
||||
packages/bus/tests/instances-verb.test.mjs
|
||||
packages/bus/tests/land.test.mjs
|
||||
packages/bus/tests/launch-notice.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/messages.test.mjs
|
||||
packages/bus/tests/messaging.test.mjs
|
||||
packages/bus/tests/names.test.mjs
|
||||
packages/bus/tests/plugins-verb.test.mjs
|
||||
packages/bus/tests/process.test.mjs
|
||||
packages/bus/tests/project-await.test.mjs
|
||||
packages/bus/tests/project-files.test.mjs
|
||||
packages/bus/tests/publish.test.mjs
|
||||
packages/bus/tests/replies.test.mjs
|
||||
packages/bus/tests/requirements.test.mjs
|
||||
packages/bus/tests/review.test.mjs
|
||||
packages/bus/tests/routes-verb.test.mjs
|
||||
packages/bus/tests/single-use.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/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-migration.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-runtime.test.mjs
|
||||
packages/bus/tests/web.test.mjs
|
||||
packages/bus/tests/workflow-roles.test.mjs
|
||||
@@ -0,0 +1,86 @@
|
||||
diff --git a/packages/bus/src/broker.mjs b/packages/bus/src/broker.mjs
|
||||
index 135a1699a..f0eb4ae65 100644
|
||||
--- a/packages/bus/src/broker.mjs
|
||||
+++ b/packages/bus/src/broker.mjs
|
||||
@@ -88,6 +88,7 @@ export const TASK_PAGE_MAX = 200;
|
||||
// Row 148 (#1642): the human-only verbs behind the Console's document editor. The save is the one
|
||||
// request allowed past the ordinary 64 KiB envelope (server.mjs and client.mjs), up to its content cap.
|
||||
export const PROJECT_FILE_VERBS = Object.freeze(['project.files', 'project.file', 'project.file.save']);
|
||||
+export const LIBRARY_VERBS = Object.freeze(['library.file', 'library.status']);
|
||||
export const PROJECT_SAVE_VERB = 'project.file.save';
|
||||
export const PROJECT_SAVE_REQUEST_MAX = 1024 * 1024 + 64 * 1024;
|
||||
export const WEB_VERBS =Object.freeze(['web.search', 'web.fetch']);
|
||||
@@ -279,6 +280,7 @@ export class Broker {
|
||||
#organization;
|
||||
#credentialVerbs;
|
||||
#project;
|
||||
+ #library;
|
||||
#usage;
|
||||
#limits;
|
||||
#harnessOn;
|
||||
@@ -294,7 +296,7 @@ export class Broker {
|
||||
#stops = new Map();
|
||||
#clock = 0;
|
||||
// credentialStatus is the runtime's metadata-only Credentials.status(); the broker never gets use().
|
||||
- constructor({ store, businesses, secretCheck = () => {}, credentialStatus = () => [], organization = null, project = null, usage = null, limits = null, harnessOn = null, credentialVerbs = null, hostGrant = null, hostKeys = null }) {
|
||||
+ constructor({ store, businesses, secretCheck = () => {}, credentialStatus = () => [], organization = null, project = null, library = null, usage = null, limits = null, harnessOn = null, credentialVerbs = null, hostGrant = null, hostKeys = null }) {
|
||||
if (!object(businesses) || !Object.keys(businesses).length) fail('invalid-business');
|
||||
this.#businesses = structuredClone(businesses);
|
||||
this.#store = store;
|
||||
@@ -306,6 +308,7 @@ export class Broker {
|
||||
this.#hostGrant = hostGrant;
|
||||
this.#hostKeys = hostKeys;
|
||||
this.#project = project;
|
||||
+ this.#library = library;
|
||||
this.#usage = usage;
|
||||
this.#limits = limits;
|
||||
// Row 65: harnessOn(business, name) is true when the organization file's plugins.harness switches
|
||||
@@ -2192,6 +2195,8 @@ export class Broker {
|
||||
return this.#requestProject(s, { verb: request.verb, args: structuredClone(args) });
|
||||
if (PROJECT_FILE_VERBS.includes(request.verb))
|
||||
return this.#requestProjectFile(s, { verb: request.verb, args: structuredClone(args) });
|
||||
+ if (LIBRARY_VERBS.includes(request.verb))
|
||||
+ return this.#requestLibrary(s, { verb: request.verb, args: structuredClone(args) });
|
||||
if (CREDENTIAL_VERBS.includes(request.verb)) return this.#requestCredential(s, request.verb, structuredClone(args));
|
||||
if (["limits", "limits.set", "organization.set", "organization.revision", "plugins", "plugins.set", "instances", "instances.set", "routes", "routes.set"].includes(request.verb)) {
|
||||
// Row 123 (#1617, REQ-COS-1, REQ-LIMIT-1): organization.set is limits.set for a role whose
|
||||
@@ -2441,6 +2446,26 @@ export class Broker {
|
||||
throw this.#refused(s, ProjectFailure && e instanceof ProjectFailure ? new BusError(e.code) : e, request);
|
||||
}
|
||||
}
|
||||
+ // C2-04 M4: only a verified human reads library text or status. Host Git
|
||||
+ // functions stay injected, preserving this module's sandbox import closure.
|
||||
+ async #requestLibrary(s, request) {
|
||||
+ const { verb, args } = request;
|
||||
+ try {
|
||||
+ this.#human(s);
|
||||
+ const fields = verb === 'library.file' ? ['project', 'path'] : ['project'];
|
||||
+ keys(args, fields, fields);
|
||||
+ if (!this.#library?.readFile || !this.#library?.status) fail('project-not-configured');
|
||||
+ const context = { business: this.#business(s.business), project: args.project };
|
||||
+ const result = verb === 'library.file'
|
||||
+ ? await this.#library.readFile({ ...context, path: args.path })
|
||||
+ : await this.#library.status(context);
|
||||
+ this.#secretCheck(result);
|
||||
+ return result;
|
||||
+ } catch (error) {
|
||||
+ const Failure = this.#library?.LibraryError;
|
||||
+ throw this.#refused(s, Failure && error instanceof Failure ? new BusError(error.code) : error, request);
|
||||
+ }
|
||||
+ }
|
||||
// The eight task verbs reach the trusted S3 handler here. It runs outside any transaction, gets the
|
||||
// cap to authorize and record through authorize() and recordTask(); refusals are recorded as in request().
|
||||
async requestTask(cap, request, handler) {
|
||||
diff --git a/packages/cli/tests/stack-release.test.mjs b/packages/cli/tests/stack-release.test.mjs
|
||||
index 7398247ce..0e316fd74 100644
|
||||
--- a/packages/cli/tests/stack-release.test.mjs
|
||||
+++ b/packages/cli/tests/stack-release.test.mjs
|
||||
@@ -1779,7 +1779,7 @@ export class Store {
|
||||
const RCOPIES=join(base,'rcopies');mkdirSync(RCOPIES);
|
||||
for(const [id,v,froms] of [[B,'3g',['3f']],[C,'3h',['3f','3g']],[A,'3g',['3f']],[C1,'3g',['3f']]]){
|
||||
const d=join(RCOPIES,id);
|
||||
- for(const p of ['scripts/mosaic','scripts/mosaic-config.mjs','packages/cli/src/config.mjs','packages/cli/src/errors.mjs','packages/bus/src/business.mjs','packages/plugins/src/kinds.mjs','packages/business/src','roles'])cpSync(join(repo,p),join(d,p),{recursive:true});
|
||||
+ for(const p of ['scripts/mosaic','scripts/mosaic-config.mjs','packages/cli/src/config.mjs','packages/cli/src/errors.mjs','packages/bus/src/business.mjs','packages/plugins/src/kinds.mjs','packages/business/src','packages/library/src','roles'])cpSync(join(repo,p),join(d,p),{recursive:true});
|
||||
if(id===C1)writeFileSync(join(d,'scripts','mosaic'),`#!/usr/bin/env bash\nexec node "${join(RCOPIES,B,'packages','cli','src','cli.mjs')}" "$@"\n`,{mode:0o755});
|
||||
for(const [f,text] of [['packages/cli/src/cli.mjs',id===A?'// fixture host from before row 163\nprocess.exit(1);\n':script(rHost)],['packages/webui/src/cli.mjs',script(rConsole)],['packages/bus/src/store.mjs',rStore(v,froms)],['packages/bus/src/migrate-schema.mjs',script(rMigrate)],['packages/bus/src/broker.mjs','export class BusError extends Error { constructor(code) { super(code); this.code = code; } }\n']]){mkdirSync(dirname(join(d,f)),{recursive:true});writeFileSync(join(d,f),text)}
|
||||
execFileSync('chmod',['-R','a-w',d]);
|
||||
@@ -0,0 +1,10 @@
|
||||
1: e333af4dc ! 1: a6101e21c feat: add human-only library projects and served reads
|
||||
@@ Metadata
|
||||
Author: Herb <[email protected]>
|
||||
|
||||
## Commit message ##
|
||||
- feat: add human-only library projects and served reads
|
||||
+ feat: carry reviewed C2-04 library entry onto row 197 landing
|
||||
|
||||
## BUILD-LOG.md ##
|
||||
@@ BUILD-LOG.md: Before: managed project/thread verbs had no Console conversation area. After: fi
|
||||
@@ -0,0 +1,166 @@
|
||||
# Row 222 build: C2-03a fetch-only library sync
|
||||
|
||||
Row 222, #1723, reviewer Dewey. Brief: C2-03a in the case 2 plan (sage-1853, sage-1854), with
|
||||
sage-2021 and sage-2022 adding to it. Built on Herb's row 215 candidate source e333af4dc (base
|
||||
f8276c5eb, packet 14a03d10f, Herb's BUILD.md blob f80f21919d95), then rebased with no conflicts
|
||||
onto 215's landing e54e05463 (sage-2099) as branch megavolt/row222-r2. The old branch
|
||||
megavolt/row222 is kept.
|
||||
|
||||
Between e333af4dc and e54e05463, two of 222's files changed. broker.mjs gained row 249's
|
||||
hostLineLeft lines, which 222 doesn't touch. stack-copy.sh gained row 66's `tools/unslop-hook`
|
||||
in COPY_PATHS, two lines below 222's `packages/library/bin`. In the range-diff, commit 1 differs
|
||||
only in that context line, and commits 2 and 3 are identical.
|
||||
|
||||
## What it does
|
||||
|
||||
- `packages/library/src/sync.mjs` (new):
|
||||
- `syncCommand('fetch', url, opts)` builds the one git command.
|
||||
- `sync(context, opts)` fetches the configured branch into `refs/remotes/library/<branch>`,
|
||||
then publishes under the C2-04 library lock:
|
||||
- a fast-forward moves `refs/heads/served`;
|
||||
- a non-fast-forward is held as `library-diverged` until a human accepts the tip;
|
||||
- a failed fetch keeps serving the old commit and records `lastError`.
|
||||
- `packages/library/bin/askpass` (new, sh) is git's GIT_ASKPASS helper. It answers only the two
|
||||
prompts for the configured host and user. For the password it reads the first line of the slot
|
||||
file. The token never reaches argv, env, git config, a URL, the state file or a log.
|
||||
- `packages/library/src/mapping.mjs`: an optional `user` (the bot account name). Sync refuses an
|
||||
entry without it.
|
||||
- Bus:
|
||||
- `broker.mjs`: `library.sync` is human-only. It takes `{project, accept?}`, and a held code
|
||||
becomes a recorded refusal.
|
||||
- `runtime.mjs`: a timer syncs every entry with a `user` at start and every 60 s.
|
||||
- `webui/src/cli.mjs`: the Console gets the call.
|
||||
- `scripts/stack-copy.sh` copies `packages/library/bin`.
|
||||
- Docs: library README "Sync" section, SURVEY-RUN.md step 5.
|
||||
|
||||
## Scope rulings followed
|
||||
|
||||
- sage-1853/1854: the timer lives in the bus runtime, not a separate unit. The slot is
|
||||
`<configDir>/secrets/<business>/library-gitea`, mode 0600, owned by the bus uid.
|
||||
- sage-2021: `user` is optional in the mapping and required for sync. Test runs wait for Sage's
|
||||
"clear".
|
||||
- sage-2022 / Filbert N2 (#1716 comment 30071):
|
||||
- Sync never runs gc or prune and never fetches with `--prune`. `maintenance.auto=false` and
|
||||
`gc.auto=0` come from SAFE.
|
||||
- Test "Filbert N2" holds a served commit, lets sync move served, then reads the held commit's
|
||||
blob.
|
||||
- The read path is unchanged, so readLibraryFile's whole-tree read stays (see Known costs).
|
||||
|
||||
## Choices and tradeoffs
|
||||
|
||||
1. **One sync per mirror, refused as `library-sync-busy`.** The C2-04 lock covers publication
|
||||
only, and readers wait 5 s for it, so the fetch runs outside it. A module-level set refuses a
|
||||
second sync into the same mirror instead of letting two fetches race. A timer tick that finds
|
||||
its pass still running is skipped, not queued.
|
||||
2. **Problems are read before the lock.** readLibrary over a large tree can take longer than a
|
||||
reader's 5 s lock wait. Problems belong to the tip alone, so they are computed outside and
|
||||
only published inside.
|
||||
3. **The served ref moves by compare-and-swap.** `update-ref refs/heads/served <tip> <old>`
|
||||
(zero id on a first sync). If the state write then fails, the ref goes back, so the ref and
|
||||
the state file never disagree.
|
||||
4. **State written via a temp file beside the mirror.** inspectMirror refuses unknown names
|
||||
inside the mirror, so the temp file goes in its parent directory (O_EXCL|O_NOFOLLOW, 0600).
|
||||
Then fsync, rename into the mirror, and fsync the directory.
|
||||
5. **Divergence is held, even through a later fast-forward.** Once diverged, served stays put
|
||||
until `accept`. `diverged.at` keeps the first detection time, and `diverged.commit` follows
|
||||
the tip, because that is the commit accept must name. A tip that comes back to the served
|
||||
commit clears it.
|
||||
6. **`accept` starts the record over.** It must equal the fetched tip (otherwise
|
||||
`library-accept-stale`). It writes a fresh record, which also clears a state left from
|
||||
another branch (readSyncState refuses a branch mismatch).
|
||||
7. **`lastFetch` is the last successful fetch.** A failed fetch leaves it alone and sets
|
||||
`lastError`.
|
||||
8. **`credential.helper=` reset in argv.** It stops a user or system helper from storing or
|
||||
offering the token. With GIT_TERMINAL_PROMPT=0 from gitEnv, askpass is the only source.
|
||||
9. **`http.followRedirects=false`.** A redirect to another host would get the prompt for that
|
||||
host, which askpass refuses anyway. Not following redirects means no request reaches the
|
||||
other host at all (tested with a 302).
|
||||
10. **`core.createObject=rename`.** A departure from the brief; see the next section.
|
||||
11. **Extra env keys.** GIT_CEILING_DIRECTORIES (git never looks above the mirror) and
|
||||
MOSAIC_LIBRARY_HOST/USER/SLOT (the askpass inputs, no secret). The brief named
|
||||
GIT_ASKPASS only.
|
||||
12. **`SAFE` exported from `packages/project/src/git.mjs`.** One word. Sync reuses the same
|
||||
safe `-c` set instead of copying it.
|
||||
13. **Row 199's fd-3 helper not reused.** publishRemote (packages/seat/src/working.mjs) puts an
|
||||
inline `credential.helper` in argv and feeds the token to it on fd 3, so node reads the token
|
||||
first. The brief names GIT_ASKPASS. With askpass, node only lstats the slot and never opens
|
||||
it; the helper script reads it. The prompt checks do the same job as row 199's host check.
|
||||
14. **The timer's test hook.** `startBroker({librarySync: {command, intervalMs, configDir}})` is
|
||||
refused unless `command` is a function. A JSON boot config can't carry a function, so a boot
|
||||
file can't set it, and process.mjs needs no change.
|
||||
15. **No server.mjs edit.** server.mjs awaits every verb in LIBRARY_VERBS with a 120 s socket
|
||||
timeout. Adding `library.sync` to LIBRARY_VERBS covers it.
|
||||
|
||||
## Departure from the brief: `core.createObject=rename`
|
||||
|
||||
Sage accepted this departure (sage-2024, rev 2898), and Dewey rules on it in review. The fetch argv
|
||||
(`syncCommand`, packages/library/src/sync.mjs) is:
|
||||
|
||||
```
|
||||
[...SAFE, '-c', 'protocol.https.allow=always', '-c', 'http.followRedirects=false', '-c', 'credential.helper=',
|
||||
'-c', 'core.createObject=rename', '-C', mirror, 'fetch', '--no-tags', '--no-write-fetch-head', '--no-recurse-submodules', '--end-of-options',
|
||||
parsed.href, `+refs/heads/${branch}:refs/remotes/library/${branch}`]
|
||||
```
|
||||
|
||||
Why: by default git files each new object by link, then unlink. While that runs, the object has
|
||||
nlink 2. C2-04's inspectMirror refuses any file in the mirror with nlink other than 1, so a reader
|
||||
running during a fetch could be refused. With `rename`, git never makes a second link.
|
||||
|
||||
The argv test in sync.test.mjs pins the full sequence, including this flag. The race itself is not
|
||||
tested (sage-2024).
|
||||
|
||||
## Known costs and residuals
|
||||
|
||||
- **readLibraryFile reads the whole tree to return one file** (C2-01 exclusions, Filbert's
|
||||
note on 215). 222 doesn't touch the read path, so it stays.
|
||||
- **The human transport times out at 5 s, a follow-up for Dewey to rule fix or defer.**
|
||||
packages/bus/src/human-cli.mjs builds its `Client` (packages/bus/src/client.mjs) with the default
|
||||
`timeout = 5000`. A fetch can take up to the GIT_LIMITS ceiling (100 s), so a human call to
|
||||
library.sync against a slow remote can return outcome-unknown while the sync finishes, and the
|
||||
state file records the result. The outer layers allow longer: busCaller and humanCall in
|
||||
packages/webui/src/bus.mjs use 30 s, and the bus server awaits library verbs for 120 s.
|
||||
222 has no Console route to fix. packages/webui/src/serve.mjs has no library route at all
|
||||
(library.file, library.status and library.sync are passed to startServer and unused there), and
|
||||
neither serve.mjs nor human-cli.mjs is in 222's paths. Follow-up: when the Console gains a
|
||||
library.sync route, give that path a 120 s client timeout.
|
||||
- **Problems are unbounded until the state hits 8 MiB.** A tree with very many problems makes
|
||||
the state write fail with `library-state-invalid`, and served doesn't move. No cap per
|
||||
problem list was added.
|
||||
- **No behaviour test for the `credential.helper=` reset, a follow-up for Dewey (sage-2033).**
|
||||
Only the argv test pins the reset: mutant 3 (drop it) was killed by that test alone. Today the
|
||||
reset is defence in depth. gitEnv() sets GIT_CONFIG_GLOBAL=/dev/null and GIT_CONFIG_NOSYSTEM,
|
||||
and C2-04's inspectMirror refuses any mirror config key outside its allowlist, so no config
|
||||
git reads can name a helper. gitEnv() also builds a fresh env, so the caller's env can't add
|
||||
one. A behaviour test would have to plant a helper through the test's `command` wrapper (for
|
||||
example GIT_CONFIG_COUNT/KEY/VALUE, the way the CA wrapper adds GIT_SSL_CAINFO), then show
|
||||
that git never calls it. Left as a named follow-up.
|
||||
- **stack-copy.test.mjs is not changed.** It copies `ls-files -co`, which includes bin/askpass.
|
||||
The cli package is not mine.
|
||||
|
||||
## Tests
|
||||
|
||||
- `packages/library/tests/sync.test.mjs` (new). It uses a fake Gitea over TLS
|
||||
(`packages/seat/tests/fake-gitea.mjs`), a made-up token and scratch roots, with no network.
|
||||
It covers the argv and env, the URL and user refusals, askpass prompts, first sync,
|
||||
fast-forward, Filbert N2, reader overlap, divergence and accept, accept across a branch
|
||||
change, a wrong token, a failed first fetch, a redirect, slot refusals, no user, and busy.
|
||||
- `packages/library/tests/mapping.test.mjs`: the `user` field.
|
||||
- `packages/bus/tests/library-sync.test.mjs` (new): bus refusals for agent, tester and reader;
|
||||
the human path; a refused boot hook; the timer.
|
||||
- Run on 4a0e0ab3a under grant sage-2028, each file whole: sync 15/15, mapping 8/8,
|
||||
packages/bus/tests/library.test.mjs 6/6, library-sync 5/5. No log contains the token.
|
||||
- Mutants, each against sync.test.mjs whole, all killed. After each one git diff was empty
|
||||
and askpass stayed 755.
|
||||
|
||||
| Mutant | Killed by |
|
||||
|---|---|
|
||||
| protocol.https.allow -> protocol.allow=always | argv test |
|
||||
| drop http.followRedirects=false | argv test, 302 test |
|
||||
| drop the credential.helper= reset | argv test only (see Known costs) |
|
||||
| askpass answers any prompt | helper prompt test |
|
||||
| askpass prints the token for Username | helper test and 8 sync tests |
|
||||
|
||||
The last mutant's log holds the made-up fixture token, because the mutant printed it.
|
||||
- After the rebase onto 215's landing: these 4 files again, plus
|
||||
packages/library/tests/mirror.test.mjs, packages/webui/tests/library-cli.test.mjs,
|
||||
packages/webui/tests/pinned-copy.test.mjs and packages/cli/tests/stack-copy.test.mjs.
|
||||
@@ -0,0 +1,128 @@
|
||||
# Row 243: too-open mode refusal tests set their mode with chmod
|
||||
|
||||
Brief: `docs/plans/2026-10-21_gate-env-rows.md` § "The startup token refusal test sets its file mode"
|
||||
(Sage, sage-1909). Reviewer Webby. Lands after row 197 (mos-1162). Design notes written before 197
|
||||
lands, read at `origin/refactor` 01e1fe512. Recheck the line cites against 197's landing before code
|
||||
starts.
|
||||
|
||||
## The defect
|
||||
|
||||
`writeFileSync(file, data, { mode })` and `mkdirSync(dir, { mode })` apply the process umask to the
|
||||
mode. A test that creates a "too open" file this way and expects a refusal passes under `umask 022`
|
||||
(0644 stays 0644) and fails under `umask 077` (0644 becomes 0600, and the source accepts it).
|
||||
|
||||
Row 197 r6 (df0c59608) runs each gate step under `umask 022` (`gate-lane.mjs:46`), so the lane no
|
||||
longer hits this. Row 243 still makes the tests independent of the umask, as the brief asks.
|
||||
|
||||
## Sweep
|
||||
|
||||
Method: every source-side mode check in `packages/*/src` and `scripts/` (grep for `mode & 0o...`), then
|
||||
the tests that reach each check's refusal branch, deciding whether the too-open object gets its mode at
|
||||
creation or from an explicit chmod. Also a scan of every `writeFileSync`/`mkdirSync`/`openSync` in
|
||||
`packages/*/tests` with a group or other bit in its mode (50 hits, 41 without a following chmod), and a
|
||||
grep of the refusal messages for objects created with no mode or by a shell-out. Read at
|
||||
`origin/refactor` with `git show` and `git grep`; nothing run.
|
||||
|
||||
Affected refusal tests, all three verified by reading the test (the fourth file, an accept test, follows the table):
|
||||
|
||||
| Creation | Test | Source check | Expected refusal |
|
||||
|---|---|---|---|
|
||||
| `packages/bus/tests/process.test.mjs:76` `writeFileSync(file, secret, { mode: 0o644 })` | startup token refusal returns safe code... | `bus/src/credentials.mjs:205` (must be 0600) | `credential-file`, exit 2 (:83-84) |
|
||||
| `packages/webui/tests/proof-cli.test.mjs:28` `writeFileSync(file, value, { mode })`, mode 0o644 from the `mode` case at :27 | proof startup refuses partial flags... | `webui/src/serve.mjs:234` (0600 or 0400) | status 2 (:38) |
|
||||
| `packages/webui/tests/sso.test.mjs:360` `writeFileSync(.../secrets/mosaic-stack/a, ..., { mode: 0o644 })` | 11: the CLI refuses --sso... | `webui/src/sso.mjs:45` (no group or other bits) | status 2 and the "no group or other permission bits" line (:361-363); the chmod to 0600 at :364 comes after |
|
||||
|
||||
Fix for each: keep the write, then `chmodSync(<path>, 0o644)` right after it. For `proof-cli.test.mjs`
|
||||
the chmod goes inside the case map after the write, with the case's own mode, so the 0o600 cases are set
|
||||
explicitly too.
|
||||
|
||||
Not affected (each sets the mode with a chmod or a chmodding helper before the code under test reads it):
|
||||
bus credentials.test :52, credential-store.test :55-61; business access.test :225-226, business.test
|
||||
:159/161/174, credentials.test :60, cli.test :151, helpers `writeJson`/`tokenFile`; cli cli.test :176,
|
||||
notifier.test :318/:321, stack-release.test :1220/1239/1294/1313/1552, stack-upgrade.test :426-430,
|
||||
case2-unit.test :340/:510/:635; control-board discord.test :79; discord binding.test :106/118/140/277,
|
||||
notify.test :76, setspark.test :110, git.test :138/:360, offline-check.test :21; mosaic safety.test :80;
|
||||
queue review.test :214/:228; ledger gitea-helper-raw.test :113; webui service.test :797, sso.test :310;
|
||||
bus host-tools.test :182/:266. The 0o644/0o755 adapter and fake-binary writes (launcher, thread-launch,
|
||||
session, sandbox, checkout, commit, etc.) aren't read by a mode check, or are only checked for the exec
|
||||
bit, which 0700 keeps. `host-tools.test.mjs:205`, `:271` and the confDir at `:77` expect acceptance and
|
||||
only need "not group-writable".
|
||||
|
||||
Mode checks with no refusal test at all (not this row; listed for the record): `bus/src/store.mjs:121`,
|
||||
`bus/src/host-run.mjs:71`, `business/src/organization.mjs:28/45/109/141`,
|
||||
`conversation/src/controller.mjs:299`, `mosaic/src/materialize-fixture.mjs:16`,
|
||||
`mosaic/src/refresh-fixture.mjs:64`, `seat/src/session.mjs:72`, `scripts/git-credential-mosaic.mjs:49`,
|
||||
and the mode branch of `scripts/stack-release.sh:1952`.
|
||||
|
||||
Fourth file, folded in by Sage (sage-1918): `packages/cli/tests/stack-instances.test.mjs:84` and `:89`
|
||||
assert 0644 on the config and `instance.json`. `scripts/mosaic-config.mjs:337` creates them with
|
||||
`openSync(file, "wx", 0o644)` and no chmod, so under `umask 077` they come out 0600 and the test fails.
|
||||
This is an accept test of a source mode, not a refusal test.
|
||||
|
||||
| Creation | Test | Source | Ruling |
|
||||
|---|---|---|---|
|
||||
| `scripts/mosaic-config.mjs:337` via `bootstrap()` (`stack-instances.test.mjs:41`, a `spawnSync` of `scripts/bootstrap.sh`) | the `--instance` create test, :79-89 | `createExclusive` passes 0o644 and the umask narrows it | test-only (sage-1918) |
|
||||
|
||||
- No change to `mosaic-config.mjs`. Letting the operator's umask narrow the config is the source's
|
||||
choice; a chmod to 0644 would make the config wider than that umask. No row asks for it.
|
||||
- `bootstrap()` runs its child under an explicit `umask 022`, the pattern from `gate-lane.mjs:46`:
|
||||
`run("/bin/bash", ["-c", 'umask 022; exec "$@"', "bash", BOOTSTRAP, ...args], homeEnv(home))`. Every
|
||||
`bootstrap()` call goes through it (:79, :99, :102, :119, :127, :136, :140, :152, :165, :169), so the
|
||||
0644 assertions still prove the mode the source asks for, whatever the gate's umask.
|
||||
- New assertion: a `bootstrap --instance` run under `umask 077` makes the config and `instance.json`
|
||||
0600. That pins that the source honors the umask, so a later chmod "fix" fails a test. The directories
|
||||
stay 0700 in both runs (they're created with `mode: 0o700`, which 077 can't narrow).
|
||||
- The `config()` helper (:42) has no mode assertion and stays as it is.
|
||||
|
||||
Tests outside `packages/*/tests`: the five `scripts/foundation/*.test.mjs` files have no open-mode
|
||||
write. `cli.test.mjs:144/148` chmods to 0o000 and 0o600, which doesn't depend on the umask. The
|
||||
`agents/*/work` probe tests are review evidence, not gate steps (`discoverSteps` doesn't run them), so
|
||||
they're out of scope.
|
||||
|
||||
## Tests
|
||||
|
||||
- Each of the four files runs whole twice, once under `umask 022` and once under `umask 077`
|
||||
(`bash -c 'umask 077; node --test <file>'`). Both pass. The brief requires this for process.test.mjs;
|
||||
Sage extended it to all four (sage-1918).
|
||||
- Proof that the change matters: before the change, the same four files under `umask 077` fail on the
|
||||
named assertions. I record that run too, on the slot, so the 077 pass after the change is meaningful.
|
||||
- Order (mos-1162): this lands after 197 r6, so r6's proof ran on the unchanged test.
|
||||
|
||||
## Files (expected)
|
||||
|
||||
`packages/bus/tests/process.test.mjs`, `packages/webui/tests/proof-cli.test.mjs`,
|
||||
`packages/webui/tests/sso.test.mjs`, `packages/cli/tests/stack-instances.test.mjs`. Test-only. No
|
||||
source change.
|
||||
|
||||
## Build (sage-2056: start on row 197's landing a36523713)
|
||||
|
||||
Branch `morgana/row243`, one commit on a36523713. Cites rechecked there: all hold except proof-cli's
|
||||
write, which is now `proof-cli.test.mjs:30` (was :28).
|
||||
|
||||
- `bus/tests/process.test.mjs`: imports `chmodSync`; `chmodSync(file, 0o644)` after the write at :76.
|
||||
- `webui/tests/proof-cli.test.mjs:30`: `chmodSync(file, mode)` after the write, with each case's own
|
||||
mode, so the 0o600 cases are set explicitly too.
|
||||
- `webui/tests/sso.test.mjs:360`: `chmodSync(..., 0o644)` after the write, before the `--sso` start
|
||||
that must refuse.
|
||||
- `cli/tests/stack-instances.test.mjs`: `underUmask(mask, home, args)` runs `scripts/bootstrap.sh`
|
||||
through `/bin/bash -c 'umask <mask>; exec "$@"'`; `bootstrap()` is `underUmask("022", ...)`. New
|
||||
subtest in T-I1: under umask 077 the config dir and root are 0700, and the config and `instance.json`
|
||||
are 0600.
|
||||
- Hash pins: no test or script names any of the four files (a grep for the basenames; positive control
|
||||
`stack-release.test` found in two files). `stack-release.test.mjs:2122` mentions
|
||||
`stack-instances.test.mjs` only in a comment.
|
||||
|
||||
Tests: on Sage's slot (sage-2062, plan approved in sage-2059), 18:55Z. My busy check read CLEAR before
|
||||
and after. Each file ran whole with `node --test --test-concurrency=2` from its package, under
|
||||
`bash -c 'umask <mask>; exec ...'`, with TMPDIR from `mktemp -d /mnt/storage/scratch/tmp/g243XXXX`.
|
||||
Script `/mnt/storage/scratch/morgana-r243/slot243.sh`, logs in `logs/` next to it.
|
||||
|
||||
| Tree | umask | process | proof-cli | sso | stack-instances |
|
||||
|---|---|---|---|---|---|
|
||||
| base a36523713 | 077 | 7/1 | 2/1 | 27/1 | 21/2 |
|
||||
| candidate 137bda3af | 022 | 8/0 | 3/0 | 28/0 | 24/0 |
|
||||
| candidate 137bda3af | 077 | 8/0 | 3/0 | 28/0 | 24/0 |
|
||||
|
||||
(pass/fail.) The base fails are the predicted ones: "startup token refusal returns safe code...",
|
||||
"proof startup refuses partial flags...", "11: the CLI refuses --sso...", and in stack-instances the
|
||||
0644 subtest "alpha and beta get a 0700 config dir..." plus its parent T-I1 (so 2). stack-instances has
|
||||
one more test on the candidate (the umask 077 subtest). No unpredicted failure.
|
||||
@@ -0,0 +1,200 @@
|
||||
# Row 66: managed sessions run the unslop check on both harnesses
|
||||
|
||||
Sage, 2026-10-20. Brief: `docs/plans/2026-10-11_managed-session-config.md`, section "Managed
|
||||
sessions run the unslop check on both harnesses", blob 21ae25a328d4. Issue #1559. Reviewers:
|
||||
Dewey and Filbert. Built in the worktree `/mnt/storage/scratch/sage-b66` (branch `sage/row66`)
|
||||
on base 5487ed39d.
|
||||
|
||||
Candidate: see the commit line in the review request. `candidate-manifest.sha256` in this
|
||||
directory has the sha256 of each changed file at the candidate.
|
||||
|
||||
## What changed
|
||||
|
||||
**Wiring.** Both harness modules mount `tools/unslop-hook/lists.json`, `unslop-check.js` and
|
||||
the harness's own entry (pi `extension.ts`, Claude Code `claude-hook.js`) read-only at their
|
||||
own paths, and the bundle manifest lists the three in `sources` with their digests. Pi loads
|
||||
`extension.ts` as the second entry of `MOSAIC_EXTENSIONS`, after the gate extension. Claude
|
||||
Code's `settings.json` gains a Stop hook and a UserPromptSubmit hook, each
|
||||
`timeout -k 2 10 '<node>' '<dir>claude-hook.js' stop|prompt; exit 0`, hook timeout 20, no
|
||||
matcher. Neither can block a reply or a prompt.
|
||||
|
||||
**claude-hook.js** (new). `stop` checks each assistant message with text since the turn's
|
||||
prompt and logs `checked` or `flagged`. `prompt` checks the last reply and, when it has tells,
|
||||
prints the extension's notice, word for word, as `additionalContext`, once per reply (it reads
|
||||
the log for an earlier `notice_injected` with the same entry id). A broken lists.json logs
|
||||
`broken_lists`; any other fault logs `hook_failed`; the exit is always 0.
|
||||
|
||||
**The operator channel.** The runner sets `MOSAIC_UNSLOP_LOG` to `<run>/unslop.jsonl` after the
|
||||
module's variables, so a module can't point it elsewhere. After the landing turn and after each message turn it reads what the
|
||||
log gained (whole lines only, from an offset). The next RESULT it sends ends with a note. The
|
||||
whole note, both parts and the blank line before them, is at most 600 characters (r2):
|
||||
|
||||
- `[unslop: N reply|replies of this session flagged since the last note: <details>. The session gets a correction notice on its next turn.]`
|
||||
- `[unslop: the check is broken, so this session's replies go unchecked: <reason>]`, once a run.
|
||||
|
||||
That RESULT is what `mosaic talk` and `mosaic follow` print. A turn that sends no reply (an
|
||||
incoming RESULT, the landing turn) keeps its note for the next one. `note()` doesn't change
|
||||
state and `sent()` runs only after `message.send` succeeds, so a failed send keeps the note.
|
||||
`clip()` caps the body at 32000 characters plus its 33-character cut line before the note, so the
|
||||
sum is at most 32633, under the bus limit of 32768. The broken reason is cut at 300 where the
|
||||
runner takes it, from the log or from its own read failure, so the broken part is at most 371
|
||||
characters and the flagged part is cut to what is left.
|
||||
|
||||
**Counts.** `unslopCounts(path)` reads the log after the session ended:
|
||||
`{checked, flagged, patterns: {<source>: n}, notices, broken}`. A missing log gives zeros.
|
||||
Findings now carry `source`, the entry's pattern id (`ms-unslop:7`), so `patterns` is per id.
|
||||
|
||||
**The stack copy (r2).** `scripts/stack-copy.sh` `COPY_PATHS` gains `tools/unslop-hook`. Both
|
||||
modules join their files under `REPO`, and a session launched from a pinned copy has
|
||||
`REPO = copies/<sha>`. Without it every managed session from a copy past this row would fail at
|
||||
bundle build with ENOENT (Dewey P1, comment 29440).
|
||||
|
||||
## Round 2
|
||||
|
||||
Round 1 (candidate 8ec03b45a, manifest e68c6bce5ec4) got changes from Filbert (29439) and Dewey
|
||||
(29440). Round 2 carries:
|
||||
|
||||
- F1 (both): a note with both parts wasn't bounded. A 300-character reason, a long flagged part
|
||||
and a clipped answer came to 32934 (Filbert) or 33004 (Dewey), over 32768, and the broker
|
||||
refused the send. `note()` now gives the flagged part only the room the broken part leaves, and
|
||||
`fresh()` cuts every reason at 300, the runner's own read-failure reason included. Tests: the
|
||||
runner test with an answer of 40000 characters, a 400-character `hook_failed` reason and 30
|
||||
flagged replies (note ≤ 600, body ≤ 32768, cut line at 32000), and a unit check that both
|
||||
parts come to exactly 600 and that a read failure on a 250-character path is cut.
|
||||
- F2 (Filbert; Dewey's M3): no test failed a send through `main()`. The new runner test has the
|
||||
broker refuse the first RESULT. The note then rides the next RESULT. One correction to the
|
||||
F1 consequence as written: the broker marks a received message delivered, so the refused
|
||||
message isn't received again in that run. It stays unread and its sender gets no reply; the
|
||||
turn doesn't rerun.
|
||||
- P1 (Dewey): `COPY_PATHS` gains `tools/unslop-hook`. The copy fixtures in
|
||||
`stack-copy.test.mjs` and `pinned-copy.test.mjs` copy `tools/unslop-hook` too, and the
|
||||
pinned-copy top-level list gains `tools`. A new `stack-copy.test.mjs` test makes a copy, loads
|
||||
both harness modules from it, and checks that the adapter, the six unslop paths and the mounts
|
||||
are under the copy and exist.
|
||||
- N1 (Filbert): the two session-test comments say `<dir>/unslop.jsonl`.
|
||||
- N2 (Filbert), doc-only follow-up: the brief's `<run>/session/unslop.jsonl` (:463) and "print
|
||||
mode notifies nobody" (:477) are stale. The brief is Jason's text for this row; the deviation
|
||||
below records the path.
|
||||
- Dewey's notes, no change: the Claude Code Stop timing (finding 3 below) gets a look in the
|
||||
landing session; `patterns` keys per entry source, which is the brief's "per pattern".
|
||||
|
||||
r2 mutants, each killed by its intended test (`mutants-r2.log`):
|
||||
|
||||
| Mutant | Killed by |
|
||||
|---|---|
|
||||
| K1 the r1 `note()` cut | the clipped-answer runner test (the send is refused and it times out) and the unit check |
|
||||
| K2 `fresh()` doesn't cut the reason | the unit check |
|
||||
| K3 `sent()` before `message.send` | the refused-send runner test |
|
||||
| K4 `COPY_PATHS` without `tools/unslop-hook` | the copy test |
|
||||
|
||||
## Ship list against the brief
|
||||
|
||||
| Brief item | Where |
|
||||
|---|---|
|
||||
| A reply with a tell gets a correction notice on the next turn, both harnesses | `pi-session.test.mjs`, `claude-session.test.mjs`, row 66 four-turn tests: notices per request `[0, 1, 1, 2]`, notice text matched in the second request |
|
||||
| A clean reply gets none | same tests: turn 2 is clean and turn 3's request carries no new notice |
|
||||
| Broken lists.json fails closed: no clean verdict, operator told once, session alive | the row 66 broken-lists tests per harness: checked 0, flagged 0, first note broken, second note empty, the session answers both turns |
|
||||
| Counts readable after the session ends | `unslopCounts` on each session's log: `{checked: 4, flagged: 2, notices: 2, broken: null}`, patterns non-empty |
|
||||
| Interface 1 and the export list unchanged | no harness module export added or removed; the runner gains `unslopLog`, `unslopCounts`, `unslopNotes` |
|
||||
|
||||
## Findings made while building
|
||||
|
||||
1. **extension.ts read the wrong reply.** Pi 0.85.1 `getBranch()` returns entries root first
|
||||
(`session-manager.js:958-967` reverses the leaf-to-root walk). `before_agent_start` took the
|
||||
first assistant entry it met, which was the session's first reply, every turn. In the
|
||||
four-turn test the old code gave notices `[0, 1, 2]` over three turns (turn 3 re-noticed
|
||||
turn 1); walking from the end gives `[0, 1, 1]`. Fixed in `extension.ts`; this also affects
|
||||
the fleet copy under `~/.mosaic/tools`, which I didn't touch.
|
||||
2. **claude-hook replies() merged replies.** Grouping by `message.id` across the transcript
|
||||
merged two replies that shared an id (the test API answers `msg_mock` for all). It now groups
|
||||
adjacent assistant lines only, keyed by the first line's uuid. Before the fix turn 4 got no
|
||||
notice (`[0, 1, 1, 1]`).
|
||||
3. **Claude Code Stop timing.** On the first turn of a new session the transcript didn't yet
|
||||
hold the reply when Stop ran, so the hook checked `last_assistant_message` with an empty
|
||||
`entryId`. On resumed turns the reply was in the transcript. The verdict is the same either
|
||||
way; only the entry id differs.
|
||||
4. The finding detail format is `banned word "delve" x1`.
|
||||
|
||||
## Deviations
|
||||
|
||||
- **The log path is `<run>/unslop.jsonl`, not the brief's `<run>/session/unslop.jsonl`.** A
|
||||
thread run's session directory is the thread's store, and
|
||||
`packages/cli/tests/thread-launch.test.mjs:179` pins that a thread run keeps no per-run
|
||||
`session/`. My first build made `<run>/session` for the log and failed that test in the gate
|
||||
(452/453). The brief's other line, "`unslop.jsonl` in the run directory", still holds, and each
|
||||
run keeps its own log.
|
||||
|
||||
- **`packages/seat/tests/sandbox.test.mjs`** isn't an owned file. Its pin
|
||||
`binds(args).length === list.length - 1` broke because the modules now mount three more files.
|
||||
It is now `- 4`, and the test asserts the three unslop read-only binds by name.
|
||||
- **`scripts/stack-copy.sh`** and the two copy tests aren't owned files. The copy change is P1
|
||||
above. PB3 of the Part B window (`repin-partB-proof.md`) holds `scripts/stack-copy.sh` still
|
||||
until B7, so this row lands after the Part B window has run.
|
||||
- `MOSAIC_EXTENSIONS` is set through the pi module's `env`, not in the runner.
|
||||
- `unslop-check.js` gained the `source` field on findings (needed for per-pattern counts).
|
||||
|
||||
## Limits
|
||||
|
||||
- The log is in the run directory, which the session can write. A session could forge or erase
|
||||
its own counts. They are the session's report, not host evidence.
|
||||
- The pi extension's dedupe is in memory: after a restart, or when a turn's final message is
|
||||
tool-only, the same earlier reply can get a second notice.
|
||||
- `hook_failed`, `skipped_broken` and `broken_lists` all count as broken for the operator note.
|
||||
- No blocking (Q84 option B), no list changes, no skill changes: out of scope by the brief.
|
||||
|
||||
## Gate
|
||||
|
||||
Recorded with the candidate in the review request: test-unslop-check, the harness, plugins,
|
||||
seat and cli suites, and every `scripts/test-*.sh`. At landing Sage runs one managed session per
|
||||
harness and attaches the notice, the correction and the counts.
|
||||
|
||||
## Round 4
|
||||
|
||||
Round 3 (2369c00e3 on sage/row66-r3, base c40d846cb, manifest 42e3876ca168) had approvals from
|
||||
Filbert (29770) and Dewey (29771). Since then rows 200, 199, 232, 233, 240 and 238 changed three
|
||||
of the 23 paths: `docs/TOOLS.md`, `scripts/stack-copy.sh` and
|
||||
`packages/cli/tests/stack-copy.test.mjs`. Round 4 is the two round 3 commits cherry-picked onto
|
||||
4ced5e63d (sage/row66-r4). Neither pick had a conflict, and the tree equals a hand merge of each
|
||||
path with `git merge-file`. No code changed: `git diff BASE TIP | git patch-id --stable` is
|
||||
6d085621fd35 for both rounds.
|
||||
|
||||
- Row 232 added `copy --bundle` (`copy_bundle`). It builds the bundle with `copy_tree`, which
|
||||
copies `COPY_PATHS`, so a bundle copy also carries `tools/unslop-hook`. No extra change needed.
|
||||
- The Part B hold under Deviations is void. Part B was superseded by the Q175 SSO work and will
|
||||
not run, so nothing holds `scripts/stack-copy.sh`.
|
||||
- Review scope: the merge on the three moved paths and this section. The other 19 paths have the
|
||||
same blobs as round 3.
|
||||
|
||||
Rebased again on fefd54e13, after row 212 landed (ee7b2f137), as branch `sage/row66-r4b`, before the round 4
|
||||
request went out. 212 added `packages/library/src` to `COPY_PATHS` and a library line to the
|
||||
`stack-copy.test.mjs` file list. None of the four picks had a conflict. Every file's patch-id equals the 4ced5e63d
|
||||
build's except `scripts/stack-copy.sh`, where the only change is the hunk's context line
|
||||
(`packages/queue/src packages/library/src`). Row 66's two added lines are the same.
|
||||
|
||||
Rebased again on 29ce1e360, after rows 195, 213 and 231 landed, as branch `sage/row66-r4c` (r4b stays at
|
||||
49ad61963). Two of row 66's paths moved: `adapters/README.md` and `docs/TOOLS.md`. TOOLS.md merged without a
|
||||
conflict. In adapters/README.md, row 213 rewrote the skill-cap paragraph, because `claude` now gets the prompt
|
||||
as a file. The merge keeps 213's paragraph whole and adds row 66's "The unslop check (row 66)" section after
|
||||
it. Row 66's old cap sentence is dropped, since it described the argument limit that 213 removed. Every other
|
||||
path has the same blob as on r4b. Row 213 also changed the harness and both adapter scripts, so all of row 66's
|
||||
harness tests run whole again on this base before the request.
|
||||
|
||||
Rebased again on 7b9737953, after rows 245, 248 and 249 landed, as branch `sage/row66-r4d` (r4c stays at
|
||||
670b83f65). Only `docs/TOOLS.md` moved under row 66: row 245 rewrote the paragraph on what root reads in the
|
||||
host check. The cherry-pick had no conflict. `git patch-id --stable` of row 66's whole diff is 508bb684eade on
|
||||
both bases, and so is each file's own patch-id, TOOLS.md included. So row 66's hunks are byte-identical and only
|
||||
their context moved. The one test that names TOOLS.md, `packages/cli/tests/stack-release.test.mjs`, uses it in a
|
||||
message string and is in the singles list.
|
||||
|
||||
Rebased on a36523713 after row 197 landed (mos-1186 item 4), as branch `sage/row66-r5` (r4d stays at
|
||||
82c830779). Row 197 also touched `packages/harness/tests/claude-session.test.mjs` and `pi-session.test.mjs`.
|
||||
The cherry-pick had no conflict. The range-diff shows commit 1 differing only in one hunk header of
|
||||
pi-session.test.mjs, where git now names the context line. Commits 2-7 are `=`. `git patch-id --stable` is
|
||||
0049d05fb585 for the whole diff and d67275ac4251 without `agents/` on both bases. Correction: the r4d note
|
||||
above gives 508bb684eade for the whole diff. That number came from e25f76f54 before the 7b9737953 rebase. The
|
||||
whole-diff number on r4d is 0049d05fb585. The harness suite runs whole again on this base before landing.
|
||||
|
||||
Correction (Filbert round 4 N2, comment 30086): the r4c paragraph says "Row 66's old cap sentence is
|
||||
dropped." That's wrong. In round 3's diff the 64 KiB cap sentence is unchanged context, so row 66 never
|
||||
wrote it. Row 213 replaced it, and none of row 66's lines were dropped. The landing sessions are in
|
||||
LANDING-SESSION.md.
|
||||
@@ -0,0 +1,43 @@
|
||||
# Row 66 landing sessions (mos-1186 items 2-3)
|
||||
|
||||
Sage, 2026-10-21. Both ran on a scratch data root built from the candidate tree, branch `sage/row66-r5`
|
||||
at 273fff6f9 on a36523713, as row 64's D2 did (rc13bcd555652). The scripts were
|
||||
`/mnt/storage/scratch/sage-r66r5x/d2s/d2-build.mjs` and `d2-drive.mjs`. They used the business example
|
||||
with stand-in token files, tracker and Gitea URLs pointing at 127.0.0.1:9, and a scratch project repo.
|
||||
Nothing live was touched. The six skills were installed and enabled on each data root with
|
||||
`scripts/skill.sh` from the candidate tree.
|
||||
|
||||
Before the sessions, the harness suite ran whole on 273fff6f9: 149 pass, 0 fail, 12 s
|
||||
(2026-10-21T18:47:42Z).
|
||||
|
||||
## Claude Code, run r4ab24630d323 (18:48Z)
|
||||
|
||||
The chief and cto were bound, and the coder was launched through `launcher.fromSession` on claude-code,
|
||||
model claude-sonnet-5-5. The launch bundle names `tools/unslop-hook/claude-hook.js`, `unslop-check.js`
|
||||
and `lists.json`.
|
||||
|
||||
- Turn 1. cto asked for one sentence with four banned words. The RESULT body `mosaic talk` would print
|
||||
ends with the operator note:
|
||||
`[unslop: 1 reply of this session flagged since the last note: banned word "additionally" x1; banned word "crucial" x1; banned word "testament" x1; banned word "vibrant" x1. The session gets a correction notice on its next turn.]`
|
||||
- Turn 2. `unslop.jsonl` logs `notice_injected` for that turn. The coder's transcript has the notice as
|
||||
UserPromptSubmit hook additional context in the API request:
|
||||
`UNSLOP NOTICE (mechanical style check, not the user speaking): your previous reply contained violations of the fleet writing standard (SYSTEM.md / ms-unslop): ...`.
|
||||
cto asked the coder to quote it. The coder answered "I can't answer that one, and I won't quote
|
||||
anything from it." So the notice reached the model, which chose not to repeat it. Its reply checked
|
||||
clean.
|
||||
- Counts from `unslopCounts`: checked 2, flagged 1, patterns `ms-unslop:7` 4, notices 1, broken null.
|
||||
|
||||
This scratch instance has no `mosaic talk` view of its own, so the note above is the RESULT body the bus
|
||||
returned to cto. That is the text `mosaic talk` and `mosaic follow` print.
|
||||
|
||||
## pi, run r1dd94171bede (launch only)
|
||||
|
||||
The coder launched on pi, model claude-sonnet-5-5. The launch bundle names
|
||||
`tools/unslop-hook/extension.ts`, `unslop-check.js` and `lists.json`. No turn ran. This host has no
|
||||
credential pi reads until P19 #383 settles, and mos-0865 D2 rules out mapping the Claude Code token into
|
||||
a pi variable. No `unslop.jsonl` was written. Counts: checked 0, flagged 0, notices 0.
|
||||
|
||||
## Still open
|
||||
|
||||
Vikunja #454 tracks both live checks. Claude Code runs in the first re-pin whose tree includes row 66,
|
||||
backup first. Pi runs one full session with a tell after #383. See `docs/plans/DEFERRED.md`.
|
||||
@@ -1419,4 +1419,20 @@ are never rewritten or removed; corrections are new entries.
|
||||
2026-10-21T06:47:54Z | researcher | row 228 (#1729) round 3 in review (rev 2702; start rev 2700) | rebase of r2 onto the 234 landing c771a36f4 as researcher/row228-r3 cf18c42b9 (one commit, pushed) with Webby's round 2 N1 (:711 and :718); manifest 82cf98c6 (3 files); slot sage-1796: session.test 13 + host.test 42 = 55/0, manifest OK before and after, busy228.sh copy named in the clear; r2 94/0 and M1 killed stand (seat blobs unchanged); request attempt left in requesting state (lock held by sage-238-review-2b when the outcome rev was written, exit 3; transport said failed pre-send, no token), Sage resolves and posts as jarvis; packet agents/researcher/work/queue-228/r3
|
||||
2026-10-21T07:29:23Z | researcher | row 228 (#1729) landed as 86249ac55 (pushed 07:25Z by Sage) | patch-id b6ffe31feb0d matches my r3 candidate cf18c42b9 (checked here against origin/refactor); Sage combined gate with 238: seat 165/0, cli 640/0, scripts 585/0; queue note rev 2725, done rev 2727, #1729 closed comment 29966 (sage-1824); q228r2 worktree removed, branches researcher/row228, -r2 and -r3 stay on origin and locally; packets agents/researcher/work/queue-228 r1 r2 r3 uncommitted
|
||||
2026-10-21T15:19:14Z | Sage (Opus 5.5, 1ef1e4f8) | MVP push 10-21 afternoon: rows 249, 197 proof 3/4, 222 singles, 66 r4d, queue-commit | 249 landed 9de5a57ab (+7b9737953 DEFERRED N1, #1751 closed, Vikunja 445 c442); 197 proof 3 rc=1 on a driver defect, Herb's fix a5b636750 to Webby, proof 4 set up in sage-r197p4; 222 singles 34/34 and 5 mutants killed (sage-2028); 66 round 4 in review (82c830779, c30083/30084); queue revs 2642-2904 committed 0636721e6
|
||||
2026-10-21T15:20:10Z | Dewey (Opus 5.5, 84fb346c) | row 66 r4 review (sage-2036, sage/row66-r4d 82c830779, manifest 6cfd812da4ca) | APPROVE 30085, rev 2905; rebase only, code lines identical to r3 (-U0 patch-id b3e9e076e5f1), four shared files clean; no tests run; dewey-0768 Sage
|
||||
2026-10-21T15:20:58Z | Filbert (Opus 5.5, 048f3c63) | row 66 r4 review (sage-2037, sage/row66-r4d 82c830779, manifest 6cfd812da4ca) | APPROVE 30086, rev 2906; static, no tests; rebase only, row 66 +/- lines identical to r3 next to rows 212/213/232/245; N1 code-only patch-id d67275ac4251 (508bb684eade includes BUILD.md), N2 BUILD.md cap-sentence wording; packet-only notes
|
||||
2026-10-21T18:55:21Z | Filbert (Opus 5.5, 048f3c63) | row 215 r2 merge-scoped review (herb-0093, mos-1160, herb/row215-on197 dde3445ab, manifest 40d9722a) | APPROVE 30103, rev 2924; static, no tests; patch-id d191e7e9586c same as r1, 28/30 blobs+modes = e333af4dc, broker.mjs and stack-release.test.mjs = clean merge-file onto a36523713; r1 N1-N4 carry, suite gate Sage's
|
||||
2026-10-21T19:06:16Z | Sage (Opus 5.5, 1ef1e4f8) | row 66 landing, #435/J2 brief, 196 r2/215/243/250/251 gate coordination (mos-1186, mos-1193, mos-1195, mos-1197) | row 66 LANDED 2c38325ec + DEFERRED 3b0aef995, #1559 closed; 640aa03f2 brief pushed; REQ-WEB-2 wording to Mos (sage-2067); 196 r2 stop 2 ruled (sage-2072); 215 gate on slot (Herb); #1754 for 243; 250 Gizmoduck/Filbert, 251 Darkwing/Dewey
|
||||
2026-10-21T19:20:16Z | Darkwing (Opus 5.5, 7525c8e4) | row 251 T27 ssh-add lifetime (sage-2075, sage-2084, Vikunja #453, Gitea #1756) | darkwing/row251 68f2dfd4b pushed (e5e4b2e5a step 1, c19b4167e -t 2 + 3.5 s sleep, host-run.mjs unchanged); in-review r1 rev 2944, request 30121 resolved rev 2947, manifest c7497de3; Dewey woken darkwing-0111; slot asked darkwing-0110, nothing run
|
||||
2026-10-21T19:23:11Z | Dewey (Opus 5.5, 84fb346c) | row 251 r1 static review (darkwing-0111), 68f2dfd4b, digest c7497de3 | no blocking findings; OpenSSH 10.5p1 citations checked at V_10_5_P1; comment 30126 on #1756; verdict to be recorded on r2 with part A results; no tests run
|
||||
2026-10-21T19:23:48Z | Filbert (Opus 5.5, 048f3c63) | row 250 r1 static review (gizmoduck-0146, sage-2091, gizmoduck/row250 e9cfd92f8, manifest 14ff20b6) | CHANGES 30125, rev 2950; static, no tests; C1 R13 never calls h.ctrl.close() so the controller server (controller.mjs:548) stays open and cohort.test.mjs is expected not to exit; fix await h.ctrl.close() before h.c.close(); cause trace, step 1, no loosening, R13 coverage, no pins, no drift all hold
|
||||
2026-10-21T19:28:22Z | Filbert (Opus 5.5, 048f3c63) | row 250 r2 static review (gizmoduck-0148, gizmoduck/row250-r2 c1a858975, manifest eca0b8e2) | APPROVE 30130, rev 2957; static, no tests; C1 fixed: R13 closes its controller after the checks (cached release, one entry) and again in finally (no-op); no drift, no findings; gate run Sage's
|
||||
2026-10-21T19:31:02Z | Herb (gpt-6.1-sol, f6cf4287) | row 215 C2-04 landed as e54e05463 (#1716 closed c30133, queue done rev 2955) | Filbert round 2 APPROVE c30103/rev 2924; candidate dde3445ab on a36523713 preserves rows 249 and 197. Granted sage-2071: business 209/0, seat 166/0, cli 729/0, project 41/0, bus 604/0, webui 300/0 with one environment editor-build skip; all ten scripts/test-*.sh 585/0; total 2634/0 in 926.796 s, ended 19:20:47Z, leftover process sweep 0, temp root and owned network removed. Sage accepted receipts and landed after 6096b051b (sage-2097); no further 215 work.
|
||||
2026-10-21T19:34:18Z | Sage (Opus 5.5, 1ef1e4f8) | row 215 landing, 196 r3 grant withdrawn for the base change and r4 granted, 250/222/244/251 slot order | 215 LANDED e54e05463 (patch-id 2f68188b6c9d = a36523713..dde3445ab, tree = merge-tree; herb-0095 2634/0, webui esbuild skip ruled env); #1716 closed c30133, done rev 2955, Vikunja 416 c471. sage-2092 withdrawn (r3 conflicted with 215), sage-2096 to Gander r4 f8a59e6aa, mutant kills kept by blob sha. 250 r2 request c30131 (rev 2958), Filbert APPROVE 2957. 244 issue #1757 (rev 2959). 222 r2 c9aa9c2ee accepted; gate scope per the row. Order: Gander, Gizmoduck, Megavolt, Morgana, Darkwing.
|
||||
2026-10-21T19:46:12Z | Dewey (Opus 5.5, 84fb346c) | row 222 r1 static review (megavolt-0095), c9aa9c2ee, manifest c2121b55 | APPROVE, comment 30138 on #1723, queue rev 2966; rulings: createObject=rename accepted, 5 s human timeout deferred with STATUS codes in the follow-up, credential.helper reset argv-only accepted; notes N1-N5; no tests run
|
||||
2026-10-21T19:49:37Z | Sage (Opus 5.5, 1ef1e4f8) | row 250 landing, row 196 r5 grant (mos-1198) and resume (mos-1200), F27 row 253 | 250 LANDED 1b6158ce2 (patch-id 29786caa, Filbert rev 2957, Gizmoduck slot green), #1755 closed c30139, Vikunja 450; 196 r5 91e3696ef hunk checked by Duckworth, webui 304/0; my queue add tripped Gander's busy check, not a stop (mos-1200), resume on 05e940117; row 253 #1758 brief 0cdead66c
|
||||
2026-10-21T20:46:03Z | Sage (Opus 5.5, 1ef1e4f8) | row 222 landing, PRD 1.9 and 1.10, Pocket ID design row 255, row 254 brief, 196 r6 grants | 222 LANDED 0b33f5e9d (megavolt-0098 gate, Dewey rev 2966, patch-id edb60b4f), #1723 closed c30147, done rev 2972; follow-up row 254 (#1759, after 196); PRD 1.9 f48725cfc (REQ-WEB-2, REQ-DEC-3 amended, mos-1202); 458 brief 7d08237e1 (#1760), row 255 rev 2976; PRD 1.10 add0f1aae REQ-INST-2 post-v1 (mos-1204, tasks 97/0, bus req 3/0); Vikunja 458 c478, 416 c479; queue-commit 21def2850 revs 2968-2976; 196 r6 gate gander-0066 2334/0, 38/38 killed; 244 granted sage-2147; 196 r6 resume granted sage-2145 after self-tee busy refusal (mos-1205). Miss: landed 222 before checking 196's manifest; 196 carried results voided. Class rule now (mos-1204, replaces the mos-1200 interface grep): before any landing push, compare every in-review and in-progress row's manifest against the landing's paths.
|
||||
2026-10-21T21:12:18Z | Della (GPT-6.1-Sol, mos-1213) | Vikunja 460 independent post-v1 email plan, della/email-plan from c3d88840c | 341-line proposal, 13 post-v1 rows, six Jason questions, 42 pinned citation anchors verified. Canonical queue next della: nothing. Planning only, no live mail/service/MVP/queue change; phase B/C with Mos, no Ludwig plan read. Commit and branch push authorized by dispatch.
|
||||
2026-10-21T21:37:07Z | Della (GPT-6.1-Sol, mos-1220) | Vikunja 460 phase B email cross-review, della/email-plan | Ludwig plan 4a27b73ac and review 143415779 read in full. Cross-review has ten findings and eleven merged questions; original Della plan unchanged. Canonical queue next della: nothing. Static verification only; review push followed by direct della-0002 handoff to both threads under Q210. Phase C base choice remains with Mos.
|
||||
2026-10-21T21:43:02Z | Della (GPT-6.1-Sol, mos-1223) | Vikunja 460 phase C merged email plan, della/email-plan | Mos-selected base plus Ludwig grafts; original plans/reviews unchanged. Sixteen post-v1 rows, eight READY and eight WAIT/optional; eleven Jason questions. Canonical queue next della: nothing. Docs-only checks. Commit/push then immediate della-0003 handoff to Ludwig/Mos; Sage landing/queueing follows approval.
|
||||
2026-10-21T21:45:20Z | Della (GPT-6.1-Sol, mos-1223 / ludwig-0004) | merged email plan focused review fixes | External content-key/expiry location and restore tests specified; fake registry work READY, production registry gated on PRD approval/Q4. Merged plan 399 lines, original plans/reviews unchanged. Commit/push and focused Ludwig review before Sage handoff.
|
||||
|
||||
+47
-29
@@ -418,6 +418,7 @@ One read-only tree supplies the bus, Console and human CLI (row 85,
|
||||
`copy` requires a canonical checkout (.git directory); --allow-worktree
|
||||
is a test override. COMMIT must be reachable from both local refactor and
|
||||
origin/refactor. It archives the runtime/import closure, adapters, roles,
|
||||
`tools/unslop-hook` (the unslop check both harness modules mount, row 66),
|
||||
RELEASE, package.json and package-lock.json; refuses missing manifests;
|
||||
runs npm ci inside the temporary copy; removes write permissions; and
|
||||
renames beside the target. A published existing copy stays unchanged.
|
||||
@@ -464,7 +465,7 @@ reports checkout or copy identity and refactor drift, and writes nothing.
|
||||
|
||||
```
|
||||
scripts/stack-release.sh adopt BUSINESS
|
||||
scripts/stack-release.sh activate ID BUSINESS [--pm | --pm-after-harness] [--migrate] [--tester-port N]
|
||||
scripts/stack-release.sh activate ID BUSINESS [--pm | --pm-after-harness] [--migrate] [--tester-socket | --tester-port N (legacy copies)]
|
||||
[--proof-header NAME --proof-file PATH | --no-proof | --sso] [--no-send] [--timeout S] [--plan]
|
||||
scripts/stack-release.sh pm-on BUSINESS [--timeout S]
|
||||
scripts/stack-release.sh rollback BUSINESS [--restore ACTIVATION [--events N]] [--timeout S] [--plan]
|
||||
@@ -561,7 +562,8 @@ refuses `capture-failed` before it stops anything. Adopt uses the same rule.
|
||||
The Console's row 178 proof pair gets into the pointer only through `activate`
|
||||
(row 187). `--proof-header NAME --proof-file PATH` puts the pair in the
|
||||
pointer's Console flags and the unit after the preview flags and before `--send`
|
||||
and `--tester-port`, where `webui-service.sh` renders it, replacing any pair
|
||||
and the tester flag (`--tester-socket`, or `--tester-port` for legacy copies),
|
||||
where `webui-service.sh` renders it, replacing any pair
|
||||
already there. `--no-proof` drops it. Either may name the live copy, which a
|
||||
plain activate refuses with `already-active`, so the proof goes on or off
|
||||
without changing copies; `--no-proof` with no pair in the pointer still refuses
|
||||
@@ -691,6 +693,12 @@ backup's checks it prints `BACKUP_STORE <activation id> schema <version>`.
|
||||
it never picks another port. `--timeout` (default 60 seconds) bounds the
|
||||
gate and each stop.
|
||||
|
||||
A copy marked for the private tester receives `--tester-socket` during rehearsal;
|
||||
a legacy copy receives no tester flag. The socket is under the rehearsal's
|
||||
scratch dataRoot, at `data/console/tester.sock`. That path is longer than the live
|
||||
one. A long dataRoot can pass activation's pathname preflight and still make the
|
||||
rehearsal Console refuse its socket path; the rehearsal then fails closed.
|
||||
|
||||
Before it makes anything, it checks the pointer, the copy (present,
|
||||
reachable from refactor, a readable schema, a bus host with `--no-launch`),
|
||||
the port and the backup's `SHA256SUMS`. Then it makes
|
||||
@@ -1263,36 +1271,46 @@ not claim an assistant answer; an uncertain receipt is never retried. Read the
|
||||
current list/history before trying again. Activation still needs Mos's separate
|
||||
window; changing these files does not authorize a live Console action.
|
||||
|
||||
### Console tester listener (`serve --tester-port N`, row 176)
|
||||
### Console tester listener (`serve --tester-socket`, row 196)
|
||||
|
||||
`node packages/webui/src/cli.mjs serve --tester-port N` adds a second listener
|
||||
bound only to `127.0.0.1:N`. N must be an integer in 1024..65535, different
|
||||
from `--port` and never 7332 (the tunnel's forwarded port). It requires the
|
||||
bus configuration. It calls only the tester shim; the main listener keeps its
|
||||
existing human transport and rejects every `x-mosaic-tester` request.
|
||||
The tester listener rejects the main preview auth header and only accepts its
|
||||
own loopback Host/port. Its Settings banner identifies the tester. Its instance,
|
||||
route and name editors use the tester's three writes; settings, document saves,
|
||||
assistant stop, role messages and chat writes stay refused. Writes require the
|
||||
exact `http://127.0.0.1:N` Origin, same-origin Fetch Metadata, JSON and the existing
|
||||
bounded strict bodies. `tester-off` and `tester-required` answer HTTP 403.
|
||||
`node packages/webui/src/cli.mjs serve --tester-socket` adds private HTTP at
|
||||
`<dataRoot>/console/tester.sock` (0600) under console/ (0700). The path must fit
|
||||
107 bytes. Unsafe ownership, modes, symlinks and pre-existing entries refuse.
|
||||
The main Console remains on its configured TCP port. New copies refuse --tester-port.
|
||||
|
||||
`scripts/webui-service.sh render|install --tester-port N` carries the flag into
|
||||
ExecStart, and status names its URL. Bad tester ports exit 4. Install remains a
|
||||
unit write for the authorized operator, with no start/restart verb.
|
||||
The tester's fixed Host is mosaic-tester.invalid and its Origin is
|
||||
http://mosaic-tester.invalid. No DNS is used. POST also needs same-origin Fetch
|
||||
Metadata and bounded JSON. The endpoint uses only TESTER_CLI. It admits the
|
||||
existing instance, route, name and tester-chat writes, never owner settings,
|
||||
document saves, assistant stop or role messages. bus.tester stays Jason's switch.
|
||||
Authorization, login/session cookies and configured proxy headers refuse.
|
||||
|
||||
`stack-release.sh activate ID BUSINESS --tester-port N` replaces or adds this
|
||||
Console flag in both the installed unit and the pointer. It checks the target
|
||||
copy's own Console before stopping anything; an explicit unsupported request
|
||||
refuses `tester-port-target`. A port outside 1024 to 65535, 7332 or the
|
||||
Console's `--port` is a usage error (exit 4). Under `--plan` both are listed
|
||||
with the plan's other refusals instead, the bad port as `tester-port-invalid`,
|
||||
and the plan exits 3. Without an explicit flag, activate and rollback
|
||||
keep it between supporting copies, or drop it when the target predates support.
|
||||
The plan prints the final Console flags and any dropped `--tester-port N`;
|
||||
the steps log records a drop too. `pm-on` keeps the pointer's Console flags.
|
||||
These operations retain their existing Mos/Jason window authority. Nothing in
|
||||
this row forwards the tester port through the tunnel or changes live units.
|
||||
```sh
|
||||
node packages/cli/src/tester-http.mjs GET /api/bus/agents
|
||||
printf '%s' '{"name":"fixture"}' | node packages/cli/src/tester-http.mjs POST /api/chat/projects
|
||||
```
|
||||
|
||||
The helper loads the selected instance config and reports HTTP status/text/body
|
||||
as JSON, exiting 2 for refusal. It never retries writes. Direct browser access
|
||||
is removed with Mos's acceptance (mos-1015). A future authenticated browser relay
|
||||
behind SSO is a separate row. No TCP compatibility bridge is provided.
|
||||
|
||||
`webui-service.sh render|install --tester-socket` checks target support and carries
|
||||
the flag into ExecStart. `stack-release.sh activate ID BUSINESS --tester-socket`
|
||||
explicitly replaces an inherited --tester-port pair in both unit and pointer.
|
||||
Without explicit conversion a new target refuses tester-transport-migration before
|
||||
stopping anything. Unsupported targets refuse tester-socket-target. Rollback drops
|
||||
unsupported socket enablement, visibly in plan/steps, without enabling TCP. Legacy
|
||||
flags remain supported by the release tool for legacy target copies only. Failed
|
||||
activation recovery can restore the previous TCP unit and its old limits.
|
||||
|
||||
Activation of a new copy preflights the pinned root-owned system Python ELF,
|
||||
records its resolved path/version/identity/hash and checks the bus's fresh startup
|
||||
receipt. Restarts revalidate and append actual interpreter identity to
|
||||
`<dataRoot>/bus/peercred-starts.jsonl`, without comparing an old activation hash.
|
||||
After an OS interpreter update, the next authorized re-pin uses a different reviewed
|
||||
copy and refreshes activation evidence. Do not bypass already-active or use a PATH shim.
|
||||
All live operations keep their existing window authority.
|
||||
|
||||
Console proxy proof (row 178, #1676): `serve`, `webui-service.sh render` and
|
||||
`install` accept `--proof-header NAME --proof-file PATH` together, under preview
|
||||
|
||||
@@ -61,7 +61,8 @@ it out, and the mirror's refs belong to the bus. If `HEAD` names no commit, stop
|
||||
5. When Jason has a draft mapping, run it again with `--mapping`. The file holds the library entry
|
||||
alone, `{"kind": "library", "remote": ..., "branch": ..., ...}`, without the business file or the
|
||||
`"projects"` wrapper around it. `remote` and `branch` are required even though the survey doesn't
|
||||
fetch. `mosaic` must be able to read the file. Set `vaultPrefix` to her books repo's folder name
|
||||
fetch. `user` is optional here: it is the bot account name from design step 3, required for sync.
|
||||
`mosaic` must be able to read the file. Set `vaultPrefix` to her books repo's folder name
|
||||
in her vault. Without it, a link with the full path from the top of her vault resolves to nothing,
|
||||
and the setup sheet tells her to write links that way.
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
# Brief: bundled Pocket ID for users with no OIDC provider (Q203, Vikunja #458), design
|
||||
|
||||
Sage, 2026-10-21, for Mos's order mos-1202 item 2. Vikunja #458, parent #412 (SSO). Owner Launchpad,
|
||||
reviewer Webby, gate owner Sage. After row 252. This row is a design. The deliverable is
|
||||
`agents/launchpad/work/queue-ROW/DESIGN.md`. Build rows come from it after the design is approved.
|
||||
|
||||
## What Jason asked for
|
||||
|
||||
DECISIONS Q203, relayed by Mos in mos-1202, verbatim: "Let's use O6. If a user does not have an OIDC
|
||||
provider to configure, we will need to use a bundled Pocket ID instances to handle this traffic."
|
||||
|
||||
O6, as Mos put it to Jason: "keep the REQ-WEB-2 wording OIDC-only. Identity is the (issuer, subject) pair
|
||||
from the Console's own verified OIDC sign-in. Local accounts come from a provider, and the Console never
|
||||
holds passwords." PRD 1.9 (f48725cfc) has REQ-WEB-2 on those terms.
|
||||
|
||||
Mos's reading of the second sentence, labelled as his, following lead decision 44 items 5 and 6
|
||||
(`docs/plans/2026-09-26_lead-decisions.md:655-663`):
|
||||
- The installer offers two choices: point the Console at one or more existing OIDC providers, or deploy a
|
||||
bundled Pocket ID.
|
||||
- The stack installs that Pocket ID and writes it as the Console's one providers entry. No Pocket ID source
|
||||
goes in the repository, and the Console gets no sign-in path apart from the Q175 relying party.
|
||||
- Pocket ID is passkey-only. Agents keep per-role service tokens.
|
||||
- dragon-lin keeps Authentik. This is outside the 10-27 MVP.
|
||||
|
||||
The PRD requirement for Q203 is drafted separately and goes to Mos first. Until it lands, cite Q203 and
|
||||
this brief. The PRD's v1 scope list still has "Pocket ID and SSO" out of v1, and its technical notes say
|
||||
"Pocket ID is wired in after v1". This row doesn't change either.
|
||||
|
||||
## Where things stand
|
||||
|
||||
- Row 192 (landed 4429a104f) is the Console's OIDC relying party, `--sso`, with the Q175 start checks.
|
||||
Row 200 adds `stack-release.sh activate --sso`, and row 238 its `--instance` hint.
|
||||
- REQ-INST-1 sets what an optional install component is: pinned, health-checked, removable, and switched
|
||||
on in the organization file or system config. SearXNG is the first one.
|
||||
- Researcher's note `agents/researcher/work/2026-10-04_vikunja-pocketid.md` covers Pocket ID v2.17.0
|
||||
(BSD-2, passkey-only, client credentials). Check the version against what is current before pinning.
|
||||
|
||||
## What the design must settle
|
||||
|
||||
1. The choice. Where the installer asks, how "existing providers" and "bundled Pocket ID" are recorded,
|
||||
and what each writes into `console.sso`. With the bundled choice, Pocket ID is the only providers
|
||||
entry.
|
||||
2. The component, against REQ-INST-1: the pinned release and how its digest is checked, how it runs
|
||||
(unit, user, data directory under the instance's data root), its health check, and removal. No Pocket ID
|
||||
source in the repository.
|
||||
3. The Q175 start checks against the bundled instance. The Console must start against it with no
|
||||
relaxation: discovery, PKCE S256, asymmetric signing algorithms only, issuer match, registered redirect
|
||||
and post-logout URIs. Name any Pocket ID default that would fail a check, and the setting that fixes it.
|
||||
4. The client. Who creates the Console's OIDC client in Pocket ID, and how its secret reaches the slot
|
||||
file. No agent reads or prints the value. Secrets never enter the repository or an image.
|
||||
5. The first person. Pocket ID is passkey-only, so say how the installing user enrolls a passkey, and how
|
||||
their subject gets into `console.sso`. On Jason's instances only his subject goes there (mos-1197).
|
||||
6. Reach. WebAuthn needs a secure origin and a fixed relying-party id. State what the bundled instance
|
||||
needs (host name, TLS, proxy) and keep loopback-only the default. Anything that changes who can reach the
|
||||
Console or Pocket ID from outside is Jason's, so the design names those steps as his.
|
||||
7. Agents. Per-role service tokens are unchanged. Pocket ID issues nothing an agent uses.
|
||||
8. Instances. Each named instance gets its own Pocket ID or shares one. Say which and why, given one
|
||||
system config per instance.
|
||||
9. Tests on stand-ins only: a fake provider shaped like Pocket ID (discovery, JWKS, token endpoint), as row
|
||||
192's tests do. No test downloads or starts a real Pocket ID.
|
||||
10. The build rows, each with its own gate, in landing order.
|
||||
|
||||
## Boundaries
|
||||
|
||||
- Design only. No code, no install anywhere, no download of Pocket ID onto any host.
|
||||
- dragon-lin keeps Authentik. No change to .53 or .54 (mos-1167).
|
||||
- No external accounts, no DNS or certificate requests, no Traefik change. Those are Jason's.
|
||||
|
||||
## Gate
|
||||
|
||||
Webby approves DESIGN.md. Sage checks it against Q203, O6, REQ-WEB-2 and REQ-INST-1, and sends any choice
|
||||
that would change what an existing requirement allows or forbids to Mos before the build rows are added.
|
||||
@@ -0,0 +1,57 @@
|
||||
# Brief: Console inbox Approve and Deny for grant requests (Vikunja #435, J2)
|
||||
|
||||
Sage, 2026-10-21, for Mos's order mos-1193 (Jason asked at 18:35Z to test J2 sooner). Vikunja #435, parent
|
||||
#424, DECISIONS Q188. Owner Gander, reviewer Webby, gate owner Sage. Chained on row 196's candidate (Q177):
|
||||
the design starts now on Gander's row 196 build. The code lands after row 196 lands and rebases onto that
|
||||
landing. Design first. The first deliverable is `agents/gander/work/queue-ROW/DESIGN.md`.
|
||||
|
||||
## What Jason asked for
|
||||
|
||||
Q188, as #435 records it: the chief surfaces each grant request to Jason's inbox in the WebUI, and he clicks
|
||||
Approve or Deny. It needs the Console to know who is signed in (Q175 SSO, #412). Until then Approve is
|
||||
`mosaic decide`.
|
||||
|
||||
## Where things stand
|
||||
|
||||
- The Console inbox shows decisions and prints `mosaic decide <id> <key>` for each choice
|
||||
(`packages/webui/README.md`, Inbox section). It takes no human writes: without `--send` every method
|
||||
other than GET and HEAD answers 403 `read-only`, and the live unit runs without it (row 189).
|
||||
- Q175 phase 1 (row 192, landed 4429a104f) builds the Console's own OIDC session. It is live only after the
|
||||
phase 2 re-pin window turns on `--sso`. Under `--sso` every request other than `GET /healthz` needs a
|
||||
verified session.
|
||||
- Row 196 (Gander, Duckworth) settles how the bus tells the human's own call from a same-uid process. A
|
||||
Console write that resolves a decision must go through whatever row 196 lands, not around it.
|
||||
- The PRD doesn't allow this yet. REQ-DEC-3 says a human resolution comes only from a `mosaic` CLI session
|
||||
started outside any agent run. Jason approved REQ-WEB-2 and the REQ-DEC-3 amendment in decision
|
||||
00ed58e2 (Vikunja 19/266), and the PRD holds the id REQ-WEB-2 for it (1.8, "held for the Console decide
|
||||
buttons amendment"). That amendment must land before this row's code does. PRD wording goes to Mos first,
|
||||
then Jason. This row doesn't edit the PRD.
|
||||
|
||||
## What the design must settle
|
||||
|
||||
1. Which decisions get the buttons. #435 names grant requests (Q188). Say whether the first cut covers only
|
||||
those or every open decision under REQ-WEB-2, and why.
|
||||
2. The identity. The resolving human is the verified OIDC subject from the Console session (row 192), mapped to
|
||||
an authorized human the bus knows. Nothing comes from a proxy header or a shared secret (Q175). A request
|
||||
from an agent session or a seat credential is refused.
|
||||
3. The write path. How the Console's POST reaches the bus's decide, using row 196's human boundary, and what
|
||||
the decision event records: `via=console` and the subject.
|
||||
4. The guards: CSRF, a confirmation step, a decision that is no longer open, a stale option key, a double
|
||||
click, and the read-only and `--no-send` modes. State each refusal's status code and message.
|
||||
5. Without `--sso` the buttons don't exist or are disabled. Say which, and what the inbox shows instead
|
||||
(today's `mosaic decide` line).
|
||||
6. Tests on stand-ins only: a fake OIDC provider and the test bus, as row 192's tests do.
|
||||
|
||||
## Boundaries
|
||||
|
||||
- No change to who can reach the Console from outside. That stays Jason's.
|
||||
- No test touches `~/.mosaic-dev`, `~/.config/mosaic-dev`, the live units or a slot file. No request to the
|
||||
live 127.0.0.1:7332 or 7333, mosaic.woltje.com or auth.diversecanvas.com.
|
||||
- Turning the buttons on live needs the phase 2 window (`--sso`) and then a re-pin whose tree has this row.
|
||||
Both are windows with Jason. This row ships the code and the tests.
|
||||
|
||||
## Gate
|
||||
|
||||
Webby approves DESIGN.md, then the manifest. The webui, bus and cli suites and every `scripts/test-*.sh` are
|
||||
green on Sage's gate, and the mutants named in DESIGN.md are killed. The PRD amendment for REQ-WEB-2 has
|
||||
landed first.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user