Commit Graph

3158 Commits

Author SHA1 Message Date
Bo 5b334a13f2 docs(ao): categorize reduction surface (#811)
## Summary
- add root `REDUCTION.md` defining the lean AO vs MTO reduction boundary
and reversible KEEP / RELOCATE / ARCHIVE / RESEARCH buckets
- add `docs/reduction/ao-file-buckets.tsv`, a generated per-file
inventory for every current `cli/cmd/ao/*.go` file with bucket,
rationale, and import dependency clusters
- inventory totals: 637 files = 450 KEEP, 146 RELOCATE, 2 ARCHIVE, 39
RESEARCH

## Validation
- `test "$(( $(wc -l < docs/reduction/ao-file-buckets.tsv) - 1 ))" -eq
"$(find cli/cmd/ao -maxdepth 1 -name '*.go' | wc -l)"`
- `bash scripts/regen-all.sh --check`
- `git diff --check`
- `PRE_PUSH_SKIP_MKDOCS=1 bash scripts/pre-push-gate.sh --fast` passed;
warning-only executable-spec drift remains pre-existing (`scenarios
--lint`, `trace --orphans`)

BR: cp-q4d
ao-pre-reduction@5b334a13f
2026-06-07 02:13:46 -04:00
Bo bb8d747d3a feat(ao): add harness-neutral bead ports (#810)
## Summary
- add harness-neutral BR/git ports: `ao ready`, `ao close ...`, and bare
`ao claim <id>` while preserving `ao claim bind/list`
- keep top-level gate commands from #809 as the shared gate surface; `ao
close` reuses the typed commit-persist close path and returns success
when the ledger already proves the bead is closed
- regenerate command docs, command surface inventory, matrix counts, and
registry metadata

## Validation
- `go test ./cmd/ao -run TestTick -count=1`
- `bash scripts/regen-all.sh && bash scripts/regen-all.sh --check`
- `go test ./cmd/ao -count=1`
- `go vet ./...`
- `go test ./... -count=1 -short`
- `git diff --check`
- `/tmp/ao-cp-ljp ready` from `/Users/bo/dev/control-plane` returned
`state_source=br`, `ready_count=20`, and counts `{ready:20, open:30,
in_progress:1, closed:19}`
- `/tmp/ao-cp-ljp claim cp-ljp` from `/Users/bo/dev/control-plane`
succeeded and did not dirty the Git ledger
- `PRE_PUSH_SKIP_MKDOCS=1 bash scripts/pre-push-gate.sh --fast` passed;
warning-only executable-spec drift remains pre-existing (`scenarios
--lint`, `trace --orphans`)

BR: cp-ljp
2026-06-07 02:03:39 -04:00
Bo a617df3028 feat(ao): expose membrane gate aliases (#809)
## Summary
- expose the membrane gate surfaces as top-level `ao` aliases:
`verdict-gate`, `council-gate`, `install-guards`, `guard-status`, and
`chaos-test`
- keep the existing `ao tick ...` implementation as the shared backend,
so the shell-oracle port and public aliases cannot drift
- regenerate CLI command docs, surface inventory, matrix counts, and
registry metadata

## Validation
- `go test ./cmd/ao -run TestTick -count=1`
- `bash scripts/check-cmdao-surface-parity.sh --write-surface`
- `bash scripts/regen-all.sh --check`
- `go test ./cmd/ao -count=1`
- `go vet ./...`
- `go test ./... -count=1 -short`
- `/tmp/ao-cp-ltj chaos-test` from `/Users/bo/dev/control-plane` =>
`SMOKE PASS`
- `./tick.sh smoke` from `/Users/bo/dev/control-plane` => `SMOKE PASS`
- top-level alias exit matrix from `/Users/bo/dev/control-plane`:
`council-gate` mixed => 8, unverified => 6
- `PRE_PUSH_SKIP_MKDOCS=1 bash scripts/pre-push-gate.sh --fast` passed;
warning-only executable-spec drift remains pre-existing (`scenarios
--lint`, `trace --orphans`)

BR: cp-ltj
2026-06-07 01:45:16 -04:00
Bo 9ddffab410 feat(ao): add typed tick oracle port (#808)
## Summary
- add `ao tick` as a typed Go port of the control-plane tick oracle
- preserve BR/git boundaries for next/status/claim/reopen/close and port
verdict/council/guard/smoke behavior
- update generated command inventory, registry, CLI docs, and
command-surface fixtures

## Validation
- cd cli && go test ./cmd/ao -run TestTick -count=1
- cd cli && go test ./cmd/ao -count=1
- cd cli && go vet ./...
- cd cli && go test ./... -count=1 -short
- bash scripts/check-cmdao-surface-parity.sh
- bash scripts/regen-all.sh --check
- git diff --check
- PRE_PUSH_SKIP_MKDOCS=1 bash scripts/pre-push-gate.sh --fast
- built /tmp/ao-cp7k6 and compared against
/Users/bo/dev/control-plane/tick.sh for verdict-gate, council-gate,
next; `ao tick smoke` returned SMOKE PASS

Note: fast pre-push gate still reports existing warn-only
executable-spec drift for scenarios --lint and trace --orphans.
2026-06-07 01:26:56 -04:00
Bo e67e41cb89 docs(agent-mail): clarify side-channel role (#807)
## Summary
- clarify that BR/beads is the durable coordination bus while Agent Mail
is the side channel for leases, lane notifications, acknowledgements,
and handoffs
- update Agent Mail bead workflow references to keep evidence and
closure in BR
- refresh Codex agent-mail artifacts and sync the AGY bundled copy

## Validation
- bash scripts/refresh-codex-artifacts.sh --scope worktree
- bash scripts/validate-agy-plugin.sh
- bash scripts/validate-codex-generated-artifacts.sh --scope worktree
- bash scripts/regen-all.sh --check
- bash scripts/validate-manifests.sh
- git diff --check
- PRE_PUSH_SKIP_MKDOCS=1 bash scripts/pre-push-gate.sh --fast

Note: fast pre-push gate still reports existing warn-only
executable-spec drift for scenarios --lint and trace --orphans.
2026-06-07 01:00:51 -04:00
Bo f62dcda748 docs(ntm): document Codex spawn fallback (#806)
## Summary
- Document that NTM `--cod` panes must be observed before use because a
local launcher can create a bare shell instead of an active Codex
runtime.
- Add the reliable `codex exec -s danger-full-access
--skip-git-repo-check -C <gitdir>` fallback to the NTM source skill,
spawn reference, troubleshooting guide, Codex wrapper, and AGY bundled
copy.
- Refresh Codex generated metadata for `ntm`.

## Validation
- bash scripts/refresh-codex-artifacts.sh --scope worktree
- bash scripts/validate-agy-plugin.sh
- bash scripts/validate-codex-generated-artifacts.sh --scope worktree
- bash scripts/regen-all.sh --check
- git diff --check
- PRE_PUSH_SKIP_MKDOCS=1 bash scripts/pre-push-gate.sh --fast (passes;
existing warn-only executable-spec drift remains: scenarios --lint,
trace --orphans)

BR: cp-ou6
2026-06-07 00:42:13 -04:00
Bo 6abc480bc1 feat(agy): package core skills for Antigravity (#805)
## Summary
- Add .agy-plugin as the Antigravity packaging unit for the 27 CORE
AgentOps skills.
- Include plugin.json, mcp_config.json, hooks.json, and bundled portable
SKILL.md files.
- Add scripts/validate-agy-plugin.sh to verify AGY CLI validation, Agent
Mail MCP config, hook sidecars, skill count, and source/bundle drift.

## Validation
- bash scripts/validate-agy-plugin.sh
- shellcheck --severity=error scripts/validate-agy-plugin.sh
- jq empty .agy-plugin/plugin.json .agy-plugin/mcp_config.json
.agy-plugin/hooks.json
- git diff --check
- bash scripts/regen-all.sh --check
- bash scripts/validate-manifests.sh
- PRE_PUSH_SKIP_MKDOCS=1 bash scripts/pre-push-gate.sh --fast (passes;
existing warn-only executable-spec drift remains: scenarios --lint,
trace --orphans)

BR: cp-fev
2026-06-07 00:31:16 -04:00
Bo f4162649b8 fix(agentops): remove api-print worker paths (#804)
## Summary
- replace AgentOps headless Claude print worker paths with Codex exec or
non-CLI providers
- switch compile auto-detect/default headless CLI runtime from
claude-cli to codex-cli
- fix two shellcheck blockers from the merged skill corpus and refresh
generated docs/hash metadata

## Validation
- bash /Users/bo/acfs/skill-pipeline/scripts/no-api-print-scan.sh
/Users/bo/dev/agentops/skills /Users/bo/dev/agentops/scripts
/Users/bo/dev/agentops/hooks
- shellcheck --severity=error skills/compile/scripts/compile.sh
scripts/eval-agent-harness.sh scripts/run-rpi-phases.sh
skills/agy-rules-workflows/scripts/close-guard.sh
skills/rch/scripts/mine_rch_history.sh
- cd cli && go test ./cmd/ao -run
'TestResolveCompileRuntime|TestPreflightCompileRuntime|TestCompileScriptOptionsPassesBatchFlags|TestRunCompile_EndToEnd_FixtureCorpus'
-count=1
- bash scripts/regen-all.sh --check
- PRE_PUSH_SKIP_MKDOCS=1 bash scripts/pre-push-gate.sh --fast

Note: unscoped
/Users/bo/acfs/skill-pipeline/scripts/no-api-print-scan.sh still flags
ACFS conformance-selftest fixture strings outside this repo; AgentOps
scoped roots are clean.
2026-06-07 00:08:59 -04:00
Bo 6d5d111faf feat(skills): land four-vendor skill corpus (#803)
## Summary
- Lands the AgentOps skill corpus across source and Codex wrappers,
including Gemini image targets.
- Integrates the skill branch onto current origin/main and refreshes
generated manifests/catalogs.
- Normalizes local next-work queue enum drift and fixes shellcheck in
alias-collision validation.

## Validation
- bash scripts/regen-all.sh --check
- bash scripts/validate-skill-schema.sh
- bash tests/skills/test-token-budgets.sh
- bash tests/skills/run-all.sh
- bash scripts/audit-codex-parity.sh && bash
scripts/validate-codex-override-coverage.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/lint-codex-native.sh
- bash skills/heal-skill/scripts/heal.sh --strict
- PRE_PUSH_SKIP_MKDOCS=1 bash scripts/pre-push-gate.sh --fast

MkDocs strict remains skipped locally via the documented
PRE_PUSH_SKIP_MKDOCS=1 override because the repo currently emits
repo-wide strict-link warnings unrelated to this landing; CI remains
authoritative.
2026-06-06 23:44:42 -04:00
Boden Fuller ac201c6b90 docs(one-session-mode): AgentOps maximally-Claude one-session mode (ag-eli0)
The distilled core run in a single Claude session: the assured loop on Claude +
br + git, no Dolt, no claude -p. Native golden image; same laws scale to the
orchestrated factory. Realizes ag-eli0 from the other direction. Reference impl +
n=1 proof: ~/dev/control-plane.
2026-06-06 13:52:21 -04:00
Bo 8458989215 docs(architecture): add integrator (merge-execution) to agentpod function enum (ag-egpu) (#802)
## What
Adds **integrator** to agentpod-spec.v1's function enum {planner,
generator, oracle, scribe}. It is **merge-execution**: takes
Oracle-passed green PRs and integrates them to main
(rebase/update-branch, CI-shepherd, serialize, keep-trunk-green,
revert-on-red) — distinct from the Oracle (*decides* to merge) and the
Orchestrator (*schedules* pods). Maps to RoleWorker; cannot fold into
Oracle (RoleVerifier never-edits) or Orchestrator (control-plane
injection boundary).

## Decided by quorum
2-of-3 cross-model, 2026-06-06 (derivation: msg #160; the gap surfaced
when a human-driven refiner drained ~36 PRs this session and it was
clearly a distinct full-time role):
- **Codex: REVISE→add, mechanics-only** · **agy: APPROVE** · **Claude:
author-recused.**

Two quorum-mandated guardrails encoded in the doc:
1. **Mechanics-only** (Codex): semantic conflict-resolution that changes
code re-enters the Generator/Oracle gate — integrator is never a
privileged post-verdict author path.
2. **Circuit-breaker** (agy): bound merge/revert + rebase loops (max
retries, halt-on-thrash) so a misbehaving integrator can't thrash trunk
/ burn CI.

Docs-only (RBAC stays roles.go; no schemas/ change, consistent with #766
PROPOSAL scope). Spine-role implication (the-agent-factory.md gains an
Integrator role) flagged for the spine owner.

Bounded-context: BC4-Factory
Evidence: docs/architecture/agentpod-swarmjob-schema.proposal.md
2026-06-06 12:53:09 -04:00
Bo 65a986c691 fix(skill-eval): constrain backtick safe-paths exemption to known file extensions (ag-eatf follow-up) (#801)
## Why (quorum remediation)
#767 (via an autonomous resolver, **merged without quorum**) broadened
the ag-eatf safe-paths false-positive filter to strip **any**
backtick-wrapped `../path`. Side effect: a backtick-wrapped
`../../../../etc/passwd` in a SKILL.md would be treated as a safe
doc-reference and **bypass the safe-paths gate**.

Cross-model quorum on the as-merged change: **Codex = REVISE**
("unacceptable bypass… constrain to repo-internal + approved extensions,
else revert"). (agy/Gemini was unreachable this round — timeouts.)
Tightening a gate back toward its documented intent is the safe
direction, so this lands the constrained version.

## Fix
Backtick strip now requires a **known repo-file extension**:
`md|markdown|mdx|txt|rst|json|yaml|toml|sh|go|py|ts|rs`. Legit
inline-code refs (``../../schemas/x.json``, ``../scripts/y.sh``) stay
exempt; an extension-less traversal (``../../../../etc/passwd``) no
longer matches → still **BLOCKS**.

## Evidence
`bats tests/scripts/skill-eval.bats` → 14/14 (2 new:
backtick-`/etc/passwd` blocks; backtick-`.json` ref passes; the
bare-traversal-blocks test still green).

Closes-scenario: ag-eatf#constrain-backtick-exemption
Bounded-context: BC2-Validation
Evidence: scripts/skill-eval.sh
2026-06-06 12:39:15 -04:00
Boden Fuller 2624f3b2c4 docs(cleanup): add AgentOps distill-to-core plan (ag-eli0)
RPI-shaped intent for distilling AgentOps to the worker's mind:
re-identify, relocate orchestration to MTO, conform to agentops-core-sdk
+ lock the single-writer seam, integrate meta_skill as the evolution
engine. Direction ratified 6/6 by mixed cross-vendor council.
2026-06-06 12:22:30 -04:00
Bo bdd62816ea docs(skills): add trigger markers to judgment-tier skills (ag-okfu #judgment-wave) (#767)
## What

Wave 1 of **ag-okfu** — adds an explicit `Use when:` discovery trigger
clause to the 8 **judgment-tier** skills: `council`, `design`,
`post-mortem`, `pre-mortem`, `red-team`, `review`, `validate`, `vibe`.

`scan_descriptions.py` flagged 73/81 skills with no trigger marker — a
silent skill-selection risk since runtime discovery is pure LLM
reasoning over the `description` field. The judgment tier ships first
because mis-selection there (e.g. grabbing `review` when you needed
`validate`) is the most costly.

## Why this slice

The bead says *"wave by metadata.tier."* This is one coherent wave = one
PR with a single rollback semantic. Remaining tiers (execution 22,
knowledge 8, meta 8, session 6, background 5, product 5, contribute 4,
cross-vendor 3, library 3, orchestration 1) ship as follow-on waves.

## Evidence

- Corpus missing-trigger count: **73 → 65** (the 8 judgment skills now
pass).
- `python3 skills/skill-builder/scripts/scan_descriptions.py skills
--strict` — all 8 judgment skills report `has_trigger=True`.
- `bash scripts/generate-registry.sh --check` → `OK: registry.json is up
to date` (regenerated, descriptions embedded).
- `markdownlint` clean on all 8 changed SKILL.md files.

## Notes

- Does **not** close ag-okfu — the `--strict` gate stays red until all
tiers are done. Advances the bead; unblocks nothing yet (ag-cx7d ratchet
waits on full corpus clean).

Bounded-context: BC1-Corpus
Evidence: skill-domain-map golden gate
2026-06-06 11:33:18 -04:00
Bo b84dcf3ca2 docs(hookless): close cold-start orientation drift (soc-qh2g1 #cold-start-orientation-coherence) (#795)
## Summary

Close the hookless cold-start orientation gap for `soc-qh2g1` by making
the live startup docs and skills point at explicit `ao session
bootstrap` plus pulled context (`ao inject` / `ao lookup`) instead of
hidden SessionStart behavior.

## Changes

- Reframes live docs that still implied automatic startup/handoff
injection to the hookless explicit-command path.
- Updates source and Codex skill mirrors for `quickstart`, `inject`,
`using-agentops`, `recover`, `bug-hunt`, and `session-bootstrap`.
- Expands the cold-start and docs drift gates so `SessionStart hook`,
`startup hooks`, and `auto-inject ... hook` promises fail unless
explicitly hedged as opt-in, removed, or historical.
- Refreshes scoped Codex skill hashes for the touched mirrors.

## Test plan

- [x] `bash scripts/check-hookless-cold-start.sh`
- [x] `bash scripts/check-doc-hooks-drift.sh`
- [x] `bats tests/scripts/check-hookless-cold-start.bats
tests/scripts/check-doc-hooks-drift.bats`
- [x] `shellcheck scripts/check-hookless-cold-start.sh
scripts/check-doc-hooks-drift.sh`
- [x] `bash scripts/regen-codex-hashes.sh --check --only
session-bootstrap,quickstart,inject,using-agentops,recover,bug-hunt`
- [x] `bash scripts/validate-codex-generated-artifacts.sh`
- [x] `bash scripts/validate-codex-lifecycle-guards.sh`
- [x] `bash scripts/validate-agents-split.sh`
- [x] `git diff --check`
- [x] `bash scripts/validate-skill-runtime-parity.sh`
- [x] `bash scripts/lint-codex-native.sh`

Closes-scenario: soc-qh2g1#cold-start-orientation-coherence
Bounded-context: BC1-Corpus
Evidence: scripts/check-hookless-cold-start.sh
2026-06-06 11:23:56 -04:00
Bo 3bab897009 test(cli): migrate dedup_test.go to t.Chdir + lock isolation ratchet 163->151 (ag-4nif #dedup-tchdir) (#773)
## What

Migrate `dedup_test.go`'s 6 manual `origDir, _ := os.Getwd();
os.Chdir(tmp); defer os.Chdir(origDir)` blocks to Go 1.20+
`t.Chdir(tmp)` — auto-restores cwd **and** refuses `t.Parallel`,
pre-empting the latent flake class flagged by **ag-4nif** / **ag-k38x**
(raw forms mutate process-global cwd). No `t.Parallel` in the file;
behavior-preserving.

Each block held two `os.Chdir(` references (the call + the defer
restore), so 6 blocks drop the repo-wide test-isolation count by **12
(163→151)**. I lowered `BASELINE_CHDIR` in
`scripts/check-test-isolation.sh` to **lock the gain** (the ratchet is
only-goes-down).

## Scope / no-collision note

`os.Chdir` only. The 3 redundant `os.Setenv` restores in
`rpi_reliability_test.go` are **already handled by the open PR #772
(ag-k38x)** — I deliberately do **not** touch that file here, to avoid a
merge collision (an earlier draft of this branch did; it was reverted).
**ag-k38x is the canonical tracker; ag-4nif/ag-y4ac are duplicates** —
worth closing as dup-of-ag-k38x during triage.

## Evidence

```
bash scripts/check-test-isolation.sh        # PASS (os.Chdir=151/151, os.Setenv=22/22)
cd cli
go build ./...                              # OK
go vet ./cmd/ao/                            # No issues found
go test ./cmd/ao/ -run 'TestRunDedup|TestMergeDedupGroups' -count=1   # 17 pass
gofmt -l                                     # clean
```

Net: −19 / +8 across `dedup_test.go` + the ratchet baseline.

Closes-scenario: ag-4nif#dedup-tchdir
Bounded-context: BC5-Runtime
Evidence: ratchet PASS + go build/vet/test (17 pass) + gofmt clean
2026-06-06 11:23:54 -04:00
Bo 2a33a64bb3 chore(ci): CLI surface count regen script + fast pre-flight (ag-lkxx #cli-surface-regen) (#760)
## Summary
- New `scripts/update-cli-surface-counts.sh` with `--check` (default)
and `--fix` modes to synchronize CLI heading counts across the smoke
script and canary matrix JSON
- Wires fast pre-flight count-check into contracts-sync CI (catches
drift in ms before the 180s canary build)
- Adding a new ao CLI command is now: add Go code →
`generate-cli-reference.sh` → `update-cli-surface-counts.sh --fix` →
push

## Test plan
- [x] Script passes in check mode with current counts (75/188/263)
- [x] Script detects simulated drift (exit 1 + clear error message)
- [x] `--fix` mode correctly updates smoke script and matrix JSON
- [x] Fixed files are byte-identical to originals (round-trip verified)
- [x] `bash -n` syntax check passes
- [x] Go build passes in worktree
- [ ] CI contracts-sync passes with new pre-flight step

Closes-scenario: ag-lkxx#cli-surface-regen
Bounded-context: BC5-Runtime
Evidence: scripts/update-cli-surface-counts.sh
2026-06-06 11:23:49 -04:00
Bo 69b8ba0a4f feat(liveness): add inbound admission core (ag-c3c7) (#757)
## Summary
- Add a substrate-neutral inbound admission primitive in
`cli/internal/liveness`.
- Gate inbound work messages by source class and intent: authenticated
operator directives may execute; peer/other-host/tmux directives are
downgraded to proposals and cannot execute reflexively.
- Require ratified quorum authority for quorum-sourced directives, with
cross-model ACK verification for significant actions.
- Extend the liveness composition test so the inbound admission path
composes with role, quorum, judge, and lease primitives.

## Validation
- `go test ./internal/liveness -count=1`
- `go test ./...` from `cli/`
- `PRE_PUSH_FAIL_FAST=false bash scripts/pre-push-gate.sh` ran and
blocked on existing repo/environment gates:
- `test-fixture parity break`: missing pre-push helper Bats stubs for
`scripts/check-author-judge-convergence.sh` and
`scripts/gc-stale-worktrees.sh`
- `worktree disposition`: canonical root `/home/boful/dev/agentops` has
pre-existing dirty/untracked operator state
- `goals validate`: reported `open GOALS.md: no such file or directory`
despite `GOALS.md` existing in this worktree
- `corpus freshness`: newest corpus snapshot is 8d old, over the 7d
threshold
- `contract canaries`: distribution README install-line drift and
pre-push governance Bats failure

Branch-specific gate sections passed, including `go build`, `go vet`,
changed-scope `go test -race`, command/test pairing, mutation-route
guard, author!=judge convergence, and the full `cli` Go test suite
above.

## Review
Cross-model review required before merge. This is not self-graded.

Refs: `ag-c3c7`
2026-06-06 11:19:07 -04:00
Bo 1c2ab1b54e ci: cancel-superseded + parallel bats + union-merge generated files (ag-bdg1) (#800)
## Why
The PR drain became a CI-wait treadmill. A 4-lens council (2026-06-06)
found three non-quorum-sensitive, mutually-reinforcing fixes. (Merge
queue — the obvious answer — is **impossible**: it's org-only and this
is a user-owned repo; strict-up-to-date was relaxed permanently
instead.)

## What
1. **`concurrency` cancel-in-progress (PRs only).** validate.yml had no
concurrency group, so every update-branch/force-push left stale runs
consuming the 20-slot free pool — a self-DoS that produced a 19-deep
queue. Now superseded PR runs cancel; **main/tag pushes never cancel**
(`cancel-in-progress` is false unless pull_request).
2. **4-way parallel bats.** Serial `bats tests/scripts/*.bats` was ~237s
= **55% of the `correctness` critical path**. `--jobs 4
--no-parallelize-within-files` targets ~150s off every run (within-file
order preserved; only independent files run concurrently). Installs GNU
`parallel`.
3. **`.gitattributes merge=union`** on `registry.json`,
`*.agentops-generated.json`, `context-map.md`, `COMMANDS.md` — kills the
O(n²) textual re-conflicts these generated files cause during multi-PR
drains (regen-all restores canonical bytes). `cli/embedded/**` +
`skills-codex/**` stay committed (go:embed / tarball-shipped).

## Risk / trial
Only #2 carries risk (parallel test collisions) — **this PR's own
`correctness` run is the live trial**: if a bats suite collides under
`--jobs 4`, correctness fails here and I drop it. The required-check SET
(`summary`) and its semantics are unchanged, so this is not
quorum-sensitive.

Closes-scenario: ag-bdg1#ci-throughput
Bounded-context: BC5-Runtime
Evidence: .github/workflows/validate.yml
2026-06-06 10:59:53 -04:00
Bo a999bcbe62 fix(embedded): restore emptied standards embeds — main hotfix (ag-arpk follow-up) (#799)
## Main is red — hotfix

`cli/embedded/skills/standards/references/{go,test-pyramid}.md` were
**empty (0 bytes)** on main HEAD; #776's merge truncated them.
`contracts-sync` / `correctness` run the full embedded-sync check on
main-push (changed-files-scoped on PRs, so it slipped through during the
batch drain) → main Validate failed (run on 3df599df, def8fc9b).

## Fix
- Re-synced both embedded files from their sources via the
`cli/Makefile` recipe (`cp ../skills/standards/references/*`).
`scripts/validate-embedded-sync.sh` now reports **All embedded files are
in sync**.
- Corrected that script's stale fix hint: `make sync-embedded` (no such
target) → `make sync-hooks` (the real recipe).

## Evidence
`bash scripts/validate-embedded-sync.sh` → "All embedded files are in
sync."

Bounded-context: BC5-Runtime
Evidence: cli/embedded/skills/standards/references/go.md
2026-06-06 10:51:59 -04:00
Bo 2dbc575ea3 docs(agent-native): add Claude + Codex/NTM runtime reference recipes (ag-ok755 #agent-native-runtime-refs) (#789)
## What

Completes ag-ok755's remaining acceptance: the `agent-native` skill
shipped doctrine-only, missing the two runtime how-to references the
bead requires (linked from SKILL.md per the heal `--strict` rule).

- `references/managed-agents-runtime.md` — **Claude path**: Anthropic
Managed Agents + Agent SDK + self-hosted sandbox. Carries the
three-phase recipe (bundle → expose `ao` → CI-gate), the
planned-mechanism status for `ao agent bundle` (ag-jspr) / `ao mcp
serve` (ag-higd), and the ZDR / no-fork / CI-is-the-gate boundaries.
- `references/codex-ntm-runtime.md` — **Codex/NTM path**: tmux pane
swarms + agent-mail + direct `ao` shell calls (no Managed Agents API),
with the Claude→Codex primitive substitution table.
- Both linked from `SKILL.md` (runtime-recipes pointer + See Also).
- Regenerated derived artifacts: skills-codex source-hash
manifest/marker (source tree changed) and `registry.json`
reference_count (1→3).

## Scope decision

Catalog treatment for `agent-native` stays **`parity_only`** — the codex
artifact is manual-maintained and already tailored (it has a dedicated
Codex/NTM section), and the bespoke override-dir flip is a deliberate
operator TODO in `skills-codex-overrides/catalog.json`. Not
auto-flipping that here (operator judgment).

## Gates run (all green, in-worktree)

- `heal.sh --strict skills/agent-native` — all references linked
- All 7 codex-parity checks: parity audit, generated-artifacts (`--scope
head`), backbone-prompts, override-coverage, runtime-sections,
lifecycle-guards, parity-drift
- `generate-registry.sh --check` — up to date
- `markdownlint-cli2` on all changed/new files — 0 errors

Closes-scenario: ag-ok755#agent-native-runtime-refs
Bounded-context: BC5-Runtime
Evidence: skills/agent-native/SKILL.md
2026-06-06 10:45:10 -04:00
Bo def8fc9bd4 chore(doctor): drop dead ao agentopsd/GasCity strings (ag-9hhm #dead-text-removed-surfaces) (#793)
## What

Two dead-text remnants pointed operators at **retired surfaces**
(discovered in the 2026-06-03 feature-map analysis). Pure string hygiene
— no behavior change.

1. **`cli/internal/doctor/fix_bridges.go`** — `openclawHealthReport` and
`snapshotStaleReport` instructed `ao agentopsd start/status/restart` and
`ao agentopsd projection rebuild --consumer openclaw`. The in-repo
daemon was **removed (ADR-0009)** and no such command exists. Reworded
to: bring the OpenClaw daemon up out-of-band / regenerate the projection
from the out-of-session substrate, naming the daemon removal instead of
a dead command. (Also fixed two stale code comments naming `agentopsd`.)
2. **`cli/cmd/ao/forge.go:43`** — the `--legacy-local-llm` deprecation
warning named *"AgentWorker/GasCity-backed Codex or Claude workers"*.
Gas City was pruned (ag-124p) and the GasCity worker adapter removed.
Reworded to point at a **Dream worker queue** (consistent with the
existing language elsewhere in `forge.go`).

## Why

These strings mislead operators toward commands/substrates that no
longer exist; the `gc`/`agentopsd` prune was code-clean but the
user-facing strings survived.

## Verification

- `gofmt` clean; `go build ./...`; `go vet ./internal/doctor/ ./cmd/ao/`
- `go test ./internal/doctor/` → 76 passed; `go test ./cmd/ao/ -run
Forge` → 379 passed
- `git grep "ao agentopsd"` / `GasCity` over live (non-test) code in
touched files → empty
- Updated the two doctor tests that asserted the old substrings.

Closes-scenario: ag-9hhm#dead-text-removed-surfaces
Bounded-context: BC5-Runtime
Evidence: cli/internal/doctor/fix_bridges_test.go
2026-06-06 10:17:48 -04:00
Bo 3df599df75 fix(ao): case-insensitive dedup in pool_ingest candidate IDs (soc-xn5s #dedup-case-insensitive) (#792)
## What

`buildCandidateFromLearningBlock` (cli/cmd/ao/pool_ingest.go) dedups the
three ID
components (`base`, `sessionHint`, `learningID`). `learningID` is
lowercased before
the check, but `base`/`sessionHint` keep their source-filename case. So
any source
filename with an uppercase character (e.g.
`2026-04-30-fix20260430T090800-1.md`)
**skipped** the `strings.Contains` dedup branch and produced a
**doubled** candidate ID:

```
pend-2026-04-30-fix20260430t090800-1-ag-test-fix20260430t090800-1   (id appears twice)
```

The final ID is lowercased by `Slugify` anyway, so the comparisons
should be
case-insensitive. Fix normalizes both sides of the equality/`Contains`
checks for
`base`↔`sessionHint` and `joined`↔`learningID`.

## Why it mattered

Verified live 2026-04-30 (soc-xn5s): a mixed-case source filename
re-amplified its
ID on each close-loop pass. Production residue was all-lowercase so
unaffected, but
the edge case remained uncovered.

## Test

Two regression subtests in
`TestPoolIngest_buildCandidateFromLearningBlock` reproduce
the exact doubled ID and the mixed-case session-hint duplication. Both
fail against the
old code, pass with the fix:

```
--- FAIL .../mixed-case_filename_does_not_double_the_learning_id
    learning id token "fix20260430t090800-1" appears 2 times ... want exactly 1
--- FAIL .../mixed-case_session_hint_matching_base_is_not_appended
    session hint token appears 2 times ... want exactly 1
```

`go build ./...`, `go vet ./cmd/ao/`, `gofmt -l` all clean.

Closes-scenario: soc-xn5s#dedup-case-insensitive
Bounded-context: BC1-Corpus
Evidence:
cli/cmd/ao/pool_metrics_test.go::TestPoolIngest_buildCandidateFromLearningBlock

🤖 Autonomous factory tick.
2026-06-06 10:17:45 -04:00
Bo cfcca74773 fix(scripts): port skill-catalog generator off gawk-only awk -v (ag-mm6q #bsd-awk-portability) (#784)
## What

`scripts/generate-skill-catalog.sh` passed the YAML frontmatter into awk
via `awk -v fm="$fm"`. A literal newline inside a `-v var=value`
assignment is accepted **only by GNU awk**; BSD/POSIX awk (macOS without
gawk) errors with `awk: newline in string ...` and emits no catalog — so
the catalog (and its drift gate `check-skill-catalog-drift.sh`) could
only run inside Linux CI.

## Fix

Feed the frontmatter on **stdin** and accumulate input lines into
`lines[]` (processed in `END` exactly as before) instead of `-v` +
`split()`. Pure input-mechanism change — the parse logic is untouched.

## Evidence (macOS BSD awk, version 20200816)

- **Before:** `bash scripts/generate-skill-catalog.sh --stdout` → `awk:
newline in string name: agent-native` (no output).
- **After:** valid JSON for all 81 skills; lists, `context_rel`, and
quoted descriptions parse correctly (e.g. `deps` → `context_rel: [{kind:
supplier-to, with: vibe}]`, matching the source SKILL.md).
- Added an explicit BSD/POSIX-awk regression test (`multi-line
frontmatter parses ... without 'newline in string'`). Full bats suite
**15/15 green** on macOS.
- `shellcheck` clean.

## Scope note

The committed `skills/catalog.json` is **independently stale** (75 vs 81
skills — drift predates this change, since the generator never ran
off-Linux). Regenerating it is deliberately left to the Linux-CI drift
path (the `check skill catalog drift` job is **I0 advisory /
non-blocking**) to avoid committing a glob-order-sensitive artifact
generated off-CI.

Closes-scenario: ag-mm6q#bsd-awk-portability
Bounded-context: BC2-Validation
Evidence: tests/scripts/generate-skill-catalog.bats
2026-06-06 10:17:42 -04:00
Bo f4f991bbda docs: fix broken intra-repo links in docs/ (ag-28dp #docs-link-rot) (#781)
## What

Fix 44 broken intra-repo links across 7 files under `docs/`, surfaced by
a `docs/` markdown link audit. `mkdocs.yml` has `strict: false`, so the
broken links slipped past CI — but they break GitHub-raw viewing and
agent file-reading (the repo treats pointer rot in base docs as a
defect).

## Two pointer-rot classes

1. **41× `](skills/<name>.md)` → `](../skills/<name>/SKILL.md)`** —
skills live at `skills/<name>/SKILL.md`, never `skills/<name>.md`, and
`docs/` is one level deep so the target needs `../`. Several links
already had the **correct link text** (e.g.
`[skills/pre-mortem/SKILL.md](skills/pre-mortem.md)`) — only the href
was wrong, confirming intent. Special case: `skills/catalog.md` →
`SKILLS.md` (`docs/SKILLS.md` = the complete 82-skill reference).
2. **3× `](cli/commands.md)` → `](../cli/docs/COMMANDS.md)`** — the
generated CLI command doc.

Files: `GLOSSARY.md`, `index.md`, `context-lifecycle.md`,
`behavioral-discipline.md`, `create-your-first-skill.md`,
`context-packet.md`, `software-factory.md`.

**Not touched:** the intentional placeholder links in
`docs/standards/markdown-style-guide.md` (syntax demos: `url`,
`image.png`, `./other-doc.md`, etc.).

## Verification

- `docs/` broken-link scan: **44 → 0** outside the style-guide
placeholders.
- `markdownlint-cli2` on all 7 files: **0 errors**.
- Pure link-href changes (44 insertions / 44 deletions); no prose or
behavior change.

Closes-scenario: ag-28dp#docs-link-rot
Bounded-context: BC1-Corpus
Evidence: ag-28dp
2026-06-06 10:17:39 -04:00
Bo 93bc54d401 fix(goals): drop unresolved heuristic scenario claims to kill prose false positives (soc-artx7 #orphans-prose-false-positive) (#779)
## What

`ao goals trace --orphans` reported **7 `broken_bead_scenario_claim`
warnings that were false positives** — bead-description prose mis-read
as scenario references. All 7 were multi-segment `auto-` slugs
(`auto-merge-update-branch`, `auto-safe-pull`, `auto-picks-up`,
`auto-regen-on-skill-change`, …) that match the heuristic free-text
token grammar but are lexically **indistinguishable** from genuine
auto-generated scenario IDs like `auto-nightly-evolution-dry-run`. No
regex can separate them — the only real discriminator is **resolution**
(does the token name an actual `spec/scenarios/<id>.json` or
`.agents/holdout/<id>.json` file?).

## Fix

`emitBeadClaimEdges` now drops heuristic (free-text) claims that resolve
to no scenario file *before* emitting an edge: a token matching the slug
grammar but naming no real scenario is prose, not a claim. This aligns
with ADR-0005 §4.1 — **only explicit `Scenarios:`-line claims are
defects.** Explicit claims are untouched: a broken explicit link stays
an **error**.

## Evidence (live repo, before → after)

| class | old | fixed |
|---|---|---|
| `broken_bead_scenario_claim` | **7** | **0** |
| `no_learning_yield` | 15 | 15 |
| `scenario_no_bead_claim` | 14 | 14 |

Surgical: only the 7 prose false positives drop; every other warning
class is unchanged. Acceptance ("`ao goals trace --orphans` returns 0
`broken_bead_scenario_claim` on current main, no false positives from
bead prose") met. This unblocks promoting `trace --orphans` to a
required gate.

## Tests

- `go test ./internal/goalstrace/...` — 78 pass (incl. new
`TestWalk_MultiSegmentProseAutoSlugProducesNoClaim` regression).
- Existing heuristic/explicit contract tests stay green; `gofmt`/`go
vet` clean.

Closes-scenario: soc-artx7#orphans-prose-false-positive
Bounded-context: BC5-Runtime
Evidence: cli/internal/goalstrace/beads_test.go
2026-06-06 10:17:36 -04:00
Bo 9af54d589a feat(corpus): per-session corpus-reuse receipt at session close (ag-469h #corpus-reuse-receipt) (#778)
## What

Makes the knowledge-flywheel moat **felt**. `ao session close` now
renders a per-session **corpus-reuse receipt**: a `Reused: N` table line
plus a loud `♻ Compounding: reused N prior learnings (titles…); corpus
now X entries` line. Closes the perception gap behind bead **ag-469h** —
users perceive the WRITE tax every session but never the READ payoff, so
they churn before the aha.

## How

- `computeReuseReceipt(cwd, sessionID)` reads
`.agents/ao/citations.jsonl` (via `ratchet.LoadCitations`), filters to
the closing session, dedupes by canonical artifact path, and excludes
`reference` (manual-pointer) citations — counting only
`retrieved`/`applied` read-payoffs.
- Corpus size counts durable `.md` under `.agents/{learnings,patterns}`.
- New `SessionCloseResult` fields
`Reused`/`ReusedTitles`/`CorpusEntries` (all `omitempty`, so JSON output
is backward-compatible).
- Best-effort: a missing ledger or corpus yields a zero receipt and
never fails the close. Cold runs print nothing.
- No new CLI command (avoids the surface-matrix canary churn documented
in ag-lkxx) — purely additive output on an existing command.

## Test

`cli/cmd/ao/session_close_receipt_test.go` — dedup, cross-session
isolation, reference-exclusion, empty/no-ledger zero-receipt,
singular-noun, cold-run silence, date-prefix title stripping, and
`printCloseTable` integration. Full `cmd/ao` suite green (`go test`/`go
vet`/`gofmt` clean).

Closes-scenario: ag-469h#corpus-reuse-receipt
Bounded-context: BC1-Corpus
Evidence: cli/cmd/ao/session_close_receipt_test.go
2026-06-06 10:17:33 -04:00
Bo 0dfac4a9bd chore(standards): guard-test fixtures must use the real persisted shape (ag-jwtx #test-standard-names-real-shape-requirement) (#776)
## What

Encodes a test standard from **ag-jwtx**:
skip/dedup/consumed/idempotency/regression **guard tests must build
fixtures from the real persisted data shape** — round-trip a real sample
(production writer → reader) or assert against a checked-in real example
— never a hand-built in-memory constructor that sets a marker at a
granularity the on-disk format never emits.

## Why

`ag-mjlg` (PR #652) shipped a next-work materialize over-creation bug
(44 vs 16) green because `TestNextWorkMaterialize_SkipsConsumed` set
`consumed` at the **per-item** level while real `next-work.jsonl` marks
it at the **batch** level. The guard exercised a shape production never
produces → false green. This converts that one-off into a durable
standard + a pre-mortem flag (catch→encode→never-repeat).

## Changes (docs/standards only)

- `skills/standards/references/test-pyramid.md` — new **Fixture
Fidelity** section (the standard + how-to-comply + the pre-mortem flag).
- `skills/standards/references/go.md` + `.claude/rules/go.md` —
Test-Conventions bullet (kept in parity).
- `skills/pre-mortem/references/mandatory-checks.md` — two flags added
to the **Test Pyramid Coverage Check (Mandatory)** table.

## Verification

- `markdownlint --config .markdownlint.json` on all four files: clean.
- `scripts/generate-registry.sh --check`: registry up to date (no new
reference files; existing files edited).
- Docs-only; no code paths touched.

## Scenario

> Given the AI-native test-shape standard doc, when an agent writes a
skip/dedup/consumed guard test, then the standard requires the fixture
to come from a round-tripped real persisted sample, and a
pre-mortem/checklist item flags item-level-only fixtures for batch-level
state.

Closes-scenario: ag-jwtx#test-standard-names-real-shape-requirement
Bounded-context: BC1-Corpus
Evidence: skills/standards/references/test-pyramid.md
2026-06-06 10:17:30 -04:00
Bo bc9a846dbd feat(eval): ao eval outcomes ingest --manifest-out emits eval-run.v1 manifest (ag-fy6e #manifest-out-eval-run) (#774)
## What

Adds `--manifest-out <dir>` (+ `--run-id`) to `ao eval outcomes ingest`.
When set, ingest **also** writes `<dir>/<run-id>/manifest.json`
conforming to `schemas/eval-run.v1.schema.json`, so the existing verdict
pipeline (`docs/contracts/eval-verdict-pipeline.md`) can pick it up and
feed the Knowledge Flywheel — closing the **Outcomes→Flywheel loop** for
the eval-run.v1 surface. Bead: **ag-fy6e**.

## How

- New file `cli/cmd/ao/eval_outcomes_manifest.go` (diversifies off
`eval_outcomes_ingest.go`); ingest.go only wires the thin flag.
- Reuses the existing `eval.RunRecord` struct rather than hand-rolling
the schema shape.
- Band mapping: `PASS→{status:pass, verdict:pass}`, `FAIL→{fail, fail}`,
`WARN→{inconclusive, advisory}`.
- `dimension_scores` filtered to the 7 schema-permitted keys (foreign
criterion dropped; `minProperties:1` guarded by synthesizing
`correctness=aggregate`).
- Out-of-process grade → honest schema-valid stubs for
`git`/`runtime`/`environment` + a `notes` provenance entry.

## Deviation from bead text (source-of-truth precedence)

The bead said `status=complete`, but that value belongs to the **other**
SCHEMA.md run-manifest. eval-run.v1's `status` enum is
`pass/fail/error/skipped/inconclusive` — no `complete` member — so this
follows the schema (per CLAUDE.md precedence: executable contracts >
narrative).

## Scope boundary (honest)

This delivers **only** the eval-run.v1 emission named in the bead's
ACCEPTANCE CRITERIA. The downstream `eval-verdict-compiler.sh` /
SCHEMA.md run-manifest path (rc3 struct verdict + holdout-sensitive
`ground_truth_ref/hash`) remains **BLOCKED** on the external compiler
contract + a holdout-safety decision, per the bead's own 2026-05-30
SCOUT CORRECTION. eval-run.v1 carries no holdout-sensitive fields, so
that blocker does not apply to this slice. Bead left open for the
compiler-path follow-up.

## Verification

- `go build ./... && go vet ./cmd/ao/` clean
- 77 eval/outcomes tests pass (`go test ./cmd/ao/ -run 'Eval|Outcomes'`)
- Real CLI run writes a manifest that validates against
`eval-run.v1.schema.json` via python `jsonschema`
- `cli/docs/COMMANDS.md` regenerated for the two new flags

Closes-scenario: ag-fy6e#manifest-out-eval-run
Bounded-context: BC2-Validation
Evidence: cli/cmd/ao/eval_outcomes_manifest_test.go
2026-06-06 10:17:25 -04:00
Bo 7265fda1b1 chore(test): migrate redundant os.Setenv to t.Setenv; lower isolation ratchet 22->12 (ag-k38x #bulk-migration-setenv) (#772)
## What

Advances the test-isolation ratchet (`scripts/check-test-isolation.sh`,
shipped in #699) by driving the `os.Setenv` baseline from **22 → 12**.
Pure test-hygiene; no production-code change.

`t.Setenv` auto-restores on cleanup **and** fails fast under
`t.Parallel` — the raw `os.Setenv` form is the latent-flake landmine the
ratchet exists to retire (cf. ag-jfzs).

## Sites migrated (10 eliminated)

| File | Δ | How |
|---|---|---|
| `internal/config/config_test.go` | -6 | Collapse the `origX :=
os.Getenv(...)` + `defer os.Setenv(... restore)` block into 3×
`t.Setenv` |
| `internal/goals/measure_test.go` | -1 | Delete the redundant
`origPath`/`defer os.Setenv` — the existing `t.Setenv("PATH","")`
already auto-restores |
| `cmd/ao/rpi_reliability_test.go` | -3 | Delete 3 redundant
restore-defers wrapped around existing `t.Setenv` calls |

## The remaining 12 are intentional (not migratable)

Documented inline in the ratchet script. They cannot use `t.Setenv`:
- **TestMain** (`cmd/ao/main_test.go`,
`internal/doctor/doctor_testmain_test.go`) — no `*testing.T` in scope
(4)
- **String-literal fixtures** (`internal/doctor/fix_cliconfig_test.go`)
— `os.Setenv` appears inside generated test-program source, not a real
call (2)
- **Unset-semantics helpers** (`cmd/ao/handoff_test.go`,
`internal/lifecycle/repo_readiness_test.go`,
`internal/wiki/locator_test.go`) — these `os.Unsetenv`+restore vars;
`t.Setenv` has no unset form (6)

## Verification

- `bash scripts/check-test-isolation.sh` → `PASS … os.Setenv=12/12`
- `go build ./...` ✓ · `go vet` (touched pkgs) ✓
- `go test ./internal/config/ ./internal/goals/` → 526 passed; touched
cmd/ao tests → 3 passed

Closes-scenario: ag-k38x#bulk-migration-setenv
Bounded-context: BC5-Runtime
Evidence: scripts/check-test-isolation.sh PASS 12/12
2026-06-06 10:17:21 -04:00
Bo ba2d0380b2 feat(eval): holdout-leak key-name backstop for outcomes compile (ag-uux93 #holdout-key-guard) (#770)
## What

Adds the key-name leak backstop that **ag-uux93** explicitly calls for
on `ao eval outcomes compile`: re-parse the emitted Outcomes rubric
payload and refuse any object key (at any depth) matching
`/target|ground_truth|expected_output|answer/i`.

## Why

The compile command itself already shipped (under sibling **ag-hdqu0** /
#601) with a value-based guard (`ContainsAny` scans for known holdout
*values* — layer 3). ag-uux93 additionally requires a **structural
key-name** backstop: "re-parse the emitted payload and assert no key
matches `/target |ground_truth|expected_output|answer/i`; abort +
non-zero exit if found."

This is **additive defense-in-depth** at a load-bearing boundary —
Managed Agents are not ZDR, so a holdout leak across the cloud boundary
is permanent. The allowlisted `Rubric` struct can't carry such a key
today; the guard *pins that invariant* so a future field that smuggles
ground truth fails closed instead of leaking silently.

## Changes

- `evalsubstrate.ScanForbiddenKeys(payload []byte)` — walks decoded JSON
for leak keys at any nesting depth
- `Rubric.HasForbiddenKey()` — marshals + scans (mirrors the existing
`ContainsAny`)
- Wired into `compileOutcomesRubric` after the value-scan, before return
(structured non-zero error on hit)
- Unit tests: positive (nested / case-insensitive / substring), clean
rubric, unparseable input, allowlist-by-construction invariant

## Verification

`cd cli && go build ./... && go vet ./... && go test` — build + vet
clean; evalsubstrate 92 pass, cmd/ao outcomes/rubric 30 pass; gofmt
clean.

## Scope note for maintainer

ag-uux93's spec also describes a `--suite/--split/--out` **flag
interface** reading locked YAML from `~/.agents/evals/`. The shipped
#601 command deliberately took a **JSON-input** design (`ao eval
outcomes compile <input.json>`) instead. I did **not** unilaterally
rewrite that working interface in an unattended tick — that's an
intentional design fork needing your call. Queued to `bo-queue`. This PR
closes only the `#holdout-key-guard` scenario.

Closes-scenario: ag-uux93#holdout-key-guard
Bounded-context: BC4-Evals
Evidence: cli/internal/evalsubstrate/holdout_guard_test.go
2026-06-06 10:17:18 -04:00
Bo 22543558a4 refactor(cli): convert beads verdict os.Exit calls to typed exit-error (ag-x22j #beads-exit-as-typed-error) (#769)
## What

`ao beads verify|lint|audit` used exit-code-as-verdict but signalled it
by calling `os.Exit(1)` **inside** RunE. `os.Exit` skips deferred
cleanup (temp files, lock release) and kills the test binary, so the
verdict branches were untestable.

This converts the 3 sites to return a typed `*beadsExitError`, which
`Execute()` maps to the process exit code at the single root exit point
— the established CLI idiom (mirrors `gateExitError` in `validate.go`
and `doctorExitError` in `doctor_surface.go`).

## Sites converted
- `runBeadsVerify` (`beads.go`) — stale citations → exit 1
- `runBeadsLint` (`beads.go`) — stale beads → exit 1
- `runBeadsAudit` (`beads_audit_cluster.go`) — `--strict` + flagged →
exit 1

## How
- New `beadsExitError{code}` type (`Error()` empty, `ExitCode()`), since
the verdict text already went to stdout.
- The returning RunE sets `cmd.SilenceErrors` (nil-guarded) so cobra
prints no spurious `Error:` line; **genuine** errors returned elsewhere
in those commands still print normally.
- `Execute()` gains a `beadsExitError` branch before the generic
fallback.

## Evidence
- `cli/cmd/ao/beads_exit_test.go` — pins the verdict contract: verify +
lint stale → `*beadsExitError` exit 1 + `SilenceErrors`; clean → nil;
nil-cmd no panic.
- `cd cli && go build ./... && go vet ./cmd/ao/` clean; `gofmt -l`
clean.
- Full `go test ./cmd/ao/` → **9314 passed**.

## Bead
`ag-x22j` (P3, child of the Go idiomatic audit `ag-tcf0`). No more
`os.Exit` outside `main`/root in the beads command paths.

Closes-scenario: ag-x22j#beads-exit-as-typed-error
Bounded-context: BC5-Runtime
Evidence: cli/cmd/ao/beads_exit_test.go
2026-06-06 10:17:15 -04:00
Bo cb8161c806 feat(ratchet): enforce R3 'no learning without a constraint' as a script gate (ag-maaa #r3-constraint-gate) (#768)
## What

Makes the Brownian-Ratchet rule **R3 — "no learning without a
constraint"** self-enforcing. Previously it was prose only
(`docs/architecture/operating-loop.md` promotion table: *"Must never
regress → add a validation gate"*): a learning could be promoted to a
durable maturity tier without ever compiling into a gate/test/rule. The
mechanism existed (`cli/internal/ratchet/`) but R3 was a manual operator
decision with no check.

## How

`scripts/check-ratchet-r3-constraint.sh` scans the learnings corpus and
flags any **durable-tier** learning
(`candidate`/`established`/`canonical`/`stable`/`promoted`) that cites
**no constraint** — a `scripts/`/`.github/workflows/` gate, a
`_test.go`/`tests/` reference, a `skills/**/SKILL.md` step, or a
`constraint:`/`enforced_by:` frontmatter field. Provisional learnings
are exempt (still forming).

- **Warn-first → blocking**, mirroring the ratchet's own warn-then-fail
ladder: warn-only by default (exit 0); `--strict` or
`RATCHET_R3_BLOCKING=true` makes the same gaps blocking (exit 1).

## Why a script, not a CI path-filter gate

`.agents/learnings/**` is **gitignored** (0 tracked). A CI path-filter
gate on it would be dead-by-design — the exact reason the
`learning-coherence` CI job was retired (2026-05-19). So R3 runs at
ratchet/flywheel time against the **live local corpus**; the script's
own correctness is gated in CI by the committed bats test
(`tests/scripts/*.bats` runs in `validate.yml`).

## Verification

- `tests/scripts/check-ratchet-r3-constraint.bats` — 11 hermetic tests
on a synthetic fixture (warn-first, --strict, env-var parity,
provisional exemption, empty-field rejection, gate/test/SKILL citation
forms, count accuracy). All pass.
- `shellcheck` clean.
- Dry-run against the real local corpus: 639 scanned, 7 durable-tier, 5
flagged — warn-only, exit 0 (honest; does not break on existing corpus).

Closes-scenario: ag-maaa#r3-constraint-gate
Bounded-context: BC1-Corpus
Evidence: tests/scripts/check-ratchet-r3-constraint.bats
2026-06-06 10:17:12 -04:00
Bo c0dc6cbd52 docs(architecture): AgentPod/SwarmJob/watch-event schema PROPOSAL (ag-egpu.1 #factory-api-schema) (#766)
## What

New doc `docs/architecture/agentpod-swarmjob-schema.proposal.md` — the
**schema-level design** for one-way-door #2 (`ag-egpu.1`). It
operationalizes the two deltas the architecture spine
`docs/architecture/the-agent-factory.md` (`ag-yv25`, cross-model
reviewed 2026-06-05) names for door #2: (a) AgentPod-spec +
SwarmJob-spec on the bead, (b) watch/event surface.

**PROPOSAL only** — no schema in `schemas/` changes, no migration. The
doc is the artifact the council ratifies before `ag-v1xk` / `ag-xanm` /
`ag-7dnb` code against the API.

## Supersedes PR #765

My first attempt (#765) branched ~80 commits behind and added a
competing `the-agent-factory.md`, colliding with the canonical spine
that already landed on main. This PR is re-homed to a non-colliding
path, **defers to the spine** for architecture, and aligns to its
vocabulary (AgentPod / SwarmJob / Oracle / anti-affine / Volume-tier).
Closing #765 in favor of this.

## Design (additive, reuses not forks)

- **agentpod-spec.v1** = `worker-spec.v1` (already a Pod template) **+**
`function` (Planner/Generator/Oracle/Scribe — product layer, not RBAC
churn) + `anti_affinity.model_family` (the membrane as a scheduling
constraint) + `volume_tier`.
- **swarm-job.v1** = typed Pod composition on a bead + a **cost-law
derivation rule** (reversible bead → 1 Generator + 1 Oracle pre-check;
one-way-door bead → ≥2 anti-affine Oracles = real quorum). Makes the ≤12
cap a schema field.
- **`bead.*` events** = additive enum on `watch-event.v1`
(`additionalProperties:true`, non-breaking) so the reconcile controller
watches bead state instead of polling `bd ready`.

## Decisions for council (in-doc)

1. AgentPod/SwarmJob binding: bead **metadata projection** (rec,
reversible) vs. first-class `bead.v1` field.
2. SwarmJob **beside** (rec) vs. merged with
`swarm-evidence`/`orchestration-result` (input vs. output contracts).
3. `bead.*` emitter: **`bd` write-path** (rec, crash-safe) vs. `ao` Dolt
tail.
4. `function` is product-layer only; `roles.go` RBAC unchanged.

## Evidence

- New doc: `docs/architecture/agentpod-swarmjob-schema.proposal.md` (158
lines, PROPOSAL-stamped).
- Reconciles:
`schemas/{worker-spec.v1,watch-event.v1,bead.v1,quest.v1,remote-compute-target}.schema.json`.

Advances ag-egpu.1; does **not** close it (closes on council
ratification — gated). Do not auto-merge.

Bounded-context: BC5-Runtime
Evidence: docs/architecture/agentpod-swarmjob-schema.proposal.md
2026-06-06 10:17:08 -04:00
Bo ca172387f9 docs(contracts): single declared gate-runner discipline (ag-8rns #gate-runner-contract) (#755)
## What

Encode the **"run the full declared gate, never a remembered subset"**
rule into the two loop-execution contracts, so autonomous consumers
(`/evolve` Step 5, `/rpi` validation) stop reconstructing the validation
bundle from memory.

- **`docs/contracts/autodev-program.md`** — new **Gate Runner
Discipline** section + a `Validation Commands` note. The bundle is run
via a single canonical runner (a repo gate script, or per gate the typed
BC2 `GateRunnerPort` surfaced as `ao gate run <name>`), in full,
**fail-closed**; a slice is "validated" only once the full declared gate
ran and passed.
- **`docs/contracts/repo-execution-profile.md`** — `validation_commands`
runs as a unit via the canonical runner; lane-narrowing is **declared**
(`validation_lanes`), never recalled; fail-closed; cross-link to the
autodev contract.

## Why

Origin (in the bead notes): 2026-06-04 a `/evolve` cycle ran a
**subset** of its declared validation bundle (skipped `PROGRAM.md`
grounding greps), reported slices green, and an independent `/validate`
caught the red. Generic failure mode: a loop that rebuilds its gate from
prose eventually runs a subset. This is the **contract** defense; it
aligns the docs to the already-shipped `ao gate`/`GateRunnerPort`.

## Scope / non-scope

- **This PR = the docs-contract (substrate) half of ag-8rns.**
Verified-cold surface (no active worktree touches these two files).
- **Deferred:** the `skills/evolve` Step-5 wiring is a **hot** surface
(live `ag-llni` delete-evolve-CLI + `ag-ro1i` evolve-backport branches)
— left to those branches to avoid collision. **Bead stays OPEN.**

## Validation

- Diff is docs-only (+21/-2). markdownlint clean; `mkdocs strict build`,
`doc-release gate`, `executable-spec link integrity`, `context map
drift` all **ok** locally.
- Local omnibus `pre-push-gate.sh` reported pre-existing substrate reds
(contract-canaries eval/bats, `context-packet-ab-wave0` off=fail
[known-expected A/B state], baseline-audit policy mismatch). **Verified
pre-existing:** pristine `origin/main` passes
`tests/scripts/pre-push-gate.bats` 56/56 (exit 0); none are reachable
from a `docs/contracts/*.md` change.

Closes-scenario: ag-8rns#gate-runner-contract
Bounded-context: BC3-Loop
Evidence: docs/contracts/autodev-program.md
2026-06-06 10:17:03 -04:00
dependabot[bot] edb6dd4186 deps(actions): bump actions/setup-node from 4 to 6 (#678)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4
to 6.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/setup-node/releases">actions/setup-node's
releases</a>.</em></p>
<blockquote>
<h2>v6.0.0</h2>
<h2>What's Changed</h2>
<p><strong>Breaking Changes</strong></p>
<ul>
<li>Limit automatic caching to npm, update workflows and documentation
by <a
href="https://github.com/priyagupta108"><code>@​priyagupta108</code></a>
in <a
href="https://redirect.github.com/actions/setup-node/pull/1374">actions/setup-node#1374</a></li>
</ul>
<p><strong>Dependency Upgrades</strong></p>
<ul>
<li>Upgrade ts-jest from 29.1.2 to 29.4.1 and document breaking changes
in v5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/setup-node/pull/1336">#1336</a></li>
<li>Upgrade prettier from 2.8.8 to 3.6.2 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/setup-node/pull/1334">#1334</a></li>
<li>Upgrade actions/publish-action from 0.3.0 to 0.4.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/setup-node/pull/1362">#1362</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/setup-node/compare/v5...v6.0.0">https://github.com/actions/setup-node/compare/v5...v6.0.0</a></p>
<h2>v5.0.0</h2>
<h2>What's Changed</h2>
<h3>Breaking Changes</h3>
<ul>
<li>Enhance caching in setup-node with automatic package manager
detection by <a
href="https://github.com/priya-kinthali"><code>@​priya-kinthali</code></a>
in <a
href="https://redirect.github.com/actions/setup-node/pull/1348">actions/setup-node#1348</a></li>
</ul>
<p>This update, introduces automatic caching when a valid
<code>packageManager</code> field is present in your
<code>package.json</code>. This aims to improve workflow performance and
make dependency management more seamless.
To disable this automatic caching, set <code>package-manager-cache:
false</code></p>
<pre lang="yaml"><code>steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
  with:
    package-manager-cache: false
</code></pre>
<ul>
<li>Upgrade action to use node24 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/setup-node/pull/1325">actions/setup-node#1325</a></li>
</ul>
<p>Make sure your runner is on version v2.327.1 or later to ensure
compatibility with this release. <a
href="https://github.com/actions/runner/releases/tag/v2.327.1">See
Release Notes</a></p>
<h3>Dependency Upgrades</h3>
<ul>
<li>Upgrade <code>@​octokit/request-error</code> and
<code>@​actions/github</code> by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/setup-node/pull/1227">actions/setup-node#1227</a></li>
<li>Upgrade uuid from 9.0.1 to 11.1.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/setup-node/pull/1273">actions/setup-node#1273</a></li>
<li>Upgrade undici from 5.28.5 to 5.29.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/setup-node/pull/1295">actions/setup-node#1295</a></li>
<li>Upgrade form-data to bring in fix for critical vulnerability by <a
href="https://github.com/gowridurgad"><code>@​gowridurgad</code></a> in
<a
href="https://redirect.github.com/actions/setup-node/pull/1332">actions/setup-node#1332</a></li>
<li>Upgrade actions/checkout from 4 to 5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/setup-node/pull/1345">actions/setup-node#1345</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/priya-kinthali"><code>@​priya-kinthali</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/setup-node/pull/1348">actions/setup-node#1348</a></li>
<li><a href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/setup-node/pull/1325">actions/setup-node#1325</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/setup-node/compare/v4...v5.0.0">https://github.com/actions/setup-node/compare/v4...v5.0.0</a></p>
<h2>v4.4.0</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/setup-node/commit/48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e"><code>48b55a0</code></a>
Update Node.js versions in versions.yml and bump package to v6.4.0 (<a
href="https://redirect.github.com/actions/setup-node/issues/1533">#1533</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/ab72c7e7eba0eaa11f8cab0f5679243900c2cac9"><code>ab72c7e</code></a>
Upgrade <a href="https://github.com/actions"><code>@​actions</code></a>
dependencies (<a
href="https://redirect.github.com/actions/setup-node/issues/1525">#1525</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/53b83947a5a98c8d113130e565377fae1a50d02f"><code>53b8394</code></a>
Bump minimatch from 3.1.2 to 3.1.5 (<a
href="https://redirect.github.com/actions/setup-node/issues/1498">#1498</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/54045abd5dcd3b0fee9ca02fa24c57545834c9cc"><code>54045ab</code></a>
Scope test lockfiles by package manager and update cache tests (<a
href="https://redirect.github.com/actions/setup-node/issues/1495">#1495</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/c882bffdbd4df51ace6b940023952e8669c9932a"><code>c882bff</code></a>
Replace uuid with crypto.randomUUID() (<a
href="https://redirect.github.com/actions/setup-node/issues/1378">#1378</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/774c1d62961e73038a114d59c8847023c003194d"><code>774c1d6</code></a>
feat(node-version-file): support parsing <code>devEngines</code> field
(<a
href="https://redirect.github.com/actions/setup-node/issues/1283">#1283</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/efcb663fc60e97218a2b2d6d827f7830f164739e"><code>efcb663</code></a>
fix: remove hardcoded bearer (<a
href="https://redirect.github.com/actions/setup-node/issues/1467">#1467</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/d02c89dce7e1ba9ef629ce0680989b3a1cc72edb"><code>d02c89d</code></a>
Fix npm audit issues (<a
href="https://redirect.github.com/actions/setup-node/issues/1491">#1491</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/6044e13b5dc448c55e2357c09f80417699197238"><code>6044e13</code></a>
Docs: bump actions/checkout from v5 to v6 (<a
href="https://redirect.github.com/actions/setup-node/issues/1468">#1468</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/8e494633d082d609d1e9ff931be32f8a44f1f657"><code>8e49463</code></a>
Fix README typo (<a
href="https://redirect.github.com/actions/setup-node/issues/1226">#1226</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/setup-node/compare/v4...v6">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bo <boden.fuller@gmail.com>
2026-06-06 10:17:00 -04:00
Bo d47faa9b09 docs(readme): surface 12factoragentops.com up top; drop dead Pages link (#798)
Surfaces the methodology site at the top of the README (newcomer line)
and removes the dead `boshu2.github.io/agentops/` link from the docs row
— that Pages site was unbuilt (`status: null`) and has now been
disabled, so 12factoragentops.com is the canonical home. The doctrine
link in that row already points there.
2026-06-06 10:16:45 -04:00
Bo 5995beb417 docs(doctrine): reconcile 3.0.md tooling-floor wording with the bd/git floor (ag-60jd #tooling-floor-reconcile) (#790)
## What

`docs/3.0.md:168` (Non-goals) read **"No new required tooling; `bd`, the
ratchet, and the `ao` CLI carry the load,"** which sounded like
*nothing* was required and contradicted two settled statements:

- `AGENTS-WORKFLOW.md` / CLAUDE.md doctrine: **"No bead, no PR"** (bd is
load-bearing for the canonical workflow).
- `docs/dependencies.md:14`: **`bd` → "Required for tracked work."**

This restates the floor in one consistent form across the doctrine
surfaces:

> `git` + an agent runtime stay **hard-required**, `bd` is **required
for the bead-tracked workflow** ("No bead, no PR"), and the ratchet +
`ao` CLI carry the rest.

## Why this is the only change needed

The README rewrite already removed the old "bd = Optional" requirements
table the bead cited (README:128). The current surfaces are already
aligned:

- `README.md:86` — "The only hard requirement is an agent runtime and
`git`."
- `docs/dependencies.md:14` — `bd` = "Required for tracked work";
`ao`/`bd` recommended (line 32).
- `AGENTS.md` — no contradicting "bd optional" statement.

So `docs/3.0.md:168` was the last outlying statement. One line changed.

## Verification

- `markdownlint-cli2 docs/3.0.md` → 0 errors.
- `scripts/pre-push-gate.sh --fast` → passed (2 pre-existing warn-only
F1.6 items, unrelated).

Closes-scenario: ag-60jd#tooling-floor-reconcile
Bounded-context: BC5-Runtime
Evidence: docs/3.0.md
2026-06-06 14:07:38 +00:00
Bo baf6ffddd2 ci(validate): run summary check on merge_group for merge-queue support (ag-arpk #merge-group-ci-support) (#797)
## What

Prerequisite for enabling GitHub's **merge queue** on `main`. The
`summary` required check is produced by `validate.yml`, which only
triggered on `push`+`pull_request`. With a merge queue, GitHub validates
queued PRs on a `merge_group` ref — if `summary` doesn't run there,
**the queue hangs forever**.

## Change (safe — no behavior change until the queue is on)

1. Add the `merge_group:` trigger to `validate.yml`.
2. Force a full validation run on `merge_group` (mirror the existing
release-tag path), because the `dorny/paths-filter` step has no PR base
in-queue and would otherwise skip all validation.

`push`/`pull_request` runs are unchanged (release stays false, filter
runs as before). `merge_group` events don't fire until the queue is
enabled — so this is inert until step 2 of the rollout.

## Next step (after this merges)

Enable the `merge_queue` rule on the `main` ruleset → the ~25-PR backlog
batch-drains instead of the strict-serial grind.

Closes-scenario: ag-arpk#merge-group-ci-support
Bounded-context: BC5-Runtime
Evidence: .github/workflows/validate.yml
2026-06-06 09:58:50 -04:00
Bo 5f69150169 test(cli): migrate curate_test.go os.Chdir to t.Chdir (ag-y4ac #curate-tchdir-w2) (#786)
## What
Collapse 7 identical `os.Getwd()` + `os.Chdir(tmpDir)` +
`t.Cleanup(restore)` blocks in `cli/cmd/ao/curate_test.go` to
`t.Chdir(tmpDir)`. Bare downstream `err =` first-uses promoted to `err
:=` (the removed block held the only function-scope `err`).

## Why
`t.Chdir` auto-restores cwd on cleanup **and** refuses to run under
`t.Parallel` — pre-empting the process-global-cwd flake class (cf.
ag-jfzs). This is one wave of the ag-k38x / ag-y4ac test-isolation sweep
(`finish-the-job`: ~133 sites already use the safe idiom).

## Scope / collision-safety
- `os.Chdir` in `_test.go`: **163 → 149 (-14)**. `os.Setenv` untouched
(owned by in-flight setenv ratchet **PR #772**).
- **`BASELINE_CHDIR` intentionally NOT lowered** — that single line is
the contention point with in-flight **PR #772/#773**; the ratchet stays
green because count-below-baseline is a NOTE, not a failure (`149 <=
163`). A later wave locks the baseline once those settle.
- Non-overlapping with PR #772 (rpi setenv) and PR #773 (dedup_test.go
os.Chdir).

## Verification
- `gofmt -l` clean · `go build ./...` · `go vet ./cmd/ao` clean
- `go test ./cmd/ao -run TestCurate` → 14 pass
- `scripts/check-test-isolation.sh` → PASS (os.Chdir=149/163,
os.Setenv=22/22)
- `scripts/pre-push-gate.sh --fast` → passed

Closes-scenario: ag-y4ac#curate-tchdir-w2
Bounded-context: BC5-Runtime
Evidence: .ntm/bo-queue/2026-06-06-ag-y4ac-pr-curate-tchdir.md
2026-06-06 09:44:51 -04:00
Bo f56f5b1521 chore(lint): clear 13 golangci-lint findings (ag-tcf0.1 #golangci-lint-clear) (#777)
## What

Clears all outstanding `golangci-lint run` findings in `cli/` — **13
issues** across 8 files. Pure mechanical lint cleanup, no behavior
change. (Several were hidden behind golangci-lint's default
`max-same-issues=3` display cap; running with caps disabled surfaced the
full set.)

| Linter | Count | Fix |
|---|---|---|
| errcheck | 7 | unchecked `f.Close()` → `defer func() { _ = f.Close()
}()` / `_ = f.Close()` |
| staticcheck S1016 | 2 | struct-literal copy → type conversion
(`reconcileCIRun(run)`, `reconcileBeadSummary(issue)`) |
| staticcheck QF1012 | 2 | `b.WriteString(fmt.Sprintf(...))` →
`fmt.Fprintf(&b, ...)` |
| staticcheck QF1001 | 1 | De Morgan: `!(a && b)` → `a' || b'` |
| copyloopvar | 1 | drop redundant `fx := fx` (Go 1.22+ per-iteration
loop var; go.mod is 1.26) |

Files: `loop_blocked.go`, `loop_next_work.go`, `cron_self_adjust.go`,
`reconcile.go`, `provenance_trace_test.go`, `internal/canon/ledger.go`,
`internal/scenarios/validate.go`, `internal/skills/catalog.go`.

## Verification

- `go build ./...` ✅  ·  `go vet ./...` ✅
- `golangci-lint run --max-same-issues 0 --max-issues-per-linter 0` →
**0 issues** ✅
- `go test ./internal/canon/... ./internal/scenarios/...
./internal/skills/...` → 116 passed ✅
- targeted `cmd/ao` tests (provenance/reconcile/cron/blocked/next-work)
→ ok ✅
- `scripts/pre-push-gate.sh --fast` → passed ✅

Closes-scenario: ag-tcf0.1#golangci-lint-clear
Bounded-context: BC5-Runtime
Evidence: golangci-lint run --max-same-issues 0 → 0 issues (verified
locally; CI re-runs the omnibus gate)
2026-06-06 09:44:48 -04:00
Bo 1601467387 chore(docs): gut dead-mechanism context poison from agent-facing docs (ag-sjz8 #gut-poison) (#764)
## What

Gut **context poison** — agent-facing docs that route a working agent at
DEAD mechanisms. This poisoned a live fleet-operating session (the bo
driver building the go-dark supervisor) into proposing `ao rpi` as a
continuity-loop worker. Found via a 5-way parallel poison fan-out.

**Scope: operational-surgical** (Bo's explicit call). Gut the
agent-facing *operational* guidance + *factual* errors; **LEAVE** the
README/`docs/3.0.md` product narrative (Gas-City-as-reference-substrate
is coherent, ADR-backed product design — a different altitude from Bo's
live fleet).

## Changes (10 files, surgical)

**Tier A — operational guidance (the poison that bit me):**
- `CLAUDE.md` Session Constraints: "route multi-phase work through `ao
rpi`" → the live substrate (NTM + MCP Agent Mail + `continuity-loop`);
`gc` reframed as optional-out-of-session, **not** the live substrate.
Kept the accurate "bridge REMOVED" + "load-bearing legacy" lines.
- `AGENTS.md`: dropped the deleted "scheduling daemon" (ADR-0009).
- `AGENTS-RUNTIME.md`: `ao rpi serve --help` → the real `ao` command
surface.

**Tier B — hookless-factual** (3.0 installs no hooks by default):
hookless banners on `ARCHITECTURE.md` + `reference.md` (surgical vs.
rewriting diagram internals); corrected SessionStart-hook prose in
`context-packet.md` + `vs-claude-flow.md`.

**Tier C — retired `/dream` shown as live:** marked retired in
`evolve`/`harvest`/`using-agentops` (compounding moved to Gas City).
`curate` **intentionally left** — its `--mode=dream` is the forward
replacement, not poison.

## Guardrails
- Does **not** claim `ao rpi` was deleted — the command still compiles
(`loop`/`phased`/`serve` exist); only its role as the *live workflow* is
corrected.
- registry.json unaffected (skill **bodies** only; `generate-registry.sh
--check` = OK).

## Evidence
`bash scripts/generate-registry.sh --check` → OK. Diff is 20 insertions
/ 16 deletions across 10 files.

Bounded-context: BC1-Corpus (agent-facing context docs)
Evidence: this PR diff + the parallel fan-out inventory
Closes: ag-sjz8

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-06-06 09:44:45 -04:00
Bo fec947be0d fix(skill-eval): filter safe-paths false-positives on markdown doc-link ../ (ag-eatf #safe-paths-doclink-filter) (#796)
## What

`scripts/skill-eval.sh` treated ms's `safe-paths` rule as blocking on
**every** `../`. That rule is a blunt regex, and `../` relative markdown
doc-links are the repo-wide SKILL.md convention (47+ skills, e.g.
`[x](../other/SKILL.md)`, `../../docs/...md`). SKILL.md is
documentation, not executed code, so those are false positives — they
redded `skill-eval` → `summary` on **every skills-touching PR** (blocked
#776; gated #759/#764/#767 in this session's drain).

## Fix

Added a file-level filter: `safe-paths` stays **blocking only when a
`../` survives stripping (1) markdown inline-link targets `](...)` and
(2) relative doc-path tokens (`*.md/.markdown/.mdx/.txt/.rst`)** — i.e.
a real, non-doc `../`. Otherwise the findings downgrade to advisory
annotations (announced, not silenced).

Net effect: **purely removes false positives; real protection is
preserved.** A genuine traversal (e.g. `../../../../etc/passwd` in a
description) still blocks — verified. No regression to the other
blocking rules.

## Evidence

- `bats tests/scripts/skill-eval.bats` → 12/12 pass (10 prior + 2 new
ag-eatf cases: doc-links downgrade→PASS; real non-doc `../`→BLOCK).
- Manual: `agent-native` and `domain` skills (previously red on
safe-paths) now PASS; a mixed real-threat fixture BLOCKs.

Closes-scenario: ag-eatf#safe-paths-doclink-filter
Bounded-context: BC2-Validation
Evidence: scripts/skill-eval.sh
2026-06-06 09:25:51 -04:00
Bo 8611b71f0f feat(corpus): auto-snapshot before destructive defrag prune (ag-32xk #defrag-autosnapshot) (#771)
## What

`ao defrag` now takes an **automatic, recoverable corpus snapshot**
before it applies a destructive `--prune` (anything that deletes from
`.agents/`). It reuses the same tar.gz machinery as `ao corpus
snapshot`, so an over-aggressive cleanup is always rehydratable via `ao
corpus restore`.

## Why (ag-32xk — moat durability)

The corpus moat is switching-cost / data-gravity, not tech — and it is
one accidental delete away from losing its receipts. Directive #11
history: routine maintenance wiped `.agents/` subdirs, counts went to
~0. A moat you can lose to routine cleanup doesn't feel like a moat.
This closes the most common loss path (the destructive defrag) first.

## Behavior

- **Apply-mode prune** → snapshot first, then prune.
- **Safe-by-default**: a snapshot failure *aborts* the prune — we refuse
to delete files we couldn't first back up.
- **No-op** for: dry-runs (nothing deleted), dedup-only runs (flags,
never deletes), and `--no-snapshot` (new escape hatch).

## Changes

- `corpus_snapshot.go`: extract `createCorpusSnapshot()` as the shared
engine behind both the `ao corpus snapshot` command and the defrag
auto-snapshot (no behavior change to the command).
- `defrag.go`: `autoSnapshotBeforeDefrag()` + `--no-snapshot` flag +
help text.
- `defrag_autosnapshot_test.go`: 6 tests (apply-prune snapshots;
dry-run/no-snapshot/dedup-only skip; missing-corpus aborts; L2
`runDefrag` leaves a recoverable tarball).
- `cli/docs/COMMANDS.md`: regenerated for the new flag (passes
`generate-cli-reference.sh --check`).

## Scope

Slice of ag-32xk. **Remaining (bead stays open):** `ao curate`
auto-snapshot + a canon/promoted-entry delete guard.

## Verification

- `cd cli && go build ./... && go vet ./cmd/ao/` — clean
- `go test ./cmd/ao/` — 9315 pass
- `scripts/pre-push-gate.sh --fast` — passed (CLI docs parity green)

Closes-scenario: ag-32xk#defrag-autosnapshot
Bounded-context: BC1-Corpus
Evidence: cli/cmd/ao/defrag_autosnapshot_test.go
2026-06-06 09:05:37 -04:00
Bo 784fcfca4e fix(test): convert goals integration lifecycle to subprocess isolation (ag-x2gv #flaky-goals-integration) (#762)
## Summary
- Convert `TestGoals_Integration_FullLifecycle` from in-process
`rootCmd.Execute()` + `captureStdout` + `chdirTemp` to subprocess
`exec.Command(bin, ...)` with isolated `t.TempDir()`
- Eliminates process-global state sharing (`os.Chdir`, `os.Stdout`,
cobra `rootCmd`) that caused intermittent empty-stdout failures under
`-race -shuffle=on`
- Same fix pattern as ag-z8c4 (PR #761) which fixed the analogous
`TestFlagMatrix_QuietMode` flake

## Test plan
- [x] 20/20 passes in isolation (`-run
TestGoals_Integration_FullLifecycle -race -shuffle=on -count=20`)
- [x] Full package suite green (`go test -race -shuffle=on -count=1
./cmd/ao/`)
- [x] `go vet ./cmd/ao/` clean
- [x] `go build ./cmd/ao/` clean

Closes-scenario: ag-x2gv#flaky-goals-integration
Bounded-context: BC5-Runtime
Evidence: 20/20 pass with -race -shuffle=on -count=20
2026-06-06 08:56:10 -04:00
Bo 242fc1695a docs(skills): match agy (Antigravity) panes in swarm-cleanup greps (ag-ni1b #agy-swarm-cleanup-grep) (#788)
## What

ntm now maps its `gemini` agent slot to `agy
--dangerously-skip-permissions` (Antigravity), so the gemini-family pane
runs as an `agy` process. The `system-tuning` swarm-cleanup reference
discovered and counted swarm agents with `grep -E 'claude|codex|gemini'`
in two places:

- the **confused-long-horizon-agent** finder (`ps ... | grep -E ...`)
- the **post-cleanup verification count** (`pgrep -af ... | wc -l`)

Both silently miss `agy` panes post-migration → confused-agent cleanup
skips them and the agent count under-reports.

## Change

Add `agy|antigravity` to both matchers and a one-line note explaining
the slot mapping. Keep `gemini` for older sessions that still launch it.

## Scope

In-repo slice of **ag-ni1b** (gemini-cli → Antigravity migration). This
advances the bead but does **not** close it — the bulk
(external/user-global skills, both-host verification,
dueling-idea-wizards + code-review-swarm end-to-end agy node) remains.

## Verification

`scripts/pre-push-gate.sh --fast` → passed (the 2 WARNs are
pre-existing, unrelated: unknown-flag noise in executable-spec
link-integrity).

Closes-scenario: ag-ni1b#agy-swarm-cleanup-grep
Bounded-context: BC5-Runtime
Evidence: skills/system-tuning/references/agent-swarm-cleanup.md
2026-06-06 08:56:07 -04:00
Bo b008e22f9b feat(domain): name silent-contract-violation + verdict.v1 finding taxonomy (ag-twl8 #verdict-category-taxonomy) (#759)
## What

First slice of the RubricRefine integration epic (**ag-5elx**). Moves
the paper's sharpest idea into the verification membrane — and it's the
dependency that **blocks the flagship** pre-execution gate (ag-rjvf).

- **`skills/domain/references/silent-contract-violation.md`** — new
draft anti-pattern entry. Names the failure class the whole membrane
exists to catch: tool-use code that **runs clean, raises no exception,
and is still wrong** (wrong routing, mismatched output shape, broken
argument provenance). Full Signature / Cost / Cause / Refusal + `bd`
incident citation, indexed in `INDEX.md` under a new "Verification
membrane concepts" section.
- **`schemas/verdict.v1.schema.json`** — adds RubricRefine's 4-category
contract-check taxonomy as an **optional** `category` enum on findings:
`tool-choice | output-contract | call-signature | data-provenance`.
Backward compatible — existing uncategorized findings stay valid
(`additionalProperties:false` preserved), an unknown category is
rejected so the taxonomy can't drift.
- **`tests/scripts/check-verdict-category-taxonomy.bats`** — behavioral
schema tests via python `jsonschema` (valid accepted · all four accepted
· omit valid · unknown rejected · enum exact). Written test-first:
confirmed failing against the unmodified schema, then green.
- **`registry.json`** — regenerated (domain `reference_count` 18→19;
scope-only diff).

## Why

RubricRefine (Anduril, arxiv 2605.09730v3) formalizes the failure
AgentOps' no-self-grade membrane targets, but AgentOps had no name for
it and no shared bucket vocabulary for findings. This slice supplies
both, so every downstream gate (and the pre-execution gate ag-rjvf) can
categorize and ablate contract violations.

## Verification

- `bats tests/scripts/check-verdict-category-taxonomy.bats` → 5/5 (CI
runs it via the bats job; surfaces changed: schemas/skills/docs/bats).
- `scripts/generate-registry.sh --check` → up to date.
- `scripts/check-bead-scenario-coverage.sh --run` → PASS (1/1 scenario
covered & passing).
- Full `pre-push-gate.sh --fast`: green except `corpus-freshness`
(env-local snapshot 8d old; CI sets `AGENTOPS_CORPUS_FRESHNESS_SKIP=1` —
not a PR blocker).

Closes-scenario: ag-twl8#verdict-category-taxonomy
Bounded-context: BC1-Corpus
Evidence: schemas/verdict.v1.schema.json
2026-06-06 08:33:38 -04:00
Bo efc2609682 docs(architecture): formalize the L0-L4 autonomy ladder (ag-wrom #autonomy-ladder) (#787)
## What

Closes the partial in Google-SRE convergence **point #8** (`ag-wrom`):
AgentOps already ran work at several autonomy levels (human-in-loop
in-session → substrate dispatch → bounded `autodev`) but the progression
was *implicit* — nothing named the rungs, stated what each may mutate,
or defined the evidence that earns a promotion. Implicit autonomy is how
a probabilistic agent quietly acquires more authority than its track
record justifies.

Adds `docs/architecture/autonomy-ladder.md`:

- **The invariant every rung obeys** — non-deterministic reasoning core
wrapped by a deterministic enforcement boundary (CI gates +
ports-and-adapters + ratchet) the agent can't bypass. The ladder moves
the *leash*, never relaxes the *boundary*. L4 code passes the same CI as
L0 code.
- **L0–L4 rungs** mapped to AgentOps' real dispatch vocabulary, with
human posture / acts-before-review / may-merge per rung.
- **Promotion gates** — per-lane, revocable, gated on
statistically-significant success vs Golden data at the
Bronze/Silver/Gold tier.
- **Demotion** — auto-downgrade on risk (the L3→L2 analog of Google's
de-escalation) + the unconditional Red Button.
- **Hard ceilings** — no rung confers authority over
external/secrets/schema/deletion/strategic-fork/merge-beyond-contract;
those stay draft-and-queue at every level.
- Honest divergence stated: AgentOps autonomy is **build-time** (code +
`.agents/` corpus), not run-time production ops — which is why L4 is
delegated to a substrate, not shipped (ADR-0009).

Wires it into the architecture index card grid + `mkdocs.yml` nav, and
flips convergence point #8 from ⚠️ partial to ✅ encoded (tally 9/1/1).

## Evidence
Closes-scenario: ag-wrom#autonomy-ladder
Bounded-context: BC1-Corpus
Evidence: markdownlint-cli2 PASS on all 3 changed docs; all cross-links
verified to resolve (operating-loop, canonical-loop-model,
fungibility-charter, google-sre, ADR-0009 in-docs relative; CLAUDE.md +
skills/autodev as GitHub URLs per repo convention for out-of-docs
targets); new page registered in mkdocs nav for `mkdocs build --strict`.
2026-06-06 12:18:20 +00:00
Bo 6489da8fab chore(cli): gofmt agent_bundle.go struct-literal indentation (ag-tcf0.2 #gofmt-agent-bundle) (#783)
Fixes a gofmt drift that landed on `main`: `cmd/ao/agent_bundle.go` had
an extra-tab indent on the `Bootstrap` field of the codex-ntm bundle
struct literal (unformatted since df3cc98, ~24h ago). Whitespace-only —
the `Bootstrap` string value is unchanged, behavior identical.

## Why it slipped through
CI runs `golangci-lint run` with **default linters**, which exclude the
`gofmt` formatter, so source-formatting drift is not gated and lands on
`main` undetected. This is the same class as the ag-tcf0 audit "14 files
unformatted" finding; the earlier sweep (ag-ozac) fixed files but did
not add an enforcement gate. **The missing gofmt CI gate is drafted to
the operator queue** (it interacts with the gate-target/path-filter
system and the active ag-tcf0.1 golangci worktree, so it warrants
operator confirmation rather than a unilateral CI-gate change).

## Test
The paired `agent_bundle_test.go` change strengthens the existing
`Bootstrap` substring assertion to **exact equality** (per
`.claude/rules/go.md`: "assert exact expected values, not just
substring"), guarding the struct literal against silent drift at the
exact site of the fix.

- `gofmt -l cli/` clean
- `go build ./...`, `go vet ./cmd/ao/` ok
- `go test ./cmd/ao/ -run TestBuildAgentBundle_CodexNTM` pass (8 bundle
tests green)
- `scripts/pre-push-gate.sh --fast` passed

Closes-scenario: ag-tcf0.2#gofmt-agent-bundle
Bounded-context: BC5-Runtime
Evidence: pre-push-gate --fast passed; gofmt -l clean; bundle tests
green
2026-06-06 08:06:44 -04:00
Bo 5dc91b9c51 chore(docs): scrub retired /dream from README skills table (ag-7vy #dream-readme-scrub) (#782)
## What

`/dream` is **retired** — `skills/dream/SKILL.md` frontmatter: *"Retired
pointer — out-of-session compounding moved to the substrate (NTM + MCP +
managed-agents)."* The README still presented it as a live skill in two
places:

1. Skills table row `| /evolve · /dream | … |` — dropped `/dream`, kept
`/evolve` with an accurate one-line description.
2. "The corpus needs hygiene" limitation — dropped `/dream`, leaving `ao
defrag` + `ao maturity` (the in-tree hygiene surfaces).
Substrate-delegated compounding is already covered by the "In session
vs. out of session" paragraph.

## Scope

Narrow + cosmetic per the bead (ag-7vy): README only. The deeper
`/dream` doc reconciliation across `docs/**` is explicitly out of scope
(separate daemon-prose arc).

## Evidence

- `grep -c "/dream" README.md` → `0`
- `markdownlint -c .markdownlint.json README.md` → PASS

Closes-scenario: ag-7vy#dream-readme-scrub
Bounded-context: BC1-Corpus
Evidence: grep /dream README.md == 0; markdownlint PASS
2026-06-06 08:06:31 -04:00