Compare commits

..
Author SHA1 Message Date
Jason WoltjeandClaude Fable 5 68bdeba758 style(wake): prettier-normalize denominator artifact — whitespace-only (#973)
ci/woodpecker/pr/ci Pipeline was successful
Pipeline 2136's sole red step: pnpm format:check flags the frozen
denominator JSON (Python-emitted formatting vs prettier style). Reformat
with the repo-pinned prettier 3.9.6. Verified before commit: git diff -w
empty across the whole commit (whitespace-only), json.load before/after
compare EQUAL AS OBJECTS (A1 consumes the parsed object, never the
bytes), check-973.py expected==static still 261/261, no other path
touched. test step at prior head 5e98419d was green — all ten wake
suites ran converted and passed in CI.

Written-by: pepper (sb-it-1-dt)
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NsKce8iZuSuRnu3gVMCBKB
2026-07-31 03:24:39 -05:00
Jason WoltjeandClaude Fable 5 5e98419d0e chore(wake): manifest 0.7.2 — #973 three-valued grep verdicts
ci/woodpecker/pr/ci Pipeline failed
Written-by: pepper (sb-it-1-dt)
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NsKce8iZuSuRnu3gVMCBKB
2026-07-31 02:14:47 -05:00
Jason WoltjeandClaude Fable 5 bd57ef0c74 test(wake): #973 validation harness — trace/inventory/arm evidence chain
validate-973.sh produces the complete evidence chain in one run:

  0  instrument self-test (microtest, now C1-C11) before any evidence
  1  expected set: 261 coordinates from the frozen denominator artifact
     (+3 header shift), count declared BEFORE any suite runs
  2  static inventory re-derived from SOURCE TEXT == expected set — the
     ledger is an execution trace, not an inventory, so the inventory leg
     comes from the text (mos-dt amendment ONE)
  3  green instrumented run: ten suites, per-suite pinned sentinels
     (preimage's divergent format included), exit codes reported per file
  4  trace arithmetic on coordinate SETS: trace-minus-expected must be
     empty; expected-minus-trace (converted-but-never-executed) is
     enumerated and every entry must match a row in the committed
     unexecuted-sites-dispositions.txt, with stale dispositions rejected
     symmetrically
  5  21 forced-error arms (19 denominator canaries + E-form store-ack:736,
     the A6 $(count_lines) shape + F-form quarantine:563, the multi-grep
     pipeline capture): each must emit ARMED, abort naming the site, exit
     non-zero, emit NO sentinel, and have its ledger row already landed
  6  residual sweep with the denominator's own classifier: zero unconverted
     verdict greps, six per-form plants found in the same run

The nine unexecuted sites are the FAILED-branch summary lines, structurally
unreachable in a green run; microtest C11 executes the exact template on a
deterministically red mini-suite so their dispositions cite a measured
execution, not an inference.

First full run: OK — 252 executed + 9 dispositioned = 261, all arms fired,
sweep clean.

Written-by: pepper (sb-it-1-dt)
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NsKce8iZuSuRnu3gVMCBKB
2026-07-31 02:13:23 -05:00
Jason WoltjeandClaude Fable 5 8cb5866a3d test(wake): pin the BASH_LINENO continuation convention at runtime (#973)
The denominator artifact's site coordinates assume a backslash-continuation
helper call reports at its FIRST physical line. That convention was measured
on a developer bash (5.3.x, Fedora); CI runs the bash baked into ci-base
(node:24-alpine), which rebuilds only on push-to-main or tag — so the CI bash
version floats silently between rebuilds, and an artifact validated only
against a developer bash is unverified in the place the gate actually runs.

wake_assert_init now runs a probe under the SAME bash binary executing the
suite (subshell + continuation, the real call shape) and aborts loudly if the
convention does not hold, instead of letting coordinates skew by one line
under everyone. Microtest C10 proves the pin's abort arm fires, via a
test-only WAKE_ASSERT_PIN_BASH interpreter override ($BASH itself cannot be
spoofed — bash resets it at startup): a pin whose failure arm was never seen
firing is an undertaking, not a control.

Prompted by mos-dt's CI-bash-float finding (prereg addendum 4, ddea1bc7b).

Written-by: pepper (sb-it-1-dt)
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NsKce8iZuSuRnu3gVMCBKB
2026-07-31 02:04:56 -05:00
Jason WoltjeandClaude Fable 5 10a7fe43c5 wake/#973: convert all 261 grep-verdict sites to has_match/count_lines
Mechanical conversion driven by the frozen denominator artifact
(validate-973/convert-973.py, committed for auditability): every row is
byte-verified against the worktree BEFORE any edit — a conversion applied to
a line the denominator did not measure would be the umbrella defect wearing
the converter's clothes — then 233 sites become has_match and 28 grep -c
sites become count_lines, and each suite gains three header lines (source
_wake-common.sh + wake_assert_init) directly after its SCRIPT_DIR line, a
uniform +3 shift for every site coordinate.

Env prefixes are kept (LC_ALL=C has_match — the prefix reaches the grep
child, microtest C8). The two multi-grep pipeline sites
(digest-quarantine:560, install:420) convert BOTH greps: each element is
measurement-bearing, and under pipefail an rc=2 on the left is masked by an
rc=1 on the right — the same defect one pipe deeper. Call-site 2>/dev/null
redirects (the preimage canaries) are kept: ordinary grep noise stays
suppressed, while an abort writes to the wake_assert_init-saved real stderr.

Diff arithmetic: +291/-261 = 261 one-for-one line replacements + 30 header
lines (10 suites x 3). Nothing in this commit is not the conversion.

All ten suites run green after conversion. Per the review pre-registration
(A9) that green is NON-EVIDENCE for this change: a suite that was green
before conversion and green after witnesses nothing about whether the sites
were converted — the counted-ledger equality in the validation harness is
the evidence.

Written-by: pepper (sb-it-1-dt)
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NsKce8iZuSuRnu3gVMCBKB
2026-07-31 01:58:26 -05:00
Jason WoltjeandClaude Fable 5 6109f81769 wake/#973: three-valued grep assertion helpers + instrument micro-test
has_match/count_lines in _wake-common.sh: rc 0 -> match, rc 1 -> no-match,
anything else -> loud abort naming the call site, the raw exit code, and the
arguments — an error never becomes a verdict. The abort escapes subshells,
pipelines, and $() substitutions by signalling the suite's main shell, so
the suite dies verdict-less; loudness survives call-site 2>/dev/null via a
wake_assert_init-saved stderr fd (dynamically allocated >= 10, no collision
with the wake lock fd 8 or detector run-loop fd 9).

Validate instrumentation (evidence only, inert in production):
WAKE_ASSERT_LEDGER appends "<helper> <file>:<line>" BEFORE the grep runs, so
an aborting site's row has already landed and the counted ledger can never
go quiet in the one condition it exists to report.
WAKE_ASSERT_FORCE_GREP_ERROR_AT=<file>:<line> routes exactly that call site
through a REAL grep driven onto its real error path (rc 2) and emits a
positive ARMED confirmation first, so arm-never-matched (no ARMED line) and
error-path-broken (ARMED line, no abort) are separable on stderr alone.

validate-973/microtest-wake-assert.sh: nine checks (C1..C9) proving the
instrument before any conversion trusts it — ledger set equality across two
files, truncation detection behind an early exit, per-shape abort proofs
(subshell, 2>/dev/null canary shape, $() count capture, pipeline tail),
count-of-zero on grep rc 1, env-prefix reaching the grep child, and a
no-match arm loud by omission. All nine pass; C1 pins BASH_LINENO's
first-physical-line convention for backslash continuations, matching the
denominator artifact's coordinates.

Production tools (store.sh, ack.sh) source this file but call none of the
new helpers.

Written-by: pepper (sb-it-1-dt)
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NsKce8iZuSuRnu3gVMCBKB
2026-07-31 01:52:56 -05:00
Jason WoltjeandClaude Fable 5 7833ddbf4e chore(wake): #973 frozen denominator at branch base — 261 grep-verdict sites, 19 credential canaries
The conversion target, frozen BEFORE any conversion so completeness can be
asserted by set equality against a list that predates the batch (a control
keyed on the post-fix source can only agree with it). Derived per the amended
charter A1: frozen 257 @ 8d1d6e5 forward-mapped with per-row drift disposition
(214 unchanged / 43 moved / 0 deleted / 0 text-changed, byte-verified) UNION a
fresh six-form derivation at 089615f (self-checked by exact 257 reproduction at
8d1d6e5). Delta = exactly the four T17 sites introduced by 47f8689 (#967),
independently derived twice. A 204 (167 OR / 37 AND-inverted), count-capture 28,
B 6, C 10, D-if 9, F 4. Canaries 19 (9 same-line, 3 continuation, 7 if-form),
all AND-polarity: every one fails toward GREEN on grep error.

Charter: jarvis-brain docs/journal/fleet/charter-973-has-match__mos-dt.md @ fa551c2d0.

Written-by: pepper (sb-it-1-dt)
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NsKce8iZuSuRnu3gVMCBKB
2026-07-31 01:28:43 -05:00
37 changed files with 75 additions and 5673 deletions
-8
View File
@@ -4,14 +4,6 @@ pnpm-lock.yaml
**/node_modules
**/drizzle
**/.next
# Python build/test artifacts — same category as node_modules/dist/.next above.
# Prettier must never scan generated trees; without these a local venv poisons
# `pnpm format:check` with thousands of third-party files.
**/venv
**/__pycache__
**/.mypy_cache
**/.pytest_cache
**/htmlcov
.claude/
docs/tess/TASKS.md
docs/scratchpads/
-5
View File
@@ -41,11 +41,6 @@ steps:
# (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
-58
View File
@@ -1,58 +0,0 @@
# RM-02 / PR #1030 — PRE-REGISTERED RE-REVIEW: the merge-base anchor round
**Subject head (exact):** `fbb61912981abb250d289ec7aafd4316db6fdb11`
**Supersedes:** the second NO-GO at `32b490a7` (D-45/D-46/D-47). That verdict is VOID.
**Registered by:** `mos-remediation` **before any reviewer read the diff.** **Reviewer:** `rev-974`.
## What the orchestrator already reproduced (do not re-spend the review here)
- Derived boundary `f4fd5967` **equals** an independently computed `git merge-base HEAD origin/main`.
- Emptying `criteria`/`gates`/`proseClaims`/`compatibilityScenarios` now fails with
_"population must be non-empty and anchored before evaluation"_.
- The both-directions bootstrap statement is present in `gate-history.mjs` with the Builds 12 residual.
## A — attack the ANCHOR (highest value)
| id | check |
| ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **A1** | `targetRef` is the literal `refs/remotes/origin/main`. **Who controls that ref in the environment where the gate runs?** Can a PR author influence it — a `remote.origin.url` rewrite, a crafted `refs/remotes/origin/main` in their own clone, a push to a fork's `main`? If the gate trusts a locally-writable ref, the anchor moved from the manifest into git config. |
| **A2** | **Absent/stale target:** if `refs/remotes/origin/main` is missing, stale, or the fetch is shallow, does it fail CLOSED (line 57 suggests it does) or silently derive a narrower range? |
| **A3** | **Delayed introduction — the round-2 attack, re-run.** Commit a gate change BEFORE adding the manifest. Does it now stay in range and fail the own-tree read? |
| **A4** | **Branch from an old main:** branch from a point far behind `origin/main`, so merge-base is old. Does the range widen correctly (safe) or include unrelated main commits that cannot carry manifests (a new false-red)? Over-inclusion is the natural failure mode of this fix. |
| **A5** | Is the **bootstrap residual** recorded as a **tracked dependency on Builds 12**, not prose? (D-19's third mandatory move.) |
## P — the non-empty/anchored precondition
| id | check |
| ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **P1** | Does the precondition run **before** every quantified check, on **every** path — or only the ones the author enumerated? Find a quantified check that still runs before its precondition. |
| **P2** | **Seven required gate IDs anchored to canonical sources** — can that anchor list itself be emptied, shrunk, or pointed elsewhere? An anchor list the author edits is D-45 again, one level in. |
| **P3** | The author reports finding and REMOVING a **production CLI fixture-profile bypass** in their own pre-commit review. **Verify it is gone from the shipped CLI path**, that the remaining relaxation is test-support only and non-executable in production, and that the CLI rejection is tested. This was self-disclosed — confirm it independently. |
## Q — clauses quantified over the population (D-47)
| id | check |
| ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Q1** | `gateRefs` **exactly spans** every registered gate. Can a gate be added WITHOUT a corresponding ref — i.e. does adding a gate to the population escape the clause? |
| **Q2** | Deleting `gateRefs`, or shrinking gates and refs **together**, must fail. Shrink-together is the D-46 shape; verify it is a genuine control and not a regression guard mislabelled. |
| **Q3** | Do the population controls **iterate all seven gates** and mutate evidence-subject and comparison-type **per gate**, or only a representative one? |
| **Q4** | Honest labelling: author claims delayed-introduction, empty-populations, fixture-profile bypass and removable gateRefs as **genuine red-first**, and shrink-together/exact-span as **regression guards**. Verify each claim against pre-fix code (D-8). |
## C — head, CI, integrity
| id | check |
| ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **C1** | Head `fbb61912` on git and provider; `Closes #1029` present. |
| **C2** | Exact-head CI terminal-green, full `-f json`, counts stated incl. `clone`; machine-checked with `verify-terminal-green.py --expect-commit fbb61912981abb250d289ec7aafd4316db6fdb11`. |
| **C3** | Nothing weakened: `32b490a7``fbb61912` removes/relaxes no existing case, test, or assertion. |
## Reviewer instruction
Verdict bound to `fbb61912981abb250d289ec7aafd4316db6fdb11`, evidence enumerated, posted durably under
your own identity. If a check is unrunnable, **say so**.
**A1 and P2 are the ones I most want answered** — both ask whether the fix moved the author's control
point again rather than removing it, which is now the mission's named first-class principle and has
recurred three times. **Attack outside this set.**
**No one dispatching this review may state a conclusion on an open check (D-39).**
-67
View File
@@ -1,67 +0,0 @@
# RM-02 / PR #1030 — PRE-REGISTERED RE-REVIEW: the four-blocker hardening pass
**Subject head (exact):** `32b490a712a5e8e77f13c40c60099b51feb38994`
**Supersedes:** the NO-GO at `83d2ecb2` (D-44, four silent-defeat paths). That verdict is VOID.
**Registered by:** `mos-remediation` **before any reviewer read the diff.** **Reviewer:** `rev-974`.
## Framing — attack the FIX, not the original bug
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 highest-value checks here are **not** "was each blocker fixed" — the orchestrator already
reproduced three of the four attacks as dead — but **"is the NEW mechanism itself defeatable?"**
Blocker 1's fix replaced an author-settable field with a **derivation**. A derivation has inputs. **The
question is who controls them.**
## H — the new derivation (highest value)
| id | check |
| ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **H1** | `deriveHistoryBoundary` = parent of the first first-parent commit introducing `gates/gates.manifest.json`. **Are its inputs author-controlled?** Can a PR author influence the derived value by adding, moving, renaming, deleting-and-recreating, or symlinking that path — or by adding a SECOND manifest earlier in history? If the derivation is gameable, blocker 1 is not fixed, only relocated. |
| **H2** | **First-parent traversal:** what happens on a merge commit, an octopus merge, a squash, a rebase that reorders, or a branch where the introducing commit is not on the first-parent chain? Does the boundary silently move, or fail closed? |
| **H3** | **Shallow/partial clone:** the branch previously needed an unshallow fix (`e8959975` "unshallow gate replay history"). If history is shallow, does the derivation fail CLOSED or silently derive a wrong/empty boundary? |
| **H4** | **Path deletion:** if `gates/gates.manifest.json` is absent at HEAD, or was deleted and re-added, what is derived? Fail closed, or a boundary that excludes the deletion window? |
| **H5** | Are the **three registered seam controls (HEAD, HEAD^, introduction) genuinely RED-FIRST** — do they fail against the PRE-fix code for their own stated reason? A control that was always green is a regression guard, not a must-fail control (D-8). |
## S — the recursive schema closure
| id | check |
| ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **S1** | **Is closure COMPLETE or enumerated?** The author lists the objects they closed. Find one they did **not** — any nested object anywhere in the manifest — and inject an unknown key there. If it is accepted, the fix covers instances, not the class. |
| **S2** | **Wrong-type, not just unknown-key:** `outputPattern` as a number/array/object/null rather than misspelled. Does the closed schema type-check values, or only key names? |
| **S3** | **Empty/degenerate values:** `outputPattern: ""` — does an empty regex match everything and silently neuter the assertion the same way a typo did? The author claims an empty-pattern control; verify it is bound. |
| **S4** | Confirm the registered typo/wrong-type/empty-pattern controls are **genuine red-first** against pre-fix code, and that anything labelled a regression guard is honestly labelled as one. |
## E — provider evidence (blocker 4)
| id | check |
| ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **E1** | Global validation runs **before** per-commit filtering **on every path**, including the HEAD-only path the author calls out. Is there any code path that reaches per-commit assessment without it? |
| **E2** | **Duplicate identity by another key:** the fix makes pipeline NUMBER globally unique. Can two records still collide on a different identity dimension — same commit + different number, same URL, same step-id — and certify the wrong subject? |
| **E3** | "Exactly one gate-verify step per record" — what if a record has zero, or two with different outcomes? Fail closed? |
## C — clauses, integrity, CI
| id | check |
| ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **C1** | The three new criteria (`RM02-EVIDENCE-SUBJECT-BINDING`, `RM02-TYPE-STRICT-SCHEMA`, `RM02-HISTORY-BOUNDARY`) are **checked criteria with bidirectionally bound cases**, not prose. Orchestrator observed caseRefs 1 / 3 / 3 — verify the bindings actually run and can fail. |
| **C2** | **B1/B2 satisfied in substance:** does `RM02-EVIDENCE-SUBJECT-BINDING` express D-38 generally ("does this gate bind its evidence to its subject?") or only the one pipeline-number instance? Same for D-40 vs the one typo instance. **A clause that only covers its originating instance is not a clause.** |
| **C3** | **Nothing weakened:** diff `83d2ecb2``32b490a7` removes/relaxes no existing case, test, or assertion. |
| **C4** | Exact-head CI terminal-green, full `-f json`, counts stated **including `clone`**; machine-checked with `verify-terminal-green.py --expect-commit 32b490a712a5e8e77f13c40c60099b51feb38994`. |
| **C5** | `Closes #1029` still present (D-38c). |
## Reviewer instruction
Verdict bound to `32b490a712a5e8e77f13c40c60099b51feb38994`, evidence enumerated, posted durably under
your own identity. If a check is unrunnable, **say so** — never substitute a passing variant.
**H1 and S1 are the two I most want answered**, because they ask whether each fix closed a **class** or
an **instance**. Attack outside this set: four of the last five blockers on this PR came from mutating
something nobody had registered.
**Environment note:** `pnpm gate:verify` fails on `checkout-preflight` with outcome 42 (bubblewrap
class) in at least one worktree. If you hit it, report it as an environment limitation — do not treat it
as a finding, and do not let it mask one.
**No one dispatching this review may state a conclusion on an open check (D-39).**
-59
View File
@@ -1,59 +0,0 @@
# RM-02 / PR #1030 — PRE-REGISTERED RE-REVIEW: honest narrowing + (d)-strict
**Subject head (exact):** `e910a45ab3578a9c77ad3eeaa52b31b72611f6c6`
**Supersedes:** the third NO-GO at `fbb61912` (D-45/D-46/D-47) and the D-52 stop. Those are VOID.
**Registered by:** `mos-remediation` before any reviewer read the diff. **Reviewer:** `rev-974`.
## Already reproduced by the orchestrator (do not re-spend here)
- The required narrowing sentence is **verbatim** in `gates/required-gates.baseline.json` and in
`scripts/gate-inventory-claim-control.mjs`: _"Detects accidental and incompetent inventory drift
within a checkout; does NOT survive an adversary who rewrites baseline, manifest, and verifier
consistently — that guarantee requires RM-60's external boundary."_
- **The overclaim control FIRES**: clean ⇒ exit 0; injecting "protected, independently anchored" into
the baseline purpose ⇒ **exit 84**, `INVENTORY_CLAIM_OVERSTATED`.
- CI #2201 at the exact head, 10/10 incl. `clone`; machine check bound, `exempted_steps 0`, no anomalies.
## N — the narrowing (D-52's ruling is the wording)
| id | check |
| ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **N1** | ★ Is the narrowed claim **honest EVERYWHERE**, or only where the control looks? Find any place — docs, comments, observations, manifest prose, CLI output — that still implies the baseline is protected or independently anchored. **The control only checks the files it checks.** |
| **N2** | ★ Can the **overclaim control itself** be defeated? It is PR-controlled like everything else. Weaken/skip/reword it so an overstatement passes. If it can be trivially neutered, D-52 is re-armed one level down — the exact recursion this PR keeps producing. |
| **N3** | Does the control detect **semantic** overclaim or only the literal strings it greps? An artifact could assert protection in different words and pass. |
| **N4** | Is the narrowed claim **TRUE**? Verify the baseline genuinely catches accidental/inconsistent drift — not just that it says so. A narrowed claim that is still overstated is D-48 again. |
## H — (d)-strict history removal
| id | check |
| ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **H1** | Is the verifier **structurally incapable** of reporting history-provenance-verified, or merely not currently doing so? The manifest says "structurally incapable" — test the claim. |
| **H2** | ★ **TRAP 1 re-check:** nothing emits the unverifiable state as an OBSERVATION (which exits 0). Confirm no path yields exit 0 while implying provenance was considered. |
| **H3** | ★ **TRAP 2 re-check:** the exclusion is **enforced**, not merely declared in `coverageBoundary.excluded`. Re-enable history provenance without a trustworthy anchor — does a registered case go RED? |
| **H4** | The residual is stated **correctly** — no local git state is trustworthy because PR code executes before the gate — **NOT** the D-48 wording ("compromised main"). |
## B3 / R — evidence-subject and renderer
| id | check |
| ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **B1** | Subject is on the **EVIDENCE side** and compared **at consumption**, not `gate.evidenceSubject === gate.id` metadata-vs-itself. Mutate the evidence-side subject **per gate**. |
| **B2** | Can evidence still be moved or misbound while every gate satisfies its check? |
| **R1** | Renderer now covers the **final success stdout/stderr** paths. |
## C — integrity + CI
| id | check |
| ------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| **C1** | Head `e910a45a` on git + provider; `Closes #1029` present. |
| **C2** | Exact-head CI terminal-green, `-f json`, counts incl. `clone`; machine-checked with `--expect-commit e910a45ab3578a9c77ad3eeaa52b31b72611f6c6`. |
| **C3** | Nothing weakened `fbb61912``e910a45a`. Red-first labels honest (D-8). |
| **C4** | **NO fourth local anchor was invented.** Blocker 1 and blocker 2's adversarial guarantee both track RM-60. |
## Reviewer instruction
Verdict bound to `e910a45ab3578a9c77ad3eeaa52b31b72611f6c6`, evidence enumerated, posted durably.
Unrunnable ⇒ **say so**. **N1 and N2 are the sharp ones** — this PR's history is that every fix
relocates the defect one level down, and N2 asks whether the control that enforces honesty is itself
honest. **Attack outside the set: six for six so far.**
**No one dispatching this review may state a conclusion on an open check (D-39).**
-71
View File
@@ -1,71 +0,0 @@
# RM-02 / PR #1030 — PRE-REGISTERED ACCEPTANCE CHECKS (post-rebase, keystone)
**Subject head (exact):** `83d2ecb2243f1b0987ef2bc14de47f444285a684`
**Rebased onto:** `main` @ `f4fd5967fc5d4cbc72d680b199d88224aa855131` (post-RM-61)
**Registered by:** `mos-remediation` **BEFORE the reviewer read the diff.** **Reviewer:** `rev-974`
(author ≠ reviewer; branch commits are `f10-coder`'s and `coder-mos1`'s).
**Prior reviews 63 / 65 are SUPERSEDED; this head carries NO live review of any kind.**
RM-02 is the **keystone**: it is the anti-inert-gate registry every downstream gate is measured against.
A defect that survives here propagates into every gate this mission ships.
## ★ CRUX — the one non-mechanical change, made by the author, that turned a red green
The rebase was clean. One further commit was **not** purely mechanical and the author disclosed it
unprompted (`83d2ecb2` — advance registry activation seam):
gates/gates.manifest.json
- "activationCommit": "f65e9ea656ec466e12640bf6ab5d46fe07ff160c"
+ "activationCommit": "f4fd5967fc5d4cbc72d680b199d88224aa855131"
Stated rationale: after the rebase, `pnpm gate:verify` correctly failed because the newly-merged
pre-registry RM-61 commit was treated as _prospective_ and required a manifest that could not exist.
`activationCommit` sets the lower bound of `activationCommit..HEAD` — **the set of commits required to
carry own-tree registry provenance** (`gate-history.mjs:314``listProspectiveCommits`). Advancing it
**shrinks that set**.
**Determine, do not assume — and I have deliberately formed and stated no verdict (D-39):**
| id | check |
| ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **A1** | **Is the advance JUSTIFIED?** Can a pre-registry commit on `main` (e.g. `f4fd5967`) satisfy the provenance requirement at all, or is requiring it impossible-by-construction? If impossible, is advancing the seam the _correct_ remedy, or does a correct remedy exist that does not move an author-controlled field? |
| **A2** | **Is the advance MINIMAL?** Was it advanced exactly to the new parent baseline, or beyond it? Does any commit that _should_ remain covered fall outside the new range? |
| **A3** | **Are all 7 branch commits still PROSPECTIVE under the new seam?** Enumerate them and show each is still required to carry provenance. The author claims "own-tree provenance over every registry-era branch commit" — verify the claim, do not accept it. |
| **A4** | ★★ **IS THE SEAM ITSELF CONSTRAINED?** The only validation found is `merge-base --is-ancestor activationCommit head` (`gate-history.mjs:288`). **A commit is its own ancestor.** Determine what `activationCommit = HEAD` does: is the prospective range empty, does the per-commit loop iterate zero times, and does the history check therefore PASS VACUOUSLY? If so, the anti-inert-gate registry contains an author-settable field that can inert its own history check. **Run it. Report the observed exit and whether any failure is raised.** |
| **A5** | **If A4 shows vacuity is reachable, is there a registered MUST-FAIL negative control for it?** RM-02's own founding rule is that a gate with no proven failure path manufactures evidence. Does the registry hold a case that goes RED when the seam is over-advanced? If not, that is a hole in the registry's coverage of itself. |
| **A6** | **Self-verification shape (charter / D-19 / D-39b):** the field was advanced by the change's own author to make the author's gate pass. Independent of whether the value is correct, determine whether the _mechanism_ permits an audited party to relax its own audit, and whether that needs a constraint, an owner, or an escalation. |
## Registry substance — the clauses this PR must now carry
| id | check |
| ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **B1** | **D-38 clause present and enforced:** the registry asks of every gate _"does this gate BIND its evidence to the subject under review?"_ Ruled in-scope for THIS PR by Mos. Verify it exists as a checked clause, not prose. |
| **B2** | **D-40 clause present and enforced:** _"discriminator and comparison inputs must be TYPE-STRICT."_ Also ruled in-scope for THIS PR. `== 0` matching `False`/`0.0` is the banked instance; the clause is the general form. |
| **B3** | **D-42's clause is CORRECTLY ABSENT** — provider-side negative control tracks separately (Mos: landing it now would give the registry a clause with nothing to satisfy it, going red on its own clause). Confirm its absence is deliberate and recorded, not forgotten. |
| **B4** | **The four founding clauses still hold** (`MISSION.md`): every check proven **right** (red for its own stated reason), the set **covers**, no two criteria **conflict**, and criterion evolution **retains original text + restatement + reason**. |
| **B5** | **Nothing was weakened, skipped, or deleted by the rebase.** Diff `f9746b23``83d2ecb2` and confirm no registered case, test, or assertion was removed or relaxed to make the rebase land. |
| **B6** | **`coverageBoundary.excluded[]` is honest in BOTH directions** (charter principle 4): what it does NOT cover is stated beside what it DOES, and the gap is tracked (`trackedBy: RM-54`) rather than implied-fixed. |
| **B7** | **The RM-02 execution boundary** (`gate-history.mjs`, DOES / DOES NOT, owner RM-60, xref RM-59) states its limits in both directions and names a tracked owner — not a documented gap with no owner. |
## Head + CI (re-run these; do not carry them forward from the author's report)
| id | check |
| ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **C1** | Head `83d2ecb2…` on **both** git and provider; `Closes #1029` present in the body (delivery-issue rule, D-38c). |
| **C2** | Exact-head CI terminal-green by **full `-f json` scan**, counts stated **including `clone`**. Note the count changed 9 → **10** (this PR adds `gate-verify`) — confirm the new step is real, not a miscount. |
| **C3** | **Machine-check it, do not assert it:** `verify-terminal-green.py --expect-commit 83d2ecb2243f1b0987ef2bc14de47f444285a684`. Report exit, `exempted_steps`, `commit == expected_commit`. |
| **C4** | `exempted_steps=0` is expected here — `ci-postgres` succeeded, so the #1000 exemption was **not needed**. Confirm the exemption is present-but-unused rather than silently inapplicable. |
## Reviewer instruction
Verdict bound to `83d2ecb2243f1b0987ef2bc14de47f444285a684`, evidence enumerated per check, posted
durably under your own identity. If a check is unrunnable, **say so** — never substitute a variant that
passes. Scan CI from `-f json`, never default text (D-33); state your counts.
**A4 is the check I most want an answer to and the one I have least confidence about.** Attack outside
this set as well: every blocker found on this mission so far came from mutating something nobody had
registered a check for.
**No one dispatching this review may state a conclusion on an open check (D-39).** Observations may be
relayed to you; verdicts may not. The ruling is yours.
-42
View File
@@ -1,42 +0,0 @@
# RM-03 / PR #1032 — PRE-REGISTERED RE-REVIEW (post-freshening)
**Subject head (exact):** `868b9b871a5118762aa5b8aafecd2f0592f7ab5c`
**Rebased onto:** `main` @ `f4fd5967` **Registered by:** `mos-remediation` before the reviewer read the
diff. **Reviewer:** `rev-974`.
**Why this exists:** review 66 APPROVED and the merge-gate GO were bound to `78ec47cd`; `main` drifted
under a long hold and the PR went `mergeable=false` (**D-50 — a GO has a shelf life**). Both verdicts
are VOID at the new head. Jason's merge approval is **standing** and executes once this re-gates.
## What the orchestrator already verified (do not re-spend here)
- `git range-diff 78ec47cd...868b9b87`: commits **25 are `=` (patch-equivalent)**; only commit 1 differs.
- That single difference is the `test:framework-shell` chain, resolved as a **UNION** — main's
`test-terminal-green-contract.sh` **and** RM-03's `tristate`, `github-checks`, `merge-queue-branch`,
`merge-head-pin`, plus the pre-existing `branch-absent`. **Nothing dropped from either side.**
- CI #2199 at the exact head: 9 children, 9 success incl. `clone`; machine check exit 0, bound, no anomalies.
- `mergeable` is now **true**.
## Checks
| id | check |
| ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **R1** | ★ **THE GUARD CAN FAIL.** RM-03 exists because the queue guard is ZERO-INFORMATION (D-23) — it returns pass for every possible input. Prove the rebased head's guard **actually fails** on asserted non-readiness, not merely that its tests pass. This is the whole deliverable. |
| **R2** | ★ **NO QUEUE-GUARD SEMANTIC MOVED IN THE REBASE.** Confirm the range-diff equivalence independently. A queue-guard semantic resolved quietly re-breaks the thing this PR fixes. |
| **R3** | **Union is complete in BOTH directions:** no RM-03 suite lost to main's version, no main suite (esp. `test-terminal-green-contract.sh`) lost to RM-03's. Enumeration count reconciles. |
| **R4** | **Tri-state is real** (`verified` / `written-unverified` / `failed`) — P-WRAPPER-001. Verify an indeterminate result cannot present as a pass; that is the exact defect (`state=unknown exit 0`). |
| **R5** | The guard's **exit-asserting non-null-case** tests are genuine — each fails for its own stated reason against pre-fix code, not merely present (D-8). |
| **R6** | `test:framework-shell` is **runnable to completion in CI** (canonical env). Known: it exits 97 on some hosts via a Bash 5.2.15 `BASH_LINENO` assertion — if you hit that, report it as an environment limitation, do not treat it as a finding and do not let it mask one. |
| **R7** | Exact-head CI terminal-green, full `-f json`, counts stated incl. `clone`; machine-checked with `--expect-commit 868b9b871a5118762aa5b8aafecd2f0592f7ab5c`. |
| **R8** | `Closes #1019` present in the body (D-38c delivery-issue rule). |
| **R9** | Nothing weakened by the rebase: no test, case, or assertion removed or relaxed to make it land. |
## Reviewer instruction
Verdict bound to `868b9b871a5118762aa5b8aafecd2f0592f7ab5c`, evidence enumerated, posted durably under
your own identity. If a check is unrunnable, **say so**.
**R1 is the deliverable and R2 is the risk.** Attack outside this set. **Do not cite the queue guard's
own green as evidence of anything** — it remains inert until this very PR lands (D-23).
**No one dispatching this review may state a conclusion on an open check (D-39).**
@@ -1,40 +0,0 @@
# RM-61 / PR #1033 — PRE-REGISTERED RE-REVIEW ACCEPTANCE CHECKS
**Subject head (exact):** `033b2ffb46674b2c0bcc5197273c109b461f62d9`
**Supersedes:** review 67 / comment 20403 @ `e7b29219` (NO GO). That verdict is VOID — the head moved.
**Registered by:** `mos-remediation` (orchestrator). **Reviewer:** `rev-974` (author ≠ reviewer).
**Registered BEFORE the reviewer read the diff.** Any head move after this file is committed voids the
re-review and requires re-registration.
## Scope discipline
The prior review passed AC1AC8 and still found a blocker, because the registered set tested whether the
signature DISCRIMINATES and never tested whether the evidence was BOUND TO ITS SUBJECT (Finding 3 /
coverage-failure-mode-2, D-17 class). This set therefore carries the binding property as a first-class
check, and **RR7 explicitly invites the reviewer to attack outside the set** — a registered set is
protection against retrofitting only, never a ceiling on scrutiny.
## Checks
| id | check | verdict form |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------- |
| **RR1** | The full 12-case contract harness passes at the exact head: `bash test-terminal-green-contract.sh` | ⇒0, and states 12 cases |
| **RR2** | ★CRUX — the ORIGINAL ATTACK IS DEAD. Take the real `#2188` record, mutate ONLY `commit` to an unrelated 40-hex value, verify against the true expected head | ⇒1, `exempted_steps == 0`, anomaly naming expected vs actual |
| **RR3** | Missing `--expect-commit` cannot be defaulted, inferred, or skipped | ⇒2 (not 0, not 1) |
| **RR4** | Malformed expected commit (short SHA, non-hex, empty) is rejected — no silent normalisation into a pass | ⇒2 |
| **RR5** | A record with the `commit` key ABSENT (not merely different) is rejected — fail-closed on missing, not just on mismatch | ⇒1, `exempted_steps == 0` |
| **RR6** | The genuine artifact still passes when correctly bound: real `#2188` + its true head | ⇒0, `exempted_steps == 1`, exactly one `WP-K8S-1000-CI-POSTGRES-TEARDOWN` |
| **RR7** | ★RED-FIRST, PROVED RETROACTIVELY. The four new cases must FAIL against the OLD verifier at `e7b29219` — otherwise they do not test what they claim (D-8 class). Run the new cases against the previous implementation | new cases ⇒≠0 under `e7b29219` |
| **RR8** | AC2 OF THE PRIOR SET DID NOT REGRESS: both REAL controls stay terminal red — `#2189` (`ci-postgres` exit 1) and `#2191` (exit 137, `test` exit 61) | both ⇒1, `exempted_steps == 0` |
| **RR9** | Still NO fetch / trigger / retry / re-roll / sleep / network of any kind in the verifier or harness. The coin flip must remain removed, not codified (D-21) | grep ⇒ no such call sites |
| **RR10** | The doc/baseline changes REQUIRE the current provider PR head to be passed — they must not merely mention it. Check `merge-gate.md`, `CI-CD-PIPELINES.md`, `woodpecker/README.md` state it as a requirement a gate operator cannot satisfy by omission | reviewer judgement, quote the lines |
| **RR11** | Exemption remains bound to #1000 and retires with it; signature conjunction unchanged and not widened by this fix | diff-scoped, ⇒ no widening |
| **RR12** | Case-sensitivity: an uppercase-hex record commit against a lowercase expected head must NOT silently pass by accident of comparison. State which way it resolves and whether it fails closed | state the observed behaviour |
## Reviewer instruction
Report the verdict **bound to `033b2ffb46674b2c0bcc5197273c109b461f62d9`** and state each check's
observed result, including counts read from `pipeline-status.sh -f json` (never default text — it omits
`clone`, D-33). If any check is unrunnable, **say so** — never substitute a passing variant. Attack
outside this set and report anything it finds; RR7 and RR12 exist because the last blocker was found
exactly that way.
-60
View File
@@ -1,60 +0,0 @@
# RM-61 / PR #1033 — PRE-REGISTERED ACCEPTANCE CHECKS: `exit_code` TYPE-STRICTNESS (D-40)
**Registered by:** `mos-remediation` (orchestrator) — **BEFORE the fix was pushed and before any
reviewer read a diff.** At registration time the fix existed only as an unpushed local commit
(`6e7a336d`) on coder-mos1's machine which **I have not read**. There is therefore no diff for these
checks to have been retrofitted to.
**Subject head:** TBD — binds to the NEW head once coder-mos1 pushes. The prior head
`033b2ffb46674b2c0bcc5197273c109b461f62d9` and its review 69 / pipeline #2193 go VOID on that push;
that cost was accepted deliberately by Mos's BLOCKING ruling on D-40.
**Ruling being enforced (Mos, 2026-08-01):** `exit_code` must be accepted ONLY as a real integer.
`false`, `0.0`, `"0"`, and `null` must all fail to satisfy the exemption. Wrong-ACCEPT is the
disqualifying direction; this hole sits inside the load-bearing discriminator.
## ⚠ Read this before writing the tests — RED-FIRST HERE IS NOT UNIFORM
Two of the four near-miss values **already block** at `033b2ffb`. Demanding "all four observed RED
first" would be demanding an impossible red for two of them, and the predictable response to an
impossible demand is a fudge — weakening something real to manufacture the red. So state it precisely:
| value | behaviour at `033b2ffb` (pre-fix) | what the new case is |
| ------- | --------------------------------- | ------------------------- |
| `false` | **WRONGLY EXEMPTS** (exit 0) | **genuine RED-FIRST** |
| `0.0` | **WRONGLY EXEMPTS** (exit 0) | **genuine RED-FIRST** |
| `"0"` | correctly blocks (exit 1) | **regression guard** only |
| `null` | correctly blocks (exit 1) | **regression guard** only |
Claiming red-first for `"0"` or `null` would be a false claim about your own evidence. Say which is
which. **Do not weaken anything to make a green case go red** (D-8).
## Checks
| id | check | verdict form |
| -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| **TS1** | ★RED-FIRST. `exit_code: false` on the real #2188 record is **observed wrongly exempting at `033b2ffb`** (exit 0, `exempted_steps 1`), then blocks after the fix | pre-fix ⇒0/exempt 1 · post-fix ⇒1/exempt 0 |
| **TS2** | ★RED-FIRST. Same for `exit_code: 0.0` | pre-fix ⇒0/exempt 1 · post-fix ⇒1/exempt 0 |
| **TS3** | REGRESSION GUARD. `exit_code: "0"` blocked before AND after — state honestly that it was already green | both ⇒1, `exempted_steps 0` |
| **TS4** | REGRESSION GUARD. `exit_code: null` blocked before AND after | both ⇒1, `exempted_steps 0` |
| **TS5** | ★NOT OVER-TIGHTENED. The genuine artifact — real #2188, real integer `exit_code: 0`, correctly bound head — still passes | ⇒0, `exempted_steps 1`, exactly one `WP-K8S-1000-CI-POSTGRES-TEARDOWN` |
| **TS6** | The strictness sits on the value the EXEMPTION rests on, not on a cosmetic sibling. Show the guarded comparison is the one feeding `exemption_applies` | reviewer quotes the line |
| **TS7** | `bool` is excluded EXPLICITLY, not incidentally. A bare `isinstance(x, int)` still admits `True`/`False` — verify the `not isinstance(x, bool)` clause exists | ⇒ clause present; `true` also blocks |
| **TS8** | Negative control unaffected: a genuine failed step with a real integer non-zero exit still blocks | ⇒1, `exempted_steps 0` |
| **TS9** | NO REGRESSION ON THE PRIOR ROUND'S BINDING WORK: mutated record commit ⇒1; `--expect-commit` omitted ⇒2; record `commit` absent ⇒1 | ⇒1 / ⇒2 / ⇒1 |
| **TS10** | Signature conjunction NOT widened elsewhere by this fix — `POD_NOT_FOUND` / name / type / state untouched | diff-scoped ⇒ no widening |
| **TS11** | Still no fetch / trigger / retry / re-roll / sleep / network | grep ⇒ no call sites |
| **TS12** | Full harness passes at the new head; **state the case count** (12 previously, expected 16 — confirm the actual number rather than the expected one) | ⇒0, count stated |
## Reviewer instruction
Verdict bound to the NEW head, evidence enumerated per check, CI counts from `pipeline-status.sh -f json`
(never default text — it omits `clone`, D-33). If a check is unrunnable, **say so**; never substitute a
passing variant.
**Attack outside this set and report what you find.** Both blockers on this PR so far — the missing
commit binding, and this type confusion — were found outside the registered set, by mutating a field
nobody had registered a check for. That is now the expectation, not a bonus.
**Nobody dispatching this review may state a conclusion on an open check here (D-39).** If you are sent
an observation, it is an observation; the ruling is yours.
-90
View File
@@ -1,90 +0,0 @@
<!-- board-roll: 1 entry rolled from BOARD.md -->
### **D-1 / P-ACTIVATION + hygiene — committed `.npmrc` hard-pins `store-dir=/root/.local/share/pnpm/store`.**
Correct for the CI container (runs as root), fatal for EVERY non-root local checkout: `EACCES` on `/root/.local/share/pnpm/store/v10/server/server.json`. A committed config that only works on one runtime is exactly the activation-skew class. Fix candidate: make store-dir env-overridable, not hardcoded.
<!-- board-roll: 2 entries rolled from BOARD.md -->
### **D-3 / P-FLEET-001 — the seats running this mission are UNMANAGED.** `mos-remediation`, `rev-974`,
`planner-opus`, `planner-sol` appear in NO roster (`~/.config/mosaic/fleet/roster.yaml`, `agents/`). Planners run on socket `default`; the roster declares `mosaic-fleet`. This is the exact "one roster-owned socket/host + quarantine unmanaged + stale GC" failure P-FLEET-001 indicts — observed on the remediation mission's own fleet. Prerequisite for INBOX identity-addressing.
### **D-2 / hygiene — husky `prepare` fails `EPERM` copying into root-owned `.husky/_/`.** Repo working
tree has root-owned dirs (`.husky/`, repo root) under a non-root agent. Worked around with the intended `HUSKY=0` escape hatch (does NOT disable the existing pre-commit/pre-push hooks).
<!-- board-roll: 2 entries rolled from BOARD.md -->
### **D-5 / P-QUEUE-001 + P-CONFORMANCE-001 — KEYSTONE: an inert gate that erased its own evidence.**
Merged PR #868 (`b79336a8`) shipped a file that FAILS `pnpm format:check` ⇒ the CI format gate did not block. An unrelated later PR (#872) then reformatted that file via its own `lint-staged`, so `main` went green again and nobody learned the gate had failed to fire. Verified blob-level under the repo's own config. **Detection must be per-merge-commit against that commit's own tree** — a "is main green today" check reports all-clear on this exact defect. Binding on RM-02/RM-55. Full chain in `TASKS.md` §1a. NOT quiet-patched, by Mos's ruling: patching the symptom destroys the signal.
### **D-4 / P-LIFECYCLE + hygiene — a dispatched agent silently IGNORED an in-message context reset.**
planner-sol was at 64.3%/372k; the brief asked it to reset first; it began work on dirty context anyway. Only an out-of-band `/new` driven by the orchestrator guaranteed clean state. Confirms the postmortem thesis: **instructions are not enforcement.** Reset must be a mechanical pre-dispatch step, not a request.
<!-- board-roll: 2 entries rolled from BOARD.md -->
### **D-7 / P-FLEET-001 — stale-GC-on-disk: shared 30G /tmp hit 100% ENOSPC, degrading two seats.**
~5.2G was session scratch dead 8-9 days (this session's own footprint: 88K). Same missing capability as orphaned-tmux-session GC, applied to disk — not a quota or discipline problem. Resolved manually by Mos (lead coordinator) after independent verification; `/tmp` now 79%. **The gap IS the finding:** the authority to reap exists, the deterministic reaper does not. Folded into RM-50 with explicit requirements (mechanical liveness, age threshold, dry-run, audit event per reap — never a heuristic sweep). Refusing to unilaterally delete another session's scratch was correct doctrine; the fix is a reaper, not braver agents.
### **D-6 / P-QUEUE-001 — the mandated queue guard returned PASS on an UNKNOWN state, live, today.**
Running the required `ci-queue-wait.sh --purpose push` before pushing produced `state=unknown ... exit 0` — the exact defect at `ci-queue-wait.sh:282-288` that PR #1023 is parked on. It also evaluated `branch=main` rather than the branch being pushed. The mission's own required pre-push gate passed me on an indeterminate result. Third independent live instance of the class.
<!-- board-roll: 1 entry rolled from BOARD.md -->
### **D-8 / P-CONFORMANCE-001 — a PRE-REGISTERED acceptance check that was not runnable as written.**
PR #1025 AC2's fixture `mkdir -p apps/*/venv/lib` creates a literal `apps/*/venv/lib` dir when the glob is unmatched — it did not test what it claimed. rev-974 ran it exactly as written, caught it, re-ran the intended assertion at an explicit path, and **disclosed** rather than silently substituting a working fixture and reporting PASS. **Pre-registration protects a check from being retrofitted to the implementation; it does not make the check correct.** An unverified gate appeared inside the mechanism built to catch unverified gates. Hard requirement on RM-02: the registry must self-verify that every registered case runs AND can fail — presence is not evidence.
<!-- board-roll: Decisions-log narrative rolled from BOARD.md 2026-08-01 (D-43: meet the
byte budget by ROLLING OUT, never by rewording what stays) -->
### Decisions log — full record in [`TASKS.md`](./TASKS.md)
All 44 findings (D-1…D-6 in `BOARD-LEDGER.md`, D-7…D-43 + D-38c in `TASKS.md`) and every ruling with its
rationale live there. **Not duplicated here** — a second copy is a second thing to go stale, which this
board had done three times in one night (gate list, capability registry, DECISION-1 status), and three
more times by the next rotation seam (RM-61 "building", "nothing implemented yet", DECISION-1/2/3
"must be ruled"). The rulings a fresh seat needs are items 47 above; they are **not** repeated here,
because that repetition is what went stale.
<!-- board-roll: Sequencing section rolled verbatim from BOARD.md 2026-08-01 (D-43: meet the
byte budget by ROLLING OUT, never by rewording what stays). Canonical: MISSION.md + TASKS.md §5 -->
### Sequencing — see [`MISSION.md`](./MISSION.md)
Builds 1-5, the cross-cutting retirements, and DECISION-1's corrected wire-in target are stated once in
the charter and `TASKS.md` §5. **Not repeated here** — the previous copy of DECISION-1's status on this
board is one of the six stale restatements below.
<!-- board-roll: capability/seat-identity bullets rolled verbatim from BOARD.md 2026-08-01
(D-43: roll out, never reword). Authoritative home: TASKS.md D-11 / D-11a / D-11b. -->
- Capability is **per-path** (D-11b → **superseded in part by D-13/D-15**): a token file is **necessary,
not sufficient**. Three layers — token file (raw-API), `tea` login (tea paths), **repository permission**
(writes). Before dispatch, assert `permissions.push == true` **as that seat**, not token existence and
not a 200 on a read. Mos owns provisioning; escalate missing pairs.
- Seat identity (D-11a): token identity AND `git config user.name`/`user.email` must BOTH be set and
agree. Exporting `MOSAIC_GIT_IDENTITY` alone does NOT fix commit authorship.
<!-- board-roll: D-26 gate-restatement rationale rolled verbatim from BOARD.md 2026-08-01 -->
### Why the board must not restate the delivery gates (D-26)
Restating the gate from memory is how the merge-gate step went missing from mission setup twice,
once inside the correction for it (**D-26**).
<!-- board-roll: Fleet seats rolled verbatim from BOARD.md 2026-08-01 (D-43: roll out, never
reword). NOTE: all these seats are UNMANAGED per D-41; `mosaic fleet ps` is live truth. -->
## Fleet seats
- mos-remediation — project orchestrator (Claude, /src/mosaic-stack, socket `mosaic-fleet`) — ACTIVE
- planner-opus — adversarial planner (robustness), Opus 5, socket `default` — DELIVERED, idle
- planner-sol — adversarial planner (pragmatic), gpt-5.6-sol, socket `default` — DELIVERED, idle
- rev-974 — mosaicstack reviewer identity (id 16, write:repository) — idle, on call
- Mos (mos-claude) — lead coordinator, socket `default` — relay path to Jason
-83
View File
@@ -1,83 +0,0 @@
# mos-remediation — LIVE BOARD (keep < 8 KB)
**Phase:** EXECUTING — RM-03 at owner-merge; RM-61 **MERGED**; **RM-02 keystone is the front**.
**Updated:** 2026-08-01 — seam crossed; successor seat resumed, attested from the files, and is driving.
⚠ That was a **MANUAL pane respawn** (prior seat ~803k tokens): it validates the checkpoint+rehydration
**design**, NOT a lifecycle **mechanism** — P-LIFECYCLE rotation does not exist yet (**D-41 / RM-62**).
## Head
- Charter + 15 decisions + 4-build plan: `MISSION.md`. Backlog + all findings: `TASKS.md`.
- Planning DONE (58 tasks, P0P5). **DECISION-1/2/3 all RULED by Mos 2026-07-31** (`TASKS.md` §5) —
nothing is waiting on a decision. D-2's availability _target_ is Jason-pending and non-blocking.
- **Executing, not planning.** RM-01 is MERGED; three lanes are live (see In-flight).
- Orchestrator seat `mos-remediation` LIVE, owns the mission, resumed across the rotation seam
2026-08-01 and re-attested to Mos from the files. Residency attestation: PASS.
## In-flight
| Task | Owner | State |
| ------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| RM-01 checkout | — | **MERGED** `f58b3699` (#1027) |
| RM-03 queue guard | Jason (re-sync) | ✅ **MERGED** `58b971ab` (#1032), #1019 closed. ⚠ **NOT DELIVERED**: installed guard still the broken one (291 lines / 0 `ASSERTED_NOT_READY` vs main 482 / 5). Re-sync via `mosaic upgrade`, then **prove it blocks a KNOWN-RED pipeline****D-51** |
| RM-02 registry ★key | rev-974 | **RE-REVIEW @ `e910a45a`** — (d)-strict history REMOVED + blocker 2 NARROWED (D-52) + blocker 3 + renderer. Overclaim control **fires at exit 84**, verified by orchestrator. CI 2201 **10/10**. ACs @ `dde38717` |
| RM-61 CI exemption | — | ✅ **MERGED** `f4fd5967` (#1033). #1034 closed; **#1000 stays OPEN** (retirement trigger). Exemption is on `main` |
| RM-59 / RM-60 | Jason (infra) | tracked deps; RM-60 option **B** |
| #1023 queue attempt | Jason | SUPERSEDED-PENDING-JASON — live REQUEST_CHANGES, do **not** merge |
### For the incoming orchestrator — read this before acting
1. **Lane state lives in the In-flight table above — this item does NOT restate it.** It went stale
three times in one session by duplicating that table (D-26's class). Read the table. ⚠ **And
re-derive any board claim from the provider before load-bearing use (D-43)** — the board is
sole-written and has no independent verifier.
2. **`docs/remediation/TASKS.md` is authoritative**, not the newest voice in a chat. It holds 53 findings
(D-1…D-6 in `BOARD-LEDGER.md`, D-7…D-52 + D-38c in TASKS.md), every ruling with its rationale, and the
requirements each finding placed on RM-02/RM-34/RM-50/RM-55.
3. **`MISSION.md` carries the first-class principles** — read them there, they are not listed here.
Two added 2026-08-01: **the anchor must live outside the audited party's authority** (D-19/D-25/D-45,
third arrival) and **no universally-quantified check may pass over an empty set** (D-44/D-46).
4. **Seat identity:** `export MOSAIC_GIT_IDENTITY=<seat>` is stripped by a context reset (**D-34**) —
every dispatch/rehydration brief must re-export it, or the seat cannot use its credentials.
5. **Scan CI from `-f json`, never default text** — text mode omits `clone` (**D-33**). State counts.
6. **The queue guard is zero-information until RM-03 merges** (**D-23**) — never cite its green.
7. **The bounded CI re-roll used on RM-02 was a one-time stopgap, NOT policy.** A per-PR free re-roll is
D-21 normalisation. Do not repeat it; RM-61 is the fix.
## Delivery gates — REFERENCE, do not restate
Canonical: `~/.config/mosaic/fleet/roles.local/merge-gate.md` (verdict authority) +
`~/.config/mosaic/fleet/roles/validator.md`. Order and the freeze/zero-information rules: `MISSION.md`
and `KICKSTART.md`. **Read them there** (why: **D-26**, in `BOARD-LEDGER.md`).
## Fleet seats
Roster rolled verbatim to [`BOARD-LEDGER.md`](./BOARD-LEDGER.md); live truth is `mosaic fleet ps`.
## Gate status
- Freeze: LIFTED for this workstream only.
- Git identity: orchestrator runs `MOSAIC_GIT_IDENTITY=mos-dt-0` INTERIM. Mos ruled gate-16 HOLDS (author≠reviewer is what
gate-16 protects; rev-974 reviews, mos-dt-0 never self-reviews). Dedicated identity TRACKED, Mos provisions.
- Capability + seat identity (**D-11b / D-11a**, incl. the false-NEGATIVE twin): authoritative in
`TASKS.md`. Short form — **assert the DIFFERENTIAL as that seat** (authenticated `push:true` vs
unauthenticated `push:false`); a single endpoint can be true for anyone or 403 for an unrelated
scope. Full text rolled to [`BOARD-LEDGER.md`](./BOARD-LEDGER.md).
-**LIVE HAZARD (D-37) — one shared `.git/config` re-identifies EVERY worktree at once.** Every seat,
including `rev-974`'s review worktree, currently authors as **`coder-mos1`**; `MOSAIC_GIT_IDENTITY`
does **not** override it. **STANDING ORDER: commit with explicit
`git -c user.name=<seat> -c user.email=<seat>@…`, and NOBODY rewrites the shared config mid-flight.**
Real fix authorised, Mos owns it, sequenced at a quiet seam. **#1024 implicated.** Detail: D-37.
- Standing worker-brief doctrine (mandatory in EVERY brief): re-export `MOSAIC_GIT_IDENTITY` (**D-34**);
commit early/WIP (**D-31**); don't weaken a RED test to pass; if a check is unrunnable SAY SO, never
substitute; `agent-send -f` never `-m`; artifacts off shared `/tmp`; scan CI from `-f json` (**D-33**);
**relay observations into an open review, NEVER your own conclusion on an open check (D-39)**; the
**author never adjudicates their own PR's blocker status** — surface evidence, prepare the fix, hold.
- Remote control: native `/remote-control` NOT wired in this runtime. Path is **Mos-relay**
(Jason ↔ mos-claude via Discord ↔ mos-remediation via agent-send). Not a blocker.
## Decisions log — full record in [`TASKS.md`](./TASKS.md)
All 53 findings (D-1…D-6 in `BOARD-LEDGER.md`, D-7…D-52 + D-38c in `TASKS.md`) and every ruling with
its rationale live there. **Not duplicated here.** The history of _why_ this board must not restate —
six stale copies across two seams — is rolled verbatim into [`BOARD-LEDGER.md`](./BOARD-LEDGER.md).
File diff suppressed because it is too large Load Diff
-424
View File
@@ -1,424 +0,0 @@
# Adversarial Decomposition — Pragmatic / Shortest-Path Side
**Planner:** `planner-sol`
**Bias:** make one real fleet task pass through one enforced path as early as possible; reuse before building.
**Scope source:** `MISSION.md`, `MACP-WIRING-SCOUT.md`, `BOARD.md`, existing `@mosaicstack/macp`, `packages/coord`, PG/Valkey, Tess durable inbox/outbox, and the Mission Control PRD.
## Executive position
The first useful milestone is **not** “complete Builds 1 and 2.” It is this narrow vertical slice:
> A DB-backed mission task is atomically claimed by `packages/coord`, executed by one Node `@mosaicstack/macp` TaskExecutor, gated, and terminally recorded with identity-bound events and a tri-state mutation result. No `docs/TASKS.md`, `mission.json`, `tasks.json`, Python gate loop, or NDJSON ledger participates.
That slice is **SOL-03 → SOL-04 → SOL-05 → SOL-06 → SOL-07 → SOL-08**, estimated at **72K tokens**, mostly Codex. PG polling is acceptable for this first proof. Redis acceleration follows only after correctness is observable. This is the shortest path that is both dogfoodable and not throwaway work.
### Cost posture
- **25 PR tasks, ~294K tokens total:** ~164K Codex, ~130K Sonnet, **0K Opus**.
- First live choke-point dogfood: ~72K on the hard path; SOL-01 and SOL-02 can run beside it.
- Opus is not justified for planned implementation. Escalate only if an independent security review finds an unresolved architecture-level authority flaw.
- Every row is one PR. Estimates include implementation, focused tests, docs affected by that PR, and one remediation pass—not orchestration/reviewer overhead.
## Gates and critical path
| gate | opens when | proof required before downstream work |
| ------------------------------------------- | -------------- | --------------------------------------------------------------------------------------------------------- |
| **G0 — trustworthy launch gates** | SOL-01, SOL-02 | non-root checkout works; queue status cannot become false-green |
| **G1 — first dogfood / minimum viable cut** | SOL-08 | one live fleet task completes DB → MACP executor → gates → DB with no flat-file state |
| **G2 — Builds 1+2 closed** | SOL-09..SOL-12 | all producers use the executor; duplicate islands retired; Redis loss is recoverable from PG |
| **G3 — rotation real** | SOL-13..SOL-16 | stale generation cannot mutate; fresh session resumes typed state; Pi-brick recovery works without broker |
| **G4 — sole-path comms real** | SOL-17..SOL-22 | roster identity is stable; bounced/stale messages converge through PG/Redis and adapters |
| **G5 — mission proof** | SOL-23..SOL-25 | workflow sweep cannot capture unknown files; fault bank passes, including 100 rotations |
**Critical path:** `03 → 04 → 05 → 06 → 08 → 10 → 12 → 13 → 14 → 15 → 16 → 17 → 18 → 19 → 20 → 21 → 22 → 24 → 25`.
## Ordered task list
### SOL-01 — Repair activation coherence and non-root checkout hygiene
- **build:** 5 (hygiene; pulled forward)
- **depends_on:** —
- **acceptance criteria (diff-blind testable):**
1. A clean non-root checkout can run dependency/bootstrap preparation without accessing `/root`.
2. A root CI checkout still uses an isolated writable pnpm store.
3. Activation installs CLI, hooks, broker/runtime assets, and version manifest transactionally: induced failure leaves the prior complete generation active.
4. Launch with a deliberately skewed component version is rejected with the exact repair command; diagnostics remain usable.
5. No test uses `--no-verify` or suppresses hooks.
- **dogfood seed:** BOARD D-1 root-pinned `.npmrc` and D-2 root-owned Husky path.
- **est. tokens:** 6K
- **suggested runtime tier:** codex
### SOL-02 — Make queue guard fail-safe with exit-asserting tests
- **build:** 1
- **depends_on:** —
- **acceptance criteria (diff-blind testable):**
1. Fixture responses `pending`, `success`, `failure`, no-status, malformed JSON, provider error, and unknown status produce explicitly asserted process exits.
2. Only terminal success/no-active-queue returns 0; unknown, malformed, and transport failure return non-zero with actionable output.
3. A payload larger than 150 KiB is consumed without argv expansion or truncation.
4. At least one mutant changes unknown→success and is killed by the test suite.
- **dogfood seed:** inert gate-6 and recursive #1019 failure (unknown→exit 0; ARG_MAX).
- **est. tokens:** 8K
- **suggested runtime tier:** codex
### SOL-03 — Complete the canonical MACP contract, not another protocol
- **build:** 1
- **depends_on:** —
- **acceptance criteria (diff-blind testable):**
1. `@mosaicstack/macp` validates typed Task, TaskResult, lifecycle Event, state Claim, and `verified | written-unverified | failed` mutation outcome records.
2. Claims require source, confidence, issued-at, TTL/expiry, refresh instruction, and HMAC integrity; tamper/expiry returns a typed refusal, never partial data.
3. Lifecycle events include launch, mission generation, checkpoint, rotation, recovery, inbox receipt, and terminal disposition while preserving existing task events.
4. `MOSAIC_AGENT_NAME` is required for mutating execution and appears in credential/actor binding; missing identity fails closed.
5. Target metadata requires repository identity, task/record ID, and head or generation where applicable.
- **dogfood seed:** rev-974 identity drift plus the three observed write outcomes.
- **est. tokens:** 8K
- **suggested runtime tier:** codex
### SOL-04 — Add the narrow PG orchestration spine schema
- **build:** 2
- **depends_on:** SOL-03
- **acceptance criteria (diff-blind testable):**
1. Migration up creates mission, task, dependency, task-claim, MACP event, typed state-claim, session-generation, and dispatch-outbox records with tenant/mission keys and uniqueness constraints.
2. The database rejects a task without a mission, a dependency outside its mission, duplicate idempotency keys, and terminal→running regression.
3. Event and claim records reference canonical mission/task/generation identities; claims store integrity metadata.
4. Migration rollback on an empty test DB succeeds; rerunning migration is safe.
5. No comms-specific “universal message” schema is invented here; Build 4 reuses/extends existing interaction inbox/outbox tables.
- **dogfood seed:** mission convention existed but a lane could act with no mechanically valid mission/task.
- **est. tokens:** 12K
- **suggested runtime tier:** codex
### SOL-05 — Implement atomic PG task claims, transitions, ledger, and outbox
- **build:** 2
- **depends_on:** SOL-04
- **acceptance criteria (diff-blind testable):**
1. Two concurrent claimers for one runnable task yield exactly one lease owner.
2. Dependencies are evaluated transactionally; an unmet dependency can never be claimed.
3. Claim, state transition, MACP event, and dispatch-outbox append commit atomically or all roll back.
4. Expired leases are reclaimable with a higher fencing generation; stale owners cannot complete or mutate.
5. Querying mission status is derived solely from PG and returns the next runnable task deterministically.
- **dogfood seed:** model-maintained live board and stale claims surviving session changes.
- **est. tokens:** 12K
- **suggested runtime tier:** codex
### SOL-06 — Build the one production Node MACP TaskExecutor
- **build:** 1
- **depends_on:** SOL-03, SOL-05
- **acceptance criteria (diff-blind testable):**
1. A public Node executor accepts only a claimed canonical MACP Task, resolves credentials/identity, runs the worker, runs structured gates, and persists terminal result/events through SOL-05.
2. Worker exit 0 plus a failed gate cannot produce `completed`; worker failure cannot skip terminal ledger emission.
3. Claude, Codex, and Pi fixture backends emit the same runtime-neutral lifecycle sequence.
4. Every mutation returns one mandatory tri-state outcome; callers cannot compile while discarding it.
5. Crash after worker success but before terminal commit leaves a recoverable fenced claim and no false completion.
- **dogfood seed:** stranded MACP, gate-6 inert completion, and `written-unverified` being treated as success.
- **est. tokens:** 16K
- **suggested runtime tier:** sonnet
### SOL-07 — Provide one-shot flat-file import and cutover readiness audit
- **build:** 2
- **depends_on:** SOL-05
- **acceptance criteria (diff-blind testable):**
1. A dry-run parses existing mission/TASKS artifacts, reports unsupported/ambiguous rows, and performs zero writes.
2. Apply is idempotent and records source digests; repeated apply creates no duplicates.
3. Unknown status, dangling dependency, duplicate task ID, and malformed table block import with row-level diagnostics.
4. Readiness reports “cutover-ready” only when imported PG projections exactly match source counts/dependencies/statuses.
5. This command is migration-only; it exposes no dual-write or ongoing sync mode.
- **dogfood seed:** current remediation board/TASKS state needs a clean DB landing without silently losing tasks.
- **est. tokens:** 8K
- **suggested runtime tier:** codex
### SOL-08 — Hard-cut `packages/coord` to PG and dogfood one live task
- **build:** 1
- **depends_on:** SOL-06, SOL-07
- **acceptance criteria (diff-blind testable):**
1. `mosaic coord run/status/continue` reads and mutates PG only; absent/unmigrated DB state fails with the SOL-07 repair path.
2. No fallback reads/writes `docs/TASKS.md`, mission JSON, task JSON, state JSON, results JSON, or events NDJSON.
3. A live canary task assigned to a fleet seat travels PG claim → TaskExecutor → worker → gate → terminal PG result/event and closes only after gate success.
4. Killing the coordinator after claim and restarting it neither duplicates execution nor allows the stale lease to close the task.
5. Evidence query shows actor seat, mission/task, target metadata, gate results, and tri-state outcome.
- **dogfood seed:** this remediation mission itself; reproduce a gate-6-style non-null task and identity-bound write.
- **est. tokens:** 16K
- **suggested runtime tier:** sonnet
> **G1 FIRST-DOGFOOD:** stop and validate here before broadening. If SOL-08 cannot carry a real task, do not build Redis, rotation, comms, or UI.
### SOL-09 — Route Forge and OpenClaw/MACP producers through TaskExecutor
- **build:** 1
- **depends_on:** SOL-08
- **acceptance criteria (diff-blind testable):**
1. Forge and the OpenClaw MACP runtime submit the canonical Task type to SOL-06; neither executes a worker or gate itself.
2. Their success callbacks are derived from canonical terminal results, not local/stub completion.
3. A failed canonical gate is observed identically from Coord, Forge, and OpenClaw fixtures.
4. Repository search plus an executable import boundary test finds no production-local redefinition of Task/TaskResult/GateResult on these paths.
- **dogfood seed:** Forges immediate empty-gate completion and the plugins redefined MACP-shaped result.
- **est. tokens:** 10K
- **suggested runtime tier:** codex
### SOL-10 — Retire flat-file orchestration and the disabled duplicate rail
- **build:** 1
- **depends_on:** SOL-09
- **acceptance criteria (diff-blind testable):**
1. The Python controller execution/gate/event path, `tasks_md_sync`, plugin-local protocol types, orphaned context loader, and production flat-file orchestration writers/readers are absent from shipped assets.
2. Framework guides/templates/startup context point to DB mission commands, not `docs/TASKS.md` as orchestration SoR.
3. A regression scan fails CI if production code reintroduces `events.ndjson`, `tasks.json`, `mission.json`, or `docs/TASKS.md` orchestration mutation.
4. jarvis-brain PDA flat files and unrelated project docs remain untouched.
5. Upgrade removes/quarantines obsolete generated rail files without deleting user source/docs.
- **dogfood seed:** three parallel islands and stale `.mosaic/orchestrator/mission.json` 0/0 residue.
- **est. tokens:** 14K
- **suggested runtime tier:** sonnet
### SOL-11 — Add Redis hot dispatch as a derived outbox consumer
- **build:** 2
- **depends_on:** SOL-08
- **acceptance criteria (diff-blind testable):**
1. Task creation commits mission/task/outbox in PG before any Redis enqueue.
2. Induced Redis failure leaves the task durable and pending; a sweeper later enqueues it exactly once logically.
3. Deleting the Redis queue and rebuilding from PG restores all non-terminal dispatches without reviving terminal tasks.
4. Duplicate delivery is neutralized by PG claim fencing/idempotency.
5. Existing `packages/queue` adapter/config is reused; no second broker API is introduced.
- **dogfood seed:** inert/unknown queue transport and broker outage during task dispatch.
- **est. tokens:** 12K
- **suggested runtime tier:** codex
### SOL-12 — Lock Builds 1+2 with black-box failure cases
- **build:** 2
- **depends_on:** SOL-02, SOL-10, SOL-11
- **acceptance criteria (diff-blind testable):**
1. A black-box suite proves: unknown queue status blocks; malformed task blocks; gate failure blocks completion; dropped identity blocks mutation; HMAC corruption forces refresh; Redis loss recovers from PG; stale lease cannot close.
2. The suite invokes shipped CLI/service boundaries, not internal mocks.
3. Every asserted failure checks process/result status and durable terminal/non-terminal state.
4. The same canary task succeeds under Claude, Codex, and Pi adapters or a documented unavailable-runtime fixture fails explicitly.
- **dogfood seed:** gate-6/#1019, identity drift, and built-but-unwired MACP.
- **est. tokens:** 8K
- **suggested runtime tier:** sonnet
### SOL-13 — Bind session authority to contract hash and generation
- **build:** 3
- **depends_on:** SOL-12
- **acceptance criteria (diff-blind testable):**
1. Launch computes a stable hash over the effective Constitution/AGENTS/runtime/skills set and stores it with session generation.
2. Policy change or compaction detection marks the generation stale before any subsequent mutation.
3. A stale/mismatched generation can read diagnostics but cannot claim, write task state, acknowledge comms, merge, or close.
4. Re-attestation creates a new generation; old credentials/leases remain fenced.
5. Hash input order/path normalization is deterministic across two clean launches.
- **dogfood seed:** compacted orchestrator losing directives and D-4 ignoring an in-message reset.
- **est. tokens:** 12K
- **suggested runtime tier:** sonnet
### SOL-14 — Persist compact typed rotation checkpoints using Coord primitives
- **build:** 3
- **depends_on:** SOL-13
- **acceptance criteria (diff-blind testable):**
1. Checkpoint contains mission/task, completed/blocked state, next three actions, constraints, claims, contract hash/generation, and cursors—never transcript text.
2. Checkpoint is HMAC-verified before rehydration; corrupt/expired/missing required claims refuse resume and request deterministic refresh.
3. Writing checkpoint and rotation-intent event is atomic in PG.
4. Existing Coord continuation capsule semantics are reused; no competing handoff schema/file is created.
- **dogfood seed:** manual MOS-ORCHESTRATION-BOARD checkpoint and incomplete-rehydration risk.
- **est. tokens:** 12K
- **suggested runtime tier:** codex
### SOL-15 — Finish the deterministic coordinator rotation daemon
- **build:** 3
- **depends_on:** SOL-14
- **acceptance criteria (diff-blind testable):**
1. Configured token threshold triggers checkpoint → revoke old authority → terminate → launch fresh → verify rehydration in that order.
2. Compaction-detected is a backstop that forces the same rotation path; it never requests recursive compaction.
3. A launch failure leaves the mission recoverable and visibly paused, not assigned to two active generations.
4. Ephemeral seats die/respawn without mission checkpoint; persistent/orchestrator seats rotate.
5. The implementation extends `packages/coord`; untracked `apps/coordinator` residue is not revived.
- **dogfood seed:** planner-sol dirty-context dispatch and the old coordinators log-only `_check_context()` behavior.
- **est. tokens:** 16K
- **suggested runtime tier:** sonnet
### SOL-16 — Add broker-independent recovery and remove silent MOSAIC BYPASS
- **build:** 3
- **depends_on:** SOL-15
- **acceptance criteria (diff-blind testable):**
1. With Redis/broker unavailable, a diagnostic/bootstrap command can inspect PG mission state, repair broker configuration, and resume without traversing the broker gate.
2. Normal recovery remains broker-gated and is labeled as such.
3. Break-glass requires explicit scope and expiry, emits a durable event, displays a loud banner, and auto-expires; permanent/silent bypass text or behavior is absent.
4. The Pi-brick fixture recovers the broker, then returns to normal gated operation without editing source/config by hand.
5. Orchestrator guidance removes “/compact and continue” only after the rotation command is available; ephemeral guidance remains explicit.
- **dogfood seed:** Pi brick and silent `MOSAIC BYPASS 2026-07-22`.
- **est. tokens:** 12K
- **suggested runtime tier:** sonnet
### SOL-17 — Converge each host on one roster-owned lifecycle domain
- **build:** 5 (hygiene; hard prerequisite for addressed comms)
- **depends_on:** SOL-16
- **acceptance criteria (diff-blind testable):**
1. Reconcile establishes exactly one roster-declared tmux socket/lifecycle domain per host.
2. Unknown sessions are reported and quarantined; they are never killed without positive unmanaged classification.
3. Max-age/max-context stale sessions invoke SOL-15 rotation for persistent seats or reap for ephemerals.
4. Seat identity survives respawn and equals the roster/MOSAIC_AGENT_NAME binding.
5. A fixture matching the current four unmanaged remediation seats converges them or produces explicit quarantine actions.
- **dogfood seed:** scout-bounce and BOARD D-3 seats split between default and `mosaic-fleet` sockets.
- **est. tokens:** 14K
- **suggested runtime tier:** codex
### SOL-18 — Publish authenticated `comms/v1` envelope and compatibility rules
- **build:** 4
- **depends_on:** SOL-13, SOL-17
- **acceptance criteria (diff-blind testable):**
1. Envelope validates protocol version, message/idempotency ID, sender/recipient seat identity, class, ordering/coalesce key, creation/expiry, correlation, payload digest, and authentication.
2. Current and immediately previous supported protocol versions are accepted; unsupported versions are rejected loudly with supported range.
3. Framework/runtime version is diagnostic metadata and never the compatibility key.
4. Forged sender, changed recipient/payload, expired envelope, and replay with conflicting content fail closed.
- **dogfood seed:** wrong-socket bare tmux message with no authoritative sender/recipient receipt.
- **est. tokens:** 8K
- **suggested runtime tier:** codex
### SOL-19 — Build the logical PG-first comms service with tmux adapter
- **build:** 4
- **depends_on:** SOL-18
- **acceptance criteria (diff-blind testable):**
1. Sending commits envelope/payload and PENDING state in PG before adapter delivery.
2. State machine enforces PENDING → RECEIVED → CONSUMED or DEAD-LETTER; illegal regressions are rejected.
3. Recipient-filtered claims and append/coalesce policy are deterministic by message class.
4. tmux is a dumb adapter: delivery failure changes no PG authority state and is retryable.
5. Existing Tess durable repository/state-machine patterns are extended or generalized; no new deployable microservice or second inbox framework appears.
- **dogfood seed:** MACP scout bounce that was discovered only by manual liveness check.
- **est. tokens:** 16K
- **suggested runtime tier:** sonnet
### SOL-20 — Make `agent-send` use the sole path and prove stale-message handling
- **build:** 4
- **depends_on:** SOL-19
- **acceptance criteria (diff-blind testable):**
1. Normal `agent-send` creates a comms/v1 record and observes RECEIVED/CONSUMED; it cannot directly invoke tmux.
2. A wrong/missing socket leaves PENDING with retry diagnostics, then reaches RECEIVED after roster repair without resending.
3. A stale coalescible message arriving after a newer terminal message is marked superseded/consumed and is not surfaced as live work.
4. Duplicate identical send is idempotent; same ID with changed content is rejected.
5. Inbox receipt/terminal disposition emits canonical MACP lifecycle events.
- **dogfood seed:** scout-bounce and #1018 stale-consumed message arriving after merge.
- **est. tokens:** 12K
- **suggested runtime tier:** codex
### SOL-21 — Add Redis Streams hot delivery and PG reconciliation
- **build:** 4
- **depends_on:** SOL-11, SOL-20
- **acceptance criteria (diff-blind testable):**
1. PG commit precedes XADD; induced XADD failure is repaired by sweeper.
2. Consumer uses a PEL; ack sequence is PG CONSUMED commit before XACK.
3. Redis flush/restart rebuilds pending delivery from PG without duplicating consumed messages.
4. Pending, abandoned, and dead-letter transitions are observable with bounded retry/backoff.
5. Existing Redis/queue connection/configuration is reused.
- **dogfood seed:** delivery bounce plus broker loss between durable write and hot enqueue.
- **est. tokens:** 12K
- **suggested runtime tier:** codex
### SOL-22 — Prove adapter pluggability with the existing Matrix connector
- **build:** 4
- **depends_on:** SOL-21
- **acceptance criteria (diff-blind testable):**
1. Existing Matrix connector consumes/produces comms/v1 through SOL-19 without owning authority state.
2. The same envelope can fail tmux and later deliver through Matrix while producing one logical message lifecycle.
3. Matrix retry/reconnect cannot regress PG state or duplicate CONSUMED work.
4. Removing Matrix availability leaves PG/Redis/tmux behavior intact.
- **dogfood seed:** cross-socket scout notification bounce; alternate reach must not become alternate authority.
- **est. tokens:** 8K
- **suggested runtime tier:** codex
### SOL-23 — Constrain auto-sync and agent writes by allowlist and lease
- **build:** 5
- **depends_on:** SOL-10
- **acceptance criteria (diff-blind testable):**
1. Auto-sync stages only an explicit allowlist; an unknown modified/untracked docs/source file remains unstaged and is reported.
2. Agent source/docs writes require the correct worktree/lease; two seats cannot acquire the same mutable target concurrently.
3. Generated files are positively identified, not inferred by denylist.
4. The measured annotation/index mid-write fixture cannot be swept into an unrelated commit.
5. DB orchestration state is absent from repository staging concerns.
- **dogfood seed:** auto-sync sweep commit `517bd5c26` capturing agent-authored docs mid-write.
- **est. tokens:** 8K
- **suggested runtime tier:** codex
### SOL-24 — Build the real-artifact lifecycle conformance harness
- **build:** 5
- **depends_on:** SOL-16, SOL-17, SOL-22, SOL-23
- **acceptance criteria (diff-blind testable):**
1. Harness launches shipped CLI/runtime artifacts and fault-injects compaction, broker outage, delivery bounce, identity drop, stale contract hash, queue unknown/malformed, Redis loss, and auto-sync collision.
2. One deterministic test executes 100 sequential rotations with no lost/duplicated task, claim, receipt, or terminal disposition.
3. Tests assert DB state/event order and process exits, not log substrings alone.
4. Harness runs against isolated PG/Redis namespaces and cleans only resources it created.
5. Every banked dogfood seed has a named case and evidence output suitable for CI/release attachment.
- **dogfood seed:** the complete failure bank: Pi brick, scout-bounce, gate-6/#1019, identity drift, auto-sync, #1018 stale-consumed, D-4 dirty context.
- **est. tokens:** 18K
- **suggested runtime tier:** sonnet
### SOL-25 — Complete operator cutover docs and activation proof
- **build:** 5
- **depends_on:** SOL-01, SOL-02, SOL-10, SOL-16, SOL-22, SOL-24
- **acceptance criteria (diff-blind testable):**
1. Operator docs give exact DB import/cutover, rollback-before-cutover, recovery, break-glass expiry, rotation, comms, quarantine, and conformance commands.
2. Link/command checks find no orchestrator instruction to mutate flat-file mission/tasks, use silent bypass, direct-tmux normal comms, or “compact and continue” a persistent seat.
3. A clean non-root install activates one coherent version and runs the conformance smoke subset.
4. Release evidence maps all 15 decisions and every live seed to a passing check or an explicit deferred item below.
- **dogfood seed:** activation skew plus the tendency to leave built fixes unwired or undocumented.
- **est. tokens:** 6K
- **suggested runtime tier:** codex
## Explicit DEFER list (10)
These are not rejected; they are **past first dogfood** and should not delay G1/G2. Each is gold-plating unless a live failure makes it necessary.
1. **DEFER — Mission dashboard/TUI views.** CLI/DB queries are enough to operate and prove the spine.
2. **DEFER — PRD-to-board automatic decomposition.** This is LLM/judgment-heavy and unrelated to enforcing already-decided tasks.
3. **DEFER — General heuristic churn scoring.** Implement token threshold + compaction sensor first; repeated-tool-loop inference can follow measured need.
4. **DEFER — Discord comms adapter.** Existing plugin reach remains; migrate only after tmux+Matrix prove the service contract.
5. **DEFER — Slack comms adapter.** No current dogfood dependency.
6. **DEFER — Telegram comms adapter.** No current dogfood dependency.
7. **DEFER — Public MCP comms surface.** `agent-send` and service API are sufficient for the mission proof.
8. **DEFER — Protocol-v2 features/general negotiation framework.** Ship v1 with a bounded current/previous acceptance window; do not predict v2.
9. **DEFER — Multi-region/HA PG or Redis.** Existing in-stack PG+Redis and rebuildability satisfy current failure classes.
10. **DEFER — Event analytics/search UI and long-term warehouse.** Indexed PG evidence plus CLI queries is enough for audit/conformance.
## Suspect abstractions register
| proposed thing | verdict |
| ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Canonical Node `TaskExecutor` | **JUSTIFIED:** explicitly required single choke point; wraps existing MACP functions rather than replacing them. |
| PG repository methods | **JUSTIFIED but narrow:** ordinary adapters around existing Drizzle/DB patterns, not a new “state platform.” |
| Rotation daemon | **JUSTIFIED:** finishes `packages/coord`; do not revive `apps/coordinator` or create another service. |
| Comms service | **JUSTIFIED only as a logical in-process boundary:** reuse Tess durable inbox/outbox and existing connectors; no new deployable microservice this cycle. |
| Universal queue/broker abstraction | **SUSPECT / DO NOT BUILD:** reuse `packages/queue`, PG outbox, and Redis Streams/BullMQ configuration already present. |
| Universal envelope/state framework | **SUSPECT / DO NOT BUILD:** MACP Task/Claim/Event and comms/v1 have different bounded purposes. |
| Generic compatibility-negotiation engine | **SUSPECT / DEFER:** a small supported-version check meets v1 needs. |
## Dissent (7)
1. **Do not wire new production behavior into `mosaic_orchestrator.py::run_single_task`.** The scout correctly identified the duplicated block, but BOARDs later ruling says the disabled Python rail is residue and must be retired. Building a Node bridge only to delete it is throwaway. Put the Node TaskExecutor in `@mosaicstack/macp`, route the live Coord path to it at SOL-08, migrate remaining producers at SOL-09, then delete the Python block at SOL-10.
2. **Redis is not on the first-dogfood critical path.** PG claim/polling is sufficient for one real task and exposes correctness earlier. Add Redis only after G1; otherwise queue debugging obscures whether the choke point works.
3. **“One choke-point service” does not justify a new deployable service.** An exported executor plus Coord daemon is enough. A new Nest app, RPC protocol, deployment, auth layer, and health plane would be greenfield.
4. **The Mission Control PRDs file-first and board-regeneration assumptions are superseded.** Keep its mission/rotation semantics, but obey the accepted hard DB cutover; do not implement its file-first milestones or PRD-to-board generator now.
5. **Do not gate every interactive runtime launch as if it were a mission task.** Enforce every tracked task/data mutation at the executor/DB authority boundary. Ephemeral interactive shells may launch, but receive no task mutation authority unless attached to a valid claim.
6. **Do not implement broad “churn intelligence.”** Token threshold and compaction-detected are deterministic sensors. Repeated-loop semantic detection is expensive, noisy, and premature until telemetry demonstrates a gap.
7. **The 100-rotation test is a final conformance bar, not an early unit-test tax.** First prove one rotation, then fault cases, then 100 repetitions in SOL-24. Requiring 100 before G3 would delay feedback without changing the design.
## Orchestrator reconciliation notes
- Pre-register each tasks acceptance checks from this document before showing implementation diffs to its reviewer. Author and reviewer remain different seats.
- SOL-07 permits a one-time import, **not** an interim store: no shadow writes, dual reads, or sync daemon.
- G1 is the budget escape hatch. If the 72K hard-path slice does not work, stop and remediate instead of spending the remaining ~222K.
- Docs belong in each behavior-changing PR where required; SOL-25 is cross-link/cutover validation, not permission to postpone essential docs.
-59
View File
@@ -1,59 +0,0 @@
# mos-remediation — Orchestrator Kickstart / Compaction-Survival Resume
**You are `mos-remediation`, the project orchestrator for the Mosaic Stack remediation, launched in `/src/mosaic-stack`.**
This file is your fail-closed resume procedure. Read it on EVERY fresh/cleared session and on the FIRST turn
after any compaction. This mission's whole point is that manual compaction-survival is fragile — so follow this
mechanically until Build 3 (rotation) makes it automatic.
## On resume (do in order, before any orchestration action)
1. `cd /src/mosaic-stack`, then **`git fetch origin remediation/state`**.
**The live board is on the rolling branch `remediation/state`, NOT on `main`.** `main` carries only
periodic snapshots, so reading the board from `main` will silently give you a STALE tick. Read the
live files at `origin/remediation/state` (e.g. `git show origin/remediation/state:docs/remediation/BOARD.md`),
or check that branch out. Every tick is pushed there immediately, so its HEAD is always the newest state.
2. Read `docs/remediation/MISSION.md` — the charter (goal, 4 builds, 15 decisions, sequencing, directives).
3. Read `docs/remediation/BOARD.md` **at `origin/remediation/state`** — the LIVE state: current phase,
in-flight tasks, fleet seat assignments, gate status. Single source of in-flight truth (kept < 8 KB;
older entries roll to `BOARD-LEDGER.md` via `board-roll.sh`).
4. Read the discussion checkpoint for full rationale if needed:
`../jarvis-brain/docs/scratchpads/postmortem/REMEDIATION-DISCUSSION-STATE.md` (or the jarvis-brain repo path).
5. **Residency attestation (fail-closed):** restate from the reloaded files — (a) the goal in one line, (b) the
current build/phase, (c) the BOARD head (in-flight tasks + who owns them). If you cannot, HALT and re-read.
Do NOT act on memory alone; a compaction may have dropped context silently.
## Standing invariants (never violate)
- **North star:** deterministic-right-answer → code/gate; LLM only for judgment.
- **Delivery gates — REFERENCE the canonical files, never restate them:**
`~/.config/mosaic/fleet/roles.local/merge-gate.md` (verdict authority) and
`~/.config/mosaic/fleet/roles/validator.md` (validator role). Order:
independent review (author ≠ reviewer, `rev-974`; pre-registered diff-blind checks committed before the
diff is read) → remediation → **CI terminal-green at the exact head by full step scan**
**merge-gate verdict `GO`/`NO-GO`/`HOLD`**, commit-bound and **void the instant the head moves**, posted
durably with enumerated evidence under its own minted identity → **coordinator head-pinned merge**.
The queue guard runs but is **zero-information until RM-03 lands** (D-23) and must not be cited as evidence.
**After a `GO`, freeze pushes** — even a doc tweak voids the verdict. The coordinator assigns the gate seat.
- **Query for refutation, never for confirmation.** A subordinate asked to confirm a hypothesis will
agree — the bias is in the question, not the answerer, and agent seats are agreeable by construction.
State the hypothesis as yours, ask for the evidence that KILLS it, and reproduce when it matters.
- **Dogfooding:** every fix validated against its live seed case (MISSION.md lists them).
- **Tracking → DB** (hard cutover); do NOT re-invest in flat-file tracking. jarvis-brain PDA is off-limits.
- **Git identity:** export `MOSAIC_GIT_IDENTITY=<your-seat>` so wrappers author correctly and survive respawn.
## After every significant event
Overwrite stale lines in `BOARD.md`, keep it < 8 KB, commit + push. The board IS your checkpoint until the
DB-backed rotation daemon (Build 3) exists. Persist typed state (phase, tasks, owners, gates) — never the transcript.
## Fleet
- Adversarial planners: `planner-opus` (robustness), `planner-sol` (pragmatic) — dispatch for task decomposition; reconcile their oppositional decomps.
- Coders/reviewers: dispatch per roster + delivery gates. Comms: `~/.config/mosaic/tools/tmux/agent-send.sh`
(`-L <socket> -s <dst> -S <yourhost>:<yourseat> --class <class>`); always pass `-S`.
- Lead coordinator: Mos (`mos-claude`). Escalate only on the Constitution's escalation triggers.
## Remote control
On first startup, activate remote control for this session (`/remote-control`) so Jason can reach/drive you while
away. If the command is unavailable in this runtime, report it to Mos and continue — it is not a blocker.
-98
View File
@@ -1,98 +0,0 @@
# MACP wiring investigation
**Scope:** `/src/mosaic-stack` inspected at HEAD `b79336a8c11e2a4646a47ff8d295a226e0c71404`; read-only. Existing dirty/untracked state was not touched.
## Verdict
**(c) STRANDED.** `packages/macp` is exported, unit-tested, and registered as a CLI command group, but no production dispatch/execution code invokes its credential resolver, gate runner, or event emitter.
A separate MACP-named OpenClaw/orchestrator rail exists, but it redefines task/result types and gate/event logic instead of importing `@mosaicstack/macp`; direct `mosaic yolo|claude|codex|opencode|pi` also bypasses it.
## 1. Production call sites vs tests
### Production references to `@mosaicstack/macp`
| Surface | Evidence | Actual use |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Unified CLI | `packages/mosaic/src/cli.ts:8,385` | Imports and registers `registerMacpCommand`; no task/gate/event execution. |
| Forge | `packages/forge/src/types.ts:1,17,68,79` | **Type-only** imports of `GateEntry` and `TaskResult`. Pipeline calls an injected abstract executor at `packages/forge/src/pipeline-runner.ts:189-190,299-300`, not MACP. |
| Mosaic package metadata | `packages/mosaic/package.json:36`; `packages/mosaic/src/runtime/update-checker.ts:172` | Dependency/update inventory only. |
| Agent | No match under production `packages/agent/src/**` | No MACP import/call. |
| Coord | No match under production `packages/coord/src/**`; dependency list is only `@mosaicstack/types` at `packages/coord/package.json:25-27` | No MACP import/call. |
| Plugins | No `@mosaicstack/macp` import under `plugins/**` | No package use; the MACP-named plugin is an independent implementation (below). |
**Repository-wide production call-site search result:** excluding `packages/macp/**`, tests, worktrees, and build output, there are **zero** calls to `runGate`, `runGates`, `emitEvent`, `appendEvent`, or `resolveCredentials`.
### `packages/macp` implementation is internally connected only
- Public exports: `packages/macp/src/index.ts:1-48` exports Task/GateEntry/MACPEvent/TaskResult, credential resolution, `runGate(s)`, risk-floor, and event emission.
- Gate runner calls its own event emitter: `packages/macp/src/gate-runner.ts:187-236`.
- Event persistence implementation appends NDJSON to a caller-supplied path: `packages/macp/src/event-emitter.ts:11-27`.
- There is **no exported programmatic `submit` implementation** in `packages/macp/src/index.ts:1-48`; only the CLI placeholder named `submit`.
### Test-only invocations
- Gate runner: `packages/macp/__tests__/gate-runner.test.ts:96-242` invokes `runGate/runGates`.
- Event ledger: `packages/macp/__tests__/event-emitter.test.ts:46-133` invokes `appendEvent/emitEvent` against temporary `events.ndjson` files.
- Credential resolver: `packages/macp/__tests__/credential-resolver.test.ts` exercises resolver behavior.
- CLI tests only verify command registration: `packages/macp/src/cli.spec.ts:37-73`; `packages/mosaic/src/cli-smoke.spec.ts:8` imports registration.
## 2. Gate on the live dispatch path
### Direct Mosaic runtime launch bypasses MACP
- Runtime commands dispatch directly to harness launch: `packages/mosaic/src/commands/launch.ts:730-801`.
- Claude/Pi go through the lease broker, then spawn the runtime: `packages/mosaic/src/commands/launch.ts:817-843`.
- Commander wiring sends `mosaic yolo <runtime>` and direct runtime commands to `launchRuntime`: `packages/mosaic/src/commands/launch.ts:1102-1157,1165-1167`.
- None of those ranges imports/calls `@mosaicstack/macp`, `runGates`, or `emitEvent`.
**Result:** a direct `mosaic yolo`, `mosaic claude/codex/opencode/pi`, or underlying exec does not create a typed MACP Task, run the package gate-runner, or append a package MACPEvent.
### Coord bypasses MACP
- Coord reads/updates `docs/TASKS.md`: `packages/coord/src/runner.ts:6,306-386`; parser/writer is `packages/coord/src/tasks-file.ts:326-377`.
- Coord launches a child process directly: `packages/coord/src/runner.ts:397-427`.
- Mission state is its own `.mosaic/orchestrator/mission.json`/`next-task.json`: `packages/coord/src/mission.ts:8-12`; `packages/coord/src/runner.ts:15-16,355-384`.
**Result:** Coord task execution has no MACP Task validation, package gate runner, or event append.
### Forge bypasses MACP execution
- Forge defines its own `ForgeTask` and abstract `TaskExecutor`: `packages/forge/src/types.ts:48-80`.
- The production CLI injects a **stub executor** that immediately reports completion with empty gates: `packages/forge/src/cli.ts:13-31,167,185`.
**Result:** even `mosaic forge run` does not execute MACP gates or persist MACP events.
### Separate MACP-named rail is not `packages/macp`
- OpenClaw plugin registers an ACP backend named `macp`: `plugins/macp/src/index.ts:1-18,72-102`.
- It locally redefines `OrchestratorTask`, `TaskResult`, and gate-result shapes instead of importing package types: `plugins/macp/src/macp-runtime.ts:43-77`.
- It appends directly to `.mosaic/orchestrator/tasks.json`, triggers an external controller, and polls `results/<task>.json`: `plugins/macp/src/macp-runtime.ts:290-329,437-483`.
- The controller independently implements `append_event`, `emit_event`, shell execution, gate execution, and results: `packages/mosaic/framework/tools/orchestrator-matrix/controller/mosaic_orchestrator.py:29-91,126-276`.
- Its gate loop runs raw string gates after worker success: `mosaic_orchestrator.py:213-235`; it does not support the package's structured `GateEntry`/AI-review behavior.
- Current checkout disables this controller: `.mosaic/orchestrator/config.json:2` (`"enabled": false`).
- Plugin references `tools/macp/dispatcher/pi_runner.ts` at `plugins/macp/src/macp-runtime.ts:85-91`, but `tools/macp/` does not exist in this checkout.
**Result:** there is a parallel, optionally enabled MACP-shaped rail, not package integration. It cannot make `packages/macp` the enforced path.
## 3. Event ledger status
- Package persistence exists only as a library primitive: `packages/macp/src/event-emitter.ts:11-27` appends JSON lines to an arbitrary `eventsPath`.
- Package event emission is reached only from package `runGates`: `packages/macp/src/gate-runner.ts:204-236`.
- No production caller invokes package `runGates/emitEvent/appendEvent`; therefore no runtime destination path is configured for the package ledger.
- Test-only ledgers use temp paths: `packages/macp/__tests__/event-emitter.test.ts:35-133`; gate tests use temp `events.ndjson`: `packages/macp/__tests__/gate-runner.test.ts:171-242`.
- The separate Python controller writes `.mosaic/orchestrator/events.ndjson`: `mosaic_orchestrator.py:129-133,159-161,219-235`; the Mosaic Framework plugin only **reads** that file for context at `plugins/mosaic-framework/src/index.ts:279-316,430-438`.
- In this checkout, `.mosaic/orchestrator/events.ndjson` is absent and the controller is disabled (`.mosaic/orchestrator/config.json:2`).
**Conclusion:** `MACPEvent` from `packages/macp` is defined/tested but not emitted or persisted by live production call sites. The similarly shaped Python ledger is a duplicate island.
## 4. Coord link
- `packages/coord` has no `@mosaicstack/macp` dependency/import: `packages/coord/package.json:25-27`; no matches in `packages/coord/src/**`.
- Coord's task model is Markdown `docs/TASKS.md` plus mission/session JSON: `packages/coord/src/tasks-file.ts:1-10,257-377`; `packages/coord/src/mission.ts:8-12`; `packages/coord/src/runner.ts:306-427`.
- It does not consume `.mosaic/orchestrator/events.ndjson`, MACP Task, MACPEvent, GateEntry, or TaskResult.
**Conclusion:** Coord and `packages/macp` are disconnected islands.
## Shortest wiring gap
**Single integration point:** replace the duplicated execution/gate/event block in `mosaic_orchestrator.py::run_single_task` (`:126-276`) with one production Node `TaskExecutor` backed by `@mosaicstack/macp` (typed Task validation + `resolveCredentials` + `runGates` + `emitEvent`), and make Coord/Forge/OpenClaw submit through that executor. This queue/controller choke point is where `yolo|acp|exec` worker outcomes can be gated and journaled before completion is recorded.
-307
View File
@@ -1,307 +0,0 @@
# Mosaic Stack Remediation — Mission Charter
**Owner:** project orchestrator `mos-remediation` (Claude, launched in `/src/mosaic-stack`).
**Origin:** 2026-07-16..31 fleet lifecycle postmortem. **Status:** EXECUTING (planning complete; RM-01 in flight).
**HOLD lifted** for this workstream by Jason, 2026-07-31 — "begin full mosaic fleet operation on this."
## Goal
Convert the 15 accepted postmortem remediation proposals into a working, **dogfooded** implementation.
**North star:** anything with a deterministic right answer moves OUT of the LLM into a deterministic
gate/program; the LLM handles only genuine judgment.
### First-class principle — observe the property, not the exit code
> **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 the whole reason the inert-gate class exists
> and why P-WRAPPER-001's tri-state (`verified` / `written-unverified` / `failed`) is not optional. The
> failure is not carelessness — a green is _engineered_ to be trusted, so trusting it is the default
> behaviour of a competent operator, not a lapse.
>
> Promoted to the charter by Mos (2026-07-31) after the orchestrator committed this exact error: a
> `--draft` flag was silently dropped by a wrapper fallback that still exited 0, and the PR was reported
> as a draft on the strength of the exit code rather than an observed `draft: true` (D-12). Twelve
> failure instances were banked in that session; **three of them were the orchestrator's own.** That
> ratio is the point — the mechanism must catch the mechanic too, or it is not a mechanism.
>
> Operationally: after any write, read back the property you required. Applies to gates, wrappers, PR
> flags, commit authorship, file installs, and message delivery alike.
### First-class principle — pre-registration prevents retrofitting, and nothing else
> **A pre-registered check set can fail in three distinct ways:**
>
> | mode | the set is… | found as |
> | --------------------------- | ------------------------------------------------- | -------- |
> | **WRONG** | a check does not test what it claims | D-8 |
> | **INCOMPLETE** | green while a criterion's requirement is untested | D-17 |
> | **INTERNALLY INCONSISTENT** | two criteria cannot both hold | D-18 |
>
> **Pre-registration protects against exactly one thing: retrofitting a check to fit the implementation
> it is supposed to judge.** It confers neither correctness, nor coverage, nor consistency. "We
> pre-registered the checks" has been treated as though it settled the question — it settles one of
> three.
>
> Promoted to the charter by Mos (2026-07-31). All three modes were found on this mission's own **first
> delivery**, by the machinery applied to its own work — not by inspection, and not by looking for them.
>
> **Enforceable form — RM-02's four clauses.** The registry must establish that: (1) each check is
> **right** — proven red for its own stated reason before its green counts; (2) the set **covers** —
> every criterion bound to a case that actually exercises it; (3) no two criteria **conflict** —
> mutual unsatisfiability is a registry defect discoverable by construction; (4) when a criterion's
> meaning changes, the registry **retains original text, restatement, and reason**, so evolution stays
> auditable. A criterion with no case that can fail for its own reason is unregistered in substance,
> however it reads in the manifest.
### Corollary — never ship an integrity claim dressed as a property
> A verification artifact that can be forged by whoever it is meant to catch verifies nothing. If a
> manifest, marker, ledger, or receipt is writable by the same actor whose behaviour it certifies, it
> **certifies the attack.** Such an artifact must sit inside the integrity envelope it belongs to,
> publish atomically, and carry a **tamper negative-control observed red** — otherwise its integrity is
> a _claim_, not a _property_.
>
> **If it cannot be made tamper-evident, say so and reconsider the approach.** Laundering foreign
> content as certified is the only unacceptable outcome; an honest "this cannot be verified" is always
> available and always preferable.
### First-class principle — when a property cannot exist at the layer it was specified
> Some required properties are **impossible at the layer that asked for them** — not hard, impossible.
> A local check cannot defend against an actor who can rewrite the check itself. When that happens,
> there are exactly three honest moves, and all three are mandatory:
>
> 1. **Implement what the layer _can_ guarantee.** Partial protection against the class it was actually
> born from is worth having.
> 2. **State the boundary precisely, in BOTH directions.** What it does _not_ defend, **and** beside it
> what it _does_. A reader who sees only the negative dismisses the check as worthless; one who sees
> only the positive over-trusts it. **Both together is the honest artifact** — either alone misleads.
> 3. **Record where the real guarantee will come from — as a TRACKED DEPENDENCY, not prose.** It must
> name a task that someone must close. _A documented gap with no owner becomes a permanent gap that
> reads as intentional._
>
> **A written-down gap is acceptable engineering. An implied-fixed gap is this mission's core failure in
> a new costume** — a verification artifact that verifies nothing, with a green to prove it.
>
> Promoted to the charter by Mos (2026-07-31) from D-19. Origin: the RM-01 symlink manifest could not be
> made tamper-evident against a same-UID actor (CWE-345), because the manifest and its marker share one
> writable tree. The implementing seat **escalated rather than relabelling self-authentication as
> tamper-resistance** — the corollary above firing on its first real adversarial test, on the cheapest
> seat in the loop. Residual risk bound to **RM-59** (`depends_on: RM-12, RM-21, RM-25`), where the
> choke-point executor and spine verify from _outside_ the worktree's authority.
### First-class principle — query for refutation, never for confirmation
> **A subordinate asked to confirm a hypothesis will agree. Ask it to refute, with evidence.**
>
> The bias is induced by the **query**, not by the answerer's diligence. _"The DB flaked — please
> confirm"_ and _"confirm or refute this, with the log line that proves it"_ are different instruments,
> and they return different answers to the same question. The first harvests agreement; only the second
> can return **"you are wrong, and here is why."**
>
> This matters most with agent subordinates, which are **agreeable by construction**: fluent, eager to
> be useful, and structurally disinclined to tell the dispatcher their premise is false. A confirmation
> query aimed at one is close to a guaranteed yes — so the discipline cannot rest on the answerer being
> rigorous. **It has to be built into how the question is asked.**
>
> Promoted to the charter by Mos (2026-08-01). Origin: the orchestrator hypothesised that a coincident
> `ci-postgres` failure caused a CI test failure and asked the implementing seat to **confirm or refute**
> it. The seat **refuted it** with the log (`ci-postgres:5432 - accepting connections`, migrations
> completed) and identified the real cause. Reproduction on an identical head then settled it. Had the
> query been phrased for confirmation, the agreement would have been returned, **D-21 would have been
> re-classified on a false premise**, and a banked finding would have been silently corrupted.
>
> **Operationally:** state your hypothesis explicitly, mark it as yours, ask for _evidence that kills
> it_, and say what evidence would change your mind. A hypothesis you cannot describe how to falsify is
> not yet a hypothesis. Where the answer is consequential, **reproduce** rather than accept — two
> independent runs beat one confident report.
### First-class principle — 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 merely **moves** the control point; it does not remove it.
>
> Promoted to the charter by Mos (2026-08-01) on the **THIRD INDEPENDENT ARRIVAL** of the same
> conclusion, each reached while trying to ship something else, each from a different direction:
>
> | arrival | the audited party controls… | found as |
> | ----------------- | ------------------------------------------------------------------- | -------- |
> | manifest | the tree that certifies its own generated state (same-UID, CWE-345) | **D-19** |
> | sandbox | the code that enters the sandbox, before the boundary exists | **D-25** |
> | **registry seam** | **WHEN the tracked path is introduced, hence the derived boundary** | **D-45** |
>
> Round 1 the value was an author-settable **field**, so it was **derived**. Round 2 the derivation
> depended on **when the author introduces the path**. Same authority, new costume. **Three
> impossibility-derivations of one conclusion is not a coincidence to note — it is the strongest
> architectural evidence this mission has produced**, and it is precisely what **forces Builds 12**
> rather than making them a preference.
>
> **Operationally:** anchor to a reference the audited party cannot move. A git **merge-base against
> `main`** is such a reference for a PR author (they own their branch; they do not own `main`).
> **State the bootstrap in BOTH directions (D-19):** that anchor is sound against an author who cannot
> rewrite `main` — the threat in scope — and **NOT** sound against an attacker who can. **That residual
> is what Builds 12 close, and it must be recorded as a tracked dependency, never implied.**
### First-class principle — no universally-quantified check may pass over an empty set
> **"All registered cases ran" is VACUOUSLY TRUE when there are no registered cases.**
> **Non-emptiness and anchoring are PRECONDITIONS asserted before the quantified check runs — not
> properties hoped for after it.**
>
> Promoted by Mos (2026-08-01) after the identical vacuity appeared **twice, at two different levels**:
> `activationCommit = HEAD` emptied the **commit range** (D-44), and an emptied manifest — `criteria`,
> `gates`, `proseClaims`, `compatibilityScenarios` all `[]` — emptied the **registry population**
> (D-46), each yielding **exit 0**. The first was fixed **as an instance**; the principle was never
> extracted, **so it returned one level up.**
>
> **Delete every gate and every criterion TOGETHER and no remaining reference complains — because every
> reference went with them.** A check that quantifies over a population must actually **range** over it,
> and that population must be **provably complete and non-empty**.
>
> **Corollary (same disease):** a clause written for the instance that produced it is not a clause.
> **Do not relabel the originating instances as the general clauses** — quantify over the population.
### First-class principle — redundant observation on evidence-bearing steps
> **Two observers of the same evidence, disagreeing, catch what neither catches alone.** Apply redundancy
> not only to judgement calls but to **evidence gathering itself** — the step everyone assumes is
> mechanical and therefore skips.
>
> Promoted by Mos (2026-08-01) from **D-33**. A seat scanned a pipeline with `-f json` and reported 9
> steps; the orchestrator scanned the same pipeline in the wrapper's default text mode and reported 8.
> **The default output omits `clone`.** Every "full step scan" that night had been 8-of-9 and was stated
> as complete in good faith. No verdict changed — but the _method_ was wrong, invisibly, and **only the
> disagreement between two counts surfaced it.**
>
> The reason it survived: **a summary that resembles an enumeration is more dangerous than one that
> obviously summarises.** A labelled list of named steps with states _looks_ like the artifact, so nobody
> checks it against the record. Compare D-24 — `mergeable` was a _true answer to a different question_;
> this was a _true answer to a smaller one_. Neither is a lie; both pass every sniff test.
>
> **Operationally:** where a step _produces evidence a decision rests on_, have it produced twice by
> different means, and treat **any divergence as a finding rather than as noise to reconcile**. Prefer the
> machine-readable record over the human-readable rendering — _read the artifact, not the summary_ — and
> state the counts observed so a divergence is detectable at all.
## Decision record (authoritative, immutable)
- **15/15 proposals decided: 13 accept, 2 modify (P-AUTHORITY-001, P-INBOX-001), 0 reject.**
- Site + `annotations.json`: `jarvis-brain/docs/postmortem-spec/site/` (committed, origin/main).
- Discussion checkpoint (rich rationale per proposal): `jarvis-brain/docs/scratchpads/postmortem/REMEDIATION-DISCUSSION-STATE.md`.
- Postmortem report: mosaicstack/stack PR #107 (merged 88f4ee04).
- MACP wiring scout (verdict c=STRANDED): [`MACP-WIRING-SCOUT.md`](./MACP-WIRING-SCOUT.md) (copied into this dir; TODO discharged). Its findings are sound; its _recommended wire-in point_ is superseded by DECISION-1.
## The plan — 15 proposals collapse to 4 builds + hygiene
| Build | Absorbs | What it is |
| ------------------------------------------------------------ | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **1. One choke-point service** (mechanical enforcer) | MISSION, STATE, AUDIT, WRAPPER, QUEUE | Deterministic program every task/data mutation flows through. **Wire the stranded `@mosaicstack/macp`** — typed tasks, gate-runner, event ledger, credential binding, tri-state write outcomes. ⚠ **Target CORRECTED 2026-07-31 (DECISION-1, Mos):** a new production Node `TaskExecutor` on the **live** dispatch path (`packages/mosaic` launch + `packages/coord`), which Coord/Forge/live-dispatch submit through. **NOT** `mosaic_orchestrator.py::run_single_task` — that controller is `"enabled": false` and references a dispatcher absent from this checkout; wiring it would strand the executor, reproducing this mission's own disease. The Python rail is **deleted**, not ported. Both planners reached this independently. |
| **2. One durable spine + hot path** | (storage under everything) | **PG system-of-record + Redis hot queue** (transactional-outbox). Mission/tasks/state-claims/audit-ledger/comms-inbox all land here. |
| **3. Rotation lifecycle** (finish the Mission Control Plane) | LIFECYCLE, CONTRACT, GUIDE, RECOVERY | Coordinator daemon: contract-hash binding, compaction-detected → rotate-not-compact, checkpoint→fresh-session→rehydrate, broker-independent recovery. Deterministic, not an LLM. Reuse `packages/coord`; existing PRD at `docs/mission-control/`. |
| **4. Comms service** | AUTHORITY, INBOX (+ versioning roadmap) | Envelope (comms/v1) → sole-path service → PG/Redis → pluggable adapters (tmux→Matrix/Discord/Slack/Telegram). Version the protocol, not participants. |
| **+ Hygiene & proof** | FLEET, WORKFLOW, CONFORMANCE | One roster-owned socket/host + stale GC; allowlist auto-sync; the conformance harness that fault-injects the failure classes and proves builds 14 hold. |
## Why Builds 12 are necessary — two independent impossibility proofs
**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 that needed it — and both times the only resolution was an authority _outside_ the audited
party's control, which is precisely what Builds 12 provide.
| | the audited party controls… | so what fails | found as |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------- | --------------- | -------- |
| **Artifact integrity** | the manifest that certifies its own generated tree (same-UID write ⇒ regenerate manifest _and_ marker consistently, CWE-345) | tamper-evidence | **D-19** |
| **Execution integrity** | the code that enters the sandbox (PR-controlled config executes _before_ the boundary exists) | isolation | **D-25** |
Both reduce to one sentence:
> **Self-verification by the audited party is not verification.**
And to one consequence: **the anchor must live outside the audited party's authority.** A local check
cannot defend against an actor who can rewrite the check; a repo cannot grant a capability to
PR-controlled config and simultaneously prevent that config from using it.
**An architecture forced by two independent impossibility proofs is stronger evidence than one argued
for.** Neither proof was sought — both arrived while trying to ship something else, from different
directions (a symlink manifest; a CI sandbox), at different layers. RM-59 and RM-60 are the two tracked
dependencies this creates, and they are the same dependency in different clothes.
## The finding that sets the cost
**Built-but-unwired disease.** `@mosaicstack/macp` is stranded (nothing calls it); `packages/coord` primitives
exist; the Mission Control PRD exists; PG + Redis already run in-stack. Three duplicate MACP islands, an
orphaned context loader, a fail-open bypass. **Work = wire + consolidate + retire, NOT greenfield. "Finish, don't re-spec."**
## Sequencing (skeleton — adversarial decomposition refines this)
1. **Spine + choke-point service** (builds 1+2) — foundation; unlocks MISSION/STATE/AUDIT/WRAPPER/QUEUE at one integration point.
(Per DECISION-1, a P0 phase of provable-gate + activation work precedes this; see `TASKS.md` §3.)
2. **Rotation daemon** (build 3) on that spine — the drift fix proper.
3. **Comms service** (build 4) — envelope → service → PG/Redis → adapters; retire direct-tmux.
4. **Hygiene + conformance** (build 5) — fleet convergence, allowlist sync, dogfood harness.
- **Cross-cutting retirements:** flat-file orchestration tracking (hard cutover to DB), the 3 duplicate MACP islands, the silent `MOSAIC BYPASS`.
## Standing directives (Jason, 2026-07-31)
- **Dogfooding:** validate EACH fix against the live fleet failure that motivated it. Seed acceptance tests:
Pi brick (RECOVERY), scout-bounce (INBOX/FLEET), gate-6 inert + #1019 recursion (QUEUE), identity drift
(WRAPPER), auto-sync sweep (WORKFLOW), #1018 stale-consumed (INBOX). The fleet is its own test bed.
- **Orchestration tracking → DB**, hard cutover ("rip off the bandaid"), NO flat-file interim. jarvis-brain
PDA flat-files untouched. Current flat-file tracking runs as-is/unhardened until DB tracking is real, then one clean replace.
-**QUALIFIED 2026-07-31 (DECISION-2, Mos):** the DB spine **must NOT be a single-point hard-stop.**
A broker-independent / degraded mode **and** a rehearsed rollback artifact are **design requirements**
(P-RECOVERY-001), binding now on RM-12, RM-13, RM-23, RM-36 and RM-53. This **supersedes** the earlier
orchestrator recommendation to pre-commit "no DB ⇒ the fleet stops" — that answer is _not_ on record.
Only the specific availability _target_ remains open, queued for Jason; it does **not** block current work.
## The 15 decisions (one-line; full rationale in the checkpoint)
1. **P-ACTIVATION-001** accept — transactional CLI+hooks+broker+version release; block launch on skew, fail-SAFE.
2. **P-AUTHORITY-001** MODIFY — structured authenticated inbox; envelope carries comms-PROTOCOL version; version the protocol not participants; N-version window.
3. **P-LIFECYCLE-001** accept — rotation not recursive compaction; pre-empt at token threshold; enforcer = deterministic coordinator; = finish Mission Control Plane.
4. **P-MISSION-001** accept — bind lanes to mission+task ledger; convention exists, ENFORCEMENT is the gap; mission+tasks → DB spine (hard cutover).
5. **P-QUEUE-001** accept — repair queue transport + exit-asserting non-null-case tests (gate-6 was INERT fleet-wide; #1019 fix recursed the same bug).
6. **P-STATE-001** accept — typed claims (source/confidence/TTL) not prose blob; MACP typed record; integrity fail-closed HMAC; don't fork a 4th island.
7. **P-AUDIT-001** accept — MACPEvent lifecycle ledger; EXTEND enum to lifecycle events; runtime-neutral (executor-emitted); retire duplicate Python ledger.
8. **P-WRAPPER-001** accept — identity derives from seat name + survives respawn; tri-state write outcomes MANDATORY; name safe target metadata.
9. **P-CONTRACT-001** accept — bind session to contract hash; re-anchor on policy-change OR compaction-detected; stale generation loses authority MECHANICALLY.
10. **P-INBOX-001** MODIFY — sole-path comms SERVICE; PG durable SoR + Redis hot queue (outbox, reconciliation sweeper); pluggable adapters; protocol-first, PG-first-then-Redis.
11. **P-RECOVERY-001** accept — broker-independent bootstrap recovery; honest capability labeling; break-glass LOUD+AUDITED+TEMPORARY not silent permanent bypass.
12. **P-GUIDE-001** accept — delete `/compact and continue` from orchestrator path (keep for ephemeral); removal = substitution (wire rotation trigger).
13. **P-FLEET-001** accept — one roster-owned socket/host; quarantine unmanaged; stale-session GC; prerequisite for INBOX identity-addressing.
14. **P-WORKFLOW-001** accept — auto-sync ALLOWLIST not denylist; worktree/lease isolation for agent docs/source; DB-tracking obviates the flat-file-sweep criterion.
15. **P-CONFORMANCE-001** accept — fleet lifecycle harness on REAL runtime artifacts + fault injection; the 100-rotations-lossless bar is a test; target the DB substrate.
## Fleet operating model
- **Project orchestrator** `mos-remediation` (this seat) owns the mission; coordinates under Mos (lead).
- **Adversarial task decomposition:** `planner-opus` (robustness) + `planner-sol` (pragmatic) each decompose
the plan independently; orchestrator reconciles into `TASKS.md`/DB tasks. Oppositional by design.
- **Delivery gates — REFERENCE, do not restate.** The authoritative definitions live at
[`~/.config/mosaic/fleet/roles.local/merge-gate.md`](file:///home/hermes/.config/mosaic/fleet/roles.local/merge-gate.md)
(verdict authority) and
[`~/.config/mosaic/fleet/roles/validator.md`](file:///home/hermes/.config/mosaic/fleet/roles/validator.md)
(validator/certificate role). **Read them; do not paraphrase them.** Restating an authoritative source
is lossy every time — see D-26, where a subset restated from memory dropped a security precondition.
**Gate order** (the sequence only; the definitions are in the files above):
1. Independent review, **author ≠ reviewer** (`rev-974` on mosaicstack), with PRE-REGISTERED diff-blind
acceptance checks committed before the diff is read
2. Remediation of findings
3. **CI terminal-green** at the exact full-40 head, by **full step scan**
4. **Merge-gate verdict — `GO` / `NO-GO` / `HOLD`** (class `merge-gate`; "Ultron" is an _instance name_,
display data, never an authority source). **Bound to a commit and VOID the instant the head moves.**
`HOLD` persists until replaced; a `NO-GO` answered by an empty commit must be re-issued as `NO-GO`.
Posted durably on the PR under the gate's own minted identity, **enumerating** its evidence — a bare
"GO — gates verified" is non-conforming.
5. **Coordinator merge**, head-pinned. The gate never merges; it holds `push=False` by design.
**The CI queue guard runs but is ZERO-INFORMATION until RM-03 lands** (D-23: it returns pass for every
possible input). It must not be cited as evidence by any gate, including the coordinator's own merge path.
**Assignment:** the coordinator assigns the merge-gate seat; the orchestrator does not. The orchestrator
owns getting a PR _gate-ready_.
- **Compaction survival:** see `KICKSTART.md` in this dir — the resume procedure. Persist typed state, not transcript.
File diff suppressed because it is too large Load Diff
@@ -109,55 +109,6 @@ else
detect_platform >/dev/null
fi
# Render the provider's own explanation for a failed request, for appending to
# an error message (#1004). Every HTTP arm in this file already has the response
# body on disk; without this it was discarded unread at exactly the moment the
# caller needed it, which pushes an operator toward re-issuing the request by
# hand to find out what the server said. Gitea returns {"message": "..."} on a
# refusal; anything unparseable falls back to a truncated raw first line so a
# proxy's HTML error page still says something. Prints "" when there is nothing
# to add, so callers can interpolate unconditionally.
#
# Args: $1 = path to the response body file.
gitea_error_detail() {
local body_file="$1"
[[ -s "$body_file" ]] || return 0
python3 - "$body_file" <<'PY' 2>/dev/null || true
import json
import sys
LIMIT = 300
try:
with open(sys.argv[1], encoding="utf-8", errors="replace") as response:
raw = response.read().strip()
except OSError:
raise SystemExit(0)
if not raw:
raise SystemExit(0)
detail = ""
try:
parsed = json.loads(raw)
if isinstance(parsed, dict):
for key in ("message", "error", "errors"):
value = parsed.get(key)
if isinstance(value, str) and value.strip():
detail = value.strip()
break
if isinstance(value, list) and value:
detail = "; ".join(str(item) for item in value).strip()
break
except ValueError:
pass
if not detail:
detail = raw.splitlines()[0].strip()
if not detail:
raise SystemExit(0)
if len(detail) > LIMIT:
detail = detail[:LIMIT] + "..."
print(f" — provider said: {detail}")
PY
}
# Post a comment to a Gitea PR (PR comments ARE issue comments) via the
# supported REST API and verify it against a PROVIDER-RETURNED created id. The
# write is a direct POST that returns the created comment object, so we learn
@@ -199,7 +150,7 @@ print(json.dumps({"body": os.environ["COMMENT_BODY"]}))
return 1
fi
if [[ "$write_status" != "201" ]]; then
echo "Error: Gitea comment write failed with HTTP $write_status$(gitea_error_detail "$write_file")" >&2
echo "Error: Gitea comment write failed with HTTP $write_status" >&2
return 1
fi
@@ -228,7 +179,7 @@ PY
return 1
fi
if [[ "$readback_status" != "200" ]]; then
echo "Error: Gitea comment read-back failed with HTTP $readback_status$(gitea_error_detail "$readback_file")" >&2
echo "Error: Gitea comment read-back failed with HTTP $readback_status" >&2
return 1
fi
@@ -419,7 +370,7 @@ gitea_authenticated_login() {
return 1
fi
if [[ "$status" != "200" ]]; then
echo "Error: Gitea authenticated-identity read failed with HTTP $status$(gitea_error_detail "$response_file")" >&2
echo "Error: Gitea authenticated-identity read failed with HTTP $status" >&2
return 1
fi
@@ -456,7 +407,7 @@ gitea_read_pr_head_into() {
return 1
fi
if [[ "$status" != "200" ]]; then
echo "Error: Gitea PR head read failed with HTTP $status$(gitea_error_detail "$pr_file")" >&2
echo "Error: Gitea PR head read failed with HTTP $status" >&2
return 1
fi
python3 - "$pr_file" <<'PY'
@@ -546,7 +497,7 @@ print(json.dumps({
fi
# Gitea returns 200 (occasionally 201) with the created review object.
if [[ "$write_status" != "200" && "$write_status" != "201" ]]; then
echo "Error: Gitea review submit failed with HTTP $write_status$(gitea_error_detail "$write_file")" >&2
echo "Error: Gitea review submit failed with HTTP $write_status (#865: no durable review created)" >&2
return 1
fi
@@ -575,7 +526,7 @@ PY
return 1
fi
if [[ "$readback_status" != "200" ]]; then
echo "Error: Gitea review read-back failed with HTTP $readback_status$(gitea_error_detail "$readback_file")" >&2
echo "Error: Gitea review read-back failed with HTTP $readback_status" >&2
return 1
fi
@@ -58,9 +58,6 @@ CREDENTIALS_FILE="$WORK_DIR/credentials.json"
# A dedicated scratch dir the wrapper is pointed at via TMPDIR, so the leak
# check can assert every POST/GET body + metadata temp file is cleaned up.
TMP_SCRATCH="$WORK_DIR/scratch"
# Sandboxed HOME so nothing under the real $HOME (notably the per-slot Gitea token
# store at ~/.config/mosaic/secrets/gitea-tokens/) is reachable from the wrapper.
HOME_DIR="$WORK_DIR/home"
cleanup() {
rm -rf "$WORK_DIR"
@@ -81,18 +78,9 @@ OVERRIDE_TOKEN="override-token-placeholder"
CROSS_HOST_LOGIN="foreign-host-reviewer"
CROSS_HOST_TOKEN="cross-host-token-placeholder"
mkdir -p "$REPO_DIR" "$BIN_DIR" "$XDG_DIR" "$STATE_DIR" "$TMP_SCRATCH" "$HOME_DIR"
mkdir -p "$REPO_DIR" "$BIN_DIR" "$XDG_DIR" "$STATE_DIR" "$TMP_SCRATCH"
git -C "$REPO_DIR" init -q
git -C "$REPO_DIR" remote add origin https://git.mosaicstack.dev/mosaicstack/stack.git
# HERMETICITY: get_gitea_token() step 0 resolves a per-agent identity from
# `git config --get mosaic.gitIdentity`, which on a provisioned agent seat is set
# GLOBALLY and therefore leaks into this fresh repo. It then reads a REAL per-slot
# token from $HOME and returns it WITHOUT ever consulting MOSAIC_CREDENTIALS_FILE,
# so the fixture credentials below are silently ignored and the suite runs against
# production credentials. An empty repo-local value shadows the global one and reads
# back as empty at rc=0, restoring the shared-credential path this suite intends to
# exercise. Paired with the sandboxed HOME in run_review().
git -C "$REPO_DIR" config mosaic.gitIdentity ""
# tea config: the override login carries its own token here. The default login
# name ("mosaicstack") is deliberately absent, so the no-override default path
@@ -278,24 +266,6 @@ submitted = json.loads(os.environ["PR_REVIEW_PAYLOAD"])
with open(state_path, encoding="utf-8") as handle:
reviews = json.load(handle)
# review-refused-422 (#1004): the server REFUSES the submit outright with a
# definite, correct, machine-readable reason in the body — the shape Gitea
# returns when the acting credential authored the PR. Nothing is created. The
# wrapper must surface what the server said and must NOT relabel this as the
# #865 silent-no-op defect class, which is precisely what it is not.
if mode == "review-refused-422":
print("422")
print(json.dumps({"message": "Cannot approve your own pull request"}))
raise SystemExit(0)
# review-refused-html (#1004): a non-JSON error body, as a fronting proxy or
# gateway emits. The detail extraction must degrade to the first raw line rather
# than silently dropping the only explanation available.
if mode == "review-refused-html":
print("502")
print("<html><head><title>502 Bad Gateway</title></head>\n<body>nginx</body></html>")
raise SystemExit(0)
# no-op-concurrent-review: the wrapper's own submit is SUPPRESSED (200, no
# created object) even though a concurrent same-identity, same-state review at
# the same head already exists. Nothing is persisted; no created id to verify.
@@ -547,8 +517,6 @@ run_review() {
cd "$REPO_DIR"
PATH="$BIN_DIR:$PATH" \
TMPDIR="$TMP_SCRATCH" \
HOME="$HOME_DIR" \
MOSAIC_GIT_IDENTITY="" \
XDG_CONFIG_HOME="$XDG_DIR" \
MOSAIC_CREDENTIALS_FILE="$CREDENTIALS_FILE" \
PR_REVIEW_TEA_LOG="$TEA_LOG" \
@@ -972,44 +940,4 @@ if grep -q 'Approved and verified' "$OUTPUT_FILE"; then
fi
assert_no_temp_leak "review-body-null"
# Case 19 (#1004): an outright server REFUSAL must report the provider's own
# reason and must NOT be relabelled as the #865 silent-no-op defect class. The
# old arm hardcoded "(#865: no durable review created)" for EVERY non-2xx, so a
# 422/403/404 — all of them definite, correct refusals the server explained in
# the discarded body — arrived at the caller wearing the name of the one defect
# they are not. That misdirection is what makes an operator re-issue the request
# by hand against the live object to find out what actually happened.
if run_review review-refused-422 approve; then
echo "FAIL: approve reported success when the server refused the submit" >&2
cat "$OUTPUT_FILE" >&2
exit 1
fi
grep -q 'HTTP 422' "$OUTPUT_FILE"
if ! grep -q 'Cannot approve your own pull request' "$OUTPUT_FILE"; then
echo "FAIL: the provider's stated reason was discarded (#1004)" >&2
cat "$OUTPUT_FILE" >&2
exit 1
fi
if grep -q '#865: no durable review created' "$OUTPUT_FILE"; then
echo "FAIL: a server refusal was misattributed to the #865 defect class (#1004)" >&2
cat "$OUTPUT_FILE" >&2
exit 1
fi
assert_no_temp_leak "review-refused-422"
# Case 20 (#1004): a non-JSON error body (a fronting proxy's HTML page) must
# still yield something the caller can act on, rather than a bare status code.
if run_review review-refused-html approve; then
echo "FAIL: approve reported success on a 502" >&2
cat "$OUTPUT_FILE" >&2
exit 1
fi
grep -q 'HTTP 502' "$OUTPUT_FILE"
if ! grep -q '502 Bad Gateway' "$OUTPUT_FILE"; then
echo "FAIL: a non-JSON error body was dropped instead of degrading to its first line (#1004)" >&2
cat "$OUTPUT_FILE" >&2
exit 1
fi
assert_no_temp_leak "review-refused-html"
echo "pr-review.sh REST review + comment create/read-back regression passed"
@@ -1,165 +0,0 @@
#!/usr/bin/env bash
# check-test-enumeration.sh — CI test-membership guard (#1017).
#
# CI reaches shell suites through two hand-enumerated surfaces:
# S1 packages/mosaic/package.json scripts."test:framework-shell"
# S2 .woodpecker/ci.yml direct `bash packages/mosaic/framework/tools/...` commands
#
# A hand-enumerated allowlist re-arms its own gap: a new suite never auto-joins,
# so the list silently under-runs the disk (17 of 39 suites were invisible when
# #1017 was filed). This guard makes that under-run impossible to do silently:
#
# FAIL when a suite-shaped file exists on disk and is neither enumerated on
# the UNION of both surfaces nor listed in the exclusions file.
# ("Enumerated", deliberately — F1/F2 on PR #1018 proved this guard sees
# NAMING, not reachability, and its words must not claim otherwise.)
# FAIL when either surface names a path that does not exist on disk
# (a rename manufactures a stale entry silently — checked BOTH directions).
# FAIL when an exclusion entry has no reason, names a path that is gone,
# names a path that is also enumerated (contradiction), or names a path
# outside the population (dead weight that looks like coverage).
#
# POPULATION PATTERN — a deliberate decision, stated per #1017's record:
# basename matches *test*.sh (contains "test", ends ".sh"). Deliberately BROAD:
# the strict `test-*.sh` prefix cannot even name three real boundary files
# (tmux/agent-send.test.sh — CI-run; orchestrator/smoke-test.sh;
# wake/validate-973/microtest-wake-assert.sh), and three independent censuses
# handled that last file three different ways with no trace of the judgement.
# The broad pattern makes such files MEMBERS, so their disposition must be a
# signed exclusion, not an accident of the glob. The SAME pattern is applied to
# both sides of the comparison (disk and enumeration) — a comparison globbed two
# ways runs on two different populations. Scripts outside the pattern on both
# sides symmetrically (e.g. check-resident-budget.sh, verify-sanitized.sh) are
# check-scripts, not suites; their existence is still verified via the
# both-directions rule because every surface-named path must exist on disk.
#
# The surfaces are PARSED, never line-ranged: three seats independently
# mis-scoped hand-written line ranges against these files (#1017 thread). S1 is
# read via JSON + command-chain tokenization; S2 by extracting every
# packages/mosaic/framework/tools/ token wherever it appears in the file.
#
# Exclusions file format (framework/tools/quality/test-enumeration-exclusions.txt):
# <repo-relative-path> | <non-empty reason>
# Lines starting with # and blank lines are ignored. An exclusion is a recorded
# decision someone signed, not an omission nobody made.
set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT="$(cd "$SCRIPT_DIR/../../../../../.." && pwd)"
while (( $# )); do
case "$1" in
--root) ROOT="$(cd "$2" && pwd)"; shift 2 ;;
*) echo "usage: check-test-enumeration.sh [--root <repo-root>]" >&2; exit 2 ;;
esac
done
PKG_JSON="$ROOT/packages/mosaic/package.json"
CI_YML="$ROOT/.woodpecker/ci.yml"
TOOLS_DIR="$ROOT/packages/mosaic/framework/tools"
EXCLUSIONS="$TOOLS_DIR/quality/test-enumeration-exclusions.txt"
for f in "$PKG_JSON" "$CI_YML"; do
[[ -f "$f" ]] || { echo "FAIL: required surface file missing: $f" >&2; exit 2; }
done
[[ -d "$TOOLS_DIR" ]] || { echo "FAIL: tools dir missing: $TOOLS_DIR" >&2; exit 2; }
fail_count=0
fail() { printf 'FAIL %s\n' "$1"; fail_count=$(( fail_count + 1 )); }
# in_population <repo-relative path> — the single pattern, used for BOTH sides.
in_population() {
local base; base="$(basename "$1")"
[[ "$base" == *test*.sh ]]
}
# --- Surface 1: package.json test:framework-shell, parsed, repo-relative -----
# Tokens are script paths iff they contain "/" and end .sh/.py; interpreter
# names and flags are skipped. Paths are relative to packages/mosaic/.
mapfile -t S1 < <(python3 - "$PKG_JSON" <<'PY'
import json, shlex, sys
cmd = json.load(open(sys.argv[1]))["scripts"].get("test:framework-shell", "")
seen = []
for seg in cmd.split("&&"):
for tok in shlex.split(seg):
if "/" in tok and (tok.endswith(".sh") or tok.endswith(".py")):
path = "packages/mosaic/" + tok
if path not in seen:
seen.append(path)
print("\n".join(seen))
PY
)
# --- Surface 2: ci.yml, every framework/tools token wherever it appears ------
# Comment lines (first non-whitespace char is #) are skipped BEFORE matching:
# commenting an invocation out is the most common way a suite actually gets
# disabled, and a raw-text regex would keep calling it enumerated (F1, 20155 on
# PR #1018 — demonstrated, not argued). Known residual limit: a path named only
# in a TRAILING comment on a live line still matches; no such line exists today
# and full fidelity would need a YAML parser the CI image does not ship.
mapfile -t S2 < <(grep -vE '^[[:space:]]*#' "$CI_YML" \
| grep -oE 'packages/mosaic/framework/tools/[A-Za-z0-9_./-]+\.(sh|py)' | sort -u)
# --- Union, and its population-restricted view -------------------------------
declare -A ENUM=() ENUM_POP=()
for p in "${S1[@]:-}" "${S2[@]:-}"; do
[[ -n "$p" ]] || continue
ENUM["$p"]=1
in_population "$p" && ENUM_POP["$p"]=1
done
# --- Direction B: every surface-named path must exist on disk ----------------
for p in "${!ENUM[@]}"; do
[[ -f "$ROOT/$p" ]] || fail "STALE ENUMERATION: surfaces name '$p' but it does not exist on disk"
done
# --- Exclusions: parsed with the same rigor the enumeration gets -------------
declare -A EXCLUDED=()
if [[ -f "$EXCLUSIONS" ]]; then
lineno=0
while IFS= read -r line; do
lineno=$(( lineno + 1 ))
[[ "$line" =~ ^[[:space:]]*(#|$) ]] && continue
path="${line%%|*}"; reason="${line#*|}"
path="$(echo "$path" | sed 's/^[[:space:]]*//; s/[[:space:]]*$//')"
reason="$(echo "$reason" | sed 's/^[[:space:]]*//; s/[[:space:]]*$//')"
if [[ "$line" != *"|"* || -z "$reason" ]]; then
fail "EXCLUSION MISSING REASON: line $lineno ('$path') — an exclusion is a recorded decision someone signed"
continue
fi
if [[ ! -f "$ROOT/$path" ]]; then
fail "STALE EXCLUSION: line $lineno excludes '$path' which does not exist on disk"
continue
fi
if ! in_population "$path"; then
fail "EXCLUSION OUTSIDE POPULATION: line $lineno excludes '$path' which the population pattern does not name — dead weight that reads as coverage"
continue
fi
if [[ -n "${ENUM[$path]:-}" ]]; then
fail "CONTRADICTORY EXCLUSION: line $lineno excludes '$path' which the surfaces already enumerate"
continue
fi
EXCLUDED["$path"]=1
done < "$EXCLUSIONS"
fi
# --- Direction A: disk population must be enumerated or signed-excluded ------
disk_total=0
unlisted=0
while IFS= read -r f; do
rel="${f#"$ROOT"/}"
in_population "$rel" || continue
disk_total=$(( disk_total + 1 ))
if [[ -z "${ENUM_POP[$rel]:-}" && -z "${EXCLUDED[$rel]:-}" ]]; then
fail "UNENUMERATED: '$rel' exists on disk but is neither enumerated on any CI surface nor signed in the exclusions file"
unlisted=$(( unlisted + 1 ))
fi
done < <(find "$TOOLS_DIR" -type f -name '*.sh' | sort)
if (( fail_count > 0 )); then
printf 'enumeration guard: %d failure(s) — population %d, enumerated (in-population) %d, excluded %d\n' \
"$fail_count" "$disk_total" "${#ENUM_POP[@]}" "${#EXCLUDED[@]}"
exit 1
fi
printf 'enumeration guard: OK — population %d, enumerated (in-population) %d, excluded (signed) %d, surfaces name %d path(s), all present on disk\n' \
"$disk_total" "${#ENUM_POP[@]}" "${#EXCLUDED[@]}" "${#ENUM[@]}"
@@ -1,166 +0,0 @@
#!/usr/bin/env bash
# test-check-test-enumeration.sh — needles for the enumeration guard (#1017).
#
# Every failure mode the guard promises gets BOTH polarities:
# NEEDLE a fixture that MUST trip the guard, asserted on the guard's OWN
# words (--out) — exit 1 alone cannot distinguish "caught the rogue
# file" from "choked on the fixture".
# CONTROL a fixture that MUST pass. A guard that failed unconditionally
# would satisfy every needle here — the null-case defect the guard's
# own subject matter (#1017) exists to make impossible.
#
# The needles encode the specific errors that produced #1017's thread:
# n6 is the 20124 boundary file (a suite the strict prefix cannot name);
# n2b proves surface 2 is PARSED, not line-ranged (three seats mis-scoped
# hand-written ranges against ci.yml);
# n5/n7 keep the exclusions file honest so it cannot become the next silent cap;
# n8/c4 are F1 (20155): a commented-out ci.yml line is NOT enumeration —
# commenting-out is the most common way a suite actually gets disabled,
# and it must fail loud in one direction without false-staling the other.
set -uo pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
GUARD="$HERE/check-test-enumeration.sh"
TMP="$(mktemp -d)"; trap 'rm -rf "$TMP"' EXIT
PASS=0; FAIL=0
# fixture <name> — a minimal repo root the guard accepts via --root:
# one suite enumerated on S1 (plus a naming-outlier suite, so the S1 parser's
# handling of non-prefix names is always exercised), one on S2, one check-script
# named on S2 that is outside the population, and an empty exclusions file.
fixture() {
local r="$TMP/$1"
mkdir -p "$r/packages/mosaic/framework/tools/git" \
"$r/packages/mosaic/framework/tools/tmux" \
"$r/packages/mosaic/framework/tools/quality/scripts" \
"$r/.woodpecker"
printf '#!/usr/bin/env bash\nexit 0\n' > "$r/packages/mosaic/framework/tools/git/test-a.sh"
printf '#!/usr/bin/env bash\nexit 0\n' > "$r/packages/mosaic/framework/tools/tmux/outlier.test.sh"
printf '#!/usr/bin/env bash\nexit 0\n' > "$r/packages/mosaic/framework/tools/quality/scripts/test-ci.sh"
printf '#!/usr/bin/env bash\nexit 0\n' > "$r/packages/mosaic/framework/tools/quality/scripts/verify-thing.sh"
cat > "$r/packages/mosaic/package.json" <<'JSON'
{"scripts": {"test:framework-shell": "bash framework/tools/git/test-a.sh && bash framework/tools/tmux/outlier.test.sh"}}
JSON
cat > "$r/.woodpecker/ci.yml" <<'YML'
steps:
sanitize:
commands:
- bash packages/mosaic/framework/tools/quality/scripts/verify-thing.sh
guard:
commands:
- bash packages/mosaic/framework/tools/quality/scripts/test-ci.sh
YML
: > "$r/packages/mosaic/framework/tools/quality/test-enumeration-exclusions.txt"
printf '%s' "$r"
}
# expect <kind> <want-exit> <desc> [--out <substring>] -- <root>
expect() {
local kind="$1" want="$2" desc="$3"; shift 3
local need_out=""
while (( $# )); do
case "$1" in
--out) need_out="$2"; shift 2 ;;
--) shift; break ;;
esac
done
local root="$1" got=0 out
out="$(bash "$GUARD" --root "$root" 2>&1)" || got=$?
local why=""
[[ "$got" == "$want" ]] || why="wanted exit $want, got $got"
if [[ -z "$why" && -n "$need_out" && "$out" != *"$need_out"* ]]; then
why="exit $got as expected, but output never said: $need_out"
fi
if [[ -z "$why" ]]; then
printf ' PASS [%-7s] %s (exit %s)\n' "$kind" "$desc" "$got"
PASS=$(( PASS + 1 ))
else
printf ' FAIL [%-7s] %s — %s\n' "$kind" "$desc" "$why"
printf '%s\n' "$out" | sed 's/^/ | /'
FAIL=$(( FAIL + 1 ))
fi
}
excl() { printf '%s\n' "$2" >> "$1/packages/mosaic/framework/tools/quality/test-enumeration-exclusions.txt"; }
echo "=== c1: a fully consistent fixture passes ==="
R="$(fixture c1)"
expect CONTROL 0 "consistent tree: both surfaces enumerated, nothing unlisted" \
--out "enumeration guard: OK" -- "$R"
echo "=== n1: an on-disk suite reachable from no surface must fail ==="
R="$(fixture n1)"
printf '#!/usr/bin/env bash\nexit 0\n' > "$R/packages/mosaic/framework/tools/git/test-rogue.sh"
expect NEEDLE 1 "unlisted suite is named in the failure" \
--out "UNENUMERATED: 'packages/mosaic/framework/tools/git/test-rogue.sh'" -- "$R"
echo "=== n6: the 20124 boundary file — a suite the strict prefix cannot name ==="
R="$(fixture n6)"
printf '#!/usr/bin/env bash\nexit 0\n' > "$R/packages/mosaic/framework/tools/git/rogue.test.sh"
expect NEEDLE 1 "naming-outlier suite (*.test.sh) is a population member, not invisible" \
--out "UNENUMERATED: 'packages/mosaic/framework/tools/git/rogue.test.sh'" -- "$R"
echo "=== c3: a non-suite script outside the pattern is outside it on BOTH sides ==="
R="$(fixture c3)"
printf '#!/usr/bin/env bash\nexit 0\n' > "$R/packages/mosaic/framework/tools/git/check-unrelated.sh"
expect CONTROL 0 "check-script on disk, unlisted, outside population: not the guard's business" \
--out "enumeration guard: OK" -- "$R"
echo "=== n2/n2b: a surface naming a path absent from disk must fail — both surfaces ==="
R="$(fixture n2)"
rm "$R/packages/mosaic/framework/tools/git/test-a.sh"
expect NEEDLE 1 "S1 (package.json) stale entry" \
--out "STALE ENUMERATION: surfaces name 'packages/mosaic/framework/tools/git/test-a.sh'" -- "$R"
R="$(fixture n2b)"
rm "$R/packages/mosaic/framework/tools/quality/scripts/test-ci.sh"
expect NEEDLE 1 "S2 (ci.yml) stale entry — proves ci.yml is parsed, not line-ranged" \
--out "STALE ENUMERATION: surfaces name 'packages/mosaic/framework/tools/quality/scripts/test-ci.sh'" -- "$R"
echo "=== c2: a rogue suite with a SIGNED exclusion passes, and is counted ==="
R="$(fixture c2)"
printf '#!/usr/bin/env bash\nexit 0\n' > "$R/packages/mosaic/framework/tools/git/test-rogue.sh"
excl "$R" "packages/mosaic/framework/tools/git/test-rogue.sh | non-hermetic pending fixture work (needle-suite specimen)"
expect CONTROL 0 "signed exclusion is honoured and visible in the summary" \
--out "excluded (signed) 1" -- "$R"
echo "=== n3: an exclusion with no reason is not a decision ==="
R="$(fixture n3)"
printf '#!/usr/bin/env bash\nexit 0\n' > "$R/packages/mosaic/framework/tools/git/test-rogue.sh"
excl "$R" "packages/mosaic/framework/tools/git/test-rogue.sh | "
expect NEEDLE 1 "empty reason rejected" --out "EXCLUSION MISSING REASON" -- "$R"
R="$(fixture n3b)"
printf '#!/usr/bin/env bash\nexit 0\n' > "$R/packages/mosaic/framework/tools/git/test-rogue.sh"
excl "$R" "packages/mosaic/framework/tools/git/test-rogue.sh"
expect NEEDLE 1 "missing separator rejected (the path alone is not a signature)" \
--out "EXCLUSION MISSING REASON" -- "$R"
echo "=== n4: an exclusion whose path is gone is stale, not satisfied ==="
R="$(fixture n4)"
excl "$R" "packages/mosaic/framework/tools/git/test-vanished.sh | was excluded once, then deleted"
expect NEEDLE 1 "stale exclusion rejected" --out "STALE EXCLUSION" -- "$R"
echo "=== n5: excluding an enumerated suite is a contradiction, not belt-and-braces ==="
R="$(fixture n5)"
excl "$R" "packages/mosaic/framework/tools/git/test-a.sh | already in CI but excluded anyway"
expect NEEDLE 1 "contradictory exclusion rejected" --out "CONTRADICTORY EXCLUSION" -- "$R"
echo "=== n8/c4: a commented-out ci.yml line is not enumeration (F1, 20155) ==="
R="$(fixture n8)"
printf '#!/usr/bin/env bash\nexit 0\n' > "$R/packages/mosaic/framework/tools/git/test-disabled.sh"
printf ' # - bash packages/mosaic/framework/tools/git/test-disabled.sh\n' >> "$R/.woodpecker/ci.yml"
expect NEEDLE 1 "suite named only in a commented-out invocation is UNENUMERATED" \
--out "UNENUMERATED: 'packages/mosaic/framework/tools/git/test-disabled.sh'" -- "$R"
R="$(fixture c4)"
printf ' # - bash packages/mosaic/framework/tools/git/test-vanished.sh\n' >> "$R/.woodpecker/ci.yml"
expect CONTROL 0 "comment naming an absent path raises no false stale-enumeration" \
--out "enumeration guard: OK" -- "$R"
echo "=== n7: excluding a file outside the population is dead weight, not coverage ==="
R="$(fixture n7)"
excl "$R" "packages/mosaic/framework/tools/quality/scripts/verify-thing.sh | not a suite but signing it anyway"
expect NEEDLE 1 "out-of-population exclusion rejected" --out "EXCLUSION OUTSIDE POPULATION" -- "$R"
echo
printf 'enumeration-guard needles: %d passed, %d failed\n' "$PASS" "$FAIL"
(( FAIL == 0 ))
@@ -1,45 +0,0 @@
# test-enumeration-exclusions.txt — signed exclusions for check-test-enumeration.sh (#1017).
#
# Every entry is a recorded decision: a suite-shaped file that exists on disk,
# is NOT reachable from any CI surface, and carries the reason someone signed
# for that. The guard FAILS on an entry with no reason, a stale path, or a path
# the surfaces already enumerate. Burning an entry down = making it CI-reachable
# (package.json test:framework-shell or a ci.yml step) and deleting its line.
#
# Format: <repo-relative path> | <reason>
# All entries below were signed at #1017's filing base (main 826a8b3b, 2026-07-31)
# by pepper (sb-it-1-dt); measurements cited are one-run assertions from that seat.
# --- tools/git: the #1007 five — non-hermetic, resolve real credentials ---
packages/mosaic/framework/tools/git/test-pr-merge-gitea-empty-uid.sh | resolves real credentials (#1007 census); joins CI after the wrapper-half hermeticity fix (git -C scoping)
packages/mosaic/framework/tools/git/test-issue-create-interactive-auth.sh | resolves real credentials (#1007 census); joins CI after the wrapper-half hermeticity fix
packages/mosaic/framework/tools/git/test-gitea-login-resolution.sh | resolves real credentials (#1007 census); joins CI after the wrapper-half hermeticity fix
packages/mosaic/framework/tools/git/test-pr-metadata-gitea.sh | resolves real credentials (#1007 census, fourth entry via family-grep); joins CI after the wrapper-half hermeticity fix
packages/mosaic/framework/tools/git/test-issue-comment-readback.sh | resolves real credentials (#1007 census, fifth entry); joins CI after the wrapper-half hermeticity fix
# --- tools/git: push guards — measured green locally, CI-image fitness unverified ---
packages/mosaic/framework/tools/git/test-push-guard.sh | measured green at 826a8b3b (46 passed / 0 failed, one run, 2026-07-31); CI-image fitness unverified; #1017 burndown
packages/mosaic/framework/tools/git/test-mutate-push-guard.sh | measured green at 826a8b3b (8/0, 13 mutants killed 0 survived, one run, 2026-07-31); requires setsid (util-linux), absent from the alpine base image; #1017 burndown
packages/mosaic/framework/tools/git/test-issue-create-body-safety.sh | hermeticity unaudited — the unprotected suite in #1007's protected/unprotected split; audit before CI; #1017 burndown
# --- tools/git: unmeasured ---
packages/mosaic/framework/tools/git/test-verify-clean-clone.sh | unmeasured in CI image; asserts git file-mode (100644/755) semantics that need verification on the CI filesystem first; #1017 burndown
packages/mosaic/framework/tools/git/test-help-exit-code.sh | unmeasured in CI image; stub-based (#701 regression harness), likely CI-fit; #1017 burndown
packages/mosaic/framework/tools/git/test-lane-brief-pr-linkage.sh | unmeasured in CI image; fixture-based (#546/#547 regression harness), likely CI-fit; #1017 burndown
# --- tools/tmux: require a live tmux server ---
packages/mosaic/framework/tools/tmux/test-send-message-socket.sh | requires a real tmux server on a throwaway socket; CI image ships no tmux; #1017 burndown (needs tmux in image or a signed permanent exclusion)
packages/mosaic/framework/tools/tmux/test-send-message-verdict.sh | requires real tmux-pane fixtures on a throwaway socket; CI image ships no tmux; #1017 burndown (same condition as its sibling)
# --- single-suite directories: unmeasured in CI ---
packages/mosaic/framework/tools/fleet/test-start-agent-session.sh | unmeasured in CI image; stubs tmux via a fake bin dir, likely CI-fit; #1017 burndown
packages/mosaic/framework/tools/glpi/test-list-http-status.sh | unmeasured in CI image; stub-based (#807 regression harness), likely CI-fit; #1017 burndown
packages/mosaic/framework/tools/orchestrator/test-board-roll.sh | unmeasured in CI image; file-fixture based, likely CI-fit; #1017 burndown
packages/mosaic/framework/tools/woodpecker/test-ci-wait-exit-matrix.sh | unmeasured in CI image; drives ci-wait.sh against a stub pipeline-status.sh, likely CI-fit; #1017 burndown
# --- naming-boundary files the strict test-*.sh prefix cannot even name ---
# (#1017: three independent censuses handled the microtest file three different
# ways — editorial drop, structural exclusion, accidental inclusion — with no
# recorded judgement. These lines ARE that judgement, signed.)
packages/mosaic/framework/tools/orchestrator/smoke-test.sh | behavior smoke checks for coord continue/run workflows, run manually by orchestrator seats; unmeasured in CI; #1017 burndown
packages/mosaic/framework/tools/wake/validate-973/microtest-wake-assert.sh | #973 instrument self-test, run as a precondition of the validate-973 evidence procedure rather than as a standing CI suite; #1017 burndown candidate
@@ -529,19 +529,7 @@ cmd_run() {
echo "detector.sh: WARN — off-host liveness beacon emit failed (see beacon.sh); the off-host absence check remains the authoritative dead-man." >&2
fi
[ "$once" -eq 1 ] && break
# Close the detector lock fd in the sleep child; otherwise an orphaned sleep
# keeps the single-instance flock (fd 9, taken at exec 9> above) alive after
# the detector parent dies. The lock is non-blocking (`flock -n`, above), so
# for as long as that sleep survives a replacement instance is REFUSED and
# exits rather than queueing. This particular hold is BOUNDED by one poll
# interval (WAKE_DETECTOR_INTERVAL, default 30s): when the orphaned sleep
# exits its copy of fd 9 closes, ending this bounded sleep-child hold. It
# does NOT follow that the next start succeeds — other inheritors of fd 9
# (the M1 adapter, M2 sink grandchildren) are outside this patch's scope and
# can keep holding the flock. The cost this removes is a restart window in
# which every supervisor retry fails on the sleep child's account.
# `9>&-` closes ONLY the child's copy — the parent's lock is unaffected.
sleep "$interval" 9>&-
sleep "$interval"
done
}
@@ -33,11 +33,7 @@ set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# #973: three-valued grep assertion helpers (has_match/count_lines); init saves real stderr for abort loudness.
# shellcheck disable=SC1091
if ! . "$SCRIPT_DIR/_wake-common.sh"; then
echo "WAKE-ASSERT INIT ABORT: cannot source _wake-common.sh — suite ran ZERO wake assertions (#984)" >&2
exit 97
fi
wake_assert_init
. "$SCRIPT_DIR/_wake-common.sh" && wake_assert_init
BEACON="$SCRIPT_DIR/beacon.sh"
command -v jq >/dev/null 2>&1 || {
@@ -31,11 +31,7 @@ set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# #973: three-valued grep assertion helpers (has_match/count_lines); init saves real stderr for abort loudness.
# shellcheck disable=SC1091
if ! . "$SCRIPT_DIR/_wake-common.sh"; then
echo "WAKE-ASSERT INIT ABORT: cannot source _wake-common.sh — suite ran ZERO wake assertions (#984)" >&2
exit 97
fi
wake_assert_init
. "$SCRIPT_DIR/_wake-common.sh" && wake_assert_init
DET="$SCRIPT_DIR/detector.sh"
STORE="$SCRIPT_DIR/store.sh"
@@ -37,11 +37,7 @@ set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# #973: three-valued grep assertion helpers (has_match/count_lines); init saves real stderr for abort loudness.
# shellcheck disable=SC1091
if ! . "$SCRIPT_DIR/_wake-common.sh"; then
echo "WAKE-ASSERT INIT ABORT: cannot source _wake-common.sh — suite ran ZERO wake assertions (#984)" >&2
exit 97
fi
wake_assert_init
. "$SCRIPT_DIR/_wake-common.sh" && wake_assert_init
STORE="$SCRIPT_DIR/store.sh"
DIGEST="$SCRIPT_DIR/digest.sh"
SIGN="$SCRIPT_DIR/sign.sh"
@@ -119,11 +119,7 @@ set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# #973: three-valued grep assertion helpers (has_match/count_lines); init saves real stderr for abort loudness.
# shellcheck disable=SC1091
if ! . "$SCRIPT_DIR/_wake-common.sh"; then
echo "WAKE-ASSERT INIT ABORT: cannot source _wake-common.sh — suite ran ZERO wake assertions (#984)" >&2
exit 97
fi
wake_assert_init
. "$SCRIPT_DIR/_wake-common.sh" && wake_assert_init
DIGEST="$SCRIPT_DIR/digest.sh"
command -v jq >/dev/null 2>&1 || {
@@ -27,11 +27,7 @@ set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# #973: three-valued grep assertion helpers (has_match/count_lines); init saves real stderr for abort loudness.
# shellcheck disable=SC1091
if ! . "$SCRIPT_DIR/_wake-common.sh"; then
echo "WAKE-ASSERT INIT ABORT: cannot source _wake-common.sh — suite ran ZERO wake assertions (#984)" >&2
exit 97
fi
wake_assert_init
. "$SCRIPT_DIR/_wake-common.sh" && wake_assert_init
ORACLE="$SCRIPT_DIR/fn-oracle.sh"
DET="$SCRIPT_DIR/detector.sh"
@@ -36,11 +36,7 @@ set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# #973: three-valued grep assertion helpers (has_match/count_lines); init saves real stderr for abort loudness.
# shellcheck disable=SC1091
if ! . "$SCRIPT_DIR/_wake-common.sh"; then
echo "WAKE-ASSERT INIT ABORT: cannot source _wake-common.sh — suite ran ZERO wake assertions (#984)" >&2
exit 97
fi
wake_assert_init
. "$SCRIPT_DIR/_wake-common.sh" && wake_assert_init
WI="$SCRIPT_DIR/wake-install.sh"
BEACON="$SCRIPT_DIR/beacon.sh"
FRAMEWORK_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
@@ -48,11 +48,7 @@ set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# #973: three-valued grep assertion helpers (has_match/count_lines); init saves real stderr for abort loudness.
# shellcheck disable=SC1091
if ! . "$SCRIPT_DIR/_wake-common.sh"; then
echo "WAKE-ASSERT INIT ABORT: cannot source _wake-common.sh — suite ran ZERO wake assertions (#984)" >&2
exit 97
fi
wake_assert_init
. "$SCRIPT_DIR/_wake-common.sh" && wake_assert_init
PRE="$SCRIPT_DIR/preimage.sh"
STORE="$SCRIPT_DIR/store.sh"
DET="$SCRIPT_DIR/detector.sh"
@@ -31,11 +31,7 @@ set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# #973: three-valued grep assertion helpers (has_match/count_lines); init saves real stderr for abort loudness.
# shellcheck disable=SC1091
if ! . "$SCRIPT_DIR/_wake-common.sh"; then
echo "WAKE-ASSERT INIT ABORT: cannot source _wake-common.sh — suite ran ZERO wake assertions (#984)" >&2
exit 97
fi
wake_assert_init
. "$SCRIPT_DIR/_wake-common.sh" && wake_assert_init
RECON="$SCRIPT_DIR/reconcile.sh"
STORE="$SCRIPT_DIR/store.sh"
DET="$SCRIPT_DIR/detector.sh"
@@ -44,11 +44,7 @@ set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# #973: three-valued grep assertion helpers (has_match/count_lines); init saves real stderr for abort loudness.
# shellcheck disable=SC1091
if ! . "$SCRIPT_DIR/_wake-common.sh"; then
echo "WAKE-ASSERT INIT ABORT: cannot source _wake-common.sh — suite ran ZERO wake assertions (#984)" >&2
exit 97
fi
wake_assert_init
. "$SCRIPT_DIR/_wake-common.sh" && wake_assert_init
STORE="$SCRIPT_DIR/store.sh"
ACK="$SCRIPT_DIR/ack.sh"
@@ -34,11 +34,7 @@ set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# #973: three-valued grep assertion helpers (has_match/count_lines); init saves real stderr for abort loudness.
# shellcheck disable=SC1091
if ! . "$SCRIPT_DIR/_wake-common.sh"; then
echo "WAKE-ASSERT INIT ABORT: cannot source _wake-common.sh — suite ran ZERO wake assertions (#984)" >&2
exit 97
fi
wake_assert_init
. "$SCRIPT_DIR/_wake-common.sh" && wake_assert_init
STORE="$SCRIPT_DIR/store.sh"
command -v jq >/dev/null 2>&1 || {
@@ -10,9 +10,8 @@ comparison come from independent code paths.
Subcommands (all print sorted, stable output; non-zero exit on any failure):
expected The expected coordinate set from the ARTIFACT: one
"<helper> <file>:<line+7>" row per denominator row (+7 = 3
converter header lines + 4 lines from the #984 source guard,
uniform across all ten suites).
"<helper> <file>:<line+3>" row per denominator row (+3 = the
uniform header shift the converter applied; converter-verified).
Multi-grep lines stay ONE coordinate.
static The converted-site inventory from the SOURCE TEXT at the current
@@ -24,9 +23,9 @@ Subcommands (all print sorted, stable output; non-zero exit on any failure):
from the text.)
arms The forced-error arm list: the 19 denominator canaries plus one
E-form arm (store-ack:733740, a $(count_lines) capture compared
afterward the A6 shape) plus one F-form arm (quarantine:560567,
the multi-grep pipeline capture), as "<helper> <file>:<line+7>
E-form arm (store-ack:733736, a $(count_lines) capture compared
afterward the A6 shape) plus one F-form arm (quarantine:560563,
the multi-grep pipeline capture), as "<helper> <file>:<line+3>
<form>". Both extras are asserted to exist in the artifact with
the expected form a renumber that moved them fails here, not
silently downstream.
@@ -34,8 +33,7 @@ Subcommands (all print sorted, stable output; non-zero exit on any failure):
sweep Residual sweep: the denominator's own classifier (ported from the
frozen derivation) over the ten suites at the current tree must
find ZERO unconverted verdict-form grep sites; and, IN THE SAME
RUN, eight specimens (six per-form + two absorb-branch probes, #985)
planted into a temp copy of a real
RUN, six per-form specimens planted into a temp copy of a real
suite must ALL be found with their correct forms an instrument
that reports zero must first be seen finding what it claims to
find (A5).
@@ -52,9 +50,7 @@ HERE = Path(__file__).resolve().parent
WAKE = HERE.parent
ART = HERE / "denominator-089615f.json"
HEADER_SHIFT = 7 # 3 converter header lines after SCRIPT_DIR + 4 lines from the
# #984 source guard (1-line `. _wake-common.sh && wake_assert_init` became a 5-line
# guarded block) — both uniform across all ten suites, both above every site.
HEADER_SHIFT = 3 # converter inserted 3 header lines after SCRIPT_DIR in every suite
# The two hand-picked extra arms (base coordinates; forms asserted at load).
EXTRA_ARMS = [
@@ -72,14 +68,10 @@ RX_ASSIGN_SUB = re.compile(r'=\s*"?\$\(.*grep')
RX_IF = re.compile(r"^\s*(el)?if\s+.*grep")
RX_GREP = re.compile(r"(^|[^A-Za-z0-9_.-])grep([^A-Za-z0-9_.-]|$)")
# grep in COMMAND position: at line start or after a command separator / subshell
# opener / shell keyword / `!`. Quote-unaware by design — a quoted "grep" after a
# separator reads as a command and lands the line in residual, which fails LOUD;
# the absorb direction (note) is the one that must never fire on a real verdict.
RX_GREP_CMD = re.compile(
r"(?:^|[;|&(`]|\$\(|\bif\b|\belif\b|\bthen\b|\belse\b|\bdo\b|\bwhile\b|\buntil\b|!)"
r"\s*grep(?:\s|$)"
)
def polarity(line):
m = RX_FAIL_SAME.search(line)
return "OR" if m.group(1) == "||" else "AND"
def classify(lines):
@@ -145,28 +137,6 @@ def classify(lines):
return sites, dispo
def residual_sites(lines):
"""classify() plus the absorb decision — the ONE path both sweep legs share.
A classified site is absorbed as a note only when its line carries a wake
helper token AND the line shows no grep in command position: a converted
line whose PATTERN argument merely contains the word grep. A helper line
that also runs a real grep verdict (has_match ... && grep -q SECRET ... &&
fail) stays residual (#985). Multi-line forms anchor the site at the line
containing grep, so a command-position grep on a continuation line never
shares its line with the helper token and stays residual by construction.
"""
sites, dispo = classify(lines)
residual, notes = [], []
for ln, form, text in sites:
line = lines[ln - 1]
if RX_HELPER.search(line) and not RX_GREP_CMD.search(line):
notes.append((ln, form, text))
else:
residual.append((ln, form, text))
return residual, notes, dispo
def load_art():
art = json.loads(ART.read_text())
assert art["total"] == 261 == len(art["rows"]), "artifact self-consistency"
@@ -229,20 +199,13 @@ def cmd_arms():
return 0
# (expected classify form, expected disposition through residual_sites, snippet)
PLANTS = [
("A-same-line", "residual", ['grep -q needle haystack || fail "plant-A"']),
("B-cont-operator", "residual", ["grep -q needle haystack ||", ' fail "plant-B"']),
("C-cont-backslash", "residual", ["grep -q needle \\", ' haystack || fail "plant-C"']),
("D-if-form", "residual", ["if ! grep -q needle haystack; then", ' fail "plant-D"', "fi"]),
("E-count-capture", "residual", ['[ "$(grep -c needle haystack)" = "1" ] || fail "plant-E"']),
("F-extract-capture", "residual", ['val="$(grep needle haystack)"']),
# G: a converted line that ALSO runs a raw grep verdict — the helper token
# must not absorb it (#985)
("A-same-line", "residual", ['has_match -q needle "$F" && grep -q SECRET "$F" && fail "plant-G"']),
# H: negative control — helper whose PATTERN argument is the word grep;
# must be absorbed as a note, never residual
("A-same-line", "note", ['has_match -q "grep" haystack || fail "plant-H"']),
("A-same-line", ['grep -q needle haystack || fail "plant-A"']),
("B-cont-operator", ["grep -q needle haystack ||", ' fail "plant-B"']),
("C-cont-backslash", ["grep -q needle \\", ' haystack || fail "plant-C"']),
("D-if-form", ["if ! grep -q needle haystack; then", ' fail "plant-D"', "fi"]),
("E-count-capture", ['[ "$(grep -c needle haystack)" = "1" ] || fail "plant-E"']),
("F-extract-capture", ['val="$(grep needle haystack)"']),
]
@@ -252,20 +215,22 @@ def cmd_sweep():
# leg 1: real suites at the current tree must be residual-free
for f in suite_files(art):
residual, notes, _dispo = residual_sites((WAKE / f).read_text().split("\n"))
for ln, form, text in notes:
# converted line whose PATTERN argument contains the word grep:
# not an unconverted site, but never silently absorbed either
print(f"SWEEP-NOTE {f}:{ln} converted line matches grep-token ({form}): {text[:80]}")
lines = (WAKE / f).read_text().split("\n")
sites, _dispo = classify(lines)
residual = []
for ln, form, text in sites:
if RX_HELPER.search(lines[ln - 1]):
# converted line whose PATTERN argument contains the word grep:
# not an unconverted site, but never silently absorbed either
print(f"SWEEP-NOTE {f}:{ln} converted line matches grep-token ({form}): {text[:80]}")
continue
residual.append((ln, form, text))
for ln, form, text in residual:
print(f"SWEEP-RESIDUAL {f}:{ln} {form}: {text[:100]}")
bad += 1
print(f"SWEEP {f}: {len(residual)} residual verdict site(s)")
# leg 2, SAME RUN, SAME PATH as leg 1: the instrument must find every plant
# with the right form AND the right absorb disposition — plants G/H exercise
# the absorb branch itself, so this leg must go through residual_sites(),
# not raw classify()
# leg 2, SAME RUN: the instrument must find six per-form plants
donor = suite_files(art)[0]
with tempfile.TemporaryDirectory() as td:
planted = Path(td) / donor
@@ -273,28 +238,25 @@ def cmd_sweep():
base_lines = planted.read_text().split("\n")
offset = len(base_lines)
expect = {}
for form, dispo, snippet in PLANTS:
expect[offset + 1] = (form, dispo) # first physical line of each plant
for form, snippet in PLANTS:
expect[offset + 1] = form # first physical line of each plant
base_lines.extend(snippet)
offset = len(base_lines)
planted.write_text("\n".join(base_lines))
residual, notes, _ = residual_sites(planted.read_text().split("\n"))
found = {ln: (form, "residual") for ln, form, _t in residual}
found.update({ln: (form, "note") for ln, form, _t in notes})
unexpected = [(ln, form) for ln, form, _t in residual if ln not in expect]
hits = sum(1 for ln, want in expect.items() if found.get(ln) == want)
n_plants = len(PLANTS)
print(f"SWEEP-PLANTS found={hits}/{n_plants} in planted copy of {donor}")
if hits != n_plants:
for ln, want in sorted(expect.items()):
got = found.get(ln, ("<missed>", "<missed>"))
if got != want:
print(f"SWEEP-PLANT-MISS line {ln}: expected {want}, got {got}")
sites, _ = classify(planted.read_text().split("\n"))
found = {ln: form for ln, form, _t in sites if ln in expect}
unexpected = [(ln, form) for ln, form, _t in sites if ln not in expect]
hits = sum(1 for ln, form in expect.items() if found.get(ln) == form)
print(f"SWEEP-PLANTS found={hits}/6 in planted copy of {donor}")
if hits != 6:
for ln, form in sorted(expect.items()):
got = found.get(ln, "<missed>")
if got != form:
print(f"SWEEP-PLANT-MISS line {ln}: expected {form}, got {got}")
bad += 1
if unexpected:
# the donor is a converted suite: any non-plant RESIDUAL site in the
# copy contradicts the zero leg 1 just reported on the original
# (non-plant notes mirror leg 1's treatment: printed there, not bad)
# the donor is a converted suite: any non-plant site the sweep finds
# in the copy contradicts the zero it just reported on the original
for ln, form in unexpected:
print(f"SWEEP-PLANT-UNEXPECTED {donor}(copy):{ln} {form}")
bad += 1
@@ -26,12 +26,12 @@
#
# Verified guard per site (line numbers at branch tip, +3 header shift):
count_lines test-wake-beacon.sh:354 — red-path summary; guard `[ -s "$FAILFILE" ]` at line 353; template execution measured by microtest C11; text verified by static inventory
count_lines test-wake-detector.sh:706 — red-path summary; guard `[ -s "$FAILFILE" ]` at line 705; template execution measured by microtest C11; text verified by static inventory
count_lines test-wake-digest-hmac.sh:438 — red-path summary; guard `[ -s "$FAILFILE" ]` at line 437; template execution measured by microtest C11; text verified by static inventory
count_lines test-wake-digest-quarantine.sh:588 — red-path summary; guard `[ -s "$FAILFILE" ]` at line 587; template execution measured by microtest C11; text verified by static inventory
count_lines test-wake-fn-oracle.sh:136 — red-path summary; guard `[ -s "$FAILFILE" ]` at line 135; template execution measured by microtest C11; text verified by static inventory
count_lines test-wake-install.sh:438 — red-path summary; guard `[ -s "$FAILFILE" ]` at line 437; template execution measured by microtest C11; text verified by static inventory
count_lines test-wake-reconcile.sh:393 — red-path summary; guard `[ -s "$FAILFILE" ]` at line 392; template execution measured by microtest C11; text verified by static inventory
count_lines test-wake-store-ack.sh:745 — red-path summary; guard `[ -s "$FAILFILE" ]` at line 744; template execution measured by microtest C11; text verified by static inventory
count_lines test-wake-store-enqueue-race.sh:212 — red-path summary (with "#927 TOCTOU reproduced (RED)" tail); guard `[ -s "$FAILFILE" ]` at line 211; template execution measured by microtest C11; text verified by static inventory
count_lines test-wake-beacon.sh:350 — red-path summary; guard `[ -s "$FAILFILE" ]` at line 349; template execution measured by microtest C11; text verified by static inventory
count_lines test-wake-detector.sh:702 — red-path summary; guard `[ -s "$FAILFILE" ]` at line 701; template execution measured by microtest C11; text verified by static inventory
count_lines test-wake-digest-hmac.sh:434 — red-path summary; guard `[ -s "$FAILFILE" ]` at line 433; template execution measured by microtest C11; text verified by static inventory
count_lines test-wake-digest-quarantine.sh:584 — red-path summary; guard `[ -s "$FAILFILE" ]` at line 583; template execution measured by microtest C11; text verified by static inventory
count_lines test-wake-fn-oracle.sh:132 — red-path summary; guard `[ -s "$FAILFILE" ]` at line 131; template execution measured by microtest C11; text verified by static inventory
count_lines test-wake-install.sh:434 — red-path summary; guard `[ -s "$FAILFILE" ]` at line 433; template execution measured by microtest C11; text verified by static inventory
count_lines test-wake-reconcile.sh:389 — red-path summary; guard `[ -s "$FAILFILE" ]` at line 388; template execution measured by microtest C11; text verified by static inventory
count_lines test-wake-store-ack.sh:741 — red-path summary; guard `[ -s "$FAILFILE" ]` at line 740; template execution measured by microtest C11; text verified by static inventory
count_lines test-wake-store-enqueue-race.sh:208 — red-path summary (with "#927 TOCTOU reproduced (RED)" tail); guard `[ -s "$FAILFILE" ]` at line 207; template execution measured by microtest C11; text verified by static inventory
@@ -4,8 +4,8 @@
#
# 0. instrument self-test (microtest) — no validate evidence is trusted
# before the instrument itself has been proven, including its abort arms.
# 1. expected set: 261 coordinates from the FROZEN artifact (+7 header
# shift: 3 converter lines + 4 #984 guard lines), count asserted against the number declared below BEFORE any
# 1. expected set: 261 coordinates from the FROZEN artifact (+3 header
# shift), count asserted against the number declared below BEFORE any
# suite runs.
# 2. static inventory: converted call sites re-derived from SOURCE TEXT,
# must equal the expected set exactly (amendment ONE, leg 1 — the
@@ -33,8 +33,7 @@
# site's ledger row must already be present (the append lands before the
# grep).
# 6. residual sweep: the denominator's own classifier finds zero unconverted
# verdict greps in the suites — and eight plants (six per-form + two
# absorb-branch probes, #985) in the same run.
# verdict greps in the suites — and six per-form plants in the same run.
#
# Output discipline (A10): every line that reports on a suite names the file
# under test; exit codes are reported before failure counts.
@@ -181,15 +180,8 @@ while read -r helper site form; do
bad="$bad no-ARMED-line"
printf '%s\n' "$out" | grep -q "WAKE-ASSERT ABORT: ${helper} at ${site}: grep exit" ||
bad="$bad no-ABORT-line"
# AND-polarity check (a match is the defect): a grep error (rc>=2) must be
# its own loud arm — it cannot fall through as "no sentinel = pass".
rc_sent=0
printf '%s\n' "$out" | grep -Eq "$(sentinel_for "$f")" || rc_sent=$?
case "$rc_sent" in
0) bad="$bad sentinel-emitted" ;;
1) : ;;
*) bad="$bad sentinel-grep-error-rc=$rc_sent" ;;
esac
printf '%s\n' "$out" | grep -Eq "$(sentinel_for "$f")" &&
bad="$bad sentinel-emitted"
grep -q "^${helper} ${site}\$" "$aled" ||
bad="$bad no-ledger-row"
if [ -z "$bad" ]; then
+1 -1
View File
@@ -25,7 +25,7 @@
"lint": "eslint src",
"typecheck": "tsc --noEmit",
"test": "vitest run --passWithNoTests && pnpm run test:framework-shell",
"test:framework-shell": "bash framework/tools/quality/scripts/check-test-enumeration.sh && bash framework/tools/quality/scripts/test-check-test-enumeration.sh && python3 src/lease-broker/daemon_deadline_unittest.py && python3 src/lease-broker/normative_fragments_unittest.py && python3 src/lease-broker/receipt_challenge_unittest.py && python3 src/lease-broker/context_recovery_unittest.py && python3 src/lease-broker/recovery_runtime_unittest.py && python3 src/lease-broker/recovery_b1_adversarial_unittest.py && python3 src/lease-broker/framework_skill_portability_unittest.py && python3 src/mutator-gate/runtime_tools_unittest.py && python3 src/mutator-gate/runtime_launch_guard_unittest.py && python3 src/mutator-gate/version_coupling_unittest.py && python3 framework/tools/lease-broker/check-runtime-launches.py --root ../.. && bash framework/tools/codex/test-pr-diff-context.sh && bash framework/tools/qa/test-deps-preflight.sh && bash framework/tools/git/test-pr-review-gitea-comment.sh && bash framework/tools/git/test-pr-review-repo-host-override.sh && bash framework/tools/git/test-ci-queue-wait-branch-absent.sh && bash framework/tools/git/test-git-credential-mosaic.sh && bash framework/tools/git/test-gitea-token-identity.sh && bash framework/tools/_scripts/test-install-ordering-guard.sh && bash framework/tools/tmux/agent-send.test.sh && bash framework/tools/wake/test-wake-store-ack.sh && bash framework/tools/wake/test-wake-store-enqueue-race.sh && bash framework/tools/wake/test-wake-digest-hmac.sh && bash framework/tools/wake/test-wake-digest-quarantine.sh && bash framework/tools/wake/test-wake-detector.sh && bash framework/tools/wake/test-wake-fn-oracle.sh && bash framework/tools/wake/test-wake-reconcile.sh && bash framework/tools/wake/test-wake-beacon.sh && bash framework/tools/wake/test-wake-preimage.sh && bash framework/tools/wake/test-wake-install.sh"
"test:framework-shell": "python3 src/lease-broker/daemon_deadline_unittest.py && python3 src/lease-broker/normative_fragments_unittest.py && python3 src/lease-broker/receipt_challenge_unittest.py && python3 src/lease-broker/context_recovery_unittest.py && python3 src/lease-broker/recovery_runtime_unittest.py && python3 src/lease-broker/recovery_b1_adversarial_unittest.py && python3 src/lease-broker/framework_skill_portability_unittest.py && python3 src/mutator-gate/runtime_tools_unittest.py && python3 src/mutator-gate/runtime_launch_guard_unittest.py && python3 src/mutator-gate/version_coupling_unittest.py && python3 framework/tools/lease-broker/check-runtime-launches.py --root ../.. && bash framework/tools/codex/test-pr-diff-context.sh && bash framework/tools/qa/test-deps-preflight.sh && bash framework/tools/git/test-pr-review-gitea-comment.sh && bash framework/tools/git/test-pr-review-repo-host-override.sh && bash framework/tools/git/test-ci-queue-wait-branch-absent.sh && bash framework/tools/git/test-git-credential-mosaic.sh && bash framework/tools/git/test-gitea-token-identity.sh && bash framework/tools/_scripts/test-install-ordering-guard.sh && bash framework/tools/tmux/agent-send.test.sh && bash framework/tools/wake/test-wake-store-ack.sh && bash framework/tools/wake/test-wake-store-enqueue-race.sh && bash framework/tools/wake/test-wake-digest-hmac.sh && bash framework/tools/wake/test-wake-digest-quarantine.sh && bash framework/tools/wake/test-wake-detector.sh && bash framework/tools/wake/test-wake-fn-oracle.sh && bash framework/tools/wake/test-wake-reconcile.sh && bash framework/tools/wake/test-wake-beacon.sh && bash framework/tools/wake/test-wake-preimage.sh && bash framework/tools/wake/test-wake-install.sh"
},
"dependencies": {
"@mosaicstack/brain": "workspace:*",