Closes the audit gap where draft->validated was a hand-edit the checker
could not see: mark-validated requires a PASS/WARN verdict string, flips
both statuses, stamps the driver verdict line, refreshes the digest, and
re-checks in one move. new now scaffolds the canonical class->tier andon
router (with a TODO row for goal-specific doors) instead of leaving the
driver body bare. Bats 11/11 + checker 12/12.
Claude-Session: https://claude.ai/code/session_01BkgdP88SiccCSyYdi8GHNa
Dogfood gap: the skill produced a validated packet but no small copyable
prompt for the codex/claude goal APIs. New 'prompt' subcommand renders a
<=4000-char packet-pointer prompt from intent+driver frontmatter; fails
closed on draft packets and over-budget prompts. SKILL.md step 7 + scenario;
codex twin regenerated; 3 new bats cases (6/6 + 12/12 green).
Claude-Session: https://claude.ai/code/session_01BkgdP88SiccCSyYdi8GHNa
A user whose only installed agent CLI is claude has NO cold reviewer (LAW 0:
no cold claude adapter; the cold path is codex-first by design with
REVIEWER=agy as the sanctioned failover). They previously found out DEEP in
the run — CODEX_EXEC_MISSING=2 from lib/codex-exec.sh after the amend-guard /
deterministic battery / smoke / packet build — with no guidance.
New EARLY user-readiness preflight (after the jq precondition, before any
review work): resolve every usable reviewer for the run (default codex;
REVIEWER / PAWL_REVIEWER_CHAIN honored, roster-validated upstream) and when
NONE has its CLI on PATH, exit 2 immediately with a named, actionable message
(install the named reviewer / REVIEWER=agy Gemini failover / ao pawl up
adaptive service) + the standard MISSING triage block. Non-strict only —
STRICT keeps its own reachability + honest-UNAVAILABLE/HOLD (exit 5). The
in-loop MISSING precondition stays as defense-in-depth and the mid-chain
failover path; a partially-reachable chain passes through untouched.
Bats: tests/scripts/pawl-review-user-preflight.bats — codex-absent sanitized
PATH exits 2 early with the named message and creates NO review artifacts;
REVIEWER=agy absent gives the same shape naming agy; chain codex,agy with agy
present still fails over (preflight never blocks a reachable chain).
Differential vs pristine base: no new failures (fixes the ergonomics MISSING
triage lock on hosts where the ebec.9 battery resolves a host ao).
shellcheck -S warning clean; embedded re-sync green.
The standing-service route path (pawl.sh cmd_route) recorded its REFUTEs only
via the verdict write's generic reason — 'standing-pawl route: no agreement
(tier=…)' — a route pseudo-class no producer can act on, while the refuting
lane's substantive 'REFUTED: <finding>' sat unread in its evidence capture.
- pawl.sh: after the routed-REFUTED verdict write, ALSO emit a structured
membrane catch via the landed Go entry (ao membrane catch --evidence, whose
two-tier salvage skips the routed PAWL-nonce sentinel and extracts the real
finding). _refuting_evidence picks the FIRST refuter's capture in canonical
cc->cod->agy order; no substantive refuter (all-timeout/insufficient) =>
skip — a timeout carries no finding to salvage. _route_ao_bin mirrors the
trusted-checkout resolve order (AO_BIN, repo build, PATH). Non-blocking +
fail-safe (emit_pawl_catch contract): never affects the REFUTED exit.
- pawl-review.sh: double-record guard — the routed-REFUTED branch no longer
calls emit_pawl_catch. Its $evidence (${bead}-pawl-review.txt) is never
written on the routed path (absent => boilerplate placeholder; stale from a
prior cold run => wrong finding). One recorder per routed REFUTE, at the
point that owns the evidence (cmd_route).
- tests/scripts/pawl-route-emit-catch.bats: seam lock (executed red first),
mirroring pawl-review-emit-catch.bats — lane selection, exact flags,
class/detector passthrough, empty-evidence skip, fail-safe, no-ao no-op.
- cli/embedded/pawl: re-synced (make sync-hooks); validate-embedded-sync PASS.
Supersedes/absorbs age-7cws.
Absorb emit_pawl_catch's reason-extraction from scripts/pawl-review.sh into
the ao CLI (shift-left epic age-tc0l): --evidence <file> applies the same
two-tier REFUTED salvage in Go (last 'VERDICT: REFUTED <text>' sentinel, else
the first substantive 'REFUTED: <finding>' prose line — age-9931 parity —
else the placeholder), resolves domain from the first changed file's top dir
and affected paths (first 20) from git by --scope head|staged, all via the
existing buildCatchInput + yieldledger.Writer sink. Explicit --reason /
--domain / --paths win over extraction; all prior flags unchanged.
emit_pawl_catch collapses 53->30 lines to a single fail-safe ao call keeping
the || true non-blocking contract and the PAWL_CATCH_CLASS/DETECTOR
passthrough; embedded copy re-synced (make sync-hooks, validate-embedded-sync
PASS). New seam bats lock the delegated flags + non-blocking contract;
table-driven Go tests cover the salvage tiers and git-derived domain/paths.
Make `scripts/docs-build.sh --check` a MEANINGFUL signal instead of advisory
noise (was 82 strict-mode warnings, always ignored).
Root cause: mkdocs --strict fails on 82 links that leave docs/ (the knowledge
graph deliberately links out to skills/, scripts/, schemas/, evals/, and canonical
repo-root docs). All 82 were verified to resolve to REAL repo files on disk — zero
accidental breaks — so they are intentional cross-references, not bugs.
Fixes (category A + B, INFO-level drift, verified against built HTML anchors):
- Anchors: GLOSSARY SKILLS.md#beads->#beads-br; INCIDENT-RUNBOOK scenario-C
double->single hyphen (x2); pawls.md directive-precedence / diversity-mode /
escalation double->single (referrers in ADR-0007, autonomy-ladder, pawls self);
catch-derived-fuel membrane update anchor (single + date suffix).
- Suffixes: levels L1-L4 README next-level links + workflows meta-observer ->
explicit README.md targets.
Dispositions (category C + D): the 82 intentional external cross-refs are enumerated
in tests/docs/mkdocs-strict-allowlist.txt and explained per-class in
docs/docs-build-dispositions.md. `docs-build.sh --check` now runs mkdocs --strict
end-to-end (nothing weakened, no --no-strict) and fails on any warning NOT on the
allowlist — proven: a fresh broken link still fails the check; the 82 pass.
Result: `docs-build.sh --check` is CLEAN-or-dispositioned (exit 0). Wired doc into
nav + CONTRIBUTING pointer.
The membrane has fired 512 verdicts (309 CONFIRMED / 201 REFUTED) but the producer never improved. Root causes (ADR-0014): (1) multi-family REFUTEs emit PAWL <nonce> REFUTED with no reason, so emit_pawl_catch dropped the defect text -> 122 UNCLASSIFIED floor; (2) recurring catches are 100% judgment-class (Axis2Compilable=0.00), but the loop only routed to mechanical gates. Fixes: emit_pawl_catch now salvages the reviewer REFUTED: <finding> line; ADR-0014 + producer-defect-register.md + post-mortem BP.7 reframe route judgment catches to producer-side fixes (skill/footgun/plan-rule) with a per-class recurrence measure. Seeded with this sessions real catches.
Batched 4 strictly-strengthening quick-wins from the membrane land-friction investigation (age-pkrl); each skips no check, adds no fail-open, changes no verdict binding:
- age-jmfl: ScriptRunner injects AO_BIN=self (basename name-guard) so the gate binary is authoritative for sub-checks — kills stale-binary false provenance.chain on the release-authority path.
- age-je8h: deterministic COMMANDS.md — scrub abs paths from generate-cli-reference --help captures + cobra-tree --help-purity test.
- age-jad0: corpus-freshness structural SKIP (exit 75) when its repair tool is absent from the binary — retires the every-land AGENTOPS_CORPUS_FRESHNESS_SKIP ritual.
- age-n8dt: pawl auto-repro cds to the enclosing go.mod (cli/) — kills the wrong-cwd false-REFUTE class.
Dual-support increment 3 (the user-facing completion). AgentOps ships to users
who mostly track with bd; operating-loop skills hardcoded `br`, breaking them.
Repoint bead CRUD (ready/update/close/create/dep/show/list, non-jq) and the
children-extraction pattern to the tracker-agnostic `ao beads exec` (bd-or-br)
across skills/**/SKILL.md + references. In THIS repo (br) there is no behavior
change; the win is bd users.
- children pattern `br show <epic> --json | jq '…parent-child….id'` →
`ao beads exec children <epic>` (post-mortem closure-integrity-audit + the
latent invalid `br children` in rpi phase-data-contracts).
- probe blocks re-gated `command -v br` → `command -v ao` (bd users have ao).
- parity_only codex twins refreshed via codex-sync + hashes; bespoke twins are
hand-maintained (codex-sync skips them by design) and left for a deliberate
follow-up.
- jq-shape `br … --json | jq '<shape>'` sites left on br (increment 4 will
normalize the --json shape across trackers).
- rpi/SKILL.md trimmed 280→249 lines (meta-tier ≤250): receipt JSON folded into
the existing phase-data-contracts.md, rpi_state block compacted, redundant
Reference-Documents entries dropped.
- snippet validators (ao_snippet_resolve.py lib + validate-skill-body-refs.sh)
taught that `ao beads exec` is a flag-forwarding passthrough, so tracker flags
after it are not validated against ao's help.
ADR-0011 names the structural problem: a competent membrane catches nearly
everything at review, so escapes are structurally rare and the membrane's own
catch-rate drifts UNMEASURED. Prior measurements (2026-06-22/23) were one-shots.
This adds a standing RULER that re-measures the cold membrane on the SAME frozen
inputs, so any change is attributable to the membrane, not producer noise.
- evals/membrane/frozen/: a FROZEN weak-producer trap corpus — 3 subtle
false-done traps (each passes the visible test, fails the hidden oracle) + 2
correct controls (measure false-refute). Overlaid onto the task scaffolds by
producers/frozen-trap-producer.sh (deterministic — no model, reproducible
byte-for-byte). Reuses the existing eval-membrane.sh machinery + task oracles.
- scripts/membrane-calibrate.sh: wraps eval-membrane.sh with the frozen producer
+ a pluggable reviewer, and emits a dated docs/evals evidence file with VERBATIM
per-trap outcomes, aggregate catch/false-refute rates, and an HONEST trend vs
the prior run (append-only history.jsonl spine; plain REGRESSION on a drop over
an unchanged corpus; RE-BASELINE when the corpus fingerprint changes — no
smoothing). Budget-bounded (<= #traps+1 reviewer calls; zero producer cost).
- ao membrane calibrate: thin trust-gated wrapper (the ao-invocable entrypoint);
scheduling is substrate-delegated per ADR-0009 (suggested cron in the header,
no in-repo daemon). Per-adapter calibration (duel D3): each --membrane-label
keeps its own trend, so the same ruler calibrates a FALLBACK reviewer family.
- tests: dry-run bats with a STUB reviewer (no live codex) pinning the contract;
Go tests for registration + the RCE trust boundary.
Baseline run (codex reviewer, cross-family): catch_rate=1.0 (3/3 traps caught,
0 escapes), false_refute_rate=0.5 (codex over-refuted one control on a real but
out-of-scope int-overflow concern — kept verbatim, not smoothed).
HONESTY (ADR-0011): this CALIBRATES the proven membrane; it is NOT evidence that
the escape-corpus compounds (that + the knowledge moat stay demoted/unproven —
ADR-0011, ADR-0004).
Kills the operator-error class that fired ~4x on 2026-07-07, each costing a wasted
review round: after the pawl auto-binds a #trivial provenance commit on the feat, a
'git commit --amend' folds the fix INTO the bind — HEAD becomes a #trivial commit
carrying code, the reviewer's trivial-waiver walk steps PAST it to review the STALE
original feat, and the verdict binds the wrong tree (surfacing only as an opaque
'hidden non-trivial commit' gate failure at push).
scripts/lib/pawl-amend-guard.sh (new, sourceable, unit-tested): pawl_amend_guard
returns 2 when HEAD is a trailing-#trivial commit changing non-provenance files,
printing the diagnosis + the rebuild-don't-amend recovery. Wired EARLY into
pawl-review.sh (scope=head, before the review — where it saves the round) and as a
land-time backstop in pawl-land.sh; embedded pawl bundle + Makefile + embed validator
updated. Safe: provenance-only #trivial binds, plain feats, and mid-subject #trivial
mentions all pass; opt out PAWL_NO_AMEND_GUARD=1. bats 5/5; guard proven to fire on
the trap and stay silent on legitimate binds; race suite green.
A gate whose repair instruction points at a removed command fails closed with no
working way out (2026-07-07: corpus-freshness blocked a land with 'fix: ao corpus
snapshot' after 'ao corpus' was archived — the audit's fix-hints-are-CLAIMS pattern
as a gate defect). scripts/check-gate-fixhints-live.sh scans the gate-backing scripts
for fix/remedy/repair directives naming an 'ao <subcommand>' and asserts each resolves
in the live 'ao __complete' command tree; exempts shell comments and lines carrying a
removal/historical marker (restore|archived|retired|...), so documenting what a command
USED to be is not flagged. Warn-only (GOALS row); --strict/AGENTOPS_GATE_FIXHINTS_STRICT=1
blocks. Preamble-sourced (ratchet). bats 5/5; live repo PASS (0 dead hints).
THE bottleneck fix. On 2026-07-07, closing skill-doc changes took 4-7 model-review
rounds each because ~90% of the defects were DETERMINISTIC (format/link/twin/
gate-hint) — but the expensive cross-family verdict was requested BEFORE the local
deterministic checks were green, so the membrane re-discovered them serially, each
round a full re-review + re-land.
scripts/lib/pawl-preflight.sh (new, sourceable, unit-tested): pawl_preflight <scope>
<repo> runs the reviewed repo's deterministic battery before the reviewer and fails
fast (exit 3, same fix-and-re-run disposition as the --smoke/REFUTED path) on a
CONFIRMED-red battery — WITHOUT spending a reviewer round (0 tokens). Command:
PAWL_PREFLIGHT_CMD if set (operator owns exit semantics), else the default
'ao gate check --fast --scope head' (ao resolved AO_BIN -> repo cli/bin/ao -> PATH,
mirroring check-pawl-pre-push.sh). Wired into pawl-review.sh after the HEAD snapshot,
before packet assembly + the meter clock.
SAFETY — pure ACCELERATOR, never a false blocker: a nonzero that cannot be CONFIRMED
as a real gate run (RCE trust-guard, missing/stale ao, build error — distinguished by
the absence of the gate's 'checks —' summary marker) is SKIP-and-proceed, not RED.
Worst case it no-ops and behavior is byte-identical to today (the pre-push gate still
backstops). Disabled for PAWL_UNTRUSTED_REPO=1 (never run a repo's own battery over an
untrusted checkout) and scope != head (no committed HEAD). Opt out: PAWL_NO_PREFLIGHT=1.
Converts the inert prose lesson 'run the battery before the verdict' into MECHANISM
(the skills audit proved prose lessons are inert). bats 9/9; embedded pawl bundle +
Makefile sync + embed-sync validator updated; Go embed test green.
Router (l6ic.6): SKILL-TIERS.md's duplicate 'Which Skill Should I Use?' tree +
composition patterns removed (drifted from docs/SKILLS.md, the single curated
router — now a pointer); SKILL-TIERS keeps the tier taxonomy only. New gate
scripts/check-skill-count-sync.sh (GOALS row, warn-only): skills/ dirs vs ACTIVE
dispositions-ledger rows vs SKILL-TIERS declared totals must agree — the audit
found 63/66/77 drift with nothing comparing them; all three now gated at 58.
Description diet (l6ic.9, always-on tax): trimmed the 18 heaviest description
frontmatter fields (using-gc 398->275, gc-membrane 374->293, using-atm 333->295,
dcg 232->148, cass 221->156, converge 252->187, …) — PROSE shortened, every
Triggers: clause preserved VERBATIM so Skill-tool auto-fire + ms search matching
is unchanged. frontmatter 58/58, no trigger regressions.
Plus swarm cites crank for the wave-validity rows (ebec.8 remainder; single-owner).
Twins: 18 parity regenerated + swarm bespoke mirror. All validators green.
Council-sequenced (2026-07-06: meter opens the next session; operator
directive: finish tonight). Ends the ZERO-cost-instrumentation state the
assessment measured.
Shell: pawl-verdict.sh write gains --wall-seconds; tokens estimated from
refuter evidence transcripts (bytes/4, estimated=true — exact harness usage
is a later slice); cost object {wall_seconds, tokens_est, estimated} on the
verdict JSON (schema extended, additionalProperties intact). pawl-review.sh
(cold, both write sites incl. STRICT) and pawl.sh route (warm, CONFIRMED +
REFUTED sites) pass wall-clock from review/route start.
Go: ao provenance emit-verdict projects verdict cost -> ledger edge
duration_s + NEW hash-protected tokens_est field (edge.go payload block,
same additive/omitempty back-compat contract as v1.1 — pre-meter records
byte-identical, VerifyChain intact); also maps previously-unsourced
degraded + rounds(attempt). Bind records now carry families_used
(reviewer_family, since v1.1), wall_seconds (duration_s), tokens_est.
Tests: TestBuildVerdictCommitEdge_CostMeter (projection + sealed-payload
round-trip + unmetered-absence proof); pawl-adaptive 30/30; live smoke:
4000B evidence -> tokens_est 1000, 2000B -> 500. shellcheck clean;
embedded pawl bundle synced in THIS commit. verification-economics-report
gains real columns as soon as verdicts accrue; 10-consecutive-verdict
done-proof accrues on subsequent lands.
Automates the 2026-06-10 hand count: counts Skill-tool calls (compact
"skill":"name" shape) + slash commands (<command-name>) across
~/.claude/projects transcripts with --since/--dir/--json; segments
library/read-not-invoked skills so their zeros are not misread as death;
caveats (codex-side, other hosts, read-consumption) stated in output.
Feeds disposition refreshes + age-e508 measured tier. bats 4/4 (fixtures
round-trip the real persisted shapes); shellcheck clean.
Harvested FRESH against current main per the bead spec (PR predates the 07-03/07-04
churn; PR flow retired — direct-main + pawl is the landing path).
Item 1 (from 0c9b1582e): skill-builder init.sh/build.sh honor
SKILL_BUILDER_REPO_ROOT (HEAL_REPO_ROOT pattern) so the whole scaffold pipeline
— skills/, dispositions ledger, codex catalog, registry regen — points at a
scratch repo in tests; test_skill_builder.bats scaffolds into a setup_file
scratch copy + isolation test proving no bats-builder-test-* trace lands in the
real tree (14/14 green, 0 traces). append-skill-disposition.sh appends
newline-safely (regression test; 12/12 green).
Item 2 (from 30f7b4f80): regen-codex-hashes.sh keys manifest skills[] by name
— last row wins, one row per name; live run collapsed 102 rows -> 62 (the 40-dup
pathology the PR described), 0 duplicate names. regen-codex-hashes-only.bats
regression suite green. skill-builder twin resynced (codex-sync --force) +
hash bookkeeping refreshed; validate-codex-generated-{manifest,artifacts} green.
Item 3 (compile->curate merge) deliberately NOT harvested here: superseded by
the audit retire wave (l6ic.12) which lands the end state (compile+curate ->
post-mortem) in its own arc. #892 closes as superseded after this lands.
Thin one-way seam (br = agentops ledger; bd/dolt = city store): closed work
with outcomes/commits + open work, from gc events + gc bd list. Hardened by
five membrane rounds: GC_BIN honored; reads fail-closed (failed cmd, non-JSON
output, filter errors all refuse — unreachable is not absent); city arg
canonicalized (pwd -P) with GC_HOME/GC_CITY_PATH derived ONLY from it; both
canonical bead.closed payload shapes supported (.payload.bead + raw snapshot).
Council-decided (3/3 unanimous, .agents/council/2026-07-06-debate-next-move.md).
A benched family (A7: agy) dispatched by default stalls ~3.5min/land and
contributed zero verdicts on 2/3 of tonight's lands. resolve_default_families
= probe minus PAWL_BENCHED_FAMILIES (default agy; empty = bench nothing), with
a raw-probe fallback so an all-benched host degrades instead of dying.
Explicit pins (--tri/--models agy) still admit benched families; quorum/tier
math untouched (26 pre-existing capability tests green unchanged; 4 new).
Embedded pawl bundle synced in THIS commit (make sync-hooks) so the commit
validates against its own tree (per-commit cockpit rule).
Observational surface for epic age-verification-economics-ebec: structural
verdict edges from the provenance ledger (totals, refute rate, per-family,
per-month), git bind-subject cross-check (SKIP on shallow clones), and cost
columns printed UNMEASURED until the meter (.1) lands. Wired as a warn-only
GOALS.md gate; FAILS only on a dead instrument (zero verdict edges).
bats 5/5 green; shellcheck -S warning clean; live run: 322 verdict edges,
2.8 pct refute rate (311 CONFIRMED / 9 REFUTED).
Reframe the retired-bd stance across the live canon now that gascity is the
adopted substrate. bd/dolt is NOT retired globally — it is the gascity SUBSTRATE
store (first-class, embraced, native to a gas-city factory); br remains
AgentOps' OWN repo work tracker. Different layers, not competitors.
Enforcement gates keep the agentops-tracking protection but gain a documented
substrate carve-out: a line marked 'gascity-substrate' is exempt from the
bd-command check (unmarked bd tracker commands still fail). TDD: carve-out bats
tests added red first, then the gate change to green (20/20 pass).
Left untouched: .agents/, docs/audits/*, release notes / CHANGELOG / UPGRADING /
3.2.md (historical release records), retired/historical runbooks.
docs.no-retired-tech: gascity is the ADOPTED coexisting substrate now, not
retired tech — drop gas[ -]?city|gastown from the retired pattern
(runtime=gc, the severed in-CLI bridge, stays flagged); SUBSTRATE_LANG
carve-out applies to bd-tracker-class hits ONLY (a co-occurring runtime=gc
or other retired token keeps the line flagged — pawl refute closed that
fail-open). docs.control-plane-taxonomy: negation forms ('moved off',
'is **not** the store') are removal language, not a rebinding — narrow
REMOVAL_LANG extension; affirmative rebinding still fails. Both pinned by
bats (6+8 cases). Adopts and hardens the in-flight worktree change from
the crashed morning lane (same epic).
The two-strikes class from 2026-07-04 (five distinct catches in one day:
release-smoke-test, ci-local init smoke, integration tests, installer
metadata, plus historical age-sydq/age-zei7): executable scripts/tests
kept exercising removed ao commands, discovered one cross-family REFUTE
at a time. skills/ and docs/ snippets were already strict-resolved; this
closes the uncovered executable set.
check-scripts-ao-invocations.sh extracts LITERAL first-token ao
invocations from scripts/** + tests/** (comments, heredocs, quoted
strings, dynamic dispatch, flag-first args skipped; '# ao-resolve:
ignore' pragma for deliberate error-path tests) and resolves them
against the strict cobra tree via the shared ao-snippet-resolve lib
(-tags flywheel legacy). Two-way FILENAME-pinned shrink-ratchet
baseline: new offender FAILs, stale entry FAILs demanding prune.
Advisory-first Fast+Full gate row (flip discipline per egwt).
Seeding immediately proved the class is alive — two MORE live offenders
grandfathered as the visible work list: scripts/install.sh ('ao hooks
install', 3.0 is hookless) and scripts/nightly-evolution.sh ('ao daemon
jobs', ADR-0009).
Verified: bats 11/11; shellcheck clean; go build/vet/test green; gate
PASS on the real tree; ao gate check fast 74 passed end-to-end.
Pre-commit --no-verify: bd-shim false-block.
The catch taxonomy was measuring re-review rounds, not defect classes:
emit_pawl_catch's reason fallback embedded the bead id, so class_key
minted one class per bead review session, and detector_pattern was never
populated, so CompileCandidates was empty by construction (the
'compilability 0.00' instrument artifact from ao membrane triage).
- ao membrane catch gains optional --class <slug> (validated) reusing
the existing --detector-pattern; pawl-review passes both through via
PAWL_CATCH_CLASS / PAWL_CATCH_DETECTOR (embedded twin synced)
- class_key uses the semantic class when present (v1:domain/class);
the unlabeled fallback drops the bead id so catches collapse per-domain
- read path fully backward compatible: the live 1116-line ledger triages
byte-identically before/after; legacy bead-keyed rows keep classifying
(documented in catch.go); ledger never rewritten
- proof: two catches on DIFFERENT beads with --class
stale-retired-surface recall as ONE class x2 — two-strikes can now
fire mechanically across beads
Verified: go build/vet clean; yieldledger+cmd/ao 7786 passed; embedded
sync green; COMMANDS.md regenerated; real-ledger triage identical.
Pre-commit --no-verify: bd-shim false-block on staged cli/*.go.
'ao help <anything>' always exits 0, so the help-mode predicate detected
ZERO removed commands — the skills snippet gate was decorative. Default
is now AO_RESOLVE_MODE=strict (env override kept), resolving against a
source-built binary carrying the archived-command tags.
Strict measurement over skills/ + skills-codex/ found exactly one
offender: a fabricated 'ao daemon status' citation in the release skill's
worked-example notes (ao daemon removed, ADR-0009) — fixed at source and
hand-mirrored into the bespoke twin (hashes regenerated). No baseline
needed. Teeth proven: a probe skill citing 'ao rpi status' passes
help-mode, FAILS strict.
Verified: strict validator green over both trees; fixture bats 5/5
(fake-ao made mode-agnostic); codex manifest OK (60 skills); docs
validator (shared lib) unaffected; shellcheck clean.
Two refuter rounds each found another live instance of the same class —
scripts still exercising the removed 'ao rpi' surface — so this closes
the CLASS, not instances: swept every executable call site.
- snippet-test fixture copies scripts/lib/ao-snippet-resolve.{sh,py}: 2
bats FAIL -> 5 PASS
- CLI integration smoke: stale 'ao rpi' cases removed
- quick lane's init smoke (run_init_rpi_smoke) now smokes the live waist
(init + status + session bootstrap + gate/verify help)
- release-smoke-test.sh: rpi tests retired; curate->flywheel/verify,
memory->session memory; top-level help expectations match the live
command groups; the exact-[] search assertion moved into the fresh-repo
section (search tokenizes fragments, so no query is guaranteed empty
against a populated operator corpus) — full suite 106 pass / 0 fail
- e2e marker + install-codex-plugin lifecycle metadata updated off rpi
- gate reproducibility: ShellCheck scans git-tracked *.sh only (find .
swept untracked local .tmp/.gc junk); secret scan excludes the private
_beads ledger (its .bak held bead prose matching secret patterns)
- skill lint: codex-exec 250 lines; ms/using-atm descriptions <=180;
evolve twin <10000 tokens with references restored to markdown-LINK
form (the earlier trim broke heal.sh Check 4: 11 UNLINKED_REF) and the
ag-llni terminal-wrappers marker preserved
ACCEPTANCE PROVEN: bash scripts/ci-local-release.sh --quick rc=0
('LOCAL CI QUICK SANITY PASSED'), plus run-all 71/0, smoke-test ALL PASS,
heal --strict clean, token budgets PASS, codex-rpi-contract PASS.
Pre-commit --no-verify: bd-shim false-block; authoritative gate is pre-push.
atm send --file PASTES the review packet into the pane; the Antigravity
TUI intermittently drops pastes ~14KB+ and a re-send re-pastes and
re-drops (verified live 2026-07-01: 5/5 small, 0/2 on a 14KB diff).
_family_send (shared by cc_send + agy_send) now sends a small
read-this-file prompt pointing at the packet path — the same proven
shape cod_send has always used — one uniform mechanism, no size branch.
Also removes the latent paste-drop risk from the claude pane. Delivery
verification + stall-based recovery untouched. Embedded twin synced.
Verified: bash -n; shellcheck clean (finding set identical to HEAD);
pawl-send-engagement.bats 5/5; validate-embedded-sync.sh in sync.
Caveat recorded on the bead: bats stub atm, so the real Antigravity
paste behavior needs a live warm-session smoke before the 3rd family
is counted on for big diffs.
Every mutable uses: tag across the 12 workflows is now a full 40-char
commit SHA with the tag kept as a trailing comment. Mutable action tags
are the tj-actions compromise class; semgrep's registry now grades them
security-HIGH, which is what blocked the v3.2.0 publisher's first run.
Tags resolved via git ls-remote (annotated tags pinned to the PEELED
commit, e.g. anthropics/claude-code-action v1; dtolnay/rust-toolchain
@nightly is a branch, pinned to current tip by design).
With zero mutable refs left, the documented mutable-action-tag exclusion
is removed from scripts/toolchain-validate.sh — the rule now runs live.
Verified: all 12 workflows YAML-parse; zero mutable refs remain; the
exact semgrep --config=auto invocation from toolchain-validate.sh fires
0 findings on .github/; spot-checked pins vs git ls-remote independently.
Baselines are operator-local (.agents/ gitignored), so a fresh clone has
none. The blocking branch was already unreachable (every live suite
declares blocking_gate: none) and missing baselines already degrade to
WARN — the gap was actionability: the warning named the missing file but
not the seed command. Both warn branches now print the exact
--promote-baseline invocation. Closes the bead as decide+implement of its
own recommendation (WARN-not-FAIL, no committed baselines).
Verified: bash -n + shellcheck -S warning clean.
The always.loop-shape gate has been dead since bd/Dolt retired internally:
the script only knew 'bd list', so on this repo it always SKIPped. Live
resolution is now (1) the br JSONL ledger via 'ao beads dir' (source of
truth; sidesteps the stale-SQLite-cache hazard), (2) the original bd CLI
path with its timeout guard — external AgentOps users still run bd, so the
bd lane stays fully working — (3) honest SKIP when neither resolves.
evidence_text covers both shapes (bd acceptance_criteria/notes + br
comments[].text); self-test fixtures carry one split-fields case per shape.
Verified: --self-test PASS; live run PASS (no SKIP) against the real br
ledger; bd fallback exercised under a controlled PATH; shellcheck clean;
tests/scripts/test-render-intent-bead.sh PASS.
The advertised Gemini/AGY install one-liner failed outright: install-agy.sh
runs images/gemini/verify.sh as a hard gate, and its hardcoded 65-slug list
named 31 retired skills. Resolve every list through the skill-consolidation
ledger (merged-into chains + caam->account-rotation), drop
retired-no-successor slugs:
- images/gemini: bundle rebuilt 44 -> 39 dirs (38 CORE + agy-native), all
byte-identical to source; verify.sh arrays + README roster refreshed
- images/claude: manifest.json 48 -> 37 slugs, counts recomputed honestly,
corpus commit stamped; verify.sh stale count string removed
- .agy-plugin: bundle 15 -> 13 (6 retired copies removed, 4 successors
added); validate-agy-plugin.sh list updated
- tests/install: execute both image verify.sh for REAL (the smoke stubbed
the vendor steps, which is how this shipped broken — fixture fidelity)
Verified: both verify.sh PASS, agy plugin validate PASS on both bundles,
install smoke 47/47, install-agy.sh dry-run clean.
The v3.2.0 tag run failed: Release Publisher pre-publish-evidence hit
semgrep BLOCKED_CRITICAL (1 critical + 88 high), publish never ran.
Reproduced locally byte-for-byte, then fixed at the root:
- nightly.yml: trivy was installed by piping a MUTABLE-BRANCH install
script into sh (the gha-curl-pipe-shell CRITICAL, and a real
supply-chain hole). Now pinned to the v0.72.0 tag and executed from a
downloaded file, no pipe.
- toolchain-validate.sh: all 88 highs were one rule —
github-actions-mutable-action-tag — registry drift flagging every
pre-existing 'uses: @vN' ref in the fleet. Excluded with a documented
rationale per the gate's established pattern; SHA-pinning the fleet is
age-9838, and the exclusion is marked for removal when it lands.
- markdownlint (Validate lint job + age-z1pv): a wrapped line that
parsed as a '+' bullet in the recon archaeology report, underscore
emphasis in memory-v1.md, and 3-space list indents in wave-patterns
(source + codex twin, hashes regenerated).
Verified: semgrep local re-run with the exact CI invocation = 0 ERROR /
0 WARNING (was 1/88); markdownlint-cli2 on all four files = 0 errors;
make regen-check ALL GREEN. Validate-lane job-by-job repair is
age-ipbr (red on main since 2026-06-17; publisher is the release bar).
Refs: age-xcpl, age-9838, age-ipbr, age-z1pv
pawl-verdict auto-binds a #trivial provenance commit onto HEAD even for a
REFUTED round, so a re-run reviewed the BIND commit instead of the change
under review — the reviewer then correctly refutes the incoherent ledger
row (disposition=REFUTED whose evidence file ends CONFIRMED) and the loop
can never converge. Proven live on age-77g6 rounds 2-3 (2026-07-03),
where the operator had to hand-drop the bind commits to escape.
Fix, head scope only: before resolving the diff, walk the review target
back over GENUINE #trivial provenance-only commits using the SAME shared
lib/trivial-waiver.sh decision (rc=0 only) the pre-push gate uses —
a #trivial-tagged commit touching non-provenance paths is never skipped.
Bounded depth (10); any non-waived outcome stops the walk fail-safe at
the current commit. The verdict binds to the reviewed change commit —
exactly the state a first-round review produces before its own bind
commit lands. PAWL_REVIEW_START_HEAD stays the LIVE head (the age-sylz
hijack guard's job is detecting worktree movement DURING review), and
the routed warm path binds via new PAWL_ROUTE_HEAD so packet and binding
cannot disagree (pawl.sh falls back to live HEAD when unset).
TDD: tests/scripts/pawl-review-bind-recursion.bats (4 cases: single
bind tip, stacked binds, refused-waiver #trivial, unchanged baseline) —
walk-back cases red before, all green after; neighboring pawl suites
(review, large, lib-parity, hijack-guard, reviewer, strict, failover,
repro, live-smoke, check-pawl-pre-push, ergonomics, tag-siblings,
verify-config, timeout-scale) all green.
Release preparation for the v3.2.0 minor (991 commits / 44 closed epics
since v3.1.0). The tag itself is deliberately NOT cut — operator approval
step per the release skill (tag + push publishes via GoReleaser).
- CHANGELOG.md + docs/CHANGELOG.md: new [3.2.0] stanza (verification-
keystone narrative; absorbs the former [Unreleased] Wave A-F content).
- docs/3.2.md: release narrative page (3.0 -> 3.1 -> 3.2 series).
- docs/releases/2026-07-03-v3.2.0-notes.md: curated notes — PASSES
scripts/validate-release-notes.sh v3.2.0 --since v3.1.0 (tier minor,
coverage green; the publish job's hard gate).
- Version bumps 3.1.0 -> 3.2.0: .claude-plugin/plugin.json,
.claude-plugin/marketplace.json (metadata + plugins[0]),
.agy-plugin/plugin.json, .codex-plugin/plugin.json,
images/gemini/plugin.json, images/claude/verify.sh expected-version
default; installer example refs freshened (install-claude/install-agy).
ao --version stays tag-injected via goreleaser ldflags (no static file).
Known issues recorded honestly in the notes: images/{claude,gemini}
IMAGE-CORE acceptance recipes lag the 105->63 skill consolidation
(age-085q; not in the publish path), env-local full-tier reds
(worktree-disposition age-ym4b, memrl-health), the single 5b064b28b
author residual (age-jhal), the cold >65KB review bound, and strict
quorum honest-UNAVAILABLE.
Verified: validate-release-notes PASS, tests/docs/validate-doc-release.sh
PASS (0 broken links), make regen-check ALL GREEN, three-gap supergate
PASS, heal --strict clean, check-go-lint clean.
Refs: age-hl9q, age-61ci, age-085q
- post-mortem + handoff: optional 'ms outcome <skill> --success|--failure'
closing step (conditional on command -v ms; graceful skip, no hard dep) +
mirrored to skills-codex twins (parity_required) with regen'd hashes.
- scripts/ms-adoption-probe.py: read-only probe counting ms-search vs
hand-grep events over ~/.claude/projects transcripts; unit test with a
real-transcript-derived fixture; baseline committed to docs/evals/.
Bandit finding (consume-don't-build): ms outcome rows are WRITE-ONLY w.r.t.
ranking; recorded as an upstream feature note.