W1c blocker (pre-mortem #4): harness defaulted AGENT=claude but the default
runner (eval-agent-harness.sh) is codex-only — a wrong/missing --agent silently
invalidates a metered run. Default to codex; fail fast (exit 2) before any seed
if the default runner gets a non-codex agent; custom CORPUS_DELTA_RUNNER exempt.
+2 bats guards. Unblocks part of ag-epgk.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
scripts/check-provenance-feed-health.sh: non-blocking warn when the provenance
ledger has only the genesis row (dead sensor); --strict exits non-zero. Mirrors
the existing check-*.sh exit-code contract. Paired bats suite covers both
scenarios from the bead (healthy ledger, dead sensor warn/strict).
Closes: ag-z2q93
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ao provenance emit-verdict --file <verdict.json> parses bead_id, head_sha,
disposition from a pawl-verdict artifact and appends a schema-valid,
hash-chained edge (verdict --wasDerivedFrom--> commit) to the provenance
ledger. Verdict node id = <bead_id>@<sha[:7]>, trust_tier=inferred.
Wired non-blocking into scripts/pawl-verdict.sh write (after atomic rename,
|| true). Idempotent, honest, same discipline as emit-landed (ag-62jrm).
Tests: registration + L2 store (ledger grows, chain verifies, re-emit
is idempotent) + pure parser + pure edge builder.
Closes: ag-cm8nd
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
GOALS milestone 1 (position signal) was 'floor poured, unfed': ag-8jf97 built
docs/provenance/ledger.jsonl + ao provenance add/verify + the tamper gate, but
nothing auto-emitted — only the genesis row existed. This plugs the sensor in.
New: ao provenance emit-landed. For the commit(s) being landed, it appends a
schema-valid, hash-chained 'bead --wasGeneratedBy--> commit' edge per bead the
commit cites (Closes/Closes-scenario trailer or the parenthesized PR-title
convention). Honest trust tier 'inferred' (a deterministic read of the commit,
never a self-grade); idempotent (re-emit is a no-op). The bead-close mapping is
honest: in push-to-main, a bead closes when its arc lands on main, so emit-on-
landed-commit IS emit-on-close.
Wired automated + human-free at the land path: the pre-push gate (both the live
Go-gate dispatcher scripts/hooks/pre-push.local and the bash escape-hatch
scripts/pre-push-gate.sh) runs scripts/emit-landed-provenance.sh AFTER a PASS,
which emits for origin/main..HEAD and commits the ledger growth as a trailing
sensor commit (one-push lag). Non-blocking by construction (always exits 0,
slice-0 graceful-degrade), skippable via AGENTOPS_PROVENANCE_EMIT_SKIP=1, and
self-terminating (the provenance commit cites no bead → no further emission).
Smoke-caught + fixed: the conventional-commit scope 'feat(cc-hooks):' was
mis-read as a bead id; the title-parens matcher now requires start/whitespace
before '(' so scopes are excluded.
Tests: pure extractor (6 cases incl. scope-exclusion + no-false-positive),
edge-shape, L2 ledger-grows-and-stays-intact through the real store, wrapper
bats (skip/happy/no-op/non-blocking). Gate green 23/23; full cli suite green;
pre-push-gate self-test 40/40. CLI surface regenerated.
Closes-scenario: ag-62jrm#emits-edge-on-land
Closes-scenario: ag-62jrm#ledger-grows-beyond-genesis
Bounded-context: BC1-corpus
Evidence: cli/cmd/ao/provenance_emit_test.go
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Append-only JSONL yield ledger (yieldledger-event.v1): a durable,
bead-keyed operational event stream (accept | gate-verdict | usage) so
an agent factory's per-bead yield (A, R, A/R, Q, E, L) is computable
from DATA, not prose. Read by ag-qzinh (the gauges).
Rework addressing cross-family codex REFUTE of the prior commit:
- B1 Writer is now concurrent-append-safe: O_APPEND JSONL (one event
per line), no read-modify-write, no shared tmp — fungible lanes can
merge concurrently without lost/collided events.
- B2 codec enforces the closed schema (DisallowUnknownFields on the
envelope AND every typed body) — an unknown field is a REJECT.
- B3 reconcile-pr.sh emits a gate-verdict for ALL dispositions
(CONFIRMED/REFUTED/ESCALATE/HOLD) right after the gate verdict,
before exit-5 — Q's denominator + E are now computable.
- B4 reconcile-pr.sh emits a usage event at close (R/A-R/L source).
- B5 accept emit stays strictly post-MERGED; post-decision emits
backgrounded so a slow emit can never delay the merge/close path.
- B6 tests for the real risks: concurrent-append (-race), closed-schema
rejection, REFUTED/HOLD round-trip.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two blocking gates were red on main independent of the enumerated
categories; both fire on this branch because it touches skills/.
1. scenario-test-linkage: the skill fold migration (brainstorm->discovery,
vibe->validate) moved two doc-only .feature files but the
scripts/.scenario-linkage-allow entries still pointed at the old paths
(skills/brainstorm/..., skills/vibe/...), which no longer exist. The
moved files (skills/discovery/references/brainstorm.feature,
skills/validate/references/vibe.feature) thus fell out of the allowlist
and failed the gate. Restore them at their new paths — same documentation-
only intent that was green at c9c3e270, corrected for the fold. Not a
weakening: these scenarios were always allowlisted; the fold broke the path.
2. token-budget: skills/evolve/SKILL.md grew from 36800 B (green at c9c3e270)
to 41905 B (10476 tok) via feature commits, crossing the 10000-tok hard
limit. Trimmed verbose prose (intro/examples/troubleshooting/redundant
comments) to 39883 B (9970 tok) WITHOUT touching any asserted command/path
string, protected section header, or frontmatter. Regenerated the evolve
codex twin source_hash (skills-codex manifest + generated.json) to match.
regen-all.sh --check: ALL GATES GREEN.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Trunk on main has been RED since 2026-06-08 (last green c9c3e270). Restores
every blocking gate to green on a branch. Five fix categories:
1. security / dangerous-pattern: add install-claude.sh, install-agy.sh, and
install.sh to the curl|bash --exclude list in validate.yml. install.sh
gained an AGY install-instructions echo (curl|bash) on 2026-06-09; the two
new install scripts mirror the already-excluded install-codex/opencode set.
2. lint / markdownlint: fix 3 pre-existing failures without deleting content —
MD037 (backtick the glob paths so * isn't read as emphasis) in
dirty-main-attribution; two MD004 (rewrap so a continuation '+' isn't read
as a plus-style bullet) in ag-s43tg-resume + skill-prune-phase2.
3. skill-flow danglers: the Phase-2 skill prune (40ee1c34f) deleted
brainstorm/design/complexity/ratchet/audit-report/learning/
operating-loop-skill/cass-memory but left consumes/metadata.dependencies/
context_rel edges pointing at them. Removed the dangling edges from
discovery, refactor, eval-outcomes, rpi, operationalize, agy-native, perf,
test, acfs. converge (thin memo) now consumes the whitelisted command-help
artifact; converge + beads-bv (orphaned when operating-loop-skill was pruned)
added to skill-flow-standalone.txt with rationale.
4. derived-artifact drift: regenerated catalog.json, registry.json,
context-map.md, and the 10 skills-codex .agentops-generated.json twins +
manifest via scripts/regen-all.sh after the frontmatter edits.
5. stale bats: brainstorm-discovery-ideation.bats followed the deliberate
bd->br tracker migration (f650d41bb) — assert br / ban bd — and the codex
anti-leak guard now targets the real codex twin (skills-codex/discovery)
instead of the shared Claude reference (which legitimately uses
AskUserQuestion). install-sh-runtime-detection.bats updated to the new
multi-vendor install-suggestion output format.
Did NOT touch tests/scripts/validate-skill-disposition-schema.bats: its
"bad revision origin/main" failure is a CI-env artifact (checkout lacks the
origin/main named ref); all 24 cases pass locally with the ref present and the
4 guarded files unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Final holistic review FAIL: (1) commit-binding failed OPEN — gh headRefOid lookup failure →
empty cur_head → staleness check skipped → stale verdict could merge. Now fail-closed at both
layers (reconcile-pr.sh HOLDs on empty head; pawl-verdict.sh check refuses empty --head) + bats
test. (2) stale 'cross-family/both refuters/≥2 families' prose contradicted the new fresh-context
default — swept across schema/scripts/crank/evolve/pre-land-refuters/rpi/validate/pawls.md so every
file agrees: fresh-context default, multi-model opt-in. 28/28 bats, regen-check green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PART A — the gate now reflects a review that ACTUALLY RAN against THIS commit:
- head_sha REQUIRED + compared: reconcile fetches the PR's live headRefOid and
fail-closes a STALE verdict (head_sha != current after a re-push).
- terminal-green strictly necessary: still-PENDING checks after POLL_MAX BLOCK
(exit 2); pending-forever can no longer slip to merge.
- schema-validate in check (jsonschema or strict jq fallback): rejects missing
generated_at, string pr, extra props, object-shaped refuters.
- family roster normalized + validated (claude|gpt|gemini canonical, aliases
collapse); fake/unknown labels rejected so ">=2 families" can't be gamed; the
schema enum widened to the alias set (the writer stores raw labels) — the real
distinctness check is canonicalized in pawl-verdict.sh check.
- evidence-binding: each refuter's evidence path (or council_artifact) must EXIST
and be non-empty; a verdict with no reviewer evidence is fail-closed.
- honest framing throughout: "evidence-bound, commit-bound cross-family verdict
that requires real reviewer runs", NOT "un-forgeable provenance". Scope note in
schema + pawls.md: cryptographic un-forgeability is intentionally OUT OF SCOPE
(single-operator trusted loop; the cut cathedral).
- bats: +8 assertions (stale head, pending CI, schema-invalid, malformed JSON,
fake family, alias-collapse single-family, no-evidence, missing-evidence file).
PART B — escalation is now the circuit-breaker model (pawls.md, pre-land-refuters,
evolve, crank, rpi): REFUTED => AUTO-REJECT => AUTO-REDO (loop, no human); a human
is escalated to ONLY when a tunable circuit breaker trips (max-attempts / time /
cost-quota / oscillation), wired to the existing evolve breakers
(scripts/evolve/halt-check.sh). Disposition flips to ESCALATE/HOLD only on a
breaker trip, never on plain REFUTED.
Gates: make regen-check GREEN; reconcile-pr.bats 22/22; shellcheck -S warning clean
on both scripts; rpi 242 lines (<=250).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Make the mutate-shared-trunk pawl REAL: green CI is necessary but NOT
sufficient. reconcile-pr.sh now verifies a CONFIRMED cross-family verdict
(both refuters CONFIRMED, >=2 distinct families, tied to this bead+PR)
before merging, fail-closed.
- schemas/pawl-verdict.v1.schema.json: machine-checkable verdict (the
checkable summary; .agents/council/*.md stays the narrative companion).
- scripts/pawl-verdict.sh: write/check the verdict. `check` exits 0 only on
CONFIRMED + 2-family + this-bead/PR; absent/REFUTED/ESCALATE/single-family
=> non-zero (fail-closed by construction).
- scripts/reconcile-pr.sh: calls `pawl-verdict.sh check` before `gh pr merge`;
new exit 5 (HOLD: no merge, no close) when no CONFIRMED verdict. Green CI
alone can no longer merge.
- tests/scripts/reconcile-pr.bats: +5 fail-closed assertions (no verdict,
REFUTED, ESCALATE, single-family, wrong-PR all HOLD exit 5; CONFIRMED+green
merges). All 14 green.
- Consistency: crank "merge when green" -> green CI AND cross-family verdict;
validate/pre-land-refuters "large arcs"/"full-complexity" -> any complexity;
pawls.md + pre-land-refuters: ESCALATE/N-exhausted = HOLD until human (never
auto-land). pawls.md trunk row names the enforcement.
- docs/contracts/agents-write-surfaces.md: document .agents/pawl-verdicts/.
- regenerated derived artifacts (registry, context-map, codex hashes).
regen-check GREEN; reconcile-pr.bats 14/14; pre-push --fast clean of new
failures (pre-existing converge-desc + test-tuning-defaults untouched).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Operationalizes planning-rule f-2026-04-29-002 (swallowed json.Marshal
anti-pattern). The pre-existing .golangci.yml comment claimed errcheck
"already covers json.Marshal/Unmarshal" — it did NOT: the swallow uses the
blank identifier (`b, _ := json.Marshal(...)`), and golangci-lint's errcheck
has check-blank OFF by default, so the anti-pattern was invisible. Even with
check-blank on, errcheck findings route to the gate's non-blocking quality
bucket. Label-not-act; corrected here.
Audit (errcheck -blank, scoped to encoding/json) found 6 unchecked sites,
now fixed:
- cmd/ao/beads_resume.go:229 marshal -> propagate (func returns error)
- cmd/ao/scenario_list.go:70 marshal -> propagate (RunE returns error)
- cmd/ao/eval_suite.go:204 marshal -> justified //nolint (static
primitive map, cannot fail; helper returns
only string)
- cmd/ao/eval_task.go:393 marshal -> justified //nolint (in-memory
struct; CanonicalizeJSON re-validates bytes)
- internal/doctor/fix_skills.go:632/756 unmarshal -> justified //nolint
(best-effort; malformed value falls through
to drift detection / rewrite)
Enforcement (scoped to json, not errcheck-for-all): new
scripts/check-json-marshal-checked.sh runs errcheck -blank filtered to
encoding/json Marshal/MarshalIndent/Unmarshal, honoring justified
//nolint:errcheck directives. Wired blocking into the correctness job of
validate.yml (go-gated). Verified with an intentional regression: a scratch
`b, _ := json.Marshal(...)` made the guard exit 1; removing it restored
exit 0.
Out of scope, left as-is: pre-existing non-json errcheck finding at
skills_retire.go:133 (present on branch base; non-blocking quality bucket).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
docs/provenance/ledger.jsonl was declared the append-only SOT in CLAUDE.md
("ledger wins on disagreement") but the file was never created and nothing
verified it in place — a doctrine-level lying instrument. This pours the
real slab:
- Seed docs/provenance/ledger.jsonl with the genesis event
(ag-8jf97 bead --wasGeneratedBy--> landing branch, trust_tier=authored).
- Add `ao provenance verify`: verifies the COMMITTED chain in place (no
re-sort/re-chain, unlike `export --verify`), so a tampered field, forged
hash, or reordered row is caught and the offending FILE LINE is named.
provenancegraph.Store.VerifyFile() is the line-accurate verifier.
- Wire the gate: scripts/validate-provenance-ledger.sh --gate requires the
committed ledger to exist, be schema-valid per line, and be an intact hash
chain; registered as a blocking T1 CI step in validate.yml.
- Tests (windshield-correctness): L1 deterministic hashing (existing), L2
intact-chain pass, L2 TAMPER (payload-flip / forged-hash / reorder all FAIL
naming the line), missing-file-is-empty-intact, append-creates-genesis;
plus bats coverage of the committed ledger + --gate + tamper path.
Hash discipline follows the schema + existing cli/internal/rpi/ledger.go
(genesis prev_hash = "", hash = sha256(payload_hash+"\n"+prev_hash)) — the
brief's 64-zero/concat variant was superseded per the contracts-over-narrative
precedence rule.
Closes-scenario: ag-8jf97#provenance-ledger-tamper-evident
Bounded-context: BC4-Factory
Evidence: docs/provenance/ledger.jsonl
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## Summary
S2 of the factory-DDD epic (ag-3fp54): makes Claude **workflows** a
first-class, drift-gated registry surface, kind-discriminated alongside
skills and CLI commands.
Prior slices already landed the ledger rows (`workflows:` section in
`docs/contracts/skill-dispositions.yaml`) and the `registry.json`
`workflows[]` surface + summary count (ag-km74w). This slice adds the
**missing identity drift gate** and the **docs Registries pointers**.
## Changes
- **`scripts/check-workflow-governance.sh`** — promoted from a
forward-only `kind: workflow` check to a **bidirectional `.js`↔ledger
bijection** with the DDD identity triple:
- FORWARD: every `.claude/workflows/*.js` has a ledger row carrying
`kind: workflow` + a Bounded Context (`domain`) + a `hexagonal_role`.
- REVERSE: every `kind: workflow` ledger row has a matching repo-tracked
`.js` (else **STALE → FAIL**).
- Workflows are **Claude-only** (no `skills-codex` twin) — the gate
never requires a Codex twin or trips audit-codex-parity.
- **`.github/workflows/validate.yml`** — wire the gate into the
`contracts-sync` job and add `.claude/workflows/**` to the `contracts`
path filter so a `.js` add/remove/rename re-runs the gate.
- **`CLAUDE.md` + `AGENTS.md`** — Registries blocks now name the
**Workflows registry** (kind-discriminated) + the 6 BCs.
## Test (TDD: red → green)
`tests/scripts/check-workflow-governance.bats` — written first; tests
3/4/5 failed red against the forward-only gate (no stale/BC/role check),
then green after the enhancement:
- governed workflow (kind+BC+role, js↔ledger match) passes
- `.js` with no ledger row FAILS naming it
- `kind: workflow` ledger row with no matching `.js` FAILS as stale
- ledger row missing its Bounded Context FAILS
- ledger row missing its hexagonal_role FAILS
- the real repo passes the governance gate
`scripts/regen-all.sh --check` clean (no generated-surface drift — the
`workflows[]` registry surface pre-existed).
Closes-scenario: ag-jy8gj#workflows-drift
Bounded-context: BC3-Loop
Evidence: scripts/check-workflow-governance.sh
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
S0 foundation slice (v4 additive, no-rename — quorum-ratified). Adds the
artifact-classification fields to every active `- skill:` row + workflows entry
and introduces BC6 Orchestration, without renaming the ledger file, the
`- skill:` row key, or the `domain: "BCn Name"` string format.
- skill-dispositions.yaml: backfill kind/runtime_targets/parity_policy/
capability_class/path/aliases/supersedes on all 71 active rows + 4 workflows;
re-bin the 6 orchestration skills (ntm/swarm/agent-mail/using-atm/
vibing-with-ntm/continuity-loop) into BC6.
- bounded-contexts.yaml: add BC6 Orchestration + OrchestrationPort.
- sku_catalog.py: BC6 enum + cli-command-per-BC carve-out (require >=1 active
artifact per BC; cli coverage only where a BC owns commands).
- generate-registry.sh: emit the new fields (+ derived runtime_reach) and a
first-class `workflows` surface.
- generate-skill-domain-map.sh / check-bounded-contexts-drift.sh: BC-count
sites 5->6; both registry docs carry BC6.
- new gate validate-skill-disposition-schema.sh (+ bats) rejects unknown
kind/capability_class and missing fields, naming the offending row; wired into
regen-all, pre-push-gate, and the Go gate registry.
Renamed-consumer parsers (resolve-skill-path.sh, skills_retire.go, heal.sh) and
the `- skill:` fixtures are byte-untouched.
Closes-scenario: ag-4akl8#backfilled-fields-preserve-the-skill-count
Bounded-context: BC4-Factory
Evidence: docs/contracts/skill-dispositions.yaml
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
First factory-governed workflow (bootstrap engine for epic ag-3fp54).
- .claude/workflows/ship-beads.js: bead-crank with crank->ship renamed
throughout (meta.name 'ship-beads', Fan-Crank->Fan-Ship, labels/comments).
Every phase + all logic preserved exactly: Prelude admission gate,
Plan-Graph surface-collision DAG, Fan-Ship worktree-isolated implementers
(cap 4-6), Reconcile confirmed-MERGED state machine, Epilogue epic-close gate.
- bead-crank.js UNTOUCHED (additive, never breaking-renamed) — both resolve;
the dynamic drift gate (git ls-files) and install script pick up both.
- skill-dispositions.yaml: SEPARATE top-level workflows: section (kind: workflow)
parallel to historical:, so the `- skill:` line-parsers skip it. Skill
count unchanged (71); regen-all --check all-green; skill-domain-map golden.
- scripts/check-workflow-governance.sh: asserts every .claude/workflows/*.js
has a workflows: ledger entry with kind: workflow.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Shared scripts/lib/resolve-skill-path.sh routes skills/<slug>/ and
skills-codex/<slug>/ paths through the historical: section of
docs/contracts/skill-dispositions.yaml: merged-into rewrites the slug
segment to the target, cut skips visibly (stderr warn), no row / unknown
slug / missing ledger degrade to identity. Exact-slug awk parse (plan does
not match plan-foundry). The 4 validators that hardcoded skill paths
(rpi-contract, lifecycle-guards, cold-start, pre-push-gate) route their
fixed entries through it so folds/cuts auto-retarget instead of needing
hand-repointing. Identity-preserving on the current repo (no historical row
matches any routed active skill): 3 standalone validators byte-identical
before/after; 16 bats incl. 4 validator-integration cases.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The home symlink targets the MAIN checkout; a gate run from any worktree saw
realpath inequality and failed. Byte-equality with the current repo's canonical
is the real invariant — divergent bytes and dangling links still fail.
Fixture-verified: byte-equal-elsewhere=0, divergent=1, dangling=1.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
install-workflows.sh: arg-scoped, generic (no workflow special case),
idempotent ln -sfn, backup-then-replace on divergent local edits.
check-workflow-drift.sh: blocking on bdd-foundry.js (absent=>SKIP exit 0,
dangling/misresolved/divergent=>FAIL), DRIFT-REPORT-only for siblings
bead-crank.js / operating-loop.js. check-bdd-foundry-markers.sh: S4 marker
floors, fails naming the missing marker. validate-workflow-install.sh: the
named blocking parent.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Plan-time admission gate: PASS iff >=1 scenario unit (Scenario: block or
bare-GWT stanza) and every unit carries >=1 Given and >=1 Then. Missing
When = WARN, exit stays 0. Fenced content parse-inert in pre-scan + main
loop; unit verdicts flush on next-unit start, section exit, and EOF;
empty input under --admission exits 2 (infra, not policy); --admission
with --run is misuse (exit 2). JSON gains additive admission,
units_total, structurally_complete, warnings fields. --bead mode
migrated from retired bd to br (BEADS_DIR defaults to <repo>/_beads;
exit 2 when br absent). Corpus survey over 50 open beads: 17 pass /
33 fail, all fails verified true-rejects (zero false-fails; one parser
fix folded in — annotated "## Scenarios (...)" headings now accepted
in admission mode).
Closes-scenario: ag-iruq3.1#admission-mode
Bounded-context: BC5-Runtime
Evidence: tests/scripts/check-bead-scenario-coverage.bats
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
_beads/ is a PRIVATE nested git repo (boshu2/agentops-beads) and gitignored
here: this repo is PUBLIC and the ledger's 8-prefix migration snapshot carries
Home-SOC, client, and fleet-topology content that must never land on the public
remote. Tracker sync = git -C _beads add/commit/push. The 19b closeout contract
now asserts the private-ledger form and FAILS on any doc that stages _beads/
into the public repo (new bats fail-direction test).
Also lands: the 2026-06-11 codebase-recon audit reports (6 reports, the
migration's originating evidence) and peer-lane evidence files.
Closes-scenario: ag-yb8w#verify-and-ratify
Bounded-context: BC2-validation
Evidence: docs/audits/codebase-skills-2026-06-11/
ATOMIC by design: the doc flip removes the exact bd/Dolt closeout wording that
check 19b (validate-bd-closeout-contract.sh) grepped for; the inverted contract
asserts the br closeout discipline instead (br sync --flush-only + ledger staging,
no live bd dolt push instructions). Splitting these red-mains every push; a single
revert of this commit restores doc+gate together.
Tracker = br (beads_rust) + bv. Workspace at _beads/ (BEADS_DIR until .beads/
retired). bd/Dolt retired 2026-06-11: single-host SPOF, no offline lane (P1,
docs/audits/codebase-skills-2026-06-11/codebase-risk-audit.md). Migration:
3,988 issues / 4,301 deps loss-free (.agents/swarm/results/br-migration.json).
Closes-scenario: ag-joto6#closeout-contract-stopgap
Bounded-context: BC2-validation
Evidence: .agents/swarm/results/wave1-fixes.json
GOALS.md predated the control-plane run; none of the night's enforcement
surfaces were fitness gates. Wire four, all proven green first (honesty rule):
- door9-no-api-print (w6): LAW 0 as fitness — CP bin/no-api-print-scan.sh, CLEAN/224 files
- image-conformance (w5): CP bin/image-conformance.sh --built-only, 28/28
- retirement-ceiling (w4): CP ctl-retirement-count.sh --gate 37 (real count=37, not the
anticipated 39 — the +2 ctl scripts did not land)
- gated-close-rate (w4): NEW scripts/check-gated-close-rate.sh — 85% stamped of last 20
CP closes, threshold 70%
Cross-repo gates resolve $CONTROL_PLANE_ROOT and SKIP cleanly when absent. The two CP
scripts are cwd-sensitive (git ls-files / verify.sh build-farm check), so the gate
commands pin '( cd $CP && ... )' to run reliably per the three-gap honesty rule.
Scenario layer: PRE-PRODUCTION, not faked. ao scenario has no evaluate/run; nothing
writes .agents/rpi/scenario-results.json (only test callers of Writer.Append), so every
directive reads unknown/0%. Added a GOALS.md note marking the layer observational (not a
gate, excluded from weighted score) + light-it-up plan in evidence. No fixture written.
flywheel-compounding: feeder-context note linking the failing sigma-rho to cp-s82z
(backfill, raises sigma) + cp-0gyc (operator library, raises rho).
VERIFY: goals validate valid=true; measure 24/28->28/32 passing, weighted 125/142->144/161,
4 new gates green, zero regressions.
A fresh CLI agent could not discover how to send Agent Mail: the agent-mail
skill documented only the MCP send_message tool (not loaded in plain CLI
sessions), 'am --help' omits the 'mail' subcommand group, and 'am send' does
not exist (the verb is 'am mail send'). Read commands have flat aliases
(am inbox/status) but send/reply do not. Fix:
- agent-mail: TWO-SURFACES callout + MCP↔CLI command table for every op +
the 'am send' discoverability-trap warning.
- using-atm: AM-leg now gives the explicit 'am mail send'/'am mail inbox'
commands and the trap note (dropped the misleading 'MCP name retired' line).
- validator scripts/validate-am-coordination-discoverable.sh guards regression.
Follow-up (am binary): add flat 'am send'/'am reply' aliases + surface the
'mail' group in 'am --help' so the CLI is self-discoverable.
The skill count is enforced by the doc-release gate but SKILL-TIERS.md rows
were hand-maintained: adding a skill dir made rows != directories, and
sync-skill-counts.sh fail-closes on that before patching any doc — so every
skill add/remove required a manual SKILL-TIERS edit first. That (plus a stray
.pyc masking 166) stuck the 3.1 release.
- scripts/ensure-skill-tiers-rows.sh (new): auto-renders a SKILL-TIERS.md row
for any skill dir missing one (desc from frontmatter, tier=execution),
curated rows untouched. rows == directories now holds by construction.
- sync-skill-counts.sh: call ensure-rows first; extend the ASCII-diagram guard
to auto-patch same-digit-width drift (the 166->167 case), fail only on
width changes that need a hand re-pad.
- tests/docs/test-skill-count-ssot.sh (new): red-green acceptance — add a skill,
gate green with zero doc edits; wrong hand-typed count still caught. Wired
into validate.yml.
evidence/cp-9wvq.impl.md
Finding 3a — smoke count: CHANGELOG cited 41 passed; actual suite count is 45
(verified: bash tests/install/test-install-smoke.sh → "Results: 45 passed, 0 failed").
Update CHANGELOG.md to the measured figure.
Finding 3b — AGY installer: install-agy.sh exited 1 on clean fresh install
because `agy plugin enable` returns exit 1 when the plugin is already enabled
(idempotent install scenario). Fix: capture enable output and treat
"already enabled" as success. Verified: AGENTOPS_BUNDLE_ROOT=. bash
scripts/install-agy.sh now exits 0.
Changelog honesty — CHANGELOG Fixed entry for verdict-gate enforcement cited
d6576b359/94181cc89/9c1398671 (skill-edit/catalog commits) as the enforcement
code. The real enforcement is in 5f7120ff6 (cherry-picked in the preceding
commit). Updated to cite 5f7120ff6 as the primary implementation commit and
clarify the role of the other three. Update tests to accept 3.1.0-rc as the
new version source fallback (no longer "dev").
The unified scripts/install.sh detected only claude/codex and Step 1 installed
only the Codex plugin, so the documented one-liner could not install for the
third supported vendor (Gemini/AGY) — short of the spec gate ('a fresh machine
can install 3.1 for any of the 3 vendors via a documented one-liner').
- install.sh: detect agy; count runtimes for single- vs mixed-model messaging
across all three vendors; Step 1 now also installs the agentops-core-gemini
plugin from the already-extracted bundle (reuses AGENTOPS_BUNDLE_ROOT, gates
on jq, skips gracefully so claude/codex users are unaffected).
- docs/install-day2-ops.md: Recover section now opens with 'ao doctor'/'ao
version' self-check before any reinstall (idempotent re-run guidance).
- tests/install/test-install-smoke.sh: 2 new invariants asserting install.sh
delegates to install-agy.sh and detects the agy runtime (43/0 PASS).
Make the Claude IMAGE-CORE recipe a release-grade installable artifact:
- install-claude.sh: add --ref <ref> (and AGENTOPS_INSTALL_REF) to pin the
marketplace source to a tagged release (owner/repo@ref), reaching parity
with install-agy.sh; default still tracks the marketplace branch.
- images/claude/verify.sh: assert .claude-plugin/plugin.json declares the
expected version (default 3.1.0, AGENTOPS_EXPECTED_VERSION override) so a
stale-version manifest drift fails the gate.
- tests/install/test-install-smoke.sh: cover --ref support + dry-run pin spec
(smoke now 43 pass / 0 fail).
- docs/reference.md, CHANGELOG.md: document the pinned-release one-liner and
the two hardening additions.
Measured: verify.sh 66 skills + version guard PASS (exit 0), negative
version-guard exit 1; install-claude.sh --ref v3.1.0 emits
'marketplace add boshu2/agentops@v3.1.0'; smoke suite 43/0.
Refs cp-fhq3.
## Summary
- Rename the canonical and Codex `using-ntm` skill to `using-atm`.
- Update inbound references, catalogs, context-map/disposition/domain
docs, and rpi/crank/swarm/council related-skill links.
- Sync Codex generated metadata and preserve the upstream NTM note for
the ATM fork/alias surface.
- Repair post-`cp-z1s5` gate drift exposed by this PR: regenerate
`registry.json`, wire `storage-watchdog-ops` into skill-flow, refresh
context-map/Codex metadata, and remove its stale standalone allowlist
entry.
## Validation
- pre-push fast/head on `95a8e9d35`: 34 checks, 33 pass, 1 warn, 0 fail;
warn: `always.retrieval-manifest-paths`
- full local Go gate: `WORKTREE_DISPOSITION_CI_SKIP=1 /tmp/ao-cp-v8m2
gate check --full --json --workflow-coverage` => 72 total, 71 pass, 1
advisory warn, 0 fail
- `scripts/regen-all.sh --check`
- `bash scripts/validate-skill-flow.sh`
- `bash scripts/validate-skill-schema.sh`
- `bash scripts/validate-codex-generated-artifacts.sh --scope worktree`
- `bash scripts/validate-codex-api-conformance.sh`
- `bash scripts/validate-codex-runtime-sections.sh`
- `bash scripts/validate-codex-override-coverage.sh`
## Notes
- Deployed local Codex/Claude cache proof for `using-atm` was performed
before push.
- Unrelated local dirty files in the original checkout were
intentionally excluded: `skills/cass/scripts/validate.sh`,
`skills/ru-multi-repo-workflow/scripts/validate.sh`, `wt-ag-qidx/`.
- `cp-z1s5` is closed on main at `e0932310d`; this PR carries the small
gate-drift repair required to make that main state validate under PR CI.
Squash merge image consolidation after CI repair.\n\nValidated by GitHub Actions: changes, lint, codex-parity, skills-integrity, skill-gates, contracts-sync, correctness on Ubuntu and Windows, security, eval, skill-eval, doctrine-proof, process-hygiene, and summary. Cursor Bugbot was pending/advisory; main has no branch protection/rules requiring it.
Coverage-equivalence test green (registry covers every bash-gate backing script
bar the documented agents-hash deferral), so the Go gate becomes the DEFAULT
pre-push path; bash gate kept as AGENTOPS_GATE_BASH=1 escape hatch. From-source
bootstrap retained. This very push is gated by ao gate check (e2e). ag-3n71.
TX2: macOS /bin/bash 3.2 silently misbehaves on declare -A / mapfile — a check
script running under it is a FALSE GREEN. Add lib/bash4-guard.sh (source-first:
re-exec under Homebrew bash>=4 if present, else exit 70=FAIL, never PASS) and
wire it into check-worktree-disposition.sh (gate-path, uses declare -A). Harden
the Go ScriptRunner to prefer a bash>=4 binary (systemic for the Go gate path;
Linux falls back to PATH bash 5). 39 scripts use bash-4 features; the remaining
38 are the Phase-B lib-consolidation sweep. go test green (43), shellcheck clean. ag-qidx.
P1.4: serialize concurrent pushes for swarm sessions. Layer 1 = portable
within-host advisory lock (mkdir, since flock is absent on macOS) so two local
agents can't gate+push at once and corrupt a shared generated surface. Layer 2 =
rebase-on-reject retry for cross-host (Mac+bushido) convergence via git's atomic
non-ff rejection. Solo work stays lockless (plain git push). bash-3.2-safe,
shellcheck clean, bats green. ag-qidx.
TX1: remove scripts/gh-merge-chain.sh (158 LOC; retired 2026-05-19 — the
update-branch merge cascade the push-to-main collapse replaces) + its orphaned
tests/scripts/gh-merge-chain.bats, and scripts/archive-research.sh (78 LOC; zero
references). Verified zero live callers (yml/sh/Makefile/go/bats). Historical
doc/learnings mentions left as-is. ag-qidx.