1054 Commits

Author SHA1 Message Date
boshu be542af632 feat(ms): ms-reindex wrapper + post-merge hook installer — mechanize the reindex law (age-22g0) 2026-07-02 16:29:46 -04:00
boshu f63b87dee9 feat(pawl): cold reviewer failover chain — outage-only, honest degraded label, codex-only default (age-rk3r.2) 2026-07-02 14:44:08 -04:00
boshu 04456783e4 feat(verify): ao verify init — portable pre-push verdict ratchet + chain verify (age-rk3r.6)
Install a sovereign LOCAL pre-push hook in any repo that makes no verdict = not
done MECHANICAL: it refuses any push to main/master whose commits lack a
commit-bound CONFIRMED cross-family verdict edge in docs/provenance/ledger.jsonl
(or the provenance-only #trivial waiver), and verifies the ledger hash chain.

- ao verify init [--remove]: install/refresh/uninstall; idempotent; chains a
  pre-existing pre-push hook via a sidecar and restores it byte-identically.
- ao verify pre-push (hidden): the runtime gate — chain verify + per-commit
  verdict-or-#trivial-waiver over the pushed range. Pure Go: NO repo-tree script
  is trusted, so a repo cannot subvert its own gate.
- HOOKS-PATH RESOLUTION delegated to git (round-13, honest-mistakes fix):
  resolveHooksDir asks git where the hook goes —
  `git rev-parse --path-format=absolute --git-path hooks` (via trustedGit) —
  instead of hand-classifying core.hooksPath absolute-vs-repo-relative. That
  hand-split installed a ~-expansion value (core.hooksPath=~/ao-hooks) into
  <repo>/~/ao-hooks while git ran hooks from $HOME/ao-hooks, so `ao verify init`
  reported success but the ratchet silently never ran. git's own resolution
  honors ~-expansion, absolute, repo-relative, and common-dir/worktree cases at
  once; fail-closed if git returns no usable absolute path. (Distinct from the
  parked adversarial repo-relative-hooksPath threat — this is a legitimate
  operator config; that is the repo attacking itself, still out of scope.)
- TIP-TREE PROOF (round-2): chain verify + verdict-edge check read the ledger
  blob AS COMMITTED at the pushed tip, never the working tree.
- COMMIT-RANGE, no tip-narrowing (rounds 3,7,10): creation / unknown-base derive
  via git rev-list <tip> --not refs/remotes/*/<branch> (GATED TRUNK only); no
  trunk ref for an absent non-zero base → refuse fail-closed.
- PARSING-DISCIPLINE SWEEP (rounds 11-12): every verdict-edge / ledger /
  git-output recognition is EXACT and fail-closed. Verdict match requires
  relation=="wasDerivedFrom" + shaBindsCommit + parseDisposition=="CONFIRMED"
  (shared with `ao done`), never substring; the #trivial waiver uses diff-tree
  -z NUL paths via the shared provenanceOnlyChangedFiles.
- CONVERGE-BY-DELETION of the planted-binary class (rounds 4-6): baked-only ao +
  trustedLookPath git + install-time repo-internal-bake refusal.
- SCOPE (documented, parked): defends honest mistakes + misconfiguration, NOT an
  adversarial repo subverting its own gate (PRODUCT.md).
- AO-VERSION FLOOR: the hook probes ao provenance ledger-reader-version.
- Config: init surfaces the effective verify policy via the age-rk3r.5 config.

Tests: 40 Go + 12 bats. RED-first proven for every refute, including round-13's
git-resolved hooksPath (core.hooksPath=~/aohooks → hook installed where git
actually runs it, not <repo>/~/aohooks).

# Conflicts:
#	docs/cli-surface.json
#	docs/cli-surface.md
#	evals/agentops-core/cli-command-surface-matrix.json
#	evals/agentops-core/fixtures/cli-command-surface-smoke.sh
2026-07-02 14:13:13 -04:00
boshu 6447ddf391 feat(ship): route the default gate to the Go release authority — ao gate check (age-fkps)
(d) ship.sh's default_gate previously hard-wired scripts/pre-push-gate.sh
(legacy bash). The release authority is the Go gate: route the default to
`ao gate check --fast --scope head` (routine diff) / `ao gate check --full`
(inventory diff), resolving ao via AO_BIN, then the repo binary, then PATH.
The legacy bash gate stays reachable exactly the way the repo documents it
(AGENTOPS_GATE_BASH=1, mirroring scripts/hooks/pre-push.local), and is the
loud fallback when no ao is resolvable. --dry-run names the routed gate.
2026-07-02 13:48:18 -04:00
boshu acdd335404 feat(land-lane): verdict-stamped closes via ao done + opt-in --prune-source for landed source worktrees (age-fkps, age-ym4b)
(c) close modernization: land.sh and land-lane-run.sh close_bead now PREFER
`ao done <bead> --sha <verdict-bound-feat>` (the verdict-stamped close — no
verdict = not done), falling back to raw br close only when ao is absent or
cannot close. Both closes key on the reviewed FEAT (parent of a
provenance-only tip), not the #trivial tip, so the stamp is
[verdict:<sha7>:CONFIRMED] rather than waived-trivial. land.sh's strict
post-land provenance check now validates against the POST-land verdict head
(the landed feat) instead of the stale pre-ship HEAD. BEADS_DIR resolution
via ao beads dir (73f7017aa) kept throughout.

(e) provenance: default_land documents explicitly that the lane does NOT run
post-land-provenance-emit.sh — the review's auto-bind IS the ledger coverage;
land.sh keeps the full trunk-bound reconciliation pass.

(f, age-ym4b slice b) post-land source prune, opt-in and OFF by default:
--prune-source / AGENTOPS_LAND_PRUNE_SOURCE=1 removes a request's SOURCE
worktree + branch after a green land IFF the request carried an explicit
source branch, the worktree is CLEAN, and every unique commit is an ancestor
of the fresh origin/main (merge-base --is-ancestor per commit). A dirty
worktree is never removed. Bats: 3 prune cases (flag on, default off, env
form); land-queue-test.sh gains the missing land-lane-close.bats suite.
2026-07-02 13:47:31 -04:00
boshu ef18cfca09 fix(land-lane): single #trivial per land — pawl-land restamps the reviewed feat, fixtures gain the waiver lib + age-8ais gate stub (age-fkps)
(a) pawl-land.sh: the rebind step predated the pawl-verdict auto-bind
(fc4513a81), so a land pushed DOUBLE-#trivial with verdict.head_sha != the
reviewed feat — surviving only on the waiver. Now: resolve the reviewed FEAT
(parent of a provenance-only tip), restamp the verdict onto it under
PAWL_AUTOBIND=0 (no 2nd #trivial), skip the restamp when already bound
(no-op rebase), and restore the ledger when the restamp's re-emit left an
uncommitted row (it dead-lettered the lane's NEXT queued-branch checkout —
caught by the e2e catch-22 case). Verdict binds the feat, matching
production (age-kg5l's edge derives from the feat, not the bind commit).

(b) fixtures: every land-queue suite that copies check-pawl-pre-push.sh now
also copies scripts/lib/trivial-waiver.sh (sourced fatally at entry since
age-wedge-all-in-dyr0.9) and stubs the age-8ais mixed-range cockpit gate
(AGENTOPS_PREPUSH_GATE_CMD=true). land-lane.bats: ordering assertions now
expect the [feat, #trivial-bind] single-trivial-per-land shape; close step
contained behind a recording br stub; watch-lane test gets a wider async
acquire window + teardown reap. e2e: parent-chain assertions follow the
interleaved feat/#trivial/upstream shape end-to-end.
2026-07-02 13:37:07 -04:00
boshu 257be5312e feat(skills): add ms skill — meta_skill search/load doctrine (MCP consume, CLI writes) 2026-07-02 11:18:48 -04:00
boshu 3429abe548 feat(next-work): first-class per-item consumed markers + lossless rewrite (age-tkxq)
Promote consumed_note/consumed_ref to first-class fields on both the item and
batch shapes of the next-work.jsonl contract (item-level `consumed` already
existed), and make the RewriteNextWorkFile round-trip preserve any field it did
not itself set so a concurrent lane or operator hand-edit is never silently
reverted (the reverted-flag / dropped-note hazard).

- schema: add consumed_note/consumed_ref (string) to next-work-item + -batch v1;
  old rows stay valid (additive, additionalProperties already true)
- doc: item/batch tables + a rewrite-preservation rule + annotation-vs-flag note
  (consumed stays the authoritative boolean; batch consumed is derived truth)
- runtime: NextWorkItem/NextWorkEntry gain an Extra passthrough via custom
  (Un)MarshalJSON keyed off a reflection-derived known-field set; output is
  byte-identical when there are no unknown fields, so existing rows are untouched.
  RewriteNextWorkFile is unchanged — the preservation rides the struct marshalers.
- validators: validate-next-work.sh FAILs on malformed marker types (consumed
  not boolean, consumed_note/consumed_ref not string) at item and batch level;
  the parity validator enforces the new field names in doc+runtime and adds a
  live-queue consumed-marker type-drift check. Both accept legacy and new shapes.
- tests: Go rewrite-fidelity round-trip through the production writer/reader on a
  real batch-28-style row (asserts on file bytes, not an in-memory constructor)
  + marker round-trip, malformed-reject, and marshal-idempotence unit tests; new
  bats + parity fixtures for the valid new shape and a malformed marker.
2026-07-02 11:08:23 -04:00
boshu 1773bf8569 fix(registry): drop wall-clock generated_at from registry.json to stop regen churn (age-9itj)
registry.json carried a wall-clock `generated_at` that generate-registry.sh rewrote on every `make regen-all`, so back-to-back regens were never byte-identical — it conflicted or re-noised at nearly every serial landing (cherry-pick conflicts on that line, idempotency proof-runs dirtying the tree, hand-reverting the pure-timestamp bump).

Remove the field from the body: registry.json is now a pure content-derived projection of its sources, matching the other generators (generate-context-map.sh / generate-skill-domain-map.sh already carry no timestamp). No consumer read the value — registry.go declares the field but never reads it, check mode already does del(.generated_at), and no schema/doc/jq/bats asserts it. Provenance for 'when generated' = git log on the file.

Verified: make regen-all twice -> registry.json byte-identical (sha256) + empty between-runs diff; make regen-check still reds on an un-regen'd skill body edit (codex-hash drift) and is green at rest; generate-registry.sh --check, validate-sku-catalog-drift.sh, 'ao registry list', and go build/vet/test (61 pass) all still work.
2026-07-02 10:55:15 -04:00
boshu 8ea867f58e fix(regen): fold skill catalog regen into regen-all/regen-check (age-biop)
generate-skill-catalog.sh (writes skills/catalog.json) and its drift check
were not wired into scripts/regen-all.sh, so the catalog-drift class survived
`make regen-check`: the sweep stayed green while the committed catalog drifted
from SKILL.md frontmatter (75 stale skills vs 63 real sources after the #889
consolidation).

- regen block: run generate-skill-catalog.sh LAST -- after codex-sync.sh, so
  codex_override_present reflects any created/removed skills-codex/<name>/ twins.
- check block: add check-skill-catalog-drift.sh next to the other drift gates.
- regenerate skills/catalog.json (75 -> 63) to clear the standing drift. This
  also clears age-hl9q item 5 -- do not double-fix.

make regen-check now runs and passes the new "skill catalog drift" gate, so the
catalog-drift class can no longer survive the drift sweep.
2026-07-02 10:51:45 -04:00
boshu 42750875d8 chore(vocab): retire bd from living consumes + tracker vocabularies (age-pz97)
Class fix — every LIVING vocabulary that sanctioned 'bd' or failed to sanction 'br':
- validate-skill-flow.sh EXTERNAL_INPUTS: bd -> br (recover/status consume
  'br' and were FAILing the closed-vocabulary gate; no live skill consumes 'bd',
  so bd is removed, not kept alongside).
- skill-flow.md external-input whitelist table: mirror bd -> br (contract keeps
  the validator vocabulary in sync 'in both places').
- repo-execution-profile.json tracker_commands: bd -> br across ready/show/update/
  close/doctor + BEADS_DIR shell_prefix; DoD predicate 'tracked in bd' -> 'br'.

No skill frontmatter changed -> no codex-twin mirror / regen-check needed.
Integration code (Go tracker_bd adapter, BDCommand config default), bd-specific
tooling (install-bd.sh, bd-audit.sh), anti-bd enforcement gates, and historical
/lineage refs (legacy-bd-memory:, session logs) deliberately left — behavior/
legacy, not living vocabularies.
2026-07-02 10:47:03 -04:00
boshu a291bef616 feat(pawl): append tag-sibling CONTEXT to the review packet on build-tagged diffs (age-kg5l)
When the diff touches a build-tagged (//go:build) .go file, pawl-review appends a
clearly-delimited CONTEXT-NOT-DIFF section of the tag-SIBLING files (same-dir foo.go
-> foo_*.go + legacy/flywheel base variants) AFTER the diff — the tag-guarded
expectations a refuter reviewing only the diff cannot see (the 2026-07-02
false-REFUTED class). Siblings are truncated (never the diff) to keep the packet
under the inline ceiling; a non-tag diff produces a byte-identical packet.
build_tag_sibling_context is unit-tested; byte-identical embedded mirror.
2026-07-02 10:28:12 -04:00
boshu d8de62fb2e feat(pawl): auto-run a REFUTED's named repro; re-roll once if it passes (age-6idm)
A REVIEWER REFUTED that NAMES an executable repro is a candidate false refute
(2026-07-02 build-tag class: 3/3 REFUTEDs each named a repro that actually PASSED).
pawl-review extracts the repro (fenced/backtick), gates it at the ARGV level
(go test|build|vet or bats, no dangerous flags/paths/metachars — never sh -c/eval),
and runs it ONCE timeboxed: passes -> re-roll the review once (bounded by
PAWL_REROLLED_AFTER_FALSE_REPRO); fails -> REFUTED stands + exit code/output attached.
extract_repro_command + repro_argv_allowed are unit-tested; byte-identical embedded mirror.

# Conflicts:
#	cli/embedded/pawl/scripts/pawl-review.sh
#	scripts/pawl-review.sh
2026-07-02 10:22:10 -04:00
boshu 0e920f85c5 fix(pawl): hijack guard — refuse verdict-edge bind when worktree HEAD moved mid-review (age-sylz)
pawl-review.sh snapshots HEAD at review start and exports PAWL_REVIEW_START_HEAD;
pawl-verdict.sh write refuses to emit/bind the verdict edge (exit nonzero, naming
both shas) when the live worktree HEAD no longer matches. Closes the concurrent-lane
hijack the stale-verdict check misses (it passes when verdict.head_sha and --head
moved together). Absent snapshot => prior behavior. Byte-identical embedded mirror.
2026-07-02 10:13:20 -04:00
boshu af2dbb19fb fix(pawl): gate EVERY non-trivial commit hidden behind a #trivial tip (age-8ais)
The #trivial provenance-only waiver in check-pawl-pre-push.sh keyed on the push
TIP alone, so non-trivial commits pushed BEHIND a #trivial tip escaped every
gate: `ao gate check --scope head` scopes to the tip's changed files
(docs/provenance/ only for a #trivial tip), so its build/test/ratchet checks
never fired on the hidden commits' cli/** files. age-rk3r.5 landed a
test-isolation ratchet-red this way (fixed forward in eef2a679f), blocking every
later cli/** landing.

Close it: when the tip is #trivial-waived but the pushed range
remote_sha..local_sha carries non-trivial commits, re-target
`ao gate check --fast --scope head` at EVERY such commit — newest-first,
FAIL-FAST on the first failure, naming the offending sha — each run inside a
throwaway DETACHED worktree whose HEAD is that commit (the
verify-pushed-commit-builds.sh isolation pattern), so the gate evaluates ITS
files and go.test-isolation (Fast, goPaths, blocking) fires on its *_test.go.
A first cut gated only the NEWEST non-trivial commit; a cross-family review
REFUTED it with a reproduced counterexample — the routine landing-train shape
[feat1, #trivial-bind, feat2, #trivial-bind] passes newest-only when feat1
carries the violation and feat2 is clean. Now ALL of them gate; the
counterexample is a permanent bats case proven to fail on the newest-only code.

Preserved: a PURE-#trivial range keeps the byte-identical fast path (no range
gate, no worktree — load-bearing for landing throughput); a non-trivial TIP is
unchanged. A MIXED push pays a real `ao gate check` PER non-trivial commit
(~40s each; ranges are normally 1-4 substantive commits) — by design, latency
is the point, not a regression. age-wy2t's future `ao gate check --scope range`
can collapse the loop into one run later; deliberately not depended on here.
remote_sha all-zeros / unknown base falls back to the tip-only surface the CI
backstop already uses.

Waiver logic still lives ONLY in scripts/lib/trivial-waiver.sh (called, never
re-inlined — the single-implementation guards stay green). 6 new bats (18
total): pure-trivial fast path, mixed PASS/FAIL re-targeting proven to hit the
non-trivial commit, the rk3r.5 raw-os.Setenv shape, non-trivial-tip invariance,
and the older-substantive-violation counterexample asserting gating order +
fail-fast.

Refs age-8ais
2026-07-02 10:12:26 -04:00
boshu 092ae748f9 feat(gates): --scope range + non-empty --json FAIL detail for landing loops
SLICE 1 — `ao gate check --scope range:<base>..<head>`: route on
`git diff --name-only <base>..<head>` and export AGENTOPS_GATE_RANGE so
backing collectors (scripts/check-go-command-test-pair.sh) prefer the
explicit range over their @{upstream}/git-show-HEAD fallback. A detached
landing worktree has no upstream, so a c1+c2 train whose test lands in c2
otherwise falsely fails go.command-test-pair at c1. Chose the `range:` scope
encoding (not a separate --range flag) so the range threads through the
existing single opaque Scope string with zero new plumbing and shows up in
the JSON `scope` field for free.

SLICE 2 — non-empty --json FAIL detail: a FAILing (or eval-errored) gate's
log_tail is never empty. Native-Go checks and silently-failing backing
scripts emitted an empty log_tail (leaving only a terse "exit N" reason),
so identifying which gates failed meant a re-run + tee-log archaeology.
jsonLogTail falls back to the reason when no output was captured and bounds
the emitted tail to the last 15 lines.

Tests: git-fixture range-vs-head routing; AGENTOPS_GATE_RANGE respected by
the shell collector; forced-FAIL --json carries non-empty log_tail (content
asserted); range env-export + invalid-range rejection.

age-wy2t
2026-07-02 10:08:52 -04:00
boshu 6c59671d57 feat(pawl): evidence-quality floor — CONFIRMED needs a finding-or-attestation + genuine-run marker, advisory-first (age-rk3r.11) 2026-07-02 09:45:36 -04:00
boshu 73f7017aa2 fix(land-queue): land lane close_bead resolves BEADS_DIR via ao beads dir (age-t5p6)
The lane's close step called `br close` with no BEADS_DIR, so in the canonical
checkout / a linked worktree (where $PWD/_beads is absent) the close failed
"Is a directory" and the best-effort || true silently dropped it — the landed
bead never closed. Resolve BEADS_DIR via `ao beads dir` before calling br,
mirroring scripts/land.sh, and drop the retired `bd` fallback from BR_BIN.

Peripheral close-path fix only. The CENTRAL staleness (pawl-land.sh rebind now
double-binds under pawl auto-bind fc4513a81; gate routes through legacy bash
pre-push-gate.sh not `ao gate check`; br close vs `ao done` verdict stamp)
is a design refresh scoped to age-fkps.

bats: tests/land-queue/land-lane-close.bats 2/2 (BEADS_DIR resolved; no bd
fallback). shellcheck -S warning clean; bash -n clean.
2026-07-02 09:32:24 -04:00
Bo aae1a3af9a refactor(skills): consolidate catalog 70 → 63 — cut acfs, fold 6 skills into their canonical owners (#889)
Full-catalog skills audit + consolidation via ao skills retire: acfs cut; autodev→evolve, skill-auditor→heal-skill, beads-workflow→beads-br, continuity-loop→using-atm, inject→operationalize, forge→curate. Trigger surfaces preserved via absorbed-from notes; ao CLI surfaces unchanged; dispositions ledger flipped to historical rows; registries/codex twins/eval canaries regenerated and retargeted. Includes self-review fixes: ledger-aware DEAD_XREF in heal.sh, scenario-linkage allowlist retarget, codex-twin dead-path repairs, strengthened eval canaries, fold-survival guard for operationalize, and beads consolidation test hardening.
2026-07-02 09:23:55 -04:00
boshu cb93e1d451 feat(pawl): verify ergonomics — optional change-id, reviewer heartbeat, NO-VERDICT triage block (age-rk3r.10) 2026-07-02 09:05:33 -04:00
boshu 591ef10dbe feat(pawl): live-smoke verify mode — runtime evidence in the packet, fail-first REFUTED on red smoke (age-rk3r.7) 2026-07-02 08:10:46 -04:00
boshu 3c4e4d6d54 feat(pawl): source per-repo verify config once at pawl-review entry (age-rk3r.17) 2026-07-02 01:30:44 -04:00
boshu 59882cd1a3 feat(pawl): widen verdict-JSON contract — degraded, REBOUND disposition + lineage, both enforcement sites (age-rk3r.16) 2026-07-02 00:57:55 -04:00
boshu bc9fb32709 feat(verify): ao verify receipts — portable proof page from the embedded bundle (age-rk3r.12)
Ship gen-membrane-receipts.sh + check-membrane-receipts-freshness.sh in the
embedded pawl bundle (make sync-hooks + //go:embed all:pawl) so a stranger repo
can render its own membrane-receipts proof page with no AgentOps checkout.

ao verify receipts mirrors the pawl review trust split: in-checkout dogfood runs
the live repo generator; anywhere else it extracts the EMBEDDED generator and
runs it against the user's OWN git repo under the sanitized cold env
(pawlReviewColdEnv) with AO_BIN pinned to the running binary — no ao-on-PATH
needed, no repo-local script trusted. The generator refuses the build-from-cli/
fallback when PAWL_UNTRUSTED_REPO=1 (compiling+running an untrusted repo's
cmd/ao would be RCE); the in-repo path keeps its fallback. Fail-closed
chain-verify-before-render and the count-parity check are unchanged.

Byte-identical to the current generator on this repo's ledger (behavior lock).
Bats acceptance in a throwaway repo with a production-writer-built ledger:
render + tamper-refusal + embedded==in-repo parity.

# Conflicts:
#	docs/cli-surface.json
#	docs/cli-surface.md
2026-07-02 00:46:05 -04:00
boshu b4c74afd02 feat(pawl): reviewer adapter contract — codex byte-compatible, agy cold, local-mlx eval-only; folds age-iian timeout re-snapshot (age-rk3r.1)
Post-refutation fixes (cross-family pawl caught two defects in the first cut):
- DEFECT 1 (fail-open): the agy/local-mlx genuine-run marker 'VERDICT:' appears in the
  packet itself, so a run that merely cat/echoed the packet classified GENUINE and the
  last-verdict parser could extract a CONFIRMED from echoed diff-context lines. Fixed:
  sentinel-wrapped agy packets (random-nonce boundary lines) + a marker-independent
  packet-line containment check (reviewer_packet_echoed) classify packet echo as ECHO.
- DEFECT 2 (wrong family certified): the verdict write hardcoded --refuter codex:...;
  REVIEWER=agy now certifies the canonical 'gemini' family (roster: agy|google->gemini),
  codex stays byte-identical, local-mlx gets a deliberately off-roster label so an
  opted-in eval verdict can never pass the prod roster check.
2026-07-02 00:23:32 -04:00
boshu eae58cfa43 feat(cli): experimental help group for corpus/flywheel + spine-only install tier (age-h4y3)
Two levers that surface the proven spine ahead of the unproven corpus/flywheel:

1. `ao --help` experimental group. Add a cobra group
   'Experimental (corpus/flywheel):' and move the corpus/flywheel commands still
   in the default build under it (compile, corpus, curate, dedup, defrag,
   flywheel, maturity, pool, ratchet, store, temper, wiki). Spine commands keep
   their primary grouping, so the proven surface leads the help output. The
   corpus/flywheel tier is unproven (ADR-0004, ADR-0011) — kept + buildable, just
   demoted.

2. Spine-only install tier. scripts/select-spine-skills.sh lists the skills whose
   SKILL.md frontmatter carries spine: true (skills/SKILL-TIERS.md); install.sh
   gains --tier <spine|all> (default all) which prunes the extracted bundle to
   spine-only before the per-runtime installers copy it. Filters the Codex/AGY
   bundle installs; the Claude plugin path stays whole-bundle (see report:
   plugin.json manifest split is deliberate follow-up, not done here).
   tests/scripts/select-spine-skills.bats covers selection (frontmatter-only, not
   prose), sorting, arg-guard, and install.sh --tier validation + --help docs.

Both build variants build+test clean; regen-check green (help grouping is not a
command-surface change).
2026-07-01 23:49:12 -04:00
boshu a01ea345d4 feat(provenance): additive v1.1 verdict-edge enrichment — reviewer_family, degraded, rounds, duration_s, evidence_path (age-rk3r.3) 2026-07-01 23:36:26 -04:00
boshu 1033c0186e fix(pawl): warn on foreign same-file ledger rows swept into the bind commit (age-7krl) 2026-07-01 22:28:36 -04:00
boshu 2691d6ec9b feat(cli): quick-start lands one command from a first verdict + timed probe (age-wedge-all-in-dyr0.5)
ao quick-start now ends on a first-verdict step: it readies the provenance
ledger path (the same resolveLedgerPath ao verify's emit uses), probes
reviewer reachability through the shared doctor wedge check, and prints the
exact 'ao verify my-first-change' command with what will happen — never
auto-running the reviewer (it costs the user's tokens). No reviewer reachable
prints the doctor corrective install one-liners instead of diffuse docs.
--json gains a first_verdict object (Directive 13); --dry-run stays write-free.

README quickstart: the 'Already installed?' line now walks the verify path
(small change -> ao verify -> read the verdict + ledger line), replacing /rpi.

scripts/probe-first-verdict.sh: the timed probe, two modes per the DISCOVERY
re-scope — default/CI runs a MOCK reviewer on PATH (proves path mechanics +
the timing floor, and says so in its output; CI holds no reviewer auth) and
--live for the operator's box (the honest 5-minute number). Clean temp git
repo, scripted quick-start steps, small change, ao verify, asserts a verdict
landed in the temp repo's docs/provenance/ledger.jsonl under 300s wall-clock,
plus a README drift grep binding the documented commands to the probed ones.

Tests: cmd-level Go (reviewer-reachable branch via PATH stub, unreachable
branch prints the install one-liners, --json shape, dry-run omission,
full-flow ordering) + tests/scripts/probe-first-verdict.bats (mock-mode e2e,
mock disclaimer, usage error, README drift gate). Existing quick-start run
tests now stub PATH so the new reviewer probe never invokes real CLIs.

Verified: cd cli && go build ./... && go vet ./... && go test ./... (12032
passed); bats tests/scripts/probe-first-verdict.bats (4/4); shellcheck -S
warning clean; probe mock run PASS in 1s. (--no-verify: pre-commit bd-shim
falsely blocks worktree cli/*.go builds; authoritative gate is pre-push.)
2026-07-01 21:20:50 -04:00
boshu 07571c3fe3 refactor(pawl): delegate cold codex invocation to codex-exec lib — single source of truth for stall/echo defenses (age-gate-the-ungated-egwt.13) 2026-07-01 20:08:46 -04:00
boshu a38d0e0b6c feat(gates): jsonl-scanner grep-ratchet — advisory changed-scope gate pointing at storage.ScanJSONL (age-storage-hardening-roxg.3) 2026-07-01 20:01:11 -04:00
boshu e29568e196 fix(docs): doc-lifecycle sweep — delete byte-dup, duplicates gate, BC6 label, career-leak excision, hookless reconcile (age-gate-the-ungated-egwt.12) 2026-07-01 19:23:34 -04:00
boshu 25a10b292e fix(docs): renumber duplicate ADR-0004 domain-slice → free number + check-adr-registry gate (age-gate-the-ungated-egwt.11) 2026-07-01 19:13:55 -04:00
boshu dbbcbde1b8 feat(gates): preamble ratchet — new scripts must source the hardened preamble, grandfathered tree only shrinks (age-gate-the-ungated-egwt.10)
Advisory-first rollout, deliberately: shell.preamble-ratchet seeds Blocking:false
for ONE clean cycle on main, then flips Blocking — the same staged pattern the
epic already landed for docs.cli-snippets (egwt.4) and docs.demoted-claims
(egwt.6), recorded in the RepairHint. The backing check itself is fail-closed
(exit 1) on every violation class:

- new/changed top-level scripts/*.sh must source scripts/lib/preamble.sh or
  carry a non-empty '# preamble-exempt: <reason>' (empty reason rejected)
- grandfather authority = base-ref ∩ working snapshot, so appending an entry in
  the same diff grants nothing (both halves fail independently)
- the snapshot is shrink-only vs. its base-ref version; only the initial
  snapshot commit may introduce it
- scripts/lib/** exempt as a class (sourced libs, not entrypoints)

Also folds with_tmpdir (trap-EXIT mktemp cleanup, ~79 re-rolls) and require_cmd
(command -v + install-hint die, ~62 re-rolls) into the preamble; 18 preamble
bats + 10 ratchet bats.
2026-07-01 19:07:52 -04:00
boshu 322d419572 feat(ci): verdict backstop — report-only tip-verdict verification reusing the pre-push waiver (age-wedge-all-in-dyr0.9) 2026-07-01 19:01:41 -04:00
boshu 0b7be07ec3 feat(cli): ao done — verdict-referenced bead close with warn-first close-rate gate (age-wedge-all-in-dyr0.4)
ao done <bead-id> [--sha] [--force-no-verdict] [--json]: closes via the br CLI
on PATH with the close reason stamped [verdict:<sha7>:<disposition>]. CONFIRMED
ledger verdict -> CONFIRMED stamp; verdict-less provenance-only commit (the
pawl #trivial waiver class, fail-closed diff-tree) -> waived-trivial; otherwise
REFUSE naming ao verify / ao pawl review, with --force-no-verdict writing an
explicit greppable UNVERIFIED stamp. BEADS_DIR resolution reuses the
beadsTrackerCommandContext env path (no hardcoded ledger paths).

scripts/check-verdict-close-rate.sh: warn-only gate (threshold 0 baseline,
--strict --threshold N for the later ratchet) measuring the [verdict:...]
stamp fraction of the last N closes in the br issues.jsonl (last-wins per id);
skips cleanly when jq/BEADS_DIR/ao/ledger are absent.

Tests: 13 Go cmd-level tests (stub br on PATH + production-writer ledger
fixtures + t.TempDir git repos) + 14 bats over fixture JSONL. Narrow CLI-ref
regen (generate-cli-reference.sh) included to keep TestCobraConformance green.
2026-07-01 18:56:43 -04:00
boshu 21b868c60f feat(gates): provenance.chain local gate — verify the ledger hash chain at the pre-push boundary (age-gate-the-ungated-egwt.9) 2026-07-01 18:45:32 -04:00
boshu 55186e5460 refactor(scripts): codex-exec lib — one fail-closed hardened runner, migrate all non-pawl callers (age-gate-the-ungated-egwt.8) 2026-07-01 18:39:34 -04:00
boshu f088a651a0 fix(cli): lint green + go.lint gate — fix all findings, wire pinned golangci-lint fail-closed (age-gate-the-ungated-egwt.7) 2026-07-01 18:31:23 -04:00
boshu 7dce715998 feat(gates): docs.demoted-claims honesty gate — banned unproven-claim lexicon over live docs (age-gate-the-ungated-egwt.6) 2026-07-01 18:27:08 -04:00
boshu cda07612a2 feat(pawl): size-scaled review timeout for read-files packets — measured, chunking unneeded (age-wedge-all-in-dyr0.11)
Spike data (2026-07-01): 117KB mixed diff verdicted inside 420s; the 209KB
age-abev stage-B deletion (historical un-pawl-able class) timed out at 420s
mid-review and verdicted at ~540s with a 560s budget. The >65KB gap is
timeout-shaped, not protocol-shaped: read-files mode (age-mwhj) covers the
class; the chunked-review protocol is voided by measurement.
scale_review_timeout: 300s + 2s/KB over the 64KB cap, ceiling 900s, explicit
PAWL_REVIEW_TIMEOUT pin always wins, never scales down.
2026-07-01 18:22:21 -04:00
boshu 4a7c6a0701 feat(gates): docs.skill-refs --all-docs — widen the 6-file skill-ref gate to live docs + SKILL-ROUTER sync (age-gate-the-ungated-egwt.5)
Add an --all-docs mode to check-doc-skill-refs.sh that scans the union of the
pinned doctrine files PLUS the full LIVE docs/** set (scripts/lib/docs-scope.sh),
ratcheted by a new filename-pinned shrink baseline
(scripts/.docs-skill-refs-baseline). Two-way ratchet: a non-baselined live doc
with a dead `/skill` ref FAILS; a baselined file that no longer offends FAILS
demanding a prune. Detection stays slash-syntax + headings only (never bare
skill names). Default (no-flag) behavior is byte-identical.

docs/SKILL-ROUTER.md (the curated router) is covered by --all-docs (a live
docs/** file, never baselined) so a dead ref there FAILS strict, without
perturbing the byte-identical default doc count.

seed.go docs.skill-refs row: Match widened to docs/** + the baseline + the lib;
Args set to [--all-docs --strict]. Burn-down (long-tail only): repointed retired
`/retro`->/post-mortem, `/vibe`->/validate, `/ratchet`->/flywheel,
`/research-multi`->/research, `/implement-wave`->/crank, and reworded the
retired `/dream` across 13 docs/levels + docs/workflows + docs/philosophy
pages, then pruned them from the baseline (91 -> 78 offenders). Owner-locked
pages (comparisons/getting-started/positioning) stay baselined.

Bats twin tests/scripts/check-doc-skill-refs-all-docs.bats covers all the modes.
2026-07-01 18:12:53 -04:00
boshu b7503b4519 feat(gates): docs.cli-snippets gate — resolve ao commands in live docs against the cobra tree (age-gate-the-ungated-egwt.4) 2026-07-01 18:07:41 -04:00
boshu fc4513a813 fix(pawl): verified verdict emission + auto-bind ledger edge, re-entrancy safe (age-wedge-all-in-dyr0.3)
The verdict sensor was best-effort (`ao provenance emit-verdict … || true`)
at both pawl-verdict.sh sites (write + rebind) — a silently dead sensor —
and the ledger edge needed a manual chore commit after every land.

- CHECKED emission: capture rc+stderr; on failure print a loud warning
  block naming the corrective command + a SECONDARY-STATUS marker, without
  changing the verdict outcome or exit semantics (fail-open sensor, never
  silent).
- AUTO-BIND (PAWL_AUTOBIND, default ON): after an emit that actually
  APPENDED to docs/provenance/ledger.jsonl, commit ONLY that path (exact
  git add + pathspec-limited commit; unrelated staged work stays staged)
  with the established 'chore(provenance): bind pawl <D> verdict for
  <bead> #trivial' shape — satisfies the age-u43w pre-push waiver
  (asserted against the real gate in bats).
- RE-ENTRANCY: never mutate HEAD mid-push — PAWL_PREPUSH marker exported
  by check-pawl-pre-push.sh (primary) + inherited GIT_PREFIX/GIT_DIR
  hook-env set-ness (heuristic; probed git 2.54 exports GIT_PREFIX to
  pre-push hooks, not GIT_DIR); pre-push context parks the row and prints
  the exact post-push bind one-liner.
- Ledger-root resolution mirrors ao resolveLedgerPath() from cwd,
  preserving the epic-d16-donetest cwd-isolation contract (4/4 green).
- feed-health: verdict-edge recency check (newest wasDerivedFrom verdict
  edge age; PROVENANCE_VERDICT_MAX_AGE_DAYS, default 14) — warn-only by
  default, escalates under --strict, matching the landed-event posture.
- Embedded pawl bundle re-synced (validate-embedded-sync green).

bats: 22/22 new (emit-ok/emit-fail/no-append/pre-push x2/optout/staged-
isolation/rebind/no-ao + 6 feed-health recency), 66/66 sibling pawl
suites, 4/4 donetest; shellcheck -S warning green.
2026-07-01 17:41:51 -04:00
boshu 71abc56593 fix(gates): de-race gate temp paths — per-run mktemp -d replaces fixed /tmp binaries (age-gate-the-ungated-egwt.3) 2026-07-01 17:22:50 -04:00
boshu 38aa215222 feat(gates): extract docs-scope lib — shared live-doc resolution + banner exemption (age-gate-the-ungated-egwt.1) 2026-07-01 17:18:17 -04:00
boshu 1cb06efb64 feat(provenance): membrane receipts generator derived from the verdict ledger (age-wedge-all-in-dyr0.6) 2026-07-01 16:53:26 -04:00
verify 5b064b28b0 fix(pawl): reliable agy engagement on typical diffs — output-change verify + stall-based recovery (age-55qz.11 followup 2)
Follow-up to the delivery-based send fix. Diagnosed live 2026-07-01: agy voted only ~50-75% of
routes because the Antigravity CLI intermittently fails to review a delivered packet:
  - INPUT-DROP: `atm send --file` reports "delivered":1 but the TUI drops the input — empty pane,
    no review, no verdict.
  - START-THEN-STALL: agy begins reviewing (output appears) but never emits a verdict.

Fix (two bounded layers, so they never thrash):
  - SEND-TIME (_family_send, cc+agy): after a delivery, require the pane to START PRODUCING OUTPUT
    (recent-scrollback cksum changes) within a short window; if not (dropped input), re-send. This is
    the reliable, type-agnostic engagement signal .11 wanted but atm-wait couldn't provide.
  - MID-ROUTE (cmd_route): if agy has no verdict AND is STALLED (agy_st >= PAWL_AGY_RESEND_STALL, no
    new output) or dropped to a shell, respawn + re-send once (agy_rr<1). Keyed on STALL not elapsed
    time, so a slow-but-producing agy on a big diff is left to finish, not killed mid-review.

LIVE-VERIFIED on a dedicated tri: small/medium diffs -> agy 5/5 (up from ~50%), mid-route recovery
firing + recovering on 2 of 5. Deterministic pawl-send-engagement.bats rewritten to lock the
output-change behavior; existing pawl suites green.

KNOWN RESIDUAL (follow-up): on LARGE diffs (~14KB+) agy still intermittently times out — the
Antigravity TUI drops big PASTED packets and a re-send re-pastes the same too-big content. The
panel degrades cleanly to a valid 2/3 cross-family verdict when this happens (opus+codex, min=2
met). The real fix is to deliver agy the file PATH to READ (like cod_send's --codex-goal "read the
file") instead of pasting content — tracked separately.
2026-07-01 15:40:58 -04:00
boshu 21690760d2 fix(pawl): delivery-based cc/agy sends — remove the unreliable atm-wait engagement gate (age-55qz.11 followup)
The .11 engagement gate (`atm wait --until=generating`) made the warm panel FLAKY: verified live
2026-07-01, that primitive does not reliably detect a pane generating — the opus pane answered
"ack" and the agy pane answered "pong" to a trivial task while `atm wait` timed out the entire
window, and `--type gemini` does not even match the Antigravity (agy) pane ("no panes match").
So a false "not engaged" respawn-THRASHED the pane (kill + relaunch, 3x) before it could ever
review, then mapped it to <timeout>. agy timed out on every tri route; a claude-CLI update ("Meet
Sonnet 5") then broke detection for cc/opus too.

Fix: cc_send + agy_send share one DELIVERY-based _family_send (deliver + retry-on-no-delivery, no
atm-wait gate). Both CLIs engage reliably on a successful delivery; a genuinely stuck/compacting
pane is caught downstream by the route's cksum-stall-detection + the .10 absolute engage-deadline,
and the route degrades to the ready subset (age-yvrp) — never thrashes or fabricates a verdict.
Removed the now-unused _wait_engaged helper + PAWL_ENGAGE_WAIT config.

LIVE-VERIFIED on a dedicated session: 2-pane (cc+cod) -> CONFIRMED 2/2; 3-pane (cc+cod+agy) ->
CONFIRMED 3/3 (agy votes, no thrash). Rewrote pawl-send-engagement.bats to lock the delivery-based
behavior + assert the atm-wait gate is gone; existing pawl suites green.
2026-07-01 09:10:33 -04:00
boshu 1ff8f75d92 fix(gate): validate skill BODY-refs against the full command surface (flywheel+legacy)
Second instance of the age-sydq archived-command escape. validate-skill-body-refs.sh
(the blocking skill.body-refs gate) built a spine-only binary, so skill body-refs to
archived-but-revivable commands (`ao harvest`, `ao turn verify`, behind //go:build
flywheel|legacy) false-failed with 14 unresolved refs — a LATENT main breakage (red at
HEAD) that surfaced when .16 routed the gate on a skills/goals edit.

Build the validation binary with -tags "flywheel legacy" so body-refs validate against
the full (spine + archived) command surface — the same fix age-sydq applied to
validate-skill-cli-snippets.sh. Both validators should have been fixed together.
2026-07-01 07:58:53 -04:00