diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 7f7f2db2d..55672c506 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -1212,6 +1212,17 @@ jobs: chmod +x scripts/check-docs-learning-references.sh ./scripts/check-docs-learning-references.sh + - name: Hooks-runtime drift gate — live-facing docs/ stay hookless (ag-rryf) + # Companion to sync-skill-counts.sh: fails when a live-facing doc + # reintroduces a live hooks runtime (hooks/hooks.json, a hooks/*.sh path, + # `ao hooks`, or a bare session-*.sh hook ref) without a hookless/opt-in/ + # historical hedge. Archival + opt-in-subsystem surfaces are out of scope + # (see the script header). Guards the ag-t1ca de-hooking against regression. + if: needs.changes.outputs.docs == 'true' || needs.changes.outputs.ci == 'true' || needs.changes.outputs.shell == 'true' + run: | + chmod +x scripts/check-doc-hooks-drift.sh + ./scripts/check-doc-hooks-drift.sh + - name: Directive-to-scenario link lint (ao goals scenarios --lint, blocking) # T1 (≤5min). Blocking (soc-x7y9f): the directive↔scenario link lint # fails the job on any broken edge. The broader whole-chain orphan/gap diff --git a/docs/SCHEMAS.md b/docs/SCHEMAS.md index 01e44f455..af9ab8d92 100644 --- a/docs/SCHEMAS.md +++ b/docs/SCHEMAS.md @@ -69,9 +69,9 @@ Most schemas follow JSON Schema Draft 2020-12. Any compatible validator will wor # Validate skill frontmatter across all skills scripts/validate-skills.sh -# Validate hooks manifest -jq -e . hooks/hooks.json # well-formed JSON -ao hooks show --validate # schema-aware check +# Validate the legacy hooks manifest (opt-in only — AgentOps 3.0 ships zero +# hooks; you only have one if you authored it via the hooks-authoring skill) +jq -e . hooks/hooks.json # legacy/opt-in manifest, if present # Validate swarm evidence artifacts scripts/validate-swarm-evidence.sh diff --git a/docs/UPGRADING.md b/docs/UPGRADING.md index 7c966454b..45d9e442e 100644 --- a/docs/UPGRADING.md +++ b/docs/UPGRADING.md @@ -135,7 +135,6 @@ See [`CHANGELOG.md`](CHANGELOG.md) directly. No hard breakages were introduced i # Verify the new install ao --version ao doctor -ao hooks test # Re-run any local gates touched by the upgrade scripts/pre-push-gate.sh --fast diff --git a/docs/cli-skills-map.md b/docs/cli-skills-map.md index e975db4da..7b2a74cc7 100644 --- a/docs/cli-skills-map.md +++ b/docs/cli-skills-map.md @@ -46,7 +46,6 @@ Every `ao` command that is actively called by at least one skill. | `ao dedup` | flywheel | | `ao contradict` | flywheel | | `ao metrics` | flywheel | -| `ao hooks` | quickstart | | `ao init` | quickstart | | `ao session` | post-mortem, retro | | `ao temper` | post-mortem | diff --git a/docs/contracts/release-readiness.md b/docs/contracts/release-readiness.md index 8cf15f521..402c36948 100644 --- a/docs/contracts/release-readiness.md +++ b/docs/contracts/release-readiness.md @@ -58,10 +58,10 @@ checks, and optional release-version match. ```bash scripts/check-release-hil.sh \ --expected-version X.Y.Z \ - --target 'local:bushido:ao version && ao init --help && ao hooks show && ao rpi status' + --target 'local:bushido:ao version && ao init --help && ao doctor && ao rpi status' scripts/check-release-hil.sh \ --expected-version X.Y.Z \ - --target 'ssh:bushido:bushido:ao version && ao init --help && ao hooks show && ao rpi status' + --target 'ssh:bushido:bushido:ao version && ao init --help && ao doctor && ao rpi status' ``` When no physical target is available for an official release, the release owner diff --git a/docs/curation-pipeline.md b/docs/curation-pipeline.md index 4cf2b6359..cdfb216dc 100644 --- a/docs/curation-pipeline.md +++ b/docs/curation-pipeline.md @@ -446,7 +446,7 @@ draft ──────> active ──────> retired ### Connection to Existing Infrastructure - **Hooks:** Active constraints are sourced by `task-validation-gate.sh` during validation. The hook reads `.agents/constraints/index.json`, evaluates supported detector kinds, and treats companion `.sh` files as review artifacts rather than executable runtime contracts. -- **Post-mortem / Retro:** After extracting learnings, if any score >= 4/5 on actionability and are tagged `constraint` or `anti-pattern`, the skill invokes `hooks/constraint-compiler.sh ` to generate the template. +- **Post-mortem / Retro:** After extracting learnings, if any score >= 4/5 on actionability and are tagged `constraint` or `anti-pattern`, the skill generates the template via `ao curate constrain`; an opt-in `constraint-compiler.sh` hook (authored via the hooks-authoring skill) can run it too. - **Pool:** Reads established learnings from `.agents/pool/staged/` or promoted artifacts in `.agents/learnings/`. - **CLI:** `ao curate constrain` -- scans for established learnings meeting promotion criteria, generates constraint templates. diff --git a/docs/leverage-points.md b/docs/leverage-points.md index d70767e63..3be1b2061 100644 --- a/docs/leverage-points.md +++ b/docs/leverage-points.md @@ -62,7 +62,7 @@ The knowledge stock `K` lives in `.agents/`. Its structure: .agents/ learnings/ -- I(t) deposits here via ao forge patterns/ -- Reusable solutions extracted from learnings - constraints/ -- Compiled rules (constraint-compiler.sh) + constraints/ -- Compiled rules (via `ao curate constrain`) retros/ -- Retrospective summaries council/ -- Validation verdicts research/ -- Exploration findings diff --git a/docs/release-e2e-checklist.md b/docs/release-e2e-checklist.md index c3cb96123..4439ef26f 100644 --- a/docs/release-e2e-checklist.md +++ b/docs/release-e2e-checklist.md @@ -41,7 +41,7 @@ Run: ```bash bash scripts/ci-local-release.sh \ --release-version X.Y.Z \ - --hil-target 'local:bushido:ao version && ao init --help && ao hooks show && ao rpi status' + --hil-target 'local:bushido:ao version && ao init --help && ao doctor && ao rpi status' ``` Expect: diff --git a/docs/strategic-direction.md b/docs/strategic-direction.md index 33264df07..4a512815d 100644 --- a/docs/strategic-direction.md +++ b/docs/strategic-direction.md @@ -61,8 +61,8 @@ Donella Meadows ranked intervention points in complex systems from least to most | 9 | Delays | Freshness decay intervals, maturity lifecycle (expire/evict), stale run TTL | Controls lag between `I(t)` and usable `K` | | 8 | Balancing feedback loops | Regression gates auto-revert bad cycles, council FAIL blocks merge, push gate blocks unvalidated code | Prevents `K` regression | | 7 | Reinforcing feedback loops | Knowledge flywheel (session N learnings feed session N+1), citation-based utility scoring (MemRL) | The `s*r*K` compounding term | -| 6 | Information flows | `ao lookup` (knowledge into context on demand), `ao forge` (experience out of sessions), hook nudges, briefing packets | Increases `s` by getting right knowledge to right window | -| 5 | Rules | Hooks wired through `hooks/hooks.json`, validation gates, worker-guard (lead-only commit), dangerous-git guard, pre-mortem gate | Structural enforcement. Rules cannot be forgotten or ignored. | +| 6 | Information flows | `ao lookup` (knowledge into context on demand), `ao forge` (experience out of sessions), context-packet nudges, briefing packets | Increases `s` by getting right knowledge to right window | +| 5 | Rules | CI gates wired through `.github/workflows/validate.yml`, validation gates, worker-guard (lead-only commit), dangerous-git guard, pre-mortem gate | Structural enforcement. Rules cannot be forgotten or ignored. | | 4 | Self-organization | `/evolve` fitness loop (measure-fix-validate-learn-repeat), constraint compiler (learnings become structural rules), progressive skill revelation | The system improves its own rules based on experience | | 3 | Goals | `GOALS.md` with mechanically verifiable gates, `ao goals measure`, severity-weighted selection, North Stars and Anti Stars | System intent. What the system optimizes toward. | | 2 | Mindset/paradigm | The 6 paradigm shifts below | How the builder thinks about agent systems | diff --git a/docs/workflows/session-lifecycle.md b/docs/workflows/session-lifecycle.md index f0d3a204e..461c61b52 100644 --- a/docs/workflows/session-lifecycle.md +++ b/docs/workflows/session-lifecycle.md @@ -512,7 +512,7 @@ research + plan validated code learnings + next work | Progress template | `.claude/templates/claude-progress.json` | Session state template | | Feature template | `.claude/templates/feature-list.json` | Feature tracking template | | Intent router | `.claude/skills/intent-router.md` | Natural language routing | -| Session autostart | `.claude/hooks/session-autostart.sh` | Auto-show context | +| Session autostart (opt-in) | `.claude/hooks/session-autostart.sh` | Auto-show context — AgentOps ships none; author one via the hooks-authoring skill | | Session start cmd | `.claude/commands/session-start.md` | Manual session start | | Session end cmd | `.claude/commands/session-end.md` | Manual session end | | Progress update cmd | `.claude/commands/progress-update.md` | Manual progress update | diff --git a/scripts/check-doc-hooks-drift.sh b/scripts/check-doc-hooks-drift.sh new file mode 100755 index 000000000..7953976ef --- /dev/null +++ b/scripts/check-doc-hooks-drift.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash +# check-doc-hooks-drift.sh — hooks-runtime regression guard for docs/ (ag-rryf). +# +# AgentOps 3.0 is hookless: the default install ships zero hooks, there is no +# `hooks/hooks.json` runtime, and `ao hooks` is not a registered command. The +# ag-t1ca epic de-hooked ~16 live-facing docs but did NOT gate the class, so the +# rot can silently re-enter. This is the companion to scripts/sync-skill-counts.sh +# (skill-count drift) and scripts/check-hookless-cold-start.sh (a FIXED-list cold- +# start gate); this gate broadens to the live-facing narrative/onboarding/operator +# docs tree. +# +# It FAILS when a scoped doc presents a LIVE hooks runtime: +# - `hooks/hooks.json` — the retired manifest, presented as live +# - a `hooks/.sh` path — a hook runtime path presented as live +# - `ao hooks` — a command that does not exist +# - bare `session-{start,end,autostart}*.sh` — hook-file refs presented as live +# unless the SAME line hedges the reference as hookless / opt-in / historical / +# removed / a git-hook (see HEDGE). Per-line hedging mirrors check-hookless-cold- +# start.sh: an artifact that merely names a hook in a "this is gone / author your +# own" frame is legitimate; an unhedged present-tense promise is the regression. +# +# SCOPE — docs/ MINUS surfaces that legitimately/archivally reference hooks: +# archival history : CHANGELOG.md, releases/, learnings/, plans/, adr/, +# convergence/, sovereignty-proof/ (document the past / the +# removal itself — must keep naming hooks) +# opt-in subsystem : contracts/ (hooks-authoring opt-in subsystem specs), +# runbooks/ (diagnostic hook enumeration), +# code-map/ (point-in-time code audits) +# These are deliberately out of the live-facing risk class. The gate keeps the +# onboarding / operator / architecture narrative hookless. +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +DOCS="$ROOT/docs" + +# Live-hooks patterns. A doc line matching any of these is a candidate violation +# unless it also matches HEDGE. +PAT='hooks/hooks\.json|hooks/[A-Za-z0-9_-]+\.sh|\bao hooks\b|\b[a-z0-9-]*session-(start|end|autostart)[a-z0-9-]*\.sh\b' + +# A reference is "hedged" (allowed) when the SAME line carries one of these. +# They frame the hook as NOT a live default surface: hookless / opt-in / author- +# it-yourself / historical / removed / replaced / a git-hook. "SCHEMAS legacy +# hooks-manifest label" is covered by `legacy`/`opt-in`; the hooks-authoring +# skill by `hooks-authoring`/`author`; ".githooks" git hooks by `git-hook`. +HEDGE='hookless|hooks-authoring|ships (zero|no) hooks|no hooks|no `?ao hooks|removed|are gone|is gone|gone by design|retired|no longer|deleted|teardown|historical|legacy|formerly|used to|previously|was wired|pre-existed|opt-in|optional|if you author|author one|author via|author your own|example|when installed|hook-capable|can be triggered|injected|curated|replaced|instead|→|not wired|inactive|zero matches|grep yields|\.githooks|git-hook|git hook' + +# Archival + opt-in-subsystem surfaces (basenames; unique under docs/). +EXCLUDE_DIRS=(releases learnings plans adr convergence sovereignty-proof contracts runbooks code-map) + +fail() { + printf 'FAIL: %s\n' "$1" >&2 + exit 1 +} + +[[ -d "$DOCS" ]] || fail "docs/ not found under $ROOT" + +exclude_args=(--exclude=CHANGELOG.md) +for d in "${EXCLUDE_DIRS[@]}"; do + exclude_args+=(--exclude-dir="$d") +done + +violations=0 +while IFS= read -r match; do + [[ -n "$match" ]] || continue + # match form: :: + file="${match%%:*}" + rest="${match#*:}" + lineno="${rest%%:*}" + content="${rest#*:}" + if ! grep -qiE "$HEDGE" <<<"$content"; then + rel="${file#"$ROOT"/}" + printf 'FAIL: %s:%s presents a hooks runtime as live without a hookless/opt-in/historical hedge\n' \ + "$rel" "$lineno" >&2 + printf ' %s\n' "$content" >&2 + violations=$((violations + 1)) + fi +done < <(grep -rnIE "$PAT" "$DOCS" "${exclude_args[@]}" || true) + +if [[ "$violations" -gt 0 ]]; then + fail "$violations live-hooks reference(s) re-entered live-facing docs. Reframe as explicit \`ao\` commands, or hedge as opt-in (author via the hooks-authoring skill) / historical." +fi + +printf 'PASS: no live-hooks references in live-facing docs/\n' diff --git a/tests/scripts/check-doc-hooks-drift.bats b/tests/scripts/check-doc-hooks-drift.bats new file mode 100644 index 000000000..5899cf9da --- /dev/null +++ b/tests/scripts/check-doc-hooks-drift.bats @@ -0,0 +1,100 @@ +#!/usr/bin/env bats +# Tests for scripts/check-doc-hooks-drift.sh (ag-rryf — hooks-runtime doc gate). + +setup() { + REPO_ROOT="$(cd "$BATS_TEST_DIRNAME/../.." && pwd)" + SCRIPT="$REPO_ROOT/scripts/check-doc-hooks-drift.sh" + TMP_DIR="$(mktemp -d)" + FAKE_REPO="$TMP_DIR/repo" + mkdir -p "$FAKE_REPO/scripts" "$FAKE_REPO/docs" "$FAKE_REPO/docs/contracts" "$FAKE_REPO/docs/releases" + /bin/cp "$SCRIPT" "$FAKE_REPO/scripts/check-doc-hooks-drift.sh" + chmod +x "$FAKE_REPO/scripts/check-doc-hooks-drift.sh" + # A clean baseline doc so "scanned > 0" holds and the default case passes. + cat > "$FAKE_REPO/docs/index.md" <<'EOF' +# Index +Run `ao session bootstrap`. AgentOps 3.0 is hookless — nothing auto-injects. +EOF +} + +teardown() { + rm -rf "$TMP_DIR" +} + +@test "real live-facing docs/ carry no live-hooks references" { + run bash "$SCRIPT" + [ "$status" -eq 0 ] + [[ "$output" == *"PASS"* ]] +} + +@test "fails when a doc presents a hooks/*.sh runtime path as live" { + cat > "$FAKE_REPO/docs/newcomer-guide.md" <<'EOF' +# Newcomer Guide +At session start, `hooks/session-start.sh` injects repo context automatically. +EOF + run "$FAKE_REPO/scripts/check-doc-hooks-drift.sh" + [ "$status" -eq 1 ] + [[ "$output" == *"newcomer-guide.md:2"* ]] + [[ "$output" == *"presents a hooks runtime as live"* ]] +} + +@test "fails when a doc presents 'ao hooks' as a live command" { + cat > "$FAKE_REPO/docs/getting-started.md" <<'EOF' +# Getting Started +Run `ao hooks install` to wire the gates. +EOF + run "$FAKE_REPO/scripts/check-doc-hooks-drift.sh" + [ "$status" -eq 1 ] + [[ "$output" == *"getting-started.md:2"* ]] +} + +@test "fails when a doc presents hooks/hooks.json as a live manifest" { + cat > "$FAKE_REPO/docs/architecture.md" <<'EOF' +# Architecture +Hooks are wired through `hooks/hooks.json` and fire on every event. +EOF + run "$FAKE_REPO/scripts/check-doc-hooks-drift.sh" + [ "$status" -eq 1 ] + [[ "$output" == *"architecture.md:2"* ]] +} + +@test "passes when a hook ref is hedged as opt-in / hooks-authoring" { + cat > "$FAKE_REPO/docs/newcomer-guide.md" <<'EOF' +# Newcomer Guide +A `hooks/session-start.sh` is opt-in only (author one via the hooks-authoring skill). +EOF + run "$FAKE_REPO/scripts/check-doc-hooks-drift.sh" + [ "$status" -eq 0 ] + [[ "$output" == *"PASS"* ]] +} + +@test "passes when a hook ref is hedged as removed / historical" { + cat > "$FAKE_REPO/docs/migration.md" <<'EOF' +# Migration +The `ao hooks install` command and `hooks/hooks.json` manifest are gone (removed in 3.0). +EOF + run "$FAKE_REPO/scripts/check-doc-hooks-drift.sh" + [ "$status" -eq 0 ] + [[ "$output" == *"PASS"* ]] +} + +@test "ignores archival + opt-in-subsystem surfaces (releases/, contracts/)" { + cat > "$FAKE_REPO/docs/releases/v3.md" <<'EOF' +# v3 notes +`ao hooks install` and `hooks/session-start.sh` were removed. +EOF + # Unhedged live-presenting ref inside an excluded subtree must NOT fail. + cat > "$FAKE_REPO/docs/contracts/eval.md" <<'EOF' +# Eval contract +The runtime executor is `hooks/task-validation-gate.sh` and it runs during validation. +EOF + run "$FAKE_REPO/scripts/check-doc-hooks-drift.sh" + [ "$status" -eq 0 ] + [[ "$output" == *"PASS"* ]] +} + +@test "errors when docs/ does not exist under root" { + rm -rf "$FAKE_REPO/docs" + run "$FAKE_REPO/scripts/check-doc-hooks-drift.sh" + [ "$status" -eq 1 ] + [[ "$output" == *"docs/ not found"* ]] +}