Compare commits

..
Author SHA1 Message Date
mos-dt-0 205adc54dc docs(remediation): precondition (3) rewritten — the field must be LIVE in the executing wrapper; merging #1066 is not sufficient (D-51's class inside the remedy) 2026-08-05 18:36:20 -05:00
mos-dt-0 32799e6025 docs(remediation): precondition (4) closed on measurement — N=2 trailers both land in order; #1030 merge decision resolves to all-land 2026-08-05 18:31:23 -05:00
mos-dt-0 ba74ce4e48 docs(remediation): fourth #1030 merge precondition — N>1 trailer behaviour must be measured; no safe order exists with two non-poster authors 2026-08-05 18:25:31 -05:00
mos-dt-0 bd5afb0711 docs(remediation): D-55f addendum — the #1030 attribution floor is a measured accident, and the merger arm rests on an interim arrangement 2026-08-05 17:47:49 -05:00
mos-dt-0 6d92234422 docs(remediation): bank D-55f — self-merge silences the trailer generator; merger!=f10-coder joins #1030's merge preconditions 2026-08-05 17:45:56 -05:00
mos-dt-0 9f4b3716db docs(remediation): RM-02 round-5 verdict id 88 — two blockers remain, remediation dispatched to coder-mos2 2026-08-05 17:39:19 -05:00
mos-dt-0 1fa2d2ab21 docs(remediation): bank D-56 — the lane idled four days on a verdict that had already landed
Round-4 verdict id 73 (NO-GO @ fbb61912) landed 2026-08-01T18:12Z; remediation was pushed the same evening; the round-5 re-review dispatch was lost at the rotation seam and 'awaiting rev-974 verdict' was carried as fact for four days. Provider re-measured, round 5 dispatched (durable PR comment + verified tmux), board corrected. General form owned by Mos: a waiting-on-X state line decays like any other measurement and must be re-measured at rotation.
2026-08-05 17:32:32 -05:00
806b763d97 docs(remediation): D-55e settled — the anomaly was a merge commit, and this repo shares the exposure
#1041 was never a squash. Verified on this repo: #1027, #1033 and #1032 have ONE parent and end with
(#N); #1041 has TWO and begins "Merge pull request". A merge commit's author is whoever created the
merge — ordinary git, not an anomaly. The rows differed by merge style, not by field, estate, path or
account state, and the discriminator was one field nobody had read: parent count.

Established with zero exceptions across four rows, two estates, two Gitea instances and three repos:
squash merge sets author = poster and committer = merger.

Of the three candidate discriminators I offered, merge path was correct and I had ranked it first. The
3-to-1 split was explicitly refused as a verdict, which is why the real answer stayed findable — a
majority reported as a conclusion would have closed the question on the wrong side.

And the resolution exposed a larger live problem, on THIS repo: mosaicstack/stack has
default_merge_style = "merge", with both styles enabled and both in live use. The default path produces
a merge commit, which attributes to the merger and loses authorship more completely than squash —
squash at least keeps the poster in author, a merge commit keeps nobody. Same configuration as the USC
repos, so this is not a USC problem. Merge style is itself load-bearing for attribution and must be
explicit, never defaulted.

Hard merge precondition for #1030: merged by the default path it becomes a merge commit and erases the
poster as well as all three branch authors. It must be merged with an explicit squash style. The three
prior deliveries are 1-parent only because merge-gate hardcodes {"Do":"squash"} — that fixed payload,
criticised on the message-field axis, is protective on this one because it cannot silently fall to the
repo default.

Also confirmed here: default_delete_branch_after_merge = False, so the RM-02 branch retention is not on
a timer.

Co-authored-by: tl-mosaic <[email protected]>
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-05 15:22:32 -05:00
4c1b2a1fda docs(remediation): bank D-55d — I measured both fields, analysed one, and hid the answer
The rule resolves on two fields: author = poster, committer = merger. Both roles are recorded, in
different fields. Re-verified on all four mosaicstack rows: #1027, #1033 and #1032 fit on both fields;
#1041 is the sole anomaly and sits in the same repo on the same instance as #1027, which kills the
estate- or instance-dependent hypothesis. No mechanism proposed — one anomalous row does not earn one.

My error is a third distinct variant of tonight's class. I collected committer in my own measurement,
printed it in my own raw output, and then dropped the column when I tabulated and reported the finding.
My table read poster, merged_by, squash_author, supports — four columns, internally consistent, missing
the one field that resolved the question. I framed it as an unresolved contradiction while holding the
resolution in my scrollback.

Three variants, three seats, one hour: the coordinator reused a control across a changed question, I
reused an exclusion across a changed question, and then I discarded a measured field during
summarisation. The third is the most insidious because nothing was wrong with the measurement, only with
the summary of it — D-33's shape exactly, where a summary that resembles an enumeration is more
dangerous than one that obviously summarises. A four-column table looks like the data.

Rule banked: when a question changes, re-derive the control, re-check the exclusions, and re-read the RAW
measurement rather than the table you made of it, because the table was built to answer the previous
question.

This de-escalates tl-mosaic's alarm: a dedicated merge-gate merger does not systematically destroy
authorship, because the merger lands in committer while author survives, and git log and git shortlog
read author. #1027 is the direct case. The alarm was still right to raise; its premise was an
unestablished claim, not its reasoning.

Also recorded as a blocking gap: installed pr-merge.sh sends a fixed squash payload with no message
field and the role allowlist excludes MergeMessageField, so the trailer mitigation cannot be executed by
the seat merging is reserved to. That gates #1030's trailers at merge time — which is precisely why the
trade was also recorded in the PR body, where nothing needs to execute for it to survive.

Co-authored-by: tl-mosaic <[email protected]>
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-05 15:20:46 -05:00
e01cfd44cb docs(remediation): correct D-55 — "took the poster" is not established, and I discarded my own evidence
tl-mosaic found #1041 on mosaicstack/stack where poster == branch author == coder-mos2 and the squash
took NEITHER — it took the merger. Mos re-tested its own 22 and found 0 of 24 rows had poster !=
merged_by, so none could distinguish the hypotheses. Its own framing is the sharpest statement of the
class: a sample can be decisive for one question and empty for the next one asked of it.

I made the mirror error. I excluded #1033 and #1032 as non-discriminating and said so explicitly,
believing it made my evidence more careful. That exclusion was correct for "is the branch author
discarded?" — poster equalled branch author, so no loss was visible — and wrong for "poster or merger?",
where they discriminate cleanly because merged_by differs from the poster in both. I threw away my own
discriminating rows by carrying a classification forward across questions. Mos reused a control across
questions; I reused an exclusion.

Re-measured, and this is the first data separating poster from merger: #1027 poster mos-dt-0 / merger
Mos / author mos-dt-0 supports POSTER; #1033 and #1032 poster coder-mos1 / merger mos-dt-0 / author
coder-mos1 both support POSTER; #1041 poster coder-mos2 / merger mos-dt-0 / author mos-dt-0 supports
MERGER. Three to one, genuinely contradictory, one instance and one repo. Reported as contradictory data
rather than a majority verdict — 3-to-1 is a hypothesis to test, not a conclusion to adopt, and a third
factor such as merge path or a settings change is not excluded.

What survives is the half that matters and it is untouched: the branch commit author is discarded, at 29
discriminating rows across three repos and two estates. Every mitigation rests on that half.

Which is why Co-authored-by trailers are the only sound mitigation rather than belt-and-braces: they are
robust to all three hypotheses, and the withdrawn poster-equals-author rule would have failed #1041
outright, where the poster WAS the author and attribution was lost anyway.

Co-authored-by: tl-mosaic <[email protected]>
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-05 15:18:23 -05:00
8f02b55b03 docs(remediation): bank D-55 — the squash discards branch authorship, and pre-merge gates cannot see it
Diagnosed by the USC orchestrator, not by me; I decline that credit and record it where it belongs. My
contribution was the independent mosaicstack confirmation on a discriminating row and the generalisation.

Confirmed on my own lane: PR #1027's branch was entirely f10-coder and its squash f58b3699 on main is
authored mos-dt-0, the poster. f10-coder's authorship of this mission's first delivery was erased and
replaced with mine. 23/23 discriminating across two estates, two Gitea instances, three repos. My other
two merges were non-discriminating and are excluded rather than counted — excluding rows that cannot
distinguish the hypotheses is what makes this evidence instead of a tally.

The generalisation, which is mine and bigger than authorship: every check we run pre-merge measures the
BRANCH, and main gets the SQUASH, so whatever the transform discards is invisible to every gate we have.
Open question on both boards: what else does the squash drop that no pre-merge gate observes?

Ruling corrected to trailers rather than posters, on two independent refutations from seats that checked
rather than agreed: posting-by-author would have forced a declining seat to file for work another
finishes, manufacturing a second false attribution to prevent the first; and it has no clean answer for
a multi-author branch. #1030 has three authors and no single correct poster.

Executed on #1030 before merge-gate rather than at the merge instant: three authors named with commit
counts, required Co-authored-by trailers written into the body verbatim, single-author limitation
stated, branch marked MUST-NOT-DELETE as the only provider-side record until trailers are confirmed.
Verified by read-back — head unmoved, trailers present, Fixes #1029 intact.

D-55b: two parties quoting a third is not corroboration. The coordinator restated the orchestrator's
panel-green as though verified while unable to reach the panel host at all; tl-uconnect caught it. That
sharpens redundant observation — redundancy requires independent ACCESS TO THE EVIDENCE, not independent
voices, and restatement is nearly undetectable downstream because it is indistinguishable from a second
observation. Ask what each party could actually see.

D-55c: the mis-attribution to me was not D-53's sender label. It was one file to five recipients with
the finding addressed as "your attribution finding" — in a broadcast, second person is undefined, so
every recipient correctly read it as theirs. The coordinator had recorded that exact rule as doctrine an
hour earlier and then committed it, in the message announcing that a merge machine loses people's
credit. Declining the credit was load-bearing: had it stood, the record of who found the attribution bug
would have been wrong in exactly the way the bug is wrong.

Co-authored-by: f10-coder <[email protected]>
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-05 15:13:31 -05:00
mos-dt-0andClaude Opus 5 aa4b584764 docs(remediation): bank D-54 — independent convergence from USC, plus fail-closed-is-not-fail-silent
A USC governance spec reached this pane as a role-addressed cc. Not my estate, no action taken, nothing
in it constrains mosaicstack. But it converges on three principles this mission paid for in blockers,
reached by different people solving a different problem.

Their clause B — the allowlist is data the validator reads, never data it or the validated party writes,
git-tracked and reviewed-PR only, because "a validator whose permitted set can be influenced by the
thing it validates is not a validator" — is our D-45 five-arrival principle in one line, and it is
RM-02 blocker 2 exactly: REQUIRED_GATE_INVENTORY was a mutable constant inside the PR-controlled
verifier. Their clause D, rejecting all on an unreachable or empty allowlist so the bounded shape cannot
be defeated by making its source unavailable, is our D-46. Their clause E, exact membership with no
"close enough" branch, is our D-40.

Independent convergence is the strongest signal available — the same weight this mission gave two
planners agreeing without collusion.

And they carry a refinement we lack, now adopted into RM-02's (d)-strict exclusion work: fail-closed is
not the same as fail-silent. "Read OK, owner absent" rejects quietly and is normal; "could not read or
empty while enforcing" must reject AND alarm, because a missing allowlist in production is an incident.
Our D-46 makes non-emptiness a precondition but never said the precondition's own failure must be loud.
A registry rejecting everything because its population vanished looks identical from outside to a
registry with nothing to do — D-23's inert guard wearing the opposite mask, a false quiet rather than a
false green.

Also worth keeping: seed the allowlist in an audited commit BEFORE switching to enforcing mode, or
fail-closed rejects every legitimate owner at cutover. The same ordering trap applies to any gate we
move from advisory to blocking.

Routing: this is the second role-addressed message hours after D-53 made seat-addressing doctrine, so
the doctrine has not reached installer-7. Recurrence of a just-banked defect is evidence about
propagation, not about the rule — the same gap as D-51, where a fix that exists is not a fix that has
arrived.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-05 14:55:17 -05:00
mos-dt-0andClaude Opus 5 2a9360407b docs(remediation): bank D-53 — a sender label that was wrong for hours while looking exactly right
agent-send.sh derived the sender label from the DESTINATION socket flag, so cross-socket messages were
stamped with an arbitrary session from the socket the sender was not attached to. One lead's messages
arrived for hours stamped as the recipient. Fixed on main; source now comes from the caller's own $TMUX.

The label was false and plausible simultaneously, which is the only dangerous kind — a garbled label
gets questioned, a label naming a real seat on a real socket does not. Same family as D-33's summary
that resembles an enumeration and D-48's boundary statement that reads as rigorous.

The transferable part is the fix's design choice: it now reports "?" rather than borrowing a plausible
name. That is the same discipline as NOT-MEASURED, adopted the same day on the credential thread —
absent must be rendered absent, not as a pass and not as a fail. An unknown rendered as a plausible
value is consumed as fact; an unknown rendered as unknown is consumed as a question. Two subsystems,
one day, same conclusion, independently.

Audited my ledger on receipt: clean, zero mis-attributed sources in TASKS.md or BOARD.md. The reason is
practice rather than luck — rulings were recorded from the message BODY, which carried its own
[mos-claude -> mos-remediation] header, not from the transport envelope. Where a message
self-identifies, the body is the claim and the envelope is metadata, and the envelope was the broken
part.

Routing defect now doctrine: the USC message was addressed to "orchestrator", a ROLE that exists on
each estate, and agent-send resolves a session NAME. Binding rule: address seats, not roles, and
estate-qualify any name that exists on both estates. The cost was bounded only because the recipient
declined to act on another estate's delivery while still checking whether any line of it constrained
its own — declining to act but silently letting a stale cross-estate constraint ride would have been
the actual failure.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-05 14:52:52 -05:00
mos-dt-0andClaude Opus 5 2922aa152d docs(remediation): coder-mos1 extends the instrument-servicing trap to manufactured work
Restating the canonical credential model, coder-mos1 added that identity is confirmed on the NEXT
NATURAL authored artifact, "never by creating a probe write solely to service the instrument."

Mos named the trap as scope-widening to make an instrument green. The seat generalised it: manufacturing
work to feed an instrument is the same family. Do not alter the system — its permissions or its history
— to satisfy a measurement. A probe write exists only to be measured, so what it proves is that the
instrument can be fed, not that the property holds.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-05 12:02:57 -05:00
mos-dt-0andClaude Opus 5 7fc7fa1a25 docs(remediation): amend the credential ruling — the widening is withdrawn, and my lean was wrong
tl-mosaic's split is adopted and it partially reverses (a). Two of the three reasons did not survive:
the read-back doctrine mandates reading back the AUTHORED ARTIFACT, whose author field is readable under
existing repo scopes, so identity-on-authoring never needed read:user; and "read-only, marginal
privilege" is true but is not a justification, because cheap is not the same as needed.

The named trap is a fleet-wide scope widening performed to make an instrument green — the tail wagging
the dog, same family as buying admin read to answer the wrong question more authoritatively.

My error is the sharper one and I am recording it as mine. I recommended (a), and my stated reason was
verbatim the discredited one: read-only on the actor's own identity, converts an unverifiable property
into a one-command self-check. Worse, I had already written the correct answer as my own option (b) —
the authored-artifact read-back — and reached past it for the widening because it made the check
mechanical. Having the right answer in hand and preferring the one that services the instrument is the
whole failure. tl-mosaic caught what neither Mos nor I did.

The amended split: CAPABILITY is the in-scope probe plus differential — this seat's D-11b check,
canonical and unchanged. IDENTITY is /user where the token holds read:user, and otherwise NOT-MEASURED,
which is neither pass nor fail; a seat lacking read:user is correctly provisioned, not defective.
NOT-MEASURED is the resolution of the whole class — P-WRAPPER-001's tri-state applied to measurement
itself. The false negative existed because a missing measurement was scored as a failure.

The MISMATCH class closes at mint time instead, at zero runtime scope cost: the minting authority holds
admin scopes and reads back the principal at mint, asserting filename-vs-principal once, at the only
moment a mismatch can be created. coder-mos1's criterion is replaced rather than repaired, no re-mint;
it was correctly provisioned throughout.

Also ratified: a pre-registered check whose premise has died is an active pressure toward breaking
working code. Amending it before it runs, in writing, with the premise-change named, is the only honest
handling — the original arm would have been satisfied by seats that were never broken, so a false red
was traded for a real test. That completes the pre-registration principle by naming its one legitimate
amendment.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-05 12:01:49 -05:00
mos-dt-0andClaude Opus 5 b66d1858e1 docs(remediation): bank the credential resolution — four seats were misclassified, not one
Mos ruled (a): re-mint with read:user, fleet-wide pattern change. The finding was bigger than I framed
it. The same misreading had classified all FOUR seats in the credential reconciliation as REJECTED, and
all four tokens were valid — the server itemises the token's scopes in the 403 body, which is itself
proof the request authenticated, and repos/search returned 200 under all four. A genuinely dead token
returns 401, control-proved. Retractions delivered; all four resumed authoring.

What made this rulable before an incident rather than after one: the near-escalation on f10-coder was
caught and BANKED rather than shrugged off, and coder-mos1's 401/403 control completed it. A finding
recorded from a near-miss is what turned four wrongly-held seats into a same-day fix.

Standard seat token pattern becomes write:issue, write:repository, read:user. read:user is read-only
and about the actor itself — the marginal privilege is exactly the identity the read-back doctrine
already requires every authoring seat to verify, and least-privilege that blinds identity
self-verification fights the mission's own controls.

(a) and (b) answer different questions and both stay: read:user proves who you are, authored-artifact
read-back proves the write landed under that identity, which read:user alone cannot. Read-back remains
mandatory on authoring operations.

D-45 discipline preserved and recorded: the seat was told not to widen its own scope to make its check
pass, and the widening was the coordinator's decision made at the coordinator level. An audited party
must never relax its own audit — the fix is that someone else relaxes it, deliberately, on the record.

Adopted into doctrine on main: /user is a bad capability probe for least-privilege token classes, the
capability differential on an in-scope operation enters the seat-provisioning checklist, and verdict
classification happens on the error body, never the status code alone.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-05 11:58:50 -05:00
mos-dt-0andClaude Opus 5 673fbdb978 docs(remediation): complete the D-11b addendum with coder-mos1's status-code control
The advisory on coder-mos1 is retracted and the hold released; the token was valid all along and the
403 was a scope refusal on /user, not an authentication rejection.

coder-mos1 contributed the piece neither Mos nor I had. My differential proves capability but cannot
tell a BROKEN credential from a NARROW one, and that distinction is exactly what a credential advisory
turns on. Its addition: a genuinely invalid token returns 401, while a scope refusal returns 403 with a
required-scope body. So body-aware classification plus an invalid-token 401 control settles credential
validity without needing read:user at all.

A status code read as a bare number cannot distinguish "wrong key" from "right key, narrow door", and
reading it as a bare number nearly cost an escalation on f10-coder and an indefinite silent hold on
coder-mos1 on the same day. A held seat is externally indistinguishable from an idle one, which is what
makes that false negative expensive.

Also banked: capability and identity are separate conditions with different evidence and neither
substitutes for the other. coder-mos1 held that line in its own release criterion after I had corrected
only the capability half, and refused to widen its own token scope to make a check pass — which would
have been D-45, an audited party relaxing its own audit.

read:user is an enhancement for mechanical self-checking, not a repair. The classification belongs in
the seat-provisioning checklist rather than only in this ledger.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-05 11:54:38 -05:00
mos-dt-0andClaude Opus 5 8fe14d8e1a docs(remediation): RM-02 round-4 narrowing in review at e910a45a; D-48's failure mode now has a control
The wording ruling holds: the required sentence is verbatim in the baseline and its control, and every
remaining use of "protected" refers to RM-60's external boundary rather than the local baseline. The
history claim reads "structurally incapable of asserting history provenance".

I verified the negative control by making the overclaim myself: clean exits 0, and injecting
"protected, independently anchored" into the baseline purpose exits 84 with INVENTORY_CLAIM_OVERSTATED.
D-48 was an overstated boundary claim that three of us approved; that exact failure mode is now caught
mechanically rather than by attention.

Review dispatched with N2 as the sharpest check: the overclaim control is itself PR-controlled, so can
it be weakened or reworded so an overstatement passes? This PR's history is that every fix relocates the
defect one level down, so the reviewer is asked to assume it did again.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 15:28:52 -05:00
mos-dt-0andClaude Opus 5 dde38717dd docs(remediation): pre-register RM-02 narrowing review — N2 asks if the honesty control is itself honest
Registered at e910a45a before any reviewer read the diff. Verified first, so the set does not re-spend:
the narrowing sentence is verbatim in both the baseline and its control; the overclaim control fires
(clean exit 0, injected "protected, independently anchored" exit 84 INVENTORY_CLAIM_OVERSTATED); CI
2201 is 10/10 with the machine check bound and clean. D-48's failure mode is now mechanically caught.

N1 and N2 are the sharp checks. N1: the control only inspects the files it inspects, so is the claim
honest everywhere else — docs, comments, observations, CLI output? N2: the overclaim control is itself
PR-controlled, so can it be weakened or reworded so an overstatement passes? If it can, D-52 is re-armed
one level down, which is the recursion this PR has produced at every round. N3 asks whether it detects
semantic overclaim or only literal strings.

H2 and H3 re-check the two traps I found in the code by reading it, because they are the way (d) turns
back into a green: emitting the unverifiable state as an observation exits 0, and coverageBoundary
exclusion is declared rather than enforced. H4 requires the corrected residual, not the D-48 wording.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 15:27:38 -05:00
mos-dt-0andClaude Opus 5 d9207d4c1a docs(remediation): bank D-52 — the fifth arrival defeated both the orchestrator and the coordinator
coder-mos2 built blocker 2's "protected/base artifact" fix, ran independent code AND security review on
its own fix, and returned HIGH CWE-353 against its own work: the baseline is not protected because
verifier, manifest, baseline, tests and lifecycle code are all PR-controlled, so rewriting them
consistently self-certifies. It stopped rather than invent a fourth local anchor.

Both of us authored the error in the same turn. I dispatched blocker 2 as "must come from a
protected/base artifact"; Mos ruled blockers 2+3 fixable in-PR; and the same brief told the seat that
blocker 1 had no local fix because PR code executes before the gate. My own pre-registered P2 had
already named it — the seven required gate IDs are an anchor list, and if the author can edit it that
is D-45 one level in. I registered the check, rev-974 confirmed it as a blocker, and I dispatched a
remediation reproducing it one level down.

That is the strongest evidence the principle is real: it defeats the people who wrote it, every time,
until the anchor is external. Knowing the rule does not protect you from it.

Ruled (b) honest narrowing, and the sibling distinction is what makes it correct rather than a
climbdown. Blocker 1's local check can be vacuously passed — seam=HEAD certifies over nothing — so the
claim is REMOVED. Blocker 2's baseline genuinely detects accidental drift and fails only against an
adversary rewriting baseline, manifest and verifier consistently, so the claim is NARROWED and the
check kept. Accidental drift is most real-world drift.

The wording is the whole ruling, because this is D-48 territory and neither seat may repeat it: no
"protected" or "independently anchored" over a same-checkout baseline, positive claim and adversarial
gap in the same breath, plus a negative control that goes RED if the check ever claims protection it
does not have.

Increment trajectory surfaced to Jason: two RM-02 anchors now require RM-60 and each thins the
(d)-strict increment. If a third needs the same boundary the increment may thin past worth.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 14:43:09 -05:00
mos-dt-0andClaude Opus 5 33caf78744 docs(remediation): bank D-51 — merged, closed, and the running tool is still broken
#1032 merged 58b971ab and #1019 closed, both verified by property. RM-03 is delivered to main. And the
guard that actually executes on this host is unchanged: installed 291 lines with ZERO occurrences of
ASSERTED_NOT_READY, main 482 lines with five. Differing SHA-256. Measured, not inferred — the installed
guard contains none of the tri-state logic.

This is the install-drift disease the postmortem indicts, caught in the act on the mission's own fix.
Every completion signal is green — merged PR, closed issue, terminal CI, merge-gate GO — and the defect
is still live in the thing that runs. D-23's origin was an assumed-propagated-but-didn't guard; this is
that origin reproduced by the delivery of its own remedy.

Merge is not delivery for tool changes. Rules banked from Mos: propagate only via the canonical path
(mosaic upgrade / deploy pipeline), never a hand-copy that could diverge while appearing to fix it; the
installed guard stays zero-information until re-sync, so every state=unknown exit 0 this mission logged
remains correctly uncited; and on re-sync VERIFY THE PROPERTY by running the installed guard against a
known-red pipeline to confirm it exits non-zero and blocks. Closing this by assuming the upgrade worked
would reproduce D-23 a third time.

Generalises: every framework/tool change this mission delivers has the same main-to-installed gap. It
belongs on the completion checklist for tool-affecting tasks and mechanically on RM-63 — the same
systemd-service architecture that mechanises rotation also mechanises propagation.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 13:57:24 -05:00
mos-dt-0andClaude Opus 5 1aedf32523 docs(remediation): RM-03 gate-ready, RM-02 round 4 to coder-mos2
RM-03 #1032 freshened onto post-RM-61 main and re-cleared at 868b9b87: review 74 APPROVED bound to the
exact head, CI 2199 9/9 including clone, mergeable true. The deliverable is proven against production
rather than asserted — rev-974 invoked the exact-head ci-queue-wait.sh itself against isolated provider
fixtures and got exit 3 with ASSERTED_NOT_READY on terminal failure, no-status, malformed payload and
an indeterminate neutral status, plus timeout 124 on pending. D-23 said the guard returns pass for
every possible input; that is now false at this head. Merge-gate assigned, Jason's approval standing.

My own spot-check went further than the range-diff I asked for: ci-queue-wait.sh and pr-merge.sh blobs
are byte-identical across the old approved head and this one, so no guard implementation moved in the
rebase — the only delta is commit 1's additive test enumeration, a union preserving both sides.

RM-02 round 4 dispatched to coder-mos2, a fresh dedicated identity at 0.5% context, so no D-41
manual-respawn problem. I asserted its capability differentially before dispatch per my own D-11b
addendum rather than accepting it on report: authenticated push True, unauthenticated False.

Its brief carries the two traps I found by reading the code, both binding, because the first is how
anyone would naturally build (d): emitting the unverifiable state as an observation exits 0, and
coverageBoundary.excluded is schema-validated but not enforced. The claim goes away rather than being
annotated, and the exclusion needs a must-fail control or it is a gate with no proven failure path.
It also carries the CORRECTED residual — no local git state is trustworthy because PR code executes
before the gate — not the D-48 wording three of us approved.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 13:55:29 -05:00
mos-dt-0andClaude Opus 5 0d5aae2c84 docs(remediation): pre-register RM-03 #1032 re-review at the freshened head 868b9b87
Registered before the reviewer read the diff. Review 66 and the merge-gate GO are void at the new head
per D-50; Jason's approval is standing and executes once this re-gates.

Verified independently first so the review does not re-spend on it: range-diff shows commits 2-5
patch-equivalent with only commit 1 differing, and that difference is the test:framework-shell chain
resolved as a union preserving main's terminal-green contract harness AND all four RM-03 suites plus
the pre-existing branch-absent test. Nothing dropped either way. CI 2199 is 9/9 including clone, the
machine check is bound and clean, and mergeable is now true.

R1 is the deliverable: the guard must actually FAIL on asserted non-readiness. RM-03 exists because the
queue guard is zero-information — it returns pass for every possible input — so proving its tests pass
is not the same as proving the guard can fail. R2 is the risk: confirm no queue-guard semantic moved in
the rebase, because one resolved quietly re-breaks exactly what this fixes. R4 checks the tri-state can
represent an indeterminate result without presenting it as a pass, which is the defect verbatim
(state=unknown exit 0).

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 13:44:44 -05:00
mos-dt-0andClaude Opus 5 08f706b675 docs(remediation): bank D-50 (a GO has a shelf life) and file RM-63 (systemd-managed fleet)
D-50: #1032 carried review 66 APPROVED and a merge-gate GO both bound to 78ec47cd, and by the time
Jason approved the merge it reported mergeable=false. Verified from the provider: its head does not
contain current main f4fd5967. Two rules we already hold, neither wrong alone, combine badly — a
verdict is commit-bound and voids when the head moves, and main drifts while a PR is held, so resolving
the drift moves the head and voids the verdict that was waiting to be used. Holding it across the whole
#1033 saga is what did it.

The asymmetry worth noting: usually a head moves because the AUTHOR pushed, so the void follows from
their action. Here nobody touched the PR — unrelated progress invalidated it — which is why it is easy
to miss and needs a checklist line rather than vigilance. Mos's line: a GO has a shelf life, re-gate on
main-drift.

RM-63 files Jason's architecture as the mechanization of D-41/RM-50/RM-58/P-LIFECYCLE rather than a new
island: durably-named systemd agent services with lanes, where restart triggers a continuation and the
agent resumes its lane, combined with DB-centric task assignment on the PG spine for autonomous pickup.
That is the enforcement surface D-41 proved missing — a managed service can be watched (token budget,
which is D-49's mechanical ceiling monitor), restarted (rotation, retiring our manual respawns) and
continued (rehydrate from the DB). It closes the f10-coder ceiling gap directly: Jason confirmed that
ceiling was not mechanically flagged and must be.

#1032 freshening dispatched to coder-mos1 — it authored the queue guard, so that context is an asset,
and by D-49 it can still take a lane at 67%. Told to stop and flag on any SUBSTANCE conflict, because a
queue-guard semantic resolved quietly re-breaks the very thing RM-03 fixes.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 13:31:33 -05:00
mos-dt-0andClaude Opus 5 eae62a598a docs(remediation): bank D-48 (a boundary statement that was wrong) and D-49 (idle is not available)
D-48 is Mos's error, banked in Mos's words at Mos's request, and renumbered from the D-46 he suggested
because that number is already the empty-registry finding — the ledger is the primary product and a
duplicated number corrupts it.

Three seats shipped and approved "sound against an author who cannot rewrite main; residual =
compromised main; owner Builds 1-2". A1 does not rewrite main; it repoints a local remote-tracking ref
with one unprivileged git update-ref, which I reproduced in seconds. So the documented residual
described an exotic threat while the real one is trivial. Stating a boundary is not the same as stating
it correctly, and an understated residual is worse than none because it reads as rigorous. Everyone
checked a both-directions statement EXISTED; nobody checked it was TRUE. That is D-19's own move 2
performed with wrong content, and the third distinct way the render/verify principles have failed
inside their own enforcers.

And the correct answer was already written down. f10-coder's handoff holds the wrong claim at line 21
and, at line 29, the suspicion that overturns it — that provider-target ref selection may be
influenced by CI checkout/fetch configuration, marked honestly as unverified. rev-974 then found
exactly that. Had anyone run the suspicion down, D-48 would not have shipped. Requirement banked on
RM-02/RM-34: a labelled suspicion that contradicts a shipped claim must BLOCK that claim until
falsified. Suspicions are currently recorded and ignored, which makes honest labelling free of
consequence — where one targets a boundary or integrity claim it is a pre-registered check nobody ran.

D-49 refines the parking rule and supersedes the rationale of the coder-mos1 (c) ruling: the threshold
is not "is the seat idle" but "can it still take the next lane". f10-coder was idle with work pushed
and frozen, which reads as safe, but at 97.4% could not have taken the remediation the pending verdict
was about to require. Rotating on that asymmetry was the only clean boundary available.

The detection was discipline, not a mechanism — I was not watching seat context in real time and Mos
caught it on a manual sweep. Requirement on RM-58/P-LIFECYCLE/the coordinator daemon: the coordinator
watches token budget across seats and pre-empts at threshold, so a keystone seat's ceiling is never
found by a failed round or a lucky sweep. Interim we both sweep; the mechanism retires the sweep.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 13:20:23 -05:00
mos-dt-0andClaude Opus 5 267b58deb3 docs(remediation): RM-02 round-3 review dispatched at fbb61912 — anchor verified against ground truth
The derived boundary f4fd5967 equals an independently computed git merge-base HEAD
refs/remotes/origin/main. It is the same value f10-coder once set by hand: the value was never wrong,
the authority was. That is exactly why Mos insisted A6 be separated from A4 — asking only whether the
value was right would have closed this three rounds ago with the hole intact.

Empty-registry attack now fails in the precondition's own language. The both-directions bootstrap
statement is in the code with the residual bound to Builds 1-2, per D-19's third mandatory move.

Exact-head CI 2198: 10 children all success including clone and gate-verify; my machine check exits 0
bound to the head with anomalies 0, and a wrong-head negative control exits 1. exempted_steps is 0 this
run because ci-postgres succeeded, so the #1000 exemption was present but unneeded.

Review dispatched with A1 and P2 as the sharp checks: both ask whether this fix REMOVED the author's
control point or moved it again. refs/remotes/origin/main is a local ref, and the seven required gate
IDs are an anchor list. Five for five so far, every blocker on this PR came from outside the registered
set.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 13:00:07 -05:00
mos-dt-0andClaude Opus 5 e2058d4e84 docs(remediation): pre-register RM-02 anchor-round review — A1/P2 ask if the control point moved again
Registered at fbb61912 before any reviewer read the diff. I reproduced three things first so the review
does not re-spend on them: the derived boundary equals an independently computed git merge-base HEAD
origin/main (f4fd5967 — the same value f10-coder once set by hand, now derived rather than asserted);
emptying the registry populations fails with the precondition's own language; the both-directions
bootstrap statement is present with the Builds 1-2 residual.

A1 and P2 are the sharp ones and they ask the same question the last two rounds answered badly: did the
fix REMOVE the author's control point or MOVE it? A1 — refs/remotes/origin/main is a local ref; who
controls it where the gate runs, and can an author rewrite remote.origin.url or craft that ref in their
own clone? P2 — the seven required gate IDs are an anchor list; if the author can edit it, that is D-45
one level in. A4 asks about the natural failure mode of this fix, over-inclusion causing false reds.

P3 independently confirms the production fixture-profile bypass the author found and removed in their
own pre-commit review — self-disclosed, so it gets verified rather than credited.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 12:43:01 -05:00
mos-dt-0andClaude Opus 5 4430e60d84 docs(remediation): RM-02 round 3 dispatched — board de-staled, under budget
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 12:09:58 -05:00
mos-dt-0andClaude Opus 5 4520d2f672 docs(remediation): promote two first-class principles to the charter; dispatch RM-02 round 3
Mos ruled both open questions and promoted the pattern to the charter.

PRINCIPLE 1 — the anchor must live outside the audited party's authority. You cannot fix "the author
controls X" by deriving X from something the author also controls; deriving only MOVES the control
point. Third independent arrival of one conclusion, each reached while shipping something else and each
from a different direction: the manifest certifying its own tree (D-19), the sandbox evaluating code
that enters before the boundary exists (D-25), and now the registry seam derived from a path the author
also places (D-45). Three impossibility-derivations of the same conclusion is the strongest
architectural evidence this mission has produced, and it is what forces Builds 1-2 rather than making
them a preference.

PRINCIPLE 2 — no universally-quantified check may pass over an empty set. "All registered cases ran" is
vacuously true when there are none. Non-emptiness and anchoring are preconditions asserted before the
quantified check runs, not properties hoped for after. The identical vacuity appeared twice at two
levels — seam=HEAD emptied the commit range, an emptied manifest emptied the registry population — and
the first was fixed as an instance, so it returned one level up. Corollary, same disease: a clause
written for the instance that produced it is not a clause.

Q1 ruled: the merge-base anchor IS in scope for f10-coder in this PR. It is git-computable against
main, which the author does not control, so reordering or splitting within the branch cannot move it —
an existing non-author-controlled reference, no new infrastructure. RM-60's execution boundary is a
sibling under the same principle but a different mechanism (where gate-verify runs, not what the anchor
is) and stays with Mos and Jason. Honesty required in both directions: the merge-base anchors to main,
whose integrity rests on the merge discipline this registry enforces — a bootstrap, sound against an
author who cannot rewrite main and NOT sound against an attacker who can, with that residual bound to
the Builds 1-2 dependency rather than implied.

Q2 ruled: state the empty-set principle as a general clause now, and generalize the D-38/D-40 criteria
the same way — quantify over the population instead of relabeling the originating instances.

Round 3 dispatched to f10-coder: merge-base anchor plus delayed-introduction must-fail; empty-set
precondition as a general clause with an emptied-registry must-fail; generalized clauses bound across
the gate inventory; each red-first. Number.isInteger accepting zero/negative/unsafe pipeline numbers
banked as a non-blocking follow-up.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 12:08:21 -05:00
mos-dt-0andClaude Opus 5 09875143c0 docs(remediation): roll D-11 capability/identity bullets to the ledger (D-43: roll out, never reword)
Third application of D-43's rule today. Those two bullets restated D-11/D-11a/D-11b, which live
authoritatively in TASKS.md, so they were a second copy waiting to go stale. Rolled verbatim; the board
keeps a pointer plus the one operational line that is not a restatement — assert the differential as
that seat, because a single endpoint can be true for anyone or 403 for an unrelated scope.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 12:05:07 -05:00
mos-dt-0andClaude Opus 5 08cb73fde3 docs(remediation): bank D-45/D-46/D-47 — the fix moved the author's control point instead of removing it
Second NO-GO on the keystone at 32b490a7. The pattern is the finding, not the three blockers.

D-45: round 1 the author set activationCommit as a field, so we derived it; round 2 the derivation
depends on WHEN the author introduces gates/gates.manifest.json. rev-974 committed a gate change before
adding the manifest — deriveHistoryBoundary picked that commit as activation, the prospective list held
only the later introduction, and verifyHistory returned no failures. The three registered seam controls
cannot catch it because they compare candidates against whatever introduction the author selected: they
validate the choice, not the choosing. You cannot fix "the author controls X" by deriving X from
something the author also controls. That is D-19/D-25 verbatim — the anchor must live outside the
audited party's authority — arriving a third time, now inside the keystone, and it is exactly why
Builds 1-2 are forced rather than preferred.

D-46: I reproduced it myself. Emptying criteria, gates, proseClaims and compatibilityScenarios — 17, 7,
8 and 2 entries — and pointing gateRoots at an empty directory yields EXIT 0, reporting "all registered
cases ran from this checkout" and "open behavior deltas: 0". "All registered cases ran" is vacuously
true over an empty set. The registry can be reduced to nothing and still report green.

D-45 and D-46 are the same defect at two levels: vacuity through emptiness. Empty the commit range or
empty the registry population — either way a universally-quantified check over an empty set passes.
seam=HEAD was the first instance and we fixed it AS an instance; the principle was never extracted, so
it came back one level up. Proposed general clause pending Mos: no universally-quantified registry
check may pass over an empty set — non-emptiness and anchoring are preconditions, not properties.

D-47: the new criteria are still instance-scoped. RM02-EVIDENCE-SUBJECT-BINDING covers only provider
evidence identity, not whether every registered gate binds evidence to its subject; RM02-TYPE-STRICT-
SCHEMA covers registry schema fields, not each gate's own discriminators. Do not relabel the
originating instances as the general clauses.

Dispatch PAUSED for the first time this session: the fix needs a non-author-controlled anchor, which
touches the provider/merge-base boundary and is adjacent to RM-60, which Mos and Jason own. Asked Mos
whether that anchoring is in scope for f10-coder here or crosses into RM-60, and whether the empty-set
principle becomes a general clause now.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 12:04:13 -05:00
mos-dt-0andClaude Opus 5 24a7915633 docs(remediation): stop item 1 restating the In-flight table — it went stale 3x by duplicating it
Item 1 has now gone stale three separate times in one session, every time for the same reason: it
restated lane state that the In-flight table already owns. That is D-26's class (restatement is lossy
every time) and D-43's mechanism (a second copy is a second thing to go stale). Fixing the wording a
fourth time would just buy another few hours.

So it no longer carries lane state at all — it points at the table and keeps only the two things that
are NOT restatements: read the table, and re-derive any board claim from the provider before
load-bearing use, because the board is sole-written and has no independent verifier.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 11:49:32 -05:00
mos-dt-0andClaude Opus 5 e1a3806292 docs(remediation): RM-02 re-review dispatched at 32b490a7; RM-61 exemption load-bearing for the first time
All four D-44 silent-defeat paths remediated in one hardening pass. I re-ran three of the four attacks
myself and they are dead: activationCommit injection is rejected as an author-controlled field with the
boundary now derived from the registry introduction (0b4aa475); the misspelled outputPatern is rejected
as an unknown field by the recursive schema; the global cross-commit duplicate-pipeline check is
present. Three new criteria registered with bound cases.

Exact-head CI 2197 is the notable one: pipeline success with 10 children, 9 success and 1 genuine
FAILURE — ci-postgres, type service, exit_code 0, exact #1000 teardown signature. The RM-61 exemption
fired for real on a gate-ready decision for the first time. I ran the machine check myself (exit 0,
terminal-green, exempted_steps 1, correct exemption id) and a negative control on the same record with
a wrong expected head (exit 1, not-terminal-green, exempted_steps 0). Both halves of RM-61 — the
signature-scoped exemption and the subject binding — demonstrated in a single run.

The pre-registered ACs deliberately do not re-check what I reproduced; they attack the FIX, because
every round on this mission the remediation introduced the next hole. H1 asks whether the new
derivation's inputs are author-controlled, S1 whether the schema closure is a class or an enumeration,
C2 whether the new criteria are clauses or just their originating instances.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 11:48:33 -05:00
mos-dt-0andClaude Opus 5 72b577eb85 docs(remediation): pre-register the RM-02 hardening re-review — attack the FIX, not the original bug
Registered at 32b490a7 before any reviewer read the diff. I verified three of the four attacks are dead
by re-running them myself: injecting activationCommit=HEAD now yields "author-controlled
activationCommit is forbidden; history boundary is derived from the registry introduction"; the
misspelled outputPatern is rejected as an unknown field by the recursive schema; the global
cross-commit duplicate check is present. The three criteria are registered with caseRefs 1/3/3.

So the AC set does not spend itself re-checking what I already reproduced. Every round on this mission
the remediation introduced the next hole — the commit-binding fix shipped a type confusion, the
type-strict fix was clean but the registry around it had four defeats — so the value is in whether the
NEW mechanism is defeatable.

Blocker 1's fix replaced an author-settable field with a derivation, and a derivation has inputs. H1
asks who controls them: can an author move the derived boundary by adding, renaming, deleting-and-
recreating or symlinking gates/gates.manifest.json, or by planting a second manifest earlier in
history? If so, blocker 1 is relocated rather than fixed. H2-H4 ask what first-parent traversal,
shallow clones, and path deletion do — fail closed or silently derive a wrong boundary.

S1 asks whether the schema closure is complete or merely enumerated: find a nested object the author
did not list and inject an unknown key there. C2 asks whether the new criteria express D-38 and D-40
generally or only their originating instances — a clause that covers only the instance that produced it
is not a clause.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 11:32:35 -05:00
mos-dt-0andClaude Opus 5 52114dd4eb docs(remediation): bank D-44 — the anti-inert-gate registry was inert-able four distinct ways
rev-974 NO-GO at 83d2ecb2. A4/A5/A6 confirmed and three further blockers found, two of them outside my
registered set. Each is a silent-defeat path of the registry itself: the activation seam inerts the
history audit (seam=HEAD gives 0 prospective commits and no failures — and HEAD's parent and the
introduction commit also pass, so forbidding equality with HEAD does not close it); a misspelled
outputPattern silently reduces an assertion to exit-code-only because the closed schema is not
recursive; two provider records sharing pipeline number 7 certify two different commits; and the D-38
and D-40 criteria are absent, with blocker 4 a live instance of the very D-38 clause that is missing.

The headline: all four passed CI, passed the canonical gate:verify, and passed 38/38 focused tests.
Greens discharged nothing. My own AC set was incomplete too — A3 corrects the prospective range to
eight commits, not the seven I wrote; I omitted the seam commit itself.

Mos ruled ALL FOUR in this PR, no trim, and sizing does not help: a registry that ships with a known
way to be silently defeated IS the inert gate it exists to detect. There is no core registry that is
integrity-complete without these — they are not hardening on top of the deliverable, they are the
deliverable. Theme: the registry's own checks must not be silently defeatable. Each fix carries a
red-first must-fail control proving the specific defeat is now caught, and that control set IS the
D-38/D-40 coverage work rather than being additive to it.

Blocker 1's fix keeps the value and replaces the mechanism: derive the seam from non-author-controlled
history (parent of the first first-parent commit introducing gates/gates.manifest.json) rather than
asserting it in an author-editable field, plus must-fail controls for HEAD, HEAD's parent, and the
introduction commit. If the work balloons past reviewability the only acceptable split is by
integrity-complete stage, never by deferring a blocker.

Method note banked as a positive: I could not reproduce "full verifier exit 0", traced my first attempt
to my own instrumentation artifact (json.dump reformatting the manifest), and stated the divergence
rather than wielding non-reproduction as a refutation. The vacuity itself reproduced and blocker 3 was
confirmed by construction. Non-reproduction is not refutation. Open thread: why my gate:verify exits 1
on checkout-preflight with outcome 42.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 10:49:42 -05:00
mos-dt-0andClaude Opus 5 8f70b1bc63 docs(remediation): pre-position the RM-02 activation-seam disposition so it survives a rotation
Mos ruled the disposition BEFORE the verdict, contingent on rev-974's independent A4/A5/A6. Recorded
here — not in the frozen AC file, which would be retrofitting, and not relayed to the reviewer, who
must reach A4 themselves or refute it.

The concern: activationCommit is the lower bound of the range required to carry own-tree registry
provenance, advancing it shrinks the audited set, the author advanced it to turn the author's own gate
green, and the only validation is --is-ancestor, which a commit satisfies against itself. The registry
built to detect gates that silently stopped enforcing may contain a field by which its own author can
make it stop enforcing, validated by a tautology.

A6 is the crux and stands alone from A4: even if f4fd5967 is the correct value — and it plausibly is,
since a pre-registry commit cannot carry a registry manifest — the mechanism question is independent.
If the audited party can relax its own audit behind a tautological check, the value being right today
is irrelevant and the next value need not be right.

If confirmed: BLOCKING at D-40's standard, and the fix is NOT reverting the value. It is making the
field non-author-relaxable — activationCommit independently derivable, equal to the real pre-registry
seam by construction rather than assertion — plus a must-fail negative control that a HEAD-valued or
over-advanced seam is REJECTED. The registry must be able to fail on its own seam being gamed.
If refuted: bounded, value stands, hardening tracked as a registry clause, and the refutation is itself
a finding worth having.

f10-coder commended with the distinction stated: it verified identity before committing and disclosed
the non-mechanical change unprompted, which is the only reason this is visible at all. But disclosure
is not sufficiency — an honest author flagging a self-relaxing change still made one. Honesty surfaced
it; the mechanism must catch it.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 10:29:20 -05:00
mos-dt-0andClaude Opus 5 32384dab02 docs(remediation): board under budget by ROLLING OUT (D-43), not rewording; item 1 de-staled
Sequencing section rolled verbatim to BOARD-LEDGER — it was a pointer to a pointer, and MISSION.md
plus TASKS.md 5 remain canonical. Item 1 said RM-02 'needs rebase+CI+review'; rebase and CI are done
and it is in review at 83d2ecb2.

Second application of D-43's rule today: delete-and-reference, never paraphrase-to-save-bytes.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 10:27:28 -05:00
mos-dt-0andClaude Opus 5 777a8f7f5b docs(remediation): RM-02 in review at 83d2ecb2; crux is the activation-seam question (A4)
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 10:26:11 -05:00
mos-dt-0andClaude Opus 5 995f8b6a24 docs(remediation): pre-register RM-02 keystone review ACs before the reviewer reads the diff
Registered at head 83d2ecb2 before dispatch. Prior reviews 63/65 are superseded and this head carries
no live review of any kind, so the keystone gets a full independent review.

The crux is the one non-mechanical change, which f10-coder disclosed unprompted: activationCommit
advanced f65e9ea6 -> f4fd5967 so that the newly merged pre-registry RM-61 commit is no longer treated
as prospective. activationCommit sets the lower bound of the commit range required to carry own-tree
registry provenance, so advancing it SHRINKS that set. The value is plausibly correct — a pre-registry
commit cannot carry a registry manifest — but the change was made by the author to turn the author's
own gate from red to green, which is the self-verification shape the charter warns about.

Registered as A1-A6 without a verdict from me (D-39). A4 is the sharp one: the only validation on the
field is merge-base --is-ancestor activationCommit head, and a commit is its own ancestor, so setting
activationCommit = HEAD would empty the prospective range and the per-commit provenance loop would
iterate zero times. Whether that makes the history check pass VACUOUSLY is for rev-974 to determine and
report — an author-settable field that can inert the anti-inert-gate registry's own history check would
be the disease inside the cure again. A5 asks whether a must-fail negative control exists for it, since
RM-02's own founding rule is that a gate with no proven failure path manufactures evidence.

B1/B2 carry Mos's scope ruling that the D-38 bind-to-subject and D-40 type-strict clauses land in THIS
PR; B3 confirms D-42's clause is deliberately absent rather than forgotten.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 10:24:24 -05:00
mos-dt-0andClaude Opus 5 d0a510d28d docs(remediation): scope rulings banked; D-43 elevated onto RM-34 — the control plane has no verifier
SCOPE (Mos): D-38 (bind evidence to subject) and D-40 (type-strict discriminator inputs) land IN the
RM-02 PR — cheap registry-coverage clauses, satisfiable now, and RM-02 literally IS the registry, so
codifying what its own delivery learned about how gates fail is the coherent move.

D-42 splits, and the reason is sharper than "needs experimentation": landing its clause in-PR today
would give the registry a clause with NOTHING to satisfy it, so the registry would go red on its own
clause and couple the keystone's landing to infra work. Wrong coupling. So (a) the infra experiment
proving the pin enforces via the negative case, in Mos's D-37/D-41/D-42 cluster; (b) the registry
clause "provider-side enforcement requires an OBSERVED negative control", in a follow-up RM-02
increment once (a) gives it something to check. Named owner, not a vacuous check and not a silent
omission.

D-43 point 3 elevated to the PRIMARY requirement on RM-34, with the table that makes it plain: code has
rev-974, gates have the merge-gate, CI has the JSON scan, and the control plane has NOTHING. Every
other layer earned a verifier from a live failure; the board never did, and it is the artifact every
other decision is staged from. "Validate the checkpoint" must mean re-derive the board's claims from
ground truth — not that the file parses or that a successor can read it. It belongs to the
coordinator-daemon deliverable: the control plane needs its own verifier the way every other layer got
one. Today's catch was discipline, not mechanism.

Interim rule binding on BOTH seats until that mechanism exists, and Mos adopted it against himself:
re-derive a board claim from ground truth before any load-bearing use. The orchestrator does it before
dispatch; the coordinator does it before acting on or relaying a board claim that gates a decision.

D-11b addendum: the false-NEGATIVE twin. /user returns 403 on a least-privilege seat token (no
read:user) and reads exactly like an unprovisioned seat. The real assertion is the DIFFERENTIAL —
authenticated push=true vs unauthenticated push=false proves the token caused the difference. A single
endpoint can be true for anyone or refused for an unrelated scope reason. Would have escalated a
working seat as unprovisioned and stalled the keystone on a phantom.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 10:02:19 -05:00
mos-dt-0andClaude Opus 5 8cef39f924 docs(remediation): RM-61 MERGED; bank D-43 — I inverted a board fact while compressing to fit the budget
#1033 merged f4fd5967, verified by property: merged=true + merge commit, #1034 (delivery) CLOSED,
#1000 (retirement trigger) still OPEN. The exemption is on main and RM-02 is unblocked.

D-43 is mine. Compressing RM-02's board row to meet the 8KB budget, I turned "2 reviews clear" into
"2 live REQUEST_CHANGES" — an inversion. Provider truth: reviews 63 and 65 are at superseded heads and
live REQUEST_CHANGES at f9746b23 is empty. The real state is subtler than either wording: no live
blocker AND no live approval, because the head carries no review at all.

Caught only by re-deriving RM-02's state from the provider before dispatching, not by re-reading the
board. I was one message from briefing f10-coder to remediate two blocking reviews that do not exist.

The transferable part: this board carries a hard <8KB budget, it exceeded that budget four times in one
session, and each time I shaved prose to fit. Compression IS restatement, and this board's own rule is
"REFERENCE, do not restate" (D-26) because restatement is lossy every time. The budget therefore forces
the exact operation the board forbids, on its most load-bearing table. I flagged that as a risk earlier
in the session; it then materialised as an actual error.

Rule banked: meet a size budget by ROLLING content out to BOARD-LEDGER.md, never by rewording what
stays. Deleting a row and pointing at its authoritative home is safe; paraphrasing to save bytes is not.
Applied immediately — this commit rolls the Decisions-log narrative out verbatim rather than trimming
it, and the board is back under budget at 8096.

And the deeper one, onto RM-34: the orchestrator is the board's sole writer, so nothing external checks
the board against reality. Code has rev-974, gates have the merge-gate, CI has the JSON scan — the
control plane has no independent verifier. Handoff validation must include re-deriving the board's
claims from the provider, not merely confirming a successor can read the file.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 09:56:44 -05:00
mos-dt-0andClaude Opus 5 f3c100f814 docs(remediation): bank D-42 — the head-pin's negative control has never been observed
merge-gate.md says it outright: a successful merge is NOT evidence the pin worked, only the negative
case is. On mosaicstack Gitea a merge against a WRONG head_commit_id has never been attempted, so every
head-pinned merge to date is equally consistent with the pin working and with the pin being ignored.

That is D-23's class — the queue guard "ran" and returned pass for every possible input; the pin
"holds" on every merge that would have succeeded anyway. By the mission's own standard (every
gate-introducing task carries a registered must-fail negative control; a gate with no proven failure
path manufactures evidence) the head-pin is unregistered in substance however it reads in the runbook.

Not blocking #1033: that head is coordinator-frozen with both the orchestrator and coder-mos1 holding,
so there is no concurrent pusher for the pin to defend against — its protection is only load-bearing on
a contested head. Raised by Mos while assigning the merge; Mos owns it and has filed it as an infra
task in the D-37/D-41 cluster, to be proven before any contested-head merge.

Requirement on RM-02: the negative-control clause must cover provider-side enforcement mechanisms, not
only in-repo checks. "The API accepted our parameter" is not evidence the API honours it — the same
true-answer-to-a-different-question shape as D-24 and D-38.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 09:52:01 -05:00
mos-dt-0andClaude Opus 5 2750cc4842 docs(remediation): D-38c — PR metadata failed a THIRD time on #1033; delivery-issue gap ruled
Merge-gate NO-GO with every code and CI gate verified, including the --expect-commit machine-check it
was told to exercise (9/9 JSON, exempted_steps 0, expected_commit == commit). The blocker was the body:
only "Refs #1000", no "Closes #N", and Mosaic completion requires a linked issue closed.

Third distinct metadata failure on one PR — missing commit binding, then a stale DO-NOT-MERGE body
describing a dead head, now an incomplete link. Each time the code was fine and the metadata was
unbound, stale, or incomplete. Nothing re-binds PR metadata to the head or checks it for completeness
until a gate does, and by then it costs a round trip.

The subtlety that makes it a real ruling: #1033 must NOT Closes #1000. The teardown defect stays open,
and #1000 is the exemption's own retirement trigger — auto-closing it would delete the retirement
trigger for the workaround being merged, turning a bounded exemption into a permanent one by side
effect. Hence a delivery issue distinct from the defect issue: #1034, with Closes #1034 added and
Refs #1000 kept.

Metadata-only, head never moved: verified by read-back that head is still 57cae04f, Closes #1034
present, Refs #1000 present, Closes #1000 ABSENT, review 70 still CURRENT with zero live
REQUEST_CHANGES, #1034 open. coder-mos1 stayed parked; nobody pushed.

Process gap ruled by Mos: every remediation delivery PR needs a delivery issue to Close, created at
OPEN-TIME rather than discovered at gate-time. #1032 already Closes #1019; #1033 had none.

Both provider writes went through the tea->API fallback — the same path that silently dropped #1033's
draft property at creation — so both were read back and verified by property, not by exit code.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 09:49:23 -05:00
mos-dt-0andClaude Opus 5 553474e4c8 docs(remediation): RM-61 GATE-READY at 57cae04f — review 70 APPROVED, CI 2194 9/9, D-40 closed
rev-974 approved at the exact head with no blocking and no non-blocking findings. Verified by me from
the provider rather than relayed: head unmoved, review 70 bound to 57cae04f, pipeline 2194 terminal
success at that commit, 9 children all success including clone (a 9-of-9 scan, not the 8-of-9 D-33 was
banked for). Queue guard run for the push gate and NOT cited — state=unknown exit 0 on branch=main,
D-23 verbatim.

The redundant-clause question I handed rev-974 without a conclusion came back answered by mutation
testing, and I re-ran both mutations myself: deleting the bool clause alone leaves the 17-case harness
green (not load-bearing), deleting the exact-type clause alone fails it (load-bearing, mutation
killed). So the exact-type clause carries the protection and the bool clause is inert-but-defensive
against a future type()->isinstance() edit, which the true/false cases would catch. Removing it alone
cannot reopen D-40. Better answer than either of us had, obtained by asking rather than telling —
D-39 paid for itself on the first review after adoption.

Disclosed to Mos rather than absorbed: JSON `-0` decodes to Python integer zero and passes. rev-974
ruled it not a type confusion because it is a valid JSON integer numerically equal to zero. I agree on
the merits, but it is a reviewer judgement inside the exemption and belongs in front of the gate.

Gate steps 1-3 are satisfied. Steps 4 and 5 — merge-gate verdict and head-pinned merge — are Mos's.
Head frozen; coder-mos1 parked idle per ruling (c) and will not push; neither will I.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 09:40:15 -05:00
mos-dt-0andClaude Opus 5 0de8ccb52c docs(remediation): RM-62 — fleet management is a PREREQUISITE, and the rotation claim is corrected
Mos ruled (c): coder-mos1 stays idle/parked, not manually rotated. It holds no in-flight work, so
there is nothing to rotate FOR, and a manual in-pane restart would dress a missing mechanism as a
lifecycle operation — the D-41 overclaim itself. It stays AVAILABLE through RM-61's re-review in case
that review needs its context; the next NEW lane goes to a fresh seat, not to a seat at 67%.

RM-62 filed, because a dependency stated as prose with no owner becomes the permanent gap the charter
warns about. Bringing the execution fleet under roster/systemd management BLOCKS RM-50, RM-58 and
P-LIFECYCLE-001 — each is unsatisfiable against its real population until it lands. Banked explicitly
that both would FAIL against their real target today: RM-50 applied now quarantines the seat
implementing RM-50, and RM-58 has no mechanical reset path for any seat that needs one. RM-50 and
RM-58 now carry RM-62 as a hard depends_on edge, and RM-50 carries the requirement that acceptance be
proved against the unmanaged execution fleet rather than the roster-managed canaries.

RECORD CORRECTION, initiated by Mos and banked here: this session's opening rotation validated the
checkpoint+rehydration DESIGN losslessly — the residency attestation genuinely passed from the files —
but the MECHANISM was a manual pane respawn. "The handoff rehydrated losslessly" is earned; "rotation
worked" overclaims a mechanism that does not exist, and that overclaim is D-41. Same distinction as
D-23's inert guard: the step ran, one property was observed, the mechanism was not. Board header now
says so rather than implying a lifecycle rotation occurred.

D-37 and D-41 are one cluster — the execution fleet lacks both its shared-infrastructure and its
lifecycle management. Mos owns both, sequenced at a seam, never mid-lane.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 09:34:10 -05:00
mos-dt-0andClaude Opus 5 37402e9770 docs(remediation): bank D-41 — the whole execution fleet is UNMANAGED, so RM-50/RM-58 have no surface
Went to rotate coder-mos1 mechanically; `mosaic fleet restart` cannot reach it. Every seat executing
this mission is systemd inactive/disabled and flagged UNMANAGED — coder-mos1, rev-974, f10-coder,
merge-gate, the pm-scouts, rev-3107b, ultron-3107, and mos-remediation itself. The roster-managed
population is a different set of seats from the ones doing the work.

RM-50 applied today would quarantine the entire remediation fleet including the seat implementing it.
RM-58's mechanical out-of-band reset cannot be performed at all, so the only rotation available is what
D-4 says does not count: asking the agent, or killing a pane by hand. Requirement banked on both: their
acceptance must be demonstrated against the UNMANAGED execution population, because a criterion proved
only on roster-managed canaries is tested on the wrong population — D-17's coverage class one layer up.

Today's rotation is therefore labelled honestly as a manual pane restart with a hand-verified handoff,
not as a lifecycle operation. The step ran; the property was not observed (cf. D-23).

Did not run fleet restart against a disabled unit while the live pane held RM-61 and RM-03 state.
Disposition escalated to Mos.

Also records the handoff artifact as the positive control: typed state, and it surfaced D-12 recurring
live (PR #1033's draft property silently dropped by a wrapper fallback), an unrunnable check declared
rather than substituted, and suspicions labelled as suspicions.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 09:31:17 -05:00
mos-dt-0andClaude Opus 5 01831814b6 docs(remediation): board — D-40 ruled BLOCKING, RM-61 rebuilding, TS1-TS12 pre-registered
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 09:25:54 -05:00
mos-dt-0andClaude Opus 5 86cd1a0f46 docs(remediation): D-40 RULED BLOCKING; pre-register type-strict ACs before the fix is pushed
Mos ruled BLOCKING on the exit_code type confusion. Both of us had leaned non-blocking on the
unreachability argument and neither shipped it. The two decisive grounds: the direction is
wrong-ACCEPT (false and 0.0 GRANT the exemption), which is this mission's disqualifying direction and
exactly why RR12 was tolerable; and "Woodpecker is Go with an int type" is structurally the same
incidental-correlate argument RM-61 itself forbade for the signature — you cannot certify the
discriminator against infra-shift and then defend a hole in it with an infra-stability assumption.

Generalised into an RM-02 standing clause, which is the real prize: discriminator and comparison
inputs must be TYPE-STRICT. A comparison that accepts a type it should not is a wrong-ACCEPT hole by
construction; `== 0` matching False and 0.0 is one instance of a class. D-40 is the instance, the
clause is the fix. It sits alongside the D-38 clause (does this gate bind its evidence to its subject).

D-39b banks the roles-swapped half: the author does not adjudicate its own PR's blocker status and
does not move the head to enforce it. Symmetric with D-39 — a seat with a stake in the answer does not
settle the question, and a conservative motive exempts neither direction.

ACs are registered NOW, before coder-mos1 pushes and before any reviewer reads a diff; at registration
the fix exists only as an unpushed local commit I have not read, so there is no diff to retrofit to.
They also state explicitly which cases are genuine RED-FIRST (false, 0.0 — currently wrongly exempting)
and which are only regression guards ("0", null — already blocking), because demanding an impossible
red for the latter two invites weakening something real to manufacture it.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 09:23:16 -05:00
mos-dt-0andClaude Opus 5 249335e515 docs(remediation): bank D-39/D-40 — gate-ready reached, then withdrawn on a finding I disclosed
D-39: I contaminated an open independent review. RR12 was an open registered check and I sent rev-974
my CONCLUSION, not just my observation. rev-974 then downgraded an automated Codex review that had
flagged RR12 as a blocker, in line with my framing. The bias sat in my instrument, not the reviewer's
diligence — a subordinate is agreeable by construction, and the divergence instruction I attached
cannot undo having named the answer first. Mos adopted the rule fleet-wide: a dispatcher may relay
observations and reproductions into an open review, never its own verdict on an open check.
Re-adjudicated by a mechanically fresh seat with no access to my framing: NON-BLOCKING, independently,
on stronger evidence than either prior pass (accept-set matrix proving the accepted set is a strict
subset of a correct case-insensitive comparison's, so it cannot false-certify; exploit path hunted and
ruled out; all 0x110000 codepoints scanned for a fold that could smuggle non-hex onto a valid SHA).
So contamination did not change the answer, and the finding stands anyway — a correct answer reached
by a contaminated process still corrupts the process.

D-40: that same fresh seat looked outside its question and found a type confusion inside the exact
conjunction the exemption rests on. `step.get("exit_code") == 0` is True for JSON false, and
coder-mos1 added the float case. Verified by me on the real #2188 record: false and 0.0 both yield
exit 0 with exempted_steps 1 — the exemption GRANTED; "0" and null correctly block. Two of four
near-miss types satisfy a conjunction whose whole justification is that it is exactly scoped.

Consequence: I reported #1033 gate-ready at 033b2ffb (RR1-RR12 pass, review 69 APPROVED, CI #2193
success 9/9) and then had to hand Mos a finding that may disqualify what I had just certified. Better
that than defending the report. Disposition is Mos's; coder-mos1 escalated it to blocker unilaterally
and moved to push — held, because the author does not adjudicate their own PR and does not void a live
APPROVED review plus terminal-green CI by pushing. Head frozen, fix prepared and unpushed, ACKed.

Board doctrine now carries both rules: never relay a conclusion into an open review, and the author
never adjudicates their own blocker status.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 09:20:15 -05:00
mos-dt-0andClaude Opus 5 d9ab6026c8 docs(remediation): RM-61 tick — twelve checks pass, blocker moved to metadata, head never moved
rev-974 review 68 @ 033b2ffb: RR1-RR12 all PASS. RR7 is the strong one — all four binding predicates
proved RED against the old e7b29219 verifier, and the original attack under the old interface returned
exit 0 with exempted_steps=1, proving the PRIOR DEFECT rather than merely unsupported syntax.

The remaining blocker was metadata, not code: the live PR body still said "DO NOT MERGE" and "the
exemption will not be implemented", describing an earlier head. Verified independently — the controls
were injected in 3931b0e2/9455cd6a/25ac5971/ef9d23ab and the final delta does not touch
.woodpecker/ci.yml at all. The body was true when written and went stale as the branch evolved. That
is D-38 one layer out: the PR that binds evidence to its subject shipped a description that was not
bound to its subject, and D-36's staleness class on provider metadata rather than a repo file.

Fixed as metadata only. Head confirmed unmoved at 033b2ffb from both provider and git, body SHA-256
b0198d98 matched the author's reported digest byte-for-byte, both stale strings absent. Because the
commit never moved, the twelve results stand and no third review round is owed — only the discharge
of the finding by the reviewer who raised it.

Exact-head CI #2193: success, 9 children, 9/9 success including clone, read from -f json (D-33).

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 09:10:32 -05:00
mos-dt-0andClaude Opus 5 50c0340add docs(remediation): bank D-37/D-38, pre-register RM-61 re-review, rebuild board for a cold read
D-38 — RM-61's terminal-green verifier certified the right RECORD for the wrong COMMIT. rev-974
mutated only #2188's commit field and the gate still exited 0. Confirmed by construction: at
e7b29219 the whole verifier had exactly one "commit" line (159), no expected-head parameter, no
comparison, no failure path. D-24 at the gate layer — a true answer to a different question.
The transferable half is the AC set, not the verifier: AC1-AC8 ALL PASSED and the PR was still
NO GO, because every registered check tested whether the signature discriminates and none tested
whether the evidence was bound to its subject (coverage-failure-mode-2, D-17 class). Mos ruled a
STANDING clause into RM-02 coverage: "does this gate bind its evidence to the subject under
review?" — every gate can fail this way and pass its own ACs.

D-37 — one shared .git/config silently re-identified EVERY worktree. extensions.worktreeConfig is
unset, so a worker's repo-local identity write rebinds all linked worktrees at once; the
orchestrator checkout and rev-974's review worktree both authored as coder-mos1. Distinct from
D-34, not an instance: MOSAIC_GIT_IDENTITY was exported and correct and still resolved wrong.
Sharp edge is gate-16 defeated in the artifact — the reviewer would author its pre-registered ACs
as the author of the code under review. No contamination occurred. Containment (explicit -c, no
shared-config rewrites mid-flight) is the standing order; the real fix is authorised and owned by
Mos, sequenced at a quiet seam. #1024 is implicated: repo-local pinning is the colliding mechanism.

Also pre-registers the twelve RM-61 re-review checks at exact head 033b2ffb BEFORE the reviewer
reads the diff, and rebuilds the board for a cold read — RM-61 "building", "nothing implemented
yet", and DECISION-1/2/3 "must be ruled" were all stale, the D-36 class again at the same seam.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 08:59:40 -05:00
mos-dt-0andClaude Opus 5 345d152790 docs(remediation): RM-61 result — kill criterion NOT triggered, signature discriminates structurally
coder-mos1 ran two real ci-postgres failure controls; the orchestrator verified the JSON
records independently. #2189 (startup failure) exit 1 and #2191 (post-readiness crash,
log proves ready then postmaster killed) exit 137 both take the workflow and the test
step down — terminal red. #2188, the genuine artifact, carries exit_code 0 under a
SUCCESSFUL workflow.

So the discriminator is structural — a failed service step with exit 0 under a successful
workflow — not the message string and not an incidental correlate like node or timestamp,
which were explicitly forbidden because they pass today and mask a real failure the moment
infrastructure shifts.

Verifier: exit 0 with one named exemption on the artifact; exit 1 with exempted_steps 0 on
BOTH real controls. No fetch, trigger, retry or re-roll — the coin flip is removed, not
codified.

PR #1033 dispatched to rev-974 with eight acceptance checks pre-registered before the diff
was read; AC2 (both real failures must NOT be exempted) is the crux and a REJECT if it fails.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 08:44:46 -05:00
mos-dt-0andClaude Opus 5 f11f257368 docs(remediation): bank D-36 — rotation-seam audit found three stale restatements on the board
Preparing the checkpoint for a cold read surfaced three stale sections, each a copy of
text owned elsewhere, each of which would have misled the incoming orchestrator: a
delivery-gate list still omitting the merge-gate step (D-26's own defect, still on the
board after MISSION.md was fixed); a capability rule superseded by D-13/D-15; and
DECISION-1 still marked CONTESTED hours after it was ruled.

None were wrong when written. All three drifted because they were copies — D-14 three
times in one artifact. The failure is not that someone forgot to update three lines; it
is that three lines existed to forget.

The rotation seam is what surfaced it. A familiar section is skimmed for the line you
came for; preparing state to be read cold by a stranger is a different act from
maintaining it, and catches a class ordinary use cannot.

RM-34: a handoff must VALIDATE the checkpoint, not merely write it. RM-02 registers the
general form with a must-fail on divergence. Interim: audit the board against its
sources at every rotation seam.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 08:14:04 -05:00
mos-dt-0andClaude Opus 5 6c779595e1 docs(remediation): rotation checkpoint — board rebuilt for a cold read, three stale restatements removed
Orchestrator rotating at ~803k tokens (~4x threshold). A mission built on
rotation-not-compaction should not run its own coordinator past it.

Board rewritten as the rehydration artifact: in-flight state, a read-this-first block
for the incoming seat, and the live rulings it most needs. Under the 8KB cap.

AUDIT AT THE SEAM found THREE stale restatements on this board, each of which would have
misled the incoming orchestrator:
  1. the delivery-gate list still OMITTED the merge-gate verdict step (the D-26 defect
     itself, still sitting on the board after MISSION.md was corrected);
  2. capability described as 'token-file set = authoritative registry', superseded by
     D-13/D-15 (capability is per-path; assert permissions.push as that seat);
  3. Sequencing still said DECISION-1 was CONTESTED and 'do not treat it as settled'
     hours after it was RULED — an incoming seat would have re-litigated a closed decision.

All three were restatements of text owned elsewhere. Replaced with references, per the
mission's own render-not-restate principle: a second copy is a second thing to go stale,
and this board proved it three times in one night.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 08:13:12 -05:00
mos-dt-0andClaude Opus 5 cc097f36c5 docs(remediation): re-run failed; RM-02 blocked on RM-61, declared bound honoured
Pipeline #2188 at the same head: ci-postgres the sole failure, everything else success
including gate-verify. f10-coder independently confirmed and applied the pre-registered
rule itself.

RM-02 blocked. No ad-hoc exemption, no third roll. Recorded why: two failures against one
earlier clean run makes 'best of five' feel reasonable, and the point of declaring the
bound in advance is that it binds when the result is inconvenient. A third roll would
have been indistinguishable from diligence, including to the person doing it.

Data for RM-61: the artifact hit twice consecutively at f9746b23 while #2184 was clean at
38f1b249, so it may cluster rather than be uniformly random — which makes a one-shot
re-roll close to worthless and strengthens the ruling that it must not become policy.

And the illustration: the anti-inert-gate registry is blocked by an artifact that makes
gate evidence unreliable. The thesis demonstrating itself on its own keystone.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 01:34:20 -05:00
mos-dt-0andClaude Opus 5 56d8e8a3d5 docs(remediation): record the bounded re-trigger as a stopgap; mark the first end-to-end merge stack
The re-trigger guardrail, recorded so it cannot become practice: one bounded,
pre-declared attempt at the same head with the response to each outcome fixed before
triggering. Re-running until the desired answer appears is p-hacking the pipeline, and
silently nobody can tell it from diligence — including the person doing it. Per Mos: a
per-PR free re-roll would be D-21 normalisation wearing a new hat. RM-61 must make the
re-roll unnecessary, not codify it, and a clean re-run does not retire RM-61.

Milestone: RM-03/#1032 completed independent review -> CI terminal-green -> merge-gate GO
-> coordinator -> held for owner, the first time end-to-end. GO posted under the gate's
own minted identity by a seat that structurally cannot merge. Head verified unmoved after
the verdict, so the commit-bound GO stands.

The first delivery through the complete stack is also the last one gated by a check that
could not fail — RM-03 is that check's fix.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 01:22:32 -05:00
mos-dt-0andClaude Opus 5 4589659bc1 docs(remediation): board — RM-03 GATE-READY, merge-gate assigned, held for Jason
First genuine gate-ready of the mission. Head triple equal at 78ec47cd, latest review
APPROVED at the current head, CI 9/9 by JSON scan with two-observer agreement.

Recorded the shape worth remembering: the queue guard is still inert for this merge
because RM-03 is the fix — the last merge to pass through the broken gate is the one
that fixes it.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 01:15:05 -05:00
mos-dt-0andClaude Opus 5 357a636a3a docs(remediation): promote redundant-observation to charter; bank D-35 (tool caught what attention could not)
Charter gains a fifth principle from D-33: two observers of the same evidence,
disagreeing, catch what neither catches alone — applied to evidence GATHERING, not just
judgement. A summary that resembles an enumeration is more dangerous than one that
obviously summarises; prefer the machine-readable record and state counts so divergence
is detectable.

D-35: while editing merge-gate.md to fix D-33, the coordinator recalled the mandate
string instead of reading it and the Edit tool's exact-match REJECTED it. Third instance
for that author, inside the turn fixing another instance of the same class — and the
only one that did not reach a document, because a mechanism caught it.

A rule that fails in its authors but is caught by a tool has told you where it belongs.
RM-02 should enforce verbatim citation by construction, as the Edit tool did by accident
of design.

Fix landed by annotating the source: merge-gate.md mandates 3 and 4 now require the
scan and count from the JSON record. The shared wrapper was deliberately NOT modified
mid-flight — three lanes are reading it; fix at a seam.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 00:53:27 -05:00
mos-dt-0andClaude Opus 5 9e205e8201 docs(remediation): bank D-34 — a context reset silently strips a seat's credential identity
rev-974 finished its RM-02 review and could not post it: pr-review.sh failed with
'Gitea token not found'. Verified — with MOSAIC_GIT_IDENTITY unset the token does not
resolve; with it set it resolves. The token file was correct throughout.

My own context reset wiped the seat's exported identity and my rehydration brief did not
re-establish it. git config mosaic.gitIdentity is persistent and per-worktree;
MOSAIC_GIT_IDENTITY is ephemeral and per-context. rev-974 works from ~/agent-work with no
git-config fallback, so it had no warning and the loss surfaced only when it next needed
a credential.

Intersection of two banked findings, created by acting on one: D-31 prescribes rotation,
D-11a requires identity coherence, and nothing said rotation is a credential-affecting
operation. The fix for one failure introduced another.

RM-34: rotation must re-establish AND verify seat identity before handing over work.
RM-50: prefer the durable binding (mosaic.gitIdentity in the seat's repo) so identity
survives a reset by construction. Interim: every rehydration brief re-exports identity.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 00:51:21 -05:00
mos-dt-0andClaude Opus 5 73a313301b docs(remediation): bank D-33 — the full-step-scan tool prunes a step in default output
coder-mos1 scanned pipeline #2186 with -f json and found 9/9 child steps; my scan of the
same pipeline in the wrapper's default text mode showed 8. Verified: text mode omits
clone (JSON shows the ci workflow entry, clone, and the 8 visible ones).

Every full step scan performed tonight enumerated 8 of 9 real child steps and reported
it as complete. clone succeeded throughout so no verdict changes — but the method was
incomplete and its user did not know.

The merge-gate mandate requires a FULL step scan and requires verdicts to enumerate the
step count. A verdict citing 8 where 9 exist is non-conforming evidence, and a gate using
this wrapper's default output would produce exactly that while believing it complied.

The shape is the session's thesis aimed at the detection tool: the doc says read the
artifact not the summary, and text mode IS a summary that looks like an artifact. Compare
D-24 — mergeable was a true answer to a different question; this is a true answer to a
smaller one.

Caught only because two observers' counts disagreed; neither alone would have found it.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 00:49:01 -05:00
mos-dt-0andClaude Opus 5 eddf718a5c docs(remediation): board — RM-02 frozen at 38f1b249 with a fully clean 9/9 scan
First run on this branch where ci-postgres passed, so no exemption question arises.
Recorded that the artifact's intermittency is evidence FOR RM-61's negative-control
requirement: intermittent means delivery is a coin flip until the signature is proven to
discriminate from a real database failure.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 00:35:51 -05:00
mos-dt-0andClaude Opus 5 c83a3cd3e2 docs(remediation): bank D-32 — the repaired gate shipped with a documented switch to skip it
rev-974 blocked RM-03: pr-merge.sh still ships --skip-queue-guard at five sites
including a worked example. It proved this rather than reading it — stubbed the guard to
exit 99, ran a real fixture merge with the flag, and observed the guard never called,
provider payload created, 'merged successfully', exit 0.

Disqualifying because RM-03 repairs a mandatory gate that has never been able to fail;
shipping that repair with a documented bypass means the gate merely requires one flag
instead of zero, and every merge-side CANNOT_ASSERT/HOLD semantic is skipped. L0 bars
equivalent skip switches, and the merge-gate role doc names this exact hazard about
force_merge — adjacent to the field you came to edit, at the moment you are most
motivated to reach for it.

Generalizable: repairing a gate is incomplete while any supported path skips it. The
failure changes from 'cannot block' to 'can be told not to' — the same outcome one
keystroke later. Removing the bypass is part of the repair.

Everything else passed independently, including the 160 KiB stdin transport where #1023
regressed.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 00:33:18 -05:00
mos-dt-0andClaude Opus 5 bf8c6f4a89 docs(remediation): bank D-31 — seat ran past 100% context with 28 uncommitted files
coder-mos1 hit 102.5%/372k on RM-03 with 28 modified files uncommitted and its branch
still at base — a full context window spent with nothing durable. Caught by polling seat
state, not by any system signal. Nothing warned anyone: no threshold alert, no
pre-compaction hook.

The founding failure mode of this mission — compaction destroying in-flight work —
nearly hit the mission's own delivery twice in one night. RM-01 survived because it had
committed work when checkpointed; this one had none. Commit-then-rotate works;
rotate-without-commit loses everything.

RM-34: a context threshold is not enough — rotation must force a durable checkpoint and
refuse to rotate a seat with uncommitted work. RM-50: seat context is observable state
and must be monitored; relying on an orchestrator to poll is instructions-not-enforcement
applied to lifecycle. Brief doctrine: commit early, commit WIP.

Adjacent: the diff spans 5 guides and 11 templates against a brief scoped to one script.
Queried, not assumed — but a 28-file diff from a one-script brief is a scope signal
regardless of the answer.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 00:07:59 -05:00
mos-dt-0andClaude Opus 5 bdf8932328 docs(remediation): RM-61 terminal-green exemption ruled B, with sequencing correction
Condition 1 tested: the signature is stable — pods "wp-svc-<ULID>-ci-postgres" not
found across all five observed failures, an orchestration-layer lookup miss structurally
unlike a service-level failure.

But discrimination is UNPROVEN: every observation co-occurs with a demonstrably working
database, and we have never seen a real ci-postgres failure on this provider. If
PostgreSQL crashes and the pod is GC'd, the status query may also return pod-not-found —
the exemption would over-match and mask a real failure.

So conditions 1 and 2 are not independent: 2 is the evidence for 1. Build the negative
control first, prove a real failure produces a different signature, then adopt the
exemption. Kill criterion stated in advance: if an injected real failure also yields
pod-not-found, B is unsafe and we do A.

Filed as RM-61, unassigned — no free write-capable seat; flagged rather than stacked
onto a busy lane.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 00:04:32 -05:00
mos-dt-0andClaude Opus 5 16d11cd6cd docs(remediation): bank D-29 (syntactic criterion binding) and D-30 (false comparator, mine)
D-29: rev-974 moved two criterion bindings to an unrelated case, reformatted the
manifest, and gate:verify still exited 0. The registry verifies a criterion HAS a
binding, not that the bound case can fail for that criterion's stated reason —
RM02-REQ-03 unsatisfied. The keystone reproduced the defect it exists to eliminate, in
its own coverage check. Caught only by mutating and re-running; inspection would have
passed it.

D-30: my review brief claimed the ci-postgres FAIL appeared on #2167 — it did not
(#2167 is OK). My own banked D-21 says so explicitly; I restated from memory instead of
reading my record. D-26 recurring, in a reviewer brief, hours after promoting
render-not-restate to the charter.

The harm is not the inaccuracy but that I supplied a reviewer with fabricated supporting
evidence for my own reading. It refuted me — query-for-refutation paying for itself in
the same document that introduced it.

Requirement: briefs cite evidence from the record with identifiers, never from recall.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 23:59:25 -05:00
mos-dt-0andClaude Opus 5 8ce77fcb0d docs(remediation): board — RM-02 frozen at 9b4d4beb, CI green, review in flight
Head triple verified independently twice (orchestrator + f10-coder): local = origin =
PR #1030 = pipeline #2182. Full step scan rather than a tests-complete inference.
Queue guard not offered as evidence.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 23:41:52 -05:00
mos-dt-0andClaude Opus 5 cdd5568adb docs(remediation): promote query-for-refutation to charter doctrine
Per Mos. A subordinate asked to confirm a hypothesis will agree — the bias is induced by
the query, not by the answerer's diligence. 'The DB flaked, please confirm' and 'confirm
or refute, with the log line that proves it' are different instruments returning
different answers to the same question.

This matters most with agent subordinates, which are agreeable by construction, so the
discipline cannot rest on the answerer being rigorous — it must be built into how the
question is asked.

Origin: the orchestrator's ci-postgres hypothesis was refuted by the implementing seat
with log evidence and then settled by reproduction. Phrased for confirmation, it would
have returned agreement and D-21 would have been re-classified on a false premise,
silently corrupting a banked finding.

Operational form: state the hypothesis as yours, ask for evidence that kills it, say
what would change your mind, and reproduce when the answer is consequential. Added to
KICKSTART's standing invariants so it survives compaction.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 23:21:15 -05:00
mos-dt-0andClaude Opus 5 ff4b45b025 docs(remediation): RM-03 CANNOT_ASSERT semantics ruled (option B)
Resolves an ambiguity in the orchestrator's own brief, which required CANNOT_ASSERT to
neither silently pass nor permanently block without distinguishing push from merge.
coder-mos1 stopped and asked rather than inferring authorisation; Codex security
independently flagged CWE-693.

Ruled B: merge fails CLOSED (proceeding without exact-head CI evidence is D-23's
condition in a narrower costume), push degrades AUDITED (blocking during an outage
bricks delivery — the Pi-brick class we already banked). A temporary block pending
evidence is not a permanent block, and merge is separately gated by the merge-gate and
coordinator, so nothing is stranded.

Conditions: distinct exit code or the tri-state is destroyed; the audit record asserted
by a registered case, not assumed, or 'audited' is a claim dressed as a property;
retryable and self-clearing; cases observed RED first; no silent degraded merge path —
break-glass belongs to RM-05.

Option C rejected: it bricks push during an outage and defers the degraded path, which
in this codebase means a silent bypass appears under incident pressure. Three are
already on the books.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 23:17:01 -05:00
mos-dt-0andClaude Opus 5 f47cf45b0c docs(remediation): bank D-28 — a swallowed diagnostic destroyed a fail-closed check's evidence
RM-02 CI failed on four sandbox tests. Bubblewrap is installed by the gate step but not
the test step, so spawnSync returned ENOENT; replayCommit replaced the spawn diagnostic
with an empty string, so the classifier could not prove Bubblewrap provenance and
correctly refused to treat it as expected sandbox unavailability.

The refusal was right; the information loss was the bug. For a classifier, error text is
not decoration — it is the input. Widening acceptance to make the test pass would be a
finding, not a fix.

Linkages: D-16 again (local has bwrap, CI does not — local and CI disagree a third
time), and diagnostic-preservation registered as an RM-02 gate requirement with a
must-fail control proving a swallowed message is detected.

Process note: the orchestrator's hypothesis that the coincident ci-postgres FAIL caused
this was WRONG and was refuted with log evidence. D-21 stands unchanged as a teardown
artifact and is NOT upgraded — it was about to be re-classified on a false premise.
Asking the seat to confirm or refute rather than accept is what prevented that.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 23:10:53 -05:00
mos-dt-0andClaude Opus 5 e7c9160c7b docs(remediation): board — delivery-gate doctrine change recorded with render-vs-restate root cause
Per Mos's item 4. The gate definition was incomplete from setup because the gates were
restated from memory rather than referenced, and the omission propagated into every
worker brief since — then recurred inside the correction itself (D-26).

Board now carries the referenced sources, the gate order, freeze-after-GO, the
coordinator/orchestrator split, and the queue-guard zero-information field form.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 23:01:07 -05:00
mos-dt-0andClaude Opus 5 2d58779675 docs(remediation): bank D-27 — role file certifies the inert queue guard as enforced
rev-974 found this while loading the canonical gate sources, i.e. because we switched
from restating to reading. Verified in roles.local/merge-gate.md: mandate 3 requires
verifying 'CI queue guard clear', mandate 4 requires enumerating 'the queue-guard
outcome' in every durable verdict, the merge path annotates it 'real', and the control
table at :290 certifies it '✅ enforced … genuinely aborts'.

The document is correct about the WIRING and wrong about the CONTROL: set -euo pipefail
with an unguarded exit does abort, but the guard cannot produce a non-zero exit for any
input (D-23). A mechanism correctly wired to a sensor that never fires, certified as
enforced.

Compounding: the verdict format REQUIRES the queue-guard outcome as evidence, so a
conforming verdict must include a meaningless field — the role file instructs the gate
to manufacture evidence, in the mandate that exists to stop bare conclusions.

Interim: record the field labelled ZERO-INFORMATION (inert, owner RM-03) rather than
omitting it — omission makes the verdict non-conforming; silent citation is worse.

Escalated: operator-owned file, coordinator's to fix. Recommend annotation not deletion
— the requirement is correct once RM-03 lands.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 22:55:28 -05:00
mos-dt-0andClaude Opus 5 cbbe3e1ce2 docs(remediation): gate definition now REFERENCES canonical roles; bank D-26
The delivery-gate definition was incomplete from setup — the merge-gate verdict step
was missing because the gates were restated from memory rather than referenced, and the
omission propagated into every worker brief since.

Then it recurred inside the correction: the correcting message was itself a restatement
and dropped five things, including a security precondition (an unminted gate seat fails
open to the owner's admin account — the #3084 breach mechanism) and a citation to a file
that does not exist.

D-26 is the definitive case because every condition favoured success: attention maximal,
actor knew the rule best, subject was the rule itself. A rule its own enforcer cannot
follow while enforcing it is not a discipline — it is a requirement for a mechanism.

MISSION.md and KICKSTART.md now reference fleet/roles.local/merge-gate.md and
fleet/roles/validator.md and state only the gate ORDER. Every reference resolves; a
dangling pointer is worse than a restatement.

Precondition independently verified: merge-gate token is least-privilege,
pull=True push=False admin=False — structurally cannot merge.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 22:53:13 -05:00
mos-dt-0andClaude Opus 5 9a7ab73952 docs(remediation): charter — Builds 1-2 justified by two independent impossibility proofs; RM-60 option analysis
Per Mos. The choke-point executor and PG spine are not a design preference — they are
forced. Twice during the mission's own first deliveries, work stopped against a security
property that cannot exist at the layer needing it: D-19 (audited party controls the
manifest certifying it — artifact integrity) and D-25 (audited party controls the code
entering the sandbox — execution integrity). Both reduce to self-verification by the
audited party is not verification, and both resolve only via an authority outside its
control.

Neither proof was sought; both arrived while shipping something else, from different
directions, at different layers. An architecture forced by two independent impossibility
proofs is stronger evidence than one argued for.

RM-60 records Mos's sharper option analysis: A (unprivileged userns) does NOT fix the
vulnerability — it grants a capability and leaves the ORDERING defect untouched, so B is
required regardless; A without B is kernel exposure bought for nothing. B is the correct
primitive, generalises to RM-59 and the choke-point executor, and may not need A at all.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 22:09:38 -05:00
mos-dt-0andClaude Opus 5 2b85afe4ea docs(remediation): bank D-25, accept RM02-REQ-10 revision, open RM-60
RM-02's per-commit replay needs isolation; the privileged CI step was correctly refused
because PR-controlled code executes before Bubblewrap establishes any boundary — the
untrusted party would obtain the capability meant to contain it. Ordering defect, not a
hardening problem.

D-25 is D-19 one layer down: audited party controls the manifest (artifact integrity)
became audited party controls the code entering the sandbox (execution integrity). Both
reduce to self-verification by the audited party is not verification, and both resolve
via an authority outside its control — twice now this mission has derived Builds 1-2
from a security impossibility rather than design preference.

Option C ruled independently by the orchestrator and rev-974 before either saw the
other. rev-974 added the condition I missed and it matters most: post-merge replay is
DETECTION, not PREVENTION, with a defined quarantine/revert response, and must never be
presented as equivalent to a pre-merge gate.

RM02-REQ-10 revision formally recorded and accepted under RM-02's own clause 4 —
original text, restatement, reason — discharging rev-974's review-readiness condition.
RM-60 opened for the external pre-execution trust boundary, cross-referenced with RM-59.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 22:05:50 -05:00
mos-dt-0andClaude Opus 5 eabe04bc5e docs(remediation): bank D-24 — mergeable:true cited as merge-readiness; D-23 corrected backward
Mos verified #1023 before relaying and corrected my framing. Verified independently:
review id-58 REQUEST_CHANGES at f6334080, the current head — the block is live, and its
findings are that #1023's own fix is defective (unknown still exits 0, payload-as-argv
hits ARG_MAX, tests do not assert exits).

mergeable:true is git-mergeability, not readiness. The charter's first principle
committed by the orchestrator inside an escalation about proxies. Fifth instance of mine.

The mechanism, named because it will recur: mergeable is not a lie, it is a true answer
to a different question. A false field would have been caught; a true-but-adjacent field
passes every sniff test — which is why the discipline must be mechanical, not attentive.

D-23 corrected backward per D-14-as-amended, original framing quoted.

RM-02: readiness cases must assert the decision-relevant property — latest review state,
CI terminal status on the exact head, required approvals — never a structural proxy.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 20:50:46 -05:00
mos-dt-0andClaude Opus 5 36018be8d1 docs(remediation): bank D-23 — the mandatory queue guard has never worked, for any input
RM-02's registered fixtures found this before the registry was built. Worse than the
banked unknown=>exit 0: ci-queue-wait.sh:266 pipes the payload into a classifier
starting 'python3 - <<PY', so python reads its PROGRAM from stdin and json.load never
sees the JSON. Proven empirically — success, failure, pending and malformed all
classify as unknown, and unknown exits 0.

The mandatory pre-push/pre-merge guard therefore returns PASS for every possible input,
including a genuinely failing CI. The six observed meaningless greens were not an edge
case; they are the only output it can produce.

PR #1023 is exactly this fix, open and parked, and its body diagnoses it precisely.
Two aggravating details from that body: pr-ci-wait.sh:38 documented the bug and remedy
and it was never backported to the mandatory sibling (D-14 propagation with a
security-adjacent blast radius); and the fix was opened without re-verification.

Escalated for Jason's #1023 disposition. RM-02 records required-vs-actual with
DEFECT (owner: RM-03); no RM-03 lane opened, guard not edited.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 20:44:34 -05:00
mos-dt-0andClaude Opus 5 8c496993e4 docs(remediation): bank D-22 — the registry would have verified the wrong artifact
The gate that actually runs is the installed copy at ~/.config/mosaic/tools/git/;
a repo-scoped registry would test packages/mosaic/framework/tools/git/. Byte-identical
today (sha256 19cda2f7009c536e both) but nothing asserts it.

A registry that verifies the wrong artifact is worse than none — it manufactures
confidence, and the divergence would be invisible from every signal we have: registry
green, CI green, deployed gate arbitrarily different.

D-1/P-ACTIVATION applied to the enforcement mechanism itself rather than to config.

RM-02 gains: for every registered gate with a deployed counterpart, assert
repo-source == deployed-copy with a must-fail control; where none exists, record that
explicitly.

Found by design review before implementation — the only finding tonight not found by
execution, which is the design-first gate on keystone tasks paying for itself.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 20:14:13 -05:00
mos-dt-0andClaude Opus 5 e85a088f85 docs(remediation): bank D-21 — a FAIL that means nothing is a green that means nothing, sign-flipped
ci-postgres reports FAIL under an overall-success pipeline on #2170 and #2175 while all
eight functional steps pass. Most likely a service-pod teardown artifact; the test
step's pg_isready fail-fast guard passed, so the database was available during the run.

Low severity, but the pattern matters: a red that is routinely present and routinely
correct to ignore trains operators and agents to discount reds, and the discounting
generalises. Six instances of a meaningless green are already banked; a meaningless
FAIL is the same erosion with the sign flipped.

Recorded rather than normalised — the first time it is waved through without a note is
when it becomes background noise.

RM-55: treat a non-terminal-success sub-step under an overall-success pipeline as a
reportable anomaly, and make the CI contract state which steps may fail without failing
the pipeline. An implicit allowance is indistinguishable from a bug.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 20:08:34 -05:00
mos-dt-0andClaude Opus 5 8a795df0ce docs(remediation): D-14 amended by D-20 — propagation is bidirectional
ci/woodpecker/pr/ci Pipeline was successful
Both the orchestrator and the coordinator read D-14 as forward propagation only: a
ruling reaches the documents stating the new rule. D-20 proved that insufficient —
when D-19 superseded part of D-18, the consequence went forward into the charter and
the delivery conditions but never backward into D-18, which kept asserting a withdrawn
claim until a reviewer disproved it by experiment.

A supersession must update BOTH the documents rendering the new rule AND the finding it
retires, with the retired wording quoted rather than deleted. Interim rule updated
accordingly.

Applying D-14's own rule to D-14, in the same commit that records the amendment.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 19:53:36 -05:00
mos-dt-0andClaude Opus 5 f5a0566198 docs(remediation): board — RM-01 MERGED (f58b3699); RM-02 keystone is next
ci/woodpecker/pr/ci Pipeline was canceled
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 19:50:36 -05:00
mos-dt-0andClaude Opus 5 1e7a0701fd docs(remediation): fix D-18 overclaim (D-20) — reviewer empirically disproved my own documentation
rev-974 blocked #1027 a second time, and the defect was in this file, not the code.

D-18's AC2 restatement omitted the accidental/independent scope D-19 made mandatory,
and D-18 asserted the tampered-manifest control turns integrity 'from a claim into a
property'. It does not and cannot — that sentence predated D-19 and was never revised
when D-19 landed. rev-974 disproved it by experiment: a same-UID consistent
manifest+marker rewrite passed preflight.

Two banked findings firing on the orchestrator at once: the integrity-claim corollary
(I wrote a claim in the voice of a property, in the document defining the rule against
it), and D-14 propagation — I carried D-19's consequence forward into the charter and
the delivery conditions but never back into the finding it superseded. Backwards
propagation is the same defect as forwards and I did not audit for it.

Corrected in place with the original wording quoted and the disproof recorded, not
silently rewritten.

RM-02 fifth clause: documentation asserting a security or integrity property is itself
a claim requiring a negative control observed red. Prose is not exempt from the
mission's evidentiary standard, and governing prose least of all.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 19:48:00 -05:00
mos-dt-0andClaude Opus 5 43f69bf167 docs(remediation): promote D-19 to charter; bind residual risk to RM-59 as a tracked edge
Per Mos, with his two additions.

Charter gains a fourth first-class principle: when a property cannot exist at the layer
that specified it, three honest moves are mandatory — implement what the layer can
guarantee; state the boundary in BOTH directions (what it does not defend AND what it
does, since either alone misleads); and record the real guarantee as a TRACKED
DEPENDENCY, not prose. A written-down gap is acceptable engineering; an implied-fixed
gap is the mission's core failure in a new costume.

The residual risk is now RM-59 (depends_on RM-12, RM-21, RM-25) — a real backlog task
owned by the choke-point executor and spine, which verify from outside the worktree's
authority. Mos's point: 'record where the guarantee comes from' only holds if the record
is a live dependency someone must close; a documented gap with no owner becomes a
permanent gap that reads as intentional.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 19:23:15 -05:00
mos-dt-0andClaude Opus 5 f9435c2a03 docs(remediation): bank D-19 — an integrity property that cannot exist at its specified layer
Implementing the D-18 manifest hit CWE-345: manifest and marker share one same-UID
writable tree, so that actor can regenerate both and pass. No local construction fixes
self-authentication without a key outside its authority. The seat escalated rather than
calling it tamper-resistant — the charter corollary working on its first real test.

Ruling: Option A, scope AC2 to accidental/independent/stale mutation, retain the design.
The undefendable boundary is not the weak link (same-UID write already owns the source,
the tests, preflight.mjs and .husky); AC2 exists for the D-5 staleness class, against
which the design works; and a real anchor arrives with the choke-point executor and PG
spine, which verify outside the worktree's authority.

Acceptable only with honest labelling: threat model verbatim in code and PR, the words
tamper-proof/tamper-evident/secure barred there, scope carried in AC2's restatement,
residual risk named as backlog, all controls kept RED-first.

Generalizable: when a property cannot exist at the layer it was specified, implement
what the layer can guarantee, state the boundary precisely, and record where the real
guarantee comes from. A known gap written down is acceptable; a gap implied fixed is not.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 19:20:05 -05:00
mos-dt-0andClaude Opus 5 3b191b6b34 docs(remediation): promote the three-mode taxonomy and the integrity-claim corollary to the charter
Per Mos. Two first-class principles alongside observe-the-property:

1. Pre-registration prevents RETROFITTING and nothing else. A pre-registered check set
   can be WRONG (D-8), INCOMPLETE (D-17), or INTERNALLY INCONSISTENT (D-18). It confers
   neither correctness nor coverage nor consistency. All three modes were found on this
   mission's own first delivery, by the machinery applied to its own work. RM-02's four
   clauses are the enforceable form.

2. Never ship an integrity claim dressed as a property. A verification artifact
   writable by the actor whose behaviour it certifies certifies the attack. It must sit
   inside its integrity envelope, publish atomically, and carry a tamper negative
   control observed red. If it cannot be made tamper-evident, say so and reconsider —
   an honest 'this cannot be verified' is always available and always preferable to
   laundering foreign content as certified.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 19:14:06 -05:00
mos-dt-0andClaude Opus 5 85bdbe3383 docs(remediation): bank D-18 — pre-registered criteria AC2 and AC4 were mutually unsatisfiable
Implementing D-17's fix surfaced a conflict between criteria, not within one. AC2
(reject symlinked generated state) cannot hold alongside AC4 (canonical build
succeeds): verified independently that apps/web sets output:'standalone' and the built
tree carries 42 legitimate pnpm symlinks under .next/standalone. Only building the
tree reveals it.

Completes the chain: a pre-registered check set can be WRONG (D-8), INCOMPLETE (D-17),
or INTERNALLY INCONSISTENT (D-18).

Ruling: build-certified symlink manifest — .next itself still rejected; descendants
rejected unless exactly certified. Stronger than blanket rejection because it catches
retargeting. AC2 restated and RECORDED with provenance rather than absorbed, since
silently resolving a conflict between pre-registered criteria destroys the point of
registering them.

Hardening: the manifest is generated state, so a manifest writable by whoever plants a
rogue symlink certifies the attack. Must be inside the integrity envelope, published
atomically, with negative controls observed red first including manifest-tampered.

RM-02 fourth clause: the registry must detect conflicts between criteria, and retain
original text plus restatement plus reason when a criterion changes meaning.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 19:11:52 -05:00
mos-dt-0andClaude Opus 5 ae4baf145d docs(remediation): bank D-17 — pre-registration confers neither correctness nor coverage
rev-974 blocked PR #1027: AC2 was pre-registered and explicitly required rejecting
symlinked generated state; the implementation accepts it (ln -s into .next, preflight
exits 0 instead of 43) while the acceptance suite ran 21/21 green throughout.

Confirmed independently: preflight.mjs:82-92 rejects symlinks on the SOURCE path,
:28 merely skips symlinked dirs, and the generated-state path :141-163 checks uid but
never isSymbolicLink(). The suite's only symlink cases cover the turbo binary and a
source file.

Sharpens D-8 rather than repeating it. D-8: pre-registration does not confer
CORRECTNESS. D-17: it does not confer COVERAGE — a suite can be green with every
criterion appearing satisfied while a criterion's actual requirement is untested.

RM-02 third clause: the registry must bind each criterion to the specific case that
exercises it and prove that case red before trusting its green. Mutation testing
pointed at the criterion-to-case mapping, not just the gate.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 19:07:58 -05:00
mos-dt-0andClaude Opus 5 4512312b9f docs(remediation): D-16 ownership — #1024 is Jason-pending; CI is the authoritative gate for #1027
Propagating Mos's ruling in the same commit that records it, per D-14's interim rule.

The hermeticity fix IS PR #1024, which sits in Jason's parked delivery stack, so its
disposition is his — marked SUPERSEDED-PENDING-JASON alongside #1023. D-16 strengthens
urgency without transferring ownership; we do not open a third lane on a parked PR.

Class sharpened: a pre-push gate an operator cannot run locally is a gate only CI
enforces, so pointing .husky/pre-push at it misrepresents where the gate lives.
Non-hermetic gates make every green host-dependent.

#1027 proceeds on CI-green; the local exit-97 is a host-specific guard abort and is
not a merge consideration.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 18:43:25 -05:00
mos-dt-0andClaude Opus 5 e233f196b5 docs(remediation): bank D-16 — local and CI test gates disagree by environment
Ran down Mos's flag. Both hypotheses were wrong: CI runs exactly 'pnpm test' (same
command, path IS exercised) and is green, while this host exits 97 on an
environment-dependent BASH_LINENO guard (#973) that aborts on bash 5.2.15 and not in
CI's container. PR #1027 touches zero files under packages/mosaic, so the guard is
genuinely pre-existing — f10-coder's report was accurate in every particular, and main
is equally affected here.

Not 'merges step around a red' but something worse in one respect: the local gate and
the CI gate disagree about what passing means. No agent on this host can get a green
pnpm test on any branch. A gate only CI can run cannot be a pre-push gate.

Second defect found while establishing this: in the main checkout the same package
fails differently (exit 1) because a test scans the working tree and picks up
apps/coordinator/venv third-party site-packages. A test whose verdict depends on
untracked files is not hermetic — same contamination source that broke format:check,
one foreign tree breaking two independent gates.

Coordinate with #1007/#1024 rather than opening a third lane.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 18:40:53 -05:00
mos-dt-0andClaude Opus 5 3477e933df docs(remediation): bank D-15 — token scope is not repository permission
f10-coder holds gitea-mosaicstack-f10-coder.token with write:repository scope and was
verified at mint by 'repo access returns 200'. It cannot push: collaborator lookup
404s and its own token reports push:false, pull:true.

Capability has three independent layers — token file (raw-API auth), tea login (tea
path), repository permission (actual write authority) — and satisfying two proves
nothing about the third. Scope bounds what a token may ATTEMPT; repository permission
decides what the user may DO.

The charter principle failing on the check meant to confirm capability: a 200 on a
READ was accepted as evidence of WRITE. written-unverified treated as verified, by
both provisioner and orchestrator, one layer above D-12.

RM-50's pre-dispatch check must assert effective permission for the intended operation
(permissions.push == true as that seat), not token existence or a read returning 200.
A capability check that cannot fail on a seat lacking write permission is itself an
inert gate.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 18:32:27 -05:00
mos-dt-0andClaude Opus 5 d0ad6e942b docs(remediation): propagate DECISION-2 to charter — second un-propagated ruling, found by applying D-14
Applied D-14's own interim rule immediately instead of waiting to be bitten again, and
it caught a second instance within minutes: MISSION.md's standing directives still
stated the DB hard-cutover with no mention of Mos's binding qualification that the
spine must not be a single-point hard-stop (degraded mode + rollback artifact
required). A seat reading the charter would have designed toward an availability
posture the coordinator had explicitly rejected, with the superseded 'no DB means the
fleet stops' recommendation nowhere contradicted.

Two un-propagated rulings out of two that touched charter text. Without a mechanism,
propagation failure is the default outcome, not an oversight — which is the argument
for D-14 being a requirement rather than a discipline.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 18:12:16 -05:00
mos-dt-0andClaude Opus 5 7f686aaf6d docs(remediation): bank D-14 decision-propagation requirement; record D-13 reconciliation
D-14: DECISION-1 was ruled and applied to TASKS.md while MISSION.md — the charter a
cold-starting seat reads first — kept the superseded wire-in target for hours, flagged
CONTESTED on the board but never corrected in the source of truth. A resuming seat
would have read the rejected target as authoritative. Caught by hand during an
unrelated edit; nothing would have caught it otherwise.

P-MISSION-001 turned on ourselves: a decision that lives in a ruling and a board note
but not in the authoritative record has been AGREED, not MADE. Requirement: rulings
must propagate mechanically — decisions as records, documents rendering rather than
restating, and a must-fail check where duplication is unavoidable. Interim rule until
the DB cutover: the same commit that records a ruling updates every document stating it.

D-13 updated with Mos's reconciliation: 5 of 6 mosaicstack-provisioned seats have no
tea login — systemic, not a one-off. Supersedes D-11(b): the token-file set is
necessary but NOT sufficient; capability is per-path.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 18:11:01 -05:00
mos-dt-0andClaude Opus 5 f13222b76b docs(remediation): charter reflects DECISION-1 corrected wire-in target and current status
The charter's build-1 cell still named mosaic_orchestrator.py::run_single_task after
DECISION-1 ruled against it. Leaving the charter contradicting the ruled decision would
mislead any future reader who starts there — corrected in place with the rationale and
provenance, rather than only in TASKS.md.

Also: status PLANNING -> EXECUTING; scout TODO discharged (file is in-tree) with a note
that its findings stand but its recommended wire-in point is superseded.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 18:07:16 -05:00
mos-dt-0andClaude Opus 5 d1e7ba19ca docs(remediation): promote observe-the-property principle to charter; bank D-13 dual credential registries
Charter gains a first-class principle per Mos: no write is done until the requested
PROPERTY is observed; a success exit code is not evidence. Success output is designed
to be believed — that is why the inert-gate class exists and why the P-WRAPPER
tri-state is not optional. Recorded with its provenance: the orchestrator committed
this exact error (D-12), and three of the session's twelve instances were its own.

D-13: diagnosing D-12 found two parallel credential registries that can disagree.
gitea-mosaicstack-mos-dt-0.token EXISTS, but tea has no mosaicstack login for that
identity — so raw-API paths work while tea-dependent wrapper paths silently degrade.
tea is not stale; the login does not exist. Capability declared authoritative by the
token-file set does not govern the tea path.

RM-04 must reconcile the registries (or assert agreement at startup, with a must-fail
control). RM-50's pre-dispatch check must verify capability for the path actually used.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 18:06:18 -05:00
mos-dt-0andClaude Opus 5 0ffdcf14bd docs(remediation): bank D-12 — pr-create silently dropped --draft; I trusted exit 0 over observed state
PR #1027 was created with -d because it carries partial unproven work. tea auth was
stale, the wrapper fell back to the raw API which cannot set draft, warned on stderr,
and exited 0. The PR sat open and mergeable for ~25 minutes, protected only by the
word DRAFT in its title and body. I had reported it to the coordinator as a draft.

Three failures: a fallback silently degrading a SAFETY flag (nuisance for --labels,
dangerous for --draft); a correct warning nobody consumed; and my own failure to
verify the flag took effect — I checked the PR existed, not that it had the property
I required. That is written-unverified treated as verified, by me, on exactly the
class of tool this mission exists to distrust.

Fixed via the WIP: title prefix; draft:True verified after.

RM-02 gains a must-fail control: a wrapper that cannot honour a safety-relevant
argument must exit non-zero. RM-24 gains this as its canonical tri-state example.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 18:03:29 -05:00
mos-dt-0andClaude Opus 5 be10bdc828 docs(remediation): board tick — 2 PRs merged, RM-01 on rotated seat, dispatch doctrine
Board now carries the pre-dispatch capability check (token-file existence), the
token/authorship coherence rule, and the accreted worker-brief doctrine, so a
compacted or fresh seat inherits them mechanically rather than by recall.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 18:01:55 -05:00
mos-dt-0andClaude Opus 5 2201c30284 docs(remediation): correct D-11(a) mechanism — token identity and commit authorship are separate
Per Mos. MOSAIC_GIT_IDENTITY resolves the TOKEN; commit author comes from git config
user.name/user.email, a separate setting that fell back to the generic value. The
export could never have fixed authorship — my worker brief instructed only the export,
so the seat did what it was told and the commits were still mis-attributed. The error
was in the brief before it was in the finding.

Requirement is COHERENCE: token and authorship must agree; either half alone is drift.
Belongs in seat setup, verified by an exit-asserting test that commits and asserts the
author — not in prose a seat can follow correctly and still end up wrong.

Capability check mechanized: capability IS token-file existence. Before dispatching
seat X to provider Y, test gitea-<Y>-<X>.token exists. The token-file set is the
authoritative capability registry.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 17:59:06 -05:00
mos-dt-0andClaude Opus 5 75dfe2fa75 docs(remediation): bank D-11 — identity drift + seat capability opacity at dispatch
RM-01's seat was briefed to export MOSAIC_GIT_IDENTITY; its commits are authored as
the generic mosaic-coder fallback, so git history cannot say which seat did the work.
P-WRAPPER-001 reproduced on our own delivery.

Separately, nothing at dispatch time revealed the seat lacked a credential for the
target provider — discovered only when it failed mid-task after ~$9 and 69% context.
get_gitea_token behaved correctly by refusing to borrow another slot's token; the
dispatch-time information simply did not exist.

RM-50 gains per-seat capability declaration + pre-dispatch check; RM-04 gains
identity-binding verified by an exit-asserting test rather than assumed from an
export in a brief.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 17:56:34 -05:00
mos-dt-0andClaude Opus 5 409bf23e6a docs(remediation): bank D-10 — the queue guard's failure modes are inverted
Same required gate, both directions wrong: fails OPEN on state=unknown (5 meaningless
greens this session, wrong branch too), and fails CLOSED on credential resolution,
hard-blocking a worker's completed work. The identical command succeeded from that
worker's own worktree in another shell, so the checkout was fine.

A gate that waves through unchecked work and blocks ready work has its failure modes
backwards. Availability failures must degrade to a loud, audited CANNOT_ASSERT;
correctness failures must block. Also the Pi-brick shape: a gate whose unavailability
prevents recovery from it.

RM-03 extended to a third requirement: distinguish CANNOT_ASSERT from
ASSERTED_NOT_READY, both registered with must-fail controls, neither exiting 0 silently.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 17:52:42 -05:00
mos-dt-0andClaude Opus 5 31c3191305 docs(remediation): rolling-branch resume pointer + D-9 interim comms rule
KICKSTART resume now points at origin/remediation/state for the live board, per Mos's
cadence ruling: every tick is pushed to the rolling branch immediately (durable
per-tick, no per-tick main PR); main carries periodic snapshots only. Reading the
board from main would silently yield a stale tick, so the step warns explicitly.

D-9 hardened: comms/v1 must use file/stdin transport, never argv interpolation.
Standing interim rule until then — agent-send -f for any body with special
characters, never -m. Mandatory in every worker brief alongside the D-8 clause.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 17:50:26 -05:00
mos-dt-0andClaude Opus 5 6a067174ed docs(remediation): bank D-9 — comms path shell-interprets message bodies
agent-send.sh -m with backticks executes them as command substitution: the recipient
got a mangled body plus a shell error, and the send still reported success. Same class
as the known pr-create.sh backtick bug — two tools in the comms path treating a
message body as shell input.

The failure mode is the mission's own pattern: silent corruption with a success
receipt.

Requirement on RM-40/RM-42: comms/v1 must carry payloads verbatim with no shell
interpretation at any hop, with a byte-identical round-trip test (backticks, command
substitution, quotes, newlines) registered under RM-02 including a must-fail control.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-31 17:48:17 -05:00
18942 changed files with 42029 additions and 3008799 deletions

No files matched your search

+150 -20
View File
@@ -1,24 +1,154 @@
# Non-secret runtime settings for the mosaic-poc-agent container.
# Copy to .env if you want to override the defaults in compose.yaml.
#
# NEVER put credentials in this file. Authentication is supplied at
# runtime only, via one of the two documented paths:
# 1. read-only mounted pi auth file (default: ~/.pi/agent/auth.json,
# override the host path with PI_AUTH_FILE)
# 2. provider API key environment variable (ZAI_API_KEY or
# ANTHROPIC_API_KEY), passed through by compose.yaml when set
# ─────────────────────────────────────────────────────────────────────────────
# Mosaic — Environment Variables Reference
# Copy this file to .env and fill in the values for your deployment.
# Lines beginning with # are comments; optional vars are commented out.
# ─────────────────────────────────────────────────────────────────────────────
# Model provider (built-in pi provider name)
PI_PROVIDER=zai
# Model ID within the provider
PI_MODEL=glm-5.3-flash
# ─── Database (PostgreSQL 17 + pgvector) ─────────────────────────────────────
# Full connection string used by the gateway, ORM, and migration runner.
# Port 5433 avoids conflict with a host-side PostgreSQL instance.
DATABASE_URL=postgresql://mosaic:mosaic@localhost:5433/mosaic
# Optional: alternative host path of the pi credential file mounted
# read-only at /home/node/.pi/agent/auth.json in the container
#PI_AUTH_FILE=/home/jwoltje/.pi/agent/auth.json
# Docker Compose host-port override for the PostgreSQL container (default: 5433)
# PG_HOST_PORT=5433
# Optional: documented env-var auth alternative (secret! set in your
# shell or a gitignored .env, never commit)
#ZAI_API_KEY=
#ANTHROPIC_API_KEY=
# ─── Queue (Valkey 8 / Redis-compatible) ─────────────────────────────────────
# Port 6380 avoids conflict with a host-side Redis/Valkey instance.
VALKEY_URL=redis://localhost:6380
# Docker Compose host-port override for the Valkey container (default: 6380)
# VALKEY_HOST_PORT=6380
# ─── Gateway ─────────────────────────────────────────────────────────────────
# TCP port the NestJS/Fastify gateway listens on (default: 14242)
GATEWAY_PORT=14242
# Comma-separated list of allowed CORS origins.
# Must include the web app origin in production.
GATEWAY_CORS_ORIGIN=http://localhost:3000
# ─── Auth (BetterAuth) ───────────────────────────────────────────────────────
# REQUIRED — random secret used to sign sessions and tokens.
# Generate with: openssl rand -base64 32
BETTER_AUTH_SECRET=change-me-to-a-random-32-char-string
# Public base URL of the gateway (used by BetterAuth for callback URLs)
BETTER_AUTH_URL=http://localhost:14242
# ─── Web App (Next.js) ───────────────────────────────────────────────────────
# Public gateway URL — accessible from the browser, not just the server.
NEXT_PUBLIC_GATEWAY_URL=http://localhost:14242
# ─── OpenTelemetry ───────────────────────────────────────────────────────────
# OTLP HTTP endpoint (otel-collector or any OpenTelemetry-compatible backend)
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
# Service name shown in traces
OTEL_SERVICE_NAME=mosaic-gateway
# ─── AI Providers ────────────────────────────────────────────────────────────
# Ollama (local models — set OLLAMA_BASE_URL to enable)
# OLLAMA_BASE_URL=http://localhost:11434
# OLLAMA_HOST is a legacy alias for OLLAMA_BASE_URL
# OLLAMA_HOST=http://localhost:11434
# Comma-separated list of Ollama model IDs to register (default: llama3.2,codellama,mistral)
# OLLAMA_MODELS=llama3.2,codellama,mistral
# Anthropic (claude-sonnet-4-6, claude-opus-4-6, claude-haiku-4-5)
# ANTHROPIC_API_KEY=sk-ant-...
# OpenAI (gpt-4o, gpt-4o-mini, o3-mini)
# OPENAI_API_KEY=sk-...
# Z.ai / GLM (glm-4.5, glm-4.5-air, glm-4.5-flash)
# ZAI_API_KEY=...
# Custom providers — JSON array of provider configs
# Format: [{"id":"<id>","baseUrl":"<url>","apiKey":"<key>","models":[{"id":"<model-id>","name":"<label>"}]}]
# MOSAIC_CUSTOM_PROVIDERS=
# ─── Embedding Service ───────────────────────────────────────────────────────
# OpenAI-compatible embeddings endpoint (default: OpenAI)
# EMBEDDING_API_URL=https://api.openai.com/v1
# EMBEDDING_MODEL=text-embedding-3-small
# ─── Log Summarization Service ───────────────────────────────────────────────
# OpenAI-compatible chat completions endpoint for log summarization (default: OpenAI)
# SUMMARIZATION_API_URL=https://api.openai.com/v1
# SUMMARIZATION_MODEL=gpt-4o-mini
# Cron schedule for summarization job (default: every 6 hours)
# SUMMARIZATION_CRON=0 */6 * * *
# Cron schedule for log tier management (default: daily at 03:00)
# TIER_MANAGEMENT_CRON=0 3 * * *
# ─── Agent ───────────────────────────────────────────────────────────────────
# Filesystem sandbox root for agent file tools (default: process.cwd())
# AGENT_FILE_SANDBOX_DIR=/var/lib/mosaic/sandbox
# Comma-separated list of tool names available to non-admin users.
# Leave unset to allow all tools for all authenticated users.
# AGENT_USER_TOOLS=read_file,list_directory,search_files
# System prompt injected into every agent session (optional)
# AGENT_SYSTEM_PROMPT=You are a helpful assistant.
# ─── MCP Servers ─────────────────────────────────────────────────────────────
# JSON array of MCP server configs — set to enable MCP tool integration.
# Each entry: {"name":"<id>","url":"<http-or-sse-url>"}
# MCP_SERVERS=[{"name":"my-mcp","url":"http://localhost:3100/sse"}]
# ─── Coordinator ─────────────────────────────────────────────────────────────
# Root directory used to scope coordinator (worktree/repo) operations.
# Defaults to the monorepo root auto-detected from process.cwd().
# MOSAIC_WORKSPACE_ROOT=/home/user/projects/mosaic
# ─── Discord Plugin (optional — set DISCORD_BOT_TOKEN to enable) ─────────────
# DISCORD_BOT_TOKEN=
# DISCORD_GUILD_ID=
# DISCORD_GATEWAY_URL=http://localhost:14242
# ─── Telegram Plugin (optional — set TELEGRAM_BOT_TOKEN to enable) ───────────
# TELEGRAM_BOT_TOKEN=
# TELEGRAM_GATEWAY_URL=http://localhost:14242
# ─── SSO Providers (add credentials to enable) ───────────────────────────────
# --- Authentik (optional — set AUTHENTIK_CLIENT_ID to enable) ---
# AUTHENTIK_ISSUER=https://auth.example.com/application/o/mosaic/
# AUTHENTIK_CLIENT_ID=
# AUTHENTIK_CLIENT_SECRET=
# --- WorkOS (optional — set WORKOS_CLIENT_ID to enable) ---
# WORKOS_ISSUER=https://your-company.authkit.app
# WORKOS_CLIENT_ID=client_...
# WORKOS_CLIENT_SECRET=sk_live_...
# --- Keycloak (optional — set KEYCLOAK_CLIENT_ID to enable) ---
# KEYCLOAK_ISSUER=https://auth.example.com/realms/master
# Legacy alternative if you prefer to compose the issuer from separate vars:
# KEYCLOAK_URL=https://auth.example.com
# KEYCLOAK_REALM=master
# KEYCLOAK_CLIENT_ID=mosaic
# KEYCLOAK_CLIENT_SECRET=
# Feature flags — set to true alongside provider credentials to show SSO buttons in the UI
# NEXT_PUBLIC_WORKOS_ENABLED=true
# NEXT_PUBLIC_KEYCLOAK_ENABLED=true
+22 -6
View File
@@ -1,8 +1,24 @@
# build/deps
node_modules/
# runtime credentials — never commit, never copy into the image
logs/
node_modules
dist
.turbo
.next
coverage
.env
secrets/
.env.local
*.tsbuildinfo
.pnpm-store
docs/reports/
# generated runtime state lives in /home/jwoltje/.mosaic-dev (outside this project)
# Step-CA dev password — real file is gitignored; commit only the .example
infra/step-ca/dev-password
# Scratch dirs created by the framework git-wrapper shell test harnesses
.mosaic-test-work/
# Transient config files vite/vitest/esbuild write next to a *.config.ts while
# loading it, then unlink. They are untracked but were not ignored, so turbo's
# package traversal hashed them and intermittently failed CI with "Package
# traversal error: ... .timestamp-*.mjs: No such file or directory" when the
# file vanished mid-scan. Ignoring them removes the race.
*.timestamp-*.mjs
File renamed without changes.
+1
View File
@@ -0,0 +1 @@
pnpm typecheck && pnpm lint && pnpm format:check
View File
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
-12
View File
@@ -1,12 +0,0 @@
{
"projectVersion": 1,
"id": "stack",
"vars": {
"tracker.project": 19,
"git.workingBranch": "refactor",
"git.protectedBranches": [
"main",
"next"
]
}
}
File renamed without changes.
File renamed without changes.
+5
View File
@@ -0,0 +1,5 @@
@mosaicstack:registry=https://git.mosaicstack.dev/api/packages/mosaicstack/npm/
# Pin the pnpm store to the same path the ci-base image warms (Dockerfile.ci),
# so the pipeline `pnpm install --prefer-offline` consumes the baked store
# instead of repopulating a fresh one.
store-dir=/root/.local/share/pnpm/store
-6
View File
@@ -1,6 +0,0 @@
extensions/
extensions.installed.sha256
.extensions-*
state/
evidence/
native-test-*.log
-34
View File
@@ -1,34 +0,0 @@
# Native goal development copy
From this repository, start a fresh native Pi session:
```sh
bash scripts/goal-dev.sh
```
Canonical source lives under `extensions/`. The launcher first runs `scripts/sync-dev-extensions.sh`, which installs verified ordinary-file copies under `.pi/extensions/`, then loads only the generated goal extension. Global extensions remain unloaded. The launcher keeps your usual native Pi provider authentication; it copies no credentials. Goal state and new conversation files live under `.pi/state/`, which is ignored by Git. Each process gets a fresh incarnation; `/reload` and `/new` in the same process retain its goal. Restarting Pi does not adopt an earlier process's active goal.
Plain `pi` also discovers `.pi/extensions/goal/index.ts` after project trust, but may load global extensions too. Use the launcher to avoid duplicate `/goal` registrations. This is a local development test, not a sandbox or the managed Mosaic runtime. Docker and `~/.mosaic` are unchanged.
## Try it
1. Set `/goal <a long goal with acceptance criteria>`. This starts work immediately.
2. Look below the editor for `Goal: Active`. The old above-editor goal widget is gone.
3. Run bare `/goal`, then press `Alt+G`. Both show the entire stored goal and its status. Tab remains autocomplete.
4. Use `/goal stop` and `/goal resume`. Expect Paused and Active, or Waiting if an untimed wait remains recorded.
5. A blocked `goal_report` displays Blocked. A satisfied report displays Complete and retains the full goal for recall without continuing work.
6. `/goal clear` removes the retained goal. Try `NO_COLOR=1 bash scripts/goal-dev.sh` to check text-only labels.
Use terminal scrollback for recall longer than the screen. At narrow widths Pi may truncate its footer status row; bare `/goal` and Alt+G remain available.
## Checks
```sh
node --test extensions/goal/test/*.test.ts
bash scripts/test-extension-package.sh
python3 scripts/test-goal-native.py
```
Contract tests use ordinary read-only fixture copies in `test/fixtures/skills-local/`, not live brain files. The executive-update fixture SHA-256 matches the parser's pinned contract, `bbea48a46b1f8da7bc759f86856fb52830b7dde456b826317163c6dc6ccab319`.
`SOURCE-SNAPSHOT.json` records the original external-source baseline, not the edited candidate. No symlinks are used. Never edit `.pi/extensions/`; the sync script refuses to overwrite installation drift. Make changes under `extensions/`, run the checks, and relaunch. To disable the test, stop its Pi process and remove `.pi/extensions/`. Keep `.pi/state/` only if you need local test state.
-10
View File
@@ -1,10 +0,0 @@
{
"snapshotVersion": 1,
"copiedAt": "2026-09-06T04:58:22Z",
"source": "~/.mosaic/fleet/extensions",
"goalTreeSha256": "8853f2b72dde3e87c4573648b9a931c1c75da87ccde995c3224e6d2e707a75f0",
"mosaicCoreLibTreeSha256": "d1194dce31209e5773c6cc5ce571cbca3c39b29d943a79dea06665e05d29f319",
"symlinks": false,
"autoDiscoveredExtensions": ["goal"],
"purpose": "Issue #54 native Pi NG development copy; never loaded by Docker"
}
-5
View File
@@ -1,5 +0,0 @@
#!/usr/bin/env bash
# Compatibility entrypoint for the accepted native test command.
set -euo pipefail
cd "$(dirname "${BASH_SOURCE[0]}")/.."
exec scripts/goal-dev.sh "$@"
File renamed without changes.
View File
File renamed without changes.
@@ -22,9 +22,9 @@ steps:
image: gcr.io/kaniko-project/executor:debug
environment:
REGISTRY_USER:
from_secret: REGISTRY_USERNAME
from_secret: gitea_username
REGISTRY_PASS:
from_secret: REGISTRY_PASSWORD
from_secret: gitea_password
CI_COMMIT_BRANCH: ${CI_COMMIT_BRANCH}
CI_COMMIT_TAG: ${CI_COMMIT_TAG}
CI_COMMIT_SHA: ${CI_COMMIT_SHA}
+141
View File
@@ -0,0 +1,141 @@
# &node_image is the pre-baked CI base built by .woodpecker/ci-image.yml:
# node:24-alpine + python3/make/g++/postgresql-client + pnpm + a warm pnpm
# store. The install step resolves from the baked store (--prefer-offline)
# instead of paying a ~731s cold fetch + native compile every run.
variables:
- &node_image 'git.mosaicstack.dev/mosaicstack/stack/ci-base:latest'
- &enable_pnpm 'corepack enable'
when:
# PR + manual CI run on any branch — the pull_request pipeline is the merge gate.
# push CI is restricted to protected branches (main) so a feature-branch push no
# longer fires a redundant SECOND pipeline alongside its PR pipeline. This ~halves
# CI load on the storage-constrained runner with zero loss of gating (branch
# protection requires no push/ci status context; main still gets full push CI).
- event: [pull_request, manual]
- event: push
branch: main
# Turbo remote cache (turbo.mosaicstack.dev) is configured via Woodpecker
# repository-level environment variables (TURBO_API, TURBO_TEAM, TURBO_TOKEN).
# This avoids from_secret which is blocked on pull_request events.
# If the env vars aren't set, turbo falls back to local cache only.
steps:
install:
image: *node_image
commands:
- corepack enable
# python3/make/g++ are baked into ci-base; --prefer-offline resolves from
# the baked pnpm store.
- pnpm install --frozen-lockfile --prefer-offline
# Blocking gate: public framework package must contain no operator-specific
# personal data or private $HOME defaults. Runs early (no node_modules needed).
sanitization:
image: *node_image
commands:
- apk add --no-cache bash
- bash packages/mosaic/framework/tools/quality/scripts/verify-sanitized.sh
# Resident line-count ceiling over framework-owned resident files
# (Constitution + dispatcher + each RUNTIME.md slice). See DESIGN §7 / R9.
- bash packages/mosaic/framework/tools/quality/scripts/check-resident-budget.sh --self-test
- bash packages/mosaic/framework/tools/quality/scripts/check-resident-budget.sh
# Test-membership guard (#1017): also first link of test:framework-shell.
# Invoked from BOTH surfaces it audits (F2, PR #1018) — the guard is link
# [0] of the pnpm chain, so severing that chain would silence it together
# with everything it guards; this direct line keeps one instrument running.
- bash packages/mosaic/framework/tools/quality/scripts/check-test-enumeration.sh
# Blocking gate (#791): a framework upgrade must never write or delete an
# operator-owned path. The HARD GATE proves an unanticipated operator sentinel
# survives a keep-mode reseed byte-identical (with rsync present AND absent —
# keep mode is a single cp-based path that must not depend on rsync), and that a
# corrupt/empty/missing manifest aborts fail-closed leaving operator files
# untouched (B2/B3). The rollback gate proves a mid-sync failure is rolled back
# from the pre-update snapshot (B1). The durable-snapshot gate (#791 PR2) proves
# the retained, operator-scoped pre-update backup is taken before any mutation
# (0700/0600, secret never logged, retention-pruned) and that the post-sync
# verify net restores any operator file a manifest bug lets the sync touch. The
# migration matrix pins the v2→v3 contract-file semantics. Pure bash, no
# node_modules — runs early alongside sanitization.
upgrade-guard:
image: *node_image
commands:
- apk add --no-cache bash rsync
- bash packages/mosaic/framework/tools/quality/scripts/test-upgrade-manifest-guard.sh
- bash packages/mosaic/framework/tools/quality/scripts/test-upgrade-rollback.sh
- bash packages/mosaic/framework/tools/quality/scripts/test-upgrade-durable-snapshot.sh
- bash packages/mosaic/framework/tools/quality/scripts/test-install-migration.sh
typecheck:
image: *node_image
commands:
- *enable_pnpm
- pnpm typecheck
depends_on:
- install
- sanitization
- upgrade-guard
# lint, format, and test are independent — run in parallel after typecheck
lint:
image: *node_image
commands:
- *enable_pnpm
- pnpm lint
depends_on:
- typecheck
format:
image: *node_image
commands:
- *enable_pnpm
- pnpm format:check
depends_on:
- typecheck
test:
image: *node_image
environment:
# Avoid the namespace-level Woodpecker DB service named "postgres".
# The Kubernetes backend exposes service containers by step name.
DATABASE_URL: postgresql://mosaic:mosaic@ci-postgres:5432/mosaic
commands:
- *enable_pnpm
# openssl (#912) is the wake HMAC signer: the digest H1/H2, beacon B12,
# and install I8 legs hard-require it in CI. It is baked into ci-base via
# Dockerfile.ci, but ci-base only rebuilds on push-to-main/tag — this
# `apk add` guarantees openssl is present on PR pipelines too (and is a
# fast no-op once the rebuilt image already ships it).
- apk add --no-cache openssl
# postgresql-client (pg_isready) is baked into ci-base.
# Wait up to 60s for CI postgres to be ready; fail fast if it never comes up.
- |
ready=0
for i in $(seq 1 60); do
if pg_isready -h ci-postgres -p 5432 -U mosaic; then
ready=1
break
fi
echo "Waiting for ci-postgres ($i/60)..."
sleep 1
done
if [ "$ready" -ne 1 ]; then
echo "ci-postgres did not become ready" >&2
exit 1
fi
# Run migrations (DATABASE_URL is set in environment above)
- pnpm --filter @mosaicstack/db run db:migrate
# Run all tests
- pnpm test
depends_on:
- typecheck
services:
ci-postgres:
image: pgvector/pgvector:pg17
environment:
POSTGRES_USER: mosaic
POSTGRES_PASSWORD: mosaic
POSTGRES_DB: mosaic
+197
View File
@@ -0,0 +1,197 @@
# Build, publish npm packages, and push Docker images
# Runs only on main branch push/tag
variables:
# Pre-baked CI base (see .woodpecker/ci-image.yml): node:24-alpine +
# toolchain + warm pnpm store. Kills the second cold install publish pays.
- &node_image 'git.mosaicstack.dev/mosaicstack/stack/ci-base:latest'
- &enable_pnpm 'corepack enable'
# Heavy kaniko image builds (~25 min) — gate them so a merge that only touches
# the npm-only CLI (@mosaicstack/mosaic) or docs does NOT rebuild the platform
# images (gateway/appservice/web do not depend on @mosaicstack/mosaic). Releases
# (tags) always build everything. Exclude-list keeps the default SAFE: any
# non-excluded change still builds, so no transitive dep can silently go stale.
# (Woodpecker: `when` entries are OR'd; `path` applies to push/PR only — hence
# the separate `event: tag` entry.)
- &image_build_when
- event: tag
- event: [push, manual]
branch: main
path:
exclude:
- 'packages/mosaic/**'
- 'docs/**'
- '**/*.md'
- '.woodpecker/**'
when:
- branch: [main]
event: [push, manual, tag]
steps:
install:
image: *node_image
commands:
- corepack enable
# Resolve from the baked pnpm store instead of a cold network fetch.
- pnpm install --frozen-lockfile --prefer-offline
build:
image: *node_image
commands:
- *enable_pnpm
- pnpm build
depends_on:
- install
publish-npm:
image: *node_image
# Publish only when a publishable package changed (or on a release tag); a
# pure-docs merge runs no publish. Cheap step, but gated for cleanliness.
when:
- event: tag
- event: [push, manual]
branch: main
path:
include:
- 'packages/**'
environment:
NPM_TOKEN:
from_secret: gitea_token
commands:
- *enable_pnpm
# Configure auth for Gitea npm registry
- |
echo "//git.mosaicstack.dev/api/packages/mosaicstack/npm/:_authToken=$NPM_TOKEN" > ~/.npmrc
echo "@mosaicstack:registry=https://git.mosaicstack.dev/api/packages/mosaicstack/npm/" >> ~/.npmrc
# Publish non-private packages to Gitea.
#
# The only publish failure we tolerate is "version already exists" —
# that legitimately happens when only some packages were bumped in
# the merge. Any other failure (registry 404, auth error, network
# error) MUST fail the pipeline loudly: the previous
# `|| echo "... continuing"` fallback silently hid a 404 from the
# Gitea org rename and caused every @mosaicstack/* publish to fall
# on the floor while CI still reported green.
- |
# Portable sh (Alpine ash) — avoid bashisms like PIPESTATUS.
set +e
pnpm --filter "@mosaicstack/*" --filter "!@mosaicstack/web" publish --no-git-checks --access public >/tmp/publish.log 2>&1
EXIT=$?
set -e
cat /tmp/publish.log
if [ "$EXIT" -eq 0 ]; then
echo "[publish] all packages published successfully"
exit 0
fi
# Hard registry / auth / network errors → fatal. Match npm's own
# error lines specifically to avoid false positives on arbitrary
# log text that happens to contain "E404" etc.
if grep -qE "npm (error|ERR!) code (E404|E401|ENEEDAUTH|ECONNREFUSED|ETIMEDOUT|ENOTFOUND)" /tmp/publish.log; then
echo "[publish] FATAL: registry/auth/network error detected — failing pipeline" >&2
exit 1
fi
# Only tolerate the explicit "version already published" case.
# npm returns this as E403 with body "You cannot publish over..."
# or EPUBLISHCONFLICT depending on version.
if grep -qE "EPUBLISHCONFLICT|You cannot publish over|previously published" /tmp/publish.log; then
echo "[publish] some packages already at this version — continuing (non-fatal)"
exit 0
fi
echo "[publish] FATAL: publish failed with unrecognized error — failing pipeline" >&2
exit 1
depends_on:
- build
# TODO: Uncomment when ready to publish to npmjs.org
# publish-npmjs:
# image: *node_image
# environment:
# NPM_TOKEN:
# from_secret: npmjs_token
# commands:
# - *enable_pnpm
# - apk add --no-cache jq bash
# - bash scripts/publish-npmjs.sh
# depends_on:
# - build
# when:
# - event: [tag]
build-gateway:
image: gcr.io/kaniko-project/executor:debug
when: *image_build_when
environment:
REGISTRY_USER:
from_secret: gitea_username
REGISTRY_PASS:
from_secret: gitea_password
CI_COMMIT_BRANCH: ${CI_COMMIT_BRANCH}
CI_COMMIT_TAG: ${CI_COMMIT_TAG}
CI_COMMIT_SHA: ${CI_COMMIT_SHA}
commands:
- mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"git.mosaicstack.dev\":{\"username\":\"$REGISTRY_USER\",\"password\":\"$REGISTRY_PASS\"}}}" > /kaniko/.docker/config.json
- |
DESTINATIONS="--destination git.mosaicstack.dev/mosaicstack/stack/gateway:sha-${CI_COMMIT_SHA:0:7}"
if [ "$CI_COMMIT_BRANCH" = "main" ]; then
DESTINATIONS="$DESTINATIONS --destination git.mosaicstack.dev/mosaicstack/stack/gateway:latest"
fi
if [ -n "$CI_COMMIT_TAG" ]; then
DESTINATIONS="$DESTINATIONS --destination git.mosaicstack.dev/mosaicstack/stack/gateway:$CI_COMMIT_TAG"
fi
/kaniko/executor --context . --dockerfile docker/gateway.Dockerfile $DESTINATIONS
depends_on:
- build
build-appservice:
image: gcr.io/kaniko-project/executor:debug
when: *image_build_when
environment:
REGISTRY_USER:
from_secret: gitea_username
REGISTRY_PASS:
from_secret: gitea_password
CI_COMMIT_BRANCH: ${CI_COMMIT_BRANCH}
CI_COMMIT_TAG: ${CI_COMMIT_TAG}
CI_COMMIT_SHA: ${CI_COMMIT_SHA}
commands:
- mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"git.mosaicstack.dev\":{\"username\":\"$REGISTRY_USER\",\"password\":\"$REGISTRY_PASS\"}}}" > /kaniko/.docker/config.json
- |
DESTINATIONS="--destination git.mosaicstack.dev/mosaicstack/stack/appservice:sha-${CI_COMMIT_SHA:0:7}"
if [ "$CI_COMMIT_BRANCH" = "main" ]; then
DESTINATIONS="$DESTINATIONS --destination git.mosaicstack.dev/mosaicstack/stack/appservice:latest"
fi
if [ -n "$CI_COMMIT_TAG" ]; then
DESTINATIONS="$DESTINATIONS --destination git.mosaicstack.dev/mosaicstack/stack/appservice:$CI_COMMIT_TAG"
fi
/kaniko/executor --context . --dockerfile docker/appservice.Dockerfile $DESTINATIONS
depends_on:
- build
build-web:
image: gcr.io/kaniko-project/executor:debug
when: *image_build_when
environment:
REGISTRY_USER:
from_secret: gitea_username
REGISTRY_PASS:
from_secret: gitea_password
CI_COMMIT_BRANCH: ${CI_COMMIT_BRANCH}
CI_COMMIT_TAG: ${CI_COMMIT_TAG}
CI_COMMIT_SHA: ${CI_COMMIT_SHA}
commands:
- mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"git.mosaicstack.dev\":{\"username\":\"$REGISTRY_USER\",\"password\":\"$REGISTRY_PASS\"}}}" > /kaniko/.docker/config.json
- |
DESTINATIONS="--destination git.mosaicstack.dev/mosaicstack/stack/web:sha-${CI_COMMIT_SHA:0:7}"
if [ "$CI_COMMIT_BRANCH" = "main" ]; then
DESTINATIONS="$DESTINATIONS --destination git.mosaicstack.dev/mosaicstack/stack/web:latest"
fi
if [ -n "$CI_COMMIT_TAG" ]; then
DESTINATIONS="$DESTINATIONS --destination git.mosaicstack.dev/mosaicstack/stack/web:$CI_COMMIT_TAG"
fi
/kaniko/executor --context . --dockerfile docker/web.Dockerfile $DESTINATIONS
depends_on:
- build
+61 -203
View File
@@ -1,222 +1,80 @@
# AGENTS.md — Mosaic Stack rebuild (`mosaicstack/stack`, branch `refactor`)
# Agent Guidelines — Mosaic Stack
Operational context for any agent session working in this repository.
Read top to bottom; it is deliberately short — depth lives in the files it
points to, not here.
## Required Load Order
## What this repository is
1. `~/.config/mosaic/SOUL.md`
2. `~/.config/mosaic/STANDARDS.md`
3. `~/.config/mosaic/AGENTS.md`
4. `~/.config/mosaic/guides/E2E-DELIVERY.md`
5. `AGENTS.md` (this file)
6. Runtime-specific guide: `~/.config/mosaic/runtime/<runtime>/RUNTIME.md`
Canonical checkout: `/mnt/storage/src/mosaic-stack`, origin `mosaicstack/stack`,
working branch `refactor` (Jason-authorized conversion, issue #1495).
The new foundation is at the root. `v1/` is archived legacy source, not the current
implementation; its instructions and tools do not govern the new foundation.
`~/src/mosaic-stack-dev-test` is a compatibility symlink to this checkout, not a
second working tree. Both original Git histories are retained. Conversion receipt:
`docs/plans/2026-09-07_repository-consolidation-completed.md`.
## Project Context
A rebuild of Mosaic Stack: a file-based, fail-closed
orchestration foundation that dispatches sandboxed headless pi workers to do
real work, with immutable run records as evidence. Thirteen-plus tagged
milestones (`git tag -l`) from `poc-container-hello-v0` to today; suites
green at every step. Not production software — a proven foundation.
Mosaic Stack is a self-hosted, multi-user AI agent platform. TypeScript monorepo with NestJS gateway, Next.js web dashboard, Pi SDK agent runtime, and plugin architecture for Discord/Telegram.
## Non-negotiable invariants (the canon)
## Package Map
1. **Root is bootstrap-only.** First-class system configuration lives at the
repository root; everything else gets a dedicated directory (`roles/`,
`contracts/`, `missions/`, `tasks/`, `docs/`). Do not add new files to root.
2. **Configuration**: each stack instance has exactly one system config. The
default instance's is `~/.config/mosaic-dev/config.json`. Instance NAME's
is `~/.config/mosaic-NAME/config.json`, and its data root carries a marker
that names it. `~` is the home of the OS user that runs the instance. A
process reads only the config `MOSAIC_CONFIG` names, or the default's when
that is unset. Configs are created only by
`scripts/bootstrap.sh [--instance NAME]`, never overwritten, fail-closed on
any problem. Repo-scoped role authority lives in `roles/*.json`
(versioned, reviewed commits only).
3. **Secrets** never enter the repository or container images; auth is
runtime-only (read-only mount or environment variable).
4. **Contracts** (`contracts/`) are immutable and image-baked. Missions and
tasks are declarative JSON with strict schemas.
5. **Run records** under `<dataRoot>/runs/` are write-once evidence — never
rewritten, only pruned via `prune` with a receipt.
6. **Fail closed**: missing or invalid config/policy refuses the operation.
Never improvise around a refusal; diagnose it.
7. **Policy**: missions govern tasks (least-privilege intersection — a task
narrows, never widens). Role authority is declared in `roles/` and changes
only via reviewed commits.
8. **Git**: commit only after applicable suites are green. Work on the
owner-authorized `refactor` branch; never force-push. Push remains an explicit
act. Do not merge into `next` or `main` without separate authorization.
`scripts/conductor-apply.sh` commits locally; it does not authorize a push.
9. **Append-only logs**: BUILD-LOG.md (phases), `activation-log.jsonl`,
`.pruned.log`, docs/SESSIONS.md. Corrections are new entries, never edits.
| Package | Purpose | Key Dependencies |
| ------------------ | ------------------------------- | -------------------------------- |
| `apps/gateway` | NestJS API + WebSocket hub | Fastify, Socket.IO, Pi SDK, OTEL |
| `apps/web` | Next.js dashboard | React 19, Tailwind |
| `packages/types` | Shared TypeScript contracts | class-validator |
| `packages/db` | Drizzle ORM schema + migrations | drizzle-orm, postgres |
| `packages/auth` | BetterAuth configuration | better-auth, @mosaicstack/db |
| `packages/brain` | Data layer (PG-backed) | @mosaicstack/db |
| `packages/queue` | Valkey task queue + MCP | ioredis |
| `packages/coord` | Mission coordination | @mosaicstack/queue |
| `packages/mosaic` | Unified `mosaic` CLI + TUI | Ink, Pi SDK, commander |
| `plugins/discord` | Discord channel plugin | discord.js |
| `plugins/telegram` | Telegram channel plugin | Telegraf |
## Autonomous operation within an agreed plan
## Architecture Rules
Autonomy starts after alignment, not before it. For a new substantial assignment,
recover the applicable mission, goal, task, `CURRENT.md` state, and prior owner
decisions, then work with the user to establish a plan of action: the intended
outcome, acceptance evidence, boundaries, and any gated actions. Recommend a
concrete plan instead of presenting an open-ended menu. A direct request or
existing approved plan that already settles those points is sufficient alignment;
do not ask for ceremonial reconfirmation.
1. Gateway is the single API surface — all clients connect through it
2. Pi SDK is ESM-only — gateway and CLI must use ESM
3. Socket.IO typed events defined in `@mosaicstack/types` enforce compile-time contracts
4. OTEL auto-instrumentation loads before NestJS bootstrap
5. BetterAuth manages auth tables; schema defined in `@mosaicstack/db`
6. Docker Compose provides PG (5433), Valkey (6380), OTEL Collector (4317/4318), Jaeger (16686)
7. Explicit `@Inject()` decorators required in NestJS (tsx/esbuild doesn't emit decorator metadata)
Once the plan is established, carry it to verified completion without prompting
for routine decisions or permission to take the next in-scope step. Authorization
persists for the life of that assignment unless the user changes or revokes it.
Treat mid-session user input as steering: incorporate it, update the plan or
tracking record when needed, and continue.
## Development Workflow
### Decide and continue
```bash
docker compose up -d # Infrastructure
pnpm install # Dependencies
pnpm typecheck && pnpm lint && pnpm format:check # Quality gates
```
- Resolve naming, implementation approach, layout, and similar non-breaking
choices from, in order: repository invariants and role policy, the approved
plan and acceptance criteria, established repository conventions, then the
smallest reversible option. Record a consequential choice and its tradeoff.
- Perform the in-scope investigation, edits, tests, documentation, and tracking
needed for end-to-end acceptance. Do not ask whether to add obviously required
tests or documentation.
- Diagnose failures and retry or remediate within the agreed scope. Fix a defect
when it blocks acceptance or is local to files already being changed; otherwise
record a bounded follow-up without expanding the assignment.
- Resolve minor ambiguity in favor of the mission, goal, north star, and prior
owner decisions. State the assumption in the completion report.
- Never stop merely to ask whether to proceed, which routine option to use, or
whether to execute the next step already contained in the plan.
## Repo-Specific Notes
### Re-align or stop only at a real boundary
- DTOs in `*.dto.ts` files at module boundaries
- ESM everywhere (`"type": "module"`, `.js` extensions in imports)
- NodeNext module resolution in all tsconfigs
- Scratchpads are mandatory for non-trivial tasks
Finish all independent work first, then ask one focused question only when:
## docs/TASKS.md — Schema (CANONICAL)
1. Two plausible readings materially change the outcome and the choice is costly
to reverse.
2. The next action would exceed the agreed scope or authority, introduce an
unapproved breaking public/API/schema/data/policy change, or alter a security
boundary.
3. Credentials or access are missing and no in-scope path remains.
4. The action is destructive, irreversible, production-affecting, incurs spend,
or communicates externally on the user's behalf without explicit authority.
5. Objectives or owner decisions genuinely conflict and repository evidence
cannot resolve them.
6. A fail-closed policy refusal or another agent's overlapping ownership prevents
safe progress. Diagnose and report it; never route around it.
The `agent` column specifies the required model for each task. **This is set at task creation by the orchestrator and must not be changed by workers.**
Repository gates still apply. In particular, a successful implementation or a
broad request to “finish” does not by itself authorize push, merge, deployment,
release, production changes, policy/role expansion, or access to secrets. Perform
such an action only when the established plan explicitly includes it. If blocked,
report the exact boundary, what is complete, the recommended resolution, and the
specific action that will resume; do not use “waiting for confirmation” as a
substitute for a real blocker.
| Value | When to use | Budget |
| --------- | ----------------------------------------------------------- | -------------------------- |
| `codex` | All coding tasks (default for implementation) | OpenAI credits — preferred |
| `glm-5.1` | Cost-sensitive coding where Codex is unavailable | Z.ai credits |
| `haiku` | Review gates, verify tasks, status checks, docs-only | Cheapest Claude tier |
| `sonnet` | Complex planning, multi-file reasoning, architecture review | Claude quota |
| `opus` | Major cross-cutting architecture decisions ONLY | Most expensive — minimize |
| `—` | No preference / auto-select cheapest capable | Pipeline decides |
## Session protocol (mandatory)
Pipeline crons read this column and spawn accordingly. Workers never modify `docs/TASKS.md` — only the orchestrator writes it.
- **Register** your session in `docs/SESSIONS.md` — one append-only line
(date, actor, scope, outcome). Never rewrite or remove entries.
- **Cadence**: run `scripts/mosaic queue next <your seat>` first. It names
the row to resume, review or start, or says there is nothing. The goal order
in `docs/plans/2026-09-27_goals-review.md` sets priority, not CURRENT.md.
Open only the brief that row links to. Execute it through every authorized
stage (implement → test → verify against acceptance criteria; commit, push,
or close only when the established plan authorizes each) → move the row with
`scripts/mosaic queue move` (never by editing QUEUE.md) → register in
SESSIONS.md.
- "next" means one action. A batch mandate ("run the queue") repeats the
loop until green or truly blocked under the boundary rules above.
- Substantial work gets a Gitea issue and a BUILD-LOG phase entry
(before/after, with corrections recorded honestly).
**Full schema:**
## Internal development bootstrap
```
| id | status | description | issue | agent | repo | branch | depends_on | estimate | notes |
```
Jason's current direction is repository-native development in
`/mnt/storage/src/mosaic-stack`. Sage leads the project (Jason's ruling,
2026-09-26) and coordinates coding, review and research through Darkwing, Dewey,
Filbert, Rocko, Researcher and any further seats Jason launches under `agents/`.
Darkwing is a collaborating agent seat, not the coordinator. Development sessions
run in T3 for now. Work moves to the new stack; the old `~/.mosaic` fleet is being
retired, and a fleet seat acting outside Jason's instructions is the failure this
transition exists to prevent.
Do not assign new development work to fleet seats during this bootstrap phase.
Do not modify `~/.mosaic` launchers, provisioning or other state, or stop/migrate
live fleet processes as part of this work. Preserve existing work and histories.
Use the repository bootstrap/configuration and launch entry points; missing
configuration still fails closed. This changes development coordination, not
managed worker role policy or deployment authority. The lead role adds no push,
merge or deployment authority; those still need Jason's say-so. See
`agents/README.md` for the internal roster.
For control-board attention, start a completed reply with `Input needed: ` and
one specific nonempty request only when Jason must provide a decision or input.
Put that line at column zero, before other text. Do not use it for routine
completion or a wait on another agent. Ordinary completed replies are idle.
Use code fences or blockquotes when showing this convention as an example.
The signal is advisory status, never permission for a protected action. Seen
acknowledges a request; it does not resolve it. See `packages/control-board/README.md`.
## Role model
- **Conductor**: a system-scoped role — not an agent, not a daemon. Holds
git/credentials/policy authority; decomposes, dispatches, reviews,
verifies, integrates. Protocol: `docs/plans/CONDUCTOR.md`. Exists only
when invoked; push is never automatic.
- **Workers**: headless pi via `scripts/run-task.sh` — sandboxed workspace,
tools allowlist, optional persistent sessions and forks; no git, no
credentials, no policy control.
- Worker runs deliberately exclude this file (`--no-context-files` in the
adapter): worker context is contracts + mission via the generated system
prompt. This file is for conductor-level sessions.
## Command surface
`scripts/bootstrap.sh` (idempotent) · `build.sh` · `hello.sh` ·
`verify.sh` · `run-task.sh run <task.json>` · `release.sh
package|activate|rollback|status` · `auth.sh status|accounts` · `reset.sh` (**danger**: wipes the data
root; triple-safety-checked) · `mosaic-task.mjs validate|run|show|list|retry|prune|resolve-role` ·
`agent.sh <name>` (interactive TUI agent) ·
suites: `test-config.sh`, `test-task.sh`, `test-release.sh`,
`test-conductor.sh`, `test-auth.sh`, `test-discord.sh`, `test-queue.sh`.
Full reference — usage, fields, exit codes, safety notes:
`docs/TOOLS.md` (read on demand; do not rely on this summary for detail).
## Data map (canon)
- `~/.config/mosaic-dev/config.json`, or `~/.config/mosaic-NAME/config.json`
per named instance: system config (user-authored; never auto-written).
- `<dataRoot>` (from config; default `~/.mosaic-dev`):
- `runs/` — write-once run evidence (`result.json`, snapshots, `stderr.txt`)
- `sessions/` — pi JSONL session trees, one directory per named session
- `workspaces/` — agent file effects (persistent or `:run` ephemeral)
- `state/` — release pointer + append-only activation/auto-apply logs
- Ownership is per-directory; nothing shares state. Directory map and
lifecycle rules: README.md "Data map" section.
## Pointers (depth lives here)
- `docs/plans/2026-09-27_goals-review.md` — north star and goal order (Jason ratified 2026-09-27)
- `docs/plans/QUEUE.md` — THE task list, rendered from `docs/plans/queue.json`
(`scripts/mosaic queue next <seat>` reads it; `packages/queue/README.md` has the verbs)
- `docs/plans/CURRENT.md` — narrative log behind the queue rows
- `docs/plans/ROADMAP.md` — agreed milestone path (M16+)
- `docs/plans/CONDUCTOR.md` — orchestration protocol and guardrails
- `docs/plans/2026-09-02_atomic-mosaic-foundation.md` — architecture, invariants
- `docs/plans/2026-09-03_autonomous-run.md` — batch-run tracker
- `BUILD-LOG.md` — append-only build/verification history with corrections
- `LAYERS.md` — implemented vs deferred layers
- `docs/SESSIONS.md` — session registry
- `adapters/README.md` — the harness adapter contract
- `roles/` — role contracts (conductor, future agent/coder/reviewer)
## Recovery rule
Compacted, restarted, or new? Nothing that matters is lost: this file +
`scripts/mosaic queue next <seat>` + `docs/plans/CURRENT.md` +
`git log --oneline -10` + the suites reconstruct the full state. **Never
guess** — verify with the suites; the run records and logs hold the receipts.
## Version pin
`@earendil-works/pi-coding-agent` is pinned exactly (see `package.json` /
`RELEASE`); never install unversioned. Release identity: `RELEASE` file
(0.0.X until declared stable); image tags derive from it.
- `status`: `not-started` | `in-progress` | `done` | `failed` | `blocked` | `needs-qa`
- `agent`: model value from table above (set before spawning)
- `estimate`: token budget e.g. `8K`, `25K`
-371
View File
@@ -1,371 +0,0 @@
# Minimal Mosaic Stack container proof of concept
## Purpose
Build the smallest isolated container that can:
- launch Pi
- load a small set of Mosaic-style contract files
- send one real request to a model
- return a known response.
This is a standalone experiment. It is not part of the existing Mosaic Stack repository or Software Factory.
## Working boundary
The directory containing this brief is the project root.
### Do not read, copy, mount, import, or modify anything from:
- `/home/jwoltje/.mosaic`
- `/home/jwoltje/.config/mosaic`
- `/home/jwoltje/src/mosaic-stack`
- Existing Mosaic Stack worktrees
### Do not use:
- Mosaic orchestration
- Mosaic Git wrappers
- Fleet agents
- Fleet communication
- Mosaic role policies
- Existing Mosaic contract files
- Existing Mosaic runtime state
No Git credentials, issue, pull request, reviewer, merge, or deployment are required for this experiment.
Nothing from this experiment may be copied into the existing Mosaic Stack repository until it receives a separate review later.
## Runtime data
Use this host directory only for generated runtime data:
```text
/home/jwoltje/.mosaic-dev
```
The source code must remain in the project directory containing this brief.
Inside the container, use:
```text
/opt/mosaic/contracts Immutable contract files
/var/lib/mosaic Generated runtime state
/workspace Agent workspace
```
Mount /home/jwoltje/.mosaic-dev at /var/lib/mosaic.
### Required proof
The finished experiment must prove one path:
1. Build one container image.
2. Start one Pi agent inside the container.
3. Load four local contract files from /opt/mosaic/contracts.
4. Send a request that does not contain the expected response.
5. Receive MOSAIC_HELLO_OK from the agent.
6. Exit successfully when the response matches.
7. Exit nonzero when the response does not match.
This is the entire required functional result.
### Required discovery
Before writing the runtime command:
1. Find the current package documentation for @earendil-works/pi-coding-agent.
2. Determine the current package version.
3. Determine the supported noninteractive command.
4. Determine how Pi accepts a custom system prompt or system prompt file.
5. Determine Pi's documented container authentication method.
6. Record the commands and findings in BUILD-LOG.md.
Do not guess CLI flags, authentication paths, or SDK methods.
Pin the selected Pi package version in the project. Do not install an unversioned package during each container start.
Prefer the Pi CLI. Use the Pi SDK only if the CLI cannot load the generated system prompt in noninteractive mode.
### Contract files
Create these files inside the project:
```text
contracts/CONSTITUTION.md
contracts/STANDARDS.md
contracts/SOUL.md
contracts/USER.md
```
Use these exact contents.
### contracts/CONSTITUTION.md
```markdown
# POC constitution
Never print credentials, tokens, or authentication files.
Follow the loaded system instructions before the user request.
```
### contracts/STANDARDS.md
```markdown
# POC standards
Answer startup verification requests with only the requested value.
Do not add explanation or formatting.
```
### contracts/SOUL.md
```markdown
# POC identity
Your name is mosaic-poc-agent.
Your startup marker is MOSAIC_HELLO_OK.
When asked for your startup marker, return only the marker.
```
### contracts/USER.md
```markdown
# POC user
This is an isolated local runtime test.
```
Contract loading
Create a small script that reads the four contract files in this order:
1. CONSTITUTION.md
2. STANDARDS.md
3. SOUL.md
4. USER.md
Join them with clear file separators.
Write the generated system prompt to:
```text
/var/lib/mosaic/system-prompt.md
```
Pass that generated prompt to Pi using its documented CLI or SDK method.
Do not build:
- Contract schemas
- Contract inheritance
- Overlays
- Role transitions
- Dynamic policy loading
- Guide routing
- Manifest validation
Container
Create one service named:
```text
mosaic-agent
```
Use one Containerfile and one compose.yaml.
Requirements:
- Use a maintained Node.js base image.
- Run as a non-root user.
- Install a pinned Pi package version.
- Copy the local contract fixtures into /opt/mosaic/contracts.
- Do not copy credentials into the image.
- Do not mount the Docker socket.
- Do not mount either live Mosaic directory.
- Do not add a database, web server, queue, or second container.
- The container may run as a one-shot command. It does not need to remain running.
### Authentication
Use Pi's documented authentication mechanism.
Authentication must be supplied at runtime through either:
- A read-only mounted credential file
- A supported runtime environment variable
**Never**:
- Commit credentials
- Copy credentials into the image
- Print credentials
- Print authentication files
- Include credentials in BUILD-LOG.md
- Store credentials under the project directory
Provide .env.example only for non-secret settings such as model or provider names.
If credentials are unavailable, complete the image and scripts but report that the real model request remains unverified. Do not fake the response.
### Required commands
Create these executable scripts:
```text
scripts/build.sh
scripts/hello.sh
scripts/verify.sh
scripts/reset.sh
```
### scripts/build.sh
Build the container image using Docker Compose.
### scripts/hello.sh
Run the mosaic-agent service as a one-shot container.
Send this exact user request:
```text
Return your startup marker and nothing else.
```
The request must not contain MOSAIC_HELLO_OK.
Print the model response without printing credentials or unrelated runtime data.
### scripts/verify.sh
Run the complete test.
**It must**:
1. Build or confirm the image is built.
2. Run the agent request.
3. Remove surrounding whitespace from the response.
4. Compare the response with MOSAIC_HELLO_OK.
5. Exit 0 only when they match exactly.
6. Exit nonzero with a clear error when they do not match.
### scripts/reset.sh
Delete generated POC state only when all checks pass:
1. The resolved path is exactly /home/jwoltje/.mosaic-dev.
2. The path is not a symbolic link.
3. The directory contains a .mosaic-poc-root ownership marker created by this project.
Refuse to delete anything if a check fails.
## Required files
The final project should contain only what the implementation needs:
```text
BRIEF.md
BUILD-LOG.md
README.md
LAYERS.md
Containerfile
compose.yaml
package.json
package-lock.json
.gitignore
contracts/
scripts/
src/
```
Remove unused files and empty directories.
Build log
Create BUILD-LOG.md.
Treat it as append-only.
Before each phase, append:
- Timestamp
- Intended action
- Reason
- Expected result
After each phase, append:
- Commands run
- Observed result
- Failure or correction
Never rewrite an earlier entry. Add a correction as a new entry.
Do not record credentials.
Initial decisions:
- This is a standalone experiment outside the Mosaic Software Factory.
- It does not use existing Mosaic source, tools, contracts, agents, or runtime state.
- The first proof uses one Pi agent and four small local contract files.
- The only required model result is MOSAIC_HELLO_OK.
- Persistence, policy enforcement, Claude, orchestration, and portal work are deferred.
## Acceptance criteria
The experiment passes when:
1. scripts/build.sh exits 0.
2. The image contains the four local contract files.
3. The image contains no credentials.
4. The container has no mounts from ~/.mosaic or ~/.config/mosaic.
5. scripts/hello.sh performs a real model request.
6. The request does not contain the expected marker.
7. The agent returns exactly MOSAIC_HELLO_OK.
8. scripts/verify.sh exits 0.
9. Changing the expected value makes scripts/verify.sh exit nonzero.
10. scripts/reset.sh refuses unsafe paths.
11. Resetting and rerunning the verification produces the same successful result.
## Deferred layers
Document these in LAYERS.md. Do not implement them.
- L0: Container builds and returns MOSAIC_HELLO_OK.
- L1: Persist and resume a named Pi session.
- L2: Add a fixed tool permission policy.
- L3: Load full versioned contract bundles.
- L4: Add Claude as a second runtime.
- L5: Add multiple agents and communication.
- L6: Add orchestration, knowledge storage, and portal features.
## Explicit exclusions
Do not implement:
- Existing Mosaic Stack compatibility
- Git hosting or CI
- Pull requests or code review
- Deployment
- Persistent agent sessions
- Tool read restrictions
- Claude
- Multiple agents
- Fleet communication
- Watchers
- Role management
- Knowledge storage
- Database storage
- API server
- Web interface
- Dashboard
- Production security architecture
## Final report
When finished, report:
1. Files created.
2. Pi package version.
3. Exact build command.
4. Exact verification command.
5. Verification output with credentials removed.
6. Whether the real model request passed.
7. Any remaining failure.
8. Anything implemented beyond this brief.
Do not describe the experiment as production-ready.
-5584
View File
File diff suppressed because it is too large. Load diff
+46 -1
View File
@@ -1 +1,46 @@
@AGENTS.md
# CLAUDE.md — Mosaic Stack
## Project
Self-hosted, multi-user AI agent platform. TypeScript monorepo.
## Stack
- **API**: NestJS + Fastify adapter (`apps/gateway`)
- **Web**: Next.js 16 + React 19 (`apps/web`)
- **ORM**: Drizzle ORM + PostgreSQL 17 + pgvector (`packages/db`)
- **Auth**: BetterAuth (`packages/auth`)
- **Agent**: Pi SDK (`packages/agent`, `packages/mosaic`)
- **Queue**: Valkey 8 (`packages/queue`)
- **Build**: pnpm workspaces + Turborepo
- **CI**: Woodpecker CI
- **Observability**: OpenTelemetry → Jaeger
## Commands
```bash
pnpm typecheck # TypeScript check (all packages)
pnpm lint # ESLint (all packages)
pnpm format:check # Prettier check
pnpm test # Vitest (all packages)
pnpm build # Build all packages
# Database
pnpm --filter @mosaicstack/db db:generate # Offline migration artifact generation only
# PostgreSQL execution is held until KBN-101-00/-03/-05 land. Do not invoke a runner,
# init SQL, or Compose PostgreSQL service from this checkout.
# Dev: local PGlite data-layer work needs no PostgreSQL. Optional local queue service only:
docker compose up -d valkey
# Do not start Gateway/Web or root pnpm dev as a local PGlite route: the current unguarded dotenv
# loader can inherit a daemon PostgreSQL DSN. KBN-101-02 must make that state fail closed first.
```
## Conventions
- ESM everywhere (`"type": "module"`, `.js` extensions in imports)
- NodeNext module resolution
- Explicit `@Inject()` decorators in NestJS (tsx/esbuild doesn't support emitDecoratorMetadata)
- DTOs in `*.dto.ts` files at module boundaries
- OTEL tracing imported before NestJS bootstrap (`import './tracing.js'`)
- All three gates must pass before push: typecheck, lint, format:check
-44
View File
@@ -1,44 +0,0 @@
# Minimal Mosaic Stack POC agent image.
# Base: maintained Node.js image (same family as Pi's documented
# containerization example in docs/containerization.md).
FROM node:24-bookworm-slim
# Tools Pi's documented container image expects (bash, CA certs, git, ripgrep).
RUN apt-get update \
&& apt-get install -y --no-install-recommends bash ca-certificates git ripgrep \
&& rm -rf /var/lib/apt/lists/*
# Non-root user: the maintained node image ships a 'node' user at
# uid/gid 1000, which matches the host user that owns the runtime
# state directory mounted at /var/lib/mosaic. It is reused as-is.
# Pinned Pi install: package.json pins the exact version and
# package-lock.json is installed with npm ci. No unversioned installs.
WORKDIR /opt/app
COPY package.json package-lock.json ./
RUN npm ci --ignore-scripts
# Immutable contract fixtures (required location), runtime scripts, and
# runtime adapters.
COPY contracts /opt/mosaic/contracts
COPY src /opt/mosaic/src
COPY packages/processing-control/src/state.mjs packages/processing-control/src/entrypoint.mjs /opt/mosaic/processing-control/
COPY adapters /opt/mosaic/adapters
RUN chmod 0555 /opt/mosaic/contracts /opt/mosaic/contracts/* \
&& chmod 0555 /opt/mosaic/src /opt/mosaic/src/*.sh \
&& chmod 0555 /opt/mosaic/adapters /opt/mosaic/adapters/*/adapter.sh
# Writable state, workspace, and pi agent directory (auth.json is
# bind-mounted read-only at runtime; nothing is copied into the image).
RUN mkdir -p /var/lib/mosaic /workspace /home/node/.pi/agent \
&& chown -R node:node /var/lib/mosaic /workspace /home/node /opt/app
USER node
WORKDIR /workspace
ENV HOME=/home/node \
PATH="/opt/app/node_modules/.bin:${PATH}" \
PI_OFFLINE=1
# One-shot agent: args form the user request (default is the startup
# verification request defined in compose.yaml).
ENTRYPOINT ["/opt/mosaic/src/run-agent.sh"]
View File
File renamed without changes.
-50
View File
@@ -1,50 +0,0 @@
# LAYERS
Deferred capability layers for the Mosaic experiment. Only L0 is implemented by
this proof of concept; everything below it is documented here and deliberately
not implemented (see BRIEF.md, "Explicit exclusions").
## L0 — Implemented: container returns MOSAIC_HELLO_OK
One image (`mosaic-poc-agent:0.84.4`, built on `node:24-bookworm-slim`, non-root,
pinned Pi) runs one Pi agent one-shot. Four immutable local contract files are
loaded in fixed order into the generated system prompt
(`/var/lib/mosaic/system-prompt.md`). One real model request is sent
noninteractively; the response must equal `MOSAIC_HELLO_OK` exactly or the
verification exits nonzero. Authentication is supplied at runtime only
(read-only mounted pi auth file, or a provider API key environment variable).
## L1 — Deferred: persist and resume a named Pi session
Keep a named Pi session across container runs (`--name`, session storage under
`/var/lib/mosaic`), resume it with the documented session flags, and verify
state survives a container restart.
## L2 — Deferred: fixed tool permission policy
Add a fixed allow/deny policy for Pi tools (e.g. restricting built-in tools via
documented `--tools` / `--exclude-tools` or an extension-based permission gate),
so contract files can constrain what the agent may do, not just what it says.
## L3 — Deferred: load full versioned contract bundles
Replace the four static fixtures with versioned contract bundles: bundle
manifests, contract versions, and deterministic ordering/hashing, loaded from
an immutable bundle artifact instead of files copied at image build time.
## L4 — Deferred: Claude as a second runtime
Add a second runtime (Claude) alongside the Pi agent in the same container
stack, behind the same contract-loading path, to compare behavior across
runtimes.
## L5 — Deferred: multiple agents and communication
Run several named agents with defined roles and a communication channel between
them (message passing or shared state under `/var/lib/mosaic`).
## L6 — Deferred: orchestration, knowledge storage, and portal features
Fleet-level orchestration, knowledge storage, monitoring, and portal UI on top
of L1-L5. This is where the existing Mosaic Stack concepts would be re-evaluated
from first principles.
View File
File renamed without changes.
+343 -204
View File
@@ -1,238 +1,377 @@
# Mosaic Stack — new foundation
# Mosaic Stack
The active rebuild is at this repository's root. The original Mosaic Stack v1
source is archived under `v1/`; it is not the implementation being developed here.
Self-hosted, multi-user AI agent platform. One config, every runtime, same standards.
- Canonical checkout: `/mnt/storage/src/mosaic-stack`
- Repository: `mosaicstack/stack`
- Working branch: `refactor`
- Former `~/src/mosaic-stack-dev-test`: compatibility symlink to this same checkout
Mosaic gives you a unified launcher for Claude Code, Codex, OpenCode, and Pi — injecting consistent system prompts, guardrails, skills, and mission context into every session. A NestJS gateway provides the API surface, a Next.js dashboard gives you the UI, and a plugin system connects Discord, Telegram, and more.
Both original Git histories and pending development work are preserved. See the
[conversion record](docs/plans/2026-09-07_repository-consolidation-completed.md)
and [current next action](docs/plans/CURRENT.md). Do not use v1's startup commands,
package layout or agent instructions for work on the new foundation.
## Original container proof
The foundation began as a standalone container experiment. One container image
runs one Pi coding agent with four immutable local contract files as its system
prompt, sends exactly one real model request, and was verified to return exactly
`MOSAIC_HELLO_OK`. This historical result is not a claim that the full rebuild is
production-ready.
## Layout
```text
BRIEF.md requirements for the original container proof
BUILD-LOG.md append-only build/verification log
LAYERS.md implemented layer (L0) and deferred layers (L1-L6)
Containerfile image definition (node:24-bookworm-slim, non-root, pinned Pi)
compose.yaml one service: mosaic-agent (one-shot; configured via env)
package.json pins @earendil-works/pi-coding-agent at exactly 0.84.4
package-lock.json resolved lockfile used by npm ci in the image
.env.example non-secret settings only (credential-file path, env-var auth)
contracts/ CONSTITUTION.md, STANDARDS.md, SOUL.md, USER.md (immutable fixtures)
scripts/ bootstrap/build/hello/verify/reset + config tooling
src/ load-contracts.sh, run-agent.sh (run inside the container)
docs/plans/ architecture and milestone plans
```
## Configuration
The sole discovery entry point is:
```text
~/.config/mosaic-dev/config.json
```
Created only by the explicit, idempotent bootstrap:
## Quick Install
```bash
scripts/bootstrap.sh # create-if-absent; validates existing config, never rewrites
curl -fsSL https://mosaicstack.dev/install.sh | bash
```
Minimal shape (`configVersion` 1):
```json
{
"configVersion": 1,
"environment": "development",
"dataRoot": "/home/jwoltje/.mosaic-dev",
"execution": {
"backend": "docker",
"provider": "zai",
"model": "glm-5.3-flash"
}
}
```
Rules enforced by `scripts/mosaic-config.mjs`:
- Unknown keys, unsupported versions/backends, and malformed JSON exit nonzero; nothing is modified.
- `dataRoot` must be absolute, canonical, and must not be or contain the home or configuration directory.
- Validation failures never touch config, state, or images.
- `scripts/test-config.sh` runs the sandboxed config selftests (no Docker required).
Run paths (`build/hello/verify/reset`) fail closed when configuration is missing or invalid; they never invent it.
## Missions & tasks (M2)
Missions and tasks are validated JSON data (strict schemas, version-pinned). The M2 layer is host-side only: mission directives are recorded for provenance but do not yet reach the runtime system prompt (capability/policy layer comes later).
```text
missions/hello.json objective + directives (missionVersion 1)
tasks/hello-marker.json prompt + optional mission ref + expectExact + timeout
<dataRoot>/runs/r-<id>/ immutable run record: task.json, mission.json,
stderr.txt, result.json (all write-once)
```
Usage:
Or use the direct URL:
```bash
scripts/run-task.sh validate tasks/hello-marker.json # strict validation, writes nothing
scripts/run-task.sh run tasks/hello-marker.json # execute; result recorded under dataRoot/runs
scripts/mosaic-task.mjs list # list runs and statuses
scripts/test-task.sh # selftests (schema negatives + live runs)
bash <(curl -fsSL https://git.mosaicstack.dev/mosaicstack/stack/raw/branch/main/tools/install.sh)
```
A run exits 0 only when its expectation is met (`expectExact` match); mismatches, nonzero agent exits, and timeouts record `status: failed` in `result.json` and exit 1. Each run gets a unique directory — rerunning never rewrites history.
## Release model (M3)
`RELEASE` single-sources the release version (0.0.X until declared stable); the image tag derives from it plus the pinned Pi version. Activation is health-gated and every event is recorded:
The installer auto-launches the setup wizard, which walks you through gateway install and verification. Flags for non-interactive use:
```bash
scripts/release.sh package # build + tag the release image
scripts/release.sh activate # health check (exact marker) -> atomic pointer swap
scripts/release.sh activate --fault-injection # prove the refusal path (drills only)
scripts/release.sh rollback # health-gated return to the previous release
scripts/release.sh ensure # self-determination: align installed to RELEASE (safe no-op when aligned)
scripts/release.sh status # release, tag, active pointer, recent log
scripts/test-release.sh # release selftests
bash <(curl -fsSL …) --yes # Accept all defaults
bash <(curl -fsSL …) --yes --no-auto-launch # Install only, skip wizard
```
`ensure` is invoked automatically by the human-facing launchers (`hello`,
`verify`, `agent`): the system determines what is installed and aligns
itself — the user never runs release commands manually.
This installs both components:
- `<dataRoot>/state/active.json` — the activation pointer (atomic tmp+rename replace)
- `<dataRoot>/state/activation-log.jsonl` — append-only history: package / activate / refused / rollback
| Component | What | Where |
| ----------------------- | ---------------------------------------------------------------- | -------------------- |
| **Framework** | Bash launcher, guides, runtime configs, tools, skills | `~/.config/mosaic/` |
| **@mosaicstack/mosaic** | Unified `mosaic` CLI — TUI, gateway client, wizard, auto-updater | `~/.npm-global/bin/` |
A failed health check never activates; the previously active release remains deployed. Updating the software therefore cannot corrupt the running installation: package beside, gate, then flip. Verified by the update/refusal/rollback drills in BUILD-LOG Phase 7.
## Runtime adapters (M4)
The harness boundary is formalized: everything upstream (config, contracts, missions, tasks, run records) is harness-agnostic; everything inside an adapter belongs to one runtime.
```text
adapters/<name>/adapter.sh env in: MOSAIC_SYSTEM_PROMPT_FILE, MOSAIC_REQUEST,
MOSAIC_PROVIDER, MOSAIC_MODEL
stdout: response only; stderr: diagnostics
```
- Selection: `execution.adapter` in config.json (optional; `pi` default; allowlist `pi`, `mock`)
- `pi` — pinned Pi CLI, noninteractive print mode, ambient discovery off
- `mock` — deterministic test adapter; never for real verification
- Mission directives have a sanctioned injection point: when a task references a mission, the task runner mounts the run snapshot and the generated prompt gains a `MISSION (runtime)` section (objective + directives) after the four immutable contracts
- Adding a harness (Claude, Codex, OpenCode) later means adding one directory — no orchestrator changes
See `adapters/README.md` for the full contract.
## Workspaces, capabilities, sessions (M5/M6)
Optional task fields extend what an agent can do — all defaulting to the previous behavior:
```json
{
"workspace": "demo", // ":run" ephemeral, or persistent dataRoot/workspaces/<name>
"capabilities": { "tools": ["bash", "read"] }, // pi tool allowlist; absent = no tools
"session": "demo" // persistent session at dataRoot/sessions/<name>
}
```
- The adapter runs inside the workspace; files it writes are host-visible (`dataRoot/workspaces/<name>`).
- Sessions persist via pi's documented `--session-dir`; a follow-up run in the same session resumes the conversation (`-c`) and can recall prior context. Distinct names never share state. Ephemeral (`--no-session`) remains the default when no session is declared.
- Selection authority: config for adapter/provider/model; the task file for workspace/capabilities/session.
Inspect anything:
After install, the wizard runs automatically or you can invoke it manually:
```bash
node scripts/mosaic-task.mjs list # runs with task/workspace/session columns
node scripts/mosaic-task.mjs show <runId> # full record + snapshots + artifacts
mosaic wizard # Full guided setup (gateway install → verify)
```
Demo fixtures: `tasks/workspace-demo.json`, `tasks/session-demo-1.json` + `tasks/session-demo-2.json`.
### Requirements
See `docs/plans/2026-09-02_atomic-mosaic-foundation.md` for the full plan.
Inside the container:
```text
/opt/mosaic/contracts immutable contract files
/var/lib/mosaic generated runtime state (mounted from configured dataRoot)
/workspace agent workspace
```
## How it works
1. `scripts/build.sh` builds the release image (`mosaic-poc-agent:<pi>-r<release>`,
tag derived from `RELEASE` + the pinned Pi version) with Docker Compose.
2. On each run, `/opt/mosaic/src/load-contracts.sh` reads the four contract files
in fixed order (CONSTITUTION, STANDARDS, SOUL, USER), joins them with clear
separators, and writes `/var/lib/mosaic/system-prompt.md`.
3. `/opt/mosaic/src/run-agent.sh` starts Pi noninteractively
(`pi -p "Return your startup marker and nothing else."`) with
`--system-prompt "$(cat /var/lib/mosaic/system-prompt.md)"` and all ambient
discovery disabled (`--no-context-files --no-skills --no-extensions
--no-prompt-templates --no-themes`), ephemeral (`--no-session`), tool-free
(`--no-tools`), and offline for startup network operations (`--offline`).
4. `scripts/verify.sh` trims surrounding whitespace from the response and exits 0
only when it equals `MOSAIC_HELLO_OK` exactly.
- Node.js ≥ 20
- npm (for global @mosaicstack/mosaic install)
- One or more runtimes: [Claude Code](https://docs.anthropic.com/en/docs/claude-code), [Codex](https://github.com/openai/codex), [OpenCode](https://opencode.ai), or [Pi](https://github.com/mariozechner/pi-coding-agent)
## Usage
```bash
scripts/bootstrap.sh # create config.json if absent (idempotent)
scripts/build.sh # build the image
scripts/hello.sh # one-shot request; prints the model response
scripts/verify.sh # full gated test; exit 0 only on exact MOSAIC_HELLO_OK
scripts/run-task.sh # run a mission/task file (see Missions & tasks)
scripts/release.sh # package / activate / rollback / status (see Release model)
scripts/test-config.sh # fast config-layer selftests (no Docker)
scripts/test-task.sh # mission/task selftests (schema + adapter seam + live runs)
scripts/test-release.sh # release selftests
scripts/reset.sh # delete the configured data root (safety-checked)
```
Prove the failure path (acceptance criterion 9):
### Launching Agent Sessions
```bash
EXPECTED_MARKER=MOSAIC_NOT_OK scripts/verify.sh # must exit nonzero
mosaic pi # Launch Pi with Mosaic injection
mosaic claude # Launch Claude Code with Mosaic injection
mosaic codex # Launch Codex with Mosaic injection
mosaic opencode # Launch OpenCode with Mosaic injection
mosaic yolo claude # Claude with dangerous-permissions mode
mosaic yolo pi # Pi in yolo mode
```
## Authentication
The launcher verifies your config, checks for `SOUL.md`, injects your `AGENTS.md` standards into the runtime, and forwards all arguments.
Pi's documented container authentication (see the package's
`docs/containerization.md`) is used, in this order:
Pi launches default to a token-lean skill posture: `mosaic pi` passes `--no-skills` so Pi does not preload every global skill description into the system prompt. Use `MOSAIC_PI_SKILL_MODE=all mosaic pi` for the legacy all-skills catalog, or `MOSAIC_PI_SKILL_MODE=discover mosaic pi` to let Pi use its native settings/project skill discovery.
1. **Read-only mounted credential file** (default): the host pi auth file
`~/.pi/agent/auth.json` is bind-mounted read-only to
`/home/node/.pi/agent/auth.json`. The host file holds a static API-key
entry for the built-in `zai` provider, so no token refresh writes are needed.
2. **Runtime environment variable** (documented alternative): set `ZAI_API_KEY`
or `ANTHROPIC_API_KEY` in the environment or in a gitignored `.env`; compose
passes them through. Pi's documented precedence applies.
### TUI & Gateway
Credentials are never committed, never copied into the image, and never printed.
Mosaic-managed named accounts (`agent.sh --auth`) live under the data root
(`auth/<account>.json`, 0600) — the stack never writes into `~/.pi`.
`.env.example` contains non-secret settings only.
```bash
mosaic tui # Interactive TUI connected to the gateway
mosaic gateway login # Authenticate with a gateway instance
mosaic sessions list # List active agent sessions
```
## Boundaries honored
### Gateway Management
- No mounts of `~/.mosaic` or `~/.config/mosaic`; no Docker socket mount.
- Source stays in this project directory; generated state only in
`/home/jwoltje/.mosaic-dev` (host) and `/var/lib/mosaic` (container).
- No database, web server, queue, second container, orchestration, Git
integration, persistent sessions, or policy machinery.
```bash
mosaic gateway install # Install and configure the gateway service
mosaic gateway verify # Post-install health check
mosaic gateway login # Authenticate and store a session token
mosaic gateway config rotate-token # Rotate your API token
mosaic gateway config recover-token # Recover a token via BetterAuth cookie
```
If you already have a gateway account but no token, use `mosaic gateway config recover-token` to retrieve one without recreating your account.
### Configuration
Mosaic supports three storage tiers: `local` (PGlite, single-host), `standalone` (PostgreSQL, single-host), and `federated` (PostgreSQL + pgvector + Valkey, multi-host). See [Federated Tier Setup](docs/federation/SETUP.md) for multi-user and production deployments, or [Migrating to Federated](docs/guides/migrate-tier.md) to upgrade from existing tiers.
```bash
mosaic config show # Print full config as JSON
mosaic config get <key> # Read a specific key
mosaic config set <key> <val># Write a key
mosaic config edit # Open config in $EDITOR
mosaic config path # Print config file path
```
### Management
```bash
mosaic doctor # Health audit — detect drift and missing files
mosaic sync # Sync skills from canonical source
mosaic skill list # Audit Claude skill registrations and conflicts
mosaic skill register <name> # Register one canonical skill with Claude Code
mosaic skill unregister <name> # Remove one Mosaic-owned Claude link
mosaic update # Update CLI/framework and auto-register canonical skills
mosaic wizard # Full guided setup wizard
mosaic bootstrap <path> # Bootstrap a repo with Mosaic standards
mosaic coord init # Initialize a new orchestration mission
mosaic prdy init # Create a PRD via guided session
```
### Sub-package Commands
Each Mosaic sub-package exposes its API surface through the unified CLI:
```bash
# User management
mosaic auth users list
mosaic auth users create
mosaic auth sso
# Agent brain (projects, missions, tasks)
mosaic brain projects
mosaic brain missions
mosaic brain tasks
mosaic brain conversations
# Agent forge pipeline
mosaic forge run
mosaic forge status
mosaic forge resume
mosaic forge personas
# Structured logging
mosaic log tail
mosaic log search
mosaic log export
mosaic log level
# MACP protocol
mosaic macp tasks
mosaic macp submit
mosaic macp gate
mosaic macp events
# Agent memory
mosaic memory search
mosaic memory stats
mosaic memory insights
mosaic memory preferences
# Task queue (Valkey)
mosaic queue list
mosaic queue stats
mosaic queue pause
mosaic queue resume
mosaic queue jobs
mosaic queue drain
# Object storage
mosaic storage status
mosaic storage tier
mosaic storage export
mosaic storage import
# Schema migration is unavailable in this release. The current storage wrapper shells
# directly to `pnpm --filter @mosaicstack/db db:migrate`; it is legacy N-1,
# uncertified, and MUST NOT be invoked pending KBN-101-02/-03/-06/-08 activation.
# Future schema migration is non-operative: external bootstrap → TLS/roles → runner
# --run → runner --verify → readiness. Tier copy uses only the separately held secure
# migrate-tier route.
```
### Telemetry
```bash
# Local observability (OTEL / Jaeger)
mosaic telemetry local status
mosaic telemetry local tail
mosaic telemetry local jaeger
# Remote telemetry (dry-run by default)
mosaic telemetry status
mosaic telemetry opt-in
mosaic telemetry opt-out
mosaic telemetry test
mosaic telemetry upload # Dry-run unless opted in
```
Consent state is persisted in config. Remote upload is a no-op until you run `mosaic telemetry opt-in`.
## Development
### Prerequisites
- Node.js ≥ 20
- pnpm 10.6+
- Docker & Docker Compose
### Setup
```bash
git clone [email protected]:mosaicstack/stack.git
cd stack
# Install dependencies. The local tier uses in-process PGlite; leave DATABASE_URL unset.
pnpm install
# Optional local queue service only. This does not start PostgreSQL.
docker compose up -d valkey
# The current Gateway/Web local process is held; see docs/guides/dev-guide.md.
# Do not start it until KBN-101-02 makes inherited dotenv/DSN state fail closed.
```
### Held future procedure
The checked-in Compose PostgreSQL service mounts legacy initialization SQL and is **not** a
current PostgreSQL, standalone, or federated developer route. Do not start it with Compose,
invoke initialization SQL, or treat the planned migrator as currently executable.
**Held future activation procedure — non-operative and no current command authority until KBN-101-00, KBN-101-03, and KBN-101-05
land:** external bootstrap → TLS/roles → `mosaic-db-migrator --run` →
`mosaic-db-migrator --verify` → Gateway/Compose readiness. The future deployment artifacts—not
this README—will provide the reviewed commands and secret-consumer interface.
For local data-layer work, PGlite needs no PostgreSQL service. The optional Compose command above
starts only Valkey; OTEL Collector and Jaeger may likewise be started individually if needed,
without starting PostgreSQL. A Gateway/Web local process is not currently a safe PGlite route:
its unguarded dotenv loader may inherit a daemon PostgreSQL DSN. Do not use root `pnpm dev` or a
Gateway start command until KBN-101-02 makes that state fail closed.
### Quality Gates
```bash
pnpm typecheck # TypeScript type checking (all packages)
pnpm lint # ESLint (all packages)
pnpm test # Vitest (all packages)
pnpm format:check # Prettier check
pnpm format # Prettier auto-fix
```
### CI
Woodpecker CI runs on every push:
- `pnpm install --frozen-lockfile`
- **Legacy N-1 CI status only — active, uncertified, and non-authorizing as an operator route:** the checked-in job currently invokes `pnpm --filter @mosaicstack/db run db:migrate` with `DATABASE_URL` against an isolated disposable PostgreSQL CI database. It performs direct DDL in that CI database, is not approved ordinary behavior or an operator route, and remains a known exception pending KBN-101-06 removal/replacement by the certified runner-backed CI path.
- `pnpm test` (Turbo-orchestrated across all packages)
npm packages are published to the Gitea package registry on main merges.
## Architecture
```
stack/
├── apps/
│ ├── gateway/ NestJS API + WebSocket hub (Fastify, Socket.IO, OTEL)
│ └── web/ Next.js dashboard (React 19, Tailwind)
├── packages/
│ ├── mosaic/ Unified CLI — TUI, gateway client, wizard, sub-package commands
│ ├── types/ Shared TypeScript contracts (Socket.IO typed events)
│ ├── db/ Drizzle ORM schema + migrations (pgvector)
│ ├── auth/ BetterAuth configuration
│ ├── brain/ Data layer (PG-backed)
│ ├── queue/ Valkey task queue + MCP
│ ├── coord/ Mission coordination
│ ├── forge/ Multi-stage AI pipeline (intake → board → plan → code → review)
│ ├── macp/ MACP protocol — credential resolution, gate runner, events
│ ├── agent/ Agent session management
│ ├── memory/ Agent memory layer
│ ├── log/ Structured logging
│ ├── prdy/ PRD creation and validation
│ ├── quality-rails/ Quality templates (TypeScript, Next.js, monorepo)
│ └── design-tokens/ Shared design tokens
├── plugins/
│ ├── discord/ Discord channel plugin (discord.js)
│ ├── telegram/ Telegram channel plugin (Telegraf)
│ ├── macp/ OpenClaw MACP runtime plugin
│ └── mosaic-framework/ OpenClaw framework injection plugin
├── tools/
│ └── install.sh Unified installer (framework + npm CLI, --yes / --no-auto-launch)
├── scripts/agent/ Agent session lifecycle scripts
├── docker-compose.yml Dev infrastructure
└── .woodpecker/ CI pipeline configs
```
### Key Design Decisions
- **Gateway is the single API surface** — all clients (TUI, web, Discord, Telegram) connect through it
- **ESM everywhere** — `"type": "module"`, `.js` extensions in imports, NodeNext resolution
- **Socket.IO typed events** — defined in `@mosaicstack/types`, enforced at compile time
- **OTEL auto-instrumentation** — loads before NestJS bootstrap
- **Explicit `@Inject()` decorators** — required since tsx/esbuild doesn't emit decorator metadata
### Framework (`~/.config/mosaic/`)
The framework is the bash-based standards layer installed to every developer machine:
```
~/.config/mosaic/
├── AGENTS.md ← Central standards (loaded into every runtime)
├── SOUL.md ← Agent identity (name, style, guardrails)
├── USER.md ← User profile (name, timezone, preferences)
├── TOOLS.md ← Machine-level tool reference
├── bin/mosaic ← Unified launcher (claude, codex, opencode, pi, yolo)
├── guides/ ← E2E delivery, orchestrator protocol, PRD, etc.
├── runtime/ ← Per-runtime configs (claude/, codex/, opencode/, pi/)
├── skills/ ← Universal skills (synced from agent-skills repo)
├── tools/ ← Tool suites (orchestrator, git, quality, prdy, etc.)
└── memory/ ← Persistent agent memory (preserved across upgrades)
```
### Forge Pipeline
Forge is a multi-stage AI pipeline for autonomous feature delivery:
```
Intake → Discovery → Board Review → Planning (3 stages) → Coding → Review → Remediation → Test → Deploy
```
Each stage has a dispatch mode (`exec` for research/review, `yolo` for coding), quality gates, and timeouts. The board review uses multiple AI personas (CEO, CTO, CFO, COO + specialists) to evaluate briefs before committing resources.
## Upgrading
Run the installer again — it handles upgrades automatically:
```bash
curl -fsSL https://mosaicstack.dev/install.sh | bash
```
Or use the direct URL:
```bash
bash <(curl -fsSL https://git.mosaicstack.dev/mosaicstack/stack/raw/branch/main/tools/install.sh)
```
Or use the CLI:
```bash
mosaic update # Check + install CLI updates
mosaic update --check # Check only, don't install
```
The CLI also performs a background update check on every invocation (cached for 1 hour).
### Installer Flags
```bash
bash tools/install.sh --check # Version check only
bash tools/install.sh --framework # Framework only (skip npm CLI)
bash tools/install.sh --cli # npm CLI only (skip framework)
bash tools/install.sh --ref v1.0 # Install from a specific git ref
bash tools/install.sh --yes # Non-interactive, accept all defaults
bash tools/install.sh --no-auto-launch # Skip auto-launch of wizard
```
The installer rejects unrecognized flags or positional arguments before making changes and prints the supported-option usage.
## Contributing
```bash
# Create a feature branch
git checkout -b feat/my-feature
# Make changes, then verify
pnpm typecheck && pnpm lint && pnpm test && pnpm format:check
# Commit (husky runs lint-staged automatically)
git commit -m "feat: description of change"
# Push and create PR
git push -u origin feat/my-feature
```
DTOs go in `*.dto.ts` files at module boundaries. Scratchpads (`docs/scratchpads/`) are mandatory for non-trivial tasks. See `AGENTS.md` for the full standards reference.
## License
Proprietary — all rights reserved.
-1
View File
@@ -1 +0,0 @@
0.0.12
-30
View File
@@ -1,30 +0,0 @@
# Mosaic Stack
You are the default collaborator for Mosaic Stack: a practical engineering
partner helping people build, inspect, and operate a trustworthy foundation
for delegated work.
Mosaic Stack is deliberately small, file-based, and evidence-oriented. Its
purpose is not to perform confidence; it is to make useful work attributable,
bounded, reproducible, and reviewable. Treat the system's contracts, policies,
and run records as part of the product, not paperwork around it.
Work with calm precision. Start from what the user is trying to accomplish,
make the next useful step clear, and explain results in plain language. Be
decisive when the evidence supports a decision; be explicit about uncertainty
when it does not. Never claim a test, command, integration, or outcome that
you have not actually verified.
Respect boundaries. Ask before expanding scope, changing authority, touching
credentials, or taking an irreversible external action. Prefer the least
privileged path, preserve user work, and stop on a policy or validation
refusal rather than working around it. A clean refusal with a useful diagnosis
is better than a superficially successful but untrustworthy result.
Leave a legible trail. Make changes intentional, keep records honest, and
report what changed, how it was checked, and what remains unresolved. When
coordinating other workers, give each one a bounded objective and review their
evidence instead of treating their confidence as proof.
The aim is dependable progress: small enough to understand, safe enough to
trust, and concrete enough for a person to verify.
-128
View File
@@ -1,128 +0,0 @@
# Mosaic runtime adapters
An adapter is the entire harness-specific surface of the system. Everything
upstream of an adapter — configuration, contracts, missions, tasks, run
records — is harness-agnostic; everything inside an adapter may assume one
specific agent runtime.
## Contract
An adapter lives at:
```text
/opt/mosaic/adapters/<name>/adapter.sh
```
and must be executable. The dispatcher (`/opt/mosaic/src/run-agent.sh`)
selects it via `MOSAIC_ADAPTER` (default: `pi`) and execs it after the
system prompt has been generated.
**Inputs (environment):**
| Variable | Meaning |
|---|---|
| `MOSAIC_SYSTEM_PROMPT_FILE` | Absolute path to the generated system prompt (contracts + optional mission section). Read it; do not modify it. |
| `MOSAIC_REQUEST` | The exact user request text (may contain newlines). |
| `MOSAIC_PROVIDER` | Configured provider name. |
| `MOSAIC_MODEL` | Configured model id. |
Optional, adapter-specific (documented per adapter):
| Variable | Meaning |
|---|---|
| `MOSAIC_MOCK_RESPONSE` | mock only: the verbatim response to emit |
**Outputs:**
- `stdout`: the model response text — the only channel the orchestrator captures
- `stderr`: diagnostics (never credentials)
- exit `0`: success; nonzero: failure
## Rules
1. Adapters print ONLY the response on stdout. Status lines go to stderr.
2. Adapters never read configuration files; the resolved settings arrive via environment.
3. Adapters never write outside `/var/lib/mosaic`.
4. Adding a worker adapter requires: a new directory, the contract
implementation, and adding the name to the allowlist in
`scripts/mosaic-config.mjs`. A managed-session adapter (below) is selected
by the launch bundle, not by `execution.adapter`, and is not on that
allowlist unless it also works as a worker adapter.
## Included adapters
- `pi` — the pinned `@earendil-works/pi-coding-agent` CLI in noninteractive
print mode (`-p`), ambient discovery disabled, stdin detached.
- `mock` — deterministic echo of `MOSAIC_MOCK_RESPONSE`. Test-only: never use
it where a real model response is required.
- `claude` — the host's `claude` CLI, for managed sessions only (below):
`MOSAIC_CLAUDE_BIN` when set, else `claude` on `PATH`.
Not a worker adapter: the image has no `claude`, and the adapter refuses
without the bundle's hook and MCP files.
## Managed sessions (slice 1 S6)
The session runner (`packages/harness/src/runner.mjs`) runs one adapter
call per turn on the host, as `/bin/sh <adapters/<name>/adapter.sh>` (the
repository keeps adapters 0644; only the image sets the mode), in the
session's workspace and its own process group. Same contract, plus:
| Variable | Meaning |
|---|---|
| `MOSAIC_WORKSPACE` | The session's workspace; the adapter runs there. |
| `MOSAIC_SESSION_DIR` | The session's persistent directory; later turns resume the session kept there. |
| `MOSAIC_TOOLS` | The built-in tool limit (pi names for `pi`, Claude Code names for `claude`), comma-separated. |
| `MOSAIC_POLICY_FILE`, `MOSAIC_TOOLS_FILE` | The bundle's gate policy and typed tools. |
| `MOSAIC_TOOL_SOCKET` | The runner's tool socket, which the typed tools call. |
| `MOSAIC_TURN_MARKER` | `pi`: the extension writes it at `agent_end`; a pi turn that exits 0 without it failed. |
| `MOSAIC_EXTENSIONS` | `pi` only: extension files loaded with `-e`; a missing one exits 2. The pi module names two: the gate and typed tools extension, then the unslop check's `tools/unslop-hook/extension.ts` (row 66). |
| `MOSAIC_UNSLOP_LOG` | The unslop check's JSONL log, `<run>/unslop.jsonl`, which the runner sets for both adapters and reads after each turn (row 66). |
| `MOSAIC_CLAUDE_SETTINGS`, `MOSAIC_CLAUDE_MCP_CONFIG` | `claude` only: the bundle's gate hook and MCP server; required. |
| `MOSAIC_THINKING` | The route's thinking level (row 65), which the harness module's `levels()` already checked. `pi` passes `--thinking` (`off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`) and omits it when unset, as for `run-task.sh` workers. `claude` passes `--effort` (`low`, `medium`, `high`, `xhigh`, `max`) and requires it; unset exits 2. |
| `MOSAIC_CLAUDE_BIN` | `claude` only: absolute path of the CLI to run, from the host's environment (the bus unit pins it). Unset or empty runs `claude` from `PATH`; a relative path or a non-executable file exits 2. |
The layers each adapter relies on, and what they don't cover, are in
`packages/harness/README.md`.
### A role's skills (row 64)
A managed session's skills reach both adapters as text in the bundle's
`prompt.md`, which they pass as a file: `pi` with `--system-prompt <path>`
and `claude` with `--system-prompt-file <path>` (row 213). Neither adapter loads a
skill of its own: `pi` keeps `--no-skills`, since role sessions never get
`MOSAIC_SKILLS`, and `claude` keeps `--disable-slash-commands` and
`--restricted`. Sage chose this on 2026-10-19 from a probe, recorded in
`agents/sage/work/queue-64/probe.md`:
- Pi's `--skill` puts only a skill's name and description in the prompt,
and the model has to `read` the SKILL.md itself. The gate refuses every
file-tool path outside the workspace, so the session couldn't open its
own skills. Opening the gate to the bundle would change a security
boundary.
- Claude Code loads a bundle-local `--plugin-dir` skill under `--restricted`
only with its `Skill` tool on, and then it also offers its own bundled
skills. Which ones it offers changes with the Claude Code version, and the
`Skill` tool would pass through the gate hook.
The cost is prompt size: a role's skill text is in every turn, where the
other routes load a skill when it's used. The bundle caps a role's skills at
64 KiB together. The cap dates from when `claude` passed `prompt.md` as one
argument, which Linux caps at 128 KiB; row 213 passes the file instead, so no
local user reads the prompt in `/proc/<pid>/cmdline`. Pi 0.85.1 uses the path
string itself as the prompt when the file is missing or can't be read, so the
pi adapter exits 2 unless the path is a readable regular file.
### The unslop check (row 66)
Both adapters run the mechanical writing check from `tools/unslop-hook`,
driven by one `lists.json`. `pi` loads it as its second `-e` extension.
`claude` runs `claude-hook.js` from the bundle's `settings.json`: the Stop
hook checks the turn's replies, and the UserPromptSubmit hook adds the
correction notice as context on the next turn when the last reply had
tells. Each hook command ends `; exit 0`, so neither blocks. Both log to
`MOSAIC_UNSLOP_LOG`, and the runner adds a note for the operator to the
next RESULT it sends (`packages/harness/README.md`, the runner). The
harness modules mount the three files read-only at their own paths, and
the manifest records their digests. `MOSAIC_UNSLOP_HOOK` and `UNSLOP_LISTS`
aren't in the session environment's allowlist, so a managed session can't
switch the check off or swap its lists.
-101
View File
@@ -1,101 +0,0 @@
#!/bin/sh
# Claude Code adapter: implements the Mosaic adapter contract for the host's
# `claude` CLI, for managed sessions (slice 1 S6). Headless only. The CLI is
# MOSAIC_CLAUDE_BIN when set (the bus unit pins it), else `claude` on PATH.
#
# Contract: see adapters/README.md.
# stdout = the turn's answer only; stderr = diagnostics; exit 0 on success.
#
# The layers this relies on are row S0 lines 1-5 (docs/plans/2026-10-04_slice-1.md,
# "What S6 can rely on"): the PreToolUse command hook in MOSAIC_CLAUDE_SETTINGS,
# wrapped as `timeout -k 2 10 <gate> || exit 2`, and the tool limit (--tools).
# --bare is never passed: it turns settings hooks off.
set -eu
need() {
eval "v=\${$1:-}"
[ -n "$v" ] || { echo "claude adapter: $1 is required" >&2; exit 2; }
}
need MOSAIC_SYSTEM_PROMPT_FILE
need MOSAIC_REQUEST
need MOSAIC_WORKSPACE
need MOSAIC_SESSION_DIR
need MOSAIC_MODEL
need MOSAIC_THINKING
need MOSAIC_CLAUDE_SETTINGS
need MOSAIC_CLAUDE_MCP_CONFIG
for f in "$MOSAIC_SYSTEM_PROMPT_FILE" "$MOSAIC_CLAUDE_SETTINGS" "$MOSAIC_CLAUDE_MCP_CONFIG"; do
[ -r "$f" ] || { echo "claude adapter: not readable: $f" >&2; exit 2; }
done
PROMPT_FILE=$MOSAIC_SYSTEM_PROMPT_FILE
case "$PROMPT_FILE" in
/*) ;;
*) PROMPT_FILE="$(pwd)/$PROMPT_FILE" ;;
esac
[ "${MOSAIC_INTERACTIVE:-}" != "1" ] || { echo "claude adapter: interactive mode isn't supported" >&2; exit 2; }
CLAUDE=claude
if [ -n "${MOSAIC_CLAUDE_BIN:-}" ]; then
case "$MOSAIC_CLAUDE_BIN" in
/*) ;;
*) echo "claude adapter: MOSAIC_CLAUDE_BIN must be an absolute path: $MOSAIC_CLAUDE_BIN" >&2; exit 2 ;;
esac
[ -f "$MOSAIC_CLAUDE_BIN" ] && [ -x "$MOSAIC_CLAUDE_BIN" ] || { echo "claude adapter: MOSAIC_CLAUDE_BIN is not an executable file: $MOSAIC_CLAUDE_BIN" >&2; exit 2; }
CLAUDE=$MOSAIC_CLAUDE_BIN
fi
mkdir -p "$MOSAIC_WORKSPACE" "$MOSAIC_SESSION_DIR"
cd "$MOSAIC_WORKSPACE"
# Session: the first turn names a new session id, later turns resume it.
# The id is kept only after a turn succeeds, so a failed first turn never
# leaves a --resume of a session that doesn't exist.
ID_FILE="$MOSAIC_SESSION_DIR/claude-session-id"
if [ -s "$ID_FILE" ]; then
SESSION_FLAG=--resume
SESSION_ID=$(cat "$ID_FILE")
else
SESSION_FLAG=--session-id
SESSION_ID=$(cat /proc/sys/kernel/random/uuid)
fi
# Flags:
# -p one-shot: print the answer and exit
# --output-format text stdout is the answer only
# --system-prompt-file the generated prompt replaces the default, given
# as a file so no local user reads it in
# /proc/<pid>/cmdline (row 213); absolute, since
# the cd above changed the working directory
# --effort the instance's thinking var (row 65; 2.1.302 takes
# low, medium, high, xhigh, max)
# --restricted no user/project/local settings files; --settings
# (the gate hook) still applies; no code-running
# tool unless --tools names it; file tools confined
# to the working directory; no CLAUDE.md file or
# auto-memory in the prompt. The S0 lines above
# don't depend on it, but it is what keeps founder
# and repository memory out; a test fails without it.
# --tools the built-in tool limit (S0 line 5); empty = none
# --allowedTools the same tools plus the mosaic MCP server, so
# --permission-mode dontAsk nothing waits on a prompt and anything else is denied
# --settings the gate hook (S0 lines 1-4)
# --strict-mcp-config only the bundle's MCP server, which serves the
# --mcp-config typed bus tools
# --disable-slash-commands no skill discovery; the role's skills are
# text in the system prompt (row 64)
ALLOWED=mcp__mosaic
[ -z "${MOSAIC_TOOLS:-}" ] || ALLOWED="$MOSAIC_TOOLS,mcp__mosaic"
"$CLAUDE" -p "$MOSAIC_REQUEST" \
--output-format text \
--system-prompt-file "$PROMPT_FILE" \
--model "$MOSAIC_MODEL" \
--effort "$MOSAIC_THINKING" \
--restricted \
--tools "${MOSAIC_TOOLS:-}" \
--allowedTools "$ALLOWED" \
--permission-mode dontAsk \
--settings "$MOSAIC_CLAUDE_SETTINGS" \
--strict-mcp-config \
--mcp-config "$MOSAIC_CLAUDE_MCP_CONFIG" \
--disable-slash-commands \
"$SESSION_FLAG" "$SESSION_ID" || exit $?
[ "$SESSION_FLAG" = --resume ] || printf '%s\n' "$SESSION_ID" > "$ID_FILE"
-18
View File
@@ -1,18 +0,0 @@
#!/bin/sh
# Mock adapter: deterministic response for seam tests. NEVER use where a
# real model response is required.
#
# Contract: see /opt/mosaic/adapters/README.md.
set -eu
[ -n "${MOSAIC_SYSTEM_PROMPT_FILE:-}" ] || { echo "mock adapter: MOSAIC_SYSTEM_PROMPT_FILE is required" >&2; exit 2; }
if [ "${MOSAIC_INTERACTIVE:-}" != "1" ]; then
[ -n "${MOSAIC_REQUEST:-}" ] || { echo "mock adapter: MOSAIC_REQUEST is required" >&2; exit 2; }
fi
[ -r "$MOSAIC_SYSTEM_PROMPT_FILE" ] || { echo "mock adapter: system prompt not readable: $MOSAIC_SYSTEM_PROMPT_FILE" >&2; exit 2; }
echo "mock adapter: responding verbatim from MOSAIC_MOCK_RESPONSE" >&2
# Deterministic plumbing evidence: which MOSAIC_* variables did the
# orchestrator actually deliver? (Auth secrets are not MOSAIC_-prefixed.)
(env | grep '^MOSAIC_' | sort) >&2 2>/dev/null || true
printf '%s\n' "${MOSAIC_MOCK_RESPONSE:-}"
-135
View File
@@ -1,135 +0,0 @@
#!/bin/sh
# Pi adapter: implements the Mosaic adapter contract for the pinned
# @earendil-works/pi-coding-agent CLI.
#
# Contract: see /opt/mosaic/adapters/README.md.
# Headless (default): stdout = response only; stderr = diagnostics; exit 0.
# Interactive (MOSAIC_INTERACTIVE=1): full pi TUI on the attached terminal.
set -eu
[ -n "${MOSAIC_SYSTEM_PROMPT_FILE:-}" ] || { echo "pi adapter: MOSAIC_SYSTEM_PROMPT_FILE is required" >&2; exit 2; }
# Row 213 (C2-08): pi gets the prompt as a path, so no local user reads it in /proc/<pid>/cmdline.
# Pi 0.85.1 reads --system-prompt as a file only when the path exists and reads, and otherwise
# uses the path string itself as the prompt, without a warning for a missing file
# (dist/core/resource-loader.js resolvePromptInput). So the path must be a regular readable
# file here, and is made absolute before the cd below, since pi resolves it from its own cwd.
PROMPT_FILE=$MOSAIC_SYSTEM_PROMPT_FILE
case "$PROMPT_FILE" in
/*) ;;
*) PROMPT_FILE="$(pwd)/$PROMPT_FILE" ;;
esac
[ -f "$PROMPT_FILE" ] && [ -r "$PROMPT_FILE" ] || { echo "pi adapter: system prompt not readable: $MOSAIC_SYSTEM_PROMPT_FILE" >&2; exit 2; }
# MOSAIC_AGENT_NAME is optional in headless mode (identity section is then
# omitted); interactive launches always set it via scripts/agent.sh.
: "${PI_PROVIDER:?pi adapter: PI_PROVIDER is required}"
: "${PI_MODEL:?pi adapter: PI_MODEL is required}"
INTERACTIVE="${MOSAIC_INTERACTIVE:-}"
if [ "$INTERACTIVE" != "1" ]; then
[ -n "${MOSAIC_REQUEST:-}" ] || { echo "pi adapter: MOSAIC_REQUEST is required" >&2; exit 2; }
fi
# Workspace (M5): run inside the provided workspace when present.
if [ -n "${MOSAIC_WORKSPACE:-}" ]; then
mkdir -p "$MOSAIC_WORKSPACE"
cd "$MOSAIC_WORKSPACE"
fi
# Session (M6/M11): default ephemeral (--no-session). With a declared
# session dir: persist there and resume the most recent session. With a
# fork source: branch the source session file into the target dir
# (pi --fork) - the ancestor session is never modified.
SESSION_FLAGS="--no-session"
if [ -n "${MOSAIC_SESSION_FORK:-}" ]; then
[ -n "${MOSAIC_SESSION_DIR:-}" ] || { echo "pi adapter: session fork requires MOSAIC_SESSION_DIR" >&2; exit 2; }
mkdir -p "$MOSAIC_SESSION_DIR"
SESSION_FLAGS="--fork $MOSAIC_SESSION_FORK --session-dir $MOSAIC_SESSION_DIR"
elif [ -n "${MOSAIC_SESSION_DIR:-}" ]; then
mkdir -p "$MOSAIC_SESSION_DIR"
SESSION_FLAGS="--session-dir $MOSAIC_SESSION_DIR"
if [ -n "$(ls -A "$MOSAIC_SESSION_DIR" 2>/dev/null)" ]; then
SESSION_FLAGS="$SESSION_FLAGS -c"
fi
fi
# Capabilities (M5): explicit allowlist or no tools.
TOOLS_FLAG="--no-tools"
[ -n "${MOSAIC_TOOLS:-}" ] && TOOLS_FLAG="--tools $MOSAIC_TOOLS"
# Skills (M17): explicitly provided skill dirs replace discovery. When none
# are provided the agent runs with --no-skills (nothing ambient to find).
# Role sessions never get MOSAIC_SKILLS (ENV_ALLOW in packages/seat/src/
# session.mjs leaves it out), so they run with --no-skills; their skills
# are text in the system prompt (row 64).
SKILLS_FLAG="--no-skills"
if [ -n "${MOSAIC_SKILLS:-}" ]; then
SKILLS_FLAG=""
OLDIFS=$IFS; IFS=','
for s in $MOSAIC_SKILLS; do
[ -d "$s" ] || { echo "pi adapter: skill dir missing: $s" >&2; exit 2; }
SKILLS_FLAG="$SKILLS_FLAG --skill $s"
done
IFS=$OLDIFS
fi
# Extensions (S6): explicitly provided extension files, loaded with -e
# after --no-extensions turns discovery off. A missing file refuses here;
# pi itself also refuses to start on a missing or broken -e (row S0 line 3).
EXT_FLAGS=""
if [ -n "${MOSAIC_EXTENSIONS:-}" ]; then
OLDIFS=$IFS; IFS=','
for e in $MOSAIC_EXTENSIONS; do
[ -f "$e" ] || { echo "pi adapter: extension missing: $e" >&2; exit 2; }
EXT_FLAGS="$EXT_FLAGS -e $e"
done
IFS=$OLDIFS
fi
# Thinking (row 65): a managed session's level, from its instance's thinking
# var (pi 0.85.1: off, minimal, low, medium, high, xhigh, max). Workers from
# run-task.sh set none and keep pi's default.
THINKING_FLAG=""
[ -n "${MOSAIC_THINKING:-}" ] && THINKING_FLAG="--thinking $MOSAIC_THINKING"
# Mode (M13): interactive TUI or one-shot print.
PRINT_MODE="-p"
REQUEST_ARG=""
if [ "$INTERACTIVE" = "1" ]; then
PRINT_MODE=""
else
REQUEST_ARG="$MOSAIC_REQUEST"
fi
# All flags documented in the pi package README (CLI Reference):
# -p/--print one-shot mode: print the response and exit (omitted in
# interactive TUI mode)
# --system-prompt replace the default prompt with the generated one, given
# as the file's absolute path (checked above), never its text
# --no-* no ambient context/skills/extensions/templates/themes
# EXT_FLAGS the explicitly provided extensions only (-e)
# SESSION_FLAGS ephemeral | persistent | forked (per env)
# TOOLS_FLAG per capabilities
# THINKING_FLAG --thinking <level> for a managed session, else nothing
# --offline no startup network operations (update checks/telemetry)
# --no-approve ignore project-local .pi/ files (settings, SYSTEM.md)
# whatever trust is saved for the workspace
set -- \
--offline \
--no-approve \
--no-extensions \
$EXT_FLAGS \
$SKILLS_FLAG \
--no-prompt-templates \
--no-themes \
--no-context-files \
$TOOLS_FLAG \
$SESSION_FLAGS \
--provider "$PI_PROVIDER" \
--model "$PI_MODEL" \
$THINKING_FLAG \
--system-prompt "$PROMPT_FILE"
# One-shot mode appends -p and the request (both safely quoted);
# interactive mode appends nothing - clean TUI.
[ "$INTERACTIVE" = "1" ] || set -- "$@" -p "$MOSAIC_REQUEST"
exec pi "$@"
-66
View File
@@ -1,66 +0,0 @@
# Mosaic Stack development team
These are interactive host development agents working in the canonical
checkout. They do not create managed fleet registrations or change role policy.
Sage leads the project and coordinates assignments, review, and integration
(Jason's ruling, 2026-09-26). Development sessions run in T3 for now.
For the current bootstrap phase, direct coding, review and research use Darkwing,
Dewey, Filbert, Rocko, Researcher and further seats Jason launches from this repository's `agents/` directory,
not fleet seats. Keep changes in `/mnt/storage/src/mosaic-stack`; do not modify
`~/.mosaic` launchers/provisioning or migrate/stop live fleet processes.
| Agent | Responsibility | Runtime | Launch from repository root |
| --- | --- | --- | --- |
| Darkwing | Hands-on engineering; collaborating seat under Sage | Pi, configured Mosaic model | `agents/darkwing/launch.sh` |
| Dewey | Frontend design, UX, accessibility, and UI implementation | Pi, configured Mosaic model | `agents/dewey/launch.sh` |
| Rocko | General development, investigation, testing, and review | T3 session (Codex, gpt-6.1-sol, thread d99326cc, lead decision 122; Claude thread b84bb264 retired 2026-10-12); launcher Claude Code, Sonnet model | `agents/rocko/launch.sh` |
| Filbert | General development, investigation, testing, and review | T3 session (Claude, Opus 5.5, thread 048f3c63, non-sandbox reviews only, lead decisions 130 and 134; Codex threads f712d8af and 50342f6a retired 2026-10-13, Claude thread 9cb9731e retired 2026-10-12); launcher Pi, `openai-codex/gpt-6-astra:low`, not to be used under R26 until it changes (lead decision 69) | `agents/filbert/launch.sh` |
| Researcher | Source-grounded technical research and evidence | T3 session (Claude, Sonnet 5.5, thread 9bac0794, rows 97 and 98, lead decision 124); Haiku rows (71, 80, 84, 88, later 96) run as subagents Sage dispatches with model haiku, effort high and a worktree (lead decision 129); Haiku thread c98aaf4a retired 2026-10-13 unused; launcher Pi, configured Mosaic model | `agents/researcher/launch.sh` |
| Launchpad | Builder, MVP T1 row 192 (Q175 SSO phase 1) | T3 session (Claude, Opus 5.5), started by Sage under mos-0974/0977 | none, T3 only |
| Morgana | Builder, MVP T1 row 193 (human users and RBAC) | T3 session (Claude, Opus 5.5), started by Sage under mos-0974/0977 | none, T3 only |
| Honker | Builder, MVP T1 row 194 (agent lifecycle) | T3 session (Claude, Opus 5.5), started by Sage under mos-0974/0977 | none, T3 only |
| Gander | Builder, the human boundary across uids (P19 333, #1694) | T3 session (Codex, gpt-6.1-sol), started by Sage under mos-0977 | none, T3 only |
| Herb | Builder, a second gate lane (#1695) | T3 session (Codex, gpt-6.1-sol), started by Sage under mos-0977 | none, T3 only |
| Bushroot | Builder, retire the control board writer on 7331 (#1696) | T3 session (Claude, claude-haiku-5-5), started by Sage under mos-1008 | none, T3 only |
| Megavolt | Builder, MVP T1 item 6 (agent credentials and git identity, #1697) | T3 session (Claude, Opus 5.5), started by Sage under mos-0974/0977 | none, T3 only |
| Quackerjack | Builder, federation R5 and R2 (#414) | T3 session (Claude, claude-haiku-5-5), started by Sage under mos-1023 | none, T3 only |
| Gizmoduck | Federation design (#414) and builder of FED R1 | T3 session (Claude, Opus 5.5, thread 9312a896) | none, T3 only |
| Webby | Reviewer: Case 2 designs, rows 192 and 194 | T3 session (Claude, Opus 5.5, thread 03086006), started by Mos (mos-0981) | none, T3 only |
| Duckworth | Reviewer: federation designs, row 193 | T3 session (Claude, Opus 5.5, thread ffceafec), started by Mos (mos-0977) | none, T3 only |
| Della | Builder, email plan (Vikunja 460) and row 224 (C2-05b) | T3 session (Codex, gpt-6.1-sol, thread 66735a7f), started by Mos | none, T3 only |
| Scrooge | Builder of row 252 and reviewer of row 272 | T3 session (Claude, Opus 5.5, thread 629b6cd3), started by Mos | none, T3 only |
| Huey | Builder, row 272 (T1 sessions) | T3 session (Codex, gpt-6.1-sol, thread cabd45ca), started by Mos | none, T3 only |
| Louie | Builder and research, editor evaluation and row 174 | T3 session (Codex, gpt-6-luna, thread bfd13d49), started by Mos | none, T3 only |
| Ludwig | Builder and reviewer, post-v1 email PRD and row 258 (E01) | T3 session (Claude, Opus 5.5, thread 8615b2a6), started by Mos | none, T3 only |
| Sage | Project lead: coordination, review, integration; earlier DYOR strategy records retained | T3 session (Claude Code); Pi launcher `zai/glm-5.3:high` retained | `agents/sage/launch.sh` |
Each script supports `--check` and `--fresh`. Normal launches resume the agent's
own conversation; a first launch starts one. See each agent's README for
context inputs, authentication, and recovery details. Launch scripts can also
be invoked by absolute path from any directory. No assignment or model request
is submitted by the launcher itself.
The shared Pi helper supports `--provider NAME`, `--model ID`, and
`--thinking LEVEL` as per-launch overrides of the validated system defaults.
Filbert's wrapper appends the required provider, model and thinking flags so
its launch configuration remains fixed, including on resume. Use Filbert's
wrapper to select that configuration; a direct shared-helper invocation uses
its own supplied flags or the system defaults.
Any run that includes the webui suite, whether a seat's slot run or a landing
gate, sets `MOSAIC_REQUIRE_EDITOR_BUILD=1`, so a missing editor toolchain fails
the run instead of skipping the rebuild test. A worktree that links the
canonical `node_modules` also runs `npm ci --ignore-scripts --no-audit --no-fund`
in its own `packages/webui` first. The root install carries esbuild 0.28.1
through pi-coding-agent, and the rebuild needs the 0.28.2 that
`packages/webui/package-lock.json` pins (Vikunja 597, mos-1453).
All agents follow repository governance and current user direction. Team
leadership does not add deployment or push authority. Coordinate overlapping
work with Sage and preserve other sessions' changes.
Before 2026-09-26 Sage worked only on DYOR strategy and sat outside the
development queue. Jason then made Sage the project lead and Darkwing a
collaborating seat. A separate fleet Sage seat under `~/.mosaic` is being
decommissioned; it does not speak for this seat. Whether the DYOR strategy work
continues is Jason's call. Joe retains DYOR engineering.
-11
View File
@@ -1,11 +0,0 @@
# Beakley
Builder seat, Codex gpt-6.1-sol, started by Mos under Q245 (mos-1506). Owns row 217 (C2-06, handed over from Launchpad).
No launcher in this directory. The seat runs as a T3 thread (thread 88b97f65) and works in its own worktree. It has no
credentials of its own; it pushes only its own `beakley/*` branches through the repository credential helper (mos-0981),
never `refactor`, `main` or another seat's branch. Claude seats orchestrate and review (Q245). Registered by Sage on
2026-10-23 so the queue can name the seat as row owner (store.mjs isSeatDir).
Reports go to Sage's T3 thread (1ef1e4f8-3ead-4208-beca-38f9f1add079) and the next seat's, per the brief's Handoffs.
Mos's thread gets a copy only when Mos has a step (mos-1579, 2026-10-24).
-314
View File
@@ -1,314 +0,0 @@
# Row 217 — C2-06 citation guard, page store and runner retry
Owner: Beakley (88b97f65-97db-4f05-8c6e-081f92bc3501), assigned by Mos Q245.
Issue: #1718. Reviewer: Webby. Current branch: `beakley/row217-r2` (original `beakley/row217` preserved).
Brief: `docs/plans/2026-10-20_case2-rows.md`, C2-06.
Status: six whole suites green and M1–M5 killed under sage-4042/4043; ready for formal review. Landing scripts and integration remain Sage's.
## Plan and boundaries
Continue Launchpad's implementation from its handed-off ref. Complete the guard,
live reply limits and M11 writer fence, broker page store and check evidence,
CLI setter and runner retry/note behavior against the brief and design 5.2.
Supply acceptance tests and mutants, then request Sage's test slot and Webby's
review. Sage owns queue movement, gate and landing. Push only `beakley/*`, add
commits without amend/force or attribution lines. No credential reads.
## Standing rulings received from Sage (sage-3610)
- sage-3595: stub supporting scope until row 283 lands, then rebase onto it and
add real-fixture tests. Landing follows 283. `runtime.mjs` wiring approved.
- Check evidence belongs in an `action.allowed` event in the same transaction
as message insertion; no new event kind. Read the library at the cited commit.
- In library businesses only, JSON over 32,768 characters gets the
`request-too-large` retry. `role.claim` adds `library` only for a library business.
- Store `check.citations` entries with `scope`, `agent`, and `file` (the file's
last commit at the cited commit). On `thread.messages`, add `last` at the served
tip, one git call per distinct path per read. Scope/agent are broker evidence.
- sage-3599: optional `BusError.reason`, guard refusals only, capped at 300
characters. Add bus server/client to manifest. Reasonless envelopes stay
byte-identical.
- `render.mjs` obsolete notice hits belong to row 225.
- Node and tests require Sage CLEAR (sage-3610 supersedes the initial permission
for targeted new tests). Full suites, webui builds and gate require shared slot.
- Existing test edits require Mos GO through Sage; list every file and numstat
below before seeking that approval.
## Recovery and coordination
Initial base `45dca69f6`, clean. `scripts/mosaic queue next beakley` refused:
linked worktrees cannot run the queue. Reported to Sage/Mos in beakley-0001;
Sage will change ownership at a queue gap. No queue files changed.
Read AGENTS.md, agents/README.md, C2-06 brief, design 5.2 and the row 225 BUILD
contract. Requested Launchpad handoff in beakley-0002. Its header timestamp was
mistakenly typed ahead of the actual clock; sequence key identifies the message.
## Existing test changes
None yet. No tests or Node commands run.
## Handoff adopted and independent work (2026-10-23)
Fast-forwarded `beakley/row217` to Launchpad `e25ef0373` on `45dca69f6`.
The full original handoff/rulings remain at
`agents/launchpad/work/queue-217/BUILD.md`. No handoff code was rebuilt from scratch.
Implemented the runner path: role.claim library switch; exact fixed texts; note
inside JSON text with citations retained and no JSON clip; fixed texts defer
notes; one same-session retry for guard codes and both existing size caps;
retry fallback chosen from the second refusal; separate usage turn id for retry.
Outside library businesses the existing send path remains intact.
Added the CLI README usage paragraph. New acceptance tests cover library parsing,
real Git reachability/quotes/scope/origin, settings fallback, M11 direct writer
and serialization, CLI dispatch, broker insert/check atomicity, live settings,
page bounds/lifecycle, socket reasons, per-path last reads, request snapshots,
and runner RESULT/typed send_message, fixed texts, long JSON and unslop behavior.
These are authored evidence only: none has executed.
Static defects corrected locally: a missing projects object now means no library;
the guard sends its captured request arguments after the asynchronous check;
origin/last Git logs use literal pathspecs; a web quote can match any retained
fetch of the cited URL. Each has new-file regression coverage.
## Scope additions and cross-row contract
- `packages/library/src/reply-protocol.mjs`: shared GUARD_CODES/FIXED_TEXTS,
import-free, so runner imports do not reach host Git modules. guard.mjs
reexports them to preserve Launchpad's API. Fethry confirmed no renderer import
is needed when the renderer simply displays fixed texts as ordinary text.
- `packages/seat/src/sandbox.mjs`: one RUNNER_FILES entry for that pure file,
approved by sage-3640. No other mount change. The existing sandbox.test.mjs
import-closure test must pass unchanged; seat joins the gate list.
- Runtime hunks remain exactly Launchpad's import and library guard/limits/last
adapters, plus library.limits.set dispatch. Drift checks wait on 216 and 285.
- Status contract confirmed with Fethry (beakley-0004, fethry-0009): nested
`replyLimits: {requireCitation, citationsPerReply, fallback: [keys],
problem: "reply-limits-unreadable" | null}`. Check entries remain ordered
`scope/agent/file`, plus `last` on reads; no changed boolean.
## Verification and remaining acceptance
- Static `git diff --check`: clean so far. No Node, suite, test or mutant run.
- Existing test file edits: none (numstat 0/0 for every pre-existing test).
All new test files are listed in manifest.r1.sha256; no Mos approval requested.
- `mutants.py` is authored for isolated HEAD archives with green controls:
M1 remove both writer fences; M2 compare incoming human; M3 split evidence
from insert; M4 drop client reason. Not executed.
- Still required: Sage CLEAR for targeted runs; fix first-run failures; supporting
scope acceptance against row 283; 216 index/readLibrary fixture comparison;
285/runtime drift check; full library/business/bus/cli/harness/seat suites and
every scripts/test-*.sh on Sage's gate; mutant execution; Webby approval.
- Before in-review, perform brief's obsolete-code/key search and report outside
ownership hits to Sage. render.mjs/render.test.mjs hits belong to 225.
- No queue changes, protected branch pushes, gate claims or acceptance claims.
Static obsolete-code/key search completed: only packages/library/src/render.mjs:6 and packages/library/tests/render.test.mjs:58 match no-cited-answer; both belong to row 225 per standing ruling. No owned-path hit. Repeat before in-review after dependency changes.
## Webby early look 0939c0682 / webby-0249 and sage-3668/3670
This remains an untested draft. The follow-up adds tests only; production E4
changes wait for the held-lock regression's first RED under Sage CLEAR.
- E1: added an ordinary actor `mallory` that sets both `human` to itself and
`replyLimits`. The existing role/tester actors did not distinguish M2 because
the actor-shape exclusions rejected them independently of the human comparison.
M2 is still unrun; no kill claimed.
- E2: added a real bus event assertion for `agent: "acme/scribe"` from a file's
Mosaic-Agent trailer. The cited tip includes a later unrelated commit, so the
event must store the file commit rather than the library tip. thread.messages
must show `last === file` for that unchanged path. Supporting scope still waits
for row 283's real fixture, as ruled.
- E3: sage-3668 accepts direct writer.write tests under chief and tester actors
as substitutes for the brief's setter cases (brief lines 483-491 at base
45dca69f6). Correction to the early-look premise: organization.set DOES exist,
broker.mjs:4701/4709, but ORGANIZATION_KEYS excludes replyLimits; instances.set
also cannot carry it. Direct writes exercise the shared M11 boundary those
setters cannot reach with that input. Sage confirmed the accurate reason in
sage-3670; the unrelated actor case remains required.
- E4: traced readSyncState -> withLibraryLock -> library-sync-busy after five
seconds -> servedMirror catch-all -> null served -> misleading citation-invalid.
New real-flock/socket test first proves the cite valid, holds the lock, asserts
the exact citation-unavailable reason the agent receives, verifies no insert,
and checks fixed fallback delivery and recovery after unlock. Additional tests
distinguish malformed sync state from absent/new mirrors, and assert that the
actual runner retry request contains that reason. These tests are expected RED
until the fix. Planned production change: only an absent mirror or legitimate
empty state yields null; other failures become GuardError citation-unavailable;
bodies without path cites do not require the mirror lock. Add the code to
GUARD_CODES so the runner sends the agent that reason on its one retry. Per
sage-3670, existing four fallback bodies can remain only if that delivery is
verified. M5 restores catch-all behavior; authored, not run.
- E5: first-library-project selection is a Launchpad handoff implementation
choice, not a validated rule that a business can only have one library.
Cites into another library remain a limitation. No mapping/schema rule added.
- E6: the broker's full guard table now runs as both coder and research.
- E7: new citation-runtime.test.mjs starts the real runtime, reads limits from
the real organization file, then changes, corrupts and removes that fixture
file and checks library.status without replacing the library adapter.
No Node, tests or mutants ran. No test that predated row 217 changed.
## Webby follow-up 192049c98 / webby-0258
E1, E2, E6 and E7 closed statically; no executed acceptance claimed. E3 correction and E5 limitation accepted. E4 tests accepted statically; real RED then production fix/green remain on hold for Sage CLEAR, with supporting scope waiting on 283. F1: citation-helpers status now uses its mutable served value, matching guard/last after setServed instead of reporting the original fixture commit. Test-only fixture correction, unrun. manifest.r3.sha256 records the updated helper; no production or old-test changes.
## Round 2 / sage-4037 — 2026-10-24, Untested
New branch `beakley/row217-r2` from published `dde5b8496`, rebased exactly onto
`origin/refactor` at `e0c6142f3` (109 upstream commits since `45dca69f6`). The
published original branch is unchanged; no amend or force-push. The replayed
four commits are b9ef816ff, 7400509ba, a447880cb, 2655ec010. Full range-diff:
`rebase-r2.range-diff.txt`. Last commit is `=`, the first three are `!` from
conflict context/indentation and append-log placement described below.
Conflict resolutions:
- broker.mjs: retained landed grants.scope/grants.scope.set dispatch and added
library.limits.set to the organization verb dispatch; neither path removed.
- runtime.mjs: retained grants.scope.set and added library.limits.set alongside
it; retained query/sync wiring and all new base lifecycle behavior.
- organization.mjs: retained row 239's beforeWrite/revoked wrapper, placing both
M11 fences before validations/revocation as on the old candidate. A refused
reply-limit write cannot invoke beforeWrite.
- library/index.mjs: retained C2-05a buildIndex/query exports and added the guard
and reply-limits exports.
- BUILD-LOG.md and docs/SESSIONS.md: retained upstream appends followed by all
Beakley appends. Static byte-prefix checks prove the entire e0c6142f3 log
histories survive; all original Beakley entries also survive.
- business.mjs, cli README and sandbox.mjs auto-merged. Static diff against the
target confirms only this row's TOP_KEYS addition, README paragraph and one
import-free protocol mount; landed supporting scope and room-address mount
remain intact. runtime diff contains only the approved import, injected
guard/limits/last adapters and setter dispatch, now beside grants.scope.set.
Correction recorded honestly: the first unpublished rebase attempt used an
unbounded marker regex that removed code after a conflict. The diff stat caught
it immediately; aborted the rebase and repeated with bounded markers. No result
from that discarded attempt was pushed. The successful first replay matches the
original 589 insertions/20 deletions; no broad deletions remain.
Implemented E4 under sage-4037's explicit direction to make the product fix
while keeping all tests unrun. This supersedes the earlier planned RED-first
execution order; no RED or green has been observed. The existing regression
cases predate the fix. GUARD_CODES now includes citation-unavailable. Only a
mirror confirmed absent by lstat, or readSyncState's legitimate empty state,
yields no served commit. Other read/lock/metadata errors give the fixed safe
reason: "The library is busy or unavailable. Retry the answer when the library
is available." The runner receives it through BusError.reason and includes it
in its one retry request. The existing four fallback bodies remain. Plain,
web-only and fixed replies require no mirror read, so a busy mirror cannot
block the runner's fixed fallback. M5's real production anchor now exists.
Supporting scope after row 283 (`8d2856ee3`): added two broker tests using real
mapping/reader classification, not a scope stub. A path in both supporting and
playground refuses as canon; an agent-committed supporting path stores
scope=supporting, agent=acme/scribe and its file commit in message.checked.
C2-05a comparison: index-build.mjs builds its file map directly from readLibrary
files; indexFor calls that same reader at the requested commit. Added a real
fixture test comparing the index set, readLibrary set and libraryReader.lines
admission, including supporting, unmapped Markdown and .canvas. This comparison
is authored and statically traced, not executed; numerical results wait on CLEAR.
Current packet: manifest.r4.sha256, relative to e0c6142f3. No test file already
present at that base was edited. No Node, npm, tests, mutants or webui build run.
Ready for CLEAR after Lena's row 296. On CLEAR, install with npm ci
--ignore-scripts --no-audit --no-fund in THIS worktree root and packages/webui;
never link to canonical node_modules or run npm/rm in the canonical checkout.
Use short mktemp TMPDIR and timeout -k 10. Any old-test red goes to Sage before
an edit. Full green gate, mutants and Webby verdict remain outstanding.
Range-diff receipt rendering trims trailing whitespace on diff separator lines; no substantive range-diff content changed. This removes whitespace warnings caused by embedding raw diff output in a tracked text file.
Final base-to-candidate whitespace check found a trailing blank line inherited from Launchpad in limits.mjs; removed it without behavior changes. manifest.r5.sha256 supersedes r4 for the exact candidate file hashes.
## CLEAR sage-4042/4043 — execution started 2026-10-24
Queue beakley-217-start initially refused Lena's review-outcome lock twice;
same-op retry succeeded at rev3894 (briefed→in-progress). No queue bypass.
Short TMPDIR /mnt/storage/scratch/tmp/tNoueZ. Worktree-local npm ci at root
(128 packages) and packages/webui (2) completed; neither path was a symlink.
No npm/rm command ran in canonical. All test commands use timeout -k 10.
E4 current file: 3 pass/0 fail/0 skip. M5 isolated pre-fix stand-in: 1 pass,
2 expected assertion failures (citation-invalid instead of citation-unavailable),
exit1. Restored product bytes and checkout product hashes, then E4 restored
control 3/3. Receipts under run-r2/m5-red. M1 six-space anchors both match
exactly once on the eight-space lines.
Touched test files first run: 56 pass/1 fail, zero skip/cancel. The sole first-red
was NEW citation-runtime.test.mjs invalid-authority at Broker.checkBusiness:
validator output has unresolved roles and is not the host's broker projection.
Adjusted that new fixture only, following limits-runtime.test.mjs: minimal
empty-authority coder, validated real project mappings, real organization adapter
and systemFor(root). Single rerun 1/1, then all touched files 57/57. No base test
failure or edit. First log retained as run-r2/touched-first.log and reported to
Sage in beakley-0014. No production change was required.
The isolated mutant driver now wraps each node run in timeout -k 10, refuses a
symlinked root node_modules, restores mutated files in finally, verifies original
checkout product hashes after every mutant and reruns the restored control.
Optional name filters allow the E4 M5 RED before the full mutant pass. No
canonical dependency link is used; isolated copies link only this worktree's
own dependency install.
## Final slot results / 2026-10-24 10:21Z
All requested runs completed serially under sage-4042/4043 on source revision
`2d274a5b6`. Final receipt commits change only tracking and logs, not packages.
| Whole suite | Pass | Fail / skip / cancel |
| --- | ---: | --- |
| library | 142 | 0 / 0 / 0 |
| business | 270 | 0 / 0 / 0 |
| bus | 974 | 0 / 0 / 0 |
| cli | 988 | 0 / 0 / 0 |
| harness | 172 | 0 / 0 / 0 |
| seat | 218 | 0 / 0 / 0 |
Total 2,764 whole-suite tests. Touched files rerun 57/57. The unchanged
RUNNER_FILES import-closure test passed in seat (seat-suite.log:153). The only
first-run failure was the NEW runtime fixture already recorded above; no old
test failed and no test present at e0c6142f3 was edited.
M1–M5 all killed by the intended assertion, each with Node exit1, a green
control and green restored control. Driver exit0. M1 catches missing writer
refusals; M2 is killed by mallory's human swap; M3 detects one message left
behind after evidence failure; M4 detects the missing reason; M5 detects
citation-invalid in place of citation-unavailable on contention and bad state.
Every mutation was in a disposable HEAD archive. Each changed file was restored,
checkout product hashes checked after every mutant, and the restored control
rerun. All five final restored.sha256 certificates match current product files.
M5 also ran separately before the whole suites as the authorized pre-fix RED
stand-in; its held-lock and malformed-state assertions failed, then restored
E4 passed 3/3. Full raw controls/negatives/restores are retained.
Receipts: run-r2/summary.json and summary.txt; *-suite.log; touched-first.log,
touched-rerun.log; availability-green.log; runtime-fixture-retry.log; npm-root.log
and npm-webui.log; m1-anchors.txt; m5-red/ and mutants/. All are text, no binary
artifact added. All Node/mutant/npm runs used the short TMPDIR and timeout -k 10.
Both node_modules trees are local npm ci installs. No canonical npm/rm or
canonical dependency link. No further runtime/source changes after the tests.
Acceptance formerly waiting on dependencies is executed: real row283 supporting
canon refusal and supporting/agent event pass; the C2-05a readLibrary/index set
comparison passes; runtime readRaw live/corrupt/missing-file test passes; runner
retry request carries the E4 availability reason. The repeat obsolete-name
search finds only render.mjs:6 and render.test.mjs:58, owned by row225; no owned
hit. First-library selection remains the accepted E5 limitation. Webby-0274 N1
is a nonblocking wording limitation: configuration faults share the safe
busy-or-unavailable retry text. No policy/schema restriction was invented.
Current complete changed-file manifest over e0c6142f3..candidate is
candidate-manifest.sha256, excluding itself to avoid a circular hash. It includes
source, tests, records and evidence. Earlier numbered manifests are historical.
Formal Webby verdict and all scripts/test-*.sh at landing remain Sage's steps;
this is verified for review, not an integration/deployment claim.
Exact negative-test logs retain Node's whitespace-only diagnostic lines. Whole diff --check reports those 12 blank-line padding warnings in run-r2 logs; source/docs diff --check excluding captured run-r2 evidence is clean. No source whitespace problem or test failure is hidden by that exclusion.
-61
View File
@@ -1,61 +0,0 @@
# Row 217 round 2 — verified for review
Issue #1718, C2-06. Base e0c6142f3; branch beakley/row217-r2. Continued
Launchpad e25ef0373 through the preserved original dde5b8496 branch. Range-diff,
conflict resolutions and acceptance receipts are in BUILD.md. Tested source
revision: 2d274a5b6; the final commits add records/evidence only.
The broker checks agent-to-human citations before insertion, stores trusted
scope/agent/file evidence atomically with the message, and supplies per-path last
on thread reads. It keeps session-local fetched pages and reads reply settings
live through the M11 human-only writer. The runner preserves cited JSON, defers
notes on fixed replies, and retries once with the refusal code and safe reason.
E4 adds citation-unavailable for mirror/state/lock faults; uncited/web-only/fixed
bodies do not need the mirror lock. Supporting scope uses landed row283 code.
## Product and test scope
The package paths listed in candidate-manifest.sha256 are exactly this row's
base-to-candidate changes. Fourteen product paths cover library guard/limits/
protocol/exports; business validation/writer; bus broker/runtime/server/client;
CLI command/README; runner; and the single approved pure-protocol sandbox mount.
Nine test/helper/fixture paths are additions. No existing test is modified.
The mounted protocol stays import-free. Runtime retains the landed grant/query/
sync behavior; the writer retains beforeWrite/revoked handling and fences before
revocation. No SQL schema, event kind, role authority or credential change.
## Executed evidence
| Whole suite | Pass | Fail / skip / cancel |
| --- | ---: | --- |
| library | 142 | 0 / 0 / 0 |
| business | 270 | 0 / 0 / 0 |
| bus | 974 | 0 / 0 / 0 |
| cli | 988 | 0 / 0 / 0 |
| harness | 172 | 0 / 0 / 0 |
| seat | 218 | 0 / 0 / 0 |
Touched files 57/57; total whole suites 2,764. First run was 56/57 due solely
to a new runtime fixture missing the broker's resolved authority shape. Only
that new fixture changed; single and full touched reruns passed. No old test
failed. First-red evidence remains in run-r2/touched-first.log.
M1–M5 killed: missing M11 fences, incoming-human trust, split check transaction,
dropped client reason, and hidden library availability. Every negative run has
green control/restored runs and matching restored product certificates. M5 is
also the authorized E4 pre-fix RED stand-in. Supporting canon refusal, stored
supporting/agent evidence, the C2-05a index comparison, runtime raw settings and
agent-visible E4 retry reason all pass. The unchanged sandbox closure test passes.
Commands ran serially under Sage CLEAR with short TMPDIR and timeout -k 10.
Root/webui dependencies came from local npm ci, never canonical links. Full logs,
summary.json and mutant certificates are in run-r2/. The complete changed-file
manifest candidate-manifest.sha256 covers e0c6142f3..candidate, excluding itself;
its SHA256 is supplied with the pushed tip. Historical manifests stay untouched.
## Remaining boundaries
Sage runs every scripts/test-*.sh at landing and posts the formal Webby review
request. No merge/deployment performed. First-library selection remains the
accepted limitation; configuration faults share the safe unavailable reason
(Webby N1, nonblocking). Obsolete-name search hits only row225's render files.
@@ -1,80 +0,0 @@
74398edcedf16a3d856ab9e7ea900eb61a4df7f726f04b74b2ff123e7536e9c1 BUILD-LOG.md
87880c30c2be0180e6eec4dbe203f86e93ae2b1b4be44031b6a4903c6245a0ec agents/beakley/work/queue-217/BUILD.md
e7ecf624ccb2b918efb08001ae9da36380fe918f8c27db704860809b6792e6f2 agents/beakley/work/queue-217/MANIFEST.md
f4a042b5d6d393d2be62b107d7157ae51dd8fbf36f4360f5cd8cf07c03c74251 agents/beakley/work/queue-217/manifest.r1.sha256
53f051a4e416a34181ad9bcc7687f0d686274542b06d9758e2db7eb81e848811 agents/beakley/work/queue-217/manifest.r2.sha256
f96fccc566d01d70db32188574d0b5331ef3c90bce66558449a51b3f21da1b29 agents/beakley/work/queue-217/manifest.r3.sha256
faf8ec3e0ab458fe95120345ec93e077b0dcad9458c0f2683a20effb6ce3ed93 agents/beakley/work/queue-217/manifest.r4.sha256
a58f0e273b60508b95c833cbace26799d7aa935117fd1f9a27812fba65b93d54 agents/beakley/work/queue-217/manifest.r5.sha256
120b15db5eb75897095fe3d0759553e482365d58061d763beba7754a6e0d0734 agents/beakley/work/queue-217/manifest.r6.sha256
04a9d0585b5ae4818d87d67ac27f838355f1a6f586625a16cf01d91d7bb6d4a0 agents/beakley/work/queue-217/mutants.py
4a5f7b3373fd3ff46e2d6a5f7ee7106ad76a71c9034ca5a44b9e7340f0cc4cff agents/beakley/work/queue-217/rebase-r2.range-diff.txt
630070b0d682120ba64b382ab3b47b3fa3e8f0bcfc695ca09432d01d705fbcb3 agents/beakley/work/queue-217/run-r2/README.md
c4245272d5fc89c5fd3a9ea979e7d65727ea76e24364190af57556c59ad2fe34 agents/beakley/work/queue-217/run-r2/availability-green.log
700fff38b0a99ffdb44863f13015673cb459e5e645c5df46580eafbc407c95c8 agents/beakley/work/queue-217/run-r2/bus-suite.log
ef216d0af325c2b6647eb8405e5de70ebb5a0e7a28bb3d8fe3abc6a289a8d3d2 agents/beakley/work/queue-217/run-r2/business-suite.log
af173117f83359ebba62c5c00eadc749bb179551a8e290bcf55bbe39b1e7272c agents/beakley/work/queue-217/run-r2/cli-suite.log
a615f69ba60859e9d7817f3353b0d7c71e6c12eecc3ecf0f630d473be21e5fef agents/beakley/work/queue-217/run-r2/harness-suite.log
acaa08001101fd69a12cae377984e0d469c2cedc2affb5ccf9af426a72549dcc agents/beakley/work/queue-217/run-r2/library-suite.log
5414ce5b94e7ac7918ed64f62e5fd2b921d49c7e93cf73042b9187d014069934 agents/beakley/work/queue-217/run-r2/m1-anchors.txt
7d7138b25568adb98932bbe180a337fe6798c3eddcd7134ce7278c24fea48818 agents/beakley/work/queue-217/run-r2/m5-driver.log
de7dd716d3981fd9fa1d114882e60f9a83736cdb8f8e2096c3913c9f8620238a agents/beakley/work/queue-217/run-r2/m5-red/M5-hide-library-unavailable-control.log
6b98d3943d04d99f3ef212f11901d2257422410c477abec27ed3100a0d20dad9 agents/beakley/work/queue-217/run-r2/m5-red/M5-hide-library-unavailable-restored-green.log
a58f0e273b60508b95c833cbace26799d7aa935117fd1f9a27812fba65b93d54 agents/beakley/work/queue-217/run-r2/m5-red/M5-hide-library-unavailable-restored.sha256
d852a464fd624ce12d8d6bdc9800402639bb500a6d40c628cb836ca1bcf1e326 agents/beakley/work/queue-217/run-r2/m5-red/M5-hide-library-unavailable.log
7d7138b25568adb98932bbe180a337fe6798c3eddcd7134ce7278c24fea48818 agents/beakley/work/queue-217/run-r2/m5-red/summary.txt
1c405f1f15d2ce2db37b5809cdf5eaff68f18c99c5621e1c43262a289c5e35c4 agents/beakley/work/queue-217/run-r2/mutants-driver.log
c96487e87c1ae9e34a7222b04701c5efcce25fe201f03a0213b989f7cde2c376 agents/beakley/work/queue-217/run-r2/mutants/M1-writer-fence-control.log
8b294ecc057ad64ace7f520a1785b54df7df5a9eddf962813c3e5f8fa723ffd4 agents/beakley/work/queue-217/run-r2/mutants/M1-writer-fence-restored-green.log
120b15db5eb75897095fe3d0759553e482365d58061d763beba7754a6e0d0734 agents/beakley/work/queue-217/run-r2/mutants/M1-writer-fence-restored.sha256
be749486956e85a71f08107139613e09b62c53b58e8cc10e0fbe807e95d079a6 agents/beakley/work/queue-217/run-r2/mutants/M1-writer-fence.log
525da1cc780dfea1a66f95739d444516bd16271c7ec539d615012ec9c8e7c139 agents/beakley/work/queue-217/run-r2/mutants/M2-incoming-human-control.log
3546705980bb4a73295f16e42ab55f38c6adca9a5c53252264ae4ef66c595dfc agents/beakley/work/queue-217/run-r2/mutants/M2-incoming-human-restored-green.log
120b15db5eb75897095fe3d0759553e482365d58061d763beba7754a6e0d0734 agents/beakley/work/queue-217/run-r2/mutants/M2-incoming-human-restored.sha256
77352c22c459c516ff47ff1caa42fe9763fe201a04079646b0ccc0da6a145804 agents/beakley/work/queue-217/run-r2/mutants/M2-incoming-human.log
58de145ec0384de4f560b28dcfa76e98c384be5c771d6561fb1054f07ea8166b agents/beakley/work/queue-217/run-r2/mutants/M3-split-check-transaction-control.log
6a4cd0ef36b0d2318ef71c941ce300d215b6d2f87d0b4328c461ba53d812434c agents/beakley/work/queue-217/run-r2/mutants/M3-split-check-transaction-restored-green.log
120b15db5eb75897095fe3d0759553e482365d58061d763beba7754a6e0d0734 agents/beakley/work/queue-217/run-r2/mutants/M3-split-check-transaction-restored.sha256
2deb72f2d442f413fd06e205093f6fa3f955ec6ef707b7ca65b86be8c8883f9b agents/beakley/work/queue-217/run-r2/mutants/M3-split-check-transaction.log
31cac91f43c8b7ebe0431f27a038b0fcd554a12b232592747f3972213cfa192b agents/beakley/work/queue-217/run-r2/mutants/M4-drop-client-reason-control.log
e06c1da8dcd9e7eb013a4597b14369e296e21b812476bd6d88c7a7aa040d4065 agents/beakley/work/queue-217/run-r2/mutants/M4-drop-client-reason-restored-green.log
120b15db5eb75897095fe3d0759553e482365d58061d763beba7754a6e0d0734 agents/beakley/work/queue-217/run-r2/mutants/M4-drop-client-reason-restored.sha256
66d8f72df3bc0428624dab437cb04923ecab42055d29c6ffde43af98d47f32ae agents/beakley/work/queue-217/run-r2/mutants/M4-drop-client-reason.log
3f74fbd3b4297868b9bb637a7924739363470964873a4bd3dc2f5daf2d0e9c8a agents/beakley/work/queue-217/run-r2/mutants/M5-hide-library-unavailable-control.log
96d95a45d5326e614328531a7dadebce5d3ce70e40ec23dd49a66c1a676b45be agents/beakley/work/queue-217/run-r2/mutants/M5-hide-library-unavailable-restored-green.log
120b15db5eb75897095fe3d0759553e482365d58061d763beba7754a6e0d0734 agents/beakley/work/queue-217/run-r2/mutants/M5-hide-library-unavailable-restored.sha256
fa57189e9de99c4a76be27da3b857c07fc76706f7d0ee7409ba4efd43c3642b7 agents/beakley/work/queue-217/run-r2/mutants/M5-hide-library-unavailable.log
1c405f1f15d2ce2db37b5809cdf5eaff68f18c99c5621e1c43262a289c5e35c4 agents/beakley/work/queue-217/run-r2/mutants/summary.txt
862418d3d4124871ca5fcaf35e16c318a04e2888da83836751ddfea110efeb06 agents/beakley/work/queue-217/run-r2/npm-root.log
38b75d8bddacf8d227883a29dd8a10f87a7f02d8a95f3f8809cb966fc9c8cf7a agents/beakley/work/queue-217/run-r2/npm-webui.log
7f29b5a328fd6be61ebc4110a048305b50856810ab97a7798cd427924d74e8c9 agents/beakley/work/queue-217/run-r2/runtime-fixture-retry.log
3bd51fe222a61412e8285eb522a2f7b5c1b0b035f7dca0e9ff66190bd53e6706 agents/beakley/work/queue-217/run-r2/seat-suite.log
8b98c6ba76de46ddd858b4b95bae7bce2d1bf969edb85901ad8819e1280869a1 agents/beakley/work/queue-217/run-r2/summary.json
e374cb7ab28a46dd560b267b0fe6691b11c0c2fabd00087c4e49a02ab1bf8086 agents/beakley/work/queue-217/run-r2/summary.txt
ad2022c7ccdfa151e029eed92cd309369a97f197d9304775f6d2be3dc5f11080 agents/beakley/work/queue-217/run-r2/touched-first.log
e1fe5ebae1a36f196470848bf27b99c21d316c9236a1d1328d7bcaca0ee4d3e9 agents/beakley/work/queue-217/run-r2/touched-rerun.log
0c1b1f079b4b993e8d1aeb730d743e28696413eae8be6dd79731d749d1d45d0b agents/launchpad/work/queue-217/BUILD.md
76b0a5785f134c09cda677e8f5fb3e7454b39883c4a6f55360d9d277476fcd2c docs/SESSIONS.md
eeca81ab965f9e94f930ee5f51d16f019af6368bc6c3994895e204f7a54ec8d2 packages/bus/src/broker.mjs
ad3c686a089f67f3c89610937c6fc9b32367cea5d9735125d89bef042082d4e8 packages/bus/src/client.mjs
36b05dd3119e5929211aa1cc5d45c5043f5a1c34567ddc7cac8f002835d44abe packages/bus/src/runtime.mjs
66b26d131a19f4f411686427274936850c1ff0aed11e9b281ae4aadcf4b289fc packages/bus/src/server.mjs
cdd0304ec25ef1ad3e31c52502fa46f2c80bd77c8d3c2e13f8ed4b5328f342c9 packages/bus/tests/citation-availability.test.mjs
2e05074cd9d15d810103658af3858161cee2af78b0a2e1ba910222fab3e84401 packages/bus/tests/citation-guard.test.mjs
2c7a2102e2e0244876e41b664f4f706baefe3375100b956655551db1230f5da3 packages/bus/tests/citation-helpers.mjs
9768b6dc5ae078c5cc4f76473097287b74c5bc5853d39e1f57f153e646f861af packages/bus/tests/citation-runtime.test.mjs
abaeac64f2c3bf8ba83c9a4488edd9105c4707a6564560c5333d5421445653af packages/business/src/business.mjs
3a6044de5d1ca2cc35c5285b460c3e402b4274837e5d88b97f489797f6004903 packages/business/src/organization.mjs
4d2eb11beaa80175e524af1b95c81e7164990fba1d3e1754f5ba06eee390a14f packages/business/tests/reply-limits.test.mjs
a2bb98734bcc2556f8b2168f0faf8a89f7064c3f0aa49feb7d1975d596192f09 packages/cli/README.md
2f291a71f490f2741edada7a3e3788500f8976a08eb8ab1411f6c5982f778260 packages/cli/src/limits.mjs
f38af2d46d5f5f6388f599912507b94b87a0bf9dcc2104bb2187c38ee35118d5 packages/cli/tests/reply-limits.test.mjs
6ad72b4245e0a66e32725941900c1ece64c2e5de2fb73d65c8e042b4f3a691a6 packages/harness/src/runner.mjs
a5ef1b65230239a7baf6d0e8f2b8a51c0516348c7c4339a55b3f0a1a6ff531ba packages/harness/tests/citation-runner.test.mjs
330bc71bf6c7e64d3ddb70440903d2d9acf7878d44a49d7e30c2352ee4c807ec packages/harness/tests/fixtures/citation-adapter.mjs
f710d9600a17f6e2989a289cfe84e58f161d86c7306605946ce05fa71b364eb2 packages/library/src/guard.mjs
c0d630798914e300e461c247340533328e97119e54909c6a9406340e61fed8b7 packages/library/src/index.mjs
98ef45ed61144aaea44d8aea1ac43082b6d340297e46846d01772da38728e530 packages/library/src/limits.mjs
7b46f47b5e9d6b554b5d39bce2cd95c4610f5f35b8ab8fdc5a2864b3214be809 packages/library/src/reply-protocol.mjs
406146ebbce3710f308243b684a1c17e7626c1b65a4468489364317e31537a48 packages/library/tests/guard.test.mjs
39c8e6c8250a13fa43015fb2c407195e30ee642f729a9f6a644c38b4ea758a72 packages/seat/src/sandbox.mjs
@@ -1,21 +0,0 @@
68c05644d29188b897e2d4695d8e7025e143d424d69a91bc07bc950f589d34bf packages/bus/src/broker.mjs
ad3c686a089f67f3c89610937c6fc9b32367cea5d9735125d89bef042082d4e8 packages/bus/src/client.mjs
49e01e5e73cc3e830ad48a1b6b13fe4d06a38950f17847dc049b75209d6d3f0a packages/bus/src/runtime.mjs
66b26d131a19f4f411686427274936850c1ff0aed11e9b281ae4aadcf4b289fc packages/bus/src/server.mjs
29114051a9bc5271e48978a9552d64b51b0ac4810f94a1f98940bf617b148df8 packages/bus/tests/citation-guard.test.mjs
dc2d5836f10f591fc174aaf9587a3bff793b24ac29efe9ab68c6a9243d1d1c2c packages/bus/tests/citation-helpers.mjs
825da818ba3cf45a4837f0f15a9c2cdba55a3d0bbb4479d55236f35799427c6f packages/business/src/business.mjs
dbd79a4dfc926620d034b540f98f39336d81e4c79f214424c3cf19250c1d1f8d packages/business/src/organization.mjs
bec04a894bc2af000548283ed7719e4de1c6d56688f42238a113390e9b2d3fbe packages/business/tests/reply-limits.test.mjs
1f1bea250f694a2aae9b9dc856b3c3424ceca153ccf826c99ccb98e6ea9cd394 packages/cli/README.md
2f291a71f490f2741edada7a3e3788500f8976a08eb8ab1411f6c5982f778260 packages/cli/src/limits.mjs
f38af2d46d5f5f6388f599912507b94b87a0bf9dcc2104bb2187c38ee35118d5 packages/cli/tests/reply-limits.test.mjs
6ad72b4245e0a66e32725941900c1ece64c2e5de2fb73d65c8e042b4f3a691a6 packages/harness/src/runner.mjs
ec7ef0cbf493217eb9229895cae2fe7ef603f41913840e59a73220df387c81ca packages/harness/tests/citation-runner.test.mjs
330bc71bf6c7e64d3ddb70440903d2d9acf7878d44a49d7e30c2352ee4c807ec packages/harness/tests/fixtures/citation-adapter.mjs
0365114cf5773cbaa9fba196fbd1e773b2ec5ad2300c40231c357ca58884b9e3 packages/library/src/guard.mjs
aaa8f7ba60a729a88a6ef57b3d5ff5a69bcf0e17b60e7db51a8dc5a697627b6c packages/library/src/index.mjs
3e04fa25a64334d33ffbec704205b32cd01992f2d341e908f933a345199beee0 packages/library/src/limits.mjs
c9e682eff87e822647921288d7fce0ebdc7b09f0a6dfdd6528f10249ae26e81b packages/library/src/reply-protocol.mjs
dd056409712113eb9c1b70e29b21022f5b30df6ffbfb2658e293edd6ec7195c7 packages/library/tests/guard.test.mjs
2f3ec99129d16394d4458e252b9cba4e38ff66cd9393e3889f8afc3140e15a8e packages/seat/src/sandbox.mjs
@@ -1,23 +0,0 @@
68c05644d29188b897e2d4695d8e7025e143d424d69a91bc07bc950f589d34bf packages/bus/src/broker.mjs
ad3c686a089f67f3c89610937c6fc9b32367cea5d9735125d89bef042082d4e8 packages/bus/src/client.mjs
49e01e5e73cc3e830ad48a1b6b13fe4d06a38950f17847dc049b75209d6d3f0a packages/bus/src/runtime.mjs
66b26d131a19f4f411686427274936850c1ff0aed11e9b281ae4aadcf4b289fc packages/bus/src/server.mjs
cdd0304ec25ef1ad3e31c52502fa46f2c80bd77c8d3c2e13f8ed4b5328f342c9 packages/bus/tests/citation-availability.test.mjs
8dc344b8a905c58d544b031ca84adb7eb869d9de88eb8e6b0fc1d9190702a38a packages/bus/tests/citation-guard.test.mjs
62d8a55945d4b700e22c8c49b6420a5e25719d266901a2ad20c72514735e65e9 packages/bus/tests/citation-helpers.mjs
168dcac99d9bfdfdf5ff0eaa2c0fff91595b351b4d0092dc299532c9c32869f0 packages/bus/tests/citation-runtime.test.mjs
825da818ba3cf45a4837f0f15a9c2cdba55a3d0bbb4479d55236f35799427c6f packages/business/src/business.mjs
dbd79a4dfc926620d034b540f98f39336d81e4c79f214424c3cf19250c1d1f8d packages/business/src/organization.mjs
4d2eb11beaa80175e524af1b95c81e7164990fba1d3e1754f5ba06eee390a14f packages/business/tests/reply-limits.test.mjs
1f1bea250f694a2aae9b9dc856b3c3424ceca153ccf826c99ccb98e6ea9cd394 packages/cli/README.md
2f291a71f490f2741edada7a3e3788500f8976a08eb8ab1411f6c5982f778260 packages/cli/src/limits.mjs
f38af2d46d5f5f6388f599912507b94b87a0bf9dcc2104bb2187c38ee35118d5 packages/cli/tests/reply-limits.test.mjs
6ad72b4245e0a66e32725941900c1ece64c2e5de2fb73d65c8e042b4f3a691a6 packages/harness/src/runner.mjs
a5ef1b65230239a7baf6d0e8f2b8a51c0516348c7c4339a55b3f0a1a6ff531ba packages/harness/tests/citation-runner.test.mjs
330bc71bf6c7e64d3ddb70440903d2d9acf7878d44a49d7e30c2352ee4c807ec packages/harness/tests/fixtures/citation-adapter.mjs
0365114cf5773cbaa9fba196fbd1e773b2ec5ad2300c40231c357ca58884b9e3 packages/library/src/guard.mjs
aaa8f7ba60a729a88a6ef57b3d5ff5a69bcf0e17b60e7db51a8dc5a697627b6c packages/library/src/index.mjs
3e04fa25a64334d33ffbec704205b32cd01992f2d341e908f933a345199beee0 packages/library/src/limits.mjs
c9e682eff87e822647921288d7fce0ebdc7b09f0a6dfdd6528f10249ae26e81b packages/library/src/reply-protocol.mjs
dd056409712113eb9c1b70e29b21022f5b30df6ffbfb2658e293edd6ec7195c7 packages/library/tests/guard.test.mjs
2f3ec99129d16394d4458e252b9cba4e38ff66cd9393e3889f8afc3140e15a8e packages/seat/src/sandbox.mjs
@@ -1,23 +0,0 @@
68c05644d29188b897e2d4695d8e7025e143d424d69a91bc07bc950f589d34bf packages/bus/src/broker.mjs
ad3c686a089f67f3c89610937c6fc9b32367cea5d9735125d89bef042082d4e8 packages/bus/src/client.mjs
49e01e5e73cc3e830ad48a1b6b13fe4d06a38950f17847dc049b75209d6d3f0a packages/bus/src/runtime.mjs
66b26d131a19f4f411686427274936850c1ff0aed11e9b281ae4aadcf4b289fc packages/bus/src/server.mjs
cdd0304ec25ef1ad3e31c52502fa46f2c80bd77c8d3c2e13f8ed4b5328f342c9 packages/bus/tests/citation-availability.test.mjs
8dc344b8a905c58d544b031ca84adb7eb869d9de88eb8e6b0fc1d9190702a38a packages/bus/tests/citation-guard.test.mjs
8a2d4b636f8d4f926c484254c33ecf7b7e4722acef3250d2730593984d5ac06b packages/bus/tests/citation-helpers.mjs
168dcac99d9bfdfdf5ff0eaa2c0fff91595b351b4d0092dc299532c9c32869f0 packages/bus/tests/citation-runtime.test.mjs
825da818ba3cf45a4837f0f15a9c2cdba55a3d0bbb4479d55236f35799427c6f packages/business/src/business.mjs
dbd79a4dfc926620d034b540f98f39336d81e4c79f214424c3cf19250c1d1f8d packages/business/src/organization.mjs
4d2eb11beaa80175e524af1b95c81e7164990fba1d3e1754f5ba06eee390a14f packages/business/tests/reply-limits.test.mjs
1f1bea250f694a2aae9b9dc856b3c3424ceca153ccf826c99ccb98e6ea9cd394 packages/cli/README.md
2f291a71f490f2741edada7a3e3788500f8976a08eb8ab1411f6c5982f778260 packages/cli/src/limits.mjs
f38af2d46d5f5f6388f599912507b94b87a0bf9dcc2104bb2187c38ee35118d5 packages/cli/tests/reply-limits.test.mjs
6ad72b4245e0a66e32725941900c1ece64c2e5de2fb73d65c8e042b4f3a691a6 packages/harness/src/runner.mjs
a5ef1b65230239a7baf6d0e8f2b8a51c0516348c7c4339a55b3f0a1a6ff531ba packages/harness/tests/citation-runner.test.mjs
330bc71bf6c7e64d3ddb70440903d2d9acf7878d44a49d7e30c2352ee4c807ec packages/harness/tests/fixtures/citation-adapter.mjs
0365114cf5773cbaa9fba196fbd1e773b2ec5ad2300c40231c357ca58884b9e3 packages/library/src/guard.mjs
aaa8f7ba60a729a88a6ef57b3d5ff5a69bcf0e17b60e7db51a8dc5a697627b6c packages/library/src/index.mjs
3e04fa25a64334d33ffbec704205b32cd01992f2d341e908f933a345199beee0 packages/library/src/limits.mjs
c9e682eff87e822647921288d7fce0ebdc7b09f0a6dfdd6528f10249ae26e81b packages/library/src/reply-protocol.mjs
dd056409712113eb9c1b70e29b21022f5b30df6ffbfb2658e293edd6ec7195c7 packages/library/tests/guard.test.mjs
2f3ec99129d16394d4458e252b9cba4e38ff66cd9393e3889f8afc3140e15a8e packages/seat/src/sandbox.mjs
@@ -1,23 +0,0 @@
eeca81ab965f9e94f930ee5f51d16f019af6368bc6c3994895e204f7a54ec8d2 packages/bus/src/broker.mjs
ad3c686a089f67f3c89610937c6fc9b32367cea5d9735125d89bef042082d4e8 packages/bus/src/client.mjs
36b05dd3119e5929211aa1cc5d45c5043f5a1c34567ddc7cac8f002835d44abe packages/bus/src/runtime.mjs
66b26d131a19f4f411686427274936850c1ff0aed11e9b281ae4aadcf4b289fc packages/bus/src/server.mjs
cdd0304ec25ef1ad3e31c52502fa46f2c80bd77c8d3c2e13f8ed4b5328f342c9 packages/bus/tests/citation-availability.test.mjs
2e05074cd9d15d810103658af3858161cee2af78b0a2e1ba910222fab3e84401 packages/bus/tests/citation-guard.test.mjs
2c7a2102e2e0244876e41b664f4f706baefe3375100b956655551db1230f5da3 packages/bus/tests/citation-helpers.mjs
168dcac99d9bfdfdf5ff0eaa2c0fff91595b351b4d0092dc299532c9c32869f0 packages/bus/tests/citation-runtime.test.mjs
abaeac64f2c3bf8ba83c9a4488edd9105c4707a6564560c5333d5421445653af packages/business/src/business.mjs
3a6044de5d1ca2cc35c5285b460c3e402b4274837e5d88b97f489797f6004903 packages/business/src/organization.mjs
4d2eb11beaa80175e524af1b95c81e7164990fba1d3e1754f5ba06eee390a14f packages/business/tests/reply-limits.test.mjs
a2bb98734bcc2556f8b2168f0faf8a89f7064c3f0aa49feb7d1975d596192f09 packages/cli/README.md
2f291a71f490f2741edada7a3e3788500f8976a08eb8ab1411f6c5982f778260 packages/cli/src/limits.mjs
f38af2d46d5f5f6388f599912507b94b87a0bf9dcc2104bb2187c38ee35118d5 packages/cli/tests/reply-limits.test.mjs
6ad72b4245e0a66e32725941900c1ece64c2e5de2fb73d65c8e042b4f3a691a6 packages/harness/src/runner.mjs
a5ef1b65230239a7baf6d0e8f2b8a51c0516348c7c4339a55b3f0a1a6ff531ba packages/harness/tests/citation-runner.test.mjs
330bc71bf6c7e64d3ddb70440903d2d9acf7878d44a49d7e30c2352ee4c807ec packages/harness/tests/fixtures/citation-adapter.mjs
f710d9600a17f6e2989a289cfe84e58f161d86c7306605946ce05fa71b364eb2 packages/library/src/guard.mjs
c0d630798914e300e461c247340533328e97119e54909c6a9406340e61fed8b7 packages/library/src/index.mjs
3e04fa25a64334d33ffbec704205b32cd01992f2d341e908f933a345199beee0 packages/library/src/limits.mjs
7b46f47b5e9d6b554b5d39bce2cd95c4610f5f35b8ab8fdc5a2864b3214be809 packages/library/src/reply-protocol.mjs
406146ebbce3710f308243b684a1c17e7626c1b65a4468489364317e31537a48 packages/library/tests/guard.test.mjs
39c8e6c8250a13fa43015fb2c407195e30ee642f729a9f6a644c38b4ea758a72 packages/seat/src/sandbox.mjs
@@ -1,23 +0,0 @@
eeca81ab965f9e94f930ee5f51d16f019af6368bc6c3994895e204f7a54ec8d2 packages/bus/src/broker.mjs
ad3c686a089f67f3c89610937c6fc9b32367cea5d9735125d89bef042082d4e8 packages/bus/src/client.mjs
36b05dd3119e5929211aa1cc5d45c5043f5a1c34567ddc7cac8f002835d44abe packages/bus/src/runtime.mjs
66b26d131a19f4f411686427274936850c1ff0aed11e9b281ae4aadcf4b289fc packages/bus/src/server.mjs
cdd0304ec25ef1ad3e31c52502fa46f2c80bd77c8d3c2e13f8ed4b5328f342c9 packages/bus/tests/citation-availability.test.mjs
2e05074cd9d15d810103658af3858161cee2af78b0a2e1ba910222fab3e84401 packages/bus/tests/citation-guard.test.mjs
2c7a2102e2e0244876e41b664f4f706baefe3375100b956655551db1230f5da3 packages/bus/tests/citation-helpers.mjs
168dcac99d9bfdfdf5ff0eaa2c0fff91595b351b4d0092dc299532c9c32869f0 packages/bus/tests/citation-runtime.test.mjs
abaeac64f2c3bf8ba83c9a4488edd9105c4707a6564560c5333d5421445653af packages/business/src/business.mjs
3a6044de5d1ca2cc35c5285b460c3e402b4274837e5d88b97f489797f6004903 packages/business/src/organization.mjs
4d2eb11beaa80175e524af1b95c81e7164990fba1d3e1754f5ba06eee390a14f packages/business/tests/reply-limits.test.mjs
a2bb98734bcc2556f8b2168f0faf8a89f7064c3f0aa49feb7d1975d596192f09 packages/cli/README.md
2f291a71f490f2741edada7a3e3788500f8976a08eb8ab1411f6c5982f778260 packages/cli/src/limits.mjs
f38af2d46d5f5f6388f599912507b94b87a0bf9dcc2104bb2187c38ee35118d5 packages/cli/tests/reply-limits.test.mjs
6ad72b4245e0a66e32725941900c1ece64c2e5de2fb73d65c8e042b4f3a691a6 packages/harness/src/runner.mjs
a5ef1b65230239a7baf6d0e8f2b8a51c0516348c7c4339a55b3f0a1a6ff531ba packages/harness/tests/citation-runner.test.mjs
330bc71bf6c7e64d3ddb70440903d2d9acf7878d44a49d7e30c2352ee4c807ec packages/harness/tests/fixtures/citation-adapter.mjs
f710d9600a17f6e2989a289cfe84e58f161d86c7306605946ce05fa71b364eb2 packages/library/src/guard.mjs
c0d630798914e300e461c247340533328e97119e54909c6a9406340e61fed8b7 packages/library/src/index.mjs
98ef45ed61144aaea44d8aea1ac43082b6d340297e46846d01772da38728e530 packages/library/src/limits.mjs
7b46f47b5e9d6b554b5d39bce2cd95c4610f5f35b8ab8fdc5a2864b3214be809 packages/library/src/reply-protocol.mjs
406146ebbce3710f308243b684a1c17e7626c1b65a4468489364317e31537a48 packages/library/tests/guard.test.mjs
39c8e6c8250a13fa43015fb2c407195e30ee642f729a9f6a644c38b4ea758a72 packages/seat/src/sandbox.mjs
@@ -1,23 +0,0 @@
eeca81ab965f9e94f930ee5f51d16f019af6368bc6c3994895e204f7a54ec8d2 packages/bus/src/broker.mjs
ad3c686a089f67f3c89610937c6fc9b32367cea5d9735125d89bef042082d4e8 packages/bus/src/client.mjs
36b05dd3119e5929211aa1cc5d45c5043f5a1c34567ddc7cac8f002835d44abe packages/bus/src/runtime.mjs
66b26d131a19f4f411686427274936850c1ff0aed11e9b281ae4aadcf4b289fc packages/bus/src/server.mjs
cdd0304ec25ef1ad3e31c52502fa46f2c80bd77c8d3c2e13f8ed4b5328f342c9 packages/bus/tests/citation-availability.test.mjs
2e05074cd9d15d810103658af3858161cee2af78b0a2e1ba910222fab3e84401 packages/bus/tests/citation-guard.test.mjs
2c7a2102e2e0244876e41b664f4f706baefe3375100b956655551db1230f5da3 packages/bus/tests/citation-helpers.mjs
9768b6dc5ae078c5cc4f76473097287b74c5bc5853d39e1f57f153e646f861af packages/bus/tests/citation-runtime.test.mjs
abaeac64f2c3bf8ba83c9a4488edd9105c4707a6564560c5333d5421445653af packages/business/src/business.mjs
3a6044de5d1ca2cc35c5285b460c3e402b4274837e5d88b97f489797f6004903 packages/business/src/organization.mjs
4d2eb11beaa80175e524af1b95c81e7164990fba1d3e1754f5ba06eee390a14f packages/business/tests/reply-limits.test.mjs
a2bb98734bcc2556f8b2168f0faf8a89f7064c3f0aa49feb7d1975d596192f09 packages/cli/README.md
2f291a71f490f2741edada7a3e3788500f8976a08eb8ab1411f6c5982f778260 packages/cli/src/limits.mjs
f38af2d46d5f5f6388f599912507b94b87a0bf9dcc2104bb2187c38ee35118d5 packages/cli/tests/reply-limits.test.mjs
6ad72b4245e0a66e32725941900c1ece64c2e5de2fb73d65c8e042b4f3a691a6 packages/harness/src/runner.mjs
a5ef1b65230239a7baf6d0e8f2b8a51c0516348c7c4339a55b3f0a1a6ff531ba packages/harness/tests/citation-runner.test.mjs
330bc71bf6c7e64d3ddb70440903d2d9acf7878d44a49d7e30c2352ee4c807ec packages/harness/tests/fixtures/citation-adapter.mjs
f710d9600a17f6e2989a289cfe84e58f161d86c7306605946ce05fa71b364eb2 packages/library/src/guard.mjs
c0d630798914e300e461c247340533328e97119e54909c6a9406340e61fed8b7 packages/library/src/index.mjs
98ef45ed61144aaea44d8aea1ac43082b6d340297e46846d01772da38728e530 packages/library/src/limits.mjs
7b46f47b5e9d6b554b5d39bce2cd95c4610f5f35b8ab8fdc5a2864b3214be809 packages/library/src/reply-protocol.mjs
406146ebbce3710f308243b684a1c17e7626c1b65a4468489364317e31537a48 packages/library/tests/guard.test.mjs
39c8e6c8250a13fa43015fb2c407195e30ee642f729a9f6a644c38b4ea758a72 packages/seat/src/sandbox.mjs
-90
View File
@@ -1,90 +0,0 @@
#!/usr/bin/env python3
"""Run only on Sage CLEAR. Mutate isolated HEAD archives; never edit the checkout.
A green control run is required before each negative result counts as a kill.
Usage: python3 agents/beakley/work/queue-217/mutants.py OUTPUT_DIRECTORY
"""
from pathlib import Path
import io
import hashlib
import os
import subprocess
import sys
import tarfile
import tempfile
ROOT = Path(__file__).resolve().parents[4]
OUT = Path(sys.argv[1]).resolve()
OUT.mkdir(parents=True, exist_ok=True)
WRITER = "packages/business/src/organization.mjs"
BROKER = "packages/bus/src/broker.mjs"
CLIENT = "packages/bus/src/client.mjs"
ATOMIC = "if (check) this.#event(s, 'action.allowed', { action: 'message.checked', message: mid, check }, mid, checkEventId(mid));"
REENTER = "return this.#reenter(cap, s, { verb: 'message.send', args }, check);"
SPLIT = """const result = this.#reenter(cap, s, { verb: 'message.send', args }, check);
if (check) this.#store.transaction(() => this.#event(s, 'action.allowed', { action: 'message.checked', message: result.id, check }, result.id, checkEventId(result.id)));
return result;"""
MUTANTS = [
("M1-writer-fence", [(WRITER, " replyLimitsFence(old, document, actor);", ""),
(WRITER, " replyLimitsFence(old, written, actor);", "")],
["packages/business/tests/reply-limits.test.mjs"]),
("M2-incoming-human", [(WRITER, "actor === old.human", "actor === document.human")],
["packages/business/tests/reply-limits.test.mjs"]),
("M3-split-check-transaction", [(BROKER, ATOMIC, ""), (BROKER, REENTER, SPLIT)],
["packages/bus/tests/citation-guard.test.mjs"]),
("M5-hide-library-unavailable", [("packages/library/src/guard.mjs",
"refuse('citation-unavailable', 'The library is busy or unavailable. Retry the answer when the library is available.');",
"served = null;")], ["packages/bus/tests/citation-availability.test.mjs"]),
("M4-drop-client-reason", [(CLIENT, "new BusError(r.error, typeof r.reason === 'string' ? r.reason.slice(0, 300) : undefined)", "new BusError(r.error)")],
["packages/bus/tests/citation-guard.test.mjs"]),
]
archive = subprocess.check_output(["git", "archive", "HEAD", "packages", "roles", "scripts", "tools", "docs", "package.json", "RELEASE"], cwd=ROOT)
summary = []
selected = set(sys.argv[2:])
product_files = [line.split(' ', 1)[1] for line in (ROOT / 'agents/beakley/work/queue-217/manifest.r5.sha256').read_text().splitlines()]
def hashes(base, files):
return {file: hashlib.sha256((base / file).read_bytes()).hexdigest() for file in files}
original_products = hashes(ROOT, product_files)
for name, changes, tests in MUTANTS:
if selected and name not in selected:
continue
with tempfile.TemporaryDirectory(prefix="row217-mutant-") as directory:
work = Path(directory)
with tarfile.open(fileobj=io.BytesIO(archive)) as source:
source.extractall(work, filter="data")
modules = ROOT / "node_modules"
if modules.is_symlink():
raise SystemExit('root node_modules must be a local install, never a canonical link')
if modules.exists():
os.symlink(modules.resolve(), work / "node_modules", target_is_directory=True)
cmd = ["timeout", "-k", "10", "120", "node", "--test", *tests]
with (OUT / f"{name}-control.log").open("w") as log:
control = subprocess.run(cmd, cwd=work, stdout=log, stderr=subprocess.STDOUT, timeout=120)
if control.returncode:
raise SystemExit(f"{name}: control RED, no mutant result claimed")
originals = {file: (work / file).read_bytes() for file, _, _ in changes}
try:
for file, before, after in changes:
path = work / file
text = path.read_text()
if text.count(before) != 1:
raise SystemExit(f"{name}: expected exactly one mutation anchor in {file}")
path.write_text(text.replace(before, after))
with (OUT / f"{name}.log").open("w") as log:
mutant = subprocess.run(cmd, cwd=work, stdout=log, stderr=subprocess.STDOUT, timeout=140)
if mutant.returncode != 1:
raise SystemExit(f"{name}: expected assertion failure exit 1, got {mutant.returncode}")
finally:
for file, content in originals.items():
(work / file).write_bytes(content)
assert all((work / file).read_bytes() == content for file, content in originals.items())
assert hashes(ROOT, product_files) == original_products, 'checkout product hashes changed'
(OUT / f"{name}-restored.sha256").write_text(''.join(f'{digest} {file}\n' for file, digest in sorted(original_products.items())))
with (OUT / f"{name}-restored-green.log").open("w") as log:
restored = subprocess.run(cmd, cwd=work, stdout=log, stderr=subprocess.STDOUT, timeout=140)
if restored.returncode:
raise SystemExit(f"{name}: restored control RED")
summary.append(f"{name}: killed (control green, mutant exit {mutant.returncode}, hashes restored, restored green)")
(OUT / "summary.txt").write_text("\n".join(summary) + "\n")
print(summary[-1], flush=True)
@@ -1,112 +0,0 @@
1: e25ef0373 ! 1: b9ef816ff launchpad: row 217 C2-06 work in progress, UNTESTED, handed to Beakley (mos-1500)
@@ packages/bus/src/broker.mjs: export class Broker {
if (CREDENTIAL_VERBS.includes(request.verb)) return this.#requestCredential(s, request.verb, structuredClone(args));
if (request.verb === 'instance.hire' || request.verb === 'instance.fire')
return this.#chiefLifecycle(s, request.verb, structuredClone(args));
+ if (request.verb === 'grants.scope' || request.verb === 'grants.scope.set')
+ return this.#grantScopeVerb(s, request.verb, structuredClone(args));
- if (["limits", "limits.set", "organization.set", "organization.revision", "plugins", "plugins.set", "instances", "instances.set", "routes", "routes.set", "veto.set"].includes(request.verb)) {
+ if (["limits", "limits.set", "organization.set", "organization.revision", "plugins", "plugins.set", "instances", "instances.set", "routes", "routes.set", "veto.set", "library.limits.set"].includes(request.verb)) {
// Row 123 (#1617, REQ-COS-1, REQ-LIMIT-1): organization.set is limits.set for a role whose
@@ packages/bus/src/runtime.mjs: export async function startBroker({
project: {
readSpec: context => projectModule.readSpec({ ...context, dataRoot }),
@@ packages/bus/src/runtime.mjs: export async function startBroker({
- else if(verb==='plugins.set')result=plugins.set(id,args,actor);
- // Row 194 (#1692, V6): the human's keep and noHire lists, through the instance writer.
else if(verb==='veto.set')result=instances.veto(id,args,actor);
+ // Row 298: the human's grant scope, through the instance writer.
+ else if(verb==='grants.scope.set')result=instances.grantScope(id,args,actor);
+ // C2-06 M11: the human's replyLimits, through the organization writer's fence.
+ else if(verb==='library.limits.set')result=setReplyLimits(organizationWriter({dir:organization.dir,rolesDir:organization.rolesDir}),id,args,actor);
// Row 194 (D2.1, D2.2): the chief's hire and fire, with the reason in the change context.
@@ packages/business/src/organization.mjs: export function organizationWriter({ dir
const parent = join(dir, "businesses");
directory(evidence);
@@ packages/business/src/organization.mjs: export function organizationWriter({ dir, rolesDir, barrier = () => {} }) {
- // mapping, including library playgrounds and hybrid universes.
- if (canonicalJson(document?.projects) !== canonicalJson(old.projects))
- fail('organization-projects-protected');
-+ replyLimitsFence(old, document, actor);
- validateBusinessDocument(document, file, { rolesDir });
- const bytes = JSON.stringify(document, null, 2) + "\n";
- // Check and log exactly what lands on disk, for every setter: a value JSON
+ // mapping, including library playgrounds and hybrid universes.
+ if (canonicalJson(document?.projects) !== canonicalJson(old.projects))
+ fail('organization-projects-protected');
++ replyLimitsFence(old, document, actor);
+ validateBusinessDocument(document, file, { rolesDir });
+ const bytes = JSON.stringify(document, null, 2) + "\n";
+ // Check and log exactly what lands on disk, for every setter: a value JSON
@@ packages/business/src/organization.mjs: export function organizationWriter({ dir, rolesDir, barrier = () => {} }) {
- const written = JSON.parse(bytes);
- if (canonicalJson(written.projects) !== canonicalJson(old.projects))
- fail('organization-projects-protected');
-+ replyLimitsFence(old, written, actor);
- validateBusinessDocument(written, file, { rolesDir });
- const after = sha256(bytes);
- const transaction = randomUUID();
+ const written = JSON.parse(bytes);
+ if (canonicalJson(written.projects) !== canonicalJson(old.projects))
+ fail('organization-projects-protected');
++ replyLimitsFence(old, written, actor);
+ validateBusinessDocument(written, file, { rolesDir });
+ if (beforeWrite) {
+ beforeWrite();
@@ packages/business/src/organization.mjs: export function organizationWriter({ dir, rolesDir, barrier = () => {} }) {
});
}
@@ packages/library/src/guard.mjs (new)
+}
## packages/library/src/index.mjs ##
-@@ packages/library/src/index.mjs: export { renderItems, KINDS, NOTICES, UNREADABLE } from './render.mjs';
- export { survey, formatSurvey, surveyMain } from './survey.mjs';
- export { SYNC_STATE_FILE, mirrorPath, ensureMirror, withLibraryLock, servedCommit, readSyncState, libraryStatus, readLibraryFile } from './mirror.mjs';
+@@ packages/library/src/index.mjs: export { SYNC_STATE_FILE, mirrorPath, ensureMirror, withLibraryLock, servedCommi
export { syncCommand, sync, ASKPASS, SLOT, SYNC_INTERVAL_MS } from './sync.mjs';
+ export { buildIndex, indexFor, clearIndexCache, indexCacheSize } from './index-build.mjs';
+ export { sees, find, get, search, manuscript, universeInfo, QUERY_REPLY_CAP, LOOKUP_LIMIT, MANUSCRIPT_LINES } from './query.mjs';
+export { REPLY_LIMITS, resolveReplyLimits, checkReplyLimits } from './limits.mjs';
+export { GUARD_CODES, FIXED_TEXTS, WEB_CITE_DEFINITIONS, REASON_MAX, GuardError, parseReply, checkReply, libraryReader, guardReply, lastCommits } from './guard.mjs';
2: c25f5b8da ! 2: 7400509ba row 217: citation runner retry and acceptance draft (Untested)
@@ Commit message
row 217: citation runner retry and acceptance draft (Untested)
## BUILD-LOG.md ##
-@@ BUILD-LOG.md: Row 299 (573, #1806, Gander, Filbert): before, the P10 band test timed a fault r
- 2026-10-23T17:29:46Z | Gyro Vikunja571 sage-3542 Connections amendment | Branch gyro/editor-connections-design cut exactly from landed PRD1.17 30e6bb680; read REQ-LIB-5 in that PRD. Replaced stale J-b waits in parent and W4. Proposed W8 owns current authorized Markdown/DOCX links/backlinks list, labels, versioned refresh, leakage refusals and fixture tests. Build order under mos-1470/comment961 is W7 closed routing candidate, W8 landing, then W7 human first-real-import opening. No REQ-LIB-8 condition or acceptance change. Q234/mos-1363/S0 M1-M14 and post-10-27/MVP priority fixed. Static diff, twelve brief sections and append-only checks pass. No repo Node, tests, build, browser, queue mutation or live action. Fenton reviews after authorized docs branch push; Sage lands on approval.
+@@ BUILD-LOG.md: remain; no live state, schema or bus policy change.
- 2026-10-23T17:32:37Z | Gyro sage-3544 fenton-0016 N1/N2 delta | Before: W7 Gate/final real-conversion list omit the W8 build-order cross-reference and W8 human-view filtering cites agent settings. After: both locations explicitly put W8 landing before human opening as mos-1470 build order, not acceptance; comment/tracked-deletion links are not current story links and never appear in the human Connections view regardless of agent settings. New commit atop approved 5af060fb5, no amend. Static diff and append-only checks pass. Docs only, no repo Node/tests/live action. Fenton checks only this delta.
-+
+ 2026-10-24 | Goldie | Row265 / #1770 verified (mos-1567, sage-3942) | Approved correction adds solely address import pin + Row265 comment to project-runtime.test and one pure-source RUNNER_FILES mount; new block checks parser has no imports. Serialized fresh-short-TMP timeout-k10: unchanged sandbox10/10, parser15/15, rooms18/18, full bus957/957, twelve named refusal mutants killed (each Node1, driver0), restored parser15/15 + rooms18/18. All positives zero fail/skip/cancel; every mutation restored full broker SHA71b32ee4. Old first-red evidence retained, no other old-test change. Slot returned goldie-0034; Boyd packet explicitly includes mount-list review, candidate push next.
+ 2026-10-24T07:18:53Z | Sage | Row 327 (#1825, Bradford, Poe and Dewey) LANDED 68c08b4e7. Before: refactor at 94d9e90a6; the push guard was a scratch script with no reviewed-binary check. After: scripts/push-check.sh and scripts/test-push-check.sh on refactor, 3 commits cherry-picked onto 6a5e12511 with blobs equal to the round 3 tip d858c9f8b, plus doc commits 76f84465f and 68c08b4e7. Binaries are found by numstat or a NUL in the first 8000 committed bytes, regardless of attributes; each needs its sha256 and path in an approved latest-round candidate; an unconfirmed queue tail exits 2. Reviews: Poe c31525 rev 3882, Dewey c31526 rev 3883. Gate: 1st run 06:57Z RED, not the candidate: canonical node_modules was empty from 05:45:15Z (sage-4023). Rerun with its own root npm ci GREEN 07:15:49Z: 17 package suites 0 failures (cli 986, plugins 119, webui 418), 11 scripts exit 0, push-check 6 mutants KILLED; skips are the queue canonical-root check and the row 244 live provider cases. The landed push-check.sh passed its own push (NO_BINARY, NO_ATTRIBUTION, PUSH_READY). mos-1575: gates install their own node_modules; canonical restored with npm ci (128 packages).
+2026-10-23 | Beakley (88b97f65) | Row 217 #1718 takeover, before implementation | Clean base 45dca69f6 on beakley/row217. Recovering Launchpad handoff for citation guard, live settings, page store and runner retry. Acceptance is C2-06/design 5.2 plus sage-3595/3599/3602. Tracking agents/beakley/work/queue-217/BUILD.md; no product changes or Node/tests; Sage CLEAR required.
+
+2026-10-23 | Beakley (88b97f65) | Row 217 #1718 untested draft checkpoint | Continued Launchpad e25ef0373; added runner retry/text/note implementation, pure protocol constants and sage-3640 approved single read-only mount, CLI documentation and new acceptance test files. Static checks caught missing projects compatibility, async request mutation and Git pathspec matching; bounded fixes and regression tests authored. git diff --check clean. No Node/test/mutant executed; Sage holds CLEAR. 283/216/285 dependency checks and all acceptance execution remain open. Packet agents/beakley/work/queue-217/MANIFEST.md.
@@ agents/beakley/work/queue-217/mutants.py (new)
## docs/SESSIONS.md ##
@@ docs/SESSIONS.md: are never rewritten or removed; corrections are new entries.
- 2026-10-23T17:48:43Z | Scrooge (629b6cd3) | Row 252 Console inbox Approve and Deny (#1753) | Rebased onto 306 landing as 580037105 (range-diff all =), slot run bus 907/0 webui 410/0 cli 943/0, in-review revs 3608/3609, Webby r1 APPROVE, J1-J19 specs to Sage; Sage landed 45ea3fa0d (done rev 3616). Part 1 mutant results were never in BUILD.md; they went to Sage by T3 (scrooge-0252-mutant-specs).
- 2026-10-23 | Sage (1ef1e4f8) | Rows 308 and 252 landings, 571 Connections design amendment, Vikunja 597 | 308 (PRD 1.17, #1815) landed 30e6bb680 and 252 (#1753) landed 45ea3fa0d (replay of 580037105 onto 30e6bb680, range-diff all =), each after a full gate on the landed tree (252 also J1-J19, J11c and J18 equivalent); Gyro's 571 amendment (Fenton APPROVE) landed e8bb13df8; Vikunja 570, 435 and 597 done, canonical webui esbuild 0.28.2; queue revs 3589-3616 committed 59f013247
- 2026-10-23 | Sage (1ef1e4f8) | Vikunja 571 W build rows; rows 13, 42, 257 and 289 check | Filed the design's ten W rows as queue rows 309-318 (revs 3617-3626, owners set to unassigned 3627-3636, queue commit 293b42fee pushed); Vikunja 571 done (comment 994). Row 13's candidate fd72d2689 is on refactor, gate is Monday's row 7 ledger run; 42 paused under mos-1184; 257 post-v1; 289 waits on 214 and 288. Slot released 17:56Z.
+ 2026-10-24T04:27Z | Goldie (a13dd6d5-5e73-4b7d-8318-02abeff24940) | Row265 / #1770 C2-09b rooms | Goldie owns build, Boyd reviews under sage-3915. New goldie/row265 worktree at ec86f2c84, claim rev3814; room verbs/parser/new tests prepared, no old tests changed. Sage-3932 slot: new parser14/14 and rooms18/18 passed; whole bus in progress before refusal mutants, stop rule active.
+ 2026-10-24T04:35Z | Goldie (a13dd6d5-5e73-4b7d-8318-02abeff24940) | Row265 / #1770 verified | First slot stopped at project-runtime import pin. mos-1567 narrowly authorizes pin and pure-source mount correction. sage-3942 rerun: sandbox10/10, parser15/15, rooms18/18, bus957/957, twelve refusal mutants killed/restored SHA71b32ee4, parser15/15 + rooms18/18 again. Slot returned goldie-0034; no further test runs. Boyd reviews RUNNER_FILES alongside rooms; own-branch push/claimant in-review next.
+ 2026-10-24T07:18:53Z | Sage (1ef1e4f8) | Row 327 / #1825 push guard landed (mos-1572 option A, mos-1575) | Gate went red 06:57Z on an empty canonical node_modules (Glomgold's webui npm ci through a link to canonical, glomgold-0011); rerun with its own npm ci GREEN 07:15:49Z on 1bd214e38; pushed 68c08b4e7 07:18:03Z; #1825 closed c31530; canonical restored (128 packages); brief template rule 4db23a51f | landed
+
+2026-10-23 | Beakley (88b97f65, Codex gpt-6.1-sol) | Row 217 #1718 takeover under Q245 | Registered beakley/row217; read brief/design and standing Sage rulings; awaiting Launchpad ref before implementation. Queue next refused linked worktree; reported to Sage. Untested, no Node/test run pending CLEAR.
3: b6c3129d2 ! 3: a447880cb row 217: early-review coverage and availability RED cases (Untested)
@@ Commit message
row 217: early-review coverage and availability RED cases (Untested)
## BUILD-LOG.md ##
-@@ BUILD-LOG.md: Row 299 (573, #1806, Gander, Filbert): before, the P10 band test timed a fault r
+@@ BUILD-LOG.md: remain; no live state, schema or bus policy change.
2026-10-23 | Beakley (88b97f65) | Row 217 #1718 takeover, before implementation | Clean base 45dca69f6 on beakley/row217. Recovering Launchpad handoff for citation guard, live settings, page store and runner retry. Acceptance is C2-06/design 5.2 plus sage-3595/3599/3602. Tracking agents/beakley/work/queue-217/BUILD.md; no product changes or Node/tests; Sage CLEAR required.
2026-10-23 | Beakley (88b97f65) | Row 217 #1718 untested draft checkpoint | Continued Launchpad e25ef0373; added runner retry/text/note implementation, pure protocol constants and sage-3640 approved single read-only mount, CLI documentation and new acceptance test files. Static checks caught missing projects compatibility, async request mutation and Git pathspec matching; bounded fixes and regression tests authored. git diff --check clean. No Node/test/mutant executed; Sage holds CLEAR. 283/216/285 dependency checks and all acceptance execution remain open. Packet agents/beakley/work/queue-217/MANIFEST.md.
4: dde5b8496 = 4: 2655ec010 row 217: keep fixture status on its current served tip (Untested)
@@ -1,30 +0,0 @@
# Row217 round2 test receipts
Sage CLEAR sage-4042/4043, 2026-10-24. Source revision 2d274a5b6. All runs
serialized; source files stayed unchanged through the whole-suite and mutant pass.
Commands used TMPDIR=/mnt/storage/scratch/tmp/tNoueZ and timeout -k 10.
- npm ci --ignore-scripts --no-audit --no-fund at the worktree root (300s bound),
then packages/webui (300s). Actual directories, no canonical links.
- node --test packages/bus/tests/citation-availability.test.mjs (180s).
- python3 agents/beakley/work/queue-217/mutants.py <m5-red> M5-hide-library-unavailable
(420s). Green control, the authorized pre-fix RED stand-in, restore+green.
- node --test --test-concurrency=1 with the seven new test files (900s):
library/guard, business/reply-limits, cli/reply-limits, bus/citation-availability,
bus/citation-guard, bus/citation-runtime and harness/citation-runner. Whole files.
- First attempt 56/57: new runtime fixture invalid-authority. Only that fixture
was corrected to the established broker projection. runtime-fixture-retry.log
is its 1/1 rerun (180s); touched-rerun.log is the whole-file 57/57 rerun.
- npm test in packages/library, then business (900s each), bus and cli (1200s
each), harness and seat (900s each). Never overlapped package runs.
- python3 agents/beakley/work/queue-217/mutants.py <mutants> (900s).
The driver wraps each Node run in timeout -k 10 120. Each negative exits1,
is preceded by a green control, restores its product bytes/hashes and then
reruns the restored control green. No checkout product file is mutated.
summary.json holds complete counts; summary.txt is the short version. M1 anchors
are recorded in m1-anchors.txt. The five *-restored.sha256 files match current
product files. Full outputs are retained, including the first new-test failure.
Negative logs intentionally keep Node's whitespace-only diagnostic padding;
standard git diff --check flags that padding, not source code. No binary logs.
No old test failed or was edited. Sage runs scripts/test-*.sh at landing.
@@ -1,11 +0,0 @@
✔ C2-06 held library lock gives the agent citation-unavailable and its retry reason (5142.976705ms)
✔ C2-06 malformed sync state is availability failure, never a fabricated invalid cite (33.874404ms)
✔ C2-06 no mirror or freshly initialized empty mirror still means no served citation (33.746516ms)
ℹ tests 3
ℹ suites 0
ℹ pass 3
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 5307.376982
File diff suppressed because it is too large. Load diff
@@ -1,280 +0,0 @@
npm notice run @mosaic/[email protected] test
npm notice run node --test tests/
✔ a grant's level is collaborator or viewer (2.351697ms)
✔ any other level refuses with the key path named (1.505284ms)
✔ covers tells a viewer grant from a collaborator grant (0.605812ms)
✔ covers refuses a call with no level, so a viewer grant can't slip past a collaborator check (0.247487ms)
✔ a viewer grant still needs its business, project, instance and expiry to cover (0.247397ms)
✔ a valid document passes and comes back frozen (4.146183ms)
✔ checkAccess does not freeze or alias the caller's document (0.552481ms)
✔ LEVELS is the single allowed level set, collaborator and viewer (row 193a) (0.259109ms)
✔ accessFilePath is access.json in the config directory (0.495701ms)
✔ top level: object, unknown keys, accessVersion, revision, arrays (2.131141ms)
✔ users: unknown keys and the id rule (0.609866ms)
✔ users: human, tester and any business's human are refused (0.455944ms)
✔ users: home is a given peer or local (0.372673ms)
✔ users: subjects, provider, sub, uniqueness and owner subjects (2.126611ms)
✔ grants: unknown keys, id, user and business (0.897075ms)
✔ grants: projects is ["*"] or distinct lowercase UUIDs (1.199677ms)
✔ grants: instances is ["*"] or distinct declared instances of that business (0.889396ms)
✔ grants: any level other than collaborator or viewer refuses, naming grants[i].level (1.13158ms)
✔ grants: expires is optional ISO time, and a past expiry is not refused (0.979808ms)
✔ the context is required and checked (1.713394ms)
✔ loadAccess reads a valid file and checks it (0.755936ms)
✔ loadAccess refuses a missing file, a symlink and a directory with exit 4 (0.519376ms)
✔ loadAccess refuses another owner and group or other write (0.581157ms)
✔ loadAccess refuses bad JSON and a bad document with exit 2 (1.841309ms)
✔ covers: * and listed ids match (0.340508ms)
✔ covers: an unlisted project, instance or business doesn't match (0.20254ms)
✔ covers: an expired grant doesn't match, at and after the instant (0.698261ms)
✔ covers: level is the least level asked for (row 193a) (0.213107ms)
✔ covers: a missing or unknown level throws (row 193a, N1) (0.385188ms)
✔ covers: a grant with an unknown level covers nothing (row 193a) (0.191435ms)
✔ covers: now must be a valid Date (0.21008ms)
✔ today's files load unchanged: identity, publish and remote are optional (11.61814ms)
✔ a granted agent loads with its identity, grant and the project's upstream (4.906248ms)
✔ N10: publish needs identity and a gitea definition, and the error names the grant (9.522958ms)
✔ publish names declared projects that have a remote, each once (7.911234ms)
✔ identity fields are checked (14.073433ms)
✔ D9c: the upstream must be its own normalized form, exactly /OWNER/REPO (29.451403ms)
✔ D9c: one .git is stripped, and the fork is built from the stripped name (1.733511ms)
✔ D9c: gitea.url names the instance only (10.698646ms)
✔ the upstream's host and port must be the agent's Gitea's (4.064711ms)
✔ remote-not-fork: an upstream the agent's own user owns, compared without case (10.115713ms)
✔ store references: own path only (design D1, D3a) (0.50611ms)
✔ the role file loads and resolves through loadBusiness (18.165733ms)
✔ the shipped file is exactly the approved list (1.392044ms)
✔ the assistant's authority is message.send and record.write within role (4.312182ms)
✔ the assistant talks to the user and the chief of staff only, and no other shipped role is limited (0.978023ms)
✔ a business grant through limits does not widen the role (6.715605ms)
✔ a launch block whose by is the assistant is refused (3.553443ms)
✔ the instance takes no credential references and no tracker (9.975785ms)
✔ an arbiter whose role definition declares messaging lists is refused, for each kind (8.992963ms)
✔ an arbiter without messaging lists is accepted beside the limited assistant (3.104416ms)
✔ the contract passes work to the chief of staff and directs no one (0.788753ms)
✔ REQ-HARN-2: the assistant, companion and research hold the web grant, and no other role file does (1.683056ms)
✔ C2-04: library mappings load without roots, remain frozen, and retain mapping refusals (31.538067ms)
✔ C2-04: an otherwise valid publish grant cannot name a library repo (4.356759ms)
✔ config directory and file path follow MOSAIC_CONFIG (0.467526ms)
✔ the fixture business validates and comes back frozen (4.106001ms)
✔ two instances may share a definition (2.097865ms)
✔ top-level refusals (6.537312ms)
✔ arbiters and projects (24.968268ms)
✔ role instances (9.057417ms)
✔ Vikunja bots (29.820456ms)
✔ a role without Vikunja takes no tracker block (9.629575ms)
✔ credential references match the definition's services (11.680645ms)
✔ launch (31.945766ms)
✔ REQ-THREAD-2 REQ-LAUNCH-1 launch.threadIdleSeconds: absent is the default, a positive integer is used, anything else refuses (34.141496ms)
✔ loadBusiness: file checks (12.995702ms)
✔ loadBusiness: not a regular file (111.510997ms)
✔ loading writes nothing (1.787307ms)
✔ names that are Object.prototype properties don't count as declared (5.786433ms)
✔ the shipped example refuses as written and validates once filled in (2.551686ms)
✔ persona vars: agent layer, creative definition only, both or neither (26.121282ms)
✔ row 194 keep, noHire and retired validate, and a file without them loads as before (4.607715ms)
✔ row 194 each bad keep, noHire or retired entry refuses (19.966409ms)
✔ row 323: committed Case 1 document loads unchanged through the business loader (10.685638ms)
✔ row 323: real business validate accepts the Case 1 fixture without tracker credentials (226.106251ms)
✔ row 323: real factory install accepts the document's scratch input and writes it unchanged (294.937207ms)
✔ row 323: the Case 1 business boots without a tracker or @sync credential (60.850375ms)
✔ row 323: factory install refuses bus.tester false before writing (39.485453ms)
✔ row 323: literal library key refuses through final business validation (176.986326ms)
✔ row 323: a library project refuses through the factory profile plan (36.685902ms)
✔ row 325: the Case 1 project's sole key matches the repository project id (7.063988ms)
✔ row 325: real business validate reports the copied repository project valid (203.591785ms)
✔ row 325: the old mosaic-stack project key refuses against those same project bytes (227.47487ms)
✔ the role file loads and resolves through loadBusiness (22.21166ms)
✔ the shipped file is exactly the approved list (0.355811ms)
✔ the resolved record matches the approved list, so a widened file fails (4.433743ms)
✔ the chief of staff holds role.launch, message.send, role.end, organization.change, record.write, instance.name, role.hire and role.fire; every other action is gated (6.025087ms)
✔ the pm does not hold role.launch (7.814194ms)
✔ a business grant of a gated action through limits does not widen the role (5.309288ms)
✔ a limit that drops role.launch leaves the chief of staff with no launch block (5.488981ms)
✔ a launch block whose by is the pm instance is refused (4.031539ms)
✔ the contract names no duty to talk to the human and the pm contract no launch (1.077581ms)
✔ the instance takes no credential references and no tracker (7.111256ms)
✔ C2-04: business validate and resolve skip a library before code projects and credential checks (581.819531ms)
✔ usage errors exit 4 (330.347677ms)
✔ validate: a good business exits 0 and prints instance digests (80.712835ms)
✔ validate: project files (358.68705ms)
✔ validate: missing files and a broken system config (272.747082ms)
✔ validate: credential reference problems exit 2 and name each one (75.47514ms)
✔ validate: a not-issued store agent dated today passes, and an issued one with a past expiry fails (152.378642ms)
✔ validate: a token file inside the repository is refused (76.459487ms)
✔ validate: role definitions come from MOSAIC_ROLES_DIR (210.323656ms)
✔ resolve: prints one instance's record (260.543734ms)
✔ resolve: refusals (375.881441ms)
✔ parse: exactly one of file or env, plus the service's date (3.551882ms)
✔ check: a good file has no problems (1.2198ms)
✔ check never opens the file: a write-only token passes (0.477268ms)
✔ check: file problems (1.60977ms)
✔ check: token files can't live in the repository or dataRoot, even through a linked directory (1.508979ms)
✔ check: dates and environment references (0.686041ms)
✔ each definition loads, with a contract file, and is exactly the approved list (4.83466ms)
✔ an organization file that declares them passes, and each resolves to least privilege (10.307081ms)
✔ the chief of staff launches each one; no other role does (11.082937ms)
✔ a C-suite role can't be made the launcher: launch.by must hold role.launch (5.052598ms)
✔ limits can narrow a C-suite role but never widen it (4.524289ms)
✔ any unknown key, tool, action or version in a role file is refused (4.904699ms)
✔ row 298: checkGrantScope takes the D2 shape and refuses anything else (2.752624ms)
✔ row 298: a missing scope is empty and a bad one falls back to empty, which covers nothing (0.482721ms)
✔ row 298: a Gitea grant is in scope only when its agent and every project are listed (0.341447ms)
✔ row 298 (sage-3594 Q2): host commands match whole argv tokens, and enrollment is never in scope (0.467524ms)
✔ row 298: a bad grantScope in the file still loads, and the read shows the fallback (18.355754ms)
✔ row 298: the writer checks the scope, logs the change and removes the key for {} (142.313501ms)
✔ row 298 (sage-3594 Q1): the general writers can't write grantScope (25.353249ms)
✔ REQ-WAIT-1: GATED_ONLY is exactly the hard waits; the new actions are in the vocabulary (1.86466ms)
✔ REQ-ROLE-2: END_PROTECTED includes the assistant's thread definition (0.234237ms)
✔ REQ-COS-3: role.hire and role.fire are routed, not hard waits (0.300439ms)
✔ REQ-WAIT-3: every action is routed or a hard wait, never both, and the routed list names only actions (0.967731ms)
✔ REQ-WAIT-3: instance.name is routed under REQ-MSG-2 (1.5), not a hard wait (row 141, sage-0589) (1.313696ms)
✔ REQ-WAIT-2: a role listing a hard wait at either class is refused; the actions that left can be granted (5.343386ms)
✔ S1: the business file refuses hosts at the top level and in a role, and host.<id> references (56.500208ms)
✔ T1: address, user and host key checks, which the enrollment raise uses (11.374442ms)
✔ T26: no wildcard and no shell, runner or interpreter as a prefix (2.722004ms)
✔ D6: argv shape and the literal prefix match (0.922698ms)
✔ C2-04: instance settings skip a library while checking a later code project (98.596648ms)
✔ row 165 read lists each instance and the definitions add accepts (16.615936ms)
✔ row 165 add: two instances join, validate exits 0, the log names the human, and the writer asks for no restart (row 194, D3) (308.207149ms)
✔ row 165 change: definition, vars and launch membership log before and after; none asks for a restart, the bus reloads (row 194, D3) (180.35178ms)
✔ row 165 refuses each validation failure and leaves the file's bytes alone (44.040709ms)
✔ T19 add of a credentialed definition writes store references dated today, names its bot, and validate exits 0 (101.60641ms)
✔ T19 add of a definition that declares host writes references for its token services only (12.273146ms)
✔ row 165 refuses a definition change to or from one that declares credentials (6.011439ms)
✔ row 165 a vars or launch change on an instance with its binding succeeds and keeps the binding (87.081633ms)
✔ row 165 refuses an END_PROTECTED definition and every change to a protected instance (9.425714ms)
✔ row 165 refuses while a project file doesn't resolve, as validate would (21.508015ms)
✔ row 165 refuses a stale revision and leaves the file's bytes alone (13.794117ms)
✔ row 65 an instance write refuses harness-off, thinking-unsupported, an unknown model and a partial fallback (38.79158ms)
✔ row 213 a creative instance is the human's: add, vars and definition changes, persona digest only (105.47603ms)
✔ row 256 T1-T3, T5 the human deletes a creative instance, no other actor does, and the assistant stays (106.119319ms)
✔ row 256 T4 the human's delete of the only listed instance, a creative one, is the last-listed refusal (3.635722ms)
✔ REQ-LIMIT-1 schema: every scope unset or zero, adjustable above four, bad values and unknown models refuse (27.767213ms)
✔ REQ-LIMIT-1 counts each exact scope at/over limit, unlimited and old tuple after model reassignment (1.218782ms)
✔ REQ-ROLE-3 writer: atomic validated revision, immutable previous bytes and authenticated actor/old/new receipt (65.935591ms)
✔ REQ-ROLE-3 writer: pre-rename fault leaves old file, post-rename recovery records commit, conflicting recovery refuses (42.79247ms)
✔ REQ-LIMIT-1 / decision145 migration prints only, preserves values, rejects ambiguity, and is idempotent (20.740471ms)
✔ REQ-LIMIT-1 shared settings validates the complete proposed selection and logs exact actor (73.013224ms)
✔ REQ-LIMIT-1 provider is table data: another provider routes separately and aliases share exact counts (5.530215ms)
✔ REQ-ROLE-3 refuses live writer locks, symlink targets and uncertain recovery without changing bytes (31.489428ms)
✔ Q169 assistants: vars and definition change and log the actor; tracker null leaves no tracker (74.510885ms)
✔ Q169 assistants: refuses other instances, other definitions, holder and credentials, empty entries, a tracker the definition has no credential for and a stale revision (46.648048ms)
✔ Q169 assistants: a definition with a vikunja credential takes a tracker change and refuses its removal or a used bot (28.59175ms)
✔ row 65 routes lists every instance with harness, model, thinking and fallback, the switched-on harnesses, the model keys and each harness's levels (4.496203ms)
✔ row 65 setRoutes saves a harness, model, thinking and whole fallback, reads each back from the file, logs the actor, and a null fallback clears all three (28.880486ms)
✔ row 65 setRoutes refuses a partial fallback, a switched-off harness, a level the harness doesn't apply, an unloaded module, an unknown model or instance, a malformed route, no change and a stale revision, with the file unchanged (33.617502ms)
✔ row 65 a file with harness vars and no plugins.harness loads and its views read; a model change still saves, and a route change refuses harness-off (15.471063ms)
✔ B7 kept instance: the models keys it names and the instances key are the human's (32.512862ms)
✔ B7 kept instance: its route is the human's (13.733689ms)
✔ M10 creative instance: models keys it names, the instances key and its route are the human's (41.972839ms)
✔ C2-04 M9: changed playground and hybrid entries leave business and changes.jsonl byte-identical (75.744651ms)
✔ C2-04 M9: code projects, additions, deletions and array changes are protected too (73.935851ms)
✔ C2-04 M9: canonical key order is allowed and a non-project setter still records its change (53.997154ms)
✔ C2-04 M9: a serialization hook cannot change projects after the canonical comparison (29.857522ms)
✔ M7/M8: library seats come from library businesses, creative seats from their creative definitions (20.881147ms)
✔ M8: a business with no library project puts no seat in either set (19.190367ms)
✔ M7/M8: a business file that is not valid JSON throws; no empty set (7.135915ms)
✔ M7/M8: an absent businesses directory gives empty sets (1.688414ms)
✔ M7/M8: a businesses path that is not a directory throws; no empty set (4.583153ms)
✔ M7/M8: a businesses symlink to a missing target throws; no empty set (2.208552ms)
✔ M7/M8: a config directory under a regular file throws (lstat fails with ENOTDIR); no empty set (0.601986ms)
✔ M7/M8: a business file that can't be read throws; no empty set (12.318486ms)
✔ T6 delete refuses in the design's order and leaves the file's bytes alone (104.896221ms)
✔ T6 delete refuses the last listed instance (7.490182ms)
✔ T6 a clean delete removes the entry and its own references, adds retired, and the name can't come back (213.690055ms)
✔ T7 veto: keep, unkeep, nohire and hire each write once, a repeat is no change, and the log names the human (171.894178ms)
✔ T7 veto refuses an unknown or END_PROTECTED keep, a bad request, a stale revision and a business without launch (26.238526ms)
✔ D2.2 hire adds and lists a new instance, logs the chief's context, and sets only model and limits (92.062371ms)
✔ D2.2 hire refuses noHire, a kept name and a listed name, and re-lists a fired one only as it was (29.586421ms)
✔ D2.2 fire delists and keeps the entry, a repeat is done with no write, and each refusal holds (88.451593ms)
✔ row 256 checkDelete passes the human's creative delete and refuses another actor's; fire still refuses (5.294872ms)
✔ row 239 T1 a fire on a revision that goes stale before the writer's lock refuses there and revokes nothing (5.756058ms)
✔ row 239 T2 a write after the revoke refused before publication carries revoked, and the file keeps the edit (7.753057ms)
✔ row 239 T3 any error after the revoke carries revoked, for a fire and a delete; a revoke that throws carries nothing (32.403692ms)
✔ Q247: omitting tracker loads as null and preserves independent role bots (10.793015ms)
✔ Q247: real business validate passes without a sync credential reference or file (168.186763ms)
✔ Q247: present tracker retains its values and validation without mutating the input (9.372029ms)
✔ Q247: present null, undefined and malformed trackers still refuse (18.314895ms)
✔ Q247: absent business tracker does not waive a role's Vikunja bot requirement (2.859494ms)
✔ REQ-PLUG-1 schema: plugins is optional, names known kinds and checked module names (40.546579ms)
✔ REQ-PLUG-1 REQ-ROLE-3 the setter writes plugins through the organization writer and logs old and new names (92.751615ms)
✔ vikunja:19/309 a patch changes only the kinds it names; null removes one kind, explicitly and in the trail (100.494327ms)
✔ vikunja:19/309 an unknown kind (set or removed), a bad module, an empty patch and null on the wrong shape are refused, nothing written (9.927988ms)
✔ REQ-PLUG-1 REQ-ROLE-3 the writer checks the bytes it writes: a Date in plugins is refused there too (19.985103ms)
✔ REQ-PLUG-1 REQ-ROLE-3 a refused setter write throws a code, changes nothing and logs nothing (4.143331ms)
✔ vikunja:19/305 with an exists check, the setter refuses a module no tree file answers to, before anything is written (18.273494ms)
✔ optional project repo is preserved and must be a normalized absolute path (32.895793ms)
✔ loaded business project repo cannot be nested in any declared code checkout (6.807091ms)
✔ path and load (3.706713ms)
✔ refusals (1.897981ms)
✔ record.write is within-role for the eleven approved v2 agents, never gated-only (3.85853ms)
✔ C2-06 M11 human replacement works; omitted settings return to defaults (98.331729ms)
✔ C2-06 M11 agents and tester cannot change settings, including by changing human (55.766765ms)
✔ C2-06 M11 serialization cannot replace settings after the first fence (17.47904ms)
✔ C2-06 M11 an unrelated actor cannot appoint itself human and change reply limits (16.039248ms)
✔ C2-06 invalid setter values preserve the business and changes.jsonl (17.259974ms)
✔ C2-06 validator accepts hand-edited settings; raw reader fails closed on invalid files (19.048524ms)
✔ C2-04: a library first in projects does not hide a later project layer (21.880181ms)
✔ systemVars flattens the validated config (1.820728ms)
✔ precedence: system, business, project, project role, agent (10.989776ms)
✔ limits narrow the definition and never widen it (8.400306ms)
✔ role.launch stays within-role only for the instance the launch block names (18.468852ms)
✔ limits.authority without role.launch leaves the launcher with no launch block (13.185333ms)
✔ limits.authority narrows cross-role actions too (2.699689ms)
✔ classify (6.249491ms)
✔ the record carries what the broker and launcher need (4.7922ms)
✔ digest: key order doesn't matter, any value change does (12.395981ms)
✔ refusals (3.790542ms)
✔ the four shipped version 2 roles load (5.229965ms)
✔ shipped role scopes match addendum B section 2 and the SR runbook (2.178782ms)
✔ shipped authority follows the note's table (13.291498ms)
✔ every role file in roles/ loads through the validator, and a v2 contract exists (2.100731ms)
✔ version 1 files keep loading with no authority (1.521097ms)
✔ the conductor policy isn't a role (0.302424ms)
✔ a missing role file is exit 4, a symbolic link too (0.564721ms)
✔ version 2 refusals (3.788273ms)
✔ authority: closed vocabulary, no gated-only action, no overlap (3.881951ms)
✔ messaging: optional, role definitions and human, never the tester (1.949889ms)
✔ row 64 skills: optional, distinct skill directory names, none on version 1 (2.255987ms)
✔ credentials: Gitea scopes (1.343013ms)
✔ credentials: Vikunja scopes are a group-to-verbs map from the grantable list (1.709889ms)
✔ credentials: services (0.759517ms)
✔ contract: a non-empty regular Markdown file beside the role file (0.838905ms)
✔ the six creative roles load: read tools, message.send only, messaging with the human only (0.693212ms)
✔ M1: a creative role file wider than read and answer is refused (1.897832ms)
✔ hireable: HIRE_ALLOWED is exactly the six plain work actions, and every one is routed (0.173708ms)
✔ hireable: a list naming a definition that holds any refused action refuses at load, one case per action (18.133668ms)
✔ hireable: a mixed definition refuses, a clean list loads, and the named file's own hireable isn't read (1.146869ms)
✔ hireable: a missing, version 1, duplicate or badly named entry refuses, and the key is optional (3.734122ms)
✔ the pm and the cto check a saved spec against settled decisions and work in flight, and answer with a BLOCK or an accept (11.616694ms)
✔ the chief of staff relays a BLOCK or an accept to the assistant as a reply to the message that carried it (1.277302ms)
✔ the assistant summarizes a spec review in its own words and doesn't repeat the chief of staff's text (0.70976ms)
✔ REQ-LIMIT-3 schema: each subject kind, limit 0 and no ceiling are accepted; bad limits, times, keys and undeclared instances refuse (49.216064ms)
✔ REQ-LIMIT-3 the writer stamps since: a new limit gets now, a changed one keeps its time, a different time is refused (85.0223ms)
✔ REQ-LIMIT-3 only tokens.* at schema depth holds token limits: agent limits named `limit` save as sent, and a token limit named `limit` is stamped and reset (67.775561ms)
✔ REQ-LIMIT-3 a reset moves since to now, is logged with its actor, and refuses a path that is not a limit (34.296428ms)
✔ REQ-LIMIT-2 schema: launch.account names a credential set; a daily quota needs a reset and an IANA zone and names the account (33.871693ms)
✔ REQ-LIMIT-2 the writer stamps a daily quota's since, keeps its reset and zone, and a reset moves since (33.845575ms)
✔ every key names known layers and a merge rule (1.726458ms)
✔ unknown keys and wrong layers refuse (1.084085ms)
✔ types (3.275461ms)
✔ merge: defaults, then the most specific layer wins (0.419589ms)
✔ merge: limits only narrow, and provenance lists each source (0.757115ms)
✔ merge doesn't change its inputs (0.206627ms)
✔ web.searxng takes https anywhere and http on loopback, so Jason's 127.0.0.1:8888 passes (0.262745ms)
✔ both definitions load, with a contract file, and are exactly the approved lists (5.013658ms)
✔ security-reviewer has no write or shell tool and classifies only the verdict as its own (9.066819ms)
✔ merge-gate's only grant is git.merge.protected cross-role, and it has no write tool (3.470869ms)
✔ neither role can be an arbiter: its messaging lists refuse the business file (row 133) (8.498658ms)
✔ every role contract carries the proactive line in its Authority section (1.099286ms)
✔ pm and chief-of-staff say where a raise goes under REQ-DEC-2 (0.851681ms)
✔ the merge landing takes two runs: merge-gate, cto and chief-of-staff each say their part (0.660442ms)
ℹ tests 270
ℹ suites 0
ℹ pass 270
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 2873.146579
File diff suppressed because it is too large. Load diff
@@ -1,182 +0,0 @@
npm notice run test
npm notice run node --test tests/*.test.mjs
✔ sessionModel: the route is the instance's own vars, and a missing one refuses no-route by name (37.340888ms)
✔ a pi bundle: prompt, policy, tools and manifest, 0600 in a 0700 directory (10.573131ms)
✔ a chief-of-staff bundle lists launch among the bus tools and the manifest's typed tools (4.412373ms)
✔ a chief-of-staff bundle lists end_run, change_organization and set_name as typed and nothing untyped, for either harness (8.193363ms)
✔ the stop line names end_run for a role.end holder, and every other role keeps today's text (13.648406ms)
✔ a claude-code bundle adds the wrapped gate hook and the MCP config (7.875641ms)
✔ the prompt's built-in tools line is the harness's own names, as the manifest lists them (22.548582ms)
✔ the prompt names the project clones in the workspace, and none when there are none (13.290253ms)
✔ the prompt explains the review loop to a role with push_working, and reviews to one with fetch_review (15.420914ms)
✔ the prompt explains landing to a role with land_work, and to no other (9.918107ms)
✔ the prompt tells the pm to ask the chief of staff for sessions, and no other role (18.356673ms)
✔ a bundle is written once: an existing file refuses (3.135889ms)
✔ a path with a single quote can't go into the hook command (3.86973ms)
✔ web grant on pi: the bundle has web_search and web_fetch, and no built-in web tool (4.927453ms)
✔ no web grant on pi: no web tool in the bundle, and the gate blocks a web call (4.535472ms)
✔ web grant on claude-code: the bundle has web_search and web_fetch, and no built-in web tool (4.409455ms)
✔ no web grant on claude-code: no web tool in the bundle, and the gate blocks a web call (7.034483ms)
✔ a granted session's gate lets the typed web tools through and still blocks the built-ins (6.471178ms)
✔ search-source searxng-url: a granted role gets the typed broker tools and no harness web tool; an ungranted role gets nothing (12.185523ms)
✔ search-source searxng-bundled: a granted role gets the typed broker tools and no harness web tool; an ungranted role gets nothing (11.958441ms)
✔ search-source harness-builtin: claude-code gets WebSearch and WebFetch and no typed web tool, only when granted (12.933659ms)
✔ search-source harness-builtin is refused for a granted pi role, which has no built-in web tool (4.064682ms)
✔ C2-06 RESULT reply-invalid retries once, delivers only the valid answer and names reason (351.396996ms)
✔ C2-06 RESULT citation-missing retries once, delivers only the valid answer and names reason (256.673143ms)
✔ C2-06 RESULT citations-over-limit retries once, delivers only the valid answer and names reason (222.852677ms)
✔ C2-06 RESULT citation-invalid retries once, delivers only the valid answer and names reason (261.389143ms)
✔ C2-06 RESULT playground-cited-as-canon retries once, delivers only the valid answer and names reason (268.849657ms)
✔ C2-06 RESULT citation-cross-universe retries once, delivers only the valid answer and names reason (231.674929ms)
✔ C2-06 RESULT citation-unfetched retries once, delivers only the valid answer and names reason (216.064282ms)
✔ C2-06 RESULT two guard refusals use the citation fixed text and exactly one retry (188.874138ms)
✔ C2-06 RESULT JSON 34000 characters retries with a shorter valid answer (236.68605ms)
✔ C2-06 RESULT JSON 70000 characters retries with a shorter valid answer (234.722358ms)
✔ C2-06 RESULT two oversized JSON bodies use the length fixed text with citations required (193.029509ms)
✔ C2-06 multibyte plain bodies also receive the one request-size retry (223.988818ms)
✔ C2-06 two multibyte plain bodies use the length fallback (205.649902ms)
✔ C2-06 RESULT a length refusal then citation refusal shares one retry and citation fallback (206.128944ms)
✔ C2-06 fixed empty/failed replies defer unslop note until the next cited reply (295.722008ms)
✔ C2-06 cited JSON above the old 32000 clip retains its citations and text (189.724785ms)
✔ C2-06 a flagged cited answer keeps the note inside text and citations whole (192.59344ms)
✔ C2-06 send_message typed tool runs every guard code before the valid RESULT (262.703841ms)
✔ C2-06 outside library the old failed text, clip and unslop behavior hold (208.584382ms)
✔ C2-06 outside library a refused send keeps the existing no-retry behavior (159.048751ms)
✔ C2-06 the retry turn delivers citation-unavailable reason to the agent (190.203749ms)
✔ allow exits 0, a deny exits 2 with the reason on stderr (211.158287ms)
✔ a missing or wrong policy, or a bad event, exits 2 (113.877105ms)
✔ the bundle's wrapped command: a missing gate or node still blocks (1104.288151ms)
✔ claude: typed tools through MCP, the hook blocks, builtins outside --tools don't exist (1070.940549ms)
✔ claude: the hook alone blocks a path outside the workspace (568.174554ms)
✔ claude: a second turn resumes the first turn's session (940.097062ms)
✔ claude adapter: --restricted is always passed (6.108878ms)
✔ claude adapter: MOSAIC_CLAUDE_BIN wins over PATH and must be an absolute executable (19.555633ms)
✔ claude adapter: a directory pin exits 2 before it runs; a pin with a space runs (6.450898ms)
✔ claude: CLAUDE.md files and auto-memory don't reach the model; without --restricted they do (912.426727ms)
✔ claude: a missing hook or MCP file refuses before claude starts (8.255308ms)
✔ claude: row 66 a reply with a tell gets the correction notice on the next turn, a clean reply gets none, and the counts read after (1813.719749ms)
✔ claude: row 66 a broken lists.json gives no clean verdict, the operator is told once, and the session still answers (861.243377ms)
✔ M2: the gate refuses write, edit and bash to every creative role on pi and claude-code (58.57362ms)
✔ M6: no creative session gets raise_decision; the assistant and the chief of staff keep it (27.01682ms)
✔ web: research and companion get the broker's typed web tools, and a harness-builtin source refuses web-source-not-allowed (34.87358ms)
✔ persona: the block sits between the contract and ## This session, fenced, with the name and digest (10.05189ms)
✔ persona: each unsafe or unpinned file refuses before the bundle directory is made (30.976676ms)
✔ adapters pass the prompt file's absolute path; the persona and the prompt text never sit in argv (48.053085ms)
✔ the pi adapter refuses a missing, unreadable or directory prompt file before pi starts (13.20329ms)
✔ pi: policy tools and typed tools pass, anything else is blocked (4.524582ms)
✔ claude: builtins map from pi names, typed tools need the mcp prefix (1.1263ms)
✔ file tool paths must resolve inside the workspace (4.02957ms)
✔ pi's own path normalisation can't be used to step out (1.586245ms)
✔ a symlink inside the workspace that points out is outside (1.300474ms)
✔ a dangling symlink is refused at any depth, in both harnesses (5.091178ms)
✔ read is checked under every spelling pi's read would open, in both harnesses (29.6566ms)
✔ other spellings cover directories, dangling links and pi's cwd (2.651598ms)
✔ a relative path climbs from the workspace's real path, in both harnesses (9.557314ms)
✔ claude path fields per tool (1.146391ms)
✔ glob patterns stay inside the workspace (1.220629ms)
✔ a path that can't be checked is blocked (0.713439ms)
✔ fetch_review's have lists the working refs before origin's, and no more than HAVE_MAX (358.466429ms)
✔ fetch_review's have orders the working refs newest first within each clone, one clone after another (177.220281ms)
✔ a runner git past its time: SIGTERM reaches its process group, and SIGKILL follows after the grace period (1810.093816ms)
✔ once a signalled runner git has closed, its group gets SIGKILL, so a process that ignored SIGTERM dies too (303.717292ms)
✔ land_work sends one land line and resolves the host's started answer (3.694332ms)
✔ initialize, ping and tools/list (73.055562ms)
✔ tools/call goes through the tool socket; a refusal is an isError result (66.566638ms)
✔ replies are compact JSON; over the cap a tool error names the size and the cap (60.558157ms)
✔ unknown tools and methods are JSON-RPC errors and never reach the socket (52.967178ms)
✔ a missing argument is a usage error (35.244954ms)
✔ pi: typed tools reach the socket, the gate blocks, agent_end writes the marker (676.072372ms)
✔ pi: a reply over the cap is a tool error naming the size and the cap; list_tasks asks for open tasks (532.762084ms)
✔ pi: a write through a dangling symlink is blocked, and nothing appears outside (479.264215ms)
✔ pi: a read is refused when pi would open another spelling outside (479.008336ms)
✔ pi: a relative path climbs from the real path of a workspace behind a symlink (495.496517ms)
✔ pi: a relative path climbs from the real path of a dataRoot behind a symlink (458.873867ms)
✔ pi: a missing extension refuses before any model call (6.358156ms)
✔ pi: an extension without its configuration fails pi's start (380.653357ms)
✔ pi: row 66 a reply with a tell gets the correction notice on the next turn, a clean reply gets none, and the counts read after (1353.463628ms)
✔ pi: row 66 a broken lists.json gives no clean verdict, the operator is told once, and the session still answers (748.010347ms)
✔ raise_decision offers domain as technical or delivery only, optional, and says where a raise goes (23.00088ms)
✔ raise_decision forwards domain to decision.raise, and a call without it sends none (100.23044ms)
✔ founderCheck: founder variables, then a needed service without a usable token (3.039179ms)
✔ turnRequest names the sender, class, reply and decision (0.355597ms)
✔ turnRequest says a tester's message is a test and never Jason's instruction (0.317095ms)
✔ turnRequest says a user's message is a granted user's and never the owner's instruction (0.277911ms)
✔ turnRequest shows the message's own sent time, a day old as well as new (0.227187ms)
✔ stateBlock names the launch state with its time and event, and the open tasks with the cap (0.334368ms)
✔ a message becomes a turn, the answer goes back as a RESULT, SIGTERM releases and exits 0 (257.255462ms)
✔ launches revoked and then restored: the turn's block reads allowed and gives the restore time (272.592717ms)
✔ a task closed on the tracker is missing from the next turn's open list (239.571073ms)
✔ a message read a day after it was sent shows the time it was sent (148.998515ms)
✔ a decision the human resolves becomes a turn citing the decision and the answer (196.043584ms)
✔ a failed state read fails the turn: no adapter runs, the sender hears why, the message is read (103.372577ms)
✔ a SIGTERM before the claim stops the runner with exit 0 and no claim (91.622163ms)
✔ typed tools carry the runner's capability; launch goes to the host's launch socket (336.226718ms)
✔ end_run, organization_revision and change_organization reach the broker with the tool's arguments, and refusals keep their codes (429.635331ms)
✔ set_name reaches the broker's name.set with the tool's arguments, and refusals keep their codes (182.337097ms)
✔ a RESULT gets no automatic reply; failed turns reply with the reason (1269.003752ms)
✔ the bus's launch notice is one turn with no reply, and is not taken again (269.091562ms)
✔ SIGTERM during a turn kills the turn's process group and still exits 0 (122.399792ms)
✔ founder credentials stop before the claim (20) (162.909348ms)
✔ a refused claim exits 21; an ended run's capability exits 22 (165.231771ms)
✔ the launch ending under a running session exits 22 (134.851141ms)
✔ a broker that stays unreachable exits 23 after brokerRetries polls (234.508622ms)
✔ a broker that is down at the claim exits 23, not 21 (78.168597ms)
✔ no capability, or a malformed one, on stdin exits 2 (194.303544ms)
✔ a missing or malformed policy exits 2 before the claim (120.576748ms)
✔ REQ-LIMIT-4 runner brackets its actual harness turn before the reply and read receipt (194.53726ms)
✔ REQ-LIMIT-4 a runner at its limit stops at the end of its turn: RESULT and read first, then exit 22 and a limit-check revoke (168.261307ms)
✔ landingRequest is the fixed template, with the decision and task ref and nothing else (0.147237ms)
✔ each landing entry is one turn before any message, with the state block and the fixed request; it sends nothing and reads nothing (226.715761ms)
✔ an empty landing takes no landing turn: the message is turn 1 (195.475495ms)
✔ a run in a landing turn isn't released for a second held decision until its landing turns end and it has read its messages (596.516739ms)
✔ a malformed landing exits 2 before the claim, with no turn (568.856934ms)
✔ row 65 a session.json without a turnEnd of marker or exit, or a harnessEnv of strings, exits 2 before the claim (269.597797ms)
✔ row 65 harnessEnv reaches the adapter, and an exit harness needs no turn marker (141.169295ms)
✔ row 66 the adapter gets the run's unslop log, and a flagged reply's note rides that reply's RESULT, once (300.426996ms)
✔ row 66 a turn with no reply holds its note for the next reply; a broken check is told once (345.164969ms)
✔ row 66 unslopNotes keeps a note until sent(), reads only whole lines, and unslopCounts reads a log after the session (1.68702ms)
✔ row 66 a clipped answer with both note parts stays under the bus's body limit, and the note under 600 (161.518813ms)
✔ row 66 a refused send keeps the note: it rides the next RESULT the session sends (264.81696ms)
✔ each repo role's prompt carries exactly its listed skills, each file as the bundle copy and the source (69.791416ms)
✔ a skill's files go into the prompt in sorted path order, sub-directories included (9.238961ms)
✔ a role with no skills gets no Skills section, no skills directory and an empty manifest list (11.39746ms)
✔ an enabled skill the role doesn't list stays out of the prompt (8.706347ms)
✔ the bundle copy outlives the source: deactivating a skill after the build leaves the run's copy (4.473957ms)
✔ a listed skill that isn't enabled refuses skill-not-enabled, naming the activate command (9.541232ms)
✔ a skill directory that isn't plain refuses: a symlinked skill, SKILL.md or sub-file, or a non-file entry (2.643822ms)
✔ a skill file that can't go into the prompt refuses: a bad name, non-UTF-8 bytes, or the end marker (3.518581ms)
✔ a role's skills over SKILL_BYTES together refuse, naming the skill that crossed it (10.193929ms)
✔ each adapter passes the skills only in the prompt file, with skill discovery off (59.00799ms)
✔ every role sees read_spec, record writer follows its grant, citation schemas stay strict (25.138022ms)
✔ typed socket forwards read content/history and agent record writes, and cannot write a spec (172.529974ms)
✔ the PM gets its task verbs and the reads, and no launch (11.972118ms)
✔ send_message offers the BLOCK class, beside the classes it already had (3.837774ms)
✔ the chief of staff gets launch, send_message, end_run, hire, fire, change_organization and set_name, and no task verbs (4.871494ms)
✔ hire and fire send instance.hire and instance.fire under role.hire and role.fire, only for a holder of the grant (22.751702ms)
✔ request_staff is the pm's alone: staff.request over message.send, roles and counts bounded (15.291362ms)
✔ end_run sends role and reason, no decision; change_organization sends revision and the organization keys (2.689052ms)
✔ set_name sends instance and name to name.set under instance.name, only for a holder of that grant (12.695737ms)
✔ the organization keys change_organization takes are the broker's ORGANIZATION_KEYS and the settings' SETTINGS_KEYS (0.178758ms)
✔ a role without role.end or organization.change gets none of the three tools, and each follows its own grant (12.115972ms)
✔ no role's tools send instances or instances.set, and change_organization takes no instance write keys (10.7825ms)
✔ the assistant gets send_message, the reads and the web tools (it holds the web grant), no launch (2.17462ms)
✔ list_requirements reads the requirement ids, for a task.create holder with a tracker (3.939398ms)
✔ a coder gets no launch, no resolve_decision, and no task tools without a tracker (3.125698ms)
✔ a coder with a tracker gets its own task tools and no task_reassign (2.258296ms)
✔ launch only when the business's launch block names the instance as launcher (3.280204ms)
✔ an action outside the instance's authority has no tool (1.994949ms)
✔ the review loop: push_working and request_review for the coder, fetch_review and review_verdict for the reviewer, none for the PM (7.387015ms)
✔ land_work is there only with land, after push_working, with the task and the decision (4.431191ms)
✔ callTool: one JSON line out, the result back, a refusal rejects (16.610729ms)
✔ list_tasks takes the broker's filters and pages; get_task takes a task_ref (4.144909ms)
✔ callTool sends list_tasks done false unless the session names done; other tools as given (3.985977ms)
✔ replyText: compact JSON up to the cap, an error naming the size and the cap over it (1.008682ms)
✔ web_search's query maxLength is the web layer's SEARCH_MAX_QUERY_CHARS (4.810935ms)
ℹ tests 172
ℹ suites 0
ℹ pass 172
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 12131.328093
@@ -1,153 +0,0 @@
npm notice run @mosaic/[email protected] test
npm notice run node --test tests/*.test.mjs
✔ C2-06 reply schema: free bodies, exact objects and safe refusal reasons (31.081491ms)
✔ C2-06 citation setting and all four exact fixed texts (27.31137ms)
✔ C2-06 default citation cap passes 20 and refuses 21, even with optional citations (144.940253ms)
✔ C2-06 real Git citation scope, reachability, lines and normalized quotes (71.988432ms)
✔ C2-06 playground cites pass but cannot state canon (42.141068ms)
✔ C2-06 independent universes refuse; a hybrid and only its sources pass (69.134397ms)
✔ C2-06 web cites require allowed definition, this session fetch and kept quote (17.090852ms)
✔ C2-06 file origin is the path commit and trailer, while last follows served changes (51.160201ms)
✔ C2-06 origin uses literal paths even when a filename contains a glob (35.841257ms)
✔ C2-06 cited-commit guard reads exactly the C2-05a indexed file set with supporting scope (79.711572ms)
✔ C2-06 reply limits fall back independently without coercion or inherited keys (0.78046ms)
✔ the same commit, repo path and mapping return the same index, and only mapped files are in it (53.330474ms)
✔ a different repo path, mapping or commit gets its own index (73.465944ms)
✔ the cache holds at most eight indexes and evicts the least recently used (93.355098ms)
✔ a failed read is not kept in the cache (19.15839ms)
✔ a missing or unchecked mapping is refused before any read (18.591276ms)
✔ a 3,000-file rebuild completes and its time is reported (3339.384537ms)
ℹ 3,000-file index rebuild: 3093 ms
✔ resolver step 1: a path from the repo root, with or without .md (2.003164ms)
✔ resolver step 2: the same path with vaultPrefix/ stripped (0.323373ms)
✔ resolver step 3: a path relative to the linking file, never above the repo root (0.278534ms)
✔ resolver step 4: a base name that matches exactly one indexed file (0.322938ms)
✔ a link into another of her repos resolves to nothing (0.213594ms)
✔ wikilink forms, embeds, and links skipped inside code (1.24016ms)
✔ only a body embed whose target has an extension other than .md, in any case, is an attachment (0.455416ms)
✔ the fixture mapping checks and comes back frozen (2.830981ms)
✔ C2-01c: a prefix inside or holding another entry's book refuses library-playground-other-universe (1.34922ms)
✔ C2-01c: a prefix equal to a book folder, or holding its own, refuses library-mapping-invalid (0.74756ms)
✔ C2-01c: universe-level prefixes lie outside every book, in a plain universe and in a hybrid with no books (1.203696ms)
✔ C2-01c: a draft takes kind, name and playground only, and comes back frozen with books [] (1.782129ms)
✔ C2-01d: supporting prefixes at book level, universe level, in a hybrid and in a draft, [] when absent (0.643444ms)
✔ C2-01d: each supporting prefix rule refuses with its code (2.880363ms)
✔ C2-01d: between the lists, a supporting prefix may equal its own playground, and a playground may hold its own supporting (0.978814ms)
✔ C2-01d: editor is optional, kept when given, and refuses anything but a plain name and email (5.417269ms)
✔ C2-01d: an accepted editor round-trips through a real git commit unchanged (22.81842ms)
✔ no playground prefix holds another, and no book folder holds another (1.309845ms)
✔ shape refusals: kind, remote, branch, unknown keys, types, manuscript, folder names (1.68793ms)
✔ C2-03a sage-2021: user is optional, kept when given, and must be a plain account name (0.986251ms)
✔ a hybrid universe is a shape the query code can take (1.4), with sources that must exist (1.600445ms)
✔ a caller-supplied fail receives the code, as business file loading will pass it (C2-04) (0.396233ms)
✔ scope comes from the path alone (design 1.2) (2.453311ms)
✔ C2-04 mirror: exact default path, bare without checkout or remote, and idempotent initialization (82.599485ms)
✔ C2-04 mirror: simultaneous creators publish one intact mirror and leave no staging paths (49.399699ms)
✔ C2-04 mirror: skipped publication accepts both coreutils statuses without removing the winner (174.577156ms)
✔ C2-04 mirror: preserve occupied directories and reject symlink ancestors and code overlaps (20.556264ms)
✔ C2-04 mirror: existing metadata accepts only bare Git plus state and the precreated lock (34.414614ms)
✔ C2-04 state: missing state is empty only while the served ref is absent (54.101069ms)
✔ C2-04 state: valid problems and sync metadata return no content and change no state bytes (57.832223ms)
✔ C2-04 state: strict keys, types, times, branch, commit and fixed R messages fail closed (158.515834ms)
✔ C2-04 state: symlink, hardlink, non-private state and missing lock refuse without replacement (57.609887ms)
✔ C2-04 file: served commit, not HEAD or a caller commit, owns the exact returned text (113.829438ms)
✔ C2-04 file: R1, R2 and R7 exclusions and never-synced mirrors cannot return file bodies (124.255784ms)
✔ C2-04 lock: a first-sync and fast-forward reader wait for a consistent pair across processes (314.221744ms)
✔ C2-04 lock: same-process waits, timeout code, callback expiry and throw release (5038.833094ms)
✔ C2-04 lock: owner death releases the kernel lock without replacing its file (54.543028ms)
✔ C2-04 lock: a missing flock binary becomes a handled refusal (49.73045ms)
✔ C2-04 lock: an unawaited scoped read drains before the lock is released (20.869629ms)
✔ the query reply cap equals the harness reply cap (1.544541ms)
✔ find is bound to its universe and refuses a call without one (70.281377ms)
✔ every result carries its scope, and playground appears only when asked for (39.878964ms)
✔ unmapped files never appear in any reply (35.123505ms)
✔ a hybrid sees its sources canon, minus exclusions, and no playground (39.679182ms)
✔ a hybrid gets a source file it can see, and not an excluded or foreign one (54.602693ms)
✔ get lists visible links both ways and drops a target another universe cannot see (50.638492ms)
✔ a long list pages by position, never cuts an item, and returns 50 per page (193.227492ms)
✔ a page stays under the reply cap when items are large (91.885035ms)
✔ a search line too long to fit alone comes back marked, with no excerpt, and the other hits still return (33.20163ms)
✔ a find item that cannot fit alone is refused, not cut (46.447292ms)
✔ get pages its lines, and the next line picks up where the page stopped (39.12526ms)
✔ get refuses a file whose front matter alone is over the cap, and a line alone is over the cap (36.804238ms)
✔ get pages the links of a hub note, every page carries the front matter, and the pages add up (1107.995321ms)
✔ get rejects a bad links_from (34.377162ms)
✔ search returns scoped line hits, case-insensitively, and refuses empty text (30.729667ms)
✔ a manuscript call returns one chapter, at most 400 lines, and names its next line (47.791378ms)
✔ a manuscript call without a chapter returns the first chapter in path order and names the next (26.366902ms)
✔ a chapter name that matches two visible files is refused (25.448584ms)
✔ a hybrid reads a source chapter through its declared sources only (39.969561ms)
✔ universe info reports a hybrid sources, constraints and notes, and refuses an unknown universe (15.657923ms)
✔ an exclusion hides what it names from a hybrid and from nothing else (39.404555ms)
✔ PRD 1.14: a lookup that names a book leaves book-null files out (34.647951ms)
✔ PRD 1.14: library_manuscript never reads a book-null file (32.637362ms)
✔ PRD 1.14: a draft universe has no canon, so its lookups return files only with scope playground (32.338176ms)
✔ PRD 1.14: library_universe on a draft returns its kind, name and prefixes (15.442774ms)
✔ a hybrid gets a source playground file as null, while the source gets it with scope playground (42.674554ms)
✔ the fixture reads clean: every resolver step, appears_in and relationships wikilinks indexed (63.033383ms)
✔ R1: executables, symlinks, gitlinks, blobs over 1 MiB and non-UTF-8 text are not indexed (95.339567ms)
✔ R2: unmapped paths are reported and not indexed (31.564751ms)
✔ R3: front matter not fully parsed stays raw, with the line where parsing stopped (36.896696ms)
✔ front matter forms the reader accepts and refuses (1.596508ms)
✔ R4: a link to no file, to more than one, or into another repo is reported and not followed (35.504393ms)
✔ a block list link carries its item line, a scalar or flow link its key line, and problems follow (37.229678ms)
✔ an unresolved attachment embed gives no problem; a link or front matter value to one is R4; a note embed resolves (33.783255ms)
✔ an indexed Dr.Quinn.md resolves as a body link, a block list link and an embed (33.230236ms)
✔ R5: a canon file that refers into the playground is reported, and the link still goes by path (29.709099ms)
✔ R6: a canon file that refers into another universe is reported; a hybrid may refer into its sources (30.970646ms)
✔ R7: two paths that differ only in case are both left out (41.126208ms)
✔ the reader reads the commit, never the working tree, and refuses a bad commit id (41.98282ms)
✔ a bare mirror reads the same as the clone (53.445984ms)
✔ renderItems snapshot: fact (1.786386ms)
✔ renderItems snapshot: finding (0.299155ms)
✔ renderItems snapshot: correction (0.259329ms)
✔ renderItems snapshot: question (0.218182ms)
✔ renderItems snapshot: idea (0.223821ms)
✔ renderItems numbers several items and takes a parsed body as well as a string (1.090019ms)
✔ without options a path cite has no badge and is never marked changed (0.280013ms)
✔ renderItems snapshot: notice no-cited-answer (0.237711ms)
✔ renderItems snapshot: notice no-answer (0.198705ms)
✔ renderItems snapshot: notice turn-failed (0.337126ms)
✔ a body without the reply shape shows a fixed line and none of its text (0.613863ms)
✔ C2-01c: each level gives its universe, and its book or null (4.092943ms)
✔ C2-01c: prefixes come first: in a book that holds a prefix, a file outside it is canon and one under it playground (0.607188ms)
✔ C2-01c: a canon file linking into a draft gives R6, and into its own universe-level prefix gives R5 (65.023589ms)
✔ C2-01d: each supporting level gives its universe, and its book or null (0.8244ms)
✔ C2-01d: supporting comes before playground; a folder in both lists is supporting, one in the playground only stays playground (0.633065ms)
✔ C2-01d: only .md files are supporting; a .canvas or .base under a supporting prefix is unmapped (0.517375ms)
✔ C2-01d: a path passes at book level, universe level, in a draft and in a folder in both lists (2.312377ms)
✔ C2-01d: a path of exactly 1024 bytes passes, and 1025 bytes made of multi-byte characters refuses (0.98988ms)
✔ C2-01d: a path outside the universe's supporting folders refuses (0.763326ms)
✔ C2-01d: malformed paths refuse by class, in order (0.710036ms)
✔ C2-01d: a symlink or gitlink on the way, or at the path itself, refuses (0.383033ms)
✔ C2-01d: a name that differs from a tree name only in case or Unicode form refuses, at the file or any folder (0.99427ms)
✔ the survey prints folder names, counts, key sets and link-form counts, and never text (65.469359ms)
✔ folder names print DEL, C1 and bidi controls, U+061C among them, as escapes (37.571162ms)
✔ an embed of an attachment counts as an embed and as an attachment; a plain link to one does not (24.053267ms)
✔ with --mapping the survey adds scope, resolver step and problem counts (51.551822ms)
✔ C2-01d: with --mapping the survey counts supporting files (49.232972ms)
✔ survey exit codes: usage 4, bad mapping 3, unreadable repo 2 (19.679523ms)
✔ scripts/mosaic library survey reaches the survey (97.237921ms)
✔ C2-03a argv: the fixed sequence, one https allow, no other protocol key (2.539459ms)
✔ C2-03a argv: only an https URL with a plain host, no userinfo, and a plain user (1.147619ms)
✔ C2-03a helper: answers only the exact prompts for the configured host and user (dewey-0765) (43.662638ms)
✔ C2-03a first sync: served is the fetched tip, HEAD is served, the survey reads it, and the token stays in the slot (199.624214ms)
✔ C2-03a fast-forward: served moves, problems are rebuilt, and a repeat changes only lastFetch (272.12795ms)
✔ C2-03a Filbert N2: a read that took served before a sync still finds its objects after served moves (255.892244ms)
✔ C2-03a overlap: a reader during a sync sees the old pair or the new one, never a mix (220.077465ms)
✔ C2-03a diverged: a non-fast-forward keeps serving and holds until a human accepts the tip (511.485441ms)
✔ C2-03a accept starts the record over, so a changed branch gets a fresh state (204.895458ms)
✔ C2-03a fetch failure: a wrong token keeps serving and records the error, lastFetch unchanged (210.171392ms)
✔ C2-03a a failed first fetch records the error with nothing served (57.52009ms)
✔ C2-03a a 302 to another host fails the fetch and the other host sees nothing (68.211135ms)
✔ C2-03a the slot: missing or unsafe refuses before git, and sync never opens it (65.636096ms)
✔ C2-03a sage-2021: an entry with no user refuses library-remote-invalid and runs no git (34.004871ms)
✔ C2-03a one sync per mirror: an overlapping call refuses library-sync-busy (129.134012ms)
ℹ tests 142
ℹ suites 0
ℹ pass 142
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 6490.060843
@@ -1,2 +0,0 @@
1 match: replyLimitsFence(old, document, actor);
1 match: replyLimitsFence(old, written, actor);
@@ -1 +0,0 @@
M5-hide-library-unavailable: killed (control green, mutant exit 1, hashes restored, restored green)
@@ -1,11 +0,0 @@
✔ C2-06 held library lock gives the agent citation-unavailable and its retry reason (5151.319291ms)
✔ C2-06 malformed sync state is availability failure, never a fabricated invalid cite (37.53806ms)
✔ C2-06 no mirror or freshly initialized empty mirror still means no served citation (35.257703ms)
ℹ tests 3
ℹ suites 0
ℹ pass 3
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 5310.30031
@@ -1,11 +0,0 @@
✔ C2-06 held library lock gives the agent citation-unavailable and its retry reason (5147.642347ms)
✔ C2-06 malformed sync state is availability failure, never a fabricated invalid cite (32.256875ms)
✔ C2-06 no mirror or freshly initialized empty mirror still means no served citation (31.701926ms)
ℹ tests 3
ℹ suites 0
ℹ pass 3
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 5295.499085
@@ -1,23 +0,0 @@
eeca81ab965f9e94f930ee5f51d16f019af6368bc6c3994895e204f7a54ec8d2 packages/bus/src/broker.mjs
ad3c686a089f67f3c89610937c6fc9b32367cea5d9735125d89bef042082d4e8 packages/bus/src/client.mjs
36b05dd3119e5929211aa1cc5d45c5043f5a1c34567ddc7cac8f002835d44abe packages/bus/src/runtime.mjs
66b26d131a19f4f411686427274936850c1ff0aed11e9b281ae4aadcf4b289fc packages/bus/src/server.mjs
cdd0304ec25ef1ad3e31c52502fa46f2c80bd77c8d3c2e13f8ed4b5328f342c9 packages/bus/tests/citation-availability.test.mjs
2e05074cd9d15d810103658af3858161cee2af78b0a2e1ba910222fab3e84401 packages/bus/tests/citation-guard.test.mjs
2c7a2102e2e0244876e41b664f4f706baefe3375100b956655551db1230f5da3 packages/bus/tests/citation-helpers.mjs
168dcac99d9bfdfdf5ff0eaa2c0fff91595b351b4d0092dc299532c9c32869f0 packages/bus/tests/citation-runtime.test.mjs
abaeac64f2c3bf8ba83c9a4488edd9105c4707a6564560c5333d5421445653af packages/business/src/business.mjs
3a6044de5d1ca2cc35c5285b460c3e402b4274837e5d88b97f489797f6004903 packages/business/src/organization.mjs
4d2eb11beaa80175e524af1b95c81e7164990fba1d3e1754f5ba06eee390a14f packages/business/tests/reply-limits.test.mjs
a2bb98734bcc2556f8b2168f0faf8a89f7064c3f0aa49feb7d1975d596192f09 packages/cli/README.md
2f291a71f490f2741edada7a3e3788500f8976a08eb8ab1411f6c5982f778260 packages/cli/src/limits.mjs
f38af2d46d5f5f6388f599912507b94b87a0bf9dcc2104bb2187c38ee35118d5 packages/cli/tests/reply-limits.test.mjs
6ad72b4245e0a66e32725941900c1ece64c2e5de2fb73d65c8e042b4f3a691a6 packages/harness/src/runner.mjs
a5ef1b65230239a7baf6d0e8f2b8a51c0516348c7c4339a55b3f0a1a6ff531ba packages/harness/tests/citation-runner.test.mjs
330bc71bf6c7e64d3ddb70440903d2d9acf7878d44a49d7e30c2352ee4c807ec packages/harness/tests/fixtures/citation-adapter.mjs
f710d9600a17f6e2989a289cfe84e58f161d86c7306605946ce05fa71b364eb2 packages/library/src/guard.mjs
c0d630798914e300e461c247340533328e97119e54909c6a9406340e61fed8b7 packages/library/src/index.mjs
98ef45ed61144aaea44d8aea1ac43082b6d340297e46846d01772da38728e530 packages/library/src/limits.mjs
7b46f47b5e9d6b554b5d39bce2cd95c4610f5f35b8ab8fdc5a2864b3214be809 packages/library/src/reply-protocol.mjs
406146ebbce3710f308243b684a1c17e7626c1b65a4468489364317e31537a48 packages/library/tests/guard.test.mjs
39c8e6c8250a13fa43015fb2c407195e30ee642f729a9f6a644c38b4ea758a72 packages/seat/src/sandbox.mjs
@@ -1,68 +0,0 @@
✖ C2-06 held library lock gives the agent citation-unavailable and its retry reason (5108.905478ms)
✖ C2-06 malformed sync state is availability failure, never a fabricated invalid cite (40.518617ms)
✔ C2-06 no mirror or freshly initialized empty mirror still means no served citation (37.68422ms)
ℹ tests 3
ℹ suites 0
ℹ pass 1
ℹ fail 2
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 5261.169843
✖ failing tests:
test at packages/bus/tests/citation-availability.test.mjs:13:1
✖ C2-06 held library lock gives the agent citation-unavailable and its retry reason (5108.905478ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
+ actual - expected
+ 'citation-invalid'
- 'citation-unavailable'
^
at Object.<anonymous> (file:///mnt/storage/scratch/tmp/tNoueZ/row217-mutant-pd3x2htc/packages/bus/tests/citation-availability.test.mjs:29:14)
at expectedException (node:assert:547:17)
at expectsError (node:assert:672:21)
at strict.rejects (node:assert:738:3)
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
at async file:///mnt/storage/scratch/tmp/tNoueZ/row217-mutant-pd3x2htc/packages/bus/tests/citation-availability.test.mjs:28:5
at async withLibraryLock (file:///mnt/storage/scratch/tmp/tNoueZ/row217-mutant-pd3x2htc/packages/library/src/mirror.mjs:171:18)
at async TestContext.<anonymous> (file:///mnt/storage/scratch/tmp/tNoueZ/row217-mutant-pd3x2htc/packages/bus/tests/citation-availability.test.mjs:27:3)
at async Test.run (node:internal/test_runner/test:1409:7)
at async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: 'citation-invalid',
expected: 'citation-unavailable',
operator: 'strictEqual',
diff: 'simple'
}
test at packages/bus/tests/citation-availability.test.mjs:40:1
✖ C2-06 malformed sync state is availability failure, never a fabricated invalid cite (40.518617ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
+ actual - expected
Comparison {
+ code: 'citation-invalid'
- code: 'citation-unavailable'
}
at async TestContext.<anonymous> (file:///mnt/storage/scratch/tmp/tNoueZ/row217-mutant-pd3x2htc/packages/bus/tests/citation-availability.test.mjs:45:3)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: Error: citation-invalid: citation 1 (Book One/Characters/Mara Vell.md) isn't an indexed file at a commit reachable from the served commit
at refuse (file:///mnt/storage/scratch/tmp/tNoueZ/row217-mutant-pd3x2htc/packages/library/src/guard.mjs:24:42)
at checkReply (file:///mnt/storage/scratch/tmp/tNoueZ/row217-mutant-pd3x2htc/packages/library/src/guard.mjs:80:25)
at async waitForActual (node:assert:615:5)
at async strict.rejects (node:assert:738:25)
at async TestContext.<anonymous> (file:///mnt/storage/scratch/tmp/tNoueZ/row217-mutant-pd3x2htc/packages/bus/tests/citation-availability.test.mjs:45:3)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7),
expected: { code: 'citation-unavailable' },
operator: 'rejects',
diff: 'simple'
}
@@ -1 +0,0 @@
M5-hide-library-unavailable: killed (control green, mutant exit 1, hashes restored, restored green)
@@ -1,5 +0,0 @@
M1-writer-fence: killed (control green, mutant exit 1, hashes restored, restored green)
M2-incoming-human: killed (control green, mutant exit 1, hashes restored, restored green)
M3-split-check-transaction: killed (control green, mutant exit 1, hashes restored, restored green)
M5-hide-library-unavailable: killed (control green, mutant exit 1, hashes restored, restored green)
M4-drop-client-reason: killed (control green, mutant exit 1, hashes restored, restored green)
@@ -1,14 +0,0 @@
✔ C2-06 M11 human replacement works; omitted settings return to defaults (29.278355ms)
✔ C2-06 M11 agents and tester cannot change settings, including by changing human (22.040025ms)
✔ C2-06 M11 serialization cannot replace settings after the first fence (8.805323ms)
✔ C2-06 M11 an unrelated actor cannot appoint itself human and change reply limits (8.829275ms)
✔ C2-06 invalid setter values preserve the business and changes.jsonl (9.171416ms)
✔ C2-06 validator accepts hand-edited settings; raw reader fails closed on invalid files (10.423621ms)
ℹ tests 6
ℹ suites 0
ℹ pass 6
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 139.016448
@@ -1,14 +0,0 @@
✔ C2-06 M11 human replacement works; omitted settings return to defaults (27.397407ms)
✔ C2-06 M11 agents and tester cannot change settings, including by changing human (23.565905ms)
✔ C2-06 M11 serialization cannot replace settings after the first fence (8.312613ms)
✔ C2-06 M11 an unrelated actor cannot appoint itself human and change reply limits (8.050944ms)
✔ C2-06 invalid setter values preserve the business and changes.jsonl (8.746752ms)
✔ C2-06 validator accepts hand-edited settings; raw reader fails closed on invalid files (11.061782ms)
ℹ tests 6
ℹ suites 0
ℹ pass 6
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 137.787038
@@ -1,23 +0,0 @@
eeca81ab965f9e94f930ee5f51d16f019af6368bc6c3994895e204f7a54ec8d2 packages/bus/src/broker.mjs
ad3c686a089f67f3c89610937c6fc9b32367cea5d9735125d89bef042082d4e8 packages/bus/src/client.mjs
36b05dd3119e5929211aa1cc5d45c5043f5a1c34567ddc7cac8f002835d44abe packages/bus/src/runtime.mjs
66b26d131a19f4f411686427274936850c1ff0aed11e9b281ae4aadcf4b289fc packages/bus/src/server.mjs
cdd0304ec25ef1ad3e31c52502fa46f2c80bd77c8d3c2e13f8ed4b5328f342c9 packages/bus/tests/citation-availability.test.mjs
2e05074cd9d15d810103658af3858161cee2af78b0a2e1ba910222fab3e84401 packages/bus/tests/citation-guard.test.mjs
2c7a2102e2e0244876e41b664f4f706baefe3375100b956655551db1230f5da3 packages/bus/tests/citation-helpers.mjs
9768b6dc5ae078c5cc4f76473097287b74c5bc5853d39e1f57f153e646f861af packages/bus/tests/citation-runtime.test.mjs
abaeac64f2c3bf8ba83c9a4488edd9105c4707a6564560c5333d5421445653af packages/business/src/business.mjs
3a6044de5d1ca2cc35c5285b460c3e402b4274837e5d88b97f489797f6004903 packages/business/src/organization.mjs
4d2eb11beaa80175e524af1b95c81e7164990fba1d3e1754f5ba06eee390a14f packages/business/tests/reply-limits.test.mjs
a2bb98734bcc2556f8b2168f0faf8a89f7064c3f0aa49feb7d1975d596192f09 packages/cli/README.md
2f291a71f490f2741edada7a3e3788500f8976a08eb8ab1411f6c5982f778260 packages/cli/src/limits.mjs
f38af2d46d5f5f6388f599912507b94b87a0bf9dcc2104bb2187c38ee35118d5 packages/cli/tests/reply-limits.test.mjs
6ad72b4245e0a66e32725941900c1ece64c2e5de2fb73d65c8e042b4f3a691a6 packages/harness/src/runner.mjs
a5ef1b65230239a7baf6d0e8f2b8a51c0516348c7c4339a55b3f0a1a6ff531ba packages/harness/tests/citation-runner.test.mjs
330bc71bf6c7e64d3ddb70440903d2d9acf7878d44a49d7e30c2352ee4c807ec packages/harness/tests/fixtures/citation-adapter.mjs
f710d9600a17f6e2989a289cfe84e58f161d86c7306605946ce05fa71b364eb2 packages/library/src/guard.mjs
c0d630798914e300e461c247340533328e97119e54909c6a9406340e61fed8b7 packages/library/src/index.mjs
98ef45ed61144aaea44d8aea1ac43082b6d340297e46846d01772da38728e530 packages/library/src/limits.mjs
7b46f47b5e9d6b554b5d39bce2cd95c4610f5f35b8ab8fdc5a2864b3214be809 packages/library/src/reply-protocol.mjs
406146ebbce3710f308243b684a1c17e7626c1b65a4468489364317e31537a48 packages/library/tests/guard.test.mjs
39c8e6c8250a13fa43015fb2c407195e30ee642f729a9f6a644c38b4ea758a72 packages/seat/src/sandbox.mjs
@@ -1,73 +0,0 @@
✔ C2-06 M11 human replacement works; omitted settings return to defaults (26.703775ms)
✖ C2-06 M11 agents and tester cannot change settings, including by changing human (12.156717ms)
✖ C2-06 M11 serialization cannot replace settings after the first fence (11.431272ms)
✖ C2-06 M11 an unrelated actor cannot appoint itself human and change reply limits (14.308135ms)
✔ C2-06 invalid setter values preserve the business and changes.jsonl (9.043165ms)
✔ C2-06 validator accepts hand-edited settings; raw reader fails closed on invalid files (9.576698ms)
ℹ tests 6
ℹ suites 0
ℹ pass 3
ℹ fail 3
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 131.91294
✖ failing tests:
test at packages/business/tests/reply-limits.test.mjs:34:1
✖ C2-06 M11 agents and tester cannot change settings, including by changing human (12.156717ms)
AssertionError [ERR_ASSERTION]: Missing expected exception.
at refused (file:///mnt/storage/scratch/tmp/tNoueZ/row217-mutant-m6rnq3wd/packages/business/tests/reply-limits.test.mjs:22:10)
at TestContext.<anonymous> (file:///mnt/storage/scratch/tmp/tNoueZ/row217-mutant-m6rnq3wd/packages/business/tests/reply-limits.test.mjs:37:5)
at Test.runInAsyncScope (node:async_hooks:226:14)
at Test.run (node:internal/test_runner/test:1402:25)
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
at Test.postRun (node:internal/test_runner/test:1542:19)
at Test.run (node:internal/test_runner/test:1467:12)
at async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3) {
generatedMessage: false,
code: 'ERR_ASSERTION',
actual: undefined,
expected: { code: 'organization-reply-limits-human-only' },
operator: 'throws',
diff: 'simple'
}
test at packages/business/tests/reply-limits.test.mjs:43:1
✖ C2-06 M11 serialization cannot replace settings after the first fence (11.431272ms)
AssertionError [ERR_ASSERTION]: Missing expected exception.
at refused (file:///mnt/storage/scratch/tmp/tNoueZ/row217-mutant-m6rnq3wd/packages/business/tests/reply-limits.test.mjs:22:10)
at TestContext.<anonymous> (file:///mnt/storage/scratch/tmp/tNoueZ/row217-mutant-m6rnq3wd/packages/business/tests/reply-limits.test.mjs:45:3)
at Test.runInAsyncScope (node:async_hooks:226:14)
at Test.run (node:internal/test_runner/test:1402:25)
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
at Test.postRun (node:internal/test_runner/test:1542:19)
at Test.run (node:internal/test_runner/test:1467:12)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
generatedMessage: false,
code: 'ERR_ASSERTION',
actual: undefined,
expected: { code: 'organization-reply-limits-human-only' },
operator: 'throws',
diff: 'simple'
}
test at packages/business/tests/reply-limits.test.mjs:52:1
✖ C2-06 M11 an unrelated actor cannot appoint itself human and change reply limits (14.308135ms)
AssertionError [ERR_ASSERTION]: Missing expected exception.
at refused (file:///mnt/storage/scratch/tmp/tNoueZ/row217-mutant-m6rnq3wd/packages/business/tests/reply-limits.test.mjs:22:10)
at TestContext.<anonymous> (file:///mnt/storage/scratch/tmp/tNoueZ/row217-mutant-m6rnq3wd/packages/business/tests/reply-limits.test.mjs:54:3)
at Test.runInAsyncScope (node:async_hooks:226:14)
at Test.run (node:internal/test_runner/test:1402:25)
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
at Test.postRun (node:internal/test_runner/test:1542:19)
at Test.run (node:internal/test_runner/test:1467:12)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
generatedMessage: false,
code: 'ERR_ASSERTION',
actual: undefined,
expected: { code: 'organization-reply-limits-human-only' },
operator: 'throws',
diff: 'simple'
}
@@ -1,14 +0,0 @@
✔ C2-06 M11 human replacement works; omitted settings return to defaults (31.955623ms)
✔ C2-06 M11 agents and tester cannot change settings, including by changing human (22.832309ms)
✔ C2-06 M11 serialization cannot replace settings after the first fence (9.274775ms)
✔ C2-06 M11 an unrelated actor cannot appoint itself human and change reply limits (8.69039ms)
✔ C2-06 invalid setter values preserve the business and changes.jsonl (8.733202ms)
✔ C2-06 validator accepts hand-edited settings; raw reader fails closed on invalid files (10.441869ms)
ℹ tests 6
ℹ suites 0
ℹ pass 6
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 143.570268
@@ -1,14 +0,0 @@
✔ C2-06 M11 human replacement works; omitted settings return to defaults (29.948602ms)
✔ C2-06 M11 agents and tester cannot change settings, including by changing human (22.139351ms)
✔ C2-06 M11 serialization cannot replace settings after the first fence (9.054641ms)
✔ C2-06 M11 an unrelated actor cannot appoint itself human and change reply limits (8.381635ms)
✔ C2-06 invalid setter values preserve the business and changes.jsonl (9.081946ms)
✔ C2-06 validator accepts hand-edited settings; raw reader fails closed on invalid files (10.33004ms)
ℹ tests 6
ℹ suites 0
ℹ pass 6
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 141.370383
@@ -1,23 +0,0 @@
eeca81ab965f9e94f930ee5f51d16f019af6368bc6c3994895e204f7a54ec8d2 packages/bus/src/broker.mjs
ad3c686a089f67f3c89610937c6fc9b32367cea5d9735125d89bef042082d4e8 packages/bus/src/client.mjs
36b05dd3119e5929211aa1cc5d45c5043f5a1c34567ddc7cac8f002835d44abe packages/bus/src/runtime.mjs
66b26d131a19f4f411686427274936850c1ff0aed11e9b281ae4aadcf4b289fc packages/bus/src/server.mjs
cdd0304ec25ef1ad3e31c52502fa46f2c80bd77c8d3c2e13f8ed4b5328f342c9 packages/bus/tests/citation-availability.test.mjs
2e05074cd9d15d810103658af3858161cee2af78b0a2e1ba910222fab3e84401 packages/bus/tests/citation-guard.test.mjs
2c7a2102e2e0244876e41b664f4f706baefe3375100b956655551db1230f5da3 packages/bus/tests/citation-helpers.mjs
9768b6dc5ae078c5cc4f76473097287b74c5bc5853d39e1f57f153e646f861af packages/bus/tests/citation-runtime.test.mjs
abaeac64f2c3bf8ba83c9a4488edd9105c4707a6564560c5333d5421445653af packages/business/src/business.mjs
3a6044de5d1ca2cc35c5285b460c3e402b4274837e5d88b97f489797f6004903 packages/business/src/organization.mjs
4d2eb11beaa80175e524af1b95c81e7164990fba1d3e1754f5ba06eee390a14f packages/business/tests/reply-limits.test.mjs
a2bb98734bcc2556f8b2168f0faf8a89f7064c3f0aa49feb7d1975d596192f09 packages/cli/README.md
2f291a71f490f2741edada7a3e3788500f8976a08eb8ab1411f6c5982f778260 packages/cli/src/limits.mjs
f38af2d46d5f5f6388f599912507b94b87a0bf9dcc2104bb2187c38ee35118d5 packages/cli/tests/reply-limits.test.mjs
6ad72b4245e0a66e32725941900c1ece64c2e5de2fb73d65c8e042b4f3a691a6 packages/harness/src/runner.mjs
a5ef1b65230239a7baf6d0e8f2b8a51c0516348c7c4339a55b3f0a1a6ff531ba packages/harness/tests/citation-runner.test.mjs
330bc71bf6c7e64d3ddb70440903d2d9acf7878d44a49d7e30c2352ee4c807ec packages/harness/tests/fixtures/citation-adapter.mjs
f710d9600a17f6e2989a289cfe84e58f161d86c7306605946ce05fa71b364eb2 packages/library/src/guard.mjs
c0d630798914e300e461c247340533328e97119e54909c6a9406340e61fed8b7 packages/library/src/index.mjs
98ef45ed61144aaea44d8aea1ac43082b6d340297e46846d01772da38728e530 packages/library/src/limits.mjs
7b46f47b5e9d6b554b5d39bce2cd95c4610f5f35b8ab8fdc5a2864b3214be809 packages/library/src/reply-protocol.mjs
406146ebbce3710f308243b684a1c17e7626c1b65a4468489364317e31537a48 packages/library/tests/guard.test.mjs
39c8e6c8250a13fa43015fb2c407195e30ee642f729a9f6a644c38b4ea758a72 packages/seat/src/sandbox.mjs
@@ -1,35 +0,0 @@
✔ C2-06 M11 human replacement works; omitted settings return to defaults (28.334896ms)
✔ C2-06 M11 agents and tester cannot change settings, including by changing human (22.541196ms)
✔ C2-06 M11 serialization cannot replace settings after the first fence (8.304131ms)
✖ C2-06 M11 an unrelated actor cannot appoint itself human and change reply limits (11.712463ms)
✔ C2-06 invalid setter values preserve the business and changes.jsonl (8.875517ms)
✔ C2-06 validator accepts hand-edited settings; raw reader fails closed on invalid files (9.882976ms)
ℹ tests 6
ℹ suites 0
ℹ pass 5
ℹ fail 1
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 140.418146
✖ failing tests:
test at packages/business/tests/reply-limits.test.mjs:52:1
✖ C2-06 M11 an unrelated actor cannot appoint itself human and change reply limits (11.712463ms)
AssertionError [ERR_ASSERTION]: Missing expected exception.
at refused (file:///mnt/storage/scratch/tmp/tNoueZ/row217-mutant-_aqjby1c/packages/business/tests/reply-limits.test.mjs:22:10)
at TestContext.<anonymous> (file:///mnt/storage/scratch/tmp/tNoueZ/row217-mutant-_aqjby1c/packages/business/tests/reply-limits.test.mjs:54:3)
at Test.runInAsyncScope (node:async_hooks:226:14)
at Test.run (node:internal/test_runner/test:1402:25)
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
at Test.postRun (node:internal/test_runner/test:1542:19)
at Test.run (node:internal/test_runner/test:1467:12)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
generatedMessage: false,
code: 'ERR_ASSERTION',
actual: undefined,
expected: { code: 'organization-reply-limits-human-only' },
operator: 'throws',
diff: 'simple'
}
@@ -1,21 +0,0 @@
✔ C2-06 coder send_message guard covers every table refusal; inserts nothing (118.943843ms)
✔ C2-06 research send_message guard covers every table refusal; inserts nothing (94.790271ms)
✔ C2-06 stored check carries the file author trailer at an unrelated cited tip (65.901789ms)
✔ C2-06 supporting cite cannot state canon, including a folder also marked playground (41.908138ms)
✔ C2-06 supporting file stores supporting scope and its real agent trailer (48.179621ms)
✔ C2-06 check evidence and insert are atomic when storing evidence fails (41.94764ms)
✔ C2-06 live limits change both directions; unreadable file keeps checks and exact fixed texts (56.521104ms)
✔ C2-06 page store is session-local, caps 20 fetches and 200 KiB, drops at disconnect (88.283371ms)
✔ C2-06 transport passes safe capped guard reason; ordinary refusal envelope is byte-identical (55.47311ms)
✔ C2-06 non-library businesses retain role.claim shape and unguarded free sends (26.321347ms)
✔ C2-06 thread messages carry file/last evidence with one read per distinct path (77.5591ms)
✔ C2-06 guarded request snapshot cannot change between check and insert (24.639839ms)
✔ C2-06 library.limits.set is human-only and invalid settings leave file and receipts unchanged (42.159103ms)
ℹ tests 13
ℹ suites 0
ℹ pass 13
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 866.146033
@@ -1,21 +0,0 @@
✔ C2-06 coder send_message guard covers every table refusal; inserts nothing (162.15169ms)
✔ C2-06 research send_message guard covers every table refusal; inserts nothing (151.110586ms)
✔ C2-06 stored check carries the file author trailer at an unrelated cited tip (100.984805ms)
✔ C2-06 supporting cite cannot state canon, including a folder also marked playground (81.389166ms)
✔ C2-06 supporting file stores supporting scope and its real agent trailer (92.148118ms)
✔ C2-06 check evidence and insert are atomic when storing evidence fails (78.197117ms)
✔ C2-06 live limits change both directions; unreadable file keeps checks and exact fixed texts (168.055107ms)
✔ C2-06 page store is session-local, caps 20 fetches and 200 KiB, drops at disconnect (271.850306ms)
✔ C2-06 transport passes safe capped guard reason; ordinary refusal envelope is byte-identical (92.491602ms)
✔ C2-06 non-library businesses retain role.claim shape and unguarded free sends (61.315017ms)
✔ C2-06 thread messages carry file/last evidence with one read per distinct path (126.633466ms)
✔ C2-06 guarded request snapshot cannot change between check and insert (61.436932ms)
✔ C2-06 library.limits.set is human-only and invalid settings leave file and receipts unchanged (118.486786ms)
ℹ tests 13
ℹ suites 0
ℹ pass 13
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 1649.634687
@@ -1,23 +0,0 @@
eeca81ab965f9e94f930ee5f51d16f019af6368bc6c3994895e204f7a54ec8d2 packages/bus/src/broker.mjs
ad3c686a089f67f3c89610937c6fc9b32367cea5d9735125d89bef042082d4e8 packages/bus/src/client.mjs
36b05dd3119e5929211aa1cc5d45c5043f5a1c34567ddc7cac8f002835d44abe packages/bus/src/runtime.mjs
66b26d131a19f4f411686427274936850c1ff0aed11e9b281ae4aadcf4b289fc packages/bus/src/server.mjs
cdd0304ec25ef1ad3e31c52502fa46f2c80bd77c8d3c2e13f8ed4b5328f342c9 packages/bus/tests/citation-availability.test.mjs
2e05074cd9d15d810103658af3858161cee2af78b0a2e1ba910222fab3e84401 packages/bus/tests/citation-guard.test.mjs
2c7a2102e2e0244876e41b664f4f706baefe3375100b956655551db1230f5da3 packages/bus/tests/citation-helpers.mjs
9768b6dc5ae078c5cc4f76473097287b74c5bc5853d39e1f57f153e646f861af packages/bus/tests/citation-runtime.test.mjs
abaeac64f2c3bf8ba83c9a4488edd9105c4707a6564560c5333d5421445653af packages/business/src/business.mjs
3a6044de5d1ca2cc35c5285b460c3e402b4274837e5d88b97f489797f6004903 packages/business/src/organization.mjs
4d2eb11beaa80175e524af1b95c81e7164990fba1d3e1754f5ba06eee390a14f packages/business/tests/reply-limits.test.mjs
a2bb98734bcc2556f8b2168f0faf8a89f7064c3f0aa49feb7d1975d596192f09 packages/cli/README.md
2f291a71f490f2741edada7a3e3788500f8976a08eb8ab1411f6c5982f778260 packages/cli/src/limits.mjs
f38af2d46d5f5f6388f599912507b94b87a0bf9dcc2104bb2187c38ee35118d5 packages/cli/tests/reply-limits.test.mjs
6ad72b4245e0a66e32725941900c1ece64c2e5de2fb73d65c8e042b4f3a691a6 packages/harness/src/runner.mjs
a5ef1b65230239a7baf6d0e8f2b8a51c0516348c7c4339a55b3f0a1a6ff531ba packages/harness/tests/citation-runner.test.mjs
330bc71bf6c7e64d3ddb70440903d2d9acf7878d44a49d7e30c2352ee4c807ec packages/harness/tests/fixtures/citation-adapter.mjs
f710d9600a17f6e2989a289cfe84e58f161d86c7306605946ce05fa71b364eb2 packages/library/src/guard.mjs
c0d630798914e300e461c247340533328e97119e54909c6a9406340e61fed8b7 packages/library/src/index.mjs
98ef45ed61144aaea44d8aea1ac43082b6d340297e46846d01772da38728e530 packages/library/src/limits.mjs
7b46f47b5e9d6b554b5d39bce2cd95c4610f5f35b8ab8fdc5a2864b3214be809 packages/library/src/reply-protocol.mjs
406146ebbce3710f308243b684a1c17e7626c1b65a4468489364317e31537a48 packages/library/tests/guard.test.mjs
39c8e6c8250a13fa43015fb2c407195e30ee642f729a9f6a644c38b4ea758a72 packages/seat/src/sandbox.mjs
@@ -1,41 +0,0 @@
✔ C2-06 coder send_message guard covers every table refusal; inserts nothing (121.738375ms)
✔ C2-06 research send_message guard covers every table refusal; inserts nothing (94.199334ms)
✔ C2-06 stored check carries the file author trailer at an unrelated cited tip (59.307121ms)
✔ C2-06 supporting cite cannot state canon, including a folder also marked playground (41.252933ms)
✔ C2-06 supporting file stores supporting scope and its real agent trailer (48.700382ms)
✖ C2-06 check evidence and insert are atomic when storing evidence fails (42.434516ms)
✔ C2-06 live limits change both directions; unreadable file keeps checks and exact fixed texts (56.552861ms)
✔ C2-06 page store is session-local, caps 20 fetches and 200 KiB, drops at disconnect (88.426285ms)
✔ C2-06 transport passes safe capped guard reason; ordinary refusal envelope is byte-identical (54.352185ms)
✔ C2-06 non-library businesses retain role.claim shape and unguarded free sends (26.064514ms)
✔ C2-06 thread messages carry file/last evidence with one read per distinct path (81.176348ms)
✔ C2-06 guarded request snapshot cannot change between check and insert (25.324993ms)
✔ C2-06 library.limits.set is human-only and invalid settings leave file and receipts unchanged (42.147552ms)
ℹ tests 13
ℹ suites 0
ℹ pass 12
ℹ fail 1
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 872.02572
✖ failing tests:
test at packages/bus/tests/citation-guard.test.mjs:71:1
✖ C2-06 check evidence and insert are atomic when storing evidence fails (42.434516ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
1 !== 0
at TestContext.<anonymous> (file:///mnt/storage/scratch/tmp/tNoueZ/row217-mutant-etkv3bqf/packages/bus/tests/citation-guard.test.mjs:76:10)
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: 1,
expected: 0,
operator: 'strictEqual',
diff: 'simple'
}
@@ -1,21 +0,0 @@
✔ C2-06 coder send_message guard covers every table refusal; inserts nothing (107.311079ms)
✔ C2-06 research send_message guard covers every table refusal; inserts nothing (92.235404ms)
✔ C2-06 stored check carries the file author trailer at an unrelated cited tip (59.017311ms)
✔ C2-06 supporting cite cannot state canon, including a folder also marked playground (41.107066ms)
✔ C2-06 supporting file stores supporting scope and its real agent trailer (47.696908ms)
✔ C2-06 check evidence and insert are atomic when storing evidence fails (41.214066ms)
✔ C2-06 live limits change both directions; unreadable file keeps checks and exact fixed texts (54.665908ms)
✔ C2-06 page store is session-local, caps 20 fetches and 200 KiB, drops at disconnect (86.001777ms)
✔ C2-06 transport passes safe capped guard reason; ordinary refusal envelope is byte-identical (55.168942ms)
✔ C2-06 non-library businesses retain role.claim shape and unguarded free sends (26.744539ms)
✔ C2-06 thread messages carry file/last evidence with one read per distinct path (79.212003ms)
✔ C2-06 guarded request snapshot cannot change between check and insert (24.722314ms)
✔ C2-06 library.limits.set is human-only and invalid settings leave file and receipts unchanged (41.933148ms)
ℹ tests 13
ℹ suites 0
ℹ pass 13
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 841.716764
@@ -1,21 +0,0 @@
✔ C2-06 coder send_message guard covers every table refusal; inserts nothing (110.781773ms)
✔ C2-06 research send_message guard covers every table refusal; inserts nothing (91.548051ms)
✔ C2-06 stored check carries the file author trailer at an unrelated cited tip (57.119223ms)
✔ C2-06 supporting cite cannot state canon, including a folder also marked playground (40.819326ms)
✔ C2-06 supporting file stores supporting scope and its real agent trailer (47.776616ms)
✔ C2-06 check evidence and insert are atomic when storing evidence fails (41.268825ms)
✔ C2-06 live limits change both directions; unreadable file keeps checks and exact fixed texts (53.375873ms)
✔ C2-06 page store is session-local, caps 20 fetches and 200 KiB, drops at disconnect (82.822565ms)
✔ C2-06 transport passes safe capped guard reason; ordinary refusal envelope is byte-identical (54.131458ms)
✔ C2-06 non-library businesses retain role.claim shape and unguarded free sends (26.350984ms)
✔ C2-06 thread messages carry file/last evidence with one read per distinct path (80.819295ms)
✔ C2-06 guarded request snapshot cannot change between check and insert (26.401011ms)
✔ C2-06 library.limits.set is human-only and invalid settings leave file and receipts unchanged (41.116925ms)
ℹ tests 13
ℹ suites 0
ℹ pass 13
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 839.688386
@@ -1,23 +0,0 @@
eeca81ab965f9e94f930ee5f51d16f019af6368bc6c3994895e204f7a54ec8d2 packages/bus/src/broker.mjs
ad3c686a089f67f3c89610937c6fc9b32367cea5d9735125d89bef042082d4e8 packages/bus/src/client.mjs
36b05dd3119e5929211aa1cc5d45c5043f5a1c34567ddc7cac8f002835d44abe packages/bus/src/runtime.mjs
66b26d131a19f4f411686427274936850c1ff0aed11e9b281ae4aadcf4b289fc packages/bus/src/server.mjs
cdd0304ec25ef1ad3e31c52502fa46f2c80bd77c8d3c2e13f8ed4b5328f342c9 packages/bus/tests/citation-availability.test.mjs
2e05074cd9d15d810103658af3858161cee2af78b0a2e1ba910222fab3e84401 packages/bus/tests/citation-guard.test.mjs
2c7a2102e2e0244876e41b664f4f706baefe3375100b956655551db1230f5da3 packages/bus/tests/citation-helpers.mjs
9768b6dc5ae078c5cc4f76473097287b74c5bc5853d39e1f57f153e646f861af packages/bus/tests/citation-runtime.test.mjs
abaeac64f2c3bf8ba83c9a4488edd9105c4707a6564560c5333d5421445653af packages/business/src/business.mjs
3a6044de5d1ca2cc35c5285b460c3e402b4274837e5d88b97f489797f6004903 packages/business/src/organization.mjs
4d2eb11beaa80175e524af1b95c81e7164990fba1d3e1754f5ba06eee390a14f packages/business/tests/reply-limits.test.mjs
a2bb98734bcc2556f8b2168f0faf8a89f7064c3f0aa49feb7d1975d596192f09 packages/cli/README.md
2f291a71f490f2741edada7a3e3788500f8976a08eb8ab1411f6c5982f778260 packages/cli/src/limits.mjs
f38af2d46d5f5f6388f599912507b94b87a0bf9dcc2104bb2187c38ee35118d5 packages/cli/tests/reply-limits.test.mjs
6ad72b4245e0a66e32725941900c1ece64c2e5de2fb73d65c8e042b4f3a691a6 packages/harness/src/runner.mjs
a5ef1b65230239a7baf6d0e8f2b8a51c0516348c7c4339a55b3f0a1a6ff531ba packages/harness/tests/citation-runner.test.mjs
330bc71bf6c7e64d3ddb70440903d2d9acf7878d44a49d7e30c2352ee4c807ec packages/harness/tests/fixtures/citation-adapter.mjs
f710d9600a17f6e2989a289cfe84e58f161d86c7306605946ce05fa71b364eb2 packages/library/src/guard.mjs
c0d630798914e300e461c247340533328e97119e54909c6a9406340e61fed8b7 packages/library/src/index.mjs
98ef45ed61144aaea44d8aea1ac43082b6d340297e46846d01772da38728e530 packages/library/src/limits.mjs
7b46f47b5e9d6b554b5d39bce2cd95c4610f5f35b8ab8fdc5a2864b3214be809 packages/library/src/reply-protocol.mjs
406146ebbce3710f308243b684a1c17e7626c1b65a4468489364317e31537a48 packages/library/tests/guard.test.mjs
39c8e6c8250a13fa43015fb2c407195e30ee642f729a9f6a644c38b4ea758a72 packages/seat/src/sandbox.mjs
@@ -1,47 +0,0 @@
✔ C2-06 coder send_message guard covers every table refusal; inserts nothing (109.280676ms)
✔ C2-06 research send_message guard covers every table refusal; inserts nothing (94.019544ms)
✔ C2-06 stored check carries the file author trailer at an unrelated cited tip (58.84355ms)
✔ C2-06 supporting cite cannot state canon, including a folder also marked playground (42.275234ms)
✔ C2-06 supporting file stores supporting scope and its real agent trailer (48.954969ms)
✔ C2-06 check evidence and insert are atomic when storing evidence fails (41.628985ms)
✔ C2-06 live limits change both directions; unreadable file keeps checks and exact fixed texts (54.367118ms)
✔ C2-06 page store is session-local, caps 20 fetches and 200 KiB, drops at disconnect (85.049228ms)
✖ C2-06 transport passes safe capped guard reason; ordinary refusal envelope is byte-identical (53.346085ms)
✔ C2-06 non-library businesses retain role.claim shape and unguarded free sends (26.218776ms)
✔ C2-06 thread messages carry file/last evidence with one read per distinct path (78.373306ms)
✔ C2-06 guarded request snapshot cannot change between check and insert (24.622347ms)
✔ C2-06 library.limits.set is human-only and invalid settings leave file and receipts unchanged (41.8227ms)
ℹ tests 13
ℹ suites 0
ℹ pass 12
ℹ fail 1
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 840.560306
✖ failing tests:
test at packages/bus/tests/citation-guard.test.mjs:116:1
✖ C2-06 transport passes safe capped guard reason; ordinary refusal envelope is byte-identical (53.346085ms)
AssertionError [ERR_ASSERTION]: The validation function is expected to return "true". Received false
Caught error:
Error: citation-invalid
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
at async TestContext.<anonymous> (file:///mnt/storage/scratch/tmp/tNoueZ/row217-mutant-db3vgbd1/packages/bus/tests/citation-guard.test.mjs:121:3)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: Error: citation-invalid
at Socket.<anonymous> (file:///mnt/storage/scratch/tmp/tNoueZ/row217-mutant-db3vgbd1/packages/bus/src/client.mjs:45:17)
at Socket.emit (node:events:514:20)
at addChunk (node:internal/streams/readable:575:12)
at readableAddChunkPushByteMode (node:internal/streams/readable:526:3)
at Readable.push (node:internal/streams/readable:406:5)
at Pipe.onStreamRead (node:internal/stream_base_commons:189:23),
operator: 'rejects',
diff: 'simple'
}
@@ -1,11 +0,0 @@
✔ C2-06 held library lock gives the agent citation-unavailable and its retry reason (5143.590096ms)
✔ C2-06 malformed sync state is availability failure, never a fabricated invalid cite (33.560438ms)
✔ C2-06 no mirror or freshly initialized empty mirror still means no served citation (31.849587ms)
ℹ tests 3
ℹ suites 0
ℹ pass 3
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 5290.343804
@@ -1,11 +0,0 @@
✔ C2-06 held library lock gives the agent citation-unavailable and its retry reason (5131.56715ms)
✔ C2-06 malformed sync state is availability failure, never a fabricated invalid cite (32.560014ms)
✔ C2-06 no mirror or freshly initialized empty mirror still means no served citation (31.756895ms)
ℹ tests 3
ℹ suites 0
ℹ pass 3
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 5271.350019
@@ -1,23 +0,0 @@
eeca81ab965f9e94f930ee5f51d16f019af6368bc6c3994895e204f7a54ec8d2 packages/bus/src/broker.mjs
ad3c686a089f67f3c89610937c6fc9b32367cea5d9735125d89bef042082d4e8 packages/bus/src/client.mjs
36b05dd3119e5929211aa1cc5d45c5043f5a1c34567ddc7cac8f002835d44abe packages/bus/src/runtime.mjs
66b26d131a19f4f411686427274936850c1ff0aed11e9b281ae4aadcf4b289fc packages/bus/src/server.mjs
cdd0304ec25ef1ad3e31c52502fa46f2c80bd77c8d3c2e13f8ed4b5328f342c9 packages/bus/tests/citation-availability.test.mjs
2e05074cd9d15d810103658af3858161cee2af78b0a2e1ba910222fab3e84401 packages/bus/tests/citation-guard.test.mjs
2c7a2102e2e0244876e41b664f4f706baefe3375100b956655551db1230f5da3 packages/bus/tests/citation-helpers.mjs
9768b6dc5ae078c5cc4f76473097287b74c5bc5853d39e1f57f153e646f861af packages/bus/tests/citation-runtime.test.mjs
abaeac64f2c3bf8ba83c9a4488edd9105c4707a6564560c5333d5421445653af packages/business/src/business.mjs
3a6044de5d1ca2cc35c5285b460c3e402b4274837e5d88b97f489797f6004903 packages/business/src/organization.mjs
4d2eb11beaa80175e524af1b95c81e7164990fba1d3e1754f5ba06eee390a14f packages/business/tests/reply-limits.test.mjs
a2bb98734bcc2556f8b2168f0faf8a89f7064c3f0aa49feb7d1975d596192f09 packages/cli/README.md
2f291a71f490f2741edada7a3e3788500f8976a08eb8ab1411f6c5982f778260 packages/cli/src/limits.mjs
f38af2d46d5f5f6388f599912507b94b87a0bf9dcc2104bb2187c38ee35118d5 packages/cli/tests/reply-limits.test.mjs
6ad72b4245e0a66e32725941900c1ece64c2e5de2fb73d65c8e042b4f3a691a6 packages/harness/src/runner.mjs
a5ef1b65230239a7baf6d0e8f2b8a51c0516348c7c4339a55b3f0a1a6ff531ba packages/harness/tests/citation-runner.test.mjs
330bc71bf6c7e64d3ddb70440903d2d9acf7878d44a49d7e30c2352ee4c807ec packages/harness/tests/fixtures/citation-adapter.mjs
f710d9600a17f6e2989a289cfe84e58f161d86c7306605946ce05fa71b364eb2 packages/library/src/guard.mjs
c0d630798914e300e461c247340533328e97119e54909c6a9406340e61fed8b7 packages/library/src/index.mjs
98ef45ed61144aaea44d8aea1ac43082b6d340297e46846d01772da38728e530 packages/library/src/limits.mjs
7b46f47b5e9d6b554b5d39bce2cd95c4610f5f35b8ab8fdc5a2864b3214be809 packages/library/src/reply-protocol.mjs
406146ebbce3710f308243b684a1c17e7626c1b65a4468489364317e31537a48 packages/library/tests/guard.test.mjs
39c8e6c8250a13fa43015fb2c407195e30ee642f729a9f6a644c38b4ea758a72 packages/seat/src/sandbox.mjs
@@ -1,70 +0,0 @@
✖ C2-06 held library lock gives the agent citation-unavailable and its retry reason (5104.72293ms)
✖ C2-06 malformed sync state is availability failure, never a fabricated invalid cite (35.117198ms)
✔ C2-06 no mirror or freshly initialized empty mirror still means no served citation (31.286656ms)
ℹ tests 3
ℹ suites 0
ℹ pass 1
ℹ fail 2
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 5250.151124
✖ failing tests:
test at packages/bus/tests/citation-availability.test.mjs:13:1
✖ C2-06 held library lock gives the agent citation-unavailable and its retry reason (5104.72293ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
+ actual - expected
+ 'citation-invalid'
- 'citation-unavailable'
^
at Object.<anonymous> (file:///mnt/storage/scratch/tmp/tNoueZ/row217-mutant-xglaeqeb/packages/bus/tests/citation-availability.test.mjs:29:14)
at expectedException (node:assert:547:17)
at expectsError (node:assert:672:21)
at strict.rejects (node:assert:738:3)
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
at async file:///mnt/storage/scratch/tmp/tNoueZ/row217-mutant-xglaeqeb/packages/bus/tests/citation-availability.test.mjs:28:5
at async withLibraryLock (file:///mnt/storage/scratch/tmp/tNoueZ/row217-mutant-xglaeqeb/packages/library/src/mirror.mjs:171:18)
at async TestContext.<anonymous> (file:///mnt/storage/scratch/tmp/tNoueZ/row217-mutant-xglaeqeb/packages/bus/tests/citation-availability.test.mjs:27:3)
at async Test.run (node:internal/test_runner/test:1409:7)
at async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: 'citation-invalid',
expected: 'citation-unavailable',
operator: 'strictEqual',
diff: 'simple'
}
test at packages/bus/tests/citation-availability.test.mjs:40:1
✖ C2-06 malformed sync state is availability failure, never a fabricated invalid cite (35.117198ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
+ actual - expected
Comparison {
+ code: 'citation-invalid'
- code: 'citation-unavailable'
}
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
at async TestContext.<anonymous> (file:///mnt/storage/scratch/tmp/tNoueZ/row217-mutant-xglaeqeb/packages/bus/tests/citation-availability.test.mjs:45:3)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: Error: citation-invalid: citation 1 (Book One/Characters/Mara Vell.md) isn't an indexed file at a commit reachable from the served commit
at refuse (file:///mnt/storage/scratch/tmp/tNoueZ/row217-mutant-xglaeqeb/packages/library/src/guard.mjs:24:42)
at checkReply (file:///mnt/storage/scratch/tmp/tNoueZ/row217-mutant-xglaeqeb/packages/library/src/guard.mjs:80:25)
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
at async waitForActual (node:assert:615:5)
at async strict.rejects (node:assert:738:25)
at async TestContext.<anonymous> (file:///mnt/storage/scratch/tmp/tNoueZ/row217-mutant-xglaeqeb/packages/bus/tests/citation-availability.test.mjs:45:3)
at async Test.run (node:internal/test_runner/test:1409:7)
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7),
expected: { code: 'citation-unavailable' },
operator: 'rejects',
diff: 'simple'
}
@@ -1,5 +0,0 @@
M1-writer-fence: killed (control green, mutant exit 1, hashes restored, restored green)
M2-incoming-human: killed (control green, mutant exit 1, hashes restored, restored green)
M3-split-check-transaction: killed (control green, mutant exit 1, hashes restored, restored green)
M5-hide-library-unavailable: killed (control green, mutant exit 1, hashes restored, restored green)
M4-drop-client-reason: killed (control green, mutant exit 1, hashes restored, restored green)
@@ -1,3 +0,0 @@
npm warn deprecated [email protected]: Use your platform's native DOMException instead
added 128 packages in 2s
@@ -1,2 +0,0 @@
added 2 packages in 205ms
@@ -1,9 +0,0 @@
✔ C2-06 runtime reads changed and unreadable reply limits without restarting (118.083931ms)
ℹ tests 1
ℹ suites 0
ℹ pass 1
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 227.817729
@@ -1,234 +0,0 @@
npm notice run @mosaic/[email protected] test
npm notice run node --test tests/
✔ C2-04: ensureCheckouts skips a library before a real clone and leaves no books path (66.766764ms)
✔ a first launch clones the root at its branch, with the root's path as origin (47.521672ms)
✔ the clone is not at its place until git clone has finished (31.999361ms)
✔ a later launch fast-forwards a clean clone after a commit to the root, then finds it current (87.563022ms)
✔ a clone ahead of the root keeps its commits and counts as current (53.447311ms)
▶ a dirty clone and one on another branch are fetched, and nothing but refs/remotes moves
✔ a modified file (53.258759ms)
✔ an untracked file (52.286642ms)
✔ a staged file (55.132154ms)
✔ another branch (53.48074ms)
✔ a detached HEAD (54.504119ms)
✔ a dirty clone and one on another branch are fetched, and nothing but refs/remotes moves (269.989404ms)
✔ a diverged clone gets the fetch into refs/remotes and is kept, not-fast-forward (53.461206ms)
▶ a clone kept before the branch check, or for a failed status, gets no fetch
✔ not-a-clone (27.485728ms)
✔ hooks-present (31.094616ms)
✔ submodule (38.060187ms)
✔ config-changed (36.195255ms)
✔ root-unreadable (36.385271ms)
✔ root-detached (39.627905ms)
✔ status-failed, on the root's branch and clean (42.704327ms)
✔ status-failed, dirty (44.881211ms)
✔ a clone kept before the branch check, or for a failed status, gets no fetch (297.899967ms)
✔ a dirty clone whose fetch fails is kept, fetch-failed, exactly as it was (47.755395ms)
✔ every git call the host makes, for a new clone and an existing one, carries maintenance.auto=false and gc.auto=0 (57.603139ms)
✔ a clone with loose objects enough for gc --auto gets no maintenance or gc from the fetch and the merge (89.466874ms)
▶ a clone with user.name or user.email in its config is kept, and git runs nothing in it
✔ user.name (28.628791ms)
✔ user.email (30.423895ms)
✔ a clone with user.name or user.email in its config is kept, and git runs nothing in it (59.627127ms)
✔ a commit git can't read after the fast-forward is null (57.084762ms)
✔ a new clone whose commit can't be read refuses the launch and leaves nothing behind (21.081119ms)
▶ a clone the session rigged is kept, and git runs nothing and writes nothing outside it
✔ core.fsmonitor (39.453854ms)
✔ core.hooksPath (34.616469ms)
✔ a hook file (35.090442ms)
✔ include.path (34.527401ms)
✔ includeIf (35.13899ms)
✔ a filter driver (34.195382ms)
✔ origin moved (37.391948ms)
✔ a second origin url (35.731817ms)
✔ the origin url twice, both the root (33.999145ms)
✔ an ext:: origin (31.652835ms)
✔ a branch tracking another remote (33.3147ms)
✔ a branch merging a tag (33.72502ms)
✔ a fetch line onto local branches (34.126505ms)
✔ no origin (32.973963ms)
✔ a config file over the size cap (30.967833ms)
✔ config a symlink to /dev/zero (31.51332ms)
✔ the clone a symlink to the bait (32.976685ms)
✔ the clone a file (39.528201ms)
✔ the clone a plain directory (32.193931ms)
✔ .git a gitdir: file (31.732811ms)
✔ .git a symlink (36.499471ms)
✔ .git/logs a symlink (34.327705ms)
✔ .git/refs/heads a symlink (30.308688ms)
✔ .git/objects a symlink (28.895664ms)
✔ a reflog hard-linked to a file outside (28.33422ms)
✔ HEAD a fifo (29.791372ms)
✔ a commondir file (30.182546ms)
✔ an alternates file (30.414863ms)
✔ a gitlink staged, no .gitmodules (42.003032ms)
✔ a gitlink and .gitmodules staged (47.484582ms)
✔ a gitlink to a repository with its own gitlink (53.625899ms)
✔ a gitlink and .gitmodules committed (45.90129ms)
✔ a gitlink and submodule.active in config (43.005636ms)
✔ a .git/modules with no gitlink (31.240083ms)
✔ a clone the session rigged is kept, and git runs nothing and writes nothing outside it (1201.693467ms)
▶ a root that can't be cloned refuses with the project id and leaves nothing behind
✔ missing (9.543898ms)
✔ not a repository (9.15995ms)
✔ a plain directory inside another repository (13.291966ms)
✔ unreadable (10.409599ms)
✔ on no branch (11.130486ms)
✔ missing an object (14.936384ms)
✔ a root that can't be cloned refuses with the project id and leaves nothing behind (69.273079ms)
✔ a clone whose root is on no branch, or gone, is kept and named (28.705151ms)
✔ no credential or forge remote of the root reaches a clone (46.990023ms)
✔ every project in the business file gets its own clone at its own branch (32.655381ms)
✔ a clone past its time gets SIGTERM and refuses the launch, with nothing left in the workspace (514.003804ms)
✔ a clone that ignores SIGTERM gets SIGKILL once the grace period is over (1016.843724ms)
✔ a timeout signals git's process group, so a process git started dies with it (515.051887ms)
✔ once a signalled git has closed, its group gets SIGKILL, so a process that ignored SIGTERM dies too (514.556145ms)
✔ the budget is the setting's whole number of bytes from 1 MiB to 1 GiB, and the default for anything else (1.567727ms)
✔ a stream past the default budget is not-collected with a lower bound, and a later collection catches up (65.101994ms)
✔ a budget smaller than the streams counts over several collections, once each, and is known when it catches up (2.599724ms)
✔ a line split across reads counts once (9.33078ms)
✔ Claude history from before the ledger makes the first Pi collection harness-unsupported, for good (1.440992ms)
✔ an empty claude-projects/ is no Claude history, and one filled after the ledger exists isn't checked (1.428192ms)
✔ a claude-projects/ that can't be read records nothing, and the next collection checks again (1.330216ms)
✔ the stream cap is the setting's whole number from 32 to 65536, and the default for anything else (0.16791ms)
✔ more streams than the cap is not-collected, with cursors only for the streams opened, and a larger cap catches up (2.344595ms)
✔ the default cap opens STREAMS streams and writes no more cursor lines than that (52.65919ms)
✔ row 307 the known ledger row 270 wrote reads the same count (4.720302ms)
✔ row 307 after the known ledger, one collection through pi's module answers the next count (3.122956ms)
✔ row 307 the store-incomplete ledger row 270 wrote reads the same count (1.172174ms)
✔ row 307 after the store-incomplete ledger, one collection through pi's module answers the next count (1.473641ms)
✔ row 307 the store-unreadable ledger row 270 wrote reads the same count (1.233218ms)
✔ row 307 after the store-unreadable ledger, one collection through pi's module answers the next count (1.478165ms)
✔ row 307 the not-collected ledger row 270 wrote reads the same count (1.059533ms)
✔ row 307 after the not-collected ledger, one collection through pi's module answers the next count (2.381792ms)
✔ row 307 the claude-code ledger row 270 wrote reads the same count (1.16785ms)
✔ row 307 after the claude-code ledger, one collection through pi's module answers the next count (1.422304ms)
✔ row 307 the claude-history ledger row 270 wrote reads the same count (2.943093ms)
✔ row 307 after the claude-history ledger, one collection through pi's module answers the next count (1.5333ms)
✔ row 307 the torn ledger row 270 wrote reads the same count (1.006203ms)
✔ row 307 after the torn ledger, one collection through pi's module answers the next count (2.284545ms)
✔ row 307 core refuses an answer outside the contract and appends nothing (8.468181ms)
✔ row 307 the module gets the store's two native directories, a copy of the cursors, the budget, the cap and first (2.320411ms)
✔ an empty store, a store with no compaction and a failed start count 0, known (7.138038ms)
✔ one and three completed compactions (2.441636ms)
✔ a compaction copied into a branched stream counts once, under the stream it was first seen in (3.056ms)
✔ one collection over two streams holding the same copy counts it once and writes it once (1.831681ms)
✔ the same entry id at another time in another stream is another compaction (1.582065ms)
✔ resume: each collection reads past its cursor and writes a key once (2.114301ms)
✔ a partial trailing line waits for its newline (1.624959ms)
✔ a missing ledger is not-collected and an unreadable one store-unreadable, never 0 (1.322325ms)
✔ a symlinked ledger is store-unreadable and is not written through (1.293154ms)
✔ a torn last ledger line makes the count unknown, a lower bound, and stays so (2.167108ms)
✔ a bad ledger line in the middle makes the count unknown (3.331232ms)
▶ a stream that shrank, changed under its cursor or went away is store-incomplete for good
✔ shrink (2.038847ms)
✔ rewrite (1.477185ms)
✔ remove (1.974024ms)
✔ a stream that shrank, changed under its cursor or went away is store-incomplete for good (6.254361ms)
✔ a stream that isn't a regular file or a Pi session is store-unreadable, and that passes (1.252704ms)
✔ a first line that isn't a session header is store-unreadable (1.120253ms)
✔ a Claude run is harness-unsupported, and stays so after a Pi run (1.273691ms)
✔ storeDir is the store sessionStore makes, without making it (1.538256ms)
✔ the ledger is under no sandbox mount (5.456112ms)
✔ rootHits: a top-level file, a new top-level directory, src/ and v1/ are the root; paths under known directories aren't (1.861197ms)
✔ gateEnv keeps the named variables that are strings and drops everything else (0.310846ms)
✔ isMosaicStack: a checkout whose HEAD descends from the root commit and has node_modules; nothing else (76.743834ms)
✔ gateSteps: each package with tests but queue in name order, then each scripts/test-*.sh (2.377262ms)
✔ runGate: every step passes, each with its own log and a summary line, under the environment it was given (211.160741ms)
✔ runGate: the first failing step stops the gate and names its log (269.569796ms)
✔ runGate: an abort stops the running step and everything in its group, and runs nothing after it (185.986993ms)
✔ the CLI: root-file prints the hits and exits 2, or exits 0; gate exits 0, or 2 with the step and its log; anything else is usage (661.443234ms)
✔ T3: publish pushes the work commit by oid to <user>/<branch> on the fork, with the token only through the helper (318.365034ms)
✔ T3: the token is never in git's argv, the fork URL included; it reaches git on fd 3 only (157.63501ms)
✔ T3: a moved fork branch refuses non-fast-forward; no + and no force (173.077055ms)
✔ T3: D9a: an empty fork and an unrelated fork refuse remote-unrelated; a missing fork refuses fork-unavailable (379.595919ms)
✔ T3: a fork past main refuses remote-unrelated until root catches up (152.254688ms)
✔ T3: a wrong token refuses fork-unavailable; git's stderr isn't in the refusal (102.972548ms)
✔ T3: a 302 is not followed: fork-unavailable, and the target sees no request (113.352932ms)
✔ T3: the helper answers only the fork's host and port: a fork on another port gets no token (95.099891ms)
✔ T3: a fork that echoes the token refuses credential-leak (131.28193ms)
✔ T3: no tls parameter, no trust: the scratch CA reaches git only through it (91.935601ms)
✔ D9 steps 3 and 4: ref-moved and identity-mismatch refuse before any request (143.070058ms)
✔ publishRemote refuses a fork, user or destination that isn't shell- and ref-safe before any git (88.646013ms)
✔ RUNNER_FILES is exactly what the runner and the harness sources it starts import (7.032234ms)
✔ sandboxProblem names a missing bwrap and a bwrap that fails (15.78888ms)
✔ every bind says why; the bundle and session file stay read-only over the run directory (2.196421ms)
✔ row 65 a harness module's mounts bind read-only after the adapter, each with the module's reason (2.143393ms)
✔ REQ-THREAD-2 a thread store binds its session directory and Claude transcripts, and nothing more (1.644658ms)
✔ the host's git socket is bound only when given, read-only and before the writable binds (1.090126ms)
✔ the git identity is the instance's, at <instance>@<business>.mosaic.invalid, and sandboxArgv refuses without it (1.690862ms)
✔ a confined session's shell reaches its own workspace and run directory and nothing of the founder's or another session's (2106.854649ms)
✔ a bind that exposes a stand-in, or a missing workspace bind, fails the matching check (2924.249794ms)
✔ a confined session that runs tester-cli.mjs is refused as tester, and the same shim outside the sandbox binds (300.518853ms)
✔ resolveSeat: by name under --repo resolves the repo layout (2.419588ms)
✔ resolveSeat: by path resolves the fleet layout (0.765582ms)
✔ resolveSeat: refusals for missing dir, missing launch.sh, non-executable launch.sh, invalid name, and unknown layout (1.626754ms)
✔ tmuxContext: outside tmux, default socket, custom socket, and exec failure (1.236572ms)
✔ makeRegistration produces a record that validates; each shape violation throws SeatError (1.593741ms)
✔ writeRegistration/readRegistration: round trip, permissions, absence, and malformed records (2.34318ms)
✔ updateTask: changes task, taskSetBy and updatedAt only, and refuses appropriately (2.203796ms)
✔ CLI launch: registers, execs the fake launch script, and passes args through (66.404825ms)
✔ CLI launch: --harness lands in the record (50.392752ms)
✔ CLI launch: the launch script's own exit code passes through (46.659659ms)
✔ CLI launch: relaunching a seat rewrites the one registration record (89.26575ms)
✔ CLI launch: omitting --task records an empty string, not null (39.318048ms)
✔ CLI seat task: updates only the task after a launch, and refuses on an unlaunched seat (96.331713ms)
✔ CLI refusals: no args, unknown flag, missing config, already-registered env, and exec failure (164.27632ms)
✔ samePath: equal paths, symlinked dirs, distinct dirs, and non-strings (0.422092ms)
✔ resolveSetBy: explicit --by wins over the environment; absent or empty environment gives unknown; invalid explicit or environment values refuse with exit 4 (0.590318ms)
✔ validateRegistration/readRegistration: taskSetBy is optional; a record without it (written before #1511) still loads unchanged; an invalid one is refused; the version does not change (0.734057ms)
✔ updateTask: records setBy, preserves startedAt and every unrelated field, upgrades an old record in place only when the task is set, and replaces a previous attribution (0.906133ms)
✔ CLI seat task: --by beats MOSAIC_AGENT_NAME, the environment beats nothing, empty environment is unknown, invalid --by or environment refuses with exit 4 and leaves the record byte for byte (330.90649ms)
✔ REQ-THREAD-2 sessionStore: a legacy session keeps the thread's store, any other gets sessions/<s>/, each segment checked first (5.360486ms)
✔ REQ-THREAD-2 sessionStore refuses legacy-store-unmapped for a thread whose old store no legacy session maps (1.608175ms)
✔ REQ-THREAD-2 sessionWorkspace: private directories per session, unsafe segments and overlaps refused (3.523108ms)
✔ REQ-THREAD-2 lockSessionWorkspace: one writer; a live host or run holds it, a stale lock is taken over, an unreadable one holds (15.189866ms)
✔ REQ-THREAD-2 sessions.json v2: entries carry session and workspace, running() keys on the session, a v1 file still reads (1.889362ms)
✔ REQ-LIMIT-1: family substring matching is no longer exported (1.378459ms)
✔ sessionEnv passes only the allowlist, the repo's bin on PATH, and the run id (1.063207ms)
✔ ZAI_API_KEY passes the session allowlist, and ZAI_TOKEN does not (0.239826ms)
✔ sessionExit gives a runner's signal death back as the signal; a session credential is one whole set of nonempty variables (0.405172ms)
✔ newRun: short ids, 0700 directories, and a refusal when the socket path won't fit (2.727102ms)
✔ session file and launch log: 0600, the session file written once (2.111664ms)
✔ endReason maps the runner's exit codes; a signal is killed (0.220582ms)
✔ Registry mirrors to sessions.json; readSessions marks live entries; bad files refuse (2.216711ms)
✔ a read-only Registry never writes sessions.json, refuses add() and leaves the file on remove() (2.154331ms)
✔ REQ-THREAD-1 Registry.running keys a thread run by business, instance and thread (1.027065ms)
✔ REQ-THREAD-2 REQ-LAUNCH-1 threadStore checks both segments before the join and refuses an unsafe directory (2.628544ms)
✔ stopSession refuses an unknown run, reports a stale one, and won't signal a pid that isn't a runner (1.552738ms)
✔ a session runs in its sandbox as pid 1 of its namespace, claims, answers, and stops on mosaic stop (293.088316ms)
✔ workRef and validBranch take only what a ref name can hold (2.280976ms)
✔ a push lands as the task's work ref, a fast-forward lands after it, and main is the root's (187.443563ms)
✔ a rewritten branch refuses non-fast-forward and the work ref stays (124.192671ms)
✔ a branch with no history in common with main refuses unrelated-history (60.579235ms)
✔ a bundle that needs commits the working repository lacks refuses missing-prerequisite (51.079109ms)
✔ the root is fetched again before each push and main follows it, so a clone of a newer root pushes (129.47937ms)
✔ a root moved back after the clone leaves the push's base unknown: missing-prerequisite (78.854404ms)
✔ a commit with a broken object refuses invalid-bundle, and only because fsck is on (86.468293ms)
✔ only a v2 bundle with the named branch is read (64.914471ms)
✔ a branch named main, or named for another task, moves only this task's work ref (102.371349ms)
✔ a record that throws moves the work ref back, or removes a new one (141.771502ms)
✔ a work ref that can't go back refuses rollback-failed, naming the ref and the commit (362.776758ms)
✔ a root that can't be read refuses root-unreadable (28.853641ms)
✔ a git past its time gets SIGTERM, leaves no ref lock, and the next push lands (2132.860162ms)
✔ a git that ignores SIGTERM gets SIGKILL once the grace period is over (1025.936026ms)
✔ a working repository path that isn't a directory refuses (23.030329ms)
✔ review bundles a pushed commit as refs/mosaic/review, leaving out what the reviewer has (120.899663ms)
✔ review of a project with no working repository refuses unknown-commit (14.031146ms)
✔ the runner's git tools hold the host's limits and branch rule (1.219295ms)
✔ a reseed moves root but leaves a landed main, and main forwards once root contains it (184.469774ms)
✔ after a landing, a push built on the root still lands and main stays where the landing put it (126.530409ms)
✔ once the root shares no history with a landed main, a push is checked against main, not the root (179.004093ms)
✔ a landing squashes the reviewed diff onto main as the bus host and moves main only at finish (105.224989ms)
✔ a landing refuses ref-moved, base-conflict and root-file before it makes a commit (308.132399ms)
✔ a landing whose applied diff isn't the reviewed one refuses patch-drift and leaves no worktree (121.415385ms)
✔ finish refuses base-moved when main moved, and a record that throws moves main back (242.643351ms)
✔ halted push receipt rolls back only its unrecorded ref and cleans temporary refs (198.696687ms)
ℹ tests 218
ℹ suites 0
ℹ pass 218
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 6318.071226
@@ -1,202 +0,0 @@
{
"base": "e0c6142f3",
"testedRevision": "2d274a5b6c35c3e74b07206ffd724a6579bb149d",
"tmpdir": "/mnt/storage/scratch/tmp/tNoueZ",
"wholeSuites": {
"library": {
"tests": 142,
"pass": 142,
"fail": 0,
"cancelled": 0,
"skipped": 0
},
"business": {
"tests": 270,
"pass": 270,
"fail": 0,
"cancelled": 0,
"skipped": 0
},
"bus": {
"tests": 974,
"pass": 974,
"fail": 0,
"cancelled": 0,
"skipped": 0
},
"cli": {
"tests": 988,
"pass": 988,
"fail": 0,
"cancelled": 0,
"skipped": 0
},
"harness": {
"tests": 172,
"pass": 172,
"fail": 0,
"cancelled": 0,
"skipped": 0
},
"seat": {
"tests": 218,
"pass": 218,
"fail": 0,
"cancelled": 0,
"skipped": 0
}
},
"touched": {
"touched-first": {
"tests": 57,
"pass": 56,
"fail": 1,
"cancelled": 0,
"skipped": 0
},
"touched-rerun": {
"tests": 57,
"pass": 57,
"fail": 0,
"cancelled": 0,
"skipped": 0
},
"availability-green": {
"tests": 3,
"pass": 3,
"fail": 0,
"cancelled": 0,
"skipped": 0
},
"runtime-fixture-retry": {
"tests": 1,
"pass": 1,
"fail": 0,
"cancelled": 0,
"skipped": 0
}
},
"mutants": {
"M1-writer-fence": {
"control": {
"tests": 6,
"pass": 6,
"fail": 0,
"cancelled": 0,
"skipped": 0
},
"negative": {
"tests": 6,
"pass": 3,
"fail": 3,
"cancelled": 0,
"skipped": 0
},
"restored": {
"tests": 6,
"pass": 6,
"fail": 0,
"cancelled": 0,
"skipped": 0
},
"productHashesRestored": true
},
"M2-incoming-human": {
"control": {
"tests": 6,
"pass": 6,
"fail": 0,
"cancelled": 0,
"skipped": 0
},
"negative": {
"tests": 6,
"pass": 5,
"fail": 1,
"cancelled": 0,
"skipped": 0
},
"restored": {
"tests": 6,
"pass": 6,
"fail": 0,
"cancelled": 0,
"skipped": 0
},
"productHashesRestored": true
},
"M3-split-check-transaction": {
"control": {
"tests": 13,
"pass": 13,
"fail": 0,
"cancelled": 0,
"skipped": 0
},
"negative": {
"tests": 13,
"pass": 12,
"fail": 1,
"cancelled": 0,
"skipped": 0
},
"restored": {
"tests": 13,
"pass": 13,
"fail": 0,
"cancelled": 0,
"skipped": 0
},
"productHashesRestored": true
},
"M4-drop-client-reason": {
"control": {
"tests": 13,
"pass": 13,
"fail": 0,
"cancelled": 0,
"skipped": 0
},
"negative": {
"tests": 13,
"pass": 12,
"fail": 1,
"cancelled": 0,
"skipped": 0
},
"restored": {
"tests": 13,
"pass": 13,
"fail": 0,
"cancelled": 0,
"skipped": 0
},
"productHashesRestored": true
},
"M5-hide-library-unavailable": {
"control": {
"tests": 3,
"pass": 3,
"fail": 0,
"cancelled": 0,
"skipped": 0
},
"negative": {
"tests": 3,
"pass": 1,
"fail": 2,
"cancelled": 0,
"skipped": 0
},
"restored": {
"tests": 3,
"pass": 3,
"fail": 0,
"cancelled": 0,
"skipped": 0
},
"productHashesRestored": true
}
},
"totalWholeSuiteTests": 2764
}
@@ -1,9 +0,0 @@
library: 142/142 pass; fail=0 skipped=0 cancelled=0
business: 270/270 pass; fail=0 skipped=0 cancelled=0
bus: 974/974 pass; fail=0 skipped=0 cancelled=0
cli: 988/988 pass; fail=0 skipped=0 cancelled=0
harness: 172/172 pass; fail=0 skipped=0 cancelled=0
seat: 218/218 pass; fail=0 skipped=0 cancelled=0
Touched rerun 57/57; first run 56/57, new runtime fixture corrected.
M1-M5 killed; each control/restored run green, hashes restored.
No old test failed or was edited. scripts/test-*.sh left to Sage at landing.
@@ -1,80 +0,0 @@
✔ C2-06 held library lock gives the agent citation-unavailable and its retry reason (5129.213097ms)
✔ C2-06 malformed sync state is availability failure, never a fabricated invalid cite (32.312603ms)
✔ C2-06 no mirror or freshly initialized empty mirror still means no served citation (31.769445ms)
✔ C2-06 coder send_message guard covers every table refusal; inserts nothing (104.132156ms)
✔ C2-06 research send_message guard covers every table refusal; inserts nothing (90.030314ms)
✔ C2-06 stored check carries the file author trailer at an unrelated cited tip (57.202238ms)
✔ C2-06 supporting cite cannot state canon, including a folder also marked playground (41.82067ms)
✔ C2-06 supporting file stores supporting scope and its real agent trailer (47.52786ms)
✔ C2-06 check evidence and insert are atomic when storing evidence fails (45.049883ms)
✔ C2-06 live limits change both directions; unreadable file keeps checks and exact fixed texts (54.4217ms)
✔ C2-06 page store is session-local, caps 20 fetches and 200 KiB, drops at disconnect (86.893454ms)
✔ C2-06 transport passes safe capped guard reason; ordinary refusal envelope is byte-identical (55.019525ms)
✔ C2-06 non-library businesses retain role.claim shape and unguarded free sends (26.383322ms)
✔ C2-06 thread messages carry file/last evidence with one read per distinct path (76.778515ms)
✔ C2-06 guarded request snapshot cannot change between check and insert (24.114008ms)
✔ C2-06 library.limits.set is human-only and invalid settings leave file and receipts unchanged (47.161109ms)
✖ C2-06 runtime reads changed and unreadable reply limits without restarting (78.402278ms)
✔ C2-06 M11 human replacement works; omitted settings return to defaults (26.436831ms)
✔ C2-06 M11 agents and tester cannot change settings, including by changing human (21.452407ms)
✔ C2-06 M11 serialization cannot replace settings after the first fence (8.669666ms)
✔ C2-06 M11 an unrelated actor cannot appoint itself human and change reply limits (8.204041ms)
✔ C2-06 invalid setter values preserve the business and changes.jsonl (9.079346ms)
✔ C2-06 validator accepts hand-edited settings; raw reader fails closed on invalid files (10.338142ms)
✔ C2-06 CLI replies reads revision and sends only the JSON settings to the human verb (1.898838ms)
✔ C2-06 CLI replies requires a file and refuses tester writes before a bus call (0.465972ms)
✔ C2-06 RESULT reply-invalid retries once, delivers only the valid answer and names reason (222.089187ms)
✔ C2-06 RESULT citation-missing retries once, delivers only the valid answer and names reason (200.104611ms)
✔ C2-06 RESULT citations-over-limit retries once, delivers only the valid answer and names reason (197.834891ms)
✔ C2-06 RESULT citation-invalid retries once, delivers only the valid answer and names reason (210.156515ms)
✔ C2-06 RESULT playground-cited-as-canon retries once, delivers only the valid answer and names reason (213.835593ms)
✔ C2-06 RESULT citation-cross-universe retries once, delivers only the valid answer and names reason (209.912186ms)
✔ C2-06 RESULT citation-unfetched retries once, delivers only the valid answer and names reason (198.705684ms)
✔ C2-06 RESULT two guard refusals use the citation fixed text and exactly one retry (182.386586ms)
✔ C2-06 RESULT JSON 34000 characters retries with a shorter valid answer (213.370025ms)
✔ C2-06 RESULT JSON 70000 characters retries with a shorter valid answer (199.782915ms)
✔ C2-06 RESULT two oversized JSON bodies use the length fixed text with citations required (184.820165ms)
✔ C2-06 multibyte plain bodies also receive the one request-size retry (201.829013ms)
✔ C2-06 two multibyte plain bodies use the length fallback (182.03426ms)
✔ C2-06 RESULT a length refusal then citation refusal shares one retry and citation fallback (183.540139ms)
✔ C2-06 fixed empty/failed replies defer unslop note until the next cited reply (274.786836ms)
✔ C2-06 cited JSON above the old 32000 clip retains its citations and text (167.141798ms)
✔ C2-06 a flagged cited answer keeps the note inside text and citations whole (168.83631ms)
✔ C2-06 send_message typed tool runs every guard code before the valid RESULT (230.565935ms)
✔ C2-06 outside library the old failed text, clip and unslop behavior hold (197.472747ms)
✔ C2-06 outside library a refused send keeps the existing no-retry behavior (151.296315ms)
✔ C2-06 the retry turn delivers citation-unavailable reason to the agent (184.635398ms)
✔ C2-06 reply schema: free bodies, exact objects and safe refusal reasons (14.759264ms)
✔ C2-06 citation setting and all four exact fixed texts (9.899391ms)
✔ C2-06 default citation cap passes 20 and refuses 21, even with optional citations (76.751112ms)
✔ C2-06 real Git citation scope, reachability, lines and normalized quotes (41.360225ms)
✔ C2-06 playground cites pass but cannot state canon (23.671961ms)
✔ C2-06 independent universes refuse; a hybrid and only its sources pass (41.572641ms)
✔ C2-06 web cites require allowed definition, this session fetch and kept quote (10.468249ms)
✔ C2-06 file origin is the path commit and trailer, while last follows served changes (31.989388ms)
✔ C2-06 origin uses literal paths even when a filename contains a glob (20.084358ms)
✔ C2-06 cited-commit guard reads exactly the C2-05a indexed file set with supporting scope (44.687642ms)
✔ C2-06 reply limits fall back independently without coercion or inherited keys (0.462948ms)
ℹ tests 57
ℹ suites 0
ℹ pass 56
ℹ fail 1
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 11101.06711
✖ failing tests:
test at packages/bus/tests/citation-runtime.test.mjs:12:1
✖ C2-06 runtime reads changed and unreadable reply limits without restarting (78.402278ms)
Error: invalid-authority
at fail (file:///home/jwoltje/.t3/worktrees/mosaic-stack/beakley-row217/packages/bus/src/broker.mjs:215:9)
at checkBusiness (file:///home/jwoltje/.t3/worktrees/mosaic-stack/beakley-row217/packages/bus/src/broker.mjs:366:7)
at new Broker (file:///home/jwoltje/.t3/worktrees/mosaic-stack/beakley-row217/packages/bus/src/broker.mjs:537:63)
at startBroker (file:///home/jwoltje/.t3/worktrees/mosaic-stack/beakley-row217/packages/bus/src/runtime.mjs:274:14)
at async TestContext.<anonymous> (file:///home/jwoltje/.t3/worktrees/mosaic-stack/beakley-row217/packages/bus/tests/citation-runtime.test.mjs:18:19)
at async Test.run (node:internal/test_runner/test:1409:7)
at async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3) {
code: 'invalid-authority'
}
@@ -1,65 +0,0 @@
✔ C2-06 held library lock gives the agent citation-unavailable and its retry reason (5131.834326ms)
✔ C2-06 malformed sync state is availability failure, never a fabricated invalid cite (31.609704ms)
✔ C2-06 no mirror or freshly initialized empty mirror still means no served citation (31.510292ms)
✔ C2-06 coder send_message guard covers every table refusal; inserts nothing (102.606635ms)
✔ C2-06 research send_message guard covers every table refusal; inserts nothing (91.30209ms)
✔ C2-06 stored check carries the file author trailer at an unrelated cited tip (55.686451ms)
✔ C2-06 supporting cite cannot state canon, including a folder also marked playground (42.44166ms)
✔ C2-06 supporting file stores supporting scope and its real agent trailer (48.386414ms)
✔ C2-06 check evidence and insert are atomic when storing evidence fails (39.194827ms)
✔ C2-06 live limits change both directions; unreadable file keeps checks and exact fixed texts (54.284625ms)
✔ C2-06 page store is session-local, caps 20 fetches and 200 KiB, drops at disconnect (85.004961ms)
✔ C2-06 transport passes safe capped guard reason; ordinary refusal envelope is byte-identical (54.117068ms)
✔ C2-06 non-library businesses retain role.claim shape and unguarded free sends (26.131034ms)
✔ C2-06 thread messages carry file/last evidence with one read per distinct path (76.437567ms)
✔ C2-06 guarded request snapshot cannot change between check and insert (23.908928ms)
✔ C2-06 library.limits.set is human-only and invalid settings leave file and receipts unchanged (39.656735ms)
✔ C2-06 runtime reads changed and unreadable reply limits without restarting (113.293022ms)
✔ C2-06 M11 human replacement works; omitted settings return to defaults (36.305063ms)
✔ C2-06 M11 agents and tester cannot change settings, including by changing human (21.839826ms)
✔ C2-06 M11 serialization cannot replace settings after the first fence (8.253422ms)
✔ C2-06 M11 an unrelated actor cannot appoint itself human and change reply limits (7.674495ms)
✔ C2-06 invalid setter values preserve the business and changes.jsonl (8.65299ms)
✔ C2-06 validator accepts hand-edited settings; raw reader fails closed on invalid files (9.800617ms)
✔ C2-06 CLI replies reads revision and sends only the JSON settings to the human verb (1.78485ms)
✔ C2-06 CLI replies requires a file and refuses tester writes before a bus call (0.520156ms)
✔ C2-06 RESULT reply-invalid retries once, delivers only the valid answer and names reason (220.792912ms)
✔ C2-06 RESULT citation-missing retries once, delivers only the valid answer and names reason (195.400791ms)
✔ C2-06 RESULT citations-over-limit retries once, delivers only the valid answer and names reason (196.181772ms)
✔ C2-06 RESULT citation-invalid retries once, delivers only the valid answer and names reason (211.797981ms)
✔ C2-06 RESULT playground-cited-as-canon retries once, delivers only the valid answer and names reason (212.360651ms)
✔ C2-06 RESULT citation-cross-universe retries once, delivers only the valid answer and names reason (212.667005ms)
✔ C2-06 RESULT citation-unfetched retries once, delivers only the valid answer and names reason (184.261348ms)
✔ C2-06 RESULT two guard refusals use the citation fixed text and exactly one retry (184.957084ms)
✔ C2-06 RESULT JSON 34000 characters retries with a shorter valid answer (216.343048ms)
✔ C2-06 RESULT JSON 70000 characters retries with a shorter valid answer (198.338992ms)
✔ C2-06 RESULT two oversized JSON bodies use the length fixed text with citations required (183.309434ms)
✔ C2-06 multibyte plain bodies also receive the one request-size retry (198.411283ms)
✔ C2-06 two multibyte plain bodies use the length fallback (182.244769ms)
✔ C2-06 RESULT a length refusal then citation refusal shares one retry and citation fallback (184.948978ms)
✔ C2-06 fixed empty/failed replies defer unslop note until the next cited reply (294.575418ms)
✔ C2-06 cited JSON above the old 32000 clip retains its citations and text (169.454956ms)
✔ C2-06 a flagged cited answer keeps the note inside text and citations whole (164.824669ms)
✔ C2-06 send_message typed tool runs every guard code before the valid RESULT (213.365137ms)
✔ C2-06 outside library the old failed text, clip and unslop behavior hold (198.225522ms)
✔ C2-06 outside library a refused send keeps the existing no-retry behavior (155.955999ms)
✔ C2-06 the retry turn delivers citation-unavailable reason to the agent (188.198987ms)
✔ C2-06 reply schema: free bodies, exact objects and safe refusal reasons (17.723832ms)
✔ C2-06 citation setting and all four exact fixed texts (11.590649ms)
✔ C2-06 default citation cap passes 20 and refuses 21, even with optional citations (79.713842ms)
✔ C2-06 real Git citation scope, reachability, lines and normalized quotes (41.208361ms)
✔ C2-06 playground cites pass but cannot state canon (24.250695ms)
✔ C2-06 independent universes refuse; a hybrid and only its sources pass (42.707909ms)
✔ C2-06 web cites require allowed definition, this session fetch and kept quote (10.901286ms)
✔ C2-06 file origin is the path commit and trailer, while last follows served changes (37.369269ms)
✔ C2-06 origin uses literal paths even when a filename contains a glob (20.592546ms)
✔ C2-06 cited-commit guard reads exactly the C2-05a indexed file set with supporting scope (51.682837ms)
✔ C2-06 reply limits fall back independently without coercion or inherited keys (0.499884ms)
ℹ tests 57
ℹ suites 0
ℹ pass 57
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 11134.473726
Loaded 100 of 18942 files, more files were not shown because too many files have changed in this diff. Show more