cmd/ao was deterministically RED under -shuffle (the order CI uses) from
process-global os.Chdir pollution. The local fast gate ran only *changed*
tests in -run isolation, so it structurally could not observe cross-test
pollution — red shipped to main across 281 commits. The membrane had a hole
in its own hull.
- migrate ~62 os.Chdir blocks in cli/cmd/ao + the internal/paths helper to
t.Chdir (auto-restores, refuses t.Parallel); -302 net lines of boilerplate
- KEYSTONE: orchestrate_test.go did a non-restoring os.Chdir to the repo root
— the actual deterministic shuffle leak the 62-block migration alone missed
- validate-go-fast.sh: force FULL-package + fixed -shuffle=1 for the
isolation-sensitive cli/cmd/ao package (was -run-subset blind to pollution)
- promote go.test-isolation ratchet to Fast tier (ran Full-only, so it never
fired pre-push) — aligns it with its home/test-home-isolation siblings
- lower BASELINE_CHDIR 137->7 (floor = intentional cwd-behavior tests)
- link behavior-first-planning.feature in its SKILL.md + mirror the codex twin
- fix(pawl gate): check-pawl-pre-push bead extraction swallowed a sentence-
ending period (bead ids allow '.' for sub-ids), hunting for "<id>..json" and
failing-closed on a normal commit message — strip trailing separators
cmd/ao now green under -race -shuffle=on. Closes age-cmd-ao-test-floor-hvb.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The remaining 6 of the original 14 ref-dropping pointers legitimately document
NON-Codex runtimes, so the "0 Claude mentions" twin rule was wrong for them
(scrubbing "Claude" would gut the content). Adds a shared exemption list,
scripts/lint/codex-cross-runtime-skills.txt, honored by the generator AND the
gates:
- codex-sync: for listed skills, apply only the slash->$ rewrite; preserve
runtime names/paths verbatim (Claude Code / ~/.claude stay accurate).
- validate-codex-runtime-sections: skip the no-Claude-mention scan for them.
- audit-codex-parity: skip CLAUDE_TOOL_NAMING for them.
Converts all 6 to self-contained (body + references now ship to Codex):
cass (parses Claude/Codex/Gemini logs), rch (Claude Code PreToolUse hook),
vibing-with-ntm (claude -p LAW-0 ban), agent-native (per-runtime paths),
cc-hooks (Claude Code hook system), agy-native (AGY/Gemini harness).
This completes age-8wm: all 14 pointer twins now self-contained. The 8 ordinary
ones convert clean (Codex-native); these 6 stay runtime-accurate via the
exemption. shellcheck clean; the 3 codex gates pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds --force to codex-sync (scoped regenerate of existing twins; refuses
unscoped to protect the curated set) and fixes two transform bugs found in
review: the slash->$ regex was corrupting markdown PATHS (../foo/ -> ..$foo/),
and only references/scripts were copied (missing fixtures/ etc., breaking body
links). Now mirrors ALL source content except SKILL.md; catalog entries are
add-only so curated reasons aren't clobbered.
Converted 8 pointer twins to self-contained (body transformed runtime-native +
full references/scripts/fixtures mirrored) so Codex users get the real content
(installs ship skills-codex/ only): agent-mail, beads-br, beads-bv,
beads-workflow, dcg, ntm, reverse-engineer, toil-mining.
The other 6 of the original 14 are NOT auto-convertible — their docs legitimately
reference Claude tools/runtime, which the repo's own gates reject in a Codex doc:
cass + rch (Claude tool-naming "the Read tool"/"Bash tool" in references, fails
audit-codex-parity); cc-hooks, vibing-with-ntm, agy-native, agent-native (claude
-p / "the Claude path" etc., fails validate-codex-runtime-sections). They need a
manual Claude-term scrub (or bespoke classification) — tracked on age-8wm.
regen-all --check GREEN; acceptance test 15/15; shellcheck -S warning clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Research (this session) established the runtime model: Codex installs ship
skills-codex/ ONLY (plugin.json "skills":"./skills-codex"; install-codex-plugin.sh
copies only skills-codex; install-codex.sh discards the source tarball). So a
pointer twin ("read skills/<name>/SKILL.md") dangles for real users — the twin
must be self-contained (AGENTS-CODEX.md).
codex-sync now generates a self-contained twin from source:
- SKILL.md = slim (name+description) frontmatter + source body transformed
runtime-native: /<known-skill> -> $<known-skill>, ~/.claude -> ~/.codex,
"Claude Code" -> "Codex".
- references/ + scripts/ copied byte-identical (lint scans only SKILL.md).
- Still missing-twin-only + idempotent; existing hand-tended twins untouched
(converting all ~75 is a separate reviewed step; the 14 ref-dropping pointer
twins tracked in age-8wm).
Acceptance test upgraded to assert self-containment: throwaway source skill WITH
a reference + transform cases -> twin carries body + reference, transforms
applied, content-divergence gate passes (15/15). shellcheck -S warning clean.
regen-all docs reconciled (pointer -> self-contained).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
scripts/codex-sync.sh authors the COMPLETE Codex twin for any source skill that
lacks one: a slim (name+description) frontmatter + a fixed pointer body naming
skills/<name>/SKILL.md as the source of truth, the prompt.md pointer template,
the per-skill marker, and all catalog surfaces, then fixes hashes. Because a
parity twin carries no source content beyond name+description, source body edits
never require a twin hand-edit — the divergence/parity/manifest/hash cascade that
made adding a skill cost ~5 serial codex-gate fixes is gone.
- Idempotent + append-only (no catalog re-sort → minimal diffs).
- bespoke twins are the opt-out: never generated or overwritten.
- Wired into regen-all.sh (generate step + --check drift step); stale
"twins are MANUAL" note replaced.
- tests/scripts/test-codex-sync-generator.sh: self-cleaning L2 acceptance —
throwaway source skill → generate → lint-clean, registered twin, gates pass,
zero hand-edits (10/10).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Every skill description now carries trigger markers (a Triggers: clause) so no skill
silently never-fires on the LLM router (rot had reached 68%). Hand-crafted triggers for
the 12 user-facing workflow skills (autodev, bootstrap, compile, crank, curate, discovery,
inject, orchestrate, release, rpi, using-atm, validate); description-derived for the long tail.
Add gate skill.triggers (scripts/validate-skill-triggers.sh -> scan_descriptions --strict;
blocking; Fast|Full; matches skills/**) so the rot cannot regrow. Closes defect 2 of
age-fix-skill-factory-mcc (defect 1 was a false alarm — the build-report schema exists).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
S3 of the standing pawl-service epic. route no longer dies on a flaky codex send (cod_send:
send + verify engagement via atm codex wait-goal-engaged, retry 3x, respawn on dead/usage-limit);
mid-route a degraded pane is respawned + re-routed ONCE so it cannot silently time out into a
false REFUTED. rotate_account opt-in (PAWL_AUTO_ROTATE; caam/claude-acct per TOOLS-TRUTH), guarded
with || true at call sites (it returns non-zero by design when not opted in; under set -e an
unprotected non-zero would abort the route).
Liveness (cod_dead) uses the DETERMINISTIC foreground-process signal (tmux pane_current_command:
shell => dead, codex binary => alive), NOT scraped scrollback text — text-scraping yielded a series
of false-alives (stale codex chrome above a shell prompt; a cwd path containing gpt-5) the pawl
refuter demonstrated across rounds. A source guard makes the helpers unit-testable;
tests/scripts/pawl-cod-dead.bats (7 cases) locks the classification + the rotate_account guard
contract. PROVEN LIVE: routes recovered from an injected shell-drop and a real usage-limit via
respawn+reroute. Timeout 200->320s. The pawl caught 3 real bugs here (false-dead, set-e abort,
text false-alive) — the gate working, not rubber-stamping.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
S4 of the standing pawl-service epic. Removes the manual edge-commit dance behind a verdict-bound
push to main. Root cause (analysed, not assumed): the pre-push pawl gate checks ONLY
verdict.head_sha == the pushed head (stable local_sha); emit-verdict is idempotent and the ledger
edge need NOT be committed for the gate. A push fails iff the verdict points at a different commit
than HEAD — i.e. HEAD drifted since the review (a prior post-land-provenance-emit commit, or a
re-commit after routing). Committing the edge has NO fixed point (rebinding to the new head emits a
fresh edge → re-dirties forever), so the deterministic fix is to rebind the already-reviewed verdict
onto the exact pushed HEAD:
- pawl-verdict.sh rebind <bead> <pr> --head SHA — re-stamp head on a CONFIRMED verdict (refuters
preserved, sensor re-fired); fail-closed on missing/non-CONFIRMED.
- scripts/pawl-land.sh <bead> [pr] — assert HEAD cites the bead, rebind verdict to HEAD, single push.
The ledger edge is left to post-land-provenance-emit (idempotent, trunk-bound); its working-tree churn
is absorbed by rebase.autoStash (age-uqj). Regression tests added (rebind re-stamps + preserves +
re-fires; refuses non-CONFIRMED/missing).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Encodes the manual opus+codex duel (dogfooded landing age-1vy + age-uqj) into a deterministic
lifecycle so the cross-family pawl is a SERVICE you route to, not a hand-spun codex-exec per bead:
pawl up spawn + readiness-gate the standing opus+codex session (idempotent; solves the boot race)
pawl health per-pane liveness/readiness probe
pawl route send a packet to BOTH panes via FILE REFERENCE (codex /goal 4000-char limit), poll for a
per-route NONCE-tagged verdict, require BOTH CONFIRMED (fail-closed), record via pawl-verdict.sh
pawl down tear down, no orphan panes
Substantially delivers slices S1 (up/down) + S2 (route) + the health half of S3; ao pawl will wrap this
(CLI-for-deterministic). Self-validated: routed its OWN review through itself — opus + codex/gpt-5.5 both
CONFIRMED after the dogfood caught two real bugs first (stale-scrollback verdict capture -> per-route nonce;
set -euo pipefail aborting the poll on an empty grep -> verdict_of always returns 0).
Pawl: opus + codex both CONFIRMED via the standing pawl-service (self-review, multi-model).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Tracked runtime audit logs (.agents/rpi/next-work.jsonl, .agents/findings/registry.jsonl,
docs/provenance/ledger.jsonl) get dirtied by tooling mid-session, so 'git pull --rebase'
repeatedly failed with 'unstaged changes' (and a stash-pop once left conflict markers in
the hash-chained ledger). Fix: install-pre-push-gate.sh (the fresh-clone setup) now sets
repo-local rebase.autoStash=true so rebase transparently stash+reapplies the dirty tree.
.gitattributes documents WHY these JSONL logs are deliberately NOT union-merged — next-work
is rewritten in place (markEntryConsumed/markItemConsumedOwned) and the ledger is a prev_hash
chain, so union would resurrect consumed work or break the chain; a real divergence must
surface as a conflict. Ledger emit/commit churn is tracked separately (age-standing-pawl-service-ml8.4).
Pawl: opus + codex/gpt-5.5 both CONFIRMED (v3) via the standing pawl-service. The pawl caught
two real defects across rounds — union-on-a-mutated-file (codex) and a stale union reference in
the installer comment (opus) — both fixed before CONFIRMED.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The rework dynamo-e2e demonstrated L>0 via an EXPLICIT phase=rework row — the
attempt-ordering rework join (the actual cleverness, where attempt-1 spend before
the accepting attempt is classified rework by usageAttempt) never fired. Worse,
the scenario's attempt-1 700-token spend was emitted AFTER its own REFUTE verdict,
so usageAttempt attributed it FORWARD to attempt-2 and it read Productive. The
e2e proved a phase label works, not the ordering mechanism.
- New `rework-order` scenario: attempt-1 production is emitted BEFORE its verdict
(realistic order), so the 700-token spend maps to attempt-1 (< accepting
attempt-2) and is classified rework SOLELY by the ordering join — no phase
label anywhere. Verified live: L breakdown rework=700 productive=500, L=0.583.
- Tightened bats: asserts rework=700 / productive=500 (the ordering join fired).
- Fixed the existing `rework` scenario's comment to be honest — its loss is the
phase=rework label (rework=500); its attempt-1 700 spend reads Productive
(post-verdict emit order attributes it forward). Both paths now have coverage.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Decision (age-les) + fix: multi-model is STRICTLY STRONGER than fresh-context,
not a swap. The fresh-context floor (≥1 refuter whose context_id !=
author_context_id) is the foundational independence property — it catches the
DOMINANT failure, a worker rubber-stamping its own work because it shares the
author's context. multi-model ADDS ≥2-family diversity ON TOP; it must not waive
the floor.
Before: scripts/pawl-verdict.sh checked ONLY ≥2 families in multi-model mode, so
a verdict with two distinct families whose refuters BOTH ran in the author's
context authorized the merge (exit 0) — a self-approval bypass (family-diverse,
zero context-independence). This is within the gate's own threat model (a sloppy
agent opting up to multi-model and self-approving with two in-context models).
This aligns the code with the contract's own intent: pawls.md already said
multi-model catches "the above PLUS a single model's blind spots" — "the above"
being the fresh-context catch. The "only the diversity requirement changes with
mode" line was the mismatch; corrected here.
- pawl-verdict.sh: fresh-context floor moved OUT of the mode case, enforced
UNCONDITIONALLY; multi-model branch only adds the family check.
- reconcile-pr.bats: new case — multi-model, 2 families, both in author's context
→ HOLD exit 5. Existing multi-model-distinct-context case still merges.
- pawls.md: corrected the swap→strictly-stronger framing in 3 places.
Verified: shellcheck clean; reconcile-pr.bats 30/30; pawl suite 43/43.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The in-situ catch-rate gauge (age-t3f) only counted the cross-family
refuter/merge tier (reconcile-pr.sh auto-emits); deterministic pre-push gate
FAILs — real false-done catches — were dropped, so the gauge UNDERCOUNTS.
- scripts/emit-deterministic-catch.sh: fail-open, skippable emit of a REFUTED
gate-verdict (mode=deterministic, cross_family=false) mirroring the PASS-branch
SENSOR feed (emit-landed-provenance.sh). One emit per blocked push attempt —
the genuine claimed-done door — not per local `ao gate check` iteration.
- scripts/hooks/pre-push.local: FAIL-branch hook, symmetric to the PASS feed;
never changes gate_status.
- yieldledger: ModeDeterministic as a first-class diversity mode so the tier is
valid + queryable; it raises catch_rate WITHOUT touching catch_rate_cross_family.
L2 bats proves end-to-end: emit -> `ao yield gauge` counts catch_rate=1 for the
deterministic-pre-push run. Note: catch_rate is run-scoped; deterministic catches
land under run `deterministic-pre-push` (override via AO_YIELD_RUN_ID to attribute
to a session's run). Honest completion of the in-situ instrument; it grows the
real measurement window. Does NOT prove the self-improving loop (age-1gl, blocked
on a real escape).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The membrane on the control-plane docs (hardening #6 of the 2026-06-17
--mixed pass). check-control-plane-taxonomy.sh asserts: (C1) no live doc
rebinds the etcd-analog to retired bd/Dolt; (C2) the agent two-altitude note
is present in both the-agent-factory.md and ports-and-adapters.md whenever the
agent is classified both ways; (C3) the adapter-taxonomy section exists and
the unifying-entry cross-links resolve bidirectionally. Registered as
docs.control-plane-taxonomy (Fast|Full, blocking). 7 bats cases incl. 4
negatives proving the gate bites.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add --control-only for applied-OOD ceiling checks, CI validate headroom hook, and workflow coverage wiring so ceiling violations fail before live campaign spend.
Co-authored-by: Cursor <cursoragent@cursor.com>
Completes the staleness epic. 42 P2/P3 files converged to current truth
(bd→br, gascity/gt-sling/mayor→NTM+Agent Mail, daemon→substrate, hooks→hookless,
CI-authoritative→push-to-main local Go gate); GLOSSARY's 18 dead skills/* links
repaired to ../skills/<name>/SKILL.md (19 links, 0 broken); contracts/runbooks
that freeze retired-system nouns bannered RETIRED/HISTORICAL rather than rewritten.
Adds the Arc-7 ratchet — scripts/check-docs-no-retired-tech.sh — which scans all
live docs (260) for retired-subsystem commands/phrases and fails on regression.
A doc opts out by carrying a RETIRED/HISTORICAL/SUPERSEDED banner (or being an
ADR / migration / upgrade / index doc), and lines that describe a removal are not
flagged. Running it caught 12 stale refs the deep-read sweep missed — a
"CI is the authoritative gate" cluster (agentops-brief, primitive-chains,
INCIDENT-RUNBOOK, knowledge-flywheel, philosophy, software-factory), stale
hook-smoke in release-e2e-checklist, and GasCity descriptors in
contracts/index + SCHEMAS + strategic-direction — now fixed. Gate: PASS.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Run check-pawl-pre-push.sh after ao gate check on main pushes; allow pr=0
verdicts for push-to-main landings per goal-context default.
Co-authored-by: Cursor <cursoragent@cursor.com>
Bind disposition/mode/verdict before index() so minimal hosts without
jsonschema still accept valid CONFIRMED verdicts; add bats with validators shadowed.
Co-authored-by: Cursor <cursoragent@cursor.com>
Salvaged the uncommitted work from wt-ag-ez7y6 and completed the 4->2 beads
skill consolidation the salvaged test asserts:
- Fold the "Issue-Lifecycle Discipline" doctrine (live-reads-authoritative,
scoped-closure-proof, parent-reconciliation, narrow-the-umbrella-issue,
normalize-stale-queue) from the retired `beads` umbrella into beads-br.
- Retire skills/beads --into beads-br via `ao skills retire` (trees removed,
ledger row moved to historical: merged-into beads-br).
- Re-target every retired-skill reference: crank/implement/plan/post-mortem/
refactor frontmatter+deps, SKILL-TIERS rows, docs/SKILLS.md, GLOSSARY link,
sku_catalog LOOP_MOVES[2], image manifests (counts adjusted).
- Codex twin: mirror the doctrine into skills-codex/beads-br, prune `beads` from
the codex catalog/manifest, regen hashes (parity gate age-yxl).
- Add cli/cmd/ao/beads_consolidation_test.go (L2 structural invariants). Uses a
leak-proof repo-root finder (skills/+docs/contracts/) because the shared
findRepoRoot keys on .agents/, which the cmd/ao suite leaks into the pkg dir.
Fixed an ao-skills-retire bug surfaced here: the historical row was appended at
the end of the `workflows:` section (between historical: and dispositions:)
instead of inside historical:. Corrected manually; full fix tracked separately.
Bounded-context: BC3-Loop
Evidence: cli/cmd/ao/beads_consolidation_test.go
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The terminal integration. scripts/epic-d16-donetest.sh composes the five landed
organs (M1 sensor, M2 recovery, M3 binding verdict, M4 ASSAY, M5 guard) into one
closed loop and asserts the mechanical done-test (plan §48-55):
seed -> no-human boundary -> injected failure -> recovery branch fires ->
accepted ONLY via a fresh-context verdict (self-approval refused) ->
ASSAY mines a follow-up bead -> evidence artifact lists every path.
Runs over the REAL organs in an isolated, self-contained temp root (its own
docs/+schemas/+_beads), so it is repeatable and NEVER pollutes the real _beads /
provenance ledger (asserted byte-for-byte). A deterministic composition, not a
multi-hour live coding worker; the live codex worker is the production demo.
A proven run: seed ag-odq -> rescope recovery ag-cyt (seed not closed) ->
fresh-context verdict authorizes + lands in the isolated ledger; self-approval
(refuter==author) REFUSED -> ASSAY mines ag-k9p. result:PASS.
A fresh-context refuter CONFIRMED the PASS is genuine: step 4b refuses for
exactly the fresh-context-floor reason (the authorizing vs self-approval verdict
files differ only in refuter context_id), ledger isolation is MD5-identical
before/after, no step silently no-ops, deterministic across 3 runs.
Re-anchored on real interfaces: ao provenance emit-verdict resolves the ledger
by cwd (no env override) and pawl-verdict.sh write emits internally, so every
write/emit runs cwd=WORKDIR; pawl schema requires pr>=1; isolated store uses
prefix ag so the verdict bead id is mined by M4.
Closes-scenario: age-d16-self-hosting-route-nkr#epic-donetest
Bounded-context: BC3-Loop
Evidence: docs/evidence/age-d16-epic-donetest.md
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The M5 organ. A kind-unified, added-only, FAIL-CLOSED admission guard:
scripts/check-frontdoor-admission.sh blocks a newly-ADDED skill/workflow/loop
from merging unless its front-door evidence shows all three facts — bounded-
context found (BC1..6) + role assigned (hexagonal_role) + a runnable acceptance
(references/<name>.feature or a ## Scenarios block with steps). Evidence is read
from committed sources (domain map, SKILL.md frontmatter, the workflows ledger);
existing units are never re-judged (added-only), so routine edits aren't blocked.
Enforcement at TWO points (intake.sh stays the advisory early-warning):
- pre-push gate: new blocking gate governance.frontdoor-admission (seed.go),
matching skills/** + .claude/workflows/** — fires when a unit is added.
- the named door: reconcile-pr.sh runs the guard after the pawl verdict and
before merge; an under-governed unit yields ADMISSION-HOLD (no merge/close).
A fresh-context refuter caught THREE fail-OPEN holes (each would admit an
under-governed unit), all fixed + regression-locked: (1) the git fallback
silently degraded to HEAD~1 when origin/main was unresolvable -> now fail-closed
on an undetermined diff; (2) a non-BC workflow domain satisfied "BC found" ->
now requires BC[1-6]; (3) an empty .feature satisfied acceptance -> now requires
a runnable scenario. A 4th (inline-comment leak in the ledger parser, introduced
by fix#2) was caught on re-refute and fixed. 15 fail-closed bats green.
Closes-scenario: age-d16-self-hosting-route-nkr.6#frontdoor-admission
Bounded-context: BC4-Factory
Evidence: docs/evidence/age-d16-6-frontdoor-guard.md
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Keystone of the workflow-guardrail-hooks epic. A PreToolUse Edit|Write guard
that routes an edit of an installed skill copy (*/.claude/skills/**, .codex,
.gemini) back to the repo source of truth skills/<name>/. A true mistake-token:
editing an installed/symlinked copy has no legitimate form. Matches
tool_input.file_path only (zero false-positive surface); reversible -> ROUTE
(exit 2 + one-line redirect), not hard-block; SILENT on the happy path; fires
once per session. Ships INERT with an opt-in installer; AgentOps 3.0 hookless
default unchanged.
- skills/cc-hooks/hooks/installed-skill-edit-guard.sh — the guard
- scripts/install-installed-skill-edit-guard.sh — opt-in installer (idempotent jq merge)
- tests/scripts/installed-skill-edit-guard.bats — FIRE/SILENT/false-positive/once-per-session (round-trips real PreToolUse JSON)
- skills/cc-hooks/references/INSTALLED-SKILL-EDIT-GUARD.md + SKILL.md wiring
Closes-scenario: age-workflow-guardrail-hooks-j39.1#installed-skill-edit-guard
Bounded-context: BC6-Orchestration
Evidence: tests/scripts/installed-skill-edit-guard.bats
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The M4 organ. A BOUNDED pure-shell tick that mines a completed run's evidence
from docs/provenance/ledger.jsonl (SENSOR), derives suggestions over EXISTING
miners (default: a built-in ledger assay; --mine-cmd swaps in ao harvest/curate
without rebuilding them) (ASSAY), and files each suggestion as a follow-up bead
through the front door via `br create` (GATE) — unattended.
Mirrors scripts/recovery-statemachine.sh (M2) discipline; crisp terminal
invariants asserted by failure-injection bats (15 cases, br + miner stubbed):
- NO daemon / NO spin: single pass over a bounded window; --window caps the
SENSOR, --max-suggestions caps the GATE. One terminal JSON verdict per run.
- NO silent defer: every path emits a verdict; a non-zero --mine-cmd, default
assay, or `br create` ESCALATES loudly (exit 4), never a set -e abort.
- NO mis-close: the tick NEVER closes a bead — close authority stays at the
merge/pawl door (reconcile-pr.sh, M3).
Two degraded-path silent-failure holes were caught by a fresh-context refuter
(both the M2 fail-open class) and fixed + regression-locked: (1) an unguarded
default-assay substitution that aborted under set -e with no verdict when
reverse() failed on a tac-less / tail-r-less host — fixed with a portable
always-exit-0 reverser + an if-guard escalation; (2) a printf '%s' (no trailing
newline) reverse-glue that silently dropped a distinct bead at
--max-suggestions >=2 — fixed with printf '%s\n'.
Reuse, don't rebuild: no dream/harvest invention, no flywheel/gold/corpus-
PROMOTE (Mossy's lane), no unbounded/daemonized mining.
Closes-scenario: age-d16-self-hosting-route-nkr.5#assay-tick
Bounded-context: BC1-Corpus
Evidence: docs/evidence/age-d16-5-assay-tick.md
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Port the Claude-only ship-beads.js fix-forward policy (poll -> flake-rerun
[budget 1] -> fix-forward -> terminal) into the bo-mac Codex/local runtime as a
pure-shell state machine, and add the two missing branches: re-scope-as-new-
acceptance and andon. Replaces the silent-defer (|| echo "failed") that
run-rpi-phases.sh does on failure today.
Crisp terminal invariants (asserted by failure-injection bats):
- no spin: fix-forward bounded by FIX_FORWARD_BUDGET=1, then forced escalation
- no silent defer: every path emits one terminal verdict + one bead mutation
- no mis-close: recovery NEVER closes the bead (the merge/pawl door's authority)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PILOT attempt 2 was a rate-limited burst (30 calls in 2.3min) yet recorded as an honest
off=0/3 on=0/3 null because the ContextDeltaScorecard read only .pass and discarded the
runner's degraded flag. Now:
- --timeout <secs> passes through to the default runner (drops the wrapper hack; live codex
gets a real timeout instead of the 120s default)
- run_arm counts degraded seeds (runner .degraded) per arm
- scorecard carries degraded (bool), delta_valid (=!degraded), per-arm degraded_seeds +
status="degraded", and elapsed_seconds (wall-time sanity — an impossibly-fast run is
self-evident)
- evidence_kind = live_agent (default runner) vs harness_plumbing (stub) — folds age-jxq
- bats: degraded-seed-flags-run + clean-run-delta_valid (13/13)
A degraded/rate-limited/timed-out run can no longer masquerade as a null.
Bead: age-t8n (unblocks readable RULER PILOT age-d16-self-hosting-route-nkr.2)
Evidence: .agents/evals/runs/pilot2-20260616T203331Z/PILOT-VERDICT.md
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Align br-first tracker truth, RPI terminology, stale architecture surfaces,
new drift gates, gate deferral drain (13→11), and audit artifacts so agents
and operators share one hookless map with mechanical acceptance.
Co-authored-by: Cursor <cursoragent@cursor.com>
The corpus-delta sandbox isolates HOME and copied only .claude; codex auth lives in
~/.codex, so codex failed 401 Unauthorized on every seed in BOTH arms — a DEGRADED run
(PILOT attempt 1: all 5 frozen tasks off=0/3 on=0/3). Carry codex CREDENTIALS
(auth.json + config.toml + config.json) into each sandbox HOME's .codex in BOTH arms
(auth is runtime, never corpus context; sessions/history NOT copied) via
CORPUS_DELTA_CODEX_HOME (default ~/.codex).
Verified: real codex via the fixed harness on cd-beads-1 → context_off 0/1 (fail),
context_on 1/1 (pass), delta +1 — first non-stub, non-degraded corpus-delta datapoint.
bats: codex-auth-carried-into-both-arms (11/11 green).
Bead: age-94f (blocks RULER age-d16-self-hosting-route-nkr.2)
Evidence: .agents/evals/runs/pilot-20260616T201843Z/PILOT-VERDICT.md
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The live eval harness never ran the agent. eval-agent-harness.sh runs each task in
a fresh non-git mktemp dir; modern `codex exec` refuses to launch there ("Not
inside a trusted directory and --skip-git-repo-check was not specified", exit 1)
and the harness swallowed it (`>/dev/null 2>&1 || true`). Net: codex never
executed, wrote nothing, and every cd-* task scored 0 in BOTH arms — the n=1 PILOT
"floor" was launch failure, not timeout/capability.
- add --skip-git-repo-check to both codex exec call sites
- stop swallowing the agent exit; surface a non-zero exit as degraded:true +
agent_exit:N (distinguishes a launch/timeout failure from an honest grader-fail),
happy path output unchanged
- bats: degraded-on-nonzero-exit + no-marker-on-clean-exit
Verified end-to-end: real codex via the fixed harness on cd-door9-1 →
{"score":3,"total":3,"pass":true}, deliverable written, EXIT=0.
Bead: age-o9x (blocks RULER age-d16-self-hosting-route-nkr.2)
Evidence: docs/evals/2026-06-16-eval-orchestration-decision.md
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
age-yxl gated source references/** divergence but left SKILL.md-body divergence
ungated (the residual it filed). Same silent-staleness: a source SKILL.md body
edit with a stale twin is masked by a regen hash bump.
validate-codex-generated-artifacts.sh now requires a real non-marker twin
content change when a source SKILL.md *body* changed — scoped to the BODY on
purpose: frontmatter-only edits (hex-wiring fields the twin never carries:
consumes/produces/hexagonal_role/context_rel) need no twin change and stay green,
so legit hex-wiring pushes don't red main. Body-vs-frontmatter is detected by
comparing the frontmatter-stripped body across the scope's base ref
(head: HEAD~1..HEAD; worktree: HEAD..working; staged/upstream handled);
conservative — any ambiguity (new file, unresolved base) requires the twin.
TEST: 3 new cases — body divergence FAILs under both worktree and head scopes,
frontmatter-only change PASSes. Verified both FAIL tests fail against the
unfixed gate (guard the regression). Real-skill smoke: frontmatter-strip yields
the correct body on discovery/rpi/skill-builder.
Closes-scenario: age-j1g#skillmd-body-gate
Bounded-context: BC2-Skills
Evidence: tests/scripts/test-codex-generated-artifacts.sh
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PROBE (evidence, not inspection): built the post-mortem divergent state in a
worktree — edited skills/discovery/references/dag.md, ran regen-codex-hashes
(twin left stale), committed, ran both gates. check-codex-parity-drift.sh and
validate-codex-generated-artifacts.sh BOTH passed (exit 0). The audit is a
Claude-ism scanner that never reads source; the structural source->codex check
was satisfied by the regen marker bump alone (a counterfactual source-only
commit with zero codex files DID fail, proving the mechanism). Verdict: the
gate does NOT catch content divergence.
FIX (routed to the gate, per the verdict): validate-codex-generated-artifacts.sh
now requires a REAL twin content change to mirror a source references/** edit —
the generated .agentops-generated.json / .agentops-manifest.json bookkeeping no
longer satisfies the mirror requirement. Scoped to references/** (mirrored
near-verbatim) to avoid false-positiving the legit frontmatter-only/hex-wiring
flow that has no twin equivalent.
TEST: two new cases in test-codex-generated-artifacts.sh — divergence (regen
hash bump only) FAILs, mirrored edit PASSes. Verified the divergence test FAILs
against the unfixed gate (guards the regression) and PASSes against the fix.
DOCS: skill-builder/SKILL.md, AGENTS-CODEX.md, CLAUDE.md registry section now
state that editing an EXISTING skill needs a manual twin mirror (regen refreshes
hashes, not prose) — prior docs only warned about NEW skills. Dogfooded: this
commit's skill-builder edit is mirrored into its codex twin.
Closes-scenario: age-yxl#probe-and-gate-fix
Bounded-context: BC2-Skills
Evidence: .agents/learnings/2026-06-16-codex-twin-content-not-auto-mirrored.md
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
check-skill-isolation.sh used GNU-awk 3-arg match(line, /re/, m), which BSD/macOS
awk rejects — the awk errored but the script still printed PASS: a FALSE GREEN on
the dev platform (agents believed isolation was enforced when it wasn't).
- Rewrite the matcher to POSIX awk so it runs correctly on macOS (BSD awk) and
Linux CI (gawk) alike; awk-dialect failure now hard-fails, never silent-PASS.
- Wire as gate `skill.isolation` (Fast|Full, Blocking: false — warn-first, so a
future violation flood reports without walling the repo). Flywheel/gold/wiki/
corpus stay out of scope (Mossy's lane).
- bats (tests/scripts/check-skill-isolation.bats): asserts no awk error, self-test
passes, and a real compression pattern is caught.
Current skills/ tree: 0 violations (the gate now genuinely runs). Enforces the
strict-delegation contract that operating-loop principle 8 (single-agent-first)
relies on. gates + gates/checks Go suites green; shellcheck clean.
Closes-scenario: ag-skill-isolation-ci-gate-jxpbx#isolation-gate
Bounded-context: BC4-Factory
Evidence: tests/scripts/check-skill-isolation.bats
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Satisfies the derived.changed-scope pre-push gate: regenerates cli-surface
docs + the command-surface eval matrix/smoke fixture, and allowlists 'wiki
gold' as public-stateful-fixture-needed (siblings wiki inject/query use the
same category; compiler logic is covered by cli/internal/wiki/gold_test.go).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds scripts/intake.sh — the minimal operating model's missing front-door
primitive: require a done-test (no destination, no start), trip the basement
alarm at >2 prerequisite layers, and triage blast-radius -> CHAOS (solo) vs
PAWL (summon the cross-family Navi). Advisory triage, not enforcement: the
doors (reconcile-pr.sh + dcg) are the un-leakable gates.
Generalizes docs/contracts/pawls.md from a static list to the blast-radius
rule (mutates shared state | changes enforcement logic | external effect |
hard rollback = pawl); the list becomes examples.
tests/scripts/intake.bats: 23 cases (fuses, both classes, omission +
false-positive guards, record uniqueness). shellcheck clean.
Gated cross-family: 3 Codex-Navi pawl rounds (each caught real defects the
green tests missed; all resolved), human-adjudicated the advisory-triage scope
at the circuit breaker, final merge receipt CONFIRMED.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Guard fails the build if the wake bridge is wired into any always-on launcher (systemd/launchd/cron/loop/watch/nohup/pm2/supervisor) until ag-egpu ratifies a watch surface; finite on-demand loops pass. Wired into CI via repo-root bats case. Cross-family gate PASS (codex gpt-5.5). 18 bats, shellcheck clean.
Closes: ag-cjruu
Navi review caught a fail-OPEN hole: when the authoritative base (origin/main) is
unavailable, the guard fell back to HEAD~1..HEAD — a narrow window that misses a
forbidden path introduced in an EARLIER unpushed commit still present in HEAD.
Fix: missing base now scans HEAD's FULL TREE (every path that would be pushed),
never HEAD~1. Regression bats added (missing base + earlier forbidden commit).
Closes-scenario: ag-ao0eo#fail-closed-missing-base
Bounded-context: BC5-Runtime
Evidence: tests/scripts/check-corpus-path-guard.bats
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Dynamo e2e E2 (self-excitation readout). The e2e now wires C both ways: --c-delta
<float> (a PUBLISHED corpus delta from ag-8p8o/W1c) populates C in the gauge
readout; omitted -> C reports pending, NEVER a fabricated value. Asserts the
honesty (pending without, value with) + validates --c-delta is numeric. Completes
the self-excitation organ's readout wiring; the real VALUE stays gated on the W1c
run (ag-epgk + blockers). +1 bats = 4 total. shellcheck clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
B2 of the 2026-06-15 council judgment (operability lane). Bo's ask: 'additional
models as the second poll... works from codec-specific and cloud-specific.'
The default pawl poll is a single fresh-context refuter (model-agnostic). The
opt-in second poll adds a different model FAMILY — today a manual multi-step in
the pre-land-refuters skill. second-poll.sh collapses the cross-family half into
ONE command from any shell: runs the gpt-family (codex exec --sandbox read-only)
refuter, parses its verdict, captures real evidence, and emits a ready-to-run
'pawl-verdict.sh write --mode multi-model' with the Claude-family refuter left as
a clear placeholder for the in-session subagent.
DISJOINT by construction: CONSUMES the stable pawl-verdict.sh write CLI; does NOT
modify the pawl mechanism or any membrane file (no collision with mossylantern's
docs/schema/eval membrane work). Cross-runtime: it's a shell script.
Safety: a REFUTED second family is surfaced + exit 1 (never emits CONFIRMED);
codex-unavailable fails loud (exit 2) rather than silently degrading to a fake
single-family multi-model verdict; --write refuses a half-filled verdict.
Tests: 6 bats (confirmed/refuted/unknown/unavailable/half-write/evidence) green;
shellcheck clean. Smoked against LIVE codex exec (v0.139.0, gpt-5.5) end-to-end —
real refuter dispatched, verdict parsed, evidence written.
Discoverability pointer into pre-land-refuters = coordinated follow-up (seam-adjacent).
Closes-scenario: ag-mg757#second-poll-one-command
Bounded-context: BC5-runtime
Evidence: tests/scripts/second-poll.bats
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Dynamo e2e E3 (reconcile-by-rejection). Adds --scenario=clean|rework to the e2e
harness. rework runs the defining dynamo dynamic: gate REFUTED attempt-1 ->
reconcile (rework) -> CONFIRMED attempt-2 -> accept bound to attempt-2. Asserts
the gauges PENALIZE it honestly: Q=0 (reworked bead is NOT a clean first pass,
0/1 clean) AND L>0 (rework spend = loss, e.g. 0.417). Proves reject->rework->
accept closes e2e and the ratchet is measured, not just asserted. Still no LLM,
isolated ledger. +1 bats (rework) = 3 total. shellcheck clean.
An agile reconcile-by-rejection demo; the full control-plane controller is ag-v1xk
(blocked on ag-egpu). This shows the reject/rework half of the loop runs today.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Dynamo e2e E1 (epic ag-13osz). scripts/dynamo-e2e.sh runs ONE full cycle on a
synthetic bead with a deterministic stub worker (NO LLM, no compute, no network):
dispatch -> gate (cross-family CONFIRMED, author!=judge, fresh-context) -> accept
-> usage -> ao yield gauge (real A/Q/A-R/E/L) -> C status (pending, never faked) ->
shadow-tune readout. Wires the REAL yieldledger organs (emit+gauge); runs in an
isolated temp project dir (never touches the real ledger). Proves the loop CLOSED
by flowed values (A>=1, R>0 reached the sensor), not just label presence.
+2 bats (loop-closes + teeth: empty-emit fails). shellcheck clean.
Real-organ gaps tracked: controller ag-v1xk (blocked ag-egpu), C via ag-8p8o W1c,
auto-tune ag-qpg99. This is the integration thread they plug into.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Slice 3 of ag-tixgy (the gateway was built+live but nothing passed the flags).
Re-anchored (council): only using-atm uses 'atm spawn' — crank/swarm spawn via
runtime-native subagents (different coord model), and ship-beads/SKILL.md does
not exist. So the honest rollout is using-atm + a coverage check, NOT a 3-skill
sweep, and it touches NO shared surfaces (spawn.go, yieldledger, SYSTEM.md).
- using-atm SKILL.md: the canonical spawn is now 'atm spawn --reserve <scope>'
(born into coordination), with a note that bare spawn leaves workers
uncoordinated and a pointer to the coverage check.
- scripts/check-spawn-reservation-coverage.sh: flags atm-registered workers that
are recently-active but hold NO reservation (the uncoordinated-worker drift).
Warn-only by default, --strict to fail, skips cleanly when AM/jq absent,
recency-filtered so dead historical agents aren't flagged. Fixture-injectable
(AGENTS_JSON/RESERVATIONS_JSON) for testing.
Tests: 6 bats cases (warn/strict/pass/all-uncoordinated/skip/stale) green;
shellcheck clean. Smoke against live AM correctly reports 'nothing live to check'
(the fleet is down) — confirming the recency filter + skip path on real data.
The deeper headless codex-exec prompt-injection gap (rpi runtime exec sites) is
a SEPARATE follow-up, not this bead.
Closes-scenario: ag-xe6u5#rollout
Bounded-context: BC5-runtime
Evidence: tests/scripts/check-spawn-reservation-coverage.bats
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
W1c blocker (pre-mortem #3): the default runner did mktemp -d, ignoring the
harness-exported CORPUS_DELTA_WORKSPACE — so the agent ran OUTSIDE the per-arm
isolation sandbox (ag-5apc proof was stub-only). Now:
- use the caller's sandbox when provided (else mktemp);
- rm ONLY a runner-created workspace, never a caller-provided one;
- EXIT trap cleans the runner-created workspace even when setup.sh/score.sh
fails under set -e (codex review: failure-path leak);
- WORKBENCH overridable via EVAL_WORKBENCH for testing.
3 bats (honor / fallback-cleanup / abort-cleanup, no LLM via fake codex + empty
TMPDIR) + harness 10/10, shellcheck clean.
NOTE: codex review also found CODEX_HOME / AGENTOPS_RPI_RUNTIME* are not isolated
in the arm env (a separate env-hygiene leak per docs/contracts/eval-environment.md)
— filed as ag-aekxj (auth-preserving fix), blocking ag-epgk so no metered run
proceeds until it lands. Out of scope for this workspace-isolation fix.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>