- Dressed quoted computed keys (as/satisfies/!) fail closed anywhere: the
static key survives the dressing but breaks every ['name'] matcher, and
matcher tolerance cannot span types containing ']' (as Foo['x']), so the
shape itself is the trigger (with an !(?!=) guard for ordinary
comparisons).
- Escape-built quoted keys (\u/\x/octal) fail closed: statically
resolvable, so outside the non-literal computed-member residual.
- Reflect verb indirection fails closed: any Reflect.* call naming a
write/exec verb in its argument text (Reflect.apply(db.insert, ...),
Reflect.get(db, 'insert')).
- CODE_SHAPE_REGISTER: enumerated disposition path for the fail-closed
code-shape rules (template key, dressed/escaped key, apply/call/bind,
Reflect) — a reviewed legitimate hit is registered, never resolved by
weakening the shape. Empty today; eval/new Function stays unconditional.
- KNOWN RESIDUALS: test-file/out-of-src modules named as import-graph
conduit blind spots; TYPE_ANN/DECL_LIST single-line limit documented.
- Controls E93-E102 (dressed/escaped keys at write target, conduit export,
default export, single-file factory extraction; Reflect.apply/get) plus a
clean control pinning the !== guard.
The text-only template-key rule fires on any computed member — access or
call — not only the call form, so template-keyed write targets, export
expressions, and receivers fail closed at their origin. Declaration
exports and derivations tolerate a type annotation and prior declarators
via shared TYPE_ANN/DECL_LIST shapes at all five declarator sites.
Invoking a write/exec verb through .apply/.call/.bind fails closed
anywhere (both member names statically visible, unlike the
method-extraction residual). The evasion test counts violations across
the whole synthetic chain, since some routes fail closed at the helper.
Controls E82-E92; clean control pinning the interpolated-key
discriminator.
stripExprDressing also strips trailing non-null assertions and satisfies
clauses, so export-default dressing (companies!, createDb satisfies T,
(x as unknown)!) resolves at both ends. The three ns-member right-hand
sides tolerate parenthesization. Every verb matcher admits the optional-
call form (?.() via a shared CALL_OPEN shape. A computed member call
whose key is a text-only template literal fails closed (its text never
reaches lexed code); interpolated keys stay under the non-literal
residual. Document the DB_FACTORY_IMPORTERS ns-destructure enumeration
blind spot as a residual. Controls E69-E81.
Unify member-access matching on shared DOT/BRACKET_OPEN/MEMBER_SEG shapes
(dot, bracket, ?. and ! forms) across both conduit computations, the write
targets, the factory-import clause, and the DI backstop. Treat export-default
as an expression at both ends: strip parens/assertions, classify bare-word vs
namespace-member chain, on the schema AND capability sides. Add the
capability-side export-default ns-member pass (round-5 finding 2). Admit bare
SQL qualifier words (TABLE, ONLY, IF EXISTS) between keyword and table name in
prong (ii). Controls E54-E68.
Default-export slot treated as an export name at both ends (helper-side
export-default passes, consumer-side bare-default-import resolution);
namespace-member write targets match the source's exported names via a
per-file memberSyms union; factory conduits carry a name map computed to
a fixpoint so renames propagate hop by hop (export-from, export-of-local,
export default); tracked dynamic imports of capability conduits confer
capability; factory destructure-rename from a schema namespace; static
module-namespace createRequire destructure; spread-argument writes; DCL
keywords (GRANT/REVOKE ON, LOCK TABLE); bracketed conventional DI
receiver. Permanent controls E40-E53.
Per the second M4-1a detached review (REQUEST_CHANGES, R1-R8):
- R1: prong (i) now tracks namespace destructuring, nested namespace
re-exports (ns.schema.companies), and literal dynamic-import bindings
(destructured and namespace) per contract rev 9.
- R2: capability-conduit fixpoint (computeCapabilityConduits) closes
driver/factory laundering through export-from modules.
- R3: dynamic-import check is per call site with a full-literal tail
match, so concatenated specifiers no longer pass.
- R4: computed-member calls with literal verb names (obj['insert'],
obj['query']) and spaced member access are flagged.
- R5: prong (ii) adjacency tolerates schema qualification, interposed
block comments, COPY, and escaped quotes.
- R6/R8: header documents KNOWN RESIDUALS (DI receiver rename in
capability-free files, computed non-literal member access, scan
perimeter) with the measured counterfactuals.
- createRequire fails outside a 5-module measured register (R1 route).
- 15 new permanent evasion controls (E9-E23) with helper-file conduits
run through the production analyzer.
Calibration: tree-wide prong test green with zero new exclusions;
tsc, eslint, and the full package suite pass.
Review findings F1-F8 (REQUEST_CHANGES) addressed:
- F5: replace regex comment stripping with a string-aware lexer producing
comment-free code plus accurate string/template spans (handles nesting,
regex literals, escapes)
- F3: prong (i) now tracks namespace imports and re-export conduits via a
fixpoint over the scanned import graph
- F1/F2: tagged-template exemption dropped; backlog.ts joins the infra
register; capability-gated prong (iii) — driver import flags any-receiver
execute/query/unsafe, factory import flags any-receiver execute/unsafe,
db-shaped receiver backstop covers DI'd handles; sql.raw tracked through
aliases and namespaces
- F4: closed importer enumeration added for createDb/createPgliteDb;
composition property of remaining register modules documented
- F6: plugins/ added to scan roots
- F7: per-parent slug scoping witnessed at platform_projects and workspaces
- F8: dynamic-import disposition register added; stricter-than-contract
stances documented in the header
The review's 8 evasion samples are embedded as permanent controls run
through the production analyzer, plus clean controls guarding against
false positives.
Implements docs/requirements/hierarchy-schema.md sections 2-4 and the
schema-layer half of section 6:
- Five class tables (companies, estates, platform_projects, workspaces,
hierarchy_grants) with the section 2.7 exhaustive column sets: child
node tables carry no timestamps (renames are audited via events), no
owner_id anywhere (section 4.4 - ownership is computed from grants).
- Grant constraints per section 3: exactly-one-subject and
exactly-one-target num_nonnulls CHECKs, six-column UNIQUE NULLS NOT
DISTINCT, target FKs CASCADE / principal FKs RESTRICT, six btree
indexes.
- Migration 0018 generated by drizzle-kit; SQL verified against the
contract text and applied on PGlite.
- hierarchy-schema.witness.test.ts: dual-leg witness suite (PGlite
always; real PostgreSQL under DATABASE_URL, the section 6.8 binding
leg in CI). Covers parent-FK integrity + catalog assertion, slug
scoping, column allowlist (6.2), all six grant subject/target forms,
CHECK refusals, NULLS NOT DISTINCT duplicates, NOT NULL refusals, and
deletion semantics (6.6): fail-closed parent delete, leaf cascade of
exactly its grants, principal RESTRICT.
- hierarchy-writer-coverage.test.ts: section 6.3(b) three-prong static
assertion (alias-aware symbol writes, class-table names in SQL
literals, raw-execution primitives) with empty writer allowlist,
closed infrastructure register, and closed importer enumerations for
the migration runner and migrate-tier. All prongs proven able to fire
via a planted-violation control.
Command family, audit events, and route inventory land in M4-1b.
- docs/PRD.md: Part I product north star authored from ratified decisions
D1-D14; Part II preserves all active workstream contracts verbatim
(KBN-101, FCM #758, FCOM #766, TESS, #756, MOS-PORT, #1150, #1174, #1194,
RI #1275, M1). Referenced anchors unchanged.
- docs/archive/PRD-v0.1.md: v0.1.0 beta PRD body archived verbatim with
supersession header.
- docs/ROADMAP.md: all phases P0-P5 present from day one per D11
(P2-P5 as explicit placeholders).
- docs/requirements/native-kanban-sot.md: Amendment A1 (D13) - hierarchy
parentage + RBAC chain above workspaces; sections 1-7 untouched.
rev-code-01's non-blocking nit on #1313 round 2. The no-linking-step paragraph
pointed at the bridge explanation as 'described below'; it is above. Now names the
section, which survives further reordering better than a direction word does.
Text-only. Verified with the repo's PINNED prettier (3.8.1 via pnpm-lock.yaml) and
the sanitization gate, both clean.
All four findings reproduced before fixing. rev-code-01 was right on each.
B2 (blocker, mine). SEAT-IDENTITY provisioning step 4 said to symlink the
framework store entry to the seat slot, while the same file says those bridges
must not be recreated. The same bridge, told both ways, in one document. I
rewrote the resolution and token-location sections when the deploy made them
stale and did not carry the change into the numbered steps. Step 4 is gone and
the file now says explicitly that no provisioning step links the store to the
slot, so the omission cannot read as an oversight.
S1 (mine). The guide claimed the helper "attempts a fleet notification" on
refusal. The shipped helper does no such thing — its only reference to
notification is a comment saying an alert built on the record is best-effort, and
there is no send or wake call anywhere in the file. Now: it writes a durable
record, the record is what exists, and nobody should wait for a notification that
nothing sends. A guide that promises an alert is worse than one that promises
nothing.
S2. Estate-local content removed from files that ship to every estate: the
~/.mosaic/fleet/bin script paths (dead paths elsewhere) and the 2026-08-18 dates,
which dated a specific host's migration rather than describing behavior. The
bridge-removal passage now states the ORDERING that matters — remove bridges only
after a seat-aware helper can reach the slot, never before — which is the part
that transfers.
B1. prettier reformatted all three files. Reproduced the pipeline 2515 failure
locally before and confirmed clean after; the other three guides prettier flags
are untouched by this branch (0 changes vs origin/next) and are pre-existing.
Sanitization gate re-run and passing.
Verified for the record, since I could not verify my own work: rev-code-01
confirmed the no-fallback claim TRUE against helper content on origin/next, and
judged the evidence rules actionable on the grounds that each names an executable
replacement.
Pipeline 2514 failed the sanitization gate on 'Jason mints the token into the
seat slot'. The denylist is jarvis|jason|woltje|... and a shipped framework file
must not carry operator identity. My mistake: I generalized the estate paths and
seat names when promoting this guide and did not check the operator name.
Now reads 'the estate operator', with the accompanying rule that an agent does
not ask another agent to mint one either.
Verified by running tools/quality/scripts/verify-sanitized.sh locally rather than
guessing at the pattern: gate passes.
The #1280 prohibition carried an explanation of how the tools misattribute and
why the failure is invisible from inside them. A reader who is not going to use
the tool cannot act on any of it. Same for rule 2's closing clause about what
reviews commonly miss. Both cut to the decree and the corrective action.
Rules 1 and 3-12 keep their trailing sentences: those are corrective actions or
the detail that makes the case recognizable, not justification.
Three guides that existed only as one host's working copy, promoted to framework
templates so every estate gets them. A working copy under ~/.mosaic binds one
host; only a template here binds all of them.
SEAT-IDENTITY.md (new) documents how a seat's git credential is actually
resolved after #1311: identity from MOSAIC_GIT_IDENTITY, then
mosaic.gitIdentity, then the stdin username; host mapped to a store prefix; then
ONE of two stores chosen by whether the seat directory exists, with no
precedence and no fallback between them. A seat with a directory and an empty
slot fails closed rather than reaching the service store, and that is the point.
It also corrects how to find the helper. credential.helper commonly names an
absolute path, so `command -v git-credential-mosaic` answers a different question
than the one git asks, and the two stop agreeing the moment the PATH copy is
removed. Git also tries EVERY configured helper in order, so a fail-closed helper
in front silently hands the request to whatever is configured behind it. The
guide says to read the whole list.
FLEET-COMMS.md (new) documents agent-send.sh: the class table, the addressing
preamble, and the exit codes — including that rc=2 means the text reached the
pane as an unsubmitted draft, so retrying double-sends it. Confirm with
capture-pane instead. It also says to measure the fleet rather than trust
roster.yaml, which on a live host was simultaneously naming a socket that did not
exist, listing seats that were not running, and omitting seats that were.
CODE-REVIEW.md gains an Evidence Discipline section: a green is not a result
until you have shown it could go red, measurement and explanation are separate
sentences, verify by content on the ref that ships rather than by ancestry of a
local sha, and confidence is part of a finding. Plus four shell-measurement rules
earned on #1311, each of which produced a wrong conclusion first — `cmd | tail;
echo rc=$?` reports tail's status, a missed glob under pipefail exits 2 and kills
the run under set -e, nonzero-with-no-output is an environment question before it
is a code question, and `git -C` in a non-repo directory answers from the
enclosing repo.
The estate-specific repository exception that lived in the working copy is not
carried here. The template says an estate may document one, scoped to a named
repository and never precedent for a second.
Both new guides are added to the two routing tables that agents read.
Both defects found in review by rev-code-01 on #1311.
F3 — the JSONL record interpolated every field with a bare %s. An identity comes
from git config or the environment and a cwd is whatever directory git ran in, so
either can contain a quote or a backslash. One such refusal turned the day's spool
into unparseable JSONL, and the operator would only discover it while reading the
record that explains an outage. Fields are now JSON-escaped.
F2 — the diagnostic printed "record: <spool>/<date>.jsonl" unconditionally, but
the record is only written inside the branch where mkdir -p succeeded. When the
spool cannot be created the helper named a file that does not exist, on exactly
the hosts where the escalation was lost. It now reports the real path or says
NOT WRITTEN.
Also: prettier on README.md, which was the format-step failure on pipeline 2508.
It reflowed only the two tables this branch added.
Tests: cases 14 and 15 cover both. Verified discriminating — against the previous
helper with these same tests, case 14 fails with the unparseable record printed
and case 15 fails on both assertions; against this one both pass.
The first draft of case 14 used `ls "$spool"/*.jsonl | head -1`, which under
`set -o pipefail` exits 2 on a missed glob and killed the suite with zero output
— the same silent-nonzero failure rev-code-01 hit from a partial tools/ extraction
and the reason this file exists. Replaced with a glob loop and a comment.
Two changes to one rule: a credential is resolved from exactly one place,
and an identity that cannot be resolved is refused rather than substituted.
FAIL CLOSED. Both readers ended in an unconditional fall-through to the
shared Gitea account whenever an identity did not resolve. Every seat in a
fleet therefore pushed, opened PRs and filed reviews under one account, and
a record made that way cannot be traced to the agent that made it
afterwards. The fallback now applies only where there is no attribution to
lose: a host with no fleet. Where seats exist, an unresolvable request emits
nothing, exits nonzero, explains itself on stderr, and — in the git helper —
appends a record naming the identity, host, reason and cwd, and no token
value, to ${MOSAIC_CREDENTIAL_SPOOL:-~/.local/state/mosaic-credential-escalations}.
A host runs a fleet when <brain>/fleet/agents exists, which is the signal
packages/mosaic/src/fleet/brain-home.ts already uses to decide a brain is
active, resolved the same way (MOSAIC_BRAIN_HOME, else ~/.mosaic). This is
what keeps the change a no-op for an operator who has not provisioned
per-slot tokens: no fleet directory, shared account, unchanged. It is also
why there is no environment variable to restore the old behavior — one would
reintroduce the substitution being removed.
STORE SELECTION. Both readers hardcoded ~/.config/mosaic/secrets/gitea-tokens,
so a seat's own secrets/ slot was invisible to the framework: a seat could
hold a valid credential and still be served the shared account. The store is
now chosen by what the identity is. An identity with a directory under
<brain>/fleet/agents/ is a seat and is read only from
<brain>/fleet/agents/<id>/secrets/; any other identity is a service identity
and is read from the framework store. There is no precedence between them
and no fallback from one to the other, so a seat with an empty slot is
refused even when a same-named token sits in the framework store. Two copies
of one credential are drift rather than redundancy, and drift surfaces as
the stale copy returning 401, which reads as a revoked token and sends
whoever debugs it somewhere else.
detect-platform.sh is in scope alongside git-credential-mosaic because they
are the two readers of these tokens. Patching only the git helper would make
"one credential, one location" true for push and fetch and false for
pr-create.sh, issue-create.sh and pr-review.sh, which is the harder failure
to notice.
TESTS. The three assertions that pinned the shared-account fall-through are
now fail-closed assertions, and a refusal is checked four independent ways:
nonzero exit, empty stdout, a stderr diagnostic naming identity and host,
and no shared token value anywhere in the output. The exit code alone would
pass against a helper that emitted the credential and then failed. Added:
seat-slot resolution, the no-cross-store-fallback case with a control
proving the framework-store file it declines to read is readable, no-identity
on a fleet host, the fleet gate firing on the default ~/.mosaic and not only
on an injected MOSAIC_BRAIN_HOME, and a cross-host leak check. Both suites
were run against the pre-change code as a control and fail there on exactly
the shared-token emission.
shellcheck is not installed on the authoring host, so the rewritten helper
is unlinted locally and CI is the first lint of it.
The first PR for this change was filed under the retired mos-dt-0 principal
(pr-create.sh has no --login flag and find_tea_login_for_host returns the first
host match) and was closed and refiled as #1270. That left in-tree references
pointing at a closed duplicate PR rather than at the burn-down issue, which is
the wrong target for them anyway: the open design question belongs on #1271.
The `test` step has failed on every `next` pipeline since #1017 on exactly one
assertion, and it is the same one on unrelated PRs:
FAIL: host provides 'pi' in the system path; missing-binary cases are not
measurable here (framework/tools/fleet/test-start-agent-session.sh:103)
Measured 2026-08-16 across pipelines 2444 (#1256), 2438 (#1240) and 2441
(#1017-quality): exactly one FAIL line in each full log, identical, this line.
Control `zzz-not-present-zzz` -> 0 on all three.
Cause. #1241 (5c35a250) added the guard: the suite shims fake mosaic/pi/npm into
$FAKE_BIN, but the constructed PANE_PATH always ends in the real system path, so
on a host that installs those binaries the missing-binary cases cannot be
measured and a green run would mean nothing. The guard says so instead of
passing. Its own pipeline 2430 was green only because the suite was CI-excluded
at the time, so the guard had never run in CI. #1017 (c56483eb) then enumerated
it and dropped the exclusion. The CI image installs
@earendil-works/[email protected].1 on purpose, so the precondition is
unsatisfiable there. Both commits are mine.
The guard is correct and is not being softened. A check that cannot measure its
property and reports success is the failure mode this repo has been cataloguing
all week; the error was wiring the suite into an image that violates its
precondition, so the wiring is what gets reverted.
Second effect, which is the reason this cost a day rather than an hour:
test:framework-shell is one && chain and this sat at position 44 of 48, so
glpi/test-list-http-status.sh, orchestrator/test-board-roll.sh,
woodpecker/test-ci-wait-exit-matrix.sh and _scripts/test-fleet-transport-check.sh
have not run at all since the merge. The pipeline reported one failure, never
"one failure plus four unrun". All four are green when run directly on
sb-it-1-dt, so the mask hid nothing broken -- but that is a local result on one
host, not a CI-image result.
Verification, with controls:
- enumeration guard OK (population 52, enumerated 36, signed-excluded 16).
- control A, exclusion line removed while unwired -> FAIL UNENUMERATED.
- control B, exclusion line kept while rewired -> FAIL CONTRADICTORY EXCLUSION.
The gate discriminates in both directions, so its OK is load-bearing.
- the four formerly-masked suites: rc=0 each, run directly.
- the full chain cannot be run to completion on sb-it-1-dt: it stops earlier, at
the lease-broker Invariant R test, because this host carries the quarantined
operator-global pi 0.84.2 against a measured 0.84.1. That is host-specific and
out of scope here -- CI pins 0.84.1, and the single FAIL line in those three
pipelines proves positions 1-43 passed there.
Burn-down is to control the tail of PANE_PATH inside the test, not to remove pi
from the image. Recorded in the exclusion reason and in #1269.
Comment-only, no behaviour change. Both raised by scooby in the #1229 review
as non-blocking findings worth writing down rather than fixing here.
F-A: the SHASUMS256.txt check gives integrity, not authenticity. TLS to
$NODE_DIST_BASE is the whole trust root, and MOSAIC_NODE_DIST_BASE widens it
to any mirror with no signature backstop. GPG-verifying SHASUMS256.txt.sig is
filed as its own follow-up so it gets its own review.
F-C: the uname map pulls the glibc build, so musl hosts fail — visibly, via
node_is_suitable, not silently.