Commit Graph

501 Commits

Author SHA1 Message Date
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
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
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 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 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 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 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 463a6b31b1 chore(ci): guard author≠judge convergence on liveness.Disjoint (DRIFT #149 gate) (#746)
## What
The empty-ID self-grade bypass **recurred** — #737 (PG3/PG4) → #741
(citation reward) — because the author≠judge invariant had been
reimplemented in divergent places. #744 + #741 converged the 3 sites
onto `liveness.Disjoint`. This is the **2nd-occurrence gate** that keeps
them converged.

`scripts/check-author-judge-convergence.sh` flags any Go site doing its
own `author == judge` / `EqualFold(author, judge)` / `judge_id ==
author_id` equality **outside** `liveness.Disjoint`
(`cli/internal/liveness/guards.go`). Comments and `*_test.go` are
excluded.

## Why
This completes the no-self-grade invariant to its full form —
**converged + locked + gated**:
- **Converged** — #744 (`evidencedturn`) + #741 (`citation`) collapse
the 3 impls onto one `Disjoint`.
- **Locked** — #744's `TestAuthorNeqValidator_AgreesWithDisjoint` fails
CI if impl-#2 re-diverges.
- **Gated (this PR)** — catches a *new* 4th divergent impl **anywhere**,
in the gate every cluster agent runs pre-push.

Catch → encode → never-again. A failure that recurred twice mandates a
durable gate, not a third per-site patch.

## Validation
- Passes clean on current `main` (post-convergence: **zero** divergent
sites).
- 5 bats specs: pass-on-converged, flag-equality, flag-`EqualFold`,
skip-comment, skip-`_test.go`.
- Wired into `pre-push-gate.sh` always-on (fast grep, ~ms) — verified
`ok author!=judge convergence` in a full gate run. shellcheck clean (the
2 SC2317 infos are pre-existing in pre-push-gate.sh, not this change).
- Scope: 3 files, +96/−0 (guard script + bats + gate wiring). No
production code.

> Follow-up: mirror as a `validate.yml` CI step once the validate.yml
merge-churn settles (low-collision now via the pre-push gate). DRIFT
bead pending Dolt-write recovery (#149); Agent Mail #151/#166 carry
provenance.

Bounded-context: BC5-Runtime
Evidence: author!=judge convergence
2026-06-05 02:45:53 -04:00
Bo 419bda7532 feat(memory): classify bd remember notes (ag-u1zi) (#745)
## Summary

Implements ag-u1zi W4.1: a deterministic classifier for migrating `bd
remember` notes into the memory architecture without promoting
bead-local operational chatter into pull-learning memory.

Changes:
- adds `scripts/classify-bd-remember.py` with JSON/markdown output,
`--input`, `--expected-count`, and `--generated-at` options
- adds fixture and Bats coverage for classification coverage, lineage
preservation, markdown manifest, and expected-count mismatch
- adds `docs/contracts/bd-remember-migration-manifest.md` plus
documentation-index entry

Classification policy:
- `bead`: bead-linked, session-local, one-off, or tracker-operational
notes
- `pull-learning`: reusable project learning candidates, emitted as
`reach=pull`, `maturity=provisional`, `source=migrated-bd-remember`
- `discard`: empty/stale/deprecated/obsolete notes

Dolt/bd caveat: `bd update ag-u1zi --claim` and `bd ready` are failing
via the known Dolt/MySQL write/read path (`context canceled` / invalid
connection), so claim/provenance is recorded in Agent Mail rather than
bd state.

## Validation

Focused:
- `bats tests/scripts/bd-remember-classifier.bats` PASS
- `python3 -m py_compile scripts/classify-bd-remember.py` PASS
- `bash scripts/check-contracts-structural-floor.sh` PASS after indexing
the new contract doc
- `git diff --check` PASS

Required push path:
- `bash scripts/regen-all.sh` ran; failed only known CMDAO surface
parity red, timestamp-only `registry.json` drift reverted
- `PRE_PUSH_FAIL_FAST=false bash scripts/pre-push-gate.sh` completed
with the known red set: 4 failures (`test-fixture parity`,
canonical-root worktree disposition, corpus freshness, contract canary
pre-push-governance); no observed diff-caused failure

## Review Request

Requesting cross-model ACK before merge. Do not merge unless PR checks
reach CLEAN and quorum is satisfied.

Closes-scenario: ag-u1zi
Bounded-context: BC1-Corpus
Validation-evidence: classifier script + Bats coverage; see Validation
section above.
2026-06-05 02:24:15 -04:00
Bo 015bb52286 ci(ci): wire scan_descriptions --probe as I0-informational receipt lane (ag-iyu4 #probe-i0) (#738)
Wires `scripts/skill-probe-i0.sh` — the deterministic lexical trigger
ranker (`scan_descriptions.py --probe`, ag-7led) — as an
**I0-INFORMATIONAL** step inside the `skill-eval` job.

## What it does
- Runs the probe over every `trigger_probes:` phrase in the corpus,
writes a per-skill JSON receipt to `.agents/ao/skill-eval/<id>.json`,
and uploads it as the `skill-retrieval-probe-receipts` workflow
artifact.
- Asserts byte-stable **determinism** across two runs; a
non-deterministic probe is surfaced as a `::warning::` only.
- **Not a PR check:** `continue-on-error: true` lives INSIDE the
existing `skill-eval` job, so no new GitHub check is created and the
step can never block (or even advisory-fail) a merge. I0 =
informational.
- No-ops cleanly (exit 0, no receipts) until a skill opts in with
`trigger_probes:`.

## Acceptance
- Probe emits the JSON-receipt artifact AND no new PR check appears
(verify absent from `gh pr checks`).
- A deliberately non-deterministic probe input is caught by the
determinism assertion before it could become a gate —
`tests/scripts/skill-probe-i0.bats` (3 specs, all green).

## 2-week stability baseline
Documented in three places (validate.yml comment,
`docs/contracts/ci-jobs.yaml` skill-eval entry,
`skills/skill-builder/SKILL.md` trigger_probes note): keep `--probe`
I0-only until the receipt lane runs green + byte-stable across the
corpus for a 2-week baseline of merges before any blocking-gate
promotion.

Closes-scenario: ag-iyu4#probe-i0
Bounded-context: BC1-Corpus
Evidence: scripts/skill-probe-i0.sh
2026-06-05 01:00:52 -04:00
Bo 8ad6747913 chore(ao): delete the ao evolve CLI surface (ag-llni slice 1) (#724)
**Slice 1 of ag-llni** — retire `ao rpi`/`ao evolve` (orchestration is
no longer an in-CLI engine). This PR removes the **`ao evolve`** half;
the `rpi*.go` + phased web is slice 2.

**Architecture (operator-confirmed 2026-06-04):** orchestration is
two-tier — *inner loop* (one session) = skills/CLIs/native-subagents +
**Workflows** (`.claude/workflows/operating-loop.js` + `bead-crank.js` —
the Claude encoding of inner-orchestration that was mis-shaped as
`rpi`/`evolve`); *outer loop* (many sessions) = **NTM +
mcp-agent-mail**. Codex inner-loop = NTM + agent-mail for now. Leaf CLIs
(`corpus`/`goals`/flywheel/knowledge loops = BC1 corpus), NTM, and
agent-mail all stay.

### Changes
- Deleted `ao evolve` + 4 subcommands (`config`, `next-work`, `blocked`,
`write-stop-marker`) — 10 files.
- Relocated the one non-evolve coupling, `countCronHistoryRows`, into
its sole consumer `cron_self_adjust.go`.
- Removed `evolve` from the `cobra_commands_test.go` golden
`expectedCmds` list (2 sites).
- Regenerated `cli/docs/COMMANDS.md` (−125 lines) +
`docs/cli-skills-map.md`.

### Verification
- `go build ./...` green · `go vet ./cmd/ao` clean · **`go test
./cmd/ao` = 9251 pass**.
- Net: 13 files, −2192 LOC.

Bounded-context: BC5-Runtime
Closes-scenario: ag-llni#delete-evolve-cli
Evidence: cli/cmd/ao/cron_self_adjust.go
Test-Removal-Reason: ao evolve CLI surface retired (ag-llni) —
orchestration moved to .claude/workflows + NTM; the 5 deleted
evolve_*_test.go covered now-deleted command code, not kept behavior.

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-06-05 00:21:53 +00:00
Bo 092b99dad9 feat(skills): add skill-eval.sh ms-backed quality gate (ag-yzoz #skill-eval) (#726)
## What

Adds `scripts/skill-eval.sh` — a thin gate that runs one skill's
`SKILL.md` through Jeff Emanuel's `ms` (meta_skill) `lint` + `validate`.
The wrapper decides the gate purely on whether a **blocking** `rule_id`
appears (ms's own severity/exit is not trusted):

- Blocking: `no-secrets`, `no-injection`, `safe-paths`,
`required-metadata`, `no-cycle`, `valid-version` → non-zero exit.
- Everything else → annotated only (`::warning::`), never fails.
- `ms` not on PATH (or `MS_BIN` missing) → **loud `::error::` hard-fail
(exit 3)**, never skip-and-pass — a silent skip would recreate the
no-evaluation gap this gate closes.

Planted `skills/_fixtures/{bad,good}-skill/SKILL.md` fixtures +
`tests/scripts/skill-eval.bats` (10 tests) exercise the
bad/good/ms-absent contracts.

## Fixture scoping

`skills/_fixtures/` is non-skill scaffolding (planted fixtures). The
skill-enumerating gates/generators are taught to skip `skills/_*` so the
fixtures never inflate the skill count (stays 82) or fail registry /
schema / wiring / runtime / count gates. Touched enumerators:
`generate-registry`, `validate-skill-schema`, `sync-skill-counts`,
`validate-skill-count`, `generate-skill-catalog`,
`generate-context-map`, `validate-manifests`, `check-wiring-closure`,
`validate-headless-runtime-skills`, `lib/sku_catalog.py`,
`check-alias-collisions`, `run-all`, `test-runtime-opencode-smoke`,
`release-smoke-test`, `smoke-test`, `validate-skill`.

Does **not** touch `validate.yml` — wiring skill-eval.sh into CI is a
separate bead.

Epic: ag-czzf

## Verification

- `bats tests/scripts/skill-eval.bats` → 10/10 pass (ms 0.1.2 on PATH)
- `shellcheck scripts/skill-eval.sh` → clean
- `check-registry-drift`, `validate-skill-schema`, `sync-skill-counts`,
`run-all`, opencode-smoke → all PASS with fixtures present, skill count
= 82 (fixtures excluded)

Closes-scenario: ag-yzoz#skill-eval
Bounded-context: BC2-Validation
Evidence: scripts/skill-eval.sh

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-06-04 16:38:57 -04:00
Bo 7e8197ba93 ci(skills): consolidate live skill gates into one required skill-gates job (ag-87sv #skill-gates-job) (#723)
Consolidates the live skill-authoring CI gates into one named, required
`skill-gates` job (pure regroup of already-live gates — no behavior
change). Replaces the phantom `scenario-hash-stability` reference in
`CLAUDE.md` with the real `check-scenario-test-linkage` gate now grouped
under `skill-gates`. Adds the `skill-gates` row to the CI-policy-parity
manifest (`docs/contracts/ci-jobs.yaml` + `AGENTS-CI.md`) and the
`gate:skill-gates` SKU to `registry.json` (11→12 gates). New
`tests/scripts/skill-gates.bats` (12 tests) locks the job's structure,
required-check wiring, and drift-sweep behavior.

Part of epic ag-czzf.

Closes-scenario: ag-87sv#skill-gates-job
Bounded-context: BC2-Validation
Evidence: .github/workflows/validate.yml

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-06-04 16:16:04 -04:00
Bo ab138a5418 feat(skills): add scan_descriptions --probe deterministic trigger ranker (ag-7led #trigger-probe) (#722)
## Summary

Adds a `--probe "<phrase>"` mode to
`skills/skill-builder/scripts/scan_descriptions.py` that ranks every
skill against a lexical trigger phrase **deterministically** (no live
model, byte-stable output). Introduces an optional `trigger_probes:`
skill-frontmatter field so a skill can self-declare phrases it must rank
#1 for; the probe asserts the declaring skill wins its own phrases
against the corpus.

Epic: ag-czzf.

**INFORMATIONAL-only tooling — not a blocking gate.** The probe is a
self-check authors can run; no CI gate is wired to it.

## Changes
- `skills/skill-builder/scripts/scan_descriptions.py` — `--probe` ranker
+ `trigger_probes` parser (flow + block YAML forms).
- `schemas/skill-frontmatter.v2.schema.json` — optional `trigger_probes`
array field.
- `tests/scripts/scan-descriptions-probe.bats` — 4 scenarios (rank-#1,
determinism, demotion-on-mutation, usage-error exit codes).

## Validation
- New bats suite: 4/4 pass.
- `scripts/pre-push-gate.sh` reds are pre-existing main-red
(context-packet-ab canary + its downstream pre-push-gate-governance
nested bats), not caused by this diff; CI is changed-files-scoped.

Closes-scenario: ag-7led#trigger-probe
Bounded-context: BC2-Validation
Evidence: skills/skill-builder/scripts/scan_descriptions.py

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-06-04 15:40:07 -04:00
Bo 3d99d4bf69 fix(corpus): unify secret redaction + compile/CI git-safety (ag-sz3h ag-zi90 ag-y2xy #w1-git-safety) (#720)
Completes the **W1 git-safety arc** of epic ag-lhu0 (memory-system
re-architecture) — three beads, one coherent surface, after #719 wired
scrub-on-write into corpus_fs.

- **ag-zi90 (dedup):** `redactContent` (`ao context assemble`) now runs
canonical `llm.Redact` first — a single source of truth for credential
patterns (AWS / GitHub / GitLab / Slack / GCP / PEM, previously
uncovered in this path) — then keeps the supplements `llm.Redact` does
*not* cover: 2-segment app JWTs, sensitive env-var assignments,
high-entropy strings.
- **ag-sz3h (compile chokepoint):** new `ao redact` (stdin→stdout
canonical scrub) bridges the shell compile path; `compile.sh` pipes
every rendered article through it before `os.WriteFile` (loud fallback
if `ao` absent).
- **ag-y2xy (CI backstop):** `check-corpus-secret-scan.sh` scans
**git-tracked** (committed/allowlisted) `.agents` corpus + canon only —
repo-root `.agents` is local-only by policy, so scrub-on-write (#719 +
`ao redact`) is the primary defense and this is the backstop. Wired into
`validate.yml`; bats covers clean / leak-with-file:line /
untracked-not-scanned.

Scrub-on-write is primary; CI is the backstop. Verified: go
build/vet/test (incl. `TestRunRedact`, JWT-dedup regression test green),
bats 3/3, shellcheck clean, conformance regenerated.

Closes-scenario: ag-sz3h#compile-render-scrub
Closes-scenario: ag-zi90#dedup-redactor
Closes-scenario: ag-y2xy#ci-secret-scan
Bounded-context: BC1-Corpus
Evidence: scripts/check-corpus-secret-scan.sh

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-06-04 14:11:55 -04:00
Bo e74d8899fd feat(ci): gate live-hooks reintroduction in docs/ (ag-rryf #doc-hooks-drift-gate) (#713)
## What

Adds `scripts/check-doc-hooks-drift.sh` — a CI regression guard that
fails when a **live-facing** doc reintroduces a live hooks runtime after
the 3.0 hookless teardown:

- `hooks/hooks.json` (retired manifest), a `hooks/<name>.sh` runtime
path,
- `ao hooks` (not a registered command — verified absent from
`cli/cmd/ao/`),
- a bare `session-{start,end,autostart}*.sh` hook-file ref

…unless the **same line** hedges it as hookless / opt-in / historical /
removed / a git-hook. Companion to `sync-skill-counts.sh` (skill-count
drift) and `check-hookless-cold-start.sh` (fixed-list cold-start gate).

## Scope (and why the exclusions)

`docs/` **minus** surfaces that legitimately/archivally name hooks:
- **archival history** — `CHANGELOG.md`, `releases/`, `learnings/`,
`plans/`, `adr/`, `convergence/`, `sovereignty-proof/` (document the
past / the removal itself)
- **opt-in subsystem** — `contracts/` (hooks-authoring opt-in specs),
`runbooks/` (diagnostic enumeration), `code-map/` (point-in-time audits)

The gate keeps the onboarding / operator / architecture narrative
hookless.

## Also: finishes the ag-t1ca residue the gate flags

The ag-t1ca de-hooking missed 8 live-facing lines (gate caught them);
each is reframed:
- stale `ao hooks` command/smoke refs → removed / `ao doctor`
(`cli-skills-map`, `UPGRADING`, `release-e2e-checklist`,
`contracts/release-readiness`)
- present-tense hooks-as-rules → CI gates (`strategic-direction`)
- hook-runtime mentions → `ao curate constrain` / opt-in framing
(`curation-pipeline`, `leverage-points`, `SCHEMAS` legacy-manifest
label, `workflows/session-lifecycle`)

## Verification

- `scripts/check-doc-hooks-drift.sh` → PASS on this branch (FAILed on
all 8 before the reframes)
- `tests/scripts/check-doc-hooks-drift.bats` → 8/8 (positive /
negative×3 / hedge×2 / exclusion / no-docs error)
- `shellcheck` clean · `markdownlint` 0 errors (9 docs) ·
`validate-cli-skills-map.sh` PASS · `generate-ci-jobs-table.sh --check`
PASS · existing `check-hookless-cold-start.sh` still green
- Wired into `validate.yml` lint/contracts (gated on docs/ci/shell
changes) + auto-run via the bats suite

Closes-scenario: ag-rryf#doc-hooks-drift-gate
Bounded-context: BC2-Validation
Evidence: scripts/check-doc-hooks-drift.sh
2026-06-03 22:38:26 -04:00
Bo 215fcef720 feat(eval): held corpus-delta tasks cd-ci-1 + cd-ci-4 (ag-nfux #approved-tasks-ci1-ci4) (#703)
## What
Materializes the **two operator-vetted** W1b tasks (the only 2 the
adversarial audit passed as clean: `.agents/`-grounded,
principle-not-answer, deterministically gradeable).

- **cd-ci-1** — author an advisory-tier guard gate. Grounds in
`.agents/learnings/2026-05-17-ci-advisory-killed.md`; the agent must
build `check-no-advisory-tier.sh`.
- **cd-ci-4** — author a removed-job assertion pre-flight gate. Grounds
in `.agents/learnings/2026-05-17-delete-grep-asserts.md`; the agent must
build `check-removed-job-assertions.sh`.

Each task ships `prompt.md` + `setup.sh` + `score.sh` (deterministic,
no-LLM grader) + a `golden-solution.sh` reference (**not** given to the
agent). The grounding learning lives in `.agents/`, so the W1a sandbox
(ag-5apc) surfaces it in `context_on` and strips it in `context_off` → a
real delta.

## Grader-discrimination test
The task fixtures' own validity: each grader scores the **golden
solution PASS** and an **empty workspace FAIL** — a grader that can't
tell the difference would make the A/B meaningless. 5/5 bats pass;
shellcheck clean on all 6 task scripts.

## N note
This is the honest **N=2** starting set. The adversarial audit showed
N≥10 isn't reachable from the first drafting slate without a second
`.agents/`-only pass; a rigorous small-N beats a large rigged one (per
the product panel). **ag-nfux stays open** for N expansion.

Closes-scenario: ag-nfux#approved-tasks-ci1-ci4
Bounded-context: BC2-Validation
Evidence: evals/workbench/tasks/cd-ci-1/score.sh

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-06-03 19:09:36 +00:00
Bo e6ec5561df fix(eval): strip always-loaded roots in context_off (ag-5apc #strip-always-loaded) (#702)
## What
Fixes the contamination flaw the W1b adversarial audit surfaced:
isolating `AO_AGENTS_DIR` alone is **insufficient** — the agent also
auto-loads knowledge from **always-loaded roots** (repo-root
`CLAUDE.md`, `.claude/rules/*`, user-global `~/.claude/CLAUDE.md`,
auto-memory `MEMORY.md`), read in **both** arms → no delta to measure (6
of 12 W1b candidates were invalidated by this).

Each arm now runs in an isolated **sandbox** (HOME + workspace). Those
surfaces are treated as **corpus** — populated in `context_on`, absent
from `context_off`:
- `build_arm_sandbox()` — ON copies project CLAUDE.md + .claude/rules +
user CLAUDE.md + auto-memory + the .agents corpus; OFF leaves them out
(and strips any base-carried context).
- `CORPUS_DELTA_HOME_BASE` seeds auth/settings into both arms **before**
context, so a real agent keeps credentials while OFF stays context-clean
(off = base − context, on = base + context).
- Runner now gets `HOME` + `AO_AGENTS_DIR` + `CORPUS_DELTA_WORKSPACE`; a
real agent MUST run with that HOME + cwd=workspace.

## Contamination self-test (the bead's success criterion)
A marker seeded into **every** always-loaded root reaches `context_on`
but **NOT** `context_off` (delta=1); a separate test proves auth
(`HOME_BASE`) survives both arms while base-carried context is stripped
from off.

## Verification
7/7 bats pass; shellcheck clean. No `ao` surface; no derived-surface
regen. Unblocks honest W1b/W1c.

Closes-scenario: ag-5apc#strip-always-loaded
Bounded-context: BC2-Validation
Evidence: scripts/corpus-delta-harness.sh

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-06-03 18:41:51 +00:00
Bo 8ad336122f feat(eval): corpus-delta A/B side-harness (ag-u6jh #harness) (#701)
## What
Wave-1a of the corpus-delta proof (ag-8p8o) — the runnable arm.

The deterministic eval runner rejects non-shell runtimes ("out of
deterministic scope", `cli/internal/eval/io.go`) and is CI-locked, so
this is a **side harness** — *not* an extension of that runner, and
**not a new `ao` subcommand** (no CLI surface growth, per the
minimalist/competitive lenses).

- **`scripts/corpus-delta-harness.sh`** — runs one task in two context
arms: `context_off` (isolated **empty** `AO_AGENTS_DIR`) vs `context_on`
(organic `--corpus` root), K seeds each → a
`ContextDeltaScorecard`-shaped JSON (matches the Go struct fields). The
agent runner is **injectable** (`CORPUS_DELTA_RUNNER`, default
`eval-agent-harness.sh --agent claude|codex`) so it's testable **without
LLM calls**.
- **`tests/scripts/corpus-delta-harness.bats`** — 5 cases via a stub
runner: off(empty)→fail, on(corpus)→pass, delta=1.0; no-delta when arms
match; scorecard shape; `--out`; arg validation.

## Honesty guard (baked in)
The script header, test comments, and `evidence_kind:
"harness_plumbing"` all state: **a stub/plumbing run is NOT evidence of
the corpus delta.** The real claim needs a real agent + held
non-engineered tasks + K seeds (ag-nfux W1b, ag-epgk W1c). This
explicitly avoids repeating the wave0 confusion of citing plumbing as
proof.

## Verification
5/5 bats pass; shellcheck clean. No ao is the CLI for AgentOps, a
software-factory control plane for repo-native agent work.

"Problem in. Value out. Intelligence compounds."

Software Factory Lane:
  ao factory start --goal "fix auth startup"
  /rpi "fix auth startup"   or   ao rpi phased "fix auth startup"
  ao codex stop

The Knowledge Flywheel underneath it:
  Sessions compound via .agents/ + Smart Connections.
  Others start fresh. You get smarter every session.

For AI agents:
ao capabilities Machine-readable CLI contract (JSON) — run this first.
  ao robot-docs       Paste-ready agent handbook.
  Append --json to any read-side command for structured output.

Use "ao <command> --help" for more information about a command.

Usage:
  ao [command]

Getting Started:
  demo            Show the council-first AgentOps 3.0 value path
  init            Initialize AgentOps in the current repository
  quick-start     Set up AgentOps in your project (5 minutes)
  seed            Plant the seed in any repository

Core Commands:
  anti-patterns   List learnings marked as anti-patterns
  badge           Display knowledge flywheel health badge
canon Team-knowledge canon: learnings earned by independent attestation
  capabilities    Print the machine-readable CLI contract (JSON)
ci BC2 CI status operations (latest run by SHA, recent runs)
citation BC1 CitationPort operations (verify file/function/symbol
citations)
claim BC2 ClaimEvidenceBinderPort operations (bind/list claim-evidence)
  constraint      Manage compiled constraints
  contradict      Detect potentially contradictory learnings
  curate          Curation pipeline operations
  dedup           Detect near-duplicate learnings
  doctor          Check AgentOps health
  flywheel        Knowledge flywheel operations
  gate            Human review gates
harness BC5 HarnessPort operations (sync state across skill harnesses)
  loop            BC3 Loop operations (cycle history, etc.)
  maturity        Check and manage learning maturity levels
  metrics         Knowledge flywheel metrics
operator BC4 OperatorPort operations (record/list operator intents)
  pool            Manage quality pools
reconcile Join git, CI, release, beads, and .agents truth into one
report
robot-docs Print the paste-ready agent handbook for the ao CLI
(Markdown)
  status          Show AgentOps status
  version         Show version information
  vibe-check      Analyze codebase health and vibe

Workflow:
autodev Manage the PROGRAM.md operational contract for autonomous
development
codex Codex lifecycle commands (fallback for pre-v0.115.0; native hooks
preferred)
  cron            Cron-fire loop helpers (used by /evolve --mode=loop)
  eval            Run deterministic local evaluation suites
  evolve          Run the autonomous code-improvement loop
  feedback-loop   Close the MemRL feedback loop for a session
  goals           Fitness goal measurement and validation
handoff Write a structured handoff artifact for session boundary
isolation
  orchestrate     Resolve and inspect the orchestration backend ladder
  ratchet         Brownian Ratchet workflow tracking
  rpi             RPI lifecycle automation
  session         Session lifecycle operations
validate Umbrella validation gate (exit-code-as-verdict with --gate)

Configuration:
  completion      Generate shell completion scripts
  config          Manage configuration
  memory          Manage repo-root MEMORY.md for cross-runtime access
  notebook        Manage the session notebook (MEMORY.md)

Communication:

Knowledge:
  beads           Complementary tooling for the bd (beads) issue tracker
  compile         Compile .agents knowledge into an interlinked wiki
corpus Corpus-quality probes for Dream and the knowledge flywheel
  defrag          Prune and deduplicate .agents/ learning artifacts
  findings        Manage promoted findings
  forge           Extract knowledge from sources
harvest Sweep all rigs, extract and deduplicate cross-rig knowledge
inject Output relevant knowledge for explicit or JIT injection
knowledge Operationalize a mature .agents corpus into reusable operator
surfaces
  lookup          Retrieve specific knowledge artifacts by ID or query
  mind            Knowledge graph operations
  mine            Extract knowledge signal from git, .agents/, and code
  patterns        Inspect and repair .agents/patterns/ artifacts
  retrieval-bench Run retrieval quality benchmarks
search Search workspace session history and repo-local knowledge
  sessions        Manage indexed session pages
  trace           Track artifact provenance
  wiki            Unified wiki knowledge surface (experimental)

Additional Commands:
agent Produce AgentOps-native session profiles for background agents
  agents          Inspect and manage .agents/ contracts and surfaces
  extract         Process pending learning extractions
  help            Help about any command
mcp Expose the ao tool surface over MCP for hosted/SDK Claude loops
next-work Operate on the harvested next-work queue
(.agents/rpi/next-work.jsonl)
  provenance      Write and read the SDLC provenance edge ledger
  registry        Query the unified registry
  scenario        Manage holdout scenarios for behavioral validation
  scope           Manage edit-scope guard (freeze, unfreeze, status)
  skills          Inspect and validate the skills/ tree
turn Evidenced-Turn operations (the enforced unit-of-work
definition-of-done)

Flags:
      --config string   Config file (default: ~/.agentops/config.yaml)
      --dry-run         Show what would happen without executing
  -h, --help            help for ao
      --json            Output as JSON (shorthand for -o json)
-o, --output string Output format (json, table, yaml) (default "table")
  -v, --verbose         Enable verbose output
      --version         version for ao

Use "ao [command] --help" for more information about a command. command
surface; doesn't touch the locked deterministic eval runner; no
derived-surface regen needed.

Closes-scenario: ag-u6jh#harness
Bounded-context: BC2-Validation
Evidence: scripts/corpus-delta-harness.sh
2026-06-03 18:07:48 +00:00
Bo 7455382416 refactor(gc): strip Gas City coupling; adopt NTM+MCP+managed-agents (ag-124p) (#679)
## What

Operator-authorized (Bo, 2026-06-02). Strips the remaining **Gas City**
(`gastown`) coupling from AgentOps and reconciles the **split-doctrine
state** on `main` that the #672–#676 post-mortem flagged: canonical docs
(#676) said NTM+MCP+managed-agents while user-facing docs still
described Gas City as the reference substrate.

The out-of-session substrate is now uniformly **NTM** (local tmux swarm)
+ **MCP** (`ao mcp serve`, shipped) + **managed-agents** (`ao agent`).
AgentOps adopts a substrate; it owns none. Closes **ag-124p** (and
resolves **ag-h93p** — the claude.json gc-hook decouple).

## Deleted (load-bearing surfaces, per the bead's verified scope)

- `packs/agentops/` (the reference City) + root `city.toml`
- `skills/using-gc` + `skills-codex/using-gc` (+
`tests/scripts/using-gc-skill.bats`)
- `gc prime/nudge/mail/hook` wiring in `cli/hooks/claude.json` → now
hookless, matching 3.0 doctrine

## Doc sweep (the split-doctrine fix the post-mortem required)

- **README.md, docs/MIGRATION-3.0.md, docs/dependencies.md,
docs/activation-profiles.md** re-narrated to the substrate trio (the
four files the verdict named)
- AGENTS.md / CLAUDE.md substrate bullets; `dream` skill (+codex twin)
retirement pointer; `shared` / `agent-native` / `using-agentops`
cross-refs; skill-dispositions, context-map, sku-catalog, google-sre
convergence map

## Regenerated derived surfaces

Skill counts (81→80), `registry.json`, `skills/catalog.json`,
context-map, skill-domain-map, codex hashes (14) + manifest, SKILL-TIERS
— all via the generators, validated drift-free.

## Scope boundaries / follow-ups

- **`cli/internal/doctor/fix_bridges.go`** still carries a gc-bridge
detector/fixer subsystem. Out of the bead's verified scope; degrades
gracefully (stat-checks, returns empty when `gc`/`city.toml` absent);
removing it is a test-backed Go change → **follow-up bead**.
- **CLAUDE.md "Gas City bridge — REMOVED"** note kept intentionally:
it's an anti-re-coupling record, not substrate-framing.
- The local-only **bd-closeout** pre-push check (not in CI) is a
pre-existing gap on `main` (its AGENTS.md has no `bd dolt push` line) —
untouched here.
- `thesis-stability` gate FAIL, if present, is the pre-existing
README/PRODUCT/GOALS tagline drift, unrelated to this PR (my
README/PRODUCT edits are the dependency table + skill-count numbers, not
the tagline).

## Verification

`go build ./...` + `go vet` green · skill schema (80/80) + integrity
(heal --strict clean) + lint suite (0 fail) + codex parity green ·
sku-catalog & context-map drift gates green · zero broken markdown links
to deleted paths.

Closes-scenario: ag-124p#gc-coupling-strip
Bounded-context: BC5-Runtime
Evidence: docs/MIGRATION-3.0.md
2026-06-02 09:06:41 -04:00
Bo 37c86dc282 docs(doctrine): re-narrate out-of-session substrate Gas City → NTM+MCP+managed-agents (ag-vg40 #substrate-renarration) (#676)
## What

The **doctrine slice** of the ACFS-prune (operator-authorized
2026-06-02). Re-narrates AgentOps's out-of-session story.

**Kept (the sovereignty floor — unchanged):** AgentOps = the in-session
loop + compounding context; ships no daemon/scheduler/overnight-runner;
delegates out-of-session execution to a *swappable substrate*. The
in-session/out-of-session boundary and the "substrate owns
when/where/who-supervises/coordination" split stay.

**Changed (the reference substrate):** Gas City → the adopted ACFS trio
— **NTM** (local tmux swarm) + **MCP** (`ao mcp serve`, shipped) +
**managed-agents** (`ao agent`). "AgentOps IS a Gas City reference
config" → "AgentOps adopts NTM+MCP+managed-agents; it still owns no
core, it just doesn't own or reference Gas City." This is the
deep-dive's "adopt the substrate, don't own it."

## Changes (7 files, +25 / −120)
- `docs/3.0.md` — substrate table row; replaced the "Gas City reference
City" section with "Running the loop out of session" (the three
substrate options); Olympus comparison rows; sovereignty-floor line
- `docs/architecture/canonical-loop-model.md` — Factory-driver framing,
ASCII diagram, boundary table, dispatch paragraph
- `docs/cdlc.md`, `docs/architecture/fungibility-charter.md` — substrate
one-liners
- **deleted** `docs/architecture/gc-posture.md` + reconciled its 4
inbound links (both index files, documentation-index,
fungibility-charter)

## Scope boundaries
- **ADR-0009 left historical** — decision records are immutable; it
records the *then*-rationale.
- **`thesis-stability` not tripped** — that gate guards the product
thesis (README/PRODUCT/GOALS), not the substrate detail. (Its current
FAIL is pre-existing README/PRODUCT/GOALS tagline drift, unrelated to
this PR.)
- **Follow-up `ag-124p`** (separate PR): the code/config strip —
`packs/agentops` + `city.toml` + `skills/using-gc` +
`cli/hooks/claude.json` gc-wiring.

## Note
This is outward-facing doctrine — opened for your review rather than
auto-merged. PR #5 this session; you authorized continuing past the
scope ceiling for the prune.

Closes-scenario: ag-vg40#substrate-renarration
Bounded-context: BC1-Corpus
Evidence: docs/3.0.md
2026-06-02 07:51:25 -04:00
Bo eba83ad11b feat(ci): committed reconcile-pr + no-epic-close-with-open-child gate (ag-9gac #reconcile-helper-epic-gate) (#669)
Promotes the ephemeral `/tmp` bead-crank reconcile engine (ran ~20x this
session) to committed, **tested, enforced** scripts. Turns S3's advisory
prose into executable gates.

## What lands
- **`scripts/reconcile-pr.sh <pr> <bead> [--epic <epic>]`** — polls
checks until terminal, reruns the lone `correctness (ubuntu-latest)`
tar-cache flake **once**, treats only substantive non-`claude-review`
fails as blocking, `gh pr merge --squash --admin` when clean, confirms
`gh pr view --json state == MERGED`, then `bd update <bead> --status
closed` (bd close has a dolt blocker-query glitch). `--epic` mode calls
the gate before closing the epic.
- **`scripts/check-epic-children-closed.sh <epic>`** — the
**no-epic-close-with-open-child** gate: exit 1 naming any
open/in_progress child, exit 0 when all closed.
- **15 hermetic bats** (`gh`+`bd` stubbed via PATH shims) — prove
merge+close on green, BLOCK (exit 2) on a substantive fail,
rerun-once-then-merge on the lone flake, no-close when state != MERGED,
gate rejects+names an open child, passes when all closed. shellcheck -S
warning clean.
- **crank/evolve SKILL.md** prose now points to the committed scripts
(tiny edits).

## Exit-code contract (asserted in tests)
`0` merged+closed · `1` epic-gate fail (open child) · `2` blocked
(substantive fail) · `3` merge attempted but state != MERGED · `4`
usage/dep error.

## Gates
- shellcheck -S warning: CLEAN (both scripts)
- `bats tests/scripts/{reconcile-pr,check-epic-children-closed}.bats`:
15/15 pass
- `scripts/regen-all.sh --check --skills crank,evolve`: ALL GATES GREEN
- Diff scope-only: 2 scripts + 2 bats + 2 skill pointers + 3 codex hash
files (source_hash bumps). Pre-existing `docs/cli-surface.*` main drift
reverted, not swept in.

Orchestrator helpers (not necessarily CI jobs) — wired as enforcement
for the crank/evolve close discipline.

Closes-scenario: ag-9gac#reconcile-helper-epic-gate
Bounded-context: BC3-Loop
Evidence: scripts/check-epic-children-closed.sh
2026-05-31 17:31:08 -04:00
Bo efb7fd66e9 feat(ci): repo-wide path-filter/gate-target coverage audit + gap fixes (ag-g9ex #pathfilter-audit) (#666)
## What

Repo-wide audit of every file-reading CI gate in
`.github/workflows/validate.yml` against the invariant the #634/#638
trunk-heal proved: **a gate that READS a file must be TRIGGERED by a
path-filter covering that file.** A docs-thinning commit (`bbfd278e`)
silently disabled the security redteam canary because the `contracts`
filter didn't cover `AGENTS.md`, and it surfaced only on a later
unrelated PR.

Closes **ag-g9ex** (Slice5[GOVERNANCE]). Derived from
`.agents/retro/2026-05-31-bead-crank-postmortem.md` §4(#2) + §7(#5).

## Audit

`docs/contracts/ci-pathfilter-coverage-audit.md` enumerates every gate
that reads specific files, the files it reads, the filter(s) that
trigger it, and a COVERED/GAP verdict. 13 gates audited + verified
non-findings.

## Gaps found and fixed (2)

1. **AGENTS tiered-split siblings uncovered (direct #634 class).**
`scripts/validate-agents-split.sh` validates `AGENTS.md` +
`AGENTS-{WORKFLOW,CI,CODEX,RUNTIME}.md`, but the gate triggered on
`docs/ci/shell` and the four siblings were covered by **no** consumed
filter. A sibling-only edit would skip the split gate. **Fix:** added
the siblings to the `contracts` filter + `contracts` to the gate trigger
(mirrors #638).
2. **wiring-closure not re-triggered by GOALS.md de-wire.**
`scripts/check-wiring-closure.sh` greps `GOALS.md`/`GOALS.yaml` to
confirm every `check-*.sh` is referenced, but triggered on
`go/hooks/shell/ci` — not `goals`. A GOALS.md-only de-wire would skip
it. **Fix:** added `goals` to the gate trigger.

## Governance (--admin self-merge, §7 #4)

Documented as policy in the audit doc rather than shipped as a
half-working CI gate (GitHub Actions cannot observe `--admin` from
inside a `pull_request` workflow; building a fake gate would be
over-engineering against the bead's explicit guidance). Mechanical
enforcement filed as a follow-up.

## Guard test

Extended `tests/scripts/test-pathfilter-gate-coverage.bats` (the #638
guard) with 3 new assertions: AGENTS-split targets ⊂ `contracts`, split
gate triggers on `contracts`, wiring-closure triggers on `goals`. All 10
tests pass.

## Gates run (local)
- `python3 yaml.safe_load(validate.yml)` → VALID
- `bats test-pathfilter-gate-coverage.bats` → 10/10 ok
- `scripts/check-contracts-structural-floor.sh` → PASS (46 contracts)
- `scripts/validate-ci-policy-parity.sh` → PASS (11 rows)
- `git diff origin/main --stat` → scope-only (4 files)

Closes-scenario: ag-g9ex#pathfilter-audit
Bounded-context: BC2-Validation
Evidence: docs/contracts/ci-pathfilter-coverage-audit.md
2026-05-31 16:31:59 -04:00
Bo 7c10303184 chore(ci): regen-codex-hashes --only scoping + regen-all passthrough (ag-fbe9 #regen-scoping) (#664)
## What

Adds `--only <skill[,skill,...]>` to `scripts/regen-codex-hashes.sh` and
threads it through `scripts/regen-all.sh` (`--skills` arg /
`REGEN_SKILLS` env), so an agent can regenerate codex hashes for **only
the skills it touched**.

## Why

From `.agents/retro/2026-05-31-bead-crank-postmortem.md` §5 (#1-2): the
codex hash regen rewrites every drifted manifest entry, sweeping ~8-9
pre-existing drifts into every skill PR and forcing a manual
`jq`-splice. Scoping the loop kills that toil.

## Changes

- **`regen-codex-hashes.sh`**: `--only` parses a skill set; the
per-skill loop `continue`s when a skill isn't in the set. `--check`
honors the same scope. Default (no flag) = all skills, unchanged.
`SKILLS_ROOT` is now env-overridable (enables hermetic testing).
- **`regen-all.sh`**: `--skills a,b` / `REGEN_SKILLS=a,b` threads
`--only` into the codex-hash step in both regen and `--check` modes;
trailing NOTE instructs passing scope when only some skills changed.
- **`tests/scripts/regen-codex-hashes-only.bats`**: hermetic — `--only
foo` regenerates only foo and leaves a simulated pre-existing-drift
sibling untouched; no-`--only` regenerates all; `--check` scoping;
comma-list; arg-required.

## Verification

- `bats tests/scripts/regen-codex-hashes-only.bats` — 5/5 pass
- `shellcheck -S warning` clean on both scripts
- `git diff origin/main --stat` scope-only (2 scripts + 1 bats)
- The 9 manifest drifts on `main` (deps, post-mortem, provenance,
red-team, release, scenario, ship-loop, skill-builder, trace) are
**pre-existing**; this PR touches zero `skills-codex/` files.

Closes-scenario: ag-fbe9#regen-scoping
Bounded-context: BC2-Validation
Evidence: scripts/regen-codex-hashes.sh
2026-05-31 16:26:50 -04:00
Bo a5a0cdcb0b feat(skills): encode external skill-authoring standard + corpus trigger scanner (ag-vb3q #authoring-standard-trigger-scan) (#663)
## What

RPI cycle on **mining how AgentOps makes skills** (bead `ag-vb3q`),
using the external `meta_skill` best-practices doc as the scoring lens
(methodology only — no Rust `ms` build).

**Research:** codebase-archaeology over the 83-skill corpus + the skill
factory
(`skill-builder`/`skill-auditor`/`heal-skill`/`converter`/`forge`,
`SKILL-TIERS`, `score_agentops_skill.py`, CI gates). The corpus is
structurally excellent: **100% frontmatter conformance, 100% Codex
parity, ~94% references usage**.

**The one finding that matters:** skill selection is pure LLM reasoning
over the `description` field, yet **73 of 81 skills (90%) carry no
trigger marker**. The auditor *has* the checks
(`description-has-triggers`, `trigger-clarity`) but they were downgraded
**FAIL→WARN**, so the gap accumulated silently — a textbook
doctrine-vs-enforcement drift.

## This PR (Implement)

- **`references/skill-authoring-standard.md`** — clean-room distillation
of the external standard, cross-walked to AgentOps's *actual* enforced
rules (best-practice → gate → severity table).
- **`scripts/scan_descriptions.py`** — corpus-wide trigger scanner that
mirrors `audit.sh`'s exact three-form detection (so it never contradicts
the per-skill auditor) and adds the prioritized remediation backlog + a
suggested `Triggers:` stub the auditor never produced. `--json` robot
mode, `--strict` exit code.
- **`tests/python/test_scan_descriptions.py`** — 11 behavioral tests
(all three forms, suggestion quality, CLI exit codes, live-corpus
smoke).
- **`skill-builder/SKILL.md`** — "Corpus authoring health" section +
reference link (194/250 lines).
- Regenerated `registry.json`; patched `catalog.json` reference count.

## Plan (follow-on beads filed)

- `ag-okfu` — add trigger markers to the 73 flagged skills (wave by
tier; acceptance = scanner `--strict` exits 0)
- `ag-cx7d` — ratchet `trigger-clarity`/`description-has-triggers`
WARN→FAIL once the corpus is clean (blocked by `ag-okfu`)
- `ag-mm6q` — fix `generate-skill-catalog.sh` BSD-awk incompatibility

## Evidence

\`\`\`
python3 skills/skill-builder/scripts/scan_descriptions.py skills #
scanned 81, missing 73 (90%)
python3 -m unittest tests.python.test_scan_descriptions # 11 ok
bash scripts/check-registry-drift.sh # PASS — no drift
bash scripts/validate-context-map-drift.sh # exit 0
heal --strict skills/skill-builder # All clean
\`\`\`

Closes-scenario: ag-vb3q#authoring-standard-trigger-scan
Bounded-context: BC4-Factory
Evidence: .agents/audits/meta-skill-archaeology.md
2026-05-31 20:16:38 +00:00
Bo 0dcbae450c fix(loop): re-enforce session-PR-scope hooklessly + fix stale hook refs (ag-o5xp #session-pr-scope) (#661)
## Problem

The session-PR-scope guardrail shipped as a PreToolUse hook
(`hooks/session-pr-counter.sh`, PR #362), but **PR #511 (the 3.0
hookless teardown) deleted all hooks**. Six workflow-discipline surfaces
were never updated — they still advertise the hook as a live, shipping
mechanism. That's a **stale active-surface promise + a lost reliability
guardrail** (surfaced by the ag-4hf7 Google-SRE audit:
"explainability/trust" turned inward).

## Hookless re-enforcement (the decision)

- **The mandatory layer already survives**: the `/evolve` post-mortem
checkpoint #6 (council-gated, cannot be bypassed) enforces session-scope
for autonomous loops — the actual failure mode. It only lacked a
canonical count source.
- **New `scripts/session-pr-scope.sh`** — the reusable hookless count +
verdict (`OK`/`WARN`/`BLOCK`), fail-open, robot-friendly
(`--json`/`--count`). It is now:
  - the checkpoint's `$session_pr_count` source, and
- the one-liner an **opt-in** hook wraps (re-author via the
hooks-authoring skill — AgentOps ships none).
- 8 bats cases (thresholds, block-mode exit code, fail-open); shellcheck
clean.

## Stale-doc truth (6 surfaces, all hedged)

CLAUDE.md · AGENTS-WORKFLOW.md · skills/ship-loop/SKILL.md · the evolve
postmortem-checkpoint (skills/, skills-codex/, packs overlay — kept in
parity; codex hashes regenerated for **evolve + ship-loop only**, the 7
pre-existing drifts left untouched).

## Ratchet (knowledge → a constraint)

Extend `check-hookless-cold-start.sh` to cover these workflow-discipline
surfaces — reversing the now-stale CLAUDE.md carve-out — so this exact
drift class **cannot recur**. Gate scope 5 → 10 surfaces; its bats test
stays green. (This is the "knowledge becomes a constraint" invariant the
whole ag-4hf7 thread identified as our edge — applied to the very gap
that thread surfaced.)

## Verification

- `bats tests/scripts/session-pr-scope.bats` → 8/8
- `bash scripts/check-hookless-cold-start.sh` → PASS (10 surfaces)
- `check-hookless-cold-start.bats` → 5/5 ·
`validate-codex-generated-artifacts.sh --scope head` → pass ·
wiring-closure → pass · shellcheck clean · overlay ≡ source

Closes-scenario: ag-o5xp#session-pr-scope
Bounded-context: BC3-Loop
Evidence: scripts/session-pr-scope.sh
2026-05-31 19:51:07 +00:00
Bo a36abd3675 chore(provenance): align relation enum to W3C PROV-O vocabulary (ag-lmdx.7 #prov-o-vocabulary) (#660)
## What

Rename the provenance ledger relation enum from AgentOps-local
`subject_verb_object` names to the standard **W3C PROV-O / PROV-DM**
verbs so an external auditor recognizes the term, and document the
**columns-not-JSON-paths** guard-read principle in the schema. Schema
changes are single-writer on `main`. Implements ag-lmdx.7.

### Relation mapping (atomic contract change)

| Prior AgentOps-local | W3C PROV-O |
|---|---|
| `decision_produces_artifact` | `wasGeneratedBy` |
| `decision_authorizes` | `wasAssociatedWith` |
| `artifact_derived_from` | `wasDerivedFrom` |
| `scenario_covers_artifact` | `wasInformedBy` |
| `verdict_attests_artifact` | `wasAttributedTo` |
| `bead_scopes_decision` | `wasInfluencedBy` |
| `commit_implements_decision` | `wasRevisionOf` |
| `learning_revises_decision` | `wasInvalidatedBy` |

## Scenarios

- **Relations use PROV-O vocabulary** — the enum now contains only
PROV-O verbs; an edge with the colloquial `derives_from` (or the prior
`artifact_derived_from`) is REJECTED in favor of `wasDerivedFrom`.
Enforced by two new bats cases (accept PROV-O, reject legacy
vocabulary).
- **Guard-read field is a column not a JSON path** — the schema
description now states that guard-read/queryable fields (`from_id`,
`to_id`, `relation`, `trust_tier`, the hash-chain anchors) are
first-class top-level columns, never nested JSON payload paths, because
Dolt JSON-path generated-column indexing is unreliable. The `judge_id`
verdict guard already reads a first-class struct field in
`evidencedturn`; **no Dolt migration is invented** (no Dolt projection
schema exists in this repo — the principle is encoded in the contract).

## Ripple (every merged consumer, atomic)

- `schemas/agentops-sdlc-provenance.v1.schema.json` (enum + description)
- `cli/internal/provenancegraph/edge.go` (`Relations` + godoc)
- schema-driven validator via
`tests/scripts/validate-provenance-ledger.bats` (PROV-O accept + legacy
reject)
- consumers: `drrebuild`, `drwitness`, `evidencedturn`,
`cmd/ao/provenance_*`, `cmd/ao/turn_verify`
- all hash-chained fixtures **re-sealed via the canonical hasher**
(`drrebuild` ledger + frozen `expected-graph-hash.txt`,
`committed-witness.jsonl`); witness dolt-rows + provenance JSON fixtures
updated
- generated `cli/docs/COMMANDS.md` regenerated

## Verification

- `cd cli && go build ./... && go vet ./...` clean; **`go test ./...` →
11942 passed in 72 packages**
- `bats validate-provenance-ledger.bats
witness-dolt-jsonl-crosscheck.bats` → 20/20
- `bats provenance-orphan-fixtures.bats check-provenance-orphans.bats` →
7/7
- `scripts/check-contracts-structural-floor.sh` → PASS (45 contracts)
- `docs/provenance/ledger.jsonl` does not exist (no real entries to
migrate); `.agents/ao/provenance/graph.jsonl` is a separate
transcript-mining graph (no `relation` field) and out of scope.

Closes-scenario: ag-lmdx.7#prov-o-vocabulary
Bounded-context: BC4-Factory
Evidence: schemas/agentops-sdlc-provenance.v1.schema.json
2026-05-31 15:37:11 -04:00
Bo 81c9f305ac feat(ci): witness Dolt->JSONL re-derive + hash-compare (ag-lmdx.3 #witness-crosscheck) (#656)
## What

The **watcher that watches the watcher** (ag-lmdx.3). A blocking CI gate
that re-derives the hash-chained JSONL witness **from the Dolt
projection** and hash-compares it against the git-committed witness
ledger — proving Dolt is a *faithful projection* of the canonical event
log.

This is the **inverse** of drrebuild (#646): drrebuild rebuilds the Dolt
context graph FROM the witness (JSONL + git blobs); this rebuilds the
witness FROM Dolt rows. Together they pin both ends of the projection.
Dolt history is rewritable (reset/--force/root) so it is NOT
tamper-evidence; the git-anchored JSONL witness is. A Dolt rewrite that
did not also rewrite the committed witness is caught here, and nowhere
else.

## How

- `cli/internal/drwitness/` — re-derive + cross-check core. Reuses
drrebuild's exact hash discipline (`ComputeEventHashes`: payload_hash =
sha256(canonical-JSON), hash = sha256(payload_hash + "\n" + prev_hash))
and canonical edge ordering. Re-derivation is order-independent
(canonical sort then re-seal), which is what makes the hash-compare
meaningful.
- `cli/cmd/witness-crosscheck/` — standalone helper main (like
`cmd/skill-frontmatter-json`), **NOT** an `ao` subcommand (no CLI
surface added).
- `scripts/witness-dolt-jsonl-crosscheck.sh` — hermetic CI gate. CI has
no live Dolt, so it drives committed fixtures through the helper and
asserts the gate fires correctly.
- `tests/scripts/` + `tests/fixtures/witness/` — bats behavioral proof.

## Scenarios (acceptance)

- **Clean state passes** — the faithful Dolt projection re-derives to
the committed witness; gate exits 0.
- **Tampered Dolt fails** — a rewritten Dolt row no longer matches the
committed witness head; helper reports `DIVERGED`, gate exits non-zero.

## Verification

- `go build ./... && go vet ./... && go test ./...` (full suite: 11948
passed / 71 pkgs; drwitness: 7/7)
- `bats tests/scripts/witness-dolt-jsonl-crosscheck.bats` — 6/6
- `shellcheck -S warning` — clean
- `scripts/validate-ci-policy-parity.sh` — PASS
- diff is scope-only (10 files, additions); the sibling wave-pregate
(#655) is present and untouched.

Closes-scenario: ag-lmdx.3#witness-crosscheck
Bounded-context: BC4-Factory
Evidence: scripts/witness-dolt-jsonl-crosscheck.sh
2026-05-31 14:39:13 -04:00
Bo 46f0768ed8 feat(swarm): wave pre-gate node-state ownership disjoint (ag-lmdx.6 #wave-ownership-disjoint) (#655)
## What

Adds `scripts/check-wave-ownership-disjoint.sh` — a wave **pre-gate**
that, before spawning a parallel wave of agents, asserts each slice's
owned **node-state** set is pairwise-disjoint. Overlap means two agents
would concurrently transition the same artifact's state — a genuine Dolt
cell conflict on the `context_artifact` state projection / append-only
`state_transition` log (the real convergence invariant from the ag-lmdx
Dolt-expert review). File-disjointness
(`check-file-manifest-overlap.sh`) is only the weak textual shadow of
this.

## Behavior

Input: JSON array of `{id, subject, owns[]}` slices (file arg or stdin).
- **Overlap** → exit 1, names the contended node-state and the
conflicting slice pair, "wave NOT spawned" (Scenario: *Overlapping node
ownership blocks the wave*).
- **Disjoint** → exit 0, "wave may spawn" (Scenario: *Disjoint ownership
proceeds*).
- Slice with no declared ownership → blocked (cannot prove
disjointness).
- Bad usage/input → exit 2. Missing `jq`/old bash → soft skip.

## Tests / gates

- `tests/scripts/check-wave-ownership-disjoint.bats` — 11 hermetic tests
(both scenarios + exact exit codes 0/1/2, stdin, empty, undeclared,
duplicate-within-slice, three-slice).
- `shellcheck -S warning` clean; `bash -n` clean.

Scope is two new files; no `validate.yml`/skill wiring (follow-up).

Closes-scenario: ag-lmdx.6#wave-ownership-disjoint
Bounded-context: BC5-Runtime
Evidence: scripts/check-wave-ownership-disjoint.sh
2026-05-31 14:30:28 -04:00
Bo a6336b7c34 feat(provenance): ao provenance trace --orphans --strict gate (ag-x31t.6 #provenance-orphan-gate) (#653)
## What

Adds `ao provenance trace --orphans --strict`: detects provenance
orphans — artifact nodes with **no inbound authored/inferred edge** — by
generalizing the `goals_trace_orphans` no-inbound chain-gap detection
onto the provenance graph. Wires it as a blocking CI gate.

## How

- **`cli/internal/provenancegraph/orphans.go`** — `ReadGraphRecords`
(parses the goalstrace `Node`/`Edge` JSONL contract that the seeded
fixtures use) + `FindOrphans` (an artifact node is an orphan iff no
edge's `to_id` targets it; it flips green the moment any inbound edge is
added).
- **`cli/cmd/ao/provenance_trace.go`** — the `trace --orphans [--strict]
[--json] [--graph <path>]` subcommand. `--strict` exits non-zero when
orphans exist; `--json` emits one finding per line.
- **`scripts/check-provenance-orphans.sh`** + a new **blocking** step in
`.github/workflows/validate.yml` (in the existing goals/spec-linkage
job, right after the warn-only `ao goals trace --orphans`). The gate
asserts the strict audit **catches** each seeded orphan fixture and
**passes** once an inbound edge wires the artifact back to a directive —
so it is deterministically green while proving the detector is wired.

## Tests (TDD-first)

- `cli/cmd/ao/provenance_trace_test.go` (L2): drives the real
`tests/fixtures/provenance/` fixtures against `expected-orphans.json` —
`--strict` catches each of the 3 seeded orphans
(`gate:scenario-hash-stability`, `artifact:scripts/pre-push-gate.sh`,
`claim:65-jobs`), and a wired graph exits 0. Plus mode/flag-guard cases.
- `cli/internal/provenancegraph/orphans_test.go` (L1): detection,
non-artifact nodes never orphaned, deterministic sort, JSONL parsing +
malformed/missing-file rejection.
- `tests/scripts/check-provenance-orphans.bats`: gate-script behavior.

## Derived surfaces regenerated

- `cli/docs/COMMANDS.md` (new `ao provenance trace` subcommand,
cobra-conformance passes)
- CLI surface smoke fixture + matrix (sub 186→187, all 260→261)
- `registry.json` **unchanged** (provenance is already a top-level
command; subcommands aren't counted) — timestamp-only churn reverted.

## Gates

`go build ./... && go vet ./... && go test ./...` (11959 pass) · gosec
clean on new files (one `#nosec G304` on the operator/CI-supplied graph
path, with reason) · `scripts/validate-ci-policy-parity.sh` PASS.

Closes-scenario: ag-x31t.6#provenance-orphan-gate
Bounded-context: BC4-Factory
Evidence: .github/workflows/validate.yml
2026-05-31 14:07:45 -04:00
Bo 03e365bb92 feat(validate): generate+check tests-from-scenarios coverage (ag-9jle.4 #tests-from-scenarios) (#648)
## What

Adds the C2 "tests-from-scenarios" leaf gate (ag-9jle.4): a per-bead,
forward-from-Gherkin scenario→test coverage check, plus wiring into the
leaf validators `/vibe` and `/test`.

`scripts/check-bead-scenario-coverage.sh` parses a bead's `## Scenarios`
block (via `--bead <id>`), a `.feature` file, or stdin, and **FAILS if
any scenario lacks a `@covered-by:<test-path>` link**. With `--run` it
also executes each covering test and requires it to PASS — not merely
exist. This is the distinction the bead calls out: "tests exist" or a
coverage percentage is not sufficient.

This is the **per-slice sibling** of the existing corpus-wide
`scripts/check-scenario-test-linkage.sh` (which sweeps every `.feature`
under `skills/*/references/` in CI). They share the `@covered-by:`
convention so a scenario authored once carries linkage to both. No new
`ao` subcommand (avoids cli-command-surface churn); no symlinks (codex
twins copied).

## Why

Audit ag-9jle.1 found C2 weak: vibe/validate check test-pyramid
*presence*, `test` checks coverage %, review uses a checkbox; only
`/validation` enforced scenario→passing-test mapping and only at the
bypassable roll-up. This makes the check mechanical and moves it to the
leaf (vibe Step 2g.1, test Step 0a), working forward from behavior.

## How it's tested

`tests/scripts/check-bead-scenario-coverage.bats` — 19 hermetic cases:
M>=N gate, bead-body + `.feature` inputs, `--run` pass vs fail, dangling
`@covered-by`, `::Name` resolution, threshold override, `--json`, stdin,
`## Scenarios`-block scoping, misuse exits. The gate is dogfooded: it
passes on its own bead ag-9jle.4 (`--run` executes this very bats file).

## Gates

- `bats tests/scripts/check-bead-scenario-coverage.bats` — 19/19 pass
- `shellcheck scripts/check-bead-scenario-coverage.sh` — clean
- `bash scripts/check-codex-parity-drift.sh` — no drift (codex twins
mirrored)
- `bash tests/skills/run-all.sh` — 87/0 pass

Closes-scenario: ag-9jle.4#tests-from-scenarios
Bounded-context: BC2-Validation
Evidence: scripts/check-bead-scenario-coverage.sh
2026-05-31 13:00:06 -04:00
Bo 2c5d93e16b feat(ci): scripts/check-proof-coherence.sh (soc-57hbj #proof-coherence) (#647)
## What

Proof-coherence gate for the reconciliation engine (Wave 3C). Two axes
(plan: `.agents/plans/2026-05-07-reconciliation-engine-full-arc.md`):
claim coherence (advisory) and **proof coherence** (claim-ledger row →
daemon criterion-verdict event, **blocking for L2/L3 claims**). This PR
ships proof coherence.

## Coherence predicate

For every L2/L3 claim-ledger row, each `evidence_event_refs[]` entry
must:
1. resolve to a daemon event matching `event_type`+`run_id`
(+`criterion_id` if named) — else **DANGLING**;
2. carry `verdict: pass` — else **FAILED** (demote).

An L2/L3 row with zero refs is **UNBACKED**. L0/L1 rows are not gated.

## Forward-compatible

Wave 1's claim ledger and Wave 3B's `evidence_event_refs` schema haven't
landed, so with no ledger present the gate is a **PASS no-op** — it
lands as blocking CI surface now and becomes load-bearing automatically
once L2/L3 rows appear. Inputs auto-discover
(`docs/contracts/factory-claim-ledger{,.example}.json`,
`cli/.agents/daemon/ledger.jsonl`), overridable via
`--ledger`/`--events`.

## Output / exit codes

Text (default) + `--json`. Exit `0` coherent / no ledger · `1`
incoherent · `2` usage|env.

## Tests

`tests/scripts/check-proof-coherence.bats` — 13 hermetic cases, exact
exit codes + messages, both drift directions (missing event + failed
verdict), unbacked L2/L3, L0/L1 ungated, no-ledger no-op, JSON
pass/fail, malformed-ledger + bad-flag env errors.

## Gates

- `shellcheck -S warning scripts/check-proof-coherence.sh` — clean.
- `bats tests/scripts/check-proof-coherence.bats` — 13/13 pass.
- `git diff origin/main --stat` — scope-only (the two intended files).

## Scope note

validate.yml wiring deferred: a no-op until the ledger ships (Wave 1/3B
precondition); wiring lands with the first L2/L3 ledger row.

Closes-scenario: soc-57hbj#proof-coherence
Bounded-context: BC2-Validation
Evidence: scripts/check-proof-coherence.sh
2026-05-31 12:49:54 -04:00
Bo 5448142268 test(provenance): seed 3 failing orphan fixtures (ag-x31t.7 #orphan-fixtures) (#645)
## What

Seeds 3 **inert, failing-by-design** orphan fixtures for the no-orphan
provenance gate built in **ag-x31t.6** (`ao provenance trace --orphans
--strict`, generalizing `goals_trace_orphans`). Each fixture is a small
goalstrace-shaped graph JSONL (`node`/`edge` records per
`cli/internal/goalstrace/graph.go`) seeding **one engineered artifact
node with no inbound authored/inferred edge** — the orphan condition the
future gate detects.

The three fixtures reproduce the three audit gaps epic **ag-x31t**
closes:

| Fixture | Orphan artifact | Audit gap |
|---|---|---|
| `orphan-scenario-hash-stability.jsonl` |
`gate:scenario-hash-stability` | phantom CI gate with no authoring
directive |
| `orphan-retired-pre-push-gate.jsonl` |
`artifact:scripts/pre-push-gate.sh` | retired-but-present script
reference |
| `orphan-stale-65-jobs.jsonl` | `claim:65-jobs` | stale doctrine claim
("65 jobs") |

`expected-orphans.json` is the contract the **ag-x31t.6** gate will
assert against.

## Verification

Since the consuming gate (ag-x31t.6) isn't built yet,
`tests/scripts/provenance-orphan-fixtures.bats` only verifies the
fixtures are well-formed JSONL and internally consistent with the
manifest (orphan node present, no inbound edge). All 4 checks pass
locally.

## Scope

Fixtures + one format-check bats only. **Out of scope** (sibling beads):
the orphan gate (ag-x31t.6), the ledger schema (ag-x31t.2), any `ao`
subcommand. No symlinks, no holdout data.

Closes-scenario: ag-x31t.7#orphan-fixtures
Bounded-context: BC4-Factory
Evidence: tests/fixtures/provenance/orphan-scenario-hash-stability.jsonl
2026-05-31 12:47:16 -04:00
Bo 0bc1b5a7ee chore(ci): enforce worktree-disposition discipline + prune gate (ag-4oj9.2 #worktree-disposition) (#642)
## What

Closes the CI-gate gap in the worktree-disposition discipline
(ag-4oj9.2). The repo's `bd worktree create` flow accumulates abandoned
tmp worktrees; detection + prune already existed (`gc-stale-worktrees.sh
--apply`, live `check-worktree-disposition.sh`), but nothing **gated**
against an undisposed worktree that gets *committed* into the tree.

- **New `--check-committed` mode** on `scripts/gc-stale-worktrees.sh`:
scans tracked paths (`git ls-files`) for committed tmp-worktree
artifacts — `agentops-*-{merge,rpi*,wt}`, `*-wt/`, `.codex/worktrees/` —
and fails non-zero. Read-only: never touches the working tree, never
removes anything. Uses the existing `--git-common-dir` parent (never
`--show-toplevel`) for main-checkout safety.
- **Wired into `scripts/pre-push-gate.sh`** (step 7a), unconditionally —
it inspects only tracked paths so it is cheap and CI-safe (the live
worktree list is empty on a fresh CI checkout; this catches what CI
*can* see). Auto-runs in CI via the existing `bats tests/scripts/*.bats`
step.
- **Bats coverage**: pass-on-clean, fail-on-committed-tmp-tree (two
naming families), no-false-positive on ordinary source, and a
read-only/no-mutation assertion against the main checkout.

## Why

Undisposed worktrees are statelessness entropy — branch state no agent
owns. The disposition contract (AGENTS-RUNTIME.md) was documented but
not gated against the committed-artifact case. This makes it impossible
for a tmp worktree to land on `main`.

## Gates
- `shellcheck -S warning` — PASS (both scripts)
- `bats tests/scripts/gc-stale-worktrees.bats` — 18/18 PASS
- `scripts/validate-ci-policy-parity.sh` — PASS (no
validate.yml/manifest change; new bats picked up by existing step)
- `git diff origin/main --stat` — scope-only (3 files)

Closes-scenario: ag-4oj9.2#worktree-disposition
Bounded-context: BC5-Runtime
Evidence: scripts/gc-stale-worktrees.sh
2026-05-31 12:43:43 -04:00
Bo 2907503176 fix(ci): cover gate-target files in path filters (ag-nl1u #pathfilter-coverage) (#638)
## What

Closes both **ag-nl1u** and **ag-n4m7** — same class of bug (CI
path-filter gap) on the same surface (`.github/workflows/validate.yml`),
folded into one coherent-arc PR so they don't collide.

A gate that reads a specific set of files must be triggered by a
change-filter covering those files. When it isn't, an edit to a guarded
file SKIPS the gate that guards it, and the required `summary`
branch-protection check goes green-but-incomplete — the regression
reaches `main` and surfaces only on a later unrelated PR.

### ag-nl1u — contracts filter omits redteam-pack targets (#634)
The security-suite redteam pack
(`skills/security-suite/references/agentops-redteam-pack.json`) asserts
behavioral contracts against `AGENTS.md`, `docs/ARCHITECTURE.md`,
`docs/CI-CD.md`, `docs/strategic-direction.md`,
`docs/standards/shell-script-standards.md`, `skills/security/SKILL.md`,
`skills/security-suite/SKILL.md`. The `contracts` filter only matched
`schemas/**` + `docs/contracts/**`, so editing any guarded file skipped
the contracts-sync canaries that guard it (the #634 break, fixed
reactively). **Fix:** extend `contracts` to a superset of every
redteam-pack target glob.

### ag-n4m7 — correctness gates skip on GOALS.md/scenarios (#591/#593)
The directive-to-scenario correctness gates police `GOALS.md` +
`spec/scenarios/**` but ran only on `go || docs || ci`. A GOALS.md-only
edit citing a phantom scenario merged with the gate skipped. **Fix:**
add a `goals` filter (`GOALS.md`, `spec/scenarios/**`,
`docs/adr/ADR-0003*`) and wire `|| needs.changes.outputs.goals` into
goals-validate, F1/F2 spec-link e2e, directive-to-scenario lint,
trace-orphans, scenario-to-test linkage (and the Go setup/build steps
those depend on, since they invoke `cli/bin/ao`).

## Guard test
`tests/scripts/test-pathfilter-gate-coverage.bats` (7 tests) parses the
pack JSON + the validate.yml filters and asserts the `contracts` filter
is a superset of the pack targets and the `goals` filter + gate wiring
stay in place. Prevents this class from regressing.

## Verification
- `python3 + PyYAML` parse of validate.yml: valid; both filters present.
- `bats tests/scripts/test-pathfilter-gate-coverage.bats` -> 7/7 pass.
- `scripts/validate-ci-policy-parity.sh` -> PASS (job blocking
classification unchanged).
- Sibling `test-bats-path-filter-wiring.bats` +
`test-strict-coverage-ci-wiring.bats` -> 8/8 pass (no regression).

## Scope
Only `.github/workflows/validate.yml` + one new guard test under
`tests/`. No other surface touched.

Closes-scenario: ag-nl1u#pathfilter-coverage
Bounded-context: BC2-Validation
Evidence: .github/workflows/validate.yml
2026-05-31 12:35:11 -04:00
Bo 004fcbc249 feat(provenance): agentops-sdlc-provenance.v1 ledger-event schema (ag-x31t.2 #provenance-schema) (#637)
## What

Adds `schemas/agentops-sdlc-provenance.v1.schema.json` — the JSON Schema
(draft-07) that formally defines one event of the committed, per-record
hash-chained provenance ledger at `docs/provenance/ledger.jsonl` (schema
id `agentops-sdlc-provenance.v1`, referenced by CLAUDE.md and the
ag-x31t council architecture).

Each event = one typed provenance edge `{from_id, from_type, to_id,
to_type, relation, evidence_ref, trust_tier(authored|inferred|mined),
ts}` plus export-time hash-chain fields `{prev_hash, payload_hash,
hash}` mirroring `cli/internal/rpi/ledger.go` chaining semantics
(`payload_hash` = sha256 over the edge payload; `hash` =
sha256(payload_hash + "\n" + prev_hash)).

## Acceptance (ag-x31t.2)

> First failing test: validates a `decision_produces_artifact` edge,
rejects one missing `trust_tier`.

- `scripts/validate-provenance-ledger.sh` — python `jsonschema` (Draft7)
validator with `--selftest` and `--jsonl` modes, mirroring
`validate-outcomes-rubric.sh`; SKIPs gracefully when jsonschema is
unavailable.
- `tests/scripts/validate-provenance-ledger.bats` — 12 checks. A
`decision_produces_artifact` edge VALIDATES; an otherwise-identical edge
missing `trust_tier` is REJECTED. Structural-JSON checks are the
always-on guard (run without jsonschema).
-
`tests/fixtures/provenance/{valid-decision-produces-artifact,invalid-missing-trust-tier}.json`
— fixtures with real sha256 chain hashes.

TDD verified: the selftest FAILS when the schema is edited to drop the
`trust_tier` requirement, PASSES when restored.

## Scope

Schema + validator + test only. Does **not** create/edit
`docs/provenance/ledger.jsonl`, the write-model (ag-x31t.4), export
(ag-x31t.5), or gate (ag-x31t.6). No symlinks. No holdout data.

```
gates: validator --selftest pass · bats 12/12 pass
```

Closes-scenario: ag-x31t.2#provenance-schema
Bounded-context: BC4-Factory
Evidence: schemas/agentops-sdlc-provenance.v1.schema.json
2026-05-31 12:35:06 -04:00
Bo d82adc3717 fix(evolve): sync local main to origin/main before discovery (ag-6jt #discovery-origin-main) (#636)
## What

The evolve-cron-rpi loop's phase-1 discovery diffed candidate slices
against a **stale local `main`** (the rpi worktree's local main lags
`origin/main`), so work already merged to `origin/main` read as "open"
and got re-seeded as duplicate beads/PRs (ag-b8m≈ag-jov, ag-6kw≈ag-c2i —
4th recurrence). The `work-selection-ladder` reference *claimed* "the
cron syncs local main to origin/main before discovery" but no code
actually did it.

## Change

- **`skills/evolve/scripts/sync-main-to-origin.sh`** (new): `git fetch
origin`, then fast-forward local `main` to `origin/main` (never forced),
emitting `DIFF_BASE: origin/main <sha>` as the authoritative diff base.
A divergence is refused, never force-moved.
- **`scripts/overnight-evolve.sh`**: runs the sync before the loop's
discovery phase. Non-fatal on warning (loop proceeds with origin/main as
the base).
- **`skills/evolve/references/work-selection-ladder.md`**: the claimed
sync now points at the real, runnable script.
- **`tests/scripts/sync-main-to-origin.bats`** (new): hermetic bare-repo
tests pin the diff base = origin/main after fetch (not stale local
main), local main fast-forwards, divergence is refused, and a custom
remote is respected.

Pairs with the grep-existing-beads guard (`duplicate-work-guard.sh`,
#582) to cover both halves of the bead.

## Gates
- `shellcheck --severity=error` clean on both modified scripts.
- `bats tests/scripts/sync-main-to-origin.bats` — 5/5 pass.
- `git diff origin/main --stat` — scope-only (4 files,
evolve/rpi-discovery surface).

Closes-scenario: ag-6jt#discovery-origin-main
Bounded-context: BC3-Loop
Evidence: skills/evolve/scripts/sync-main-to-origin.sh
2026-05-31 12:35:00 -04:00
Bo 0f16a574bc feat(eval): outcomes-rubric projection contract + schema (ag-hguuf #outcomes-rubric) (#624)
## What

Defines the machine-checkable contract for projecting the **locked eval
substrate** into an **Outcomes-style grading payload** (Anthropic
Managed Agents Outcomes analog) — holdout-safe by construction *and* by
schema.

The schema validates the **actual** output of `ao eval outcomes compile`
(`evalsubstrate.Rubric`), not the bead's pre-implementation prose sketch
(which imagined `suite_id`/`metric`/`decision_rule`/`split`). Per
source-of-truth precedence (executable > narrative), the shipped
projection deliberately emits *fewer* fields — a smaller cloud boundary
is a smaller leak surface. The "deliberately NOT projected" rationale is
documented in the contract.

## The load-bearing invariant

**Managed Agents are not ZDR** — a rubric crossing the cloud boundary
must never carry a ground-truth answer / holdout value / `target` /
`expected_output`. Enforced three ways:
1. **By construction** — `ProjectRubric` can't copy ground truth
(existing).
2. **By re-scan** — `Rubric.ContainsAny` guard (existing).
3. **By schema (this PR)** — `additionalProperties:false` at **every
nesting level** → a malformed compiler emission that smuggles a leak
field **fails schema validation**, not merely a code check.

## Files
- `schemas/outcomes-rubric.v1.schema.json` — the contract schema
-
`tests/fixtures/outcomes-rubric/{valid-dev,valid-holdout-criteria-only,invalid-contains-target}.json`
- `scripts/validate-outcomes-rubric.sh` — standalone validator (python
`jsonschema`, mirrors `validate-next-work.sh`); `--selftest` asserts
pass/pass/fail
- `tests/scripts/validate-outcomes-rubric.bats` — 9 acceptance tests
- `cli/internal/evalsubstrate/rubric_schema_test.go` — Go schema↔struct
drift guard (reflection)
- `docs/contracts/outcomes-rubric-projection.md` —
SCHEMA-field→Outcomes-field mapping; catalogued in doc index;
cross-linked from `eval-verdict-pipeline.md`

The contract **references** the LOCKED `~/.agents/evals/SCHEMA.md`
§rc2/§4 — it never edits it. Substrate EXTENDED, never relitigated.

## Evidence
- `scripts/validate-outcomes-rubric.sh --selftest` → PASS/PASS/FAIL
(exit 0)
- `bats tests/scripts/validate-outcomes-rubric.bats` → 9/9 ok
- `go test ./internal/evalsubstrate/` → 82 passed; `go vet` clean; `go
build ./...` success
- `check-contract-compatibility.sh` → contract catalogued + schema
reference OK
- `shellcheck scripts/validate-outcomes-rubric.sh` → clean

Closes-scenario: ag-hguuf#outcomes-rubric-projection-contract
Bounded-context: BC4-Evaluation
Evidence: schemas/outcomes-rubric.v1.schema.json
2026-05-30 07:07:36 -04:00
Bo 9e311c7e61 fix(ci): pre-push-gate skips intentionally-removed hookless-3.0 scripts (ag-nrn7 #hookless-gate-skips) (#622)
## What

The full (non-fast) `scripts/pre-push-gate.sh` exits BLOCKED on pristine
origin/main, partly because 3 hook-validation scripts it references were
**intentionally deleted in the hookless-first migration** (#511):
`audit-codex-hooks.sh`, `validate-hook-preflight.sh`,
`validate-hooks-doc-parity.sh`. Their gate branches still ran `fail
"missing executable"` when a hook diff triggered `needs_check hook` — 3
of the 8 failures in the release-readiness gate (ag-nrn7 triage).

## Fix

Convert each `else fail` → `skip` with a hookless-3.0 rationale.
**Forward-compatible** (if a script is ever restored, the `[[ -x ]]`
branch still runs it) and **honest** (intentionally-absent ≠ broken). 3
lines changed.

## Test

Added a regression test: the bats setup stubs every helper script
present (per f-2026-04-27-002), masking the absent-script path. The new
`ag-nrn7` case removes the 3 stubs, triggers a hook diff, and asserts
the gate **skips** (no `missing executable`) rather than fails.

- `bats tests/scripts/pre-push-gate.bats` → 56/56 ok (new case green;
red before the fix on the `audit-codex-hooks.sh` assertion).
- `shellcheck -S error scripts/pre-push-gate.sh` → clean.

Removes 3 of the 8 `pre-push-gate.sh` failures triaged in ag-nrn7;
advances soc-z3jft 3.0 release readiness.

Closes-scenario: ag-nrn7#hookless-gate-skips
Bounded-context: BC5-Runtime
Evidence: tests/scripts/pre-push-gate.bats
2026-05-30 03:25:21 -04:00
Bo 0c42512fdd feat(ci): agent-output-validate.yml — reusable authoritative gate on agent output (ag-mptr #agent-output-validate) (#617)
## What

Reusable, authoritative CI gate over **agent-produced output** — the
hookless guardrail for out-of-session agents (Claude Managed Agent,
Agent SDK loop, or NTM/Codex swarm). A `workflow_call` job runs `ao
validate --gate` (the umbrella composing ratchet/standards/scenario)
against an agent's PR/artifact and propagates PASS/WARN/FAIL to the job
exit code. **CI is the gate, not a ported hook** (AgentOps 3.0 is
hookless).

Second child of epic **ag-7s9fo** (Make Managed/SDK agents
AgentOps-native), after ag-2wln `/agent-native` (#616). Inherits the
richer spec absorbed from superseded ag-toat4; the optional SDK hook
adapter was split out to ag-50m3.

## Files (3, +184/−0)

- `scripts/agent-output-validate.sh` — testable gate logic. Resolves
`ao` (`AO_BIN` override), runs `ao validate --gate "$@"`, propagates
exit (0 pass/warn, 1 fail, 2 error). **Fails loudly if `ao` is missing**
— a missing gate never reads as a clean pass.
- `.github/workflows/agent-output-validate.yml` — `workflow_call`
wrapper (inputs: `changes`, `strict`); builds `ao`, runs the script.
Runtime-agnostic (serves Managed-Agent + NTM-swarm PRs).
`workflow_call`-only **by design** — it's adopted by a caller, not
triggered standalone, so it does not run on this PR.
- `tests/scripts/agent-output-validate.bats` — 7 cases. The
**passing+failing fixture evidence** the bead requires, exercised
deterministically via an injectable fake `ao` (exit 0/1/2), plus
scope-flag forwarding, missing-binary, strict-mode, and workflow-wiring
assertions.

## Evidence

- `bats tests/scripts/agent-output-validate.bats` → **7/7 green**
- `shellcheck scripts/agent-output-validate.sh` → clean (severity=error)
- Real-`ao` smoke: against the live binary the script faithfully
propagates the gate verdict (an empty dir yields ao's exit-2 "no
artifacts" → ERROR, proving no silent pass)
- yaml parses valid

## Note for review

The workflow is `workflow_call`-only, so CI here can't execute it
(nothing `uses:` it yet). The **bats suite is the regression proof** for
the gate logic; the yaml is the thin Actions wrapper a caller adopts.
Bare invocation (no `changes`/`bead`) intentionally surfaces ao's exit-2
— callers scope the gate via the `changes` input.

Closes-scenario: ag-mptr#agent-output-validate
Bounded-context: BC5-Runtime
Evidence: tests/scripts/agent-output-validate.bats
2026-05-30 00:37:21 -04:00
Bo 8a4e78f01c docs(evolve): bake fix-and-repush discipline into the /evolve skill (ag-j4l1 #evolve-discipline-references) (#615)
## What

Promotes this session's hard-won fix-and-repush discipline — which lived
only in the **session-only cron prompt** (expires in 7 days) — into the
**durable `/evolve` skill**, so every future autonomous run inherits it.

## How

- **NEW** `skills/evolve/references/new-skill-landing.md` — the **six
derived surfaces** a new/modified skill must regenerate in one shot
(registry.json being the most-missed; it trips `contracts-sync` +
`correctness(ubuntu)` together), with the `regen-all.sh` shortcut and
the manual codex-twin / `SKILL-TIERS.md` steps.
- `gate-hygiene.md` **+2 subsections**: pre-push **diff-scope check**
(catches half-staged commits like #612 + conflict-resolution collateral
deletions like #600) and **pre-existing-vs-mine red triage**
(mkdocs-strict + the 7 codex `.agentops-generated.json` drifts).
- `SKILL.md` links both from Step 4.5 + the References list.

## Dog-fooding

Built one-shot through its own documented discipline: codex twin hash
refreshed for `evolve`, the 7 pre-existing codex drifts reverted,
manifest surgically rebuilt to the `evolve` delta only. No
inventory/count files touched (correct — adds references, not a skill).

## Evidence

- `tests/scripts/evolve-discipline-references.bats` → **4/4** (locks
both reference links + the two new gate-hygiene subsections)
- `heal.sh --strict skills/evolve` → clean
- `validate-codex-generated-artifacts.sh --scope worktree` → pass

(Companion: ag-cw2y wired the skill-builder *scaffold*; ag-ekyq added
the registry surface; this bakes the operator-side *runtime guidance*
into /evolve.)

Closes-scenario: ag-j4l1#evolve-discipline-references
Bounded-context: BC2-Validation
Evidence: skills/evolve/references/new-skill-landing.md
2026-05-29 22:29:31 -04:00
Bo b0a7f4e958 fix(skill-builder): scaffold regenerates registry.json — the 5th one-shot-green surface (ag-ekyq #scaffold-registry-regen) (#614)
## What

skill-builder's `init.sh` new-skill plumbing (ag-cw2y) wired **4 of 5**
derived surfaces — dispositions, narrative counts, codex
override-catalog — but **not** the `registry.json` SKU catalog. A stale
`registry.json` trips `contracts-sync` ("registry.json is stale") AND
`correctness(ubuntu)` ("SKU_CATALOG: DRIFT") together.

This was the **most-missed surface** this session: it cost `/burndown`
#600 a 2nd fix-and-repush (`22a0af2f`) and was a manual
`generate-registry.sh` step for `/eval-outcomes` (#613).

## How

Adds `generate-registry.sh` as plumbing **step 4** in `init.sh`,
positioned **last** (it scans the whole `skills/` tree, so the skeleton
+ the other 3 surfaces must exist on disk first), guarded with a `WARN`
fallback like its siblings. A new skill is now one-shot-green across all
5 surfaces with zero manual regen.

## TDD

`tests/scripts/scaffold-registry-regen.bats` (4/4 green) locks the
wiring + ordering contract: init.sh invokes the canonical generator,
guarded, after the override-catalog step and before the final skeleton
echo. `generate-registry.sh` is not repo-root-injectable (it reads
hooks/types.go/schedule across the tree), so the contract is the
wiring+ordering; the end-to-end behavior was empirically validated this
session running `generate-registry.sh` on the freshly-scaffolded
`/eval-outcomes` (#613, registry included the new skill).

## Scope

Reverted the 7 pre-existing-main codex `.agentops-generated.json` drifts
that `regen-codex-hashes` swept in; surgically rebuilt the manifest to
skill-builder's hash delta only (changing init.sh refreshes
skill-builder's codex twin hash — a real consequence of this diff).

Closes-scenario: ag-ekyq#scaffold-registry-regen
Bounded-context: BC4-Factory
Evidence: tests/scripts/scaffold-registry-regen.bats
2026-05-29 21:50:30 -04:00
Bo 4d18300790 chore(tests): codex-desc budget is per-skill-average, not a hard aggregate (ag-vzbt) (#612)
## What
**ag-vzbt** — the last `ag-cw2y` item. The skills-codex description
catalog budget was a **hard aggregate** (2800 chars, bumped
2600→2700→2800 as skills landed) with ~17 chars headroom. Adding the
Nth+ skill walls out — `/burndown` #600 was forced into a 17-char stub
("Bounded epic loop") to fit.

## How
Replace the hard aggregate with a **per-skill average** cap
(`CODEX_DESC_AVG_FAIL_CHARS=45`) that scales with the catalog:
- Each terse description keeps the average low; the gate fails only if
descriptions are **bloated on average** — not because the catalog grew.
- Current state: avg **35** chars/skill (77% of 45) — real headroom, and
it never becomes a wall again.
- The per-skill hard cap (`DESC_FAIL_CHARS=180`) still bounds any single
bloated description.
- `BUDGET_REPO_ROOT` override added so the rule is fixture-testable.

## Tests (TDD, red→green)
`tests/scripts/codex-desc-avg-budget.bats` — PASS under budget / FAIL
over budget / **100 skills (total ~3800 > old 2800 wall) still pass**
because avg stays low. 3/3 green; shellcheck clean; real-repo gate
passes (avg 35/45).

## ⚠️ Pre-existing unrelated red
The local fast gate also surfaces a **pre-existing** `mkdocs strict`
failure on `rfcs/0001-finding-generator-parallelism.md` — reproduces on
clean `origin/main` with my changes stashed; my diff touches only the
test script + bats (zero docs). Flagging separately; not in scope here.

## ag-cw2y status
**All four items now done** (items 1,2,4 merged #609/#610/#611; item 3
here). A brand-new skill is now **one-shot-green** → this unblocks
**`ag-hdqu0.8`** (last Outcomes bead) and **`/burndown` #600**.

Closes-scenario: ag-vzbt#per-skill-average-budget
Bounded-context: BC2-validation
Evidence: tests/scripts/codex-desc-avg-budget.bats
2026-05-29 20:30:49 -04:00
Bo 0023aa5acf feat(skills): skill-builder scaffolds codex override-catalog entry (ag-cw2y item 4) (#611)
## What
**ag-cw2y item 4** — the 4th and last new-skill gate that cost
`/burndown` #600 a CI round. A new skill previously tripped
`validate-codex-override-coverage` ("source skill missing from Codex
catalog"). skill-builder now adds the catalog entry automatically.

## How
- **`scripts/append-codex-override-entry.sh`** — idempotent, JSON-aware:
appends a `parity_only` entry
(`name`/`treatment`/`wave=catalog-parity`/`reason`) to
`skills-codex-overrides/catalog.json` if the skill is absent.
`parity_only` is correct for skill-builder's canonical-derived codex
form; author flips to `bespoke` + scaffolds the override dir only if a
Codex-only divergence is needed. Repo-root-injectable.
- **`init.sh`** — calls it in the new-skill plumbing block alongside the
dispositions row (#609/#610) and `--fix-counts` (#610). All three gates
now pre-empted at scaffold time.

## Tests (TDD, red→green)
`tests/scripts/append-codex-override-entry.bats` — appends parity_only /
stays valid JSON / idempotent / no-dup-on-existing. 4/4 green.
shellcheck clean.

## Codex artifact
Refreshed **only skill-builder's** hash (6 unrelated pre-existing `main`
drifts untouched). PR-scope codex validation passes.

## ag-cw2y status after this
Item 1 (#609 check + #610 scaffold) ✅ · Item 2 (#610) ✅ · **Item 4
(here)** ✅ · **Item 3** (codex desc token budget / `ag-vzbt`) is the
only remaining piece. Once item 3 lands, a new skill — and therefore
`ag-hdqu0.8` + `/burndown` #600 — is fully one-shot-green.

Closes-scenario: ag-cw2y#override-catalog-scaffold
Bounded-context: BC4-factory
Evidence: tests/scripts/append-codex-override-entry.bats
2026-05-29 20:03:37 -04:00
Bo 5918fd559f feat(skills): skill-builder scaffolds dispositions row + narrative counts (ag-cw2y items 1-scaffold + 2) (#610)
## What

Completes **ag-cw2y item 1's scaffold-half + item 2**. A
newly-scaffolded skill is now one-shot-green against the two gates that
silently tripped `/burndown` #600:
1. missing `skill-dispositions.yaml` row → `heal.sh` Check 12
(`MISSING_DISPOSITION`, shipped #609)
2. stale `"N checked-in skills"` narrative counts →
`check-registry-drift`

## How
- **`scripts/append-skill-disposition.sh`** — idempotent helper that
appends a dispositions row (valid `BC4 Factory` placeholder + TODO
rationale, so `check-bounded-contexts-drift` passes; author refines
during content fill). Repo-root-injectable → fixture-testable.
- **`init.sh`** — after scaffolding, calls the helper *and* runs
`check-registry-drift.sh --fix-counts` to bump the narrative skill-count
tokens. Both calls are guarded + WARN-on-failure so they never break the
scaffold.

## Discovery (scope-narrowing)
Item 2's **check + `--fix-counts` already existed** and were wired into
both the fast pre-push gate (line 1330) and CI (line 803). The only gap
was that **skill-builder never invoked them** — so the fix is wiring,
not a new check.

## Tests (TDD, red→green)
`tests/scripts/append-skill-disposition.bats` — appends row / valid BC +
TODO / idempotent / no-dup-on-existing. 4/4 green. shellcheck clean.

## Codex artifact
Refreshed **only skill-builder's** source/generated hash (6 unrelated
pre-existing `main` drifts left untouched). PR-scope
`validate-codex-generated-artifacts --scope head` passes.

## ag-cw2y remaining
Item 1 (check #609 + scaffold here) ✅ · Item 2 (here) ✅ · **Item 3**
(codex desc budget / `ag-vzbt`) and **Item 4** (override-catalog
scaffold + `test-codex-override-coverage`) remain — then `ag-hdqu0.8`
and `/burndown` #600 are fully one-shot-green.

Closes-scenario: ag-cw2y#skillbuilder-scaffold-dispositions-counts
Bounded-context: BC4-factory
Evidence: tests/scripts/append-skill-disposition.bats
2026-05-29 19:49:20 -04:00
Bo 3711106671 feat(skills): heal --strict checks skill-dispositions coverage (ag-cw2y item 1) (#609)
## What

First slice of **`ag-cw2y`** (make adding a skill one-shot-green).
Adding `/burndown` (ag-3yl8 #600) cost a CI round because a new
user-invocable skill with **no row in
`docs/contracts/skill-dispositions.yaml`** passed every local check
(`audit-codex-parity --skill`, `heal --strict`, `sync-skill-counts`)
silently — the miss only surfaced in CI.

This adds the local catch: **`heal.sh` Check 12 — dispositions
coverage.** Every user-invocable `skills/<n>` must have a dispositions
row, else `MISSING_DISPOSITION` (exit 1 under `--strict`). Same
internal/non-invocable exemptions as the existing catalog check (Check
10).

## How
- `heal.sh`: new Check 12 (global), plus a `HEAL_REPO_ROOT` env override
so the check is fixture-testable; production still derives `REPO_ROOT`
from script location.
- Verified **no `MISSING_DISPOSITION` on the real repo** — all current
skills are covered, so this is a pure tightening with zero false
positives.

## Tests (TDD, red→green)
`tests/scripts/heal-dispositions.bats` — fixture skill missing a row →
flagged; with a row → clean; `--strict` exits 1 and names the miss. All
3 green.

## Codex artifact note
Editing `skills/heal-skill/` requires a paired
`skills-codex/heal-skill/` update (the source-hash). I refreshed **only
heal-skill's** `.agentops-generated.json` + its manifest entry. The 6
unrelated pre-existing codex-hash drifts on `main`
(deps/trace/scenario/provenance/red-team/release) are **left untouched**
— out of this PR's scope. PR-diff-scoped
`validate-codex-generated-artifacts.sh --scope head` passes.

## Remaining ag-cw2y items (follow-on)
Item 1 (dispositions) is the check half done here. Items 2 (domain-map
narrative counts), 3 (codex desc budget / ag-vzbt), 4 (codex
override-catalog scaffold) + the skill-builder *scaffold* halves remain
— they fully unblock `ag-hdqu0.8` and `/burndown` #600 one-shot-green.

Closes-scenario: ag-cw2y#dispositions-coverage-check
Bounded-context: BC2-validation
Evidence: tests/scripts/heal-dispositions.bats
2026-05-29 19:33:06 -04:00
Bo fe731d12b9 feat(skills): skill-flow connectivity gate + closed consumes vocabulary (#597)
## Do all skills flow together?

**No — not until this PR.** Investigating the question surfaced a
structural gap: skill dependencies are declared across **three
overlapping frontmatter fields that drifted apart and were never
reconciled**, and nothing enforced connectivity or constrained the
`consumes` vocabulary.

| Field | Meaning | Read by context-map? |
|-------|---------|----------------------|
| `consumes` | upstream inputs | yes (data-flow table) |
| `context_rel` | DDD relationship | yes (mermaid) |
| `metadata.dependencies` | upstream skill slugs | **no** |

Findings (76 skills):
- **33 skills** where `consumes` (skills) ≠ `metadata.dependencies` —
the two skill-slug fields disagree.
- The generated `context-map.md` **ignored `metadata.dependencies`
entirely** (34 skills, the richest layer).
- Counting all three layers, **16 true orphans** (incl. core skills like
`push`, `session-bootstrap`) with zero skill-to-skill edges — silently.
- `consumes` was an **open free-text field**: no check that a token
resolves to anything.

`scripts/audit-skill-metadata.sh` already flagged the
`consumes`-vocabulary and connectivity checks as *"discovered
follow-ups, not enforced."* This is that follow-up.

## What this PR does

**1. Connectivity gate** — `scripts/validate-skill-flow.sh` (+
`validate-skill-flow` CI job):
- **Closed `consumes` vocabulary**: every token must resolve to a skill
slug, a whitelisted external input (`repo-context`, `external-api`,
`bd`, `github-pr`, `onboard`), or an artifact some skill produces.
Catches typos/undeclared deps.
- **`metadata.dependencies` resolution**: every entry must name a real
skill.
- **Orphan detection** across all three edge layers; un-allowlisted
orphans fail.
- Reports (non-fatal): cross-layer disagreement + dead-end artifacts, so
they can be reconciled later.

**2. Wire the genuine-gap edges** — added `context_rel` for 6
disconnected skills and regenerated `context-map.md`:
- `deps` → `vibe`, `red-team` → `vibe` (mirrors
`security`/`security-suite`)
- `provenance` ↔ `trace`
- `scenario` → `validation`
- `release` → `ship-loop`

**3. Close the vocabulary** — the closed `consumes` namespace is
enforced by the gate and documented in `docs/contracts/skill-flow.md`
(linked in `documentation-index.md`). 14 intentionally-standalone leaves
are allowlisted in `scripts/skill-flow-standalone.txt` with a rationale
per entry.

## Verification

```
$ bash scripts/validate-skill-flow.sh
validate-skill-flow: 76 skill(s), 121 skill-to-skill edge(s)
  orphans: 14 (allowlisted standalone: 14)
OK: skill flow is connected and the consumes vocabulary is closed.
```

- `validate-skill-flow.sh`: exit 0 ✅
- `validate-context-map-drift.sh`: exit 0 ✅
- `check-contracts-structural-floor.sh`: PASS (contract cataloged) ✅
- 11 acceptance tests in `tests/scripts/validate-skill-flow.bats` (bats
not installed locally; exercised via manual smoke + will run in CI
`bats-tests`).

Bounded-context: BC1-Corpus
Evidence: OK: skill flow is connected and the consumes vocabulary is
closed.

---
_Generated by [Claude
Code](https://claude.ai/code/session_01WLdHEva31cixBjxo8z9TXK)_

Co-authored-by: Claude <noreply@anthropic.com>
2026-05-29 18:26:05 -04:00
Bo e33fa8c5e2 feat(eval): deny-by-default holdout-leak CI gate for Outcomes payloads (ag-hdqu0 #leak-gate) (#605)
## What
Adds the **fourth holdout-leak guard** for ag-hdqu0:
`scripts/check-outcomes-holdout-leak.sh` — the authoritative CI check (a
script, not a hook) that refuses any Outcomes rubric/score payload
carrying a `target`/`ground_truth` **key**. Managed Agents are not ZDR,
so a leak is permanent; this backs the by-construction (`ProjectRubric`)
+ re-scan (`ContainsAny`) + drift (`FreshAgainst`) guards with a
deny-by-default gate.

- Deny-by-default: unreadable file → fail; no args → usage error.
- Wired as a **step in the existing `contracts-sync` job** (scans
committed Outcomes payload fixtures; empty set passes, gate armed for
future fixtures). **No new job** → jobs-table unchanged (11 rows),
`ci-policy-parity` green (verified locally pre-push).

## Tests (TDD)
- `tests/scripts/check-outcomes-holdout-leak.bats` — 6 cases: clean→0 ·
target→1 · ground_truth→1 · mixed→1 · unreadable→1 (deny-by-default) ·
no-args→usage. All pass; `shellcheck --severity=error` clean.

Closes-scenario: ag-hdqu0.6#leak-gate
Bounded-context: BC1-Corpus
Evidence: tests/scripts/check-outcomes-holdout-leak.bats
2026-05-29 16:48:30 -04:00
Bo 4107bbed1c refactor(ci): rebuild validate.yml — 67 jobs → 10 purpose-grouped (ag-877 #gate-rebuild) (#592)
## What

First-principles rebuild of `.github/workflows/validate.yml` (ag-877 /
epic ag-5ck, no strangler). Collapses the **67-job** orchestration into
**9 purpose-grouped jobs** (+ `changes` + `summary` = 12 total). All
**59** `scripts/{check,validate}-*` are preserved verbatim — the checks
are the safety logic; the 67-way job fan-out was accretion slop.

Design: `spec/teardown-2026-05-28/gate-rebuild-first-principles.md`

## How

Each purpose job runs its script family as **path-gated steps**
(per-step `if: needs.changes.outputs.X`), with advisory checks marked
`continue-on-error: true` at the **step** level (no whole-job
non-blocking). Notable structural moves:

- **correctness** = matrix `[ubuntu, windows]` — folds `windows-smoke`
in as a Windows leg (it runs `tests/windows/*.ps1`, no `scripts/`
family) instead of a standalone job.
- **doctrine-proof** = the doctrine/GOALS proofs **+ spec-linkage**
(executable-spec link, scenario↔test linkage, AGENTS split,
docs↔learning) — both prove the GOALS/spec apparatus is consistent and
share the Go+ao+Python setup (10→9).
- **summary** absorbs **AP#7** Evidence verification (was
`validate-pr-evidence-claims`) — it needs every sibling job's logs, so
it must run last, not in a parallel group.

## Acceptance (ag-877)

- **ac-gr.1 coverage-proof empty** — `comm -23` of old-vs-new
`scripts/*` invocations is empty (no script dropped). ✅
- **ac-gr.2 job count ≤12** — `grep -cE '^  [a-z][a-z0-9-]+:$'` = 12. ✅
- **ac-gr.3 self-CI green** — this PR runs the new `validate.yml`
against itself (changes `.github/**` → all paths trigger). ⏳ this run.

Coupled job-name contract projections updated in lockstep:
`docs/contracts/ci-jobs.yaml` manifest (64→9), regenerated
`AGENTS-CI.md` table + `registry.json` (gate SKUs 66→11; skills/cli/ref
untouched), and 3 structural bats tests re-anchored to the grouped jobs.
Local: `validate-ci-policy-parity`, `registry-check`,
`validate-sku-catalog-drift`, `check-wiring-closure` all PASS; full bats
suite **740 tests, 0 failures**.

## ⚠️ Operator-gated cutover (do NOT auto-merge)

Branch protection still lists the **64 old** required-check names. This
PR **cannot auto-merge** until an admin swaps them for the new ~10
(**ag-7hpl**), then verifies a no-op PR is gated by exactly the new set
(**ag-1eqi**). Both are repo-admin, repo-wide blast radius →
operator-coordinated.

Closes-scenario: ag-877#uniform-gates-consolidated
Closes-scenario: ag-877#heterogeneous-setup-ported
Closes-scenario: ag-877#changes-preserved-summary-rewired
Closes-scenario: ag-877#coverage-proof-empty-ci-green
Bounded-context: BC2-Validation
Evidence: CI_JOBS_TABLE: PASS
2026-05-29 00:16:47 -04:00
Bo 4e4842865d feat(goals): anti-regeneration fitness goal — teardown-removed apparatus stays removed (ag-8ok #anti-regen) (#591)
3.1 teardown **keystone** (ag-8ok), discovered-from ag-097. Makes
subtraction a *measured* fitness outcome so the `/evolve` loop can't
quietly rebuild what the teardown removed.

### The design (NOT a size metric — that's a GOALS.md Anti-Star)
GOALS.md "## Anti Stars" forbids "Goals that measure code metrics
instead of user outcomes." So this is a **stay-removed guard**, not a
"fewer lines/files/jobs is better" ratchet: it fails *only* when a
surface the teardown explicitly removed comes **back**. Legitimate new
growth is fine; only regrowth of specifically-removed apparatus fails.
That's a real outcome ("the slop we removed stays removed"), not a size
metric.

This session is the live evidence ag-8ok predicts: planning regenerated
duplicate P1 beads (ag-cbt/ag-2oi) faster than the system pruned.
Without an anti-regeneration signal, the loop's merge=reward incentive
re-grows apparatus.

### What changed (additive only)
- `scripts/check-no-apparatus-regrowth.sh` — reads a manifest of removed
paths; exit 0 if all stay gone, exit 1 (per-path message) on regrowth.
`--json`/`--manifest`/`--root` flags.
- `scripts/removed-apparatus.txt` — the data-driven manifest (5
surfaces: wikiworker #589, plans/worker #581, gascity + bridge/gc.go
#590). Future teardown waves append here in the same change that lands
the deletion.
- `GOALS.md` — one measurable goal (`no-apparatus-regrowth`, weight 5)
wired to the script + one strategic Directive (D15,
`d-teardown-removed-apparatus-stays-removed`), framed as an outcome. No
North/Anti-Star edits.
- `tests/scripts/check-no-apparatus-regrowth.bats` — 8 tests
(PASS-when-absent, FAIL-when-regrown, json, missing-manifest, and a
guard that the real committed manifest passes on the real tree).

### Verification
- `bash scripts/check-no-apparatus-regrowth.sh` → PASS, all 5 stay
removed, exit 0
- `bats` 8/8 · `shellcheck` clean
- `ao goals measure` (built from source) surfaces
`no-apparatus-regrowth: PASS`; `--directives` lists D15; `goals
validate` valid

Closes-scenario: ag-8ok#anti-regen
Bounded-context: BC1-Corpus
Evidence: spec/teardown-2026-05-28/
2026-05-28 20:44:39 -04:00