145 KiB
Row 285 r3 build evidence — Magica
Issue #1790, C2-08b; assignment sage-4039, mos-1542, mos-1576.
Thread 483bbea5-e548-4c97-9b85-8f29ba81e427. Base b19ffa04f.
Binding rulings: agents/scrooge/work/queue-285/BUILD.md, retained byte-identical to 53db6b7ca.
N1 (creative-only library.write refusal) stays a follow-up; no scope expansion.
State and acceptance
Seven requested commits replayed onto the assigned base. No test or npm command has run. Sage CLEAR is required before installation, tests or mutants; rows 296 and 217 have priority. Replay commits and this evidence commit are explicitly authorized before tests by sage-4039. Queue next was first attempted here and refused because this is a linked worktree; retried only from canonical, returned row 285 with a view-unknown warning. Authorized canonical queue move then succeeded: magica-285-start rev 3889, briefed→in-progress. No manual queue edit.
Overlap resolutions
Git auto-merged every overlap; there were no conflict markers or manual code resolutions. Each was inspected against the base and source patch:
- packages/business/README.md: retain Q247 optional-tracker paragraph from base, apply only chief credential examples/prose from Scrooge.
- packages/business/src/vocabulary.mjs: retain row 298 grant-scope exports/functions byte-for-byte; remove CREATIVE_KINDS, add creative action/service constants and library.write ACTIONS/ROUTED in original order.
- packages/business/tests/business.test.mjs: retain C2-01d supporting-prefix refusal and Q247 tracker omission expectation; replay only authorized fixture data and new row 285 tests.
- packages/business/tests/lifecycle-settings.test.mjs: retain row 239 imports, fixture return fields and every appended row 239 test byte-for-byte; add FAR_DATE to existing helper import and gitea to bean fixture (mos-1330).
- packages/bus/src/broker.mjs: retain all newer grant-scope/revocation/room work; only original ACTIONS/ROUTED entries and #giteaRole chief refusal change.
- packages/business/src/business.mjs: intermediate withdrawn fence replayed and removed; final blob equals
b19ffa04fexactly (mos-1333).
Old assertions are unchanged except the binding mos-1332/mos-1333 changes already annotated next to the changes by Scrooge. Other old-test edits are fixture data under mos-1330; no extra assertion, import pin, expected error or test body changed in r3.
Range-diff
Command: git range-diff --no-color 45dca69f6..53db6b7ca b19ffa04f..644bcaa16
1: 9a77fff7a = 1: ca90d28bd row 285: C2-08b, creative roles hold library.write and the gitea credential, the chief of staff a read-scoped gitea credential; #giteaRole refuses the chief (#1790, mos-1309 item 5, sage-2915, sage-2921)
2: 115889e4a ! 2: 362d1ebe3 row 285: fixtures, example and README give the chief and creative instances their gitea reference (#1790, mos-1330)
@@ packages/business/tests/launch-settings.test.mjs: test('B7 kept instance: its ro
const models=structuredClone(settings.read('acme').models);
## packages/business/tests/lifecycle-settings.test.mjs ##
-@@ packages/business/tests/lifecycle-settings.test.mjs: import { readFileSync, rmSync } from "node:fs";
- import { join } from "node:path";
+@@ packages/business/tests/lifecycle-settings.test.mjs: import { join } from "node:path";
import { instanceSettings } from "../src/instance-settings.mjs";
+ import { OrganizationError, organizationWriter } from "../src/organization.mjs";
import { CREATIVE_DEFINITIONS } from "../src/vocabulary.mjs";
-import { businessDoc, REPO, rolesCopy, systemConfig, systemFor, tmp, writeJson } from "./helpers.mjs";
+import { businessDoc, FAR_DATE, REPO, rolesCopy, systemConfig, systemFor, tmp, writeJson } from "./helpers.mjs";
3: aabfdfc60 = 3: 052e094e0 row 285: a chief-of-staff or creative instance that names publish refuses at load, keeping today's N10 refusal; instance-settings :289 follows the companion's gitea (#1790, mos-1332)
4: 66e3c3d61 = 4: 68e6d4588 row 285: webby-0178 early read, drop the stale creative publish comment and name the example's test readers (#1790)
5: cf8ba6ef4 = 5: 299a8027c row 285: mos-1333, withdraw the publish fence; N10 option (a) with an assistant instance; a chief with its gitea ref, identity and publish loads; restore the creative publish test; BUILD.md gate scope (sage-2946) (#1790)
6: 8f8b8cf15 = 6: 2773b0151 row 285: library.write joins ACTIONS and ROUTED in the business vocabulary and the broker under PRD 1.16 REQ-WAIT-3 and REQ-LIB-6, with a hard-waits test; BUILD.md records the r2 rebase, range-diff and drift check (#1790, sage-3578)
7: 53db6b7ca = 7: 644bcaa16 row 285: BUILD.md records N1, the creative-only library.write refusal as a follow-up, and the round scope (#1790, sage-3593)
The sole ! is surrounding context: lifecycle-settings gained the upstream organization import. Stable patch IDs match for six commits. The fixture commit differs because patch-id includes unchanged hunk context: the organization import moved into that hunk. The added/removed-line comparison below independently confirms identical edits.
Stable patch IDs
9a77fff7a7 -> ca90d28bd1
old e7475b6b7909102171942e99e13fcaa6b1d83cf7
new e7475b6b7909102171942e99e13fcaa6b1d83cf7
115889e4a0 -> 362d1ebe3b
old 633b592302ad0535201ba0bebfc927e8db98cfab
new 351b0df9fc1817101dc95fc19011d5b32002dca1
aabfdfc604 -> 052e094e06
old 1891895336d08bb79c8d062d2ac9958808c2bfc7
new 1891895336d08bb79c8d062d2ac9958808c2bfc7
66e3c3d616 -> 68e6d45882
old ed181994e6b7325a56288fe6d0a0be9d5e7fdcf9
new ed181994e6b7325a56288fe6d0a0be9d5e7fdcf9
cf8ba6ef45 -> 299a8027c9
old c3c60e62be61d3c12127bb0fe1e2ca9300140393
new c3c60e62be61d3c12127bb0fe1e2ca9300140393
8f8b8cf153 -> 2773b01515
old 508464365a988647751bf6415ab715fd08c72b13
new 508464365a988647751bf6415ab715fd08c72b13
53db6b7cac -> 644bcaa164
old 0140de36471c1584ff752aa6dee942b8e4560576
new 0140de36471c1584ff752aa6dee942b8e4560576
Drift scan: every candidate test reader
Static only. readers.txt lists each test with dependency paths. This list includes relative imports, re-exports, literal new URL paths, helper imports, and conservative rolesDir / REPO_ROLES / rolesCopy / join(..., "roles", ...) consumers. Runtime conditional readers are included even where the branch may not execute them. The broader grep output is in role-readers.txt; direct path and hash checks follow. No inventory is a claim that those tests passed.
packages/bus/tests/access-revoke.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/console-decide.test.mjs packages/bus/tests/creative.test.mjs packages/bus/tests/credential-claim.test.mjs packages/bus/tests/credential-status.test.mjs packages/bus/tests/credential-store.test.mjs packages/bus/tests/credential-verbs.test.mjs packages/bus/tests/credentials.test.mjs packages/bus/tests/csuite-messaging.test.mjs packages/bus/tests/daily-quota-runtime.test.mjs packages/bus/tests/decision-close.test.mjs packages/bus/tests/decision-route.test.mjs packages/bus/tests/decisions.test.mjs packages/bus/tests/end-launch.test.mjs packages/bus/tests/fire-revokes-grants.test.mjs packages/bus/tests/gitea-grant-docker.test.mjs packages/bus/tests/gitea-grant.test.mjs packages/bus/tests/grant-enroll.test.mjs packages/bus/tests/grant-executor.test.mjs packages/bus/tests/grant-host.test.mjs packages/bus/tests/grant-migration.test.mjs packages/bus/tests/grant-scope-runtime.test.mjs packages/bus/tests/grant-scope.test.mjs packages/bus/tests/hard-waits.test.mjs packages/bus/tests/host-run.test.mjs packages/bus/tests/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/launcher-released.test.mjs packages/bus/tests/library-sync.test.mjs packages/bus/tests/library.test.mjs packages/bus/tests/lifecycle-revoke.test.mjs packages/bus/tests/lifecycle-verbs.test.mjs packages/bus/tests/limit-checks.test.mjs packages/bus/tests/limit-stop.test.mjs packages/bus/tests/limits-runtime.test.mjs packages/bus/tests/limits.test.mjs packages/bus/tests/message-citation.test.mjs packages/bus/tests/message-filter.test.mjs packages/bus/tests/messages.test.mjs packages/bus/tests/messaging.test.mjs packages/bus/tests/names.test.mjs packages/bus/tests/peer-transport.test.mjs packages/bus/tests/peercred.test.mjs packages/bus/tests/plugins-verb.test.mjs packages/bus/tests/principal.test.mjs packages/bus/tests/process.test.mjs packages/bus/tests/processing-runtime.test.mjs packages/bus/tests/processing-timeout.test.mjs packages/bus/tests/processing.test.mjs packages/bus/tests/project-await.test.mjs packages/bus/tests/project-files.test.mjs packages/bus/tests/project-runtime.test.mjs packages/bus/tests/publish.test.mjs packages/bus/tests/reload.test.mjs packages/bus/tests/replies.test.mjs packages/bus/tests/requirements.test.mjs packages/bus/tests/review.test.mjs packages/bus/tests/revoke-window.test.mjs packages/bus/tests/rooms.test.mjs packages/bus/tests/routes-verb.test.mjs packages/bus/tests/session-clear.test.mjs packages/bus/tests/session-compactions.test.mjs packages/bus/tests/sessions.test.mjs packages/bus/tests/single-use.test.mjs packages/bus/tests/spec-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-claims.test.mjs packages/bus/tests/thread-migration.test.mjs packages/bus/tests/thread-shares.test.mjs packages/bus/tests/threads.test.mjs packages/bus/tests/transport.test.mjs packages/bus/tests/usage-broker.test.mjs packages/bus/tests/usage-runtime.test.mjs packages/bus/tests/user-principal.test.mjs packages/bus/tests/viewer.test.mjs packages/bus/tests/web.test.mjs packages/bus/tests/workflow-roles.test.mjs packages/business/tests/access-levels.test.mjs packages/business/tests/access.test.mjs packages/business/tests/agent-identity.test.mjs packages/business/tests/assistant.test.mjs packages/business/tests/business.test.mjs packages/business/tests/case1-business-file.test.mjs packages/business/tests/case1-project-key.test.mjs packages/business/tests/chief-of-staff.test.mjs packages/business/tests/cli.test.mjs packages/business/tests/credentials.test.mjs packages/business/tests/csuite.test.mjs packages/business/tests/grant-scope.test.mjs packages/business/tests/hard-waits.test.mjs packages/business/tests/hosts.test.mjs packages/business/tests/instance-settings.test.mjs packages/business/tests/launch-settings.test.mjs packages/business/tests/library-projects-protected.test.mjs packages/business/tests/library-seats.test.mjs packages/business/tests/lifecycle-settings.test.mjs packages/business/tests/optional-tracker.test.mjs packages/business/tests/plugin-settings.test.mjs packages/business/tests/project-repo.test.mjs packages/business/tests/project.test.mjs packages/business/tests/record-grants.test.mjs packages/business/tests/resolve.test.mjs packages/business/tests/role.test.mjs packages/business/tests/spec-review-contracts.test.mjs packages/business/tests/token-limit-settings.test.mjs packages/business/tests/vars.test.mjs packages/business/tests/workflow-roles.test.mjs packages/cli/tests/access-boot.test.mjs packages/cli/tests/access.test.mjs packages/cli/tests/app.test.mjs packages/cli/tests/boot-status.test.mjs packages/cli/tests/case1-accept.test.mjs packages/cli/tests/case1-hostcheck.test.mjs packages/cli/tests/case2-install.test.mjs packages/cli/tests/case2-persona-import.test.mjs packages/cli/tests/case2-unit.test.mjs packages/cli/tests/channel-cli.test.mjs packages/cli/tests/channel-recovery.test.mjs packages/cli/tests/cli.test.mjs packages/cli/tests/compactions-launch.test.mjs packages/cli/tests/config.test.mjs packages/cli/tests/credentials.test.mjs packages/cli/tests/follow.test.mjs packages/cli/tests/git-socket.test.mjs packages/cli/tests/grants-scope.test.mjs packages/cli/tests/grants.test.mjs packages/cli/tests/host.test.mjs packages/cli/tests/hosts.test.mjs packages/cli/tests/idle-stop-race.test.mjs packages/cli/tests/instances.test.mjs packages/cli/tests/launch-account.test.mjs packages/cli/tests/launch-limit-checks.test.mjs packages/cli/tests/launch-limits.test.mjs packages/cli/tests/launch-routes.test.mjs packages/cli/tests/launcher.test.mjs packages/cli/tests/lifecycle.test.mjs packages/cli/tests/limits-tokens.test.mjs packages/cli/tests/limits.test.mjs packages/cli/tests/mark-read.test.mjs packages/cli/tests/names.test.mjs packages/cli/tests/notifier.test.mjs packages/cli/tests/optional-tracker.test.mjs packages/cli/tests/other-tree.test.mjs packages/cli/tests/processing-cli.test.mjs packages/cli/tests/project-name-repo.test.mjs packages/cli/tests/project.test.mjs packages/cli/tests/publish-socket.test.mjs packages/cli/tests/revoke-window.test.mjs packages/cli/tests/session-clear.test.mjs packages/cli/tests/session-cli.test.mjs packages/cli/tests/session-launch.test.mjs packages/cli/tests/stack-copy.test.mjs packages/cli/tests/stack-instances.test.mjs packages/cli/tests/stack-release-external.test.mjs packages/cli/tests/stack-release.test.mjs packages/cli/tests/stack-upgrade.test.mjs packages/cli/tests/tester-http.test.mjs packages/cli/tests/tester-reads.test.mjs packages/cli/tests/tester-threads.test.mjs packages/cli/tests/tester.test.mjs packages/cli/tests/thread-cli.test.mjs packages/cli/tests/thread-launch.test.mjs packages/cli/tests/thread-revoke.test.mjs packages/cli/tests/trackers-boot.test.mjs packages/cli/tests/transport.test.mjs packages/cli/tests/usage.test.mjs packages/cli/tests/verbs.test.mjs packages/control-board/tests/creative-hidden.test.mjs packages/control-board/tests/discord.test.mjs packages/control-board/tests/relaunch.test.mjs packages/control-board/tests/serve.test.mjs packages/conversation/tests/flows.test.mjs packages/discord/tests/copy-service.test.mjs packages/discord/tests/library-seat.test.mjs packages/discord/tests/offline-check.test.mjs packages/discord/tests/processing.test.mjs packages/discord/tests/recover.test.mjs packages/harness/tests/bundle.test.mjs packages/harness/tests/claude-gate.test.mjs packages/harness/tests/claude-session.test.mjs packages/harness/tests/creative.test.mjs packages/harness/tests/gate.test.mjs packages/harness/tests/git-tools.test.mjs packages/harness/tests/mcp-server.test.mjs packages/harness/tests/pi-session.test.mjs packages/harness/tests/raise-domain.test.mjs packages/harness/tests/runner.test.mjs packages/harness/tests/skills.test.mjs packages/harness/tests/spec-tools.test.mjs packages/harness/tests/tools.test.mjs packages/library/tests/query.test.mjs packages/plugins/tests/harness-compactions.test.mjs packages/plugins/tests/harness.test.mjs packages/plugins/tests/loader.test.mjs packages/processing-control/tests/mount.test.mjs packages/processing-control/tests/task.test.mjs packages/seat/tests/compactions-budget.test.mjs packages/seat/tests/compactions-ledger.test.mjs packages/seat/tests/compactions.test.mjs packages/seat/tests/sandbox.test.mjs packages/seat/tests/session-workspace.test.mjs packages/seat/tests/session.test.mjs packages/tasks/tests/adapter.test.mjs packages/tasks/tests/comment-restart.test.mjs packages/tasks/tests/fields.test.mjs packages/tasks/tests/processing.test.mjs packages/tasks/tests/shapes.test.mjs packages/tasks/tests/startup.test.mjs packages/tasks/tests/sync.test.mjs packages/tasks/tests/tree.test.mjs packages/tasks/tests/verbs.test.mjs packages/webui/tests/agents-browser.test.mjs packages/webui/tests/agents.test.mjs packages/webui/tests/assistant.test.mjs packages/webui/tests/board-held.test.mjs packages/webui/tests/browser-edge.test.mjs packages/webui/tests/browser.test.mjs packages/webui/tests/bus-browser.test.mjs packages/webui/tests/bus.test.mjs packages/webui/tests/channel-chat.test.mjs packages/webui/tests/chat-browser.test.mjs packages/webui/tests/chat-instances.test.mjs packages/webui/tests/chat-sessions-access.test.mjs packages/webui/tests/chat.test.mjs packages/webui/tests/conversation.test.mjs packages/webui/tests/decide-browser.test.mjs packages/webui/tests/decide-sso.test.mjs packages/webui/tests/decision-http.test.mjs packages/webui/tests/discord.test.mjs packages/webui/tests/docs-browser.test.mjs packages/webui/tests/editor-browser.test.mjs packages/webui/tests/editor.test.mjs packages/webui/tests/granted-user.test.mjs packages/webui/tests/history-return-flow.test.mjs packages/webui/tests/instances-browser.test.mjs packages/webui/tests/instances.test.mjs packages/webui/tests/library-cli.test.mjs packages/webui/tests/library-status.test.mjs packages/webui/tests/limits-browser.test.mjs packages/webui/tests/limits-route.test.mjs packages/webui/tests/messages.test.mjs packages/webui/tests/pinned-copy.test.mjs packages/webui/tests/preview.test.mjs packages/webui/tests/processing-browser.test.mjs packages/webui/tests/processing.test.mjs packages/webui/tests/project-file.test.mjs packages/webui/tests/project-name-repo.test.mjs packages/webui/tests/proof-cli.test.mjs packages/webui/tests/proof.test.mjs packages/webui/tests/reads.test.mjs packages/webui/tests/relaunch.test.mjs packages/webui/tests/return-flow.test.mjs packages/webui/tests/routes-browser.test.mjs packages/webui/tests/routes.test.mjs packages/webui/tests/send-browser.test.mjs packages/webui/tests/send.test.mjs packages/webui/tests/serve.test.mjs packages/webui/tests/settings-form.test.mjs packages/webui/tests/settings-write.test.mjs packages/webui/tests/shell.test.mjs packages/webui/tests/sso-browser.test.mjs packages/webui/tests/sso.test.mjs packages/webui/tests/tester-browser.test.mjs packages/webui/tests/tester-cli.test.mjs packages/webui/tests/tester-listener.test.mjs packages/webui/tests/tester-socket.test.mjs packages/webui/tests/thread-claims-browser.test.mjs packages/webui/tests/thread-claims.test.mjs packages/webui/tests/thread-sharing.test.mjs packages/webui/tests/usage-browser.test.mjs packages/webui/tests/usage.test.mjs packages/webui/tests/user-option-swap.test.mjs packages/webui/tests/views.test.mjs
Total conservative candidate test/script readers: 291.
The inventory also includes control-board, discord, library, seat and other readers outside the explicitly assigned six-suite gate. Report this to Sage; his all-script landing gate remains assigned to him. Do not silently widen the test slot.
Gate after CLEAR
Own worktree only; no canonical npm/rm, no linked node_modules (mos-1575). Root and packages/webui: npm ci --ignore-scripts --no-audit --no-fund. Use export TMPDIR=$(mktemp -d /mnt/storage/scratch/tmp/XXXXXX). Each command gets timeout -k 10; run serially and preserve plain-text full output. Whole bus, business, cli, webui, harness and plugins suites, plus scripts/test-config.sh. Package suite command: timeout -k 10 1800 node --test --test-concurrency=1 packages/NAME/tests/.test.mjs. Config: timeout -k 10 300 bash scripts/test-config.sh. Mutants M1–M6 and M9 from Scrooge BUILD, one at a time, source sha256 restoration checked. First red in any old test: stop and report to Sage before edits or more tests. First red in new test: place and report afterward as directed by sage-4039. Sage runs every scripts/test-.sh at landing; Poe first review, Webby landing review. No Gitea posting, landing, release, deployment or live business change authorized here.
Results
Not run. Waiting for CLEAR after the explicitly authorized own-branch push.
Direct grep and pin evidence
Removed symbol, full requested trees Command: git grep -n CREATIVE_KINDS -- packages roles scripts Exit: 1 (no matches)
Grant refusal readers Command: git grep -n gitea-not-declared -- packages//tests/ Exit: 0 packages/bus/tests/gitea-grant.test.mjs:228: [{ agent: 'pm' }, 'gitea-not-declared'], packages/bus/tests/gitea-grant.test.mjs:229: [{ agent: 'nobody' }, 'gitea-not-declared'], packages/bus/tests/gitea-grant.test.mjs:247: await rejects(creative.raise(), 'gitea-not-declared'); packages/bus/tests/gitea-grant.test.mjs:249: await rejects(bare.raise(), 'gitea-not-declared'); packages/bus/tests/gitea-grant.test.mjs:270: await rejects(f.raise({ agent: 'chief' }), 'gitea-not-declared');
N10 message readers Command: git grep -n needs identity and a gitea definition -- packages//tests/ Exit: 0 packages/business/tests/agent-identity.test.mjs:47:test("N10: publish needs identity and a gitea definition, and the error names the grant", () => { packages/business/tests/agent-identity.test.mjs:48: refuses(() => check((d) => { delete d.roles.coder.identity; }), /roles.coder.publish needs identity and a gitea definition/); packages/business/tests/agent-identity.test.mjs:52: /roles.helper.publish needs identity and a gitea definition/);
64-hex scan: hex-pins.txt contains all test/helper/fixture literal hits, inspected individually. No hit pins any changed role, broker.mjs, role.mjs, vocabulary.mjs, or helper/example file. Existing literal hashes cover SQL migrations, human/transport channel sources, compaction cursors, charter records, case1 supervisor/profile bytes and markdown rendering, all unchanged. project-runtime.test.mjs pins broker imports and vocabulary import-free by reading source: no import changes; its exact expectation stays byte-identical. role.test/chief-of-staff.test pin role contents structurally, with the existing Mos annotations for approved changes.
Replay blob/patch checks
Retains newer base changes: packages/bus/src/broker.mjs
Retains newer base changes: packages/business/README.md
Retains newer base changes: packages/business/src/vocabulary.mjs
Retains newer base changes: packages/business/tests/business.test.mjs
Retains newer base changes: packages/business/tests/lifecycle-settings.test.mjs
All remaining changed paths equal 53db6b7ca byte-for-byte.
Static assertion passed: every tests/ path has exactly the same added/removed lines
as the original 45dca69f6..53db6b7ca patch; no extra old-test change introduced by replay.
CLEAR sage-4048: gate started
2026-10-24T10:28:35.498486+00:00 — candidate 66a800e15. Own root npm ci
installed 128 packages. Own webui npm ci installed 2 packages; its first command
looked up the TMPDIR receipt relative to webui and missed it, so reran that install
with the corrected receipt path and short scratch TMPDIR. Both output logs retained.
Neither node_modules directory is a symlink. CLI suite will run locally as one of
the six requested suites; authoritative landing counts and extra readers belong to Sage.
Run each whole test file serially, stop at the first failing file for old/new classification.
This replaces the one-process suite example above so no later file runs after an old red.
First-run old-test STOP (2026-10-24T10:32:02Z, sage-4048)
Whole bus: 108 files, 958/958 pass, zero fail/skip/cancel. Business partial: 6 files, 84 tests, 80 pass/4 fail; first five files green, including row 285 agent-identity/business tests. First failing file: packages/business/tests/case1-business-file.test.mjs (old row 323 tests at 57, 86, 95, 105), 3 pass/4 fail. All four refuse because roles.chief.credentials must reference exactly the services its role definition needs (gitea; got none). Full first-red evidence: gate/business/case1-business-file.test.mjs.log. Per-file commands/counts: gate/runs.txt.
Stopped before the next file. CLI/webui/harness/plugins/config/mutants NOT RUN. The mutant driver is prepared but has never executed. No source or old test edited. Sage notified immediately (magica-0002). No green claim or in-review move.
Static diagnosis under systematic-debugging (no extra test execution): case1-business-file.test.mjs:13 reads docs/guides/case1-business.mosaic-stack.json through join(REPO, "docs/guides/case1-business.mosaic-stack.json"). That committed document's chief has no credentials. The role now declares gitea; unchanged checkCredentialMap in business.mjs fails closed at load. The document is an additional repository business writer absent from Scrooge's earlier writer scan. It landed after r2's base. case1-project-key.test.mjs is another direct reader.
A document-only ref would expose further old expectations: case1-business-file line 81 deepEquals every role.credentials to {}; lines 112 and 114 expect empty credential status lists. These expectations need a specific owner ruling before any edits, and a store reference also needs the private store-root bootstrap precondition from Scrooge's binding notes. No narrowed fix has been attempted.
Recommended resolution: Sage coordinates the row 323 document owner and Mos ruling for exact document/ref/fixture expectation changes; preserve no-tracker semantics and every unrelated assertion. Re-CLEAR before resuming the gate.
Amendment 1 build (2026-10-24T10:42:28Z, mos-1580, sage-4059, sage-4060)
Canonical amendment read from local commit 98235fdb329384a948d9ce8c954c66920e6d2ed2;
queue re-pin rev3902 per Sage. This supersedes the earlier unconditional chief-reference
fixture and live-step assumption. No tests/install/queue verbs run under the held slot.
Sage explicitly authorized building and pushing before returning CLEAR. The earlier
958-pass bus and partial business evidence belongs to 66a800e15, not this amendment.
Implementation plan, following the supplied ruling:
- Write three cases in new chief-library-credentials.test.mjs against unchanged Case1 document: no-library empty refs load; library missing chief gitea refuses by name with library+reference positive control; no-library extra gitea refuses. The third also checks assistant exact-match stays enforced. Tests written before source edit, execution deferred by explicit slot order (no claimed RED/GREEN yet).
- business.mjs passes whether projects declares any kind=library to checkRoles. Only a chief-of-staff instance without a library removes gitea from required refs. Library without chief gitea refuses chief-library-gitea-required. The exact-match function is byte-identical and still rejects unused refs and every other role's mismatch; no role authority/scopes or grant-executor changes.
- Reconcile only row285-owned fixture hunks under sage-4060, keep old base assertions.
- Prepare M10: remove the chief's library filter condition; require independent kills by the new no-library positive and unchanged row323 committed-document test. gate/run-mutants.py includes both checks; it has never executed.
- Push build, report hunks and known untouched fixture dependencies; await CLEAR before rerunning the whole gate from the start.
Exact hunk list beyond 66a800e15:
- business/src/business.mjs: checkRoles hasLibrary parameter; chief-only gitea filter and named missing ref refusal; compute hasLibrary at call site. checkCredentialMap unchanged.
- business/tests/chief-library-credentials.test.mjs: new file, three ruled cases only.
- business/tests/helpers.mjs: remove row285 chief credential/comment hunk, restore whole base.
- business/tests/resolve.test.mjs: remove row285 chief2 credential/import hunk, restore whole base.
- business/tests/chief-of-staff.test.mjs: restore base import, resolved-record block, and no-credential/no-tracker refusal block. Retain only approved r2 APPROVED.credentials hunk.
- business/tests/agent-identity.test.mjs: only row285's new chief-positive test gains library mapping and explicit reference; approved N10 helper hunk remains unchanged.
- business/tests/business.test.mjs: only row285's new chief/creative-missing test declares a library for the chief case and expects the named refusal. Other assertions unchanged.
- business/examples/mosaic-stack.example.json: remove row285 chief-reference hunk; whole base restored because this example has no library. This is a retraction of row285's own data edit.
- business/README.md: retract own chief example reference; amend own prose to state the library-only rule. No unrelated base paragraph edited.
- Evidence/docs: retain first-red logs, append receipts and add M10 mutant plan.
Static byte checks (not test execution): 9e43bfef326e568488aaa4f0d8882e9b932750aeb39f587a113a226bfb30cf0f docs/guides/case1-business.mosaic-stack.json (base-identical) 9c3bf7f349d0ee8626743e1388b9a596c7f3c274beaedad5106db5f2ff8f65e7 packages/business/tests/case1-business-file.test.mjs (base-identical) a6a9971b42ddf176d9415caee3efc2eb16791dead5f0f0557d28449a550aefa1 packages/business/tests/helpers.mjs (base-identical) c74af44a83ee918196e2c1016b62786e757c0ae774c9b1613280d3fbbf3ffb22 packages/business/tests/resolve.test.mjs (base-identical) 211ce2b570f4e3034a8de6fc567b4cf7f866e612c26a3dceb327117c85785f1a packages/business/examples/mosaic-stack.example.json (base-identical) checkCredentialMap function: byte-identical to base.
Remaining known boundary, reported to Sage: base library fixtures that call businessDoc() and add a mapping now need a chief ref (e.g. business.test.mjs C2-04 mapping case, instance-settings.test.mjs C2-04, resolve.test.mjs C2-04, library-seats.test.mjs). The base library-seats bean fixtures also lack creative gitea, which row285 now requires. No unapproved base test fixture or assertion has been changed. These are static findings, not new gate failures. Resolve fixture authority before CLEAR to avoid a predictable old red.
Verification status: NOT RUN; Rockerduck holds the slot.
B1 fixture preparation (2026-10-24T10:54:55Z, mos-1581, sage-4067)
No tests/npm/queue verbs executed. First independent pass adds ten credential-data lines in six files; no deletion, original byte change, assertion change or new import. Each reference reuses the fixture's existing private dummy coder gitea ref, not a new token or a credential store file.
Library-seats companion fixtures statically require gitea under the unchanged creative definition/exact-match rule (business.mjs checkCredentialMap):
- M7/M8: library seats come from library businesses, creative seats from their creative definitions
- M8: a business with no library project puts no seat in either set Each creates companion bean with no reference, and loadSeatSets calls loadBusiness before deciding whether any project is a library. Thus the second needs bean's gitea too, while its chief still needs none. Both receive only a credential line.
Direct-reader additions so far: business library-projects-protected, CLI case2-install, control-board creative-hidden, Discord library-seat. Synthetic broker/mirror/project objects that never call the business loader are unchanged.
Pending exact-scope rulings (magica-0006/0007): inline fixture callbacks need formatting splits to insert credential data; extra direct-reader creative fixtures also lack gitea; trackers-boot's setup loop assumes every credential map contains vikunja, so chief gitea needs a one-line setup guard correction. No pending edit has been applied.
Exact partial B1 diff against babae6adc (all additions are credential lines):
diff --git a/packages/business/tests/business.test.mjs b/packages/business/tests/business.test.mjs index b79576af8..f78789250 100644 --- a/packages/business/tests/business.test.mjs +++ b/packages/business/tests/business.test.mjs @@ -15,6 +15,7 @@ test('C2-04: library mappings load without roots, remain frozen, and retain mapp 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 };
- doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; const loaded = validateBusinessDocument(doc, file, { rolesDir: REPO_ROLES }); const { checkMapping } = await import('../../library/src/mapping.mjs'); assert.deepEqual(loaded.projects.books, checkMapping(mappingEntry())); @@ -42,6 +43,7 @@ test('C2-04: an otherwise valid publish grant cannot name a library repo', async 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.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; 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/library-projects-protected.test.mjs b/packages/business/tests/library-projects-protected.test.mjs index 51672bd7b..d4d09d94f 100644 --- a/packages/business/tests/library-projects-protected.test.mjs +++ b/packages/business/tests/library-projects-protected.test.mjs @@ -14,6 +14,7 @@ function fixture(t) { books.universes.hybrid = { kind: 'hybrid', name: 'An invented crossover', sources: ['harbor', 'second'], books: ['Hybrid Book'], playground: [], constraints: [], notes: 'Fixture only' }; doc.projects = { books, ...doc.projects };
- doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; const dir = join(root, 'config'), file = writeJson(join(dir, 'businesses/acme.json'), doc); const writer = organizationWriter({ dir, rolesDir: rolesCopy(root) }); // Give both snapshots an existing ordinary committed receipt to preserve. diff --git a/packages/business/tests/library-seats.test.mjs b/packages/business/tests/library-seats.test.mjs index 3cd0f86cf..da76fdbc7 100644 --- a/packages/business/tests/library-seats.test.mjs +++ b/packages/business/tests/library-seats.test.mjs @@ -27,7 +27,9 @@ test("M7/M8: library seats come from library businesses, creative seats from the const { root, dir } = fixture(t); const doc = businessDoc(root, "acme"); doc.projects = { books: mappingEntry(), ...doc.projects };
- doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; doc.roles.bean = { definition: "companion" };
- doc.roles.bean.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; writeJson(join(dir, "businesses", "acme.json"), doc); const found = sets(dir); assert.deepEqual([...found.librarySeats].sort(), ["bean", "chief", "coder", "cto", "pm", "reviewer"]); @@ -39,6 +41,7 @@ test("M8: a business with no library project puts no seat in either set", (t) => const { root, dir } = fixture(t); const doc = businessDoc(root, "other"); doc.roles.bean = { definition: "companion" };
- doc.roles.bean.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; writeJson(join(dir, "businesses", "other.json"), doc); const found = sets(dir); assert.equal(found.librarySeats.size, 0); diff --git a/packages/cli/tests/case2-install.test.mjs b/packages/cli/tests/case2-install.test.mjs index cc1142510..50eb3c2a8 100644 --- a/packages/cli/tests/case2-install.test.mjs +++ b/packages/cli/tests/case2-install.test.mjs @@ -51,6 +51,7 @@ function world(t, { profile = "library" } = {}) { for (const r of Object.values(doc.roles)) r.vars = { ...r.vars, harness: "pi" }; if (profile === "library") { doc.projects.books = { ...mappingEntry(), user: "writer" };
- doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; doc.roles.bean = { definition: "companion", vars: { harness: "pi" } }; doc.roles.chet = { definition: "companion", vars: { harness: "pi" } }; } else doc.vars["bus.tester"] = true; @@ -212,6 +213,7 @@ test("the factory install refuses a library project and bus.tester off, before a const x = world(t, { profile: "factory" }); const doc = JSON.parse(readFileSync(x.input, "utf8")); doc.projects.books = { ...mappingEntry(), user: "writer" };
- doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; writeJson(x.input, doc); refused(install(x, { profile: "factory" }), /profile-library-business/); delete doc.projects.books; diff --git a/packages/control-board/tests/creative-hidden.test.mjs b/packages/control-board/tests/creative-hidden.test.mjs index c2abd348e..6ea3ecbea 100644 --- a/packages/control-board/tests/creative-hidden.test.mjs +++ b/packages/control-board/tests/creative-hidden.test.mjs @@ -20,6 +20,7 @@ function fixture(t) { const dir = join(root, "config"); const doc = businessDoc(root, "acme"); doc.projects = { books: mappingEntry(), ...doc.projects };
- doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; doc.roles.bean = { definition: "companion" }; writeJson(join(dir, "businesses", "acme.json"), doc); const threadDir = join(root, "data", "threads", "acme", "t1", "session"); diff --git a/packages/discord/tests/library-seat.test.mjs b/packages/discord/tests/library-seat.test.mjs index 315f69698..e8a3e3caa 100644 --- a/packages/discord/tests/library-seat.test.mjs +++ b/packages/discord/tests/library-seat.test.mjs @@ -31,6 +31,7 @@ function setup(overrides = {}) { function business(s, { library, role = "sage", definition = "companion" }) { const doc = businessDoc(s.root, "acme"); if (library) doc.projects = { books: mappingEntry(), ...doc.projects };
- if (library) doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; doc.roles[role] = { definition }; writeJson(join(s.root, "businesses", "acme.json"), doc); }
Exact partial full-file base diff against e0c6142f3 follows. business.test also
contains the previously approved row285 hunks; those are unchanged by B1. The
other five files show only the credential additions.
diff --git a/packages/business/tests/business.test.mjs b/packages/business/tests/business.test.mjs index 9d4eda831..f78789250 100644 --- a/packages/business/tests/business.test.mjs +++ b/packages/business/tests/business.test.mjs @@ -6,6 +6,7 @@ import { join } from "node:path"; import { pathToFileURL } from "node:url"; import { BusinessError, businessFilePath, configDir, loadBusiness, validateBusinessDocument } from "../src/index.mjs"; import { THREAD_IDLE_SECONDS } from "../src/business.mjs"; +import { CREATIVE_DEFINITIONS } from "../src/vocabulary.mjs"; import { launchDoc, businessDoc, REPO, REPO_ROLES, rolesCopy, tmp, writeJson } from "./helpers.mjs";
test('C2-04: library mappings load without roots, remain frozen, and retain mapping refusals', async t => { @@ -14,6 +15,7 @@ test('C2-04: library mappings load without roots, remain frozen, and retain mapp 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 };
- doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; const loaded = validateBusinessDocument(doc, file, { rolesDir: REPO_ROLES }); const { checkMapping } = await import('../../library/src/mapping.mjs'); assert.deepEqual(loaded.projects.books, checkMapping(mappingEntry())); @@ -41,6 +43,7 @@ test('C2-04: an otherwise valid publish grant cannot name a library repo', async 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.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; 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/); @@ -273,28 +276,58 @@ test("the shipped example refuses as written and validates once filled in", () = assert.equal(id, 15); });
+// Row 285 (C2-08b, #1790, mos-1330): a creative definition declares gitea, so its instance names +// the reference. The store form needs no token file, and the bus reads a missing one as no token. +const CREATIVE_GITEA = Object.freeze({ gitea: Object.freeze({ store: true, rotateBy: "2099-01-01" }) }); + // Row 213 (C2-08, #1714), deviation D1: the persona vars sit on a creative instance only, and // both or neither. The var checks themselves are vars.mjs's. test("persona vars: agent layer, creative definition only, both or neither", () => { const sha = "a".repeat(64); const persona = { "persona.name": "Bean", "persona.sha256": sha };
- const business = check((d) => { d.roles.bean = { definition: "companion", vars: { ...persona } }; });
- const business = check((d) => { d.roles.bean = { definition: "companion", credentials: CREATIVE_GITEA, vars: { ...persona } }; }); assert.deepEqual({ ...business.roles.bean.vars }, persona);
- assert.doesNotThrow(() => check((d) => { d.roles.bean = { definition: "ideas" }; }));
- assert.doesNotThrow(() => check((d) => { d.roles.bean = { definition: "ideas", credentials: CREATIVE_GITEA }; })); refuses(() => check((d) => { d.vars["persona.name"] = "Bean"; }), /persona.name can't be set at the business layer/); refuses(() => check((d) => { d.roles.pm.vars = { ...d.roles.pm.vars, ...persona }; }), /roles.pm.vars: persona vars need a creative definition (pm isn't one)/); refuses(() => check((d) => { d.roles.chief.vars = { ...persona }; }), /chief-of-staff isn't one/); for (const key of Object.keys(persona)) {
- refuses(() => check((d) => { d.roles.bean = { definition: "research", vars: { [key]: persona[key] } }; }),
- refuses(() => check((d) => { d.roles.bean = { definition: "research", credentials: CREATIVE_GITEA, vars: { [key]: persona[key] } }; }),
/roles.bean.vars: persona.name and persona.sha256 are set together or not at all/);
}
for (const [key, value] of [["persona.name", "x".repeat(41)], ["persona.name", "Be\nan"], ["persona.name", "Be\u0007an"], ["persona.name", "Be\u2028an"], ["persona.name", "Be\u2029an"], ["persona.name", 7],
["persona.sha256", "A".repeat(64)], ["persona.sha256", sha.slice(1)], ["persona.sha256",
${sha}0]]) {
- refuses(() => check((d) => { d.roles.bean = { definition: "companion", vars: { ...persona, [key]: value } }; }), new RegExp(
variable ${key.replace(".", "\\.")}), 2);
- refuses(() => check((d) => { d.roles.bean = { definition: "companion", credentials: CREATIVE_GITEA, vars: { ...persona, [key]: value } }; }), new RegExp(
variable ${key.replace(".", "\\.")}), 2); - } +});
+// Row 285 (C2-08b, #1790, mos-1330): the chief and each creative definition declare gitea, so an +// instance without the reference refuses. Amendment 1 (mos-1580, sage-4060): the chief +// requires its reference only in a library business; creative definitions always require it. +test("row 285: a chief or creative instance without credentials.gitea refuses at load", async () => {
- const { mappingEntry } = await import("../../library/tests/helpers.mjs");
- refuses(() => check((d) => { d.projects.books = mappingEntry(); delete d.roles.chief.credentials; }),
- /chief-library-gitea-required: .*roles.chief.credentials/);
- for (const definition of CREATIVE_DEFINITIONS) {
- refuses(() => check((d) => { d.roles.bean = { definition }; }),
-
/roles\.bean\.credentials must reference exactly the services its role definition needs \(gitea; got none\)/); - assert.doesNotThrow(() => check((d) => { d.roles.bean = { definition, credentials: CREATIVE_GITEA }; }), definition); } });
+// Row 285 (C2-08b, brief): a creative instance may carry identity and publish, under the rules at +// business.mjs:155-166, which the grant path reads. The grant itself still refuses it (#giteaRole). +test("row 285: a creative instance with identity and publish loads", () => {
- const identity = { name: "Bean", email: "[email protected]", gitea: { url: "https://git.example", user: "acme-bean" } };
- const business = check((d) => {
- d.projects.stack.remote = "https://git.example/acme/stack";
- d.roles.bean = { definition: "companion", credentials: CREATIVE_GITEA, identity, publish: ["stack"] };
- });
- assert.deepEqual({ ...business.roles.bean.identity, gitea: { ...business.roles.bean.identity.gitea } }, identity);
- assert.deepEqual([...business.roles.bean.publish], ["stack"]); +});
// Row 194 (#1692, D2.5, T17): the per-agent forbid and the retired list. test("row 194 keep, noHire and retired validate, and a file without them loads as before", () => { const plain = check(); diff --git a/packages/business/tests/library-projects-protected.test.mjs b/packages/business/tests/library-projects-protected.test.mjs index 51672bd7b..d4d09d94f 100644 --- a/packages/business/tests/library-projects-protected.test.mjs +++ b/packages/business/tests/library-projects-protected.test.mjs @@ -14,6 +14,7 @@ function fixture(t) { books.universes.hybrid = { kind: 'hybrid', name: 'An invented crossover', sources: ['harbor', 'second'], books: ['Hybrid Book'], playground: [], constraints: [], notes: 'Fixture only' }; doc.projects = { books, ...doc.projects };
- doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; const dir = join(root, 'config'), file = writeJson(join(dir, 'businesses/acme.json'), doc); const writer = organizationWriter({ dir, rolesDir: rolesCopy(root) }); // Give both snapshots an existing ordinary committed receipt to preserve. diff --git a/packages/business/tests/library-seats.test.mjs b/packages/business/tests/library-seats.test.mjs index 3cd0f86cf..da76fdbc7 100644 --- a/packages/business/tests/library-seats.test.mjs +++ b/packages/business/tests/library-seats.test.mjs @@ -27,7 +27,9 @@ test("M7/M8: library seats come from library businesses, creative seats from the const { root, dir } = fixture(t); const doc = businessDoc(root, "acme"); doc.projects = { books: mappingEntry(), ...doc.projects };
- doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; doc.roles.bean = { definition: "companion" };
- doc.roles.bean.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; writeJson(join(dir, "businesses", "acme.json"), doc); const found = sets(dir); assert.deepEqual([...found.librarySeats].sort(), ["bean", "chief", "coder", "cto", "pm", "reviewer"]); @@ -39,6 +41,7 @@ test("M8: a business with no library project puts no seat in either set", (t) => const { root, dir } = fixture(t); const doc = businessDoc(root, "other"); doc.roles.bean = { definition: "companion" };
- doc.roles.bean.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; writeJson(join(dir, "businesses", "other.json"), doc); const found = sets(dir); assert.equal(found.librarySeats.size, 0); diff --git a/packages/cli/tests/case2-install.test.mjs b/packages/cli/tests/case2-install.test.mjs index cc1142510..50eb3c2a8 100644 --- a/packages/cli/tests/case2-install.test.mjs +++ b/packages/cli/tests/case2-install.test.mjs @@ -51,6 +51,7 @@ function world(t, { profile = "library" } = {}) { for (const r of Object.values(doc.roles)) r.vars = { ...r.vars, harness: "pi" }; if (profile === "library") { doc.projects.books = { ...mappingEntry(), user: "writer" };
- doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; doc.roles.bean = { definition: "companion", vars: { harness: "pi" } }; doc.roles.chet = { definition: "companion", vars: { harness: "pi" } }; } else doc.vars["bus.tester"] = true; @@ -212,6 +213,7 @@ test("the factory install refuses a library project and bus.tester off, before a const x = world(t, { profile: "factory" }); const doc = JSON.parse(readFileSync(x.input, "utf8")); doc.projects.books = { ...mappingEntry(), user: "writer" };
- doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; writeJson(x.input, doc); refused(install(x, { profile: "factory" }), /profile-library-business/); delete doc.projects.books; diff --git a/packages/control-board/tests/creative-hidden.test.mjs b/packages/control-board/tests/creative-hidden.test.mjs index c2abd348e..6ea3ecbea 100644 --- a/packages/control-board/tests/creative-hidden.test.mjs +++ b/packages/control-board/tests/creative-hidden.test.mjs @@ -20,6 +20,7 @@ function fixture(t) { const dir = join(root, "config"); const doc = businessDoc(root, "acme"); doc.projects = { books: mappingEntry(), ...doc.projects };
- doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; doc.roles.bean = { definition: "companion" }; writeJson(join(dir, "businesses", "acme.json"), doc); const threadDir = join(root, "data", "threads", "acme", "t1", "session"); diff --git a/packages/discord/tests/library-seat.test.mjs b/packages/discord/tests/library-seat.test.mjs index 315f69698..e8a3e3caa 100644 --- a/packages/discord/tests/library-seat.test.mjs +++ b/packages/discord/tests/library-seat.test.mjs @@ -31,6 +31,7 @@ function setup(overrides = {}) { function business(s, { library, role = "sage", definition = "companion" }) { const doc = businessDoc(s.root, "acme"); if (library) doc.projects = { books: mappingEntry(), ...doc.projects };
- if (library) doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; doc.roles[role] = { definition }; writeJson(join(s.root, "businesses", "acme.json"), doc); }
Completed B1 data build (2026-10-24T10:59:07Z, mos-1581/1582, sage-4069/4071)
This supersedes the partial preparation above. No tests/install/queue command run. Same-line callbacks remain one line, with every original token in order. The only non-credential edit is the expressly approved trackers-boot setup guard.
Creative direct readers and their statically traced refusal without credential data:
- packages/control-board/tests/creative-hidden.test.mjs: companion bean; loadSeatSets -> loadBusiness -> BusinessError exit2, roles.bean.credentials must reference exactly ... (gitea; got none), wrapped as conversation-business-unreadable.
- packages/discord/tests/library-seat.test.mjs: role-param companion sage, both library/no-library variants; same BusinessError for roles.sage.credentials, wrapped by discord CLI as discord-business-unreadable (exit2).
- packages/cli/tests/case2-install.test.mjs: companion bean and chet in library profile; same BusinessError for roles.bean.credentials (then chet), surfaced by installer as refused: validate (exit1). The parser has no separate BusinessError.code.
- packages/cli/tests/thread-launch.test.mjs: companion bean in fromSession-refusal, companion bean + continuity chet in distinct-runs, companion bean in selected-peer termination; same BusinessError exact-match exit2, wrapped as CliError by bootConfig.
- packages/business/tests/library-seats.test.mjs: both named cases listed above, same unwrapped BusinessError exact-match exit2 for roles.bean.credentials. These are static call-chain conclusions, not claims that held-slot tests executed.
Tracker put() role-set preservation (mos-1582 B)
Base e0c6142f3 businessDoc creates exactly pm, cto, coder, reviewer, chief.
The tracker fixture changes project mappings, IDs and vars, not role membership.
Base credential services / old guard reaching put():
pm: gitea+vikunja -> yes
cto: gitea+vikunja -> yes
coder: gitea+vikunja -> yes
reviewer: gitea+vikunja -> yes
chief: none -> no
Candidate services / new credentials?.vikunja guard reaching put():
pm: gitea+vikunja -> yes
cto: gitea+vikunja -> yes
coder: gitea+vikunja -> yes
reviewer: gitea+vikunja -> yes
chief: gitea -> no (has no vikunja credential)
Both sets are exactly [pm, cto, coder, reviewer], and the original put() file/token arguments and body are byte-identical. The separate tracker.sync put remains unchanged. The new guard skips only absent vikunja credentials; a present but invalid vikunja reference still reaches the existing setup call and fails as before.
Byte reconstruction and assertion preservation
For each changed test file, statically remove exactly the added credential statements
and reverse only the allowed tracker guard. The result equals babae6adc byte-for-byte.
This proves every preexisting assertion and other source byte is untouched by B1:
packages/bus/tests/reload.test.mjs: 2 credential insertions; inverse reconstruction matches babae6adc exactly
packages/business/tests/business.test.mjs: 2 credential insertions; inverse reconstruction matches babae6adc exactly
packages/business/tests/cli.test.mjs: 1 credential insertions; inverse reconstruction matches babae6adc exactly
packages/business/tests/instance-settings.test.mjs: 1 credential insertions; inverse reconstruction matches babae6adc exactly
packages/business/tests/library-projects-protected.test.mjs: 1 credential insertions; inverse reconstruction matches babae6adc exactly
packages/business/tests/library-seats.test.mjs: 3 credential insertions; inverse reconstruction matches babae6adc exactly
packages/business/tests/resolve.test.mjs: 1 credential insertions; inverse reconstruction matches babae6adc exactly
packages/cli/tests/case2-install.test.mjs: 4 credential insertions; inverse reconstruction matches babae6adc exactly
packages/cli/tests/launcher.test.mjs: 1 credential insertions; inverse reconstruction matches babae6adc exactly
packages/cli/tests/thread-launch.test.mjs: 4 credential insertions; inverse reconstruction matches babae6adc exactly
packages/cli/tests/trackers-boot.test.mjs: 2 credential insertions; inverse reconstruction matches babae6adc exactly after reversing the sole mos-1582 guard change
packages/control-board/tests/creative-hidden.test.mjs: 2 credential insertions; inverse reconstruction matches babae6adc exactly
packages/discord/tests/library-seat.test.mjs: 2 credential insertions; inverse reconstruction matches babae6adc exactly
Exact full-base word diffs
The following are the requested literal git diff --word-diff=porcelain e0c6142f3
outputs for every B1 base file. B1 introduces zero removed tokens except the
expressly approved tracker guard. Two files also retain earlier approved r2 hunks:
business.test's preexisting ideas credential insertion replaces the punctuation
token "ideas" with "ideas",; instance-settings retains the mos-1332 gitea service
expectation and mos-1330 creative fixture insertions. Those were present unchanged
at babae6adc before B1; they are not unreported B1 deletions. The incremental
word-diff in b1-incremental-word-diff.txt isolates this, and the inverse byte proof
above checks all other bytes. Full line diff is also retained as b1-base-diff.txt.
Command: git diff --no-color --word-diff=porcelain e0c6142f3 -- packages/bus/tests/reload.test.mjs
diff --git a/packages/bus/tests/reload.test.mjs b/packages/bus/tests/reload.test.mjs
index 091b37b26..342d578d0 100644
--- a/packages/bus/tests/reload.test.mjs
+++ b/packages/bus/tests/reload.test.mjs
@@ -194,7 +194,7 @@ test('T14 a file whose project root differs from the boot copy is not reloaded,
});
~
~ test('T14 a file whose library mapping differs from the boot copy is not reloaded, because the mirror is ensured at start', async (t) => { ~ const f = await setup(t, doc => { +doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; doc.projects.books = mappingEntry(); }); ~ const doc = JSON.parse(readFileSync(f.file, 'utf8')); ~ doc.projects.books.branch = 'other'; ~ writeFileSync(f.file, JSON.stringify(doc, null, 2) + '\n', { mode: 0o600 }); ~ @@ -202,7 +202,7 @@ test('T14 a file whose library mapping differs from the boot copy is not reloade assert.equal(added.restart, true); ~ assert.equal(f.reloads.length, 0); ~ // The same library entry reloads. ~ const g = await setup(t, doc => { +doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; doc.projects.books = mappingEntry(); }); ~ assert.equal(g.ask('instances.set', { revision: g.revision(), instance: 'sec-1', op: 'add', definition: 'security-reviewer' }).restart, false); ~ assert.equal(g.reloads.length, 1); ~ }); ~
Command: git diff --no-color --word-diff=porcelain e0c6142f3 -- packages/business/tests/business.test.mjs
diff --git a/packages/business/tests/business.test.mjs b/packages/business/tests/business.test.mjs
index 9d4eda831..f78789250 100644
--- a/packages/business/tests/business.test.mjs
+++ b/packages/business/tests/business.test.mjs
@@ -6,6 +6,7 @@ import { join } from "node:path";
import { pathToFileURL } from "node:url";
~
import { BusinessError, businessFilePath, configDir, loadBusiness, validateBusinessDocument } from "../src/index.mjs";
~
import { THREAD_IDLE_SECONDS } from "../src/business.mjs";
~
+import { CREATIVE_DEFINITIONS } from "../src/vocabulary.mjs";
~
import { launchDoc, businessDoc, REPO, REPO_ROLES, rolesCopy, tmp, writeJson } from "./helpers.mjs";
~
~ test('C2-04: library mappings load without roots, remain frozen, and retain mapping refusals', async t => { ~ @@ -14,6 +15,7 @@ test('C2-04: library mappings load without roots, remain frozen, and retain mapp 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 }; ~
+doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ const loaded = validateBusinessDocument(doc, file, { rolesDir: REPO_ROLES }); ~ const { checkMapping } = await import('../../library/src/mapping.mjs'); ~ assert.deepEqual(loaded.projects.books, checkMapping(mappingEntry())); ~ @@ -41,6 +43,7 @@ test('C2-04: an otherwise valid publish grant cannot name a library repo', async 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.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ 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/); ~ @@ -273,28 +276,58 @@ test("the shipped example refuses as written and validates once filled in", () = assert.equal(id, 15); ~ }); ~
~
+// Row 285 (C2-08b, #1790, mos-1330): a creative definition declares gitea, so its instance names
~
+// the reference. The store form needs no token file, and the bus reads a missing one as no token.
~
+const CREATIVE_GITEA = Object.freeze({ gitea: Object.freeze({ store: true, rotateBy: "2099-01-01" }) });
~
~
// Row 213 (C2-08, #1714), deviation D1: the persona vars sit on a creative instance only, and
~
// both or neither. The var checks themselves are vars.mjs's.
~
test("persona vars: agent layer, creative definition only, both or neither", () => {
~
const sha = "a".repeat(64);
~
const persona = { "persona.name": "Bean", "persona.sha256": sha };
~
const business = check((d) => { d.roles.bean = { definition: "companion",
+credentials: CREATIVE_GITEA,
vars: { ...persona } }; });
~
assert.deepEqual({ ...business.roles.bean.vars }, persona);
~
assert.doesNotThrow(() => check((d) => { d.roles.bean = { definition:
-"ideas"
+"ideas", credentials: CREATIVE_GITEA
}; }));
~
refuses(() => check((d) => { d.vars["persona.name"] = "Bean"; }), /persona.name can't be set at the business layer/);
~
refuses(() => check((d) => { d.roles.pm.vars = { ...d.roles.pm.vars, ...persona }; }),
~
/roles.pm.vars: persona vars need a creative definition (pm isn't one)/);
~
refuses(() => check((d) => { d.roles.chief.vars = { ...persona }; }), /chief-of-staff isn't one/);
~
for (const key of Object.keys(persona)) {
~
refuses(() => check((d) => { d.roles.bean = { definition: "research",
+credentials: CREATIVE_GITEA,
vars: { [key]: persona[key] } }; }),
~
/roles.bean.vars: persona.name and persona.sha256 are set together or not at all/);
~
}
~
for (const [key, value] of [["persona.name", "x".repeat(41)], ["persona.name", "Be\nan"], ["persona.name", "Be\u0007an"], ["persona.name", "Be\u2028an"], ["persona.name", "Be\u2029an"], ["persona.name", 7],
~
["persona.sha256", "A".repeat(64)], ["persona.sha256", sha.slice(1)], ["persona.sha256", ${sha}0]]) {
~
refuses(() => check((d) => { d.roles.bean = { definition: "companion",
+credentials: CREATIVE_GITEA,
vars: { ...persona, [key]: value } }; }), new RegExp(variable ${key.replace(".", "\\.")}), 2);
~
+} ~ +}); ~ ~ +// Row 285 (C2-08b, #1790, mos-1330): the chief and each creative definition declare gitea, so an ~ +// instance without the reference refuses. Amendment 1 (mos-1580, sage-4060): the chief ~ +// requires its reference only in a library business; creative definitions always require it. ~ +test("row 285: a chief or creative instance without credentials.gitea refuses at load", async () => { ~
- const { mappingEntry } = await import("../../library/tests/helpers.mjs"); ~
- refuses(() => check((d) => { d.projects.books = mappingEntry(); delete d.roles.chief.credentials; }), ~
- /chief-library-gitea-required: .*roles.chief.credentials/); ~
- for (const definition of CREATIVE_DEFINITIONS) { ~
- refuses(() => check((d) => { d.roles.bean = { definition }; }), ~
-
/roles\.bean\.credentials must reference exactly the services its role definition needs \(gitea; got none\)/);
~
- assert.doesNotThrow(() => check((d) => { d.roles.bean = { definition, credentials: CREATIVE_GITEA }; }), definition); ~ } ~ }); ~
~ +// Row 285 (C2-08b, brief): a creative instance may carry identity and publish, under the rules at ~ +// business.mjs:155-166, which the grant path reads. The grant itself still refuses it (#giteaRole). ~ +test("row 285: a creative instance with identity and publish loads", () => { ~
- const identity = { name: "Bean", email: "[email protected]", gitea: { url: "https://git.example", user: "acme-bean" } }; ~
- const business = check((d) => { ~
- d.projects.stack.remote = "https://git.example/acme/stack"; ~
- d.roles.bean = { definition: "companion", credentials: CREATIVE_GITEA, identity, publish: ["stack"] }; ~
- }); ~
- assert.deepEqual({ ...business.roles.bean.identity, gitea: { ...business.roles.bean.identity.gitea } }, identity); ~
- assert.deepEqual([...business.roles.bean.publish], ["stack"]); ~ +}); ~ ~ // Row 194 (#1692, D2.5, T17): the per-agent forbid and the retired list. ~ test("row 194 keep, noHire and retired validate, and a file without them loads as before", () => { ~ const plain = check(); ~
Command: git diff --no-color --word-diff=porcelain e0c6142f3 -- packages/business/tests/cli.test.mjs
diff --git a/packages/business/tests/cli.test.mjs b/packages/business/tests/cli.test.mjs
index 3aa1d52ee..beb367f8c 100644
--- a/packages/business/tests/cli.test.mjs
+++ b/packages/business/tests/cli.test.mjs
@@ -11,7 +11,7 @@ const CLI = join(REPO, "packages", "business", "src", "cli.mjs");
test('C2-04: business validate and resolve skip a library before code projects and credential checks', async t => {
~
const { mappingEntry } = await import('../../library/tests/helpers.mjs');
~
const { rmSync } = await import('node:fs');
~
const s = setup(doc => {
+doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } };
doc.projects = { books: mappingEntry(), ...doc.projects }; });
~
t.after(() => rmSync(s.root, { recursive: true, force: true }));
~
writeJson(projectFilePath(s.doc.projects.stack.root), { projectVersion: 1, id: 'stack', vars: { 'tracker.project': 3 } });
~
const checked = run(s, 'validate', 'acme');
~
Command: git diff --no-color --word-diff=porcelain e0c6142f3 -- packages/business/tests/instance-settings.test.mjs
diff --git a/packages/business/tests/instance-settings.test.mjs b/packages/business/tests/instance-settings.test.mjs
index e85366562..54c22e0e0 100644
--- a/packages/business/tests/instance-settings.test.mjs
+++ b/packages/business/tests/instance-settings.test.mjs
@@ -9,7 +9,7 @@ import { mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync }
import { join } from "node:path";
~
import { instanceSettings } from "../src/instance-settings.mjs";
~
import { projectFilePath } from "../src/project.mjs";
~
import { businessDoc,
+FAR_DATE,
REPO, rolesCopy, systemConfig, systemFor, tmp, writeJson } from "./helpers.mjs";
~
~ const CLI = join(REPO, "packages", "business", "src", "cli.mjs"); ~ const roots = []; ~ @@ -22,7 +22,7 @@ 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.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; 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'); ~ @@ -286,7 +286,8 @@ test("row 213 a creative instance is the human's: add, vars and definition chang writeFileSync(join(f.root, "config", "personas", "acme", "bean.md"), text, { mode: 0o600 }); ~ const persona = { "persona.name": "Bean", "persona.sha256": createHash("sha256").update(text).digest("hex") }; ~ const view = f.settings.read("acme"); ~
+// Row 285 (mos-1332 item 4): the companion definition declares gitea. ~ assert.deepEqual(view.definitions.companion, { services: -[], +["gitea"], accepted: true }); ~ const add = { instance: "bean", op: "add", definition: "companion", vars: persona }; ~ for (const actor of ["chief-of-staff.chief", "tester"]) { ~ assert.throws(() => f.settings.set("acme", { revision: view.revision, ...add }, actor), e => e.code === "organization-creative-human-only", actor); ~ @@ -331,8 +332,8 @@ test("row 213 a creative instance is the human's: add, vars and definition chang // every actor, the human included. The listing's endProtected is that same check for its reader. ~ test("row 256 T1-T3, T5 the human deletes a creative instance, no other actor does, and the assistant stays", () => { ~ const f = fixture(doc => { ~ doc.roles.bean = { definition: -"companion" +"companion", credentials: { gitea: { store: true, rotateBy: FAR_DATE } } }; ~ doc.roles.muse = { definition: -"ideas" +"ideas", credentials: { gitea: { store: true, rotateBy: FAR_DATE } } }; ~ doc.roles.assistant = { definition: "assistant", holder: "mos" }; ~ }); ~ const del = (instance, actor) => () => f.settings.set("acme", { revision: f.settings.read("acme").revision, instance, op: "delete" }, actor); ~ @@ -377,7 +378,7 @@ test("row 256 T1-T3, T5 the human deletes a creative instance, no other actor do // instance can't be kept, launch.by or an arbiter, so the check it reaches is the last-listed one. ~ test("row 256 T4 the human's delete of the only listed instance, a creative one, is the last-listed refusal", () => { ~ const f = fixture(doc => { ~ doc.roles.bean = { definition: -"companion" +"companion", credentials: { gitea: { store: true, rotateBy: FAR_DATE } } }; ~ doc.launch.instances = ["bean"]; ~ }); ~ const bytes = readFileSync(f.file, "utf8"); ~
Command: git diff --no-color --word-diff=porcelain e0c6142f3 -- packages/business/tests/library-projects-protected.test.mjs
diff --git a/packages/business/tests/library-projects-protected.test.mjs b/packages/business/tests/library-projects-protected.test.mjs
index 51672bd7b..d4d09d94f 100644
--- a/packages/business/tests/library-projects-protected.test.mjs
+++ b/packages/business/tests/library-projects-protected.test.mjs
@@ -14,6 +14,7 @@ function fixture(t) {
books.universes.hybrid = { kind: 'hybrid', name: 'An invented crossover',
~
sources: ['harbor', 'second'], books: ['Hybrid Book'], playground: [], constraints: [], notes: 'Fixture only' };
~
doc.projects = { books, ...doc.projects };
~
+doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ const dir = join(root, 'config'), file = writeJson(join(dir, 'businesses/acme.json'), doc); ~ const writer = organizationWriter({ dir, rolesDir: rolesCopy(root) }); ~ // Give both snapshots an existing ordinary committed receipt to preserve. ~
Command: git diff --no-color --word-diff=porcelain e0c6142f3 -- packages/business/tests/library-seats.test.mjs
diff --git a/packages/business/tests/library-seats.test.mjs b/packages/business/tests/library-seats.test.mjs
index 3cd0f86cf..da76fdbc7 100644
--- a/packages/business/tests/library-seats.test.mjs
+++ b/packages/business/tests/library-seats.test.mjs
@@ -27,7 +27,9 @@ test("M7/M8: library seats come from library businesses, creative seats from the
const { root, dir } = fixture(t);
~
const doc = businessDoc(root, "acme");
~
doc.projects = { books: mappingEntry(), ...doc.projects };
~
+doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ doc.roles.bean = { definition: "companion" }; ~
+doc.roles.bean.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ writeJson(join(dir, "businesses", "acme.json"), doc); ~ const found = sets(dir); ~ assert.deepEqual([...found.librarySeats].sort(), ["bean", "chief", "coder", "cto", "pm", "reviewer"]); ~ @@ -39,6 +41,7 @@ test("M8: a business with no library project puts no seat in either set", (t) => const { root, dir } = fixture(t); ~ const doc = businessDoc(root, "other"); ~ doc.roles.bean = { definition: "companion" }; ~
+doc.roles.bean.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ writeJson(join(dir, "businesses", "other.json"), doc); ~ const found = sets(dir); ~ assert.equal(found.librarySeats.size, 0); ~
Command: git diff --no-color --word-diff=porcelain e0c6142f3 -- packages/business/tests/resolve.test.mjs
diff --git a/packages/business/tests/resolve.test.mjs b/packages/business/tests/resolve.test.mjs
index b1e50f349..2fa106053 100644
--- a/packages/business/tests/resolve.test.mjs
+++ b/packages/business/tests/resolve.test.mjs
@@ -31,7 +31,7 @@ const resolve = (s, instance) => resolveInstance({ system: s.system, business: s
test('C2-04: a library first in projects does not hide a later project layer', async t => {
~
const { mappingEntry } = await import('../../library/tests/helpers.mjs');
~
const { rmSync } = await import('node:fs');
~
const s = setup(doc => {
+doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } };
doc.projects = { books: mappingEntry(), ...doc.projects }; }, { vars: { 'tracker.project': 7 } });
~
t.after(() => rmSync(s.root, { recursive: true, force: true }));
~
const result = resolve(s, 'coder');
~
assert.equal(result.project, 'stack');
~
Command: git diff --no-color --word-diff=porcelain e0c6142f3 -- packages/cli/tests/case2-install.test.mjs
diff --git a/packages/cli/tests/case2-install.test.mjs b/packages/cli/tests/case2-install.test.mjs
index cc1142510..51b606bda 100644
--- a/packages/cli/tests/case2-install.test.mjs
+++ b/packages/cli/tests/case2-install.test.mjs
@@ -51,8 +51,11 @@ function world(t, { profile = "library" } = {}) {
for (const r of Object.values(doc.roles)) r.vars = { ...r.vars, harness: "pi" };
~
if (profile === "library") {
~
doc.projects.books = { ...mappingEntry(), user: "writer" };
~
+doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ doc.roles.bean = { definition: "companion", vars: { harness: "pi" } }; ~
+doc.roles.bean.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ doc.roles.chet = { definition: "companion", vars: { harness: "pi" } }; ~
+doc.roles.chet.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ } else doc.vars["bus.tester"] = true; ~ const input = writeJson(join(root, "input", "acme.json"), doc); ~ const staging = join(root, "staging"); ~ @@ -212,6 +215,7 @@ test("the factory install refuses a library project and bus.tester off, before a const x = world(t, { profile: "factory" }); ~ const doc = JSON.parse(readFileSync(x.input, "utf8")); ~ doc.projects.books = { ...mappingEntry(), user: "writer" }; ~
+doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ writeJson(x.input, doc); ~ refused(install(x, { profile: "factory" }), /profile-library-business/); ~ delete doc.projects.books; ~
Command: git diff --no-color --word-diff=porcelain e0c6142f3 -- packages/cli/tests/launcher.test.mjs
diff --git a/packages/cli/tests/launcher.test.mjs b/packages/cli/tests/launcher.test.mjs
index baabd843e..eeca18eb0 100644
--- a/packages/cli/tests/launcher.test.mjs
+++ b/packages/cli/tests/launcher.test.mjs
@@ -1,4 +1,4 @@
import {
+FAR_DATE,
launchDoc } from "../../business/tests/helpers.mjs";
~
// The S6 launcher inside a real bus host: real broker child, real runners
~
// in the bwrap sandbox, the fake adapter from packages/harness standing in for the
~
// harness. The chief of staff launches a coder through its launch tool (row 119: the
~
@@ -32,7 +32,7 @@ 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.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; 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); ~ @@ -766,7 +766,7 @@ test("row 64 a role skill that isn't enabled refuses skill-not-enabled, and one test("row 213 a creative instance's persona is read from /personas: off its digest the launch fails with the mismatch as its reason", { timeout: 30000 }, async (t) => { ~ const text = "Warm. PERSONA-MARKER-d2\n"; ~ const given = prepare(t, (doc) => { ~ doc.roles.bean = { definition: "companion", +credentials: { gitea: { store: true, rotateBy: FAR_DATE } }, vars: { harness: "pi", model: "claude-sonnet-5-5", thinking: "high", "persona.name": "Bean", "persona.sha256": createHash("sha256").update(text).digest("hex") } }; ~ doc.launch.instances.push("bean"); ~ return doc; ~ }); ~
Command: git diff --no-color --word-diff=porcelain e0c6142f3 -- packages/cli/tests/thread-launch.test.mjs
diff --git a/packages/cli/tests/thread-launch.test.mjs b/packages/cli/tests/thread-launch.test.mjs
index fa3adb866..3e313e49d 100644
--- a/packages/cli/tests/thread-launch.test.mjs
+++ b/packages/cli/tests/thread-launch.test.mjs
@@ -400,6 +400,7 @@ test("REQ-THREAD-1 REQ-LAUNCH-1 the chief can't launch the assistant outside a t
test('C2-09a: fromSession refuses a creative instance outside a thread without a sandbox', { timeout: 30000 }, async t => {
~
const prepared = prepare(t, { edit: doc => {
~
doc.roles.bean = { ...doc.roles.assistant, definition: 'companion' };
~
+doc.roles.bean.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ doc.launch.instances.push('bean'); ~ return doc; ~ } }); ~ @@ -465,7 +466,9 @@ test('C2-09a: creative thread messages start distinct runs and keep each instanc const vars = { ...doc.roles.assistant.vars }; ~ delete doc.roles.assistant; ~ doc.roles.bean = { definition: 'companion', vars: { ...vars } }; ~
+doc.roles.bean.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ doc.roles.chet = { definition: 'continuity', vars: { ...vars } }; ~
+doc.roles.chet.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ doc.launch.instances = ['coder', 'bean', 'chet']; ~ return doc; ~ } }); ~ @@ -501,6 +504,7 @@ test('C2-09a: creative thread messages start distinct runs and keep each instanc test('C2-09a: terminating one creative thread does not signal an unselected peer of the same instance', { skip, timeout: 90000 }, async t => { ~ const prepared = prepare(t, { sonnet: 2, idle: 60, edit: doc => { ~ doc.roles.bean = { ...doc.roles.assistant, definition: 'companion' }; ~
+doc.roles.bean.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ delete doc.roles.assistant; ~ doc.launch.instances = ['coder', 'bean']; ~ return doc; ~
Command: git diff --no-color --word-diff=porcelain e0c6142f3 -- packages/cli/tests/trackers-boot.test.mjs
diff --git a/packages/cli/tests/trackers-boot.test.mjs b/packages/cli/tests/trackers-boot.test.mjs
index 8d1a407c6..e7f50c947 100644
--- a/packages/cli/tests/trackers-boot.test.mjs
+++ b/packages/cli/tests/trackers-boot.test.mjs
@@ -14,7 +14,7 @@ import { fixture, tmp } from "./helpers.mjs";
~ test('C2-04: a library-only business with tracker.baseUrl boots without a project tracker', async t => { ~ const { mappingEntry } = await import('../../library/tests/helpers.mjs'); ~ const f = fixture(tmp(t), 'acme', doc => { +doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; doc.projects = { books: mappingEntry() }; return doc; }); ~ const warnings = []; ~ const boot = bootConfig({ system: loadSystem({ env: f.env }), businessId: 'acme', env: f.env, warn: text => warnings.push(text) }); ~ assert.equal(boot.trackers, undefined); ~ @@ -40,6 +40,7 @@ test("bootConfig trackers reach the S3 adapter in the real broker child, which g
~ const f = fixture(root, "acme", (doc) => { ~ doc.projects = { books: mappingEntry(), ...doc.projects }; ~
+doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ doc.vars["tracker.baseUrl"] = srv.url; ~ doc.tracker.sync.botId = bots.sync; ~ // The chief of staff (row 119) has no tracker bot. ~ @@ -51,7 +52,7 @@ test("bootConfig trackers reach the S3 adapter in the real broker child, which g chmodSync(file, 0o600); ~ }; ~ put(f.doc.tracker.sync.credentials.vikunja.file, fake.token(bots.sync, SCOPES.sync)); ~ for (const r of Object.keys(f.doc.roles)) if -(f.doc.roles[r].credentials) +(f.doc.roles[r].credentials?.vikunja) put(f.doc.roles[r].credentials.vikunja.file, fake.token(bots[r], r === "pm" ? SCOPES.pm : SCOPES.worker)); ~ writeJson(join(root, "project", ".mosaic", "project.json"), { projectVersion: 1, id: "stack", vars: { "tracker.project": project } }); ~
~ mkdirSync(f.dataRoot, { recursive: true, mode: 0o700 }); ~
Command: git diff --no-color --word-diff=porcelain e0c6142f3 -- packages/control-board/tests/creative-hidden.test.mjs
diff --git a/packages/control-board/tests/creative-hidden.test.mjs b/packages/control-board/tests/creative-hidden.test.mjs
index c2abd348e..12e16866e 100644
--- a/packages/control-board/tests/creative-hidden.test.mjs
+++ b/packages/control-board/tests/creative-hidden.test.mjs
@@ -20,7 +20,9 @@ function fixture(t) {
const dir = join(root, "config");
~
const doc = businessDoc(root, "acme");
~
doc.projects = { books: mappingEntry(), ...doc.projects };
~
+doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ doc.roles.bean = { definition: "companion" }; ~
+doc.roles.bean.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ writeJson(join(dir, "businesses", "acme.json"), doc); ~ const threadDir = join(root, "data", "threads", "acme", "t1", "session"); ~ mkdirSync(threadDir, { recursive: true }); ~
Command: git diff --no-color --word-diff=porcelain e0c6142f3 -- packages/discord/tests/library-seat.test.mjs
diff --git a/packages/discord/tests/library-seat.test.mjs b/packages/discord/tests/library-seat.test.mjs
index 315f69698..a7ac869e5 100644
--- a/packages/discord/tests/library-seat.test.mjs
+++ b/packages/discord/tests/library-seat.test.mjs
@@ -31,7 +31,9 @@ function setup(overrides = {}) {
function business(s, { library, role = "sage", definition = "companion" }) {
~
const doc = businessDoc(s.root, "acme");
~
if (library) doc.projects = { books: mappingEntry(), ...doc.projects };
~
+if (library) doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ doc.roles[role] = { definition }; ~
+doc.roles[role].credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ writeJson(join(s.root, "businesses", "acme.json"), doc); ~ } ~
~
Results: NOT RUN. Candidate is a pushed build for the next CLEAR, not accepted or green.
r4 replay onto landed 296+217 (2026-10-24T11:24:17Z, sage-4078)
New branch magica/row285-r4 starts at d0a6a87cd. All twelve commits from
b19ffa04f..eee8ad776 were cherry-picked, through replay tip 826d6e1d3.
magica/row285-r3 is retained unchanged; no force-push.
Only conflicts: BUILD-LOG.md and docs/SESSIONS.md at the first Magica evidence
commit. Keep all landed Lena/Beakley entries, then append all Magica entries.
Both resolved files retain the complete d0a6a87cd blob as an exact byte prefix.
No source, test, fixture, schema or authority conflict required manual resolution.
Source auto-merges preserve row217's broker citation guard, retry/page handling
and business.mjs replyLimits top-level key. Comparing r3→r4 business.mjs shows
only that landed replyLimits key; broker differs only by landed row217 work.
Statically compared every packages/roles path: added/removed lines relative to
each assigned base are exactly identical for all row285 product/test changes.
Every changed test file equals the r3 tip byte-for-byte. Case1 document/test
and business/tests/helpers remain byte-identical to e0c6142f3.
B1 invariants persist: 26 credential statements and the sole approved Vikunja
guard; no assertion edits; tracker put set remains pm,cto,coder,reviewer.
Post-replay e0c6142f3 full-file and word diffs regenerated in b1-base-diff.txt
and b1-base-word-diff.txt. The incremental diff now uses c53ea7d12, the
replayed amendment predecessor. Prior approved r2 token differences noted
above remain the only full-base exceptions besides the mos-1582 guard.
No tests/npm or queue operations run. Earlier r3 gate logs remain historical; r4 has no verification result. On CLEAR, reinstall root/webui locally and rerun the whole six-suite/config gate plus all mutants, including M10.
Requested range-diff (also r4-range-diff.txt): Command: git range-diff b19ffa04f..eee8ad776 d0a6a87cd..826d6e1d3
1: ca90d28bd = 1: 6ea4e3d37 row 285: C2-08b, creative roles hold library.write and the gitea credential, the chief of staff a read-scoped gitea credential; #giteaRole refuses the chief (#1790, mos-1309 item 5, sage-2915, sage-2921)
2: 362d1ebe3 = 2: 5e8e5f8a9 row 285: fixtures, example and README give the chief and creative instances their gitea reference (#1790, mos-1330)
3: 052e094e0 = 3: 86322bea2 row 285: a chief-of-staff or creative instance that names publish refuses at load, keeping today's N10 refusal; instance-settings :289 follows the companion's gitea (#1790, mos-1332)
4: 68e6d4588 = 4: 02fdae405 row 285: webby-0178 early read, drop the stale creative publish comment and name the example's test readers (#1790)
5: 299a8027c = 5: ee81d2ae6 row 285: mos-1333, withdraw the publish fence; N10 option (a) with an assistant instance; a chief with its gitea ref, identity and publish loads; restore the creative publish test; BUILD.md gate scope (sage-2946) (#1790)
6: 2773b0151 = 6: 059cf04ea row 285: library.write joins ACTIONS and ROUTED in the business vocabulary and the broker under PRD 1.16 REQ-WAIT-3 and REQ-LIB-6, with a hard-waits test; BUILD.md records the r2 rebase, range-diff and drift check (#1790, sage-3578)
7: 644bcaa16 = 7: 01dfecc1f row 285: BUILD.md records N1, the creative-only library.write refusal as a follow-up, and the round scope (#1790, sage-3593)
8: 87b7547f8 ! 8: 9f7adb03e docs: row 285 r3 replay and static drift evidence before CLEAR (#1790, sage-4039)
@@ Commit message
docs: row 285 r3 replay and static drift evidence before CLEAR (#1790, sage-4039)
## BUILD-LOG.md ##
-@@ BUILD-LOG.md: remain; no live state, schema or bus policy change.
+@@ BUILD-LOG.md: claim. Receipts and limitations in agents/lena/work/queue-296/BUILD.md and run-r
+ 2026-10-24 | Beakley (88b97f65) | Row 217 round 2, sage-4037 | Rebased published dde5b8496 onto e0c6142f3 on new beakley/row217-r2; both append-log histories retained. Conflicts preserve landed grant dispatch, revocation hook and lookup exports. Added E4 citation-unavailable product path and real supporting-scope/index comparison tests after row283 8d2856ee3. Untested: no Node/npm/tests/mutants/build; ready for Sage CLEAR after Lena296. Full range-diff and honest discarded local rebase correction in agents/beakley/work/queue-217/BUILD.md.
- 2026-10-24 | Goldie | Row265 / #1770 verified (mos-1567, sage-3942) | Approved correction adds solely address import pin + Row265 comment to project-runtime.test and one pure-source RUNNER_FILES mount; new block checks parser has no imports. Serialized fresh-short-TMP timeout-k10: unchanged sandbox10/10, parser15/15, rooms18/18, full bus957/957, twelve named refusal mutants killed (each Node1, driver0), restored parser15/15 + rooms18/18. All positives zero fail/skip/cancel; every mutation restored full broker SHA71b32ee4. Old first-red evidence retained, no other old-test change. Slot returned goldie-0034; Boyd packet explicitly includes mount-list review, candidate push next.
- 2026-10-24T07:18:53Z | Sage | Row 327 (#1825, Bradford, Poe and Dewey) LANDED 68c08b4e7. Before: refactor at 94d9e90a6; the push guard was a scratch script with no reviewed-binary check. After: scripts/push-check.sh and scripts/test-push-check.sh on refactor, 3 commits cherry-picked onto 6a5e12511 with blobs equal to the round 3 tip d858c9f8b, plus doc commits 76f84465f and 68c08b4e7. Binaries are found by numstat or a NUL in the first 8000 committed bytes, regardless of attributes; each needs its sha256 and path in an approved latest-round candidate; an unconfirmed queue tail exits 2. Reviews: Poe c31525 rev 3882, Dewey c31526 rev 3883. Gate: 1st run 06:57Z RED, not the candidate: canonical node_modules was empty from 05:45:15Z (sage-4023). Rerun with its own root npm ci GREEN 07:15:49Z: 17 package suites 0 failures (cli 986, plugins 119, webui 418), 11 scripts exit 0, push-check 6 mutants KILLED; skips are the queue canonical-root check and the row 244 live provider cases. The landed push-check.sh passed its own push (NO_BINARY, NO_ATTRIBUTION, PUSH_READY). mos-1575: gates install their own node_modules; canonical restored with npm ci (128 packages).
-+
+ 2026-10-24T10:21Z | Beakley (88b97f65) | Row 217 round2 slot verified, sage-4042/4043 | Source 2d274a5b6: touched57/57, whole library142/142 business270/270 bus974/974 cli988/988 harness172/172 seat218/218, all zero fail/skip/cancel. M1-M5 killed, controls/restored controls green, product hashes restored after each; E4 RED stand-in observed. Only first-red was new runtime fixture invalid-authority, corrected and retained in receipts; no old test failed/edited. Local root/webui npm ci, short TMPDIR, timeout-k10; no canonical npm/rm or module link. Full evidence agents/beakley/work/queue-217/run-r2; Sage owns scripts landing gate and formal review.
+2026-10-24T10:02Z | Magica | Row 285 / #1790 r3 before/after (sage-4039, mos-1542) | Before: assigned magica/row285-r3 at b19ffa04f, Scrooge r2 untested at 53db6b7ca. After: seven commits cherry-picked through 644bcaa16; five named overlaps auto-merge preserving newer base changes. Range-diff six '=', one context-only '!'; six patch IDs identical, fixture patch ID differs with upstream import context, exact test added/removed-line comparison identical for all changed tests. business.mjs equals base; Scrooge BUILD equals r2. CREATIVE_KINDS absent in packages/roles/scripts; no 64-hex changed-path pin; 291 conservative reader candidates recorded. No npm or tests before Sage CLEAR; N1 remains follow-up. Own-branch evidence push next, not accepted/green or landed.
## agents/magica/work/queue-285/BUILD.md (new) ##
@@ agents/magica/work/queue-285/role-readers.txt (new)
## docs/SESSIONS.md ##
@@ docs/SESSIONS.md: are never rewritten or removed; corrections are new entries.
- 2026-10-24T04:27Z | Goldie (a13dd6d5-5e73-4b7d-8318-02abeff24940) | Row265 / #1770 C2-09b rooms | Goldie owns build, Boyd reviews under sage-3915. New goldie/row265 worktree at ec86f2c84, claim rev3814; room verbs/parser/new tests prepared, no old tests changed. Sage-3932 slot: new parser14/14 and rooms18/18 passed; whole bus in progress before refusal mutants, stop rule active.
- 2026-10-24T04:35Z | Goldie (a13dd6d5-5e73-4b7d-8318-02abeff24940) | Row265 / #1770 verified | First slot stopped at project-runtime import pin. mos-1567 narrowly authorizes pin and pure-source mount correction. sage-3942 rerun: sandbox10/10, parser15/15, rooms18/18, bus957/957, twelve refusal mutants killed/restored SHA71b32ee4, parser15/15 + rooms18/18 again. Slot returned goldie-0034; no further test runs. Boyd reviews RUNNER_FILES alongside rooms; own-branch push/claimant in-review next.
- 2026-10-24T07:18:53Z | Sage (1ef1e4f8) | Row 327 / #1825 push guard landed (mos-1572 option A, mos-1575) | Gate went red 06:57Z on an empty canonical node_modules (Glomgold's webui npm ci through a link to canonical, glomgold-0011); rerun with its own npm ci GREEN 07:15:49Z on 1bd214e38; pushed 68c08b4e7 07:18:03Z; #1825 closed c31530; canonical restored (128 packages); brief template rule 4db23a51f | landed
+ 2026-10-24 | Beakley (88b97f65) | Row 217 round 2 under sage-4037 | New beakley/row217-r2 rebased onto e0c6142f3, retained both log histories, E4 product fix and supporting/index tests drafted. No Node/npm/tests/mutants run; ready for CLEAR; local-only dependency installs required on CLEAR, old-test red goes to Sage.
+
+ 2026-10-24T10:21Z | Beakley (88b97f65) | Row217 #1718 round2 slot | All touched57 and six whole suites2764 pass, zero skips/cancels; M1-M5 killed/restored, E4 RED stand-in observed. First-new runtime fixture red recorded and corrected; no old-test change/failure. Evidence in agents/beakley/work/queue-217/run-r2. Verified for review on beakley/row217-r2; Sage landing scripts/review remain.
+2026-10-24T10:02Z | Magica (483bbea5-e548-4c97-9b85-8f29ba81e427) | Row 285 / #1790 r3 replay, sage-4039 | Seven Scrooge commits replayed onto b19ffa04f; five overlaps auto-merged and inspected; range-diff, stable patch IDs and 291 conservative reader inventory in agents/magica/work/queue-285/BUILD.md. Every test added/removed line matches r2; N1 deferred. Canonical queue move magica-285-start rev3889 succeeded. No npm/tests; own-branch push for CLEAR next.
9: d76021656 < -: --------- docs: correct row 285 evidence timestamps with append-only receipts
-: --------- > 9: 405b05e91 docs: correct row 285 evidence timestamps with append-only receipts
10: 66a800e15 = 10: 0882bd997 docs: trim range-diff evidence trailing whitespace
11: babae6adc ! 11: c53ea7d12 row 285: require chief gitea exactly for library businesses (mos-1580, sage-4059, sage-4060)
@@ Commit message
row 285: require chief gitea exactly for library businesses (mos-1580, sage-4059, sage-4060)
## BUILD-LOG.md ##
-@@ BUILD-LOG.md: remain; no live state, schema or bus policy change.
+@@ BUILD-LOG.md: claim. Receipts and limitations in agents/lena/work/queue-296/BUILD.md and run-r
2026-10-24T10:02Z | Magica | Row 285 / #1790 r3 before/after (sage-4039, mos-1542) | Before: assigned magica/row285-r3 at b19ffa04f, Scrooge r2 untested at 53db6b7ca. After: seven commits cherry-picked through 644bcaa16; five named overlaps auto-merge preserving newer base changes. Range-diff six '=', one context-only '!'; six patch IDs identical, fixture patch ID differs with upstream import context, exact test added/removed-line comparison identical for all changed tests. business.mjs equals base; Scrooge BUILD equals r2. CREATIVE_KINDS absent in packages/roles/scripts; no 64-hex changed-path pin; 291 conservative reader candidates recorded. No npm or tests before Sage CLEAR; N1 remains follow-up. Own-branch evidence push next, not accepted/green or landed.
2026-10-24T09:58:36Z | Magica | Row 285 timestamp correction | The preceding Magica entry marked 10:02Z used an incorrect timestamp; replay/evidence commit 87b7547f8 occurred before the measured 09:58:22Z push start. Technical evidence is unchanged.
12: eee8ad776 ! 12: 826d6e1d3 row 285: align library and creative fixture credential data under B1 (mos-1581, mos-1582)
@@ Commit message
row 285: align library and creative fixture credential data under B1 (mos-1581, mos-1582)
## BUILD-LOG.md ##
-@@ BUILD-LOG.md: remain; no live state, schema or bus policy change.
+@@ BUILD-LOG.md: claim. Receipts and limitations in agents/lena/work/queue-296/BUILD.md and run-r
2026-10-24T10:32:02Z | Magica | Row285 / #1790 gate STOP (sage-4048) | Before: pushed66a800e15, no tests. After: own root/webui npm ci, short scratch TMPDIR, whole files serial timeout-k10; bus958/958 green (108 files), business partial80pass/4fail, first red old row323 case1-business-file tests57/86/95/105 because committed Case1 chief lacks required gitea ref. No more tests/mutants or source edits. Static diagnosis also finds old empty-credential assertions81/112/114, requiring a specific owner ruling. Sage notified magica-0002. No in-review move or green claim.
2026-10-24T10:42:28Z | Magica | Row285 / #1790 Amendment1 before/after | Before: unconditional chief gitea broke row323. After: chief-only library conditional plus named required-reference refusal, checkCredentialMap unchanged; new three-case test file; own helper/resolve fixture hunks restored to base, own chief/business/identity hunks reconciled under sage-4060. Case1 doc/test byte-identical. M10 planned against new no-library positive and old Case1 doc test. No tests run under held slot; not green/accepted. Residual base library fixture references need authority alignment before re-CLEAR.
The non-equal entries are log-only context changes after preserving landed append entries; git pairs the timestamp-only doc commit as delete/add because its two log hunks acquired different surrounding context. Product/test deltas were independently compared rather than inferred from those pairing labels.
Regenerated post-replay base word diffs, exact command output:
Command: git diff --no-color --word-diff=porcelain e0c6142f3 -- packages/bus/tests/reload.test.mjs
diff --git a/packages/bus/tests/reload.test.mjs b/packages/bus/tests/reload.test.mjs
index 091b37b26..342d578d0 100644
--- a/packages/bus/tests/reload.test.mjs
+++ b/packages/bus/tests/reload.test.mjs
@@ -194,7 +194,7 @@ test('T14 a file whose project root differs from the boot copy is not reloaded,
});
~
~ test('T14 a file whose library mapping differs from the boot copy is not reloaded, because the mirror is ensured at start', async (t) => { ~ const f = await setup(t, doc => { +doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; doc.projects.books = mappingEntry(); }); ~ const doc = JSON.parse(readFileSync(f.file, 'utf8')); ~ doc.projects.books.branch = 'other'; ~ writeFileSync(f.file, JSON.stringify(doc, null, 2) + '\n', { mode: 0o600 }); ~ @@ -202,7 +202,7 @@ test('T14 a file whose library mapping differs from the boot copy is not reloade assert.equal(added.restart, true); ~ assert.equal(f.reloads.length, 0); ~ // The same library entry reloads. ~ const g = await setup(t, doc => { +doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; doc.projects.books = mappingEntry(); }); ~ assert.equal(g.ask('instances.set', { revision: g.revision(), instance: 'sec-1', op: 'add', definition: 'security-reviewer' }).restart, false); ~ assert.equal(g.reloads.length, 1); ~ }); ~
Command: git diff --no-color --word-diff=porcelain e0c6142f3 -- packages/business/tests/business.test.mjs
diff --git a/packages/business/tests/business.test.mjs b/packages/business/tests/business.test.mjs
index 9d4eda831..f78789250 100644
--- a/packages/business/tests/business.test.mjs
+++ b/packages/business/tests/business.test.mjs
@@ -6,6 +6,7 @@ import { join } from "node:path";
import { pathToFileURL } from "node:url";
~
import { BusinessError, businessFilePath, configDir, loadBusiness, validateBusinessDocument } from "../src/index.mjs";
~
import { THREAD_IDLE_SECONDS } from "../src/business.mjs";
~
+import { CREATIVE_DEFINITIONS } from "../src/vocabulary.mjs";
~
import { launchDoc, businessDoc, REPO, REPO_ROLES, rolesCopy, tmp, writeJson } from "./helpers.mjs";
~
~ test('C2-04: library mappings load without roots, remain frozen, and retain mapping refusals', async t => { ~ @@ -14,6 +15,7 @@ test('C2-04: library mappings load without roots, remain frozen, and retain mapp 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 }; ~
+doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ const loaded = validateBusinessDocument(doc, file, { rolesDir: REPO_ROLES }); ~ const { checkMapping } = await import('../../library/src/mapping.mjs'); ~ assert.deepEqual(loaded.projects.books, checkMapping(mappingEntry())); ~ @@ -41,6 +43,7 @@ test('C2-04: an otherwise valid publish grant cannot name a library repo', async 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.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ 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/); ~ @@ -273,28 +276,58 @@ test("the shipped example refuses as written and validates once filled in", () = assert.equal(id, 15); ~ }); ~
~
+// Row 285 (C2-08b, #1790, mos-1330): a creative definition declares gitea, so its instance names
~
+// the reference. The store form needs no token file, and the bus reads a missing one as no token.
~
+const CREATIVE_GITEA = Object.freeze({ gitea: Object.freeze({ store: true, rotateBy: "2099-01-01" }) });
~
~
// Row 213 (C2-08, #1714), deviation D1: the persona vars sit on a creative instance only, and
~
// both or neither. The var checks themselves are vars.mjs's.
~
test("persona vars: agent layer, creative definition only, both or neither", () => {
~
const sha = "a".repeat(64);
~
const persona = { "persona.name": "Bean", "persona.sha256": sha };
~
const business = check((d) => { d.roles.bean = { definition: "companion",
+credentials: CREATIVE_GITEA,
vars: { ...persona } }; });
~
assert.deepEqual({ ...business.roles.bean.vars }, persona);
~
assert.doesNotThrow(() => check((d) => { d.roles.bean = { definition:
-"ideas"
+"ideas", credentials: CREATIVE_GITEA
}; }));
~
refuses(() => check((d) => { d.vars["persona.name"] = "Bean"; }), /persona.name can't be set at the business layer/);
~
refuses(() => check((d) => { d.roles.pm.vars = { ...d.roles.pm.vars, ...persona }; }),
~
/roles.pm.vars: persona vars need a creative definition (pm isn't one)/);
~
refuses(() => check((d) => { d.roles.chief.vars = { ...persona }; }), /chief-of-staff isn't one/);
~
for (const key of Object.keys(persona)) {
~
refuses(() => check((d) => { d.roles.bean = { definition: "research",
+credentials: CREATIVE_GITEA,
vars: { [key]: persona[key] } }; }),
~
/roles.bean.vars: persona.name and persona.sha256 are set together or not at all/);
~
}
~
for (const [key, value] of [["persona.name", "x".repeat(41)], ["persona.name", "Be\nan"], ["persona.name", "Be\u0007an"], ["persona.name", "Be\u2028an"], ["persona.name", "Be\u2029an"], ["persona.name", 7],
~
["persona.sha256", "A".repeat(64)], ["persona.sha256", sha.slice(1)], ["persona.sha256", ${sha}0]]) {
~
refuses(() => check((d) => { d.roles.bean = { definition: "companion",
+credentials: CREATIVE_GITEA,
vars: { ...persona, [key]: value } }; }), new RegExp(variable ${key.replace(".", "\\.")}), 2);
~
+} ~ +}); ~ ~ +// Row 285 (C2-08b, #1790, mos-1330): the chief and each creative definition declare gitea, so an ~ +// instance without the reference refuses. Amendment 1 (mos-1580, sage-4060): the chief ~ +// requires its reference only in a library business; creative definitions always require it. ~ +test("row 285: a chief or creative instance without credentials.gitea refuses at load", async () => { ~
- const { mappingEntry } = await import("../../library/tests/helpers.mjs"); ~
- refuses(() => check((d) => { d.projects.books = mappingEntry(); delete d.roles.chief.credentials; }), ~
- /chief-library-gitea-required: .*roles.chief.credentials/); ~
- for (const definition of CREATIVE_DEFINITIONS) { ~
- refuses(() => check((d) => { d.roles.bean = { definition }; }), ~
-
/roles\.bean\.credentials must reference exactly the services its role definition needs \(gitea; got none\)/);
~
- assert.doesNotThrow(() => check((d) => { d.roles.bean = { definition, credentials: CREATIVE_GITEA }; }), definition); ~ } ~ }); ~
~ +// Row 285 (C2-08b, brief): a creative instance may carry identity and publish, under the rules at ~ +// business.mjs:155-166, which the grant path reads. The grant itself still refuses it (#giteaRole). ~ +test("row 285: a creative instance with identity and publish loads", () => { ~
- const identity = { name: "Bean", email: "[email protected]", gitea: { url: "https://git.example", user: "acme-bean" } }; ~
- const business = check((d) => { ~
- d.projects.stack.remote = "https://git.example/acme/stack"; ~
- d.roles.bean = { definition: "companion", credentials: CREATIVE_GITEA, identity, publish: ["stack"] }; ~
- }); ~
- assert.deepEqual({ ...business.roles.bean.identity, gitea: { ...business.roles.bean.identity.gitea } }, identity); ~
- assert.deepEqual([...business.roles.bean.publish], ["stack"]); ~ +}); ~ ~ // Row 194 (#1692, D2.5, T17): the per-agent forbid and the retired list. ~ test("row 194 keep, noHire and retired validate, and a file without them loads as before", () => { ~ const plain = check(); ~
Command: git diff --no-color --word-diff=porcelain e0c6142f3 -- packages/business/tests/cli.test.mjs
diff --git a/packages/business/tests/cli.test.mjs b/packages/business/tests/cli.test.mjs
index 3aa1d52ee..beb367f8c 100644
--- a/packages/business/tests/cli.test.mjs
+++ b/packages/business/tests/cli.test.mjs
@@ -11,7 +11,7 @@ const CLI = join(REPO, "packages", "business", "src", "cli.mjs");
test('C2-04: business validate and resolve skip a library before code projects and credential checks', async t => {
~
const { mappingEntry } = await import('../../library/tests/helpers.mjs');
~
const { rmSync } = await import('node:fs');
~
const s = setup(doc => {
+doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } };
doc.projects = { books: mappingEntry(), ...doc.projects }; });
~
t.after(() => rmSync(s.root, { recursive: true, force: true }));
~
writeJson(projectFilePath(s.doc.projects.stack.root), { projectVersion: 1, id: 'stack', vars: { 'tracker.project': 3 } });
~
const checked = run(s, 'validate', 'acme');
~
Command: git diff --no-color --word-diff=porcelain e0c6142f3 -- packages/business/tests/instance-settings.test.mjs
diff --git a/packages/business/tests/instance-settings.test.mjs b/packages/business/tests/instance-settings.test.mjs
index e85366562..54c22e0e0 100644
--- a/packages/business/tests/instance-settings.test.mjs
+++ b/packages/business/tests/instance-settings.test.mjs
@@ -9,7 +9,7 @@ import { mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync }
import { join } from "node:path";
~
import { instanceSettings } from "../src/instance-settings.mjs";
~
import { projectFilePath } from "../src/project.mjs";
~
import { businessDoc,
+FAR_DATE,
REPO, rolesCopy, systemConfig, systemFor, tmp, writeJson } from "./helpers.mjs";
~
~ const CLI = join(REPO, "packages", "business", "src", "cli.mjs"); ~ const roots = []; ~ @@ -22,7 +22,7 @@ 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.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; 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'); ~ @@ -286,7 +286,8 @@ test("row 213 a creative instance is the human's: add, vars and definition chang writeFileSync(join(f.root, "config", "personas", "acme", "bean.md"), text, { mode: 0o600 }); ~ const persona = { "persona.name": "Bean", "persona.sha256": createHash("sha256").update(text).digest("hex") }; ~ const view = f.settings.read("acme"); ~
+// Row 285 (mos-1332 item 4): the companion definition declares gitea. ~ assert.deepEqual(view.definitions.companion, { services: -[], +["gitea"], accepted: true }); ~ const add = { instance: "bean", op: "add", definition: "companion", vars: persona }; ~ for (const actor of ["chief-of-staff.chief", "tester"]) { ~ assert.throws(() => f.settings.set("acme", { revision: view.revision, ...add }, actor), e => e.code === "organization-creative-human-only", actor); ~ @@ -331,8 +332,8 @@ test("row 213 a creative instance is the human's: add, vars and definition chang // every actor, the human included. The listing's endProtected is that same check for its reader. ~ test("row 256 T1-T3, T5 the human deletes a creative instance, no other actor does, and the assistant stays", () => { ~ const f = fixture(doc => { ~ doc.roles.bean = { definition: -"companion" +"companion", credentials: { gitea: { store: true, rotateBy: FAR_DATE } } }; ~ doc.roles.muse = { definition: -"ideas" +"ideas", credentials: { gitea: { store: true, rotateBy: FAR_DATE } } }; ~ doc.roles.assistant = { definition: "assistant", holder: "mos" }; ~ }); ~ const del = (instance, actor) => () => f.settings.set("acme", { revision: f.settings.read("acme").revision, instance, op: "delete" }, actor); ~ @@ -377,7 +378,7 @@ test("row 256 T1-T3, T5 the human deletes a creative instance, no other actor do // instance can't be kept, launch.by or an arbiter, so the check it reaches is the last-listed one. ~ test("row 256 T4 the human's delete of the only listed instance, a creative one, is the last-listed refusal", () => { ~ const f = fixture(doc => { ~ doc.roles.bean = { definition: -"companion" +"companion", credentials: { gitea: { store: true, rotateBy: FAR_DATE } } }; ~ doc.launch.instances = ["bean"]; ~ }); ~ const bytes = readFileSync(f.file, "utf8"); ~
Command: git diff --no-color --word-diff=porcelain e0c6142f3 -- packages/business/tests/library-projects-protected.test.mjs
diff --git a/packages/business/tests/library-projects-protected.test.mjs b/packages/business/tests/library-projects-protected.test.mjs
index 51672bd7b..d4d09d94f 100644
--- a/packages/business/tests/library-projects-protected.test.mjs
+++ b/packages/business/tests/library-projects-protected.test.mjs
@@ -14,6 +14,7 @@ function fixture(t) {
books.universes.hybrid = { kind: 'hybrid', name: 'An invented crossover',
~
sources: ['harbor', 'second'], books: ['Hybrid Book'], playground: [], constraints: [], notes: 'Fixture only' };
~
doc.projects = { books, ...doc.projects };
~
+doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ const dir = join(root, 'config'), file = writeJson(join(dir, 'businesses/acme.json'), doc); ~ const writer = organizationWriter({ dir, rolesDir: rolesCopy(root) }); ~ // Give both snapshots an existing ordinary committed receipt to preserve. ~
Command: git diff --no-color --word-diff=porcelain e0c6142f3 -- packages/business/tests/library-seats.test.mjs
diff --git a/packages/business/tests/library-seats.test.mjs b/packages/business/tests/library-seats.test.mjs
index 3cd0f86cf..da76fdbc7 100644
--- a/packages/business/tests/library-seats.test.mjs
+++ b/packages/business/tests/library-seats.test.mjs
@@ -27,7 +27,9 @@ test("M7/M8: library seats come from library businesses, creative seats from the
const { root, dir } = fixture(t);
~
const doc = businessDoc(root, "acme");
~
doc.projects = { books: mappingEntry(), ...doc.projects };
~
+doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ doc.roles.bean = { definition: "companion" }; ~
+doc.roles.bean.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ writeJson(join(dir, "businesses", "acme.json"), doc); ~ const found = sets(dir); ~ assert.deepEqual([...found.librarySeats].sort(), ["bean", "chief", "coder", "cto", "pm", "reviewer"]); ~ @@ -39,6 +41,7 @@ test("M8: a business with no library project puts no seat in either set", (t) => const { root, dir } = fixture(t); ~ const doc = businessDoc(root, "other"); ~ doc.roles.bean = { definition: "companion" }; ~
+doc.roles.bean.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ writeJson(join(dir, "businesses", "other.json"), doc); ~ const found = sets(dir); ~ assert.equal(found.librarySeats.size, 0); ~
Command: git diff --no-color --word-diff=porcelain e0c6142f3 -- packages/business/tests/resolve.test.mjs
diff --git a/packages/business/tests/resolve.test.mjs b/packages/business/tests/resolve.test.mjs
index b1e50f349..2fa106053 100644
--- a/packages/business/tests/resolve.test.mjs
+++ b/packages/business/tests/resolve.test.mjs
@@ -31,7 +31,7 @@ const resolve = (s, instance) => resolveInstance({ system: s.system, business: s
test('C2-04: a library first in projects does not hide a later project layer', async t => {
~
const { mappingEntry } = await import('../../library/tests/helpers.mjs');
~
const { rmSync } = await import('node:fs');
~
const s = setup(doc => {
+doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } };
doc.projects = { books: mappingEntry(), ...doc.projects }; }, { vars: { 'tracker.project': 7 } });
~
t.after(() => rmSync(s.root, { recursive: true, force: true }));
~
const result = resolve(s, 'coder');
~
assert.equal(result.project, 'stack');
~
Command: git diff --no-color --word-diff=porcelain e0c6142f3 -- packages/cli/tests/case2-install.test.mjs
diff --git a/packages/cli/tests/case2-install.test.mjs b/packages/cli/tests/case2-install.test.mjs
index cc1142510..51b606bda 100644
--- a/packages/cli/tests/case2-install.test.mjs
+++ b/packages/cli/tests/case2-install.test.mjs
@@ -51,8 +51,11 @@ function world(t, { profile = "library" } = {}) {
for (const r of Object.values(doc.roles)) r.vars = { ...r.vars, harness: "pi" };
~
if (profile === "library") {
~
doc.projects.books = { ...mappingEntry(), user: "writer" };
~
+doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ doc.roles.bean = { definition: "companion", vars: { harness: "pi" } }; ~
+doc.roles.bean.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ doc.roles.chet = { definition: "companion", vars: { harness: "pi" } }; ~
+doc.roles.chet.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ } else doc.vars["bus.tester"] = true; ~ const input = writeJson(join(root, "input", "acme.json"), doc); ~ const staging = join(root, "staging"); ~ @@ -212,6 +215,7 @@ test("the factory install refuses a library project and bus.tester off, before a const x = world(t, { profile: "factory" }); ~ const doc = JSON.parse(readFileSync(x.input, "utf8")); ~ doc.projects.books = { ...mappingEntry(), user: "writer" }; ~
+doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ writeJson(x.input, doc); ~ refused(install(x, { profile: "factory" }), /profile-library-business/); ~ delete doc.projects.books; ~
Command: git diff --no-color --word-diff=porcelain e0c6142f3 -- packages/cli/tests/launcher.test.mjs
diff --git a/packages/cli/tests/launcher.test.mjs b/packages/cli/tests/launcher.test.mjs
index baabd843e..eeca18eb0 100644
--- a/packages/cli/tests/launcher.test.mjs
+++ b/packages/cli/tests/launcher.test.mjs
@@ -1,4 +1,4 @@
import {
+FAR_DATE,
launchDoc } from "../../business/tests/helpers.mjs";
~
// The S6 launcher inside a real bus host: real broker child, real runners
~
// in the bwrap sandbox, the fake adapter from packages/harness standing in for the
~
// harness. The chief of staff launches a coder through its launch tool (row 119: the
~
@@ -32,7 +32,7 @@ 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.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; 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); ~ @@ -766,7 +766,7 @@ test("row 64 a role skill that isn't enabled refuses skill-not-enabled, and one test("row 213 a creative instance's persona is read from /personas: off its digest the launch fails with the mismatch as its reason", { timeout: 30000 }, async (t) => { ~ const text = "Warm. PERSONA-MARKER-d2\n"; ~ const given = prepare(t, (doc) => { ~ doc.roles.bean = { definition: "companion", +credentials: { gitea: { store: true, rotateBy: FAR_DATE } }, vars: { harness: "pi", model: "claude-sonnet-5-5", thinking: "high", "persona.name": "Bean", "persona.sha256": createHash("sha256").update(text).digest("hex") } }; ~ doc.launch.instances.push("bean"); ~ return doc; ~ }); ~
Command: git diff --no-color --word-diff=porcelain e0c6142f3 -- packages/cli/tests/thread-launch.test.mjs
diff --git a/packages/cli/tests/thread-launch.test.mjs b/packages/cli/tests/thread-launch.test.mjs
index fa3adb866..3e313e49d 100644
--- a/packages/cli/tests/thread-launch.test.mjs
+++ b/packages/cli/tests/thread-launch.test.mjs
@@ -400,6 +400,7 @@ test("REQ-THREAD-1 REQ-LAUNCH-1 the chief can't launch the assistant outside a t
test('C2-09a: fromSession refuses a creative instance outside a thread without a sandbox', { timeout: 30000 }, async t => {
~
const prepared = prepare(t, { edit: doc => {
~
doc.roles.bean = { ...doc.roles.assistant, definition: 'companion' };
~
+doc.roles.bean.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ doc.launch.instances.push('bean'); ~ return doc; ~ } }); ~ @@ -465,7 +466,9 @@ test('C2-09a: creative thread messages start distinct runs and keep each instanc const vars = { ...doc.roles.assistant.vars }; ~ delete doc.roles.assistant; ~ doc.roles.bean = { definition: 'companion', vars: { ...vars } }; ~
+doc.roles.bean.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ doc.roles.chet = { definition: 'continuity', vars: { ...vars } }; ~
+doc.roles.chet.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ doc.launch.instances = ['coder', 'bean', 'chet']; ~ return doc; ~ } }); ~ @@ -501,6 +504,7 @@ test('C2-09a: creative thread messages start distinct runs and keep each instanc test('C2-09a: terminating one creative thread does not signal an unselected peer of the same instance', { skip, timeout: 90000 }, async t => { ~ const prepared = prepare(t, { sonnet: 2, idle: 60, edit: doc => { ~ doc.roles.bean = { ...doc.roles.assistant, definition: 'companion' }; ~
+doc.roles.bean.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ delete doc.roles.assistant; ~ doc.launch.instances = ['coder', 'bean']; ~ return doc; ~
Command: git diff --no-color --word-diff=porcelain e0c6142f3 -- packages/cli/tests/trackers-boot.test.mjs
diff --git a/packages/cli/tests/trackers-boot.test.mjs b/packages/cli/tests/trackers-boot.test.mjs
index 8d1a407c6..e7f50c947 100644
--- a/packages/cli/tests/trackers-boot.test.mjs
+++ b/packages/cli/tests/trackers-boot.test.mjs
@@ -14,7 +14,7 @@ import { fixture, tmp } from "./helpers.mjs";
~ test('C2-04: a library-only business with tracker.baseUrl boots without a project tracker', async t => { ~ const { mappingEntry } = await import('../../library/tests/helpers.mjs'); ~ const f = fixture(tmp(t), 'acme', doc => { +doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; doc.projects = { books: mappingEntry() }; return doc; }); ~ const warnings = []; ~ const boot = bootConfig({ system: loadSystem({ env: f.env }), businessId: 'acme', env: f.env, warn: text => warnings.push(text) }); ~ assert.equal(boot.trackers, undefined); ~ @@ -40,6 +40,7 @@ test("bootConfig trackers reach the S3 adapter in the real broker child, which g
~ const f = fixture(root, "acme", (doc) => { ~ doc.projects = { books: mappingEntry(), ...doc.projects }; ~
+doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ doc.vars["tracker.baseUrl"] = srv.url; ~ doc.tracker.sync.botId = bots.sync; ~ // The chief of staff (row 119) has no tracker bot. ~ @@ -51,7 +52,7 @@ test("bootConfig trackers reach the S3 adapter in the real broker child, which g chmodSync(file, 0o600); ~ }; ~ put(f.doc.tracker.sync.credentials.vikunja.file, fake.token(bots.sync, SCOPES.sync)); ~ for (const r of Object.keys(f.doc.roles)) if -(f.doc.roles[r].credentials) +(f.doc.roles[r].credentials?.vikunja) put(f.doc.roles[r].credentials.vikunja.file, fake.token(bots[r], r === "pm" ? SCOPES.pm : SCOPES.worker)); ~ writeJson(join(root, "project", ".mosaic", "project.json"), { projectVersion: 1, id: "stack", vars: { "tracker.project": project } }); ~
~ mkdirSync(f.dataRoot, { recursive: true, mode: 0o700 }); ~
Command: git diff --no-color --word-diff=porcelain e0c6142f3 -- packages/control-board/tests/creative-hidden.test.mjs
diff --git a/packages/control-board/tests/creative-hidden.test.mjs b/packages/control-board/tests/creative-hidden.test.mjs
index c2abd348e..12e16866e 100644
--- a/packages/control-board/tests/creative-hidden.test.mjs
+++ b/packages/control-board/tests/creative-hidden.test.mjs
@@ -20,7 +20,9 @@ function fixture(t) {
const dir = join(root, "config");
~
const doc = businessDoc(root, "acme");
~
doc.projects = { books: mappingEntry(), ...doc.projects };
~
+doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ doc.roles.bean = { definition: "companion" }; ~
+doc.roles.bean.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ writeJson(join(dir, "businesses", "acme.json"), doc); ~ const threadDir = join(root, "data", "threads", "acme", "t1", "session"); ~ mkdirSync(threadDir, { recursive: true }); ~
Command: git diff --no-color --word-diff=porcelain e0c6142f3 -- packages/discord/tests/library-seat.test.mjs
diff --git a/packages/discord/tests/library-seat.test.mjs b/packages/discord/tests/library-seat.test.mjs
index 315f69698..a7ac869e5 100644
--- a/packages/discord/tests/library-seat.test.mjs
+++ b/packages/discord/tests/library-seat.test.mjs
@@ -31,7 +31,9 @@ function setup(overrides = {}) {
function business(s, { library, role = "sage", definition = "companion" }) {
~
const doc = businessDoc(s.root, "acme");
~
if (library) doc.projects = { books: mappingEntry(), ...doc.projects };
~
+if (library) doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ doc.roles[role] = { definition }; ~
+doc.roles[role].credentials = { gitea: { ...doc.roles.coder.credentials.gitea } }; ~ writeJson(join(s.root, "businesses", "acme.json"), doc); ~ } ~
~
r4 collection under C1 (2026-10-24T12:01:10Z, sage-4080/4085/4086, mos-1584)
Input remains 0f6cdc861, base d0a6a87cd. Fresh own npm ci128/2 installed
without symlinks, short TMPDIR, MOSAIC_REQUIRE_EDITOR_BUILD=1. Initial
r4 stop is preserved in gate-r4/. C1 unchanged collection is gate-r4-collect/.
The driver first continued only named chief-reference errors, then stopped
on instance-settings ERR_ASSERTION per sage-4085. Sage-4086 explicitly
authorized collecting every remaining red, all six suites and all12 scripts.
No source/role/test edit, fix round or row285 mutant has run.
At this receipt all suites/scripts have run, except the first stack-release file hit the evidence driver's 300s cap. Its raw exit124/interrupted TAP is retained. It was still reporting passing subtests. A whole-file unchanged retry at1800s is in progress; final counts will be appended separately. All12 scripts/test-*.sh returned0, each timeout-k10/600. Dedicated federation acceptance passed1/1 zero skips and cleanup confirmed no child groups/ports/ sockets/units. Ordinary CLI's intentional federation wrapper skip is distinct. Editor provenance/rebuild passed6/6 zero skips with the required environment.
New-base static reader inventory (sage-4082)
All8 added test files and4 helper/fixture modules in e0c6142f3..d0a6a87cd were read/traced. Only citation-runtime validates a real library business:
- bus/tests/citation-runtime.test.mjs:15 sets projects.books; write16, validate17. A same-line chief credential insertion using coder's existing dummy gitea ref covers it, preserving every original token.
- bus/tests/citation-guard.test.mjs:165 writes businessDoc for organizationWriter, but that disk doc has only code projects.stack. Its citationWorld library is a separate synthetic broker business, not copied to disk. No insertion; adding chief gitea would violate the no-library extra-ref rule.
- business/tests/reply-limits.test.mjs:11 businessDoc only changes human/settings, never projects. No library, no insertion.
- cli/tests/federation-acceptance.test.mjs:96 businessDoc, mutations97-104 change roles/plugins/launch/human only. No library, no insertion. Its fixture host loads that no-library doc at federation-host.mjs:22.
- bus/citation-availability and harness/citation-runner use citationWorld; citation-helpers:18-22 is synthetic Broker input and never validates it.
- library/guard operates on mappings/readers and partial settings docs, not business validation. CLI reply-limits uses settings JSON and fake transport.
- federation-human and citation-adapter are transport fixtures only.
Exact instance-settings traces (sage-4086)
A. Old test instance-settings.test.mjs:131 expects BusinessError when chief changes to merge-gate. Actual throw is OrganizationError with code organization-credentials-out-of-scope at instance-settings.mjs:253. set():250 accepts target merge-gate; :252 reads the old chief DEFINITION's credentials.length (now1 from row285's chief role file), not the instance's effective no-library empty credential map. It throws before commit can reach the unchanged launch validation that formerly produced BusinessError. This is caused by row285's role declaration, not rows296/217. Smallest textual fix is an exact expected-code change at131 (old assertion; not authorized). Preserving that assertion instead requires product-source logic accounting for the chief's effective conditional binding. Fixture-only data cannot correct this no-library chief case while retaining B case3.
B. Old test instance-settings.test.mjs:290 expects companion services[gitea], accepted:true (the mos-1332 approved r2 expectation). Actual accepted:false is computed by definitions(), instance-settings.mjs:165: accepted = !closed(name) && services.length === 0. closed(companion) is false, but its role file now declares gitea, so services.length1 makes accepted false. This check never examines an instance credential reference; bean has not even been added yet. It is not the chief's B condition, missing fixture data, or 296/217 code. It is row285's creative definition credential change exposing an unchanged listing rule. Smallest observed-behavior repair preserving the positive assertion needs product source to mark the supported human creative add accepted; changing the expected bit would touch/loosen that assertion and would not repair the remaining positive test's behavior.
Masked consequences, STATIC ONLY (not additional observed reds): after the listing assertion passes, that test's companion->ideas change at306 will hit definitionFor():100 because ideas declares gitea, and the old-definition guard at252 also blocks credentialed creative changes. The later transition to security-reviewer at311 would hit the old credential guard rather than the previous persona validation BusinessError. A one-bit listing fix alone is therefore insufficient for the test's established add/change behavior. Any credential-transfer exception is product policy scope for Mos, not fixture data.
Both observed instance-settings reds would also fail on r3 eee8ad776.
Reasoning proof without running r3: source and relevant roles have identical
Git blobs on r3 and r4:
instance-settings.mjs 3300a92f87
roles/companion.json af16a83e35
roles/chief-of-staff.json 539e1d134e
The test bytes are identical too. Full r3 gate never ran; no r3 pass is claimed.
Other observed red causes and smallest fix class
- bus/citation-runtime:1 failure, chief-library-gitea-required. Fixture data only: the line15 same-line chief ref described above. Newly landed test.
- business/lifecycle-settings:179 test, failing assertion191 expects organization-instance-exists when hiring chief/chief-of-staff. Actual OrganizationError organization-credentials-out-of-scope at source100: hire():350 calls definitionFor() before duplicate-name checks354-357. Chief's new declared gitea triggers the earlier fence. Would fail r3 too. Smallest textual repair changes that exact expected code (old assertion); retaining its old precedence instead changes product source. No fixture-only fix.
- cli/launcher:766 persona test, failing setup780, CliError wrapping broker credential-file. Row285's own bean store reference at769 requires the private storeRoot; credentials.mjs:212 calls privateDir(storeRoot) without missing:true. This fixture makes no such root. Smallest fix is fixture credential data: replace that own r2 store ref with the existing dummy coder gitea file ref, leaving all base assertions unchanged. Would fail r3 too; store-directory verification must remain fail-closed.
- harness/creative:all7 tests fail BusinessError exit2 at business.mjs:51: roles.bean.credentials must reference exactly ... (gitea; got none). bean() at creative.test.mjs:24-26 uses a variable definition and resolvedFor validates the doc (helpers.mjs:46). Smallest fix is one credential-data insertion in that shared callback reusing d.roles.coder.credentials.gitea, no assertions or product changes. Would fail r3 too. The earlier literal creative-fixture grep missed this variable-definition reader despite the file being present in the conservative dependency inventory. Correction recorded here; collection exposes it directly.
All7 harness test names: not ok 1 - M2: the gate refuses write, edit and bash to every creative role on pi and claude-code not ok 2 - M6: no creative session gets raise_decision; the assistant and the chief of staff keep it not ok 3 - web: research and companion get the broker's typed web tools, and a harness-builtin source refuses web-source-not-allowed not ok 4 - persona: the block sits between the contract and ## This session, fenced, with the name and digest not ok 5 - persona: each unsafe or unpinned file refuses before the bundle directory is made not ok 6 - adapters pass the prompt file's absolute path; the persona and the prompt text never sit in argv not ok 7 - the pi adapter refuses a missing, unreadable or directory prompt file before pi starts
C1 final collection result (2026-10-24T12:09:17Z, sage-4086)
All collection commands have ended. The one fix round has NOT started.
No product/role/test edits or row285 mutants ran. Candidate remains
0f6cdc8610 on magica/row285-r4.
Final git diff --quiet 0f6cdc861 -- packages roles exited0.
Per-suite counts, one completed run per file (not summing retries): bus: files=111 tests=975 pass=974 fail=1 skip=0 cancelled=0 business: files=32 tests=277 pass=274 fail=3 skip=0 cancelled=0 cli: files=68 tests=989 pass=987 fail=1 skip=1 cancelled=0 webui: files=66 tests=418 pass=418 fail=0 skip=0 cancelled=0 harness: files=14 tests=172 pass=165 fail=7 skip=0 cancelled=0 plugins: files=9 tests=119 pass=119 fail=0 skip=0 cancelled=0
Total:2950 tests,2937 pass,12 fail,1 skip,0 cancelled. Twelve failures in five files. The single CLI skip is the intentionally script-only federation acceptance wrapper; its dedicated script passed1/1 with zero skips and verified cleanup. All12 scripts/test-*.sh exit0 (full commands/results script-runs.txt).
The release retry passed224/224, duration599632.904562ms, unchanged input. The initial300s bound was too short for this file; its exit124/interrupted TAP remains as harness evidence, resolved by the1800s whole-file retry. Final CLI counts replace that incomplete log with the completed retry. No assertion was changed and no product failure was hidden.
Complete failing test names, also FINAL-REDS.txt:
agents/magica/work/queue-285/gate-r4-collect/bus/citation-runtime.test.mjs.log not ok 1 - C2-06 runtime reads changed and unreadable reply limits without restarting
agents/magica/work/queue-285/gate-r4-collect/business/instance-settings.test.mjs.log not ok 5 - row 165 refuses each validation failure and leaves the file's bytes alone not ok 14 - row 213 a creative instance is the human's: add, vars and definition changes, persona digest only
agents/magica/work/queue-285/gate-r4-collect/business/lifecycle-settings.test.mjs.log not ok 7 - D2.2 hire refuses noHire, a kept name and a listed name, and re-lists a fired one only as it was
agents/magica/work/queue-285/gate-r4-collect/cli/launcher.test.mjs.log not ok 20 - row 213 a creative instance's persona is read from /personas: off its digest the launch fails with the mismatch as its reason
agents/magica/work/queue-285/gate-r4-collect/harness/creative.test.mjs.log not ok 1 - M2: the gate refuses write, edit and bash to every creative role on pi and claude-code not ok 2 - M6: no creative session gets raise_decision; the assistant and the chief of staff keep it not ok 3 - web: research and companion get the broker's typed web tools, and a harness-builtin source refuses web-source-not-allowed not ok 4 - persona: the block sits between the contract and ## This session, fenced, with the name and digest not ok 5 - persona: each unsafe or unpinned file refuses before the bundle directory is made not ok 6 - adapters pass the prompt file's absolute path; the persona and the prompt text never sit in argv not ok 7 - the pi adapter refuses a missing, unreadable or directory prompt file before pi starts
Smallest fix classification for the owner decision, NOT APPLIED:
- citation-runtime chief-library-gitea-required: fixture credential data only, same-line existing dummy-ref insertion at15 in a newly landed test.
- instance-settings:131 chief change: exact expected-code update (assertion) is the smallest textual repair; retaining BusinessError instead requires product-source treatment of the chief's effective conditional binding.
- instance-settings:290 companion listing: product-source repair of listing acceptance, plus the statically masked creative definition-change guards described above. Do not simply flip/loosen its positive assertion.
- lifecycle-settings:191 chief hire: exact expected-code update (assertion) is the smallest textual repair; retaining duplicate-name precedence needs a product-source ordering/effective-binding change.
- CLI launcher persona store-root: row285-owned fixture data only, replace store:true reference at769 with existing dummy coder gitea file ref.
- Harness creative shared bean callback: fixture credential data only, one added reference after26; every one of its7 existing tests/guards unchanged.
Only item1 is within C1's newly-landed-chief-data fix scope. Other classes need Mos's ruling. No fix, acceptance-green claim, manifest finalization, commit, push or in-review queue move has been performed for this failed collection. Sage gets all results and static traces together, then this seat holds.
Fix round authorized (2026-10-24T12:26:48Z, sage-4088/4090/4091)
Stay on magica/row285-r4; final commit follows applicable green suites/mutants. Rulings quoted from Sage's authorized relay (not an unseen original Mos message):
mos-1585, relayed sage-4088: "The instance-settings.mjs:252 guard refuses only when the instance actually holds credentials." "hire() runs its duplicate checks before definitionFor()." "A definition change on an instance that holds no credentials works as it did at base." "On an instance that holds credentials, a definition change is allowed only when the new definition declares exactly the same service set"; "The change adds, moves and mints nothing."
The initial general P reading conflicted with base assertions, recorded in magica-0014 before implementation. mos-1586 (sage-4091) resolves it: "Rules 2 and 3 apply only to creative definitions. The validator runs first, then the credential guard, and both refuse with the base codes." "The assertions at :211, :311, :68, :189 and :290 stay byte-identical, along with every other old assertion." "Don't bring back a hardcoded creative list"; derive it from definition data, "for example library.write in withinRole". "Rule 3's 'services the human's add already mints' means the createdCredentials list exactly as it stands at your tip (gitea store). A definition that declares any other service gets the base accepted value." "Mutants cover the creative equal-set check, the creative listing rule and the refusal order (validator before guard)."
Applied product design, within those limits:
- creativeDefinition reads withinRole library.write. No new role-name list, CREATIVE_KINDS remains removed; chief has no marker and stays non-creative.
- holdsCredentials reads actual instance references, not role declarations.
- Uncredentialed changes and every non-creative fence stay as at base.
- Only an actually credentialed creative-origin change defers its guard until the complete candidate (including vars/launch) passes business validation. Its target must also be creative and declared service sets must be identical. Host is included in declared service equality even though it has no file ref. No creation path is called; references/identity/tracker stay unchanged.
- Listing preserves non-creative accepted values. Creative definitions join only when every service is the existing CREATIVE_SERVICE (gitea store). Host, Vikunja and any other service retain the base accepted result.
- Hire checks duplicate names before definitionFor; all changes before that call are only an unpublished clone, with no write/mint effect.
New real transition tests authored before source and run RED: instance-credential-transitions.test.mjs:5 tests,2 pass/3 expected fail. The failures were equal-set positive, validator order and listing acceptance. After implementation, the new file + unchanged instance-settings and lifecycle files passed33/33,0fail/skip/cancel (product-green.log). No old assertion edited.
Approved data fixes and observed refusal classes:
- citation-runtime: chief-library-gitea-required, line15 same-line chief ref.
- launcher persona fixture: broker credential-file, replace row285-owned store ref with its existing dummy coder gitea file ref; privateDir checks unchanged.
- harness creative shared bean: BusinessError exact-map gitea;got-none, add one dummy credential line in callback. Every existing assertion stays unchanged.
Exact base word diffs (also fix-r4/data-fix-base-word-diffs.txt):
Command: git diff --word-diff=porcelain d0a6a87cd -- packages/bus/tests/citation-runtime.test.mjs
diff --git a/packages/bus/tests/citation-runtime.test.mjs b/packages/bus/tests/citation-runtime.test.mjs
index fdcfdadfc..b1a2de155 100644
--- a/packages/bus/tests/citation-runtime.test.mjs
+++ b/packages/bus/tests/citation-runtime.test.mjs
@@ -12,7 +12,7 @@ import { mappingEntry } from '../../library/tests/helpers.mjs';
test('C2-06 runtime reads changed and unreadable reply limits without restarting', async t => {
~
const root = mkdtempSync(join(tmpdir(), 'citation-runtime-')); t.after(() => rmSync(root, { recursive: true, force: true }));
~
const doc = businessDoc(root), rolesDir = rolesCopy(root), dir = join(root, 'config'), dataRoot = join(root, 'data');
~
doc.projects.books = mappingEntry();
+doc.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } };
doc.replyLimits = { requireCitation: false, citationsPerReply: 3 };
~
const file = writeJson(join(dir, 'businesses/acme.json'), doc);
~
const checked = validateBusinessDocument(doc, file, { rolesDir }); mkdirSync(dataRoot, { mode: 0o700 });
~
// Runtime takes the host's broker projection, not the business validator's unresolved role entries.
~
Command: git diff --word-diff=porcelain d0a6a87cd -- packages/cli/tests/launcher.test.mjs
diff --git a/packages/cli/tests/launcher.test.mjs b/packages/cli/tests/launcher.test.mjs
index baabd843e..766bbb35a 100644
--- a/packages/cli/tests/launcher.test.mjs
+++ b/packages/cli/tests/launcher.test.mjs
@@ -1,4 +1,4 @@
import {
+FAR_DATE,
launchDoc } from "../../business/tests/helpers.mjs";
~
// The S6 launcher inside a real bus host: real broker child, real runners
~
// in the bwrap sandbox, the fake adapter from packages/harness standing in for the
~
// harness. The chief of staff launches a coder through its launch tool (row 119: the
~
@@ -32,7 +32,7 @@ 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.roles.chief.credentials = { gitea: { ...doc.roles.coder.credentials.gitea } };
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);
~
@@ -766,7 +766,7 @@ test("row 64 a role skill that isn't enabled refuses skill-not-enabled, and one
test("row 213 a creative instance's persona is read from /personas: off its digest the launch fails with the mismatch as its reason", { timeout: 30000 }, async (t) => {
~
const text = "Warm. PERSONA-MARKER-d2\n";
~
const given = prepare(t, (doc) => {
~
doc.roles.bean = { definition: "companion",
+credentials: { gitea: { ...doc.roles.coder.credentials.gitea } },
vars: { harness: "pi", model: "claude-sonnet-5-5", thinking: "high", "persona.name": "Bean", "persona.sha256": createHash("sha256").update(text).digest("hex") } };
~
doc.launch.instances.push("bean");
~
return doc;
~
});
~
Command: git diff --word-diff=porcelain d0a6a87cd -- packages/harness/tests/creative.test.mjs
diff --git a/packages/harness/tests/creative.test.mjs b/packages/harness/tests/creative.test.mjs
index 80f4516ee..c3191f99e 100644
--- a/packages/harness/tests/creative.test.mjs
+++ b/packages/harness/tests/creative.test.mjs
@@ -24,6 +24,7 @@ function bean(t, definition, { harness = "pi", persona = false, vars = {} } = {}
return resolvedFor(t, "bean", (d) => {
~
d.roles.bean = { definition, vars: { harness, model: "claude-sonnet-5-5", thinking: "high",
~
...(persona ? { "persona.name": "Bean", "persona.sha256": sha(TEXT) } : {}), ...vars } };
~
+d.roles.bean.credentials = { gitea: { ...d.roles.coder.credentials.gitea } }; ~ }); ~ } ~
~
Mutant kill plan before runs: M1-M6,M9: Scrooge's unchanged targets/kill rules. M10: drop chief library condition, independent kills by new no-library positive and unchanged Case1 committed-document test. M11: restore declaration-based holdsCredentials; old instance-settings131 kills. M12: insert definitionFor before duplicate checks; old lifecycle191 kills. M13: drop creative declared-service equality; new creative-host mismatch kills. M14: accept creative services beyond gitea; new listing host/Vikunja negatives kill. M15: drop early validation (commit still validates AFTER guard); new order test and unchanged instance-settings311 kill the wrong earlier credential refusal. Every file restored to pre-mutant SHA256 AND Git blob, each receipt retained. 13 distinct mutations,14 kill checks because M10 is independently run twice. Full gate and all mutation results still pending at this receipt.
Final verified r4 acceptance (2026-10-24T13:02:03Z)
mos-1585/1586 fix round is complete on magica/row285-r4. No force-push, no canonical npm/rm or dependency links, no live business/grant/deployment change. Fresh own root/webui npm ci128/2; MOSAIC_REQUIRE_EDITOR_BUILD=1; short TMPDIR from mktemp under /mnt/storage/scratch/tmp; serialized whole files with timeout-k10/1800, every script timeout-k10/600.
Whole-suite evidence (gate-r4-final/runs.txt and one full TAP per file): bus: files=111 tests=975 pass=975 fail=0 skip=0 cancelled=0 business: files=33 tests=282 pass=282 fail=0 skip=0 cancelled=0 cli: files=68 tests=989 pass=988 fail=0 skip=1 cancelled=0 webui: files=66 tests=418 pass=418 fail=0 skip=0 cancelled=0 harness: files=14 tests=172 pass=172 fail=0 skip=0 cancelled=0 plugins: files=9 tests=119 pass=119 fail=0 skip=0 cancelled=0
Total2955 tests:2954 pass,0 fail,1 expected skip,0 cancelled. CLI's sole skip is the script-only federation wrapper. Its dedicated script passed1/1,0skip and verified cleanup; all12 scripts/test-*.sh exit0, including test-config. Editor provenance/rebuild6/6,0skip with the required build switch. No unexpected first-run red occurred in this final gate. Earlier failed collection and expected pre-fix TDD RED logs remain preserved separately.
Mutants M1-M6,M9,M10,M11-M15: all13 distinct mutations KILLED;14 checks because M10 independently kills the new no-library positive and unchanged Case1 test. Every intended Node run exits1, driver exits0, and each source restores to both its pre-mutation SHA256 and Git blob. Individual patch, TAP and receipt files are gate-r4-final/mutants; summary mutant-summary.log. M13's declared-host case proves service equality independently of exact-map validation. M14 kills unsupported creative service addability. M15 kills removing validator-before-guard using the unchanged row213 positive test. All final file hashes were checked again against every restoration receipt. Restored whole-file controls:136/136,0fail/skip/cancel.
Old instance-settings/lifecycle test files equal0f6cdc861 byte-for-byte,
including assertions68/131/189/211/290/306/311 and lifecycle191. Case1 doc/test
and shared business helper equal e0c6142f3 byte-for-byte. No old assertion
was changed or loosened. All final data diffs and product source are in the
review packet; N1 remains explicitly deferred, outside this row.
Final manifest: MANIFEST.sha256 hashes all changed candidate files against
d0a6a87cd except itself and the two append-only tracking logs BUILD-LOG.md
and docs/SESSIONS.md. Those logs are still versioned in the pushed commit;
excluding them permits the required subsequent session registration without
changing implementation evidence. The manifest includes this finalized BUILD,
review packet, all source/tests/contracts and retained plain-text evidence.
Its digest is reported with the pushed candidate, outside this hashed file,
to avoid a self-reference. Queue candidate is the full pushed commit, which
freezes even the excluded tracking logs.
Ready for Poe's first Codex review and Webby's landing review; both must check new P logic, exact data/word diffs, assertion preservation and all mutant/restoration evidence. No push to refactor/main, merge, release or deployment is authorized by this result.
Final review diff artifacts: final-base-word-diffs.txt contains the literal
base word diff for every changed test module, including the new tests.
final-product-diff.txt is the full packages/roles diff against d0a6a87cd.
The three final data corrections remain separately recorded against that base
in fix-r4/data-fix-base-word-diffs.txt and quoted above. No assertion was edited.