## What
New CI gate `validate-skill-body-refs` (T1) that scans the **inline-code
prose** of every `SKILL.md` + `references/*.md` (under `skills/` and
`skills-codex/`) for `` `ao <command>` `` / `` `ao <command> --flag` ``
tokens and validates each against the **live `ao` help tree**.
This is the systemic fix for oracle gap #3:
`validate-skill-cli-snippets.sh` only inspects fenced/`ao`-leading
snippets, so a stale command/flag named inside an inline code span
mid-sentence (e.g. `` `ao schedule` `` , `` `ao context assemble` ``)
regenerated after every CLI rename. This gate is the **complement** of
the snippet gate — together they cover both fenced snippets and prose.
## How the gate works
- Builds a robust live command tree: `ao capabilities` (authoritative
top-level) + recursive grouped-help subcommand parse (handles `ao
goals`' category-grouped help that the standard "Available Commands:"
parser misses) + command aliases (`quickstart` → `quick-start`) +
per-command flags.
- Only validates `ao` refs inside inline `` `code` `` spans — bare-prose
English ("if ao available", "ao not installed") is never treated as a
command, eliminating false positives while still catching the genuine
(always backtick-quoted) stale refs.
- Justified historical refs skip via an inline marker (`Superseded` /
`Historical` / `removed in` / `retained for history` / `(historical)`)
on the line/file, or `scripts/skill-body-refs-allowlist.txt`.
## Prose sweep (what made main pass)
The gate detected genuine stale refs on main; swept them to keep the
gate green:
- `ao context assemble` → `ao lookup` (8 sites — the command was never
built; `ao lookup` is the real co-cited replacement)
- `ao cite` → `ao metrics cite`
- `ao worktree gc` → `git worktree prune` (4 sites — `ao worktree` never
existed)
- `ao hooks` removal note → reworded to "removed in 3.0" (matches the
`removed in` historical marker)
## Allowlist contents
- `skills/standards/references/cli-wireup-template.md` — illustrative
naming template (deliberately names `ao loop-history` / `ao loop write`
/ `ao loop tail` as good/bad examples + future placeholders)
- `skills/release/references/release-notes.md`,
`skills-codex/release/references/release-notes.md` — historical
changelog prose (e.g. `ao daemon status` from the daemon era)
## Wiring
- `.github/workflows/validate.yml` — new T1 job + `summary.needs` +
`validate-pr-evidence-claims.needs` + summary echo (65 jobs)
- `docs/contracts/ci-jobs.yaml` — manifest entry (keeps
`validate-ci-policy-parity` green)
- `AGENTS-CI.md` — regenerated via `scripts/generate-ci-jobs-table.sh
--write`
- `tests/scripts/validate-skill-body-refs.bats` — 6 cases (clean pass,
stale-cmd fail, stale-flag fail, historical-marker skip, bare-prose
ignore, committed-tree pass)
## Verification (local, green)
- `bash scripts/validate-skill-body-refs.sh` → exit 0
- `scripts/validate-ci-policy-parity.sh` → PASS (65 rows)
- `scripts/validate-skill-cli-snippets.sh` → passed (no regression)
- `scripts/check-codex-parity-drift.sh` +
`validate-codex-generated-artifacts.sh --scope worktree` → passed (codex
hashes regenerated for the 6 edited skills only)
- `bats tests/scripts/validate-skill-body-refs.bats` → 6/6 ok
- `shellcheck scripts/validate-skill-body-refs.sh` → clean
- `markdownlint` on changed docs → clean
Closes-scenario: ag-4x8#body-ref-gate
Bounded-context: BC1-Corpus
Evidence: scripts/validate-skill-body-refs.sh