From 31337c369e2dc835558da81a83efd7e91e781810 Mon Sep 17 00:00:00 2001 From: boshu <241868352+boshu2@users.noreply.github.com> Date: Tue, 14 Jul 2026 10:43:26 -0400 Subject: [PATCH] docs: establish lean AgentOps product boundary Implements: age-agentops-lean-loop-direct-cut-rp16f.1 --- AGENTS-CI.md | 27 +- AGENTS.md | 15 +- GOALS.md | 35 +- PRODUCT.md | 15 +- PROGRAM.md | 21 +- cli/README.md | 85 ++--- docs/3.0.md | 9 +- docs/CI-CD.md | 76 +++-- docs/MIGRATION.md | 17 +- docs/UPGRADING.md | 32 +- ...-membrane-bookkeeper-archive-satellites.md | 125 +++---- docs/agent-workflow-reference.md | 27 +- docs/architecture/build-tags.md | 83 ++--- .../architecture/go-cli-architecture-guide.md | 61 ++-- docs/architecture/operating-loop.md | 12 +- .../local-pre-push-gate-retirement.md | 146 ++------- docs/contracts/pawls.md | 305 ++---------------- docs/doctrine/operating-discipline.md | 287 ++++++---------- docs/documentation-index.md | 29 +- docs/newcomer-guide.md | 23 +- docs/software-factory.md | 145 +++------ tests/scripts/agentops-product-boundary.bats | 196 +++++++++++ tests/scripts/agents-operating-contract.bats | 4 +- 23 files changed, 759 insertions(+), 1016 deletions(-) create mode 100644 tests/scripts/agentops-product-boundary.bats diff --git a/AGENTS-CI.md b/AGENTS-CI.md index ee77fe8cf..f87216ea7 100644 --- a/AGENTS-CI.md +++ b/AGENTS-CI.md @@ -4,12 +4,28 @@ ## Actions Backstop -Routine changes land by local gate plus direct push to `main`. GitHub Actions are optional/manual or release-tag backstops, not the release authority for normal AgentOps work. `.github/workflows/validate.yml` remains useful for explicit workflow dispatch, PRs from external collaboration, merge-queue experiments, and `v*` release tags. Release tag pushes force every path-filtered release lane on, and the summary fails if any release lane is skipped unexpectedly. PR-only evidence jobs are allowlisted on tag pushes because tag events have no PR body; other skipped jobs are not treated as release verdicts. **Run checks locally before pushing.** The local Go gate with workflow coverage is the parity guard that prevents blocking workflow scripts from drifting outside the local contract. +AgentOps validation and repository delivery are separate transitions. A local or +cloud agent freezes one candidate, runs deterministic evidence, obtains one +fresh-context Validate verdict, and records Learn before the repository's own +delivery policy begins. Direct push, a PR, external CI, and release automation +are all valid repository adapters; none creates or upgrades the semantic +verdict. `.github/workflows/validate.yml` remains useful for explicit workflow +dispatch, external collaboration, and `v*` release tags. Release tag pushes +force every path-filtered release lane on, and the summary fails if any release +lane is skipped unexpectedly. PR-only evidence jobs are allowlisted on tag +pushes because tag events have no PR body; other skipped jobs are not treated as +release verdicts. Blocking policy list for optional Actions runs (must match the validate summary failset): every job in the CI table below except jobs marked `(non-blocking)`, including the seven `validate-codex-*` and `validate-headless-runtime-skills` jobs (split from the previous aggregated `codex-runtime-sections` job, soc-ltp2). #### Advisory Job Triage SLAs (post-merge advisory policy, soc-z7qq) -Advisory and warn-only jobs can run in optional Actions contexts, but their failure does NOT block a locally validated direct-main landing. Most surface a `(advisory)` suffix on the GitHub check name. (`executable-spec-link-integrity` was promoted to blocking in soc-x7y9f; only its inner `ao goals trace --orphans` step remains warn-only inside the now-required job.) Each listed job has a triage SLA or explicit info-only handling — when the job has been red for longer than its SLA, follow the escalation rule. +Advisory and warn-only jobs can run in optional Actions contexts, but their +failure does not rewrite an already recorded semantic verdict. Most surface a +`(advisory)` suffix on the GitHub check name. (`executable-spec-link-integrity` +was promoted to blocking in soc-x7y9f; only its inner `ao goals trace --orphans` +step remains warn-only inside the now-required job.) Each listed job has a +triage SLA or explicit info-only handling — when the job has been red for longer +than its SLA, follow the escalation rule. | Job | Triage SLA | Escalation rule | |---|---|---| @@ -26,12 +42,12 @@ These CI 1-40 items are intentionally not being hardened in this wave. Revisit o | Item | Current handling | Rationale | Promotion trigger | |---|---|---|---| -| **1 — go-build error** | DEFER | Compilation breakage is developer hygiene; `cd cli && make build && make test` already exists in the local checklist. | Promote to FIX if a merged `main` commit reaches CI with the same build-class failure twice in 30 days despite local pre-push guidance. | +| **1 — go-build error** | DEFER | Compilation breakage is developer hygiene; `cd cli && make build && make test` already exists in the local checklist. | Promote to FIX if a merged `main` commit reaches CI with the same build-class failure twice in 30 days despite focused local evidence. | | **7 — cli-integration cascade** | DEDUPE/DEFER | Failures cascade from build/test root causes, primarily items 1 and 4. | Promote to FIX if `cli-integration` fails independently after items 1 and 4 are green for two consecutive affected runs. | | **13 — contract-compatibility** | DEFER | The gate is doing its job; failures indicate real schema or catalog drift. | Promote to FIX if the same false-positive contract failure repeats twice in a quarter. | | **14 — smoke-test Python 3.14** | DEFER | Rare flake; workflow pinning already narrows the surface. | Promote to FIX if the Python 3.14 smoke failure appears in two separate PRs or nightlies within 30 days. | | **21 — GoReleaser publish failure** | DEFER | Release publish failures are covered by the `pre-tag-ci-validation` pattern and release discipline. | Promote to FIX if a publish failure recurs on two consecutive release attempts with the same root cause. | -| **22 — doc-release blocks publish** | DEDUPE/DEFER | This is a cascade from item 12 doc-release drift, now covered by pre-push gating. | Promote to FIX if publish is blocked by doc-release after item 12's local gate has passed on the release branch. | +| **22 — doc-release blocks publish** | DEDUPE/DEFER | This is a cascade from item 12 doc-release drift, covered by the repository's deterministic gate. | Promote to FIX if publish is blocked by doc-release after item 12's exact-input gate has passed on the release branch. | | **23 — markdownlint** | DEFER | Rare and cheap to repair locally. | Promote to FIX if markdownlint failures occur more than twice in a quarter or block a release branch. | | **24 — shellcheck** | DEFER | Rare and cheap to repair locally. | Promote to FIX if shellcheck failures occur more than twice in a quarter or block a release branch. | | **27 — plugin-load-test manifest** | DEFER | Low failure rate and the gate catches real manifest/plugin-structure drift. | Promote to FIX if plugin-load-test reports a false positive twice in a quarter. | @@ -54,7 +70,6 @@ These CI 1-40 items are intentionally not being hardened in this wave. Revisit o | Job | What it validates | Common failure | |-----|-------------------|----------------| | **cli-tests** | Go CLI tests with `-race` and coverage | Test regression in `cli/internal/**` | -| **static-validation** | Smoke, doc-release, and hooks/docs parity gates | Skill/doc drift slipping past pre-push | +| **static-validation** | Smoke, doc-release, and hooks/docs parity gates | Skill/doc drift absent from the candidate receipt | | **retrieval-bench** | Synthetic + live corpus retrieval precision/coverage gates | P@3 < 0.67 or live coverage < 0.80 | | **security-toolchain** | Full `security-gate.sh` (semgrep, gosec, gitleaks, trivy, hadolint) | Scanner findings or toolchain install flake | - diff --git a/AGENTS.md b/AGENTS.md index 77a6ff70b..233b3a302 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -41,6 +41,10 @@ through the owning command. ## Ordered operating loop +Discovery, Crank, Validate, and Learn are the four lifecycle umbrellas. +Premortem is a Discovery strategy; Postmortem is optional after Learn. The +context that authors a candidate cannot issue its binding verdict. + 1. **Orient.** Read the request, this contract, `git status`, and the smallest triggered canonical sources. Identify authority, current state, and risk. 2. **Shape acceptance.** State the behavior as testable Given/When/Then examples, @@ -69,8 +73,9 @@ through the owning command. chooses repair or re-plan. Deliver the same candidate through repository policy, verify the remote SHA, and emit the tranche report that releases the tranche slot. `/postmortem` and compounding stay off the critical path unless learning - invalidates the candidate. For this repo, `ao land ` is the terminal - delivery transition. + invalidates the candidate. Delivery is repository-owned: local and cloud + agents may use direct push, a PR, external CI, or another declared adapter. + AgentOps records delivery evidence; it does not control the Git transition. The orchestrator classifies evidence as NOTE, REPAIR, REPLAN, HOLD, or ANDON. Ordinary REFUTED or a failed check is REPAIR/REPLAN and returns to the earliest @@ -79,8 +84,8 @@ phase-local retry multipliers are forbidden. Max-attempts, oscillation, or no-progress enters HOLD and gets exactly one bounded fresh-context helper. UNSTUCK resumes with a new approach; only helper ESCALATE, human-only judgment, or a genuinely spent hard time, cost, or quota ceiling raises ANDON. A retry count -alone is never a spent budget. General breaker authority: -[`docs/contracts/pawls.md`](docs/contracts/pawls.md); RPI-specific transitions: +alone is never a spent budget. General disposition authority is this contract +and the operating-loop state table; RPI-specific transitions are in the [`skills/rpi/references/pull-flow-governor.md`](skills/rpi/references/pull-flow-governor.md). ## Concurrency boundary @@ -98,7 +103,7 @@ alone is never a spent budget. General breaker authority: | Trigger | Canonical owner to read | Purpose | |---|---|---| | Planning, implementation, validation, or repair | [`docs/architecture/operating-loop.md`](docs/architecture/operating-loop.md) | Legal transitions and proof loop | -| Bead, worktree, landing, or provenance operation | [`docs/agent-workflow-reference.md`](docs/agent-workflow-reference.md) and [`AGENTS-WORKFLOW.md`](AGENTS-WORKFLOW.md) | Repo-specific mechanics and compatibility detail | +| Bead, worktree, delivery, or provenance operation | [`docs/agent-workflow-reference.md`](docs/agent-workflow-reference.md) and [`AGENTS-WORKFLOW.md`](AGENTS-WORKFLOW.md) | Repo-specific mechanics and transitional detail | | CLI command or flag | `cli/cmd/ao/` then `cli/docs/COMMANDS.md` | Executable and generated command truth | | Bounded context, port, or adapter change | `docs/architecture/component-map.md` and `docs/architecture/ports-and-adapters.md` | DDD/hexagonal boundaries | | Skill behavior or inventory change | `skills//SKILL.md`, `docs/SKILL-ROUTER.md` | Skill contract and selection | diff --git a/GOALS.md b/GOALS.md index 7169631f5..b3714d014 100644 --- a/GOALS.md +++ b/GOALS.md @@ -1,6 +1,6 @@ # Goals -**AgentOps is the validation apparatus for stochastic agentic code work** — the membrane, map, evidence record, and learning loop that answer: *is this code right, and is this agent output proven enough to trust farther?* It drives a goal through four explicit umbrellas: Discovery shapes behavior, Crank executes small slices, Validate gives completed work to a fresh context that did not create it, and Learn routes the result into the next experiment. Deterministic tests remain ground truth; one fresh sub-agent is the default independent judge, while mixed-model councils are an optional rigor tier. Validation produces a verdict and proof record. Git delivery remains the repository's policy. +**AgentOps is the validation apparatus for stochastic agentic code work** — the boundary, map, evidence record, and learning loop that answer: *is this code right, and is this agent output proven enough to trust farther?* It drives a goal through four explicit umbrellas: Discovery shapes behavior, Crank executes small slices, Validate gives completed work to a fresh context that did not create it, and Learn routes the result into the next experiment. Deterministic tests remain ground truth; one fresh sub-agent is the default independent judge, while mixed-model councils are an optional rigor tier. Validation produces a verdict and proof record. Git delivery remains the repository's policy. > Canonical 3.0 + navigator architecture: [docs/3.0.md](docs/3.0.md); product framing: [PRODUCT.md](PRODUCT.md); component routing and trim/defer posture: [docs/architecture/component-map.md](docs/architecture/component-map.md). The directives below are measured against them. @@ -20,15 +20,15 @@ The self-hosting line is this: **AgentOps is done-enough when the navigator driv The prioritization rule this destination creates — and the reason it *drives* the repo: **an epic is pursued only if it advances a route milestone toward autonomous-goal→verified-done; everything else is deferred, not abandoned.** The routing source for that rule is [docs/architecture/component-map.md](docs/architecture/component-map.md): new work is KEEP only if it advances route-critical ledger/tracker truth, validation/release health, measured corpus proof, the governed factory front door, or runtime proof for the core loop; otherwise it is DEFER/TRIM until the route earns it. That rule is what turns 100+ undifferentiated epics into a route. Every North Star below is a *property* the navigator needs to reach the destination; every Directive is a *paving stone on the route*. -## One self-contained factory, delivery outside the membrane +## One self-contained factory, repository-owned delivery The destination is reached by AgentOps itself: one self-contained factory with -its own validation membrane, navigator loop, corpus/flywheel, and CDLC. The +its own validation boundary, navigator loop, corpus/flywheel, and CDLC. The trust boundary is between stochastic production and an explicit, acceptance-bound verdict from fresh context. It is not a merge boundary. - **AgentOps produces, senses, judges, and learns.** It drives work, emits deterministic evidence (**SENSOR**), obtains an independent verdict through Validate (**JUDGE**), and mines evidence into proposed improvements through Learn (**ASSAY**). -- **Repositories deliver.** Direct push, PR, merge queue, hosted CI, and release policy are adapters outside domain completion. Pawl remains available only as an opt-in high-assurance delivery adapter. +- **Repositories deliver.** Direct push, PR, merge queue, hosted CI, and release policy are adapters outside domain completion for both local and cloud agents. AgentOps records delivery evidence but never owns the Git transition. The factory runs the core loop on **two axes**: @@ -40,10 +40,10 @@ The trust comes from **separation of duties** inside the one factory: stochastic ## North Stars -- **The verification membrane is the product.** Nothing an agent generates is trusted until an independent verifier — never the authoring context; a fresh same-family agent is sufficient by default — proves it against an explicit acceptance contract. Mixed families and councils raise rigor when risk warrants them. It cannot *guarantee* stochastic output — it records bounded assurance. -- **Beneath the membrane, the corpus compounds.** A versioned, provenance-tracked context corpus makes each session measurably better than the last — fewer tokens, fewer failures, a rollback path. The knowledge flywheel is the compounding *layer under* the membrane — measured, not asserted; not the headline. +- **The validation boundary is the product.** Nothing an agent generates is trusted until an independent verifier — never the authoring context; a fresh same-family agent is sufficient by default — proves it against an explicit acceptance contract. Mixed families and councils raise rigor when risk warrants them. It cannot *guarantee* stochastic output — it records bounded assurance. +- **Beneath the validation boundary, the corpus compounds.** A versioned, provenance-tracked context corpus makes each session measurably better than the last — fewer tokens, fewer failures, a rollback path. The knowledge flywheel is the compounding *layer under* the boundary — measured, not asserted; not the headline. - **Independent verification is table stakes; sovereignty is the differentiator.** Fresh context with author≠validator is the price of entry, not a moat. What is durable is ownership: your proof and corpus, in your formats, in your repo, portable across whichever model wins next quarter. The candidate quality moat — a measurable corpus delta — remains unproven and must stay on the ruler. -- **Compute is fungible; rigor is risk-routed.** One fresh validator is the default membrane. Cross-family judges and councils are optional strategies for higher-risk work, not mandatory infrastructure or a universal quorum. +- **Compute is fungible; rigor is risk-routed.** One fresh validator is the default boundary. Cross-family judges and councils are optional strategies for higher-risk work, not mandatory infrastructure or a universal quorum. - Skills work identically across Claude Code, Codex CLI, Cursor, and OpenCode. - The wiki maintains itself: every session contributes to `.agents/` by default, and knowledge captured in one session is retrieved and applied in the next — including autonomously between sessions (dream cycle), not just on-demand. - A new user goes from install to first validated flow in under 5 minutes. @@ -145,7 +145,7 @@ When the same pattern appears across 3+ sessions — a debugging technique, a va The existing eval suites are CI canaries (contract checks). None answers "did this skill change make agents better?" Ship a behavioral eval system with a known-good workbench project, task definitions with golden solutions, and scoring scripts that measure correctness, safety, and process adherence. The eval engine already supports A/B comparison via `--baseline-mode=both` and statistical verdict — the gap is eval content, not infrastructure. -**Progress:** Workbench built: 3 components (Go CLI, Python FastAPI, DevOps scripts), 12 tasks with setup/score scripts, behavioral eval suite (`workbench-behavioral-v1`) with 12 cases covering bug-fix, feature implementation, security, refactoring, test-writing, and edge-case handling. `make -C evals/workbench verify` passes golden (12/12) and broken detection (12/12). A/B comparison via DeltaScorecard validated. Agent harness script with industry-proven eval patterns shipped. `eval-skill-delta` CI gate added to `validate.yml` (structural, runs on eval file changes). `--two-pass` mode added to pre-push head gate for local skill-delta validation. Remaining gap: expanding eval-skill-delta from structural-only to a default blocking gate with full skill-on vs skill-off execution across the workbench. +**Progress:** Workbench built: 3 components (Go CLI, Python FastAPI, DevOps scripts), 12 tasks with setup/score scripts, behavioral eval suite (`workbench-behavioral-v1`) with 12 cases covering bug-fix, feature implementation, security, refactoring, test-writing, and edge-case handling. `make -C evals/workbench verify` passes golden (12/12) and broken detection (12/12). A/B comparison via DeltaScorecard validated. Agent harness script with industry-proven eval patterns shipped. `eval-skill-delta` CI gate added to `validate.yml` (structural, runs on eval file changes). The former local head gate carried a `--two-pass` experiment; that delivery wiring is not current authority. Remaining gap: expanding eval-skill-delta from structural-only to a repository-selected blocking gate with full skill-on vs skill-off execution across the workbench. **Directive ID:** d-measure-skill-value-through-real-task-evaluation **Steer:** increase (behavioral eval tasks with scoring scripts) @@ -157,7 +157,7 @@ Non-trivial work must run through the [operating loop](docs/architecture/operati A bead is "non-trivial" when it crosses sessions, agents, files, or bounded contexts — the threshold under which the loop is overhead. Trivial one-shot work (typo fix, dep bump, doc nudge) is exempt. Everything else must, before implementation begins: name a route from the [Component Map](docs/architecture/component-map.md) and the generated [context map](docs/contracts/context-map.md); carry at least one Given/When/Then acceptance example; decompose into vertical slices with one nameable first-failing-test per slice; mark its wave plan parallel only after the wave-validity check passes; close only when every acceptance example maps to a passing test. -This directive starts in **warn-only** posture. The gate is `scripts/check-loop-shape.sh`: it currently inspects legacy `bd` JSON (open + in_progress beads, or a `--json` fixture) and warns when a bead tagged non-trivial lacks a Gherkin block (Given/When/Then) or a slice candidate. Reconcile that live path to `br` before any strict-mode flip. It runs always-warn in `scripts/pre-push-gate.sh` and never blocks a push; `--strict` (or `AGENTOPS_LOOP_SHAPE_STRICT=1`) exits non-zero on offenders, reserved for the flip to blocking once the corpus-wide pass rate is stable. Regression coverage: `bash scripts/check-loop-shape.sh --self-test`. +This directive starts in **warn-only** posture. The gate is `scripts/check-loop-shape.sh`: it currently inspects legacy `bd` JSON (open + in_progress beads, or a `--json` fixture) and warns when a bead tagged non-trivial lacks a Gherkin block (Given/When/Then) or a slice candidate. Reconcile that live path to `br` before any strict-mode flip. It never blocks repository delivery; `--strict` (or `AGENTOPS_LOOP_SHAPE_STRICT=1`) exits non-zero on offenders, reserved for the flip to blocking once the corpus-wide pass rate is stable. Regression coverage: `bash scripts/check-loop-shape.sh --self-test`. Waterfall-shaped speculative plans fail this directive when they create context bulk before proof. The acceptable unit is atomic: one behavior, one bounded context, one first failing test, one write scope, one acceptance proof, and one learning only when it changes future behavior. @@ -213,9 +213,9 @@ It is a stay-removed OUTCOME guard, not a code-size metric (GOALS.md "## Anti St Route milestones (the paving stones, in dependency order — each carries an honest status, not a claim): -1. **Position signal** — the navigator must know where it is. The SDLC provenance ledger exists and is tamper-evident (`ag-8jf97`, landed `479891017`). The bead→commit **land emitter is now wired + live** (`ao provenance emit-landed`, `ag-62jrm` landed `e17d68b9e`): the pre-push gate feeds the ledger on every landing — non-blocking and self-terminating. The **gate-verdict + claude-code-review-verdict emitters remain** (`ag-cm8nd`), so the signal feeds on *landings* but not yet on *verdicts*. *Status: feeding on landings; verdict emitters pending.* +1. **Position signal** — the navigator must know where it is. The SDLC provenance ledger exists and is tamper-evident (`ag-8jf97`, shipped `479891017`). The old bead-to-commit emitter (`ag-62jrm`, shipped `e17d68b9e`) is historical input to the new delivery receipt. Verdict recording remains the route-critical signal. *Status: historical delivery evidence exists; final verdict and delivery recorders are pending.* 2. **Resilience / the role state-machine** — the navigator must recover without a human: mechanical failures fix-forward, substantive ones re-scope with the failure as the new acceptance, blockers pull the andon (stop-the-line). `ship-beads` builds but cannot self-merge yet. *Status: build half works, recovery half is a stub.* -3. **The membrane** — "done" must be *verified*, not merely asserted: Validate binds an acceptance-grounded verdict from a fresh context, and deterministic tests provide the windshield that catches a hallucinated done. A fresh same-family validator is sufficient by default; mixed families are opt-in. Delivery adapters may consume the proof but do not create it. *Status: four-umbrella membrane live; provenance windshield poured.* +3. **The validation boundary** — "done" must be *verified*, not merely asserted: Validate binds an acceptance-grounded verdict from a fresh context, and deterministic tests provide the windshield that catches a hallucinated done. A fresh same-family validator is sufficient by default; mixed families are opt-in. Delivery adapters may consume the proof but do not create it. *Status: four-umbrella boundary live; provenance windshield poured.* 4. **Self-improvement** — each drive must measurably improve the next: SENSOR (the ledger) → ASSAY (bounded periodic miners over it) → GATE (suggestions re-enter the same front door). *Status: designed; sensor floor just poured; miners + tick unbuilt.* 5. **Governance front-door** — nothing new is born ungoverned: the kind-unified factory admits a skill / workflow / loop only with a bounded context + role + runnable acceptance (epic `ag-3fp54`; S0 schema landed `692f420ac`). *Status: schema landed; front-door unbuilt.* @@ -227,7 +227,7 @@ The drive is unattended-end-to-end only when all five hold at once. Until then, ### 17. Verification economics — hold the escape SLO at minimum token cost -The membrane's guarantee (no verdict = not done) is priced, not free. This directive makes +The validation boundary's guarantee (no verdict = not done) is priced, not free. This directive makes **discrimination per token** a measured fitness axis (assessment: [docs/audits/verification-economics.md](docs/audits/verification-economics.md); epic `age-verification-economics-ebec`). The ruler, in dependency order: **TPVD** (tokens per @@ -235,7 +235,7 @@ verified done), **VOR** (verification overhead ratio = verify spend ÷ produce s **CPCD** (cost per caught defect), and an explicit **escape SLO** with an error budget (current evidence: 0 escapes across the verdict corpus; rule-of-three CI bounds the true rate ≤ ~2%). Spend to the budget, not to zero: when the budget sits untouched at current -spend, the membrane is over-provisioned — move a lane one tier cheaper and watch the meter. +spend, the boundary is over-provisioned — move a lane one tier cheaper and watch the meter. Honesty rules (binding): thresholds are set FROM measured meter data (two weeks minimum), never invented; claims stay inside the confidence interval the sample supports; the meter @@ -247,8 +247,9 @@ instrument, never on a threshold, until the ruler earns thresholds from data. Ph numbers — act on data, not on the assessment. **Progress:** report instrument + warn-only gate landed 2026-07-06 (`b0149df9a`, bead `.2`; -live: 322 verdict edges, 2.8% refute rate). Benched-family stall tax removed from the default -pawl route 2026-07-07 (`335300b17`, bead `.7`, council-decided) — ~3.5 min/land recovered. +live: 322 verdict edges, 2.8% refute rate). Benched-family stall tax was removed +from the former review route on 2026-07-07 (`335300b17`, bead `.7`) — about 3.5 +minutes per delivery recovered. Meter (`.1`) and data-derived thresholds pending. **Directive ID:** d-verification-economics-escape-slo-at-minimum-cost @@ -257,7 +258,7 @@ Meter (`.1`) and data-derived thresholds pending. ## Three-Gap Contract Proof Surface -AgentOps defines a three-gap contract ([context lifecycle](docs/context-lifecycle.md)) covering the failure modes that persist after prompt construction and agent routing. Honesty rule: gates only appear in the **Currently enforcing** column when they (a) run in CI/pre-push/release automation AND (b) reliably go green in single-session work. Gates that are declared but not yet enforced — usually because they measure cross-session or corpus-level state — sit in the **Roadmap** column. +AgentOps defines a three-gap contract ([context lifecycle](docs/context-lifecycle.md)) covering the failure modes that persist after prompt construction and agent routing. Honesty rule: gates only appear in the **Currently enforcing** column when they (a) run in candidate, repository CI, or release automation AND (b) reliably go green in single-session work. Gates that are declared but not yet enforced — usually because they measure cross-session or corpus-level state — sit in the **Roadmap** column. | Gap | What fails without it | Currently enforcing | Roadmap (declared, not yet enforced) | |-----|-----------------------|---------------------|---------------------------------------| @@ -320,7 +321,7 @@ artifact produced by a separate run (e.g. `ao defrag` writing | flywheel-lifecycle | `timeout 30 bash scripts/check-flywheel-lifecycle.sh` | 6 | Knowledge lifecycle traces capture → index → inject → retrieval | | | eval-workbench-verify | `timeout 60 bash scripts/check-eval-workbench.sh` | 6 | Behavioral eval workbench golden state, task scoring, and suite structure verified | | | state-path-resolver-coverage | `bash scripts/check-paths-resolver-coverage.sh` | 3 | Tracks executable-code sites that still hardcode `.agents/` paths instead of sourcing the canonical resolver (lib/ao-paths.sh / cli/internal/paths from soc-irg1.1). Warn-only initially per warn-then-fail-ratchet pattern; flip to blocking is a separate follow-up issue under epic soc-irg1 after 2 weeks of baseline data. See `.agents/patterns/2026-05-01-state-path-resolver.md`. | warn-only | -| executable-spec-link-integrity | `ao goals scenarios --lint && ao goals trace --orphans` | 4 | Directive↔scenario link lint and whole-chain orphan/gap audit (F1.6, soc-58nt.1.9). Warn-only until two consecutive clean CI runs on main; promote to blocking by removing `continue-on-error: true` from the `executable-spec-link-integrity` CI job and replacing warn with fail in pre-push check 38. | warn-only | +| executable-spec-link-integrity | `ao goals scenarios --lint && ao goals trace --orphans` | 4 | Directive↔scenario link lint and whole-chain orphan/gap audit (F1.6, soc-58nt.1.9). Warn-only until two consecutive clean CI runs on main; promotion belongs to the repository CI policy and is a separate reviewed change. | warn-only | | no-apparatus-regrowth | `bash scripts/check-no-apparatus-regrowth.sh` | 5 | Anti-regeneration (Directive D15): teardown-removed apparatus stays removed. Reads the committed `scripts/removed-apparatus.txt` manifest and FAILS only when a surface the teardown (epic ag-097) explicitly removed comes BACK. Stay-removed OUTCOME guard, NOT a size/line/file/job metric — legitimate new growth is fine; only regrowth of the listed surfaces fails. Future teardown waves append the deleted path to the manifest in the same change. | | | door9-no-api-print | `CP="${CONTROL_PLANE_ROOT:-/Users/bo/dev/control-plane}"; if [ -x "$CP/bin/no-api-print-scan.sh" ]; then ( cd "$CP" && bash bin/no-api-print-scan.sh ); else echo "door9-no-api-print: SKIP (control-plane absent at $CP — set CONTROL_PLANE_ROOT)"; fi` | 6 | LAW 0 as fitness: no `claude -p` / `claude --print` (forbidden API-print) invocations across tracked control-plane files. Runs the control-plane door-9 scanner (`bin/no-api-print-scan.sh`) from the control-plane root (the scanner is cwd-sensitive — it scans `git ls-files`). Cross-repo: resolves `$CONTROL_PLANE_ROOT` (default `/Users/bo/dev/control-plane`); SKIPs cleanly with a notice when the control-plane root is absent. Measured 2026-06-10: CLEAN over 218 tracked files. | cross-repo | | image-conformance | `CP="${CONTROL_PLANE_ROOT:-/Users/bo/dev/control-plane}"; if [ -x "$CP/bin/image-conformance.sh" ]; then ( cd "$CP" && bash bin/image-conformance.sh --built-only ); else echo "image-conformance: SKIP (control-plane absent at $CP — set CONTROL_PLANE_ROOT)"; fi` | 5 | Agent-image bundles conform: every built image (claude-control-plane / claude-worker / codex-worker / agy-worker) has a complete bundle, SSOT-valid manifest, role-correct duties + dcg-pack, and a green verify.sh. Runs the control-plane conformance matrix `--built-only` **from the control-plane root** (the per-image verify.sh has cwd-sensitive checks — e.g. the worker Rust build-farm-redirect check only resolves from the repo root, so the gate must `cd` there to run RELIABLY per the three-gap honesty rule). Cross-repo: resolves `$CONTROL_PLANE_ROOT`; SKIPs cleanly when absent. Measured 2026-06-10 from the CP root: 28/28 PASS. | cross-repo | diff --git a/PRODUCT.md b/PRODUCT.md index 5027191ab..09437a8fd 100644 --- a/PRODUCT.md +++ b/PRODUCT.md @@ -6,7 +6,7 @@ last_reviewed: 2026-06-14 ## Mission -**AgentOps is autonomous code validation for agentic software development.** It answers the questions that matter before you trust an agent's work: **is this code right, and is this agent output proven enough to receive more autonomy?** The mechanism is an SDLC control-plane shape around a repo-local corpus: markdown in `.agents/` next to your code, produced and consumed by the agents that work there. The product is the loop that produces validated output with proof — it catches the agent saying done when it isn't. **What is proven is the membrane and the record:** independent, fresh-context verification (no verdict = not done) plus a durable, hash-chained provenance ledger that binds every verdict to the work. The durable differentiator is **sovereignty** — that record lives in your repo and outlives any model or vendor. Whether the accumulated corpus *compounds* into a quality edge — the knowledge corpus and the escape-corpus alike — is a named, unproven hypothesis still being measured ([ADR-0004](docs/adr/ADR-0004-corpus-moat-unproven-position-on-the-system.md), [ADR-0011](docs/adr/ADR-0011-escape-corpus-compounding-unproven-structural-starvation.md)), not the moat. The internal lifecycle is the CDLC: context is developed, tested, delivered, observed, and improved because context is what LLM agents consume. +**AgentOps is autonomous code validation for agentic software development.** It answers the questions that matter before you trust an agent's work: **is this code right, and is this agent output proven enough to receive more autonomy?** The mechanism is an SDLC control-plane shape around a repo-local corpus: markdown in `.agents/` next to your code, produced and consumed by the agents that work there. The product is the loop that produces validated output with proof — it catches the agent saying done when it isn't. **What is proven is the validation boundary and the record:** independent, fresh-context verification (no verdict = not done) plus a durable, hash-chained provenance ledger that binds every verdict to the work. The durable differentiator is **sovereignty** — that record lives in your repo and outlives any model or vendor. Whether the accumulated corpus *compounds* into a quality edge — the knowledge corpus and the escape-corpus alike — is a named, unproven hypothesis still being measured ([ADR-0004](docs/adr/ADR-0004-corpus-moat-unproven-position-on-the-system.md), [ADR-0011](docs/adr/ADR-0011-escape-corpus-compounding-unproven-structural-starvation.md)), not the moat. The internal lifecycle is the CDLC: context is developed, tested, delivered, observed, and improved because context is what LLM agents consume. > The canonical definition of what 3.0 is — the hookless-first CDLC loop and the four-practice waist — lives in [docs/3.0.md](docs/3.0.md). The component and trim/defer routing map that keeps that thesis from sprawling lives in [docs/architecture/component-map.md](docs/architecture/component-map.md). This file is consistent with both. @@ -27,13 +27,14 @@ Validation is deliberately independent from Git delivery. AgentOps does not decide whether a repository uses direct pushes, PRs, merge queues, hosted CI, or a custom release pipeline. The `ao` CLI supplies deterministic checks and optional delivery adapters; those adapters never define domain completion. -The older Pawl/landing machinery remains an optional high-assurance adapter and -lineage surface, not the universal route through Validate. +Legacy review-gated Git machinery is retired product authority. AgentOps records +proof and delivery facts; each repository chooses and operates its own delivery +adapter for local and cloud agents. **Independent verification is table stakes, not the moat.** What AgentOps -positions on is the sovereign proof record: the membrane verifies independently +positions on is the sovereign proof record: the validation boundary verifies independently and the provenance ledger records the verdict in the operator's repo across any -model or vendor. The membrane's self-improvement from an escape corpus and the +model or vendor. The boundary's self-improvement from an escape corpus and the broader corpus-delta bet remain measured hypotheses, not product claims ([ADR-0011](docs/adr/ADR-0011-escape-corpus-compounding-unproven-structural-starvation.md), [ADR-0004](docs/adr/ADR-0004-corpus-moat-unproven-position-on-the-system.md)). @@ -283,7 +284,9 @@ Full profile: [docs/assurance-profile.md](docs/assurance-profile.md). - **Local-first control.** The corpus lives in `.agents/` beside the code. AgentOps requires no product telemetry, and operators choose which model runtimes, networks, and subscriptions touch the repo. - **Context as a boundary.** Research, planning, implementation, and validation receive different context. Workers get fresh windows. Validators get evidence packets instead of the implementer's accumulated chat. - **Bookkeeping by default.** RPI packets, council verdicts, citations, ratchet records, postmortems, handoffs, and substrate/job outputs leave file-backed traces that can be inspected, diffed, archived, or excluded from source control. -- **Policy gates over advice.** Pre-push checks, CI gates, security scans, goal fitness gates, and premortems encode process as executable constraints instead of relying on the agent to remember a runbook. +- **Executable evidence over advice.** Candidate-bound checks, repository CI, + security scans, goal fitness gates, and premortems encode process as + executable constraints instead of relying on the agent to remember a runbook. - **Variable autonomy.** The same factory can run interactive, supervised, or substrate-scheduled loops. High-risk environments can keep humans in the loop for planning, validation, release, and promotion while still using agents for bounded work. - **Constrained-network fit.** The design favors repo-local state, explicit artifacts, no required cloud control plane, and operator-owned or substrate-owned scheduling. Formal deployment into classified, export-controlled, or safety-critical environments still requires the local authority's security controls, model approvals, supply-chain process, and accreditation work. diff --git a/PROGRAM.md b/PROGRAM.md index 9176879fa..1b19b7bc3 100644 --- a/PROGRAM.md +++ b/PROGRAM.md @@ -6,8 +6,9 @@ Run bounded autonomous improvement cycles for AgentOps without relying on session-only prompt policy. Each cycle is one turn of the [operating loop](docs/architecture/operating-loop.md): shape BDD-shaped intent, slice it vertically through behavior, write the first failing test, implement the -smallest change that flips it green, prove acceptance against the bead, push when -the slice is ready to land, and ratchet evidence and learnings. The loop is the +smallest change that flips it green, freeze one candidate, prove facts once, +obtain one immutable fresh-context verdict, and Learn once. Repository-owned +delivery follows as a separate local or cloud transition. The loop is the primitive — no artifact is produced unless it advances behavior toward acceptance. ## Mutable Scope @@ -59,16 +60,15 @@ One bead-backed vertical slice, shaped per the operating loop: Per slice: claim or create the bead, write the first failing test, make the smallest change that flips it green, refactor under green as a separate commit, -record evidence into the bead, run the relevant local gates, update/close the -bead, commit, rebase, push, and verify the remote gate when the slice is intended -to land. A slice that touches `cli/internal/domain/` must preserve the +run targeted deterministic checks, commit and freeze the complete candidate, +obtain one author-distinct Validate verdict, and record Learn. The repository's +delivery adapter then publishes or merges the same candidate and records remote +identity. A slice that touches `cli/internal/domain/` must preserve the no-import-from-`internal/*` invariant; a slice that touches a port writes its first failing test against the port interface, not an adapter internal. ## Validation Commands -- `cd cli && env -u AGENTOPS_RPI_RUNTIME go run -tags legacy ./cmd/ao autodev validate --file ../PROGRAM.md --json` — the `autodev` command surface is archived behind the `legacy` build tag; the shipped spine binary does not carry it -- `cd cli && env -u AGENTOPS_RPI_RUNTIME go test -tags legacy ./cmd/ao ./internal/autodev` - `cd cli && env -u AGENTOPS_RPI_RUNTIME go test ./internal/domain/... ./internal/ports/... ./internal/adapters/...` - `env -u AGENTOPS_RPI_RUNTIME bash skills/heal-skill/scripts/heal.sh --strict` - `bash scripts/check-worktree-disposition.sh` @@ -138,9 +138,10 @@ two or more slices. is still untouched; every rollback path is reachable. Activity logs do not close beads — acceptance evidence does. - The active bead is closed or updated with concrete remaining blockers. -- The relevant validation bundle is green, including the fast pre-push gate for - landed changes. -- The worktree is clean, pushed, and up to date with origin for landed changes. +- The selected deterministic bundle is green for the exact frozen candidate and + one independent Validate verdict is recorded. +- Learn is recorded once; if delivery is requested, the repository adapter has + verified the exact remote identity. - Every foreign worktree is marked merged, preserved, exported, or deleted. - Evidence is recorded in the bead and `.agents/ratchet/`; learnings are promoted only if they cleared the promotion ratchet bar. diff --git a/cli/README.md b/cli/README.md index ea5e5b93f..922338c8f 100644 --- a/cli/README.md +++ b/cli/README.md @@ -1,13 +1,8 @@ # ao — AgentOps CLI -`ao` is the local verification membrane and durable bookkeeper for agent work. -It turns a committed change into an independently checked verdict and records -that verdict in a hash-chained provenance ledger: no verdict means not done. - -The default binary intentionally exposes the membrane/bookkeeper spine from -[ADR-0012](../docs/adr/ADR-0012-focus-surface-on-membrane-bookkeeper-archive-satellites.md). -Experimental corpus/flywheel commands are restorable with the `flywheel` build -tag; retired factory/orchestration commands are restorable with `legacy`. +`ao` is the deterministic transaction kernel and evidence recorder beneath the +AgentOps operating loop. Agents own intent, implementation, and semantic +judgment. Repositories own Git delivery. ## Install @@ -15,59 +10,49 @@ tag; retired factory/orchestration commands are restorable with `legacy`. go install github.com/boshu2/agentops/cli/cmd/ao@latest ``` -## One live path +## Current executable truth -From a repository root: +The command tree is mid-cut. Inspect the binary you actually have rather than +assuming a profile or narrative list: ```bash -ao quick-start -ao session bootstrap -ao beads tracker -ao beads ready -git add . -git commit -m "fix: first validated change" -ao verify my-first-change -ao gate check --fast --scope head +ao capabilities +ao robot-docs +ao --help ``` -`ao quick-start` creates the local readiness seed. `ao session bootstrap` -orients the agent. `ao beads tracker` reports the selected BR/BD backend, and -all tracker consumers use that same selection. `ao verify` obtains and records -the first independent verdict. The gate is the final pre-push windshield. +The generated [command reference](docs/COMMANDS.md) follows executable source +and is not hand-maintained in an authority-doc change. -## Default surfaces +## Final boundary -| Surface | Purpose | -|---|---| -| `ao capabilities` | Recursive, versioned machine contract for the live command tree | -| `ao quick-start` | Seed a repository and print the one live first-verdict path | -| `ao beads` | Resolve and operate through the selected tracker | -| `ao pawl` / `ao verify` | Independent review and commit-bound verdict | -| `ao gate` / `ao validate` | Deterministic release checks and verdict-as-exit-code validation | -| `ao provenance` | Append, inspect, export, and verify the hash-chained ledger | -| `ao session` | Session bootstrap and closeout bookkeeping | -| `ao goals` / `ao claim` | Intent, fitness, ownership, and evidence bindings | -| `ao skills` | Inspect the checked-in skill contracts | +The direct-cut program converges on one profile-free command tree. Its lifecycle +transactions are: -Machine consumers should begin with `ao capabilities`. Global output formats -are closed to `table`, `json`, and `yaml`; a leaf-local flag with the same name -retains its local meaning. +- pull one ready work leaf; +- freeze exact candidate identity; +- run or reuse exact-input deterministic evidence; +- record a PASS or FAIL supplied by an external fresh-context validator; +- record one Learn receipt; +- record repository-owned delivery and remote identity; and +- close the report and tracker leaf after verification. -## Build variants +These transactions do not ask a model to judge work and do not push, merge, +queue, or select CI policy. Local and cloud agents use the same ports. -```bash -go build ./cmd/ao -go build -tags flywheel ./cmd/ao -go build -tags legacy ./cmd/ao -go build -tags 'flywheel legacy' ./cmd/ao -``` +K5, K7, and K9 own deletion of the old verdict-driving, delivery, and retired +gate implementations. Exact `CLI.` leaves own the remaining command +dispositions. F4 removes alternate build profiles. D2 regenerates this command +surface only after executable ownership is final. -Run `../scripts/verify-buildtags.sh` from this directory's parent to prove all -variants compile and that the default executable membership remains focused. +## Development -## Reference +During the cut, use the focused test named by the owning leaf. Do not add new +profile membership, `init()` registration, package-global command ownership, +compatibility aliases, or dormant scaffolds. + +## References -- [Generated CLI reference](docs/COMMANDS.md) -- [ADR-0012](../docs/adr/ADR-0012-focus-surface-on-membrane-bookkeeper-archive-satellites.md) - [Operating loop](../docs/architecture/operating-loop.md) -- [Pawl contract](../docs/contracts/pawls.md) +- [Go CLI architecture guide](../docs/architecture/go-cli-architecture-guide.md) +- [Direct-cut ADR](../docs/adr/ADR-0012-focus-surface-on-membrane-bookkeeper-archive-satellites.md) diff --git a/docs/3.0.md b/docs/3.0.md index 0c273c481..c049d5927 100644 --- a/docs/3.0.md +++ b/docs/3.0.md @@ -105,7 +105,7 @@ Hookless-first is the most misunderstood part, so be precise. - **The 2.x failure mode:** hooks were the architecture. Dozens fired on every event and pushed context into the window: standards for files you were not touching, learnings that did not apply, warnings that did not fire. Resident context stacked (a real RPI run hit ~10.35M tokens at 97.6% cache-read), and the A/B eval showed the injected context made **no difference (delta = 0)**. The problem was never hooks; it was noise stacking in the prompt. - **The 3.0 model:** context is *pulled* through explicit channels. **BDD/Gherkin** for intent, **execution and context packets through ports** for the phase-scoped working set, **hexagonal boundaries** for the seams. Dense and just-in-time, not stacked. -- **The default install works with zero hooks.** Workflow is guided by skills plus the `ao` CLI, and the local cockpit gate is the routine release authority in this repo. GitHub Actions remain an optional/manual backstop and release/tag signal. If you want a bounded gate of your own (block a dangerous operation, bootstrap a session, run a parity check), author it with the `hooks-authoring` skill. AgentOps does not ship one. +- **The default install works with zero hooks.** Workflow is guided by skills plus the `ao` CLI. The repository owns delivery and may choose direct push, PRs, external CI, or a bounded deterministic hook for local or cloud agents. AgentOps does not ship or require one. The rule in one line: **context is pulled, dense, and just-in-time; nothing sprays noise into a prompt.** @@ -146,7 +146,10 @@ In every case the substrate dispatches a whole loop as one unit — an agent run The CDLC loop is one doctrine, and it has **one implementation**: AgentOps. There is no separate hosted control plane or daemon in the running factory. AgentOps shapes work, executes it, validates it in fresh context, and records what the result changes — all in-repo, fully local, no cloud required. -Validation ends when `/validate` emits the evidence-bound verdict and `/learn` emits the bookkeeping and plan-impact receipt. Git delivery starts after that boundary. A repository may direct-push, open a PR, use hosted CI, or invoke an optional high-assurance adapter such as Pawl. None of those choices change whether AgentOps has proved the work. +Validation ends when `/validate` emits the immutable evidence-bound verdict and +`/learn` emits the bookkeeping and plan-impact receipt. Git delivery starts +after that boundary. A repository may direct-push, open a PR, or use hosted CI. +None of those choices change whether AgentOps has proved the work. Independent review is **table stakes**, not a moat. The durable differentiator is **sovereignty**: the in-session loop, proof ledger, and `.agents/` corpus stay portable across model and harness, owned by the operator. Any quality edge from accumulated context is an unproven corpus delta, measured on the eval rather than asserted here. @@ -159,7 +162,7 @@ Independent review is **table stakes**, not a moat. The durable differentiator i - [x] This north star is the single referenced source of truth; README, PRODUCT, GOALS, and the docs index point here. - [ ] **Live docs are being reconciled to reality:** the north-star and first-read routers are the source of truth, while downstream historical docs are being moved behind explicit archive/generated boundaries. Current-path docs must not teach retired tracker paths, stale counts, or CI-as-routine-authority claims. - [x] **Hexagon complete:** every skill carries `hexagonal_role` plus accurate `consumes`/`produces` plus canonical `.feature` acceptance, with the deprecated/internal/meta exceptions enumerated in the readiness level-set. -- [x] **Hookless by default:** AgentOps 3.0 ships zero hooks. Workflow is guided by skills plus the `ao` CLI, with the local cockpit gate as this repo's routine authority and CI as optional/manual backstop. Author your own via the `hooks-authoring` skill if you want them. +- [x] **Hookless by default:** AgentOps 3.0 ships zero hooks. Workflow is guided by skills plus the `ao` CLI; each repository owns any hook, CI, PR, or direct-push policy it chooses. - [x] **The loop is executable in session:** BDD intent → tests → bounded build → both-ends validation → ratchet, documented in [operating-loop.md](architecture/operating-loop.md) and exercised end-to-end. - [x] **The loop model is named:** one loop body, two drivers, one inner tick, one config, documented in [canonical-loop-model.md](architecture/canonical-loop-model.md). Out-of-session orchestration is the substrate's job. - [ ] Every AgentOps bead is worked or closed against this north star. *(Reconciliation waves closed; remaining 3.0-aligned coherence and ledger beads are open and tracked.)* diff --git a/docs/CI-CD.md b/docs/CI-CD.md index 3d7cfbdb3..6ae9647eb 100644 --- a/docs/CI-CD.md +++ b/docs/CI-CD.md @@ -1,30 +1,38 @@ # CI/CD Architecture -AgentOps uses a local push-as-CI gate for routine direct-main work. The release authority for a normal `main` push is the installed local cockpit gate: `.git/hooks/pre-push` chains to `scripts/hooks/pre-push.local`, builds a fresh `ao`, runs the full `go test ./... -race -shuffle=on -count=1` suite for pushes to `main`, then serializes the mutable `ao gate check --fast` and head-bound pawl checks. GitHub Actions remain useful telemetry and a tag/PR/manual backstop; they are not the routine release gate for direct-main pushes. +AgentOps produces candidate-bound deterministic evidence and one immutable +fresh-context Validate verdict. It does not choose or control Git delivery. +Repositories own delivery policy for local and cloud agents. A repository may +use direct push, a PR, hosted CI, or another adapter, and may select its own +deterministic checks at that boundary without running another semantic review. -Release tag pushes run a full, non-path-filtered Validate verdict for the exact tagged SHA. Releases are automated through GoReleaser with SBOM generation and SLSA provenance attestation. +Release tag pushes run a full, non-path-filtered deterministic repository CI +suite for the exact tagged SHA. That suite does not create or replace +Validate's semantic verdict. Releases are automated through GoReleaser with +SBOM generation and SLSA provenance attestation. -## Live Main-Push Path +## Product and Delivery Boundary ```text -git push origin HEAD:main - -> .git/hooks/pre-push - -> scripts/hooks/pre-push.local - -> go build ./... - -> go test ./... -race -shuffle=on -count=1 - -> acquire host-local lock for mutable gate/provenance/pawl surfaces - -> ao gate check --fast - -> scripts/check-pawl-pre-push.sh - -> remote main fast-forward +Discovery -> Crank -> frozen candidate + -> deterministic evidence for the exact candidate + -> one fresh-context Validate verdict + -> one Learn receipt + -> repository-selected delivery adapter + -> exact remote identity record ``` -The tracked `.githooks/` directory is legacy `bd` hook plumbing. It is inert for the current AgentOps cockpit gate: Git uses `.git/hooks` unless `core.hooksPath` says otherwise, and `scripts/install-pre-push-gate.sh` installs/chains the live gate in the shared `.git/hooks` directory. +Hooks and CI jobs are repository adapters, not AgentOps lifecycle authority. A +fast deterministic hook is allowed when a repository wants one. Model review, +tracker closure, delivery queues, and full validation do not belong in that +hook. Exact-input receipts may be reused only when candidate, command, registry, +toolchain, and environment identities match. ## Workflow Map | Workflow | File | Trigger | Purpose | |----------|------|---------|---------| -| Validate | `validate.yml` | Push to `main`, `v*` tag push, PRs to `main` | Backstop telemetry for routine `main`; authoritative blocking gate for release tags, PRs, and manual validation; tag pushes force every path-filtered release lane on and allowlist PR-only evidence jobs | +| Validate | `validate.yml` | Push to `main`, `v*` tag push, PRs to `main` | Repository CI policy and telemetry; tag pushes force every path-filtered release lane on and allowlist PR-only evidence jobs | | Release Publisher | `release.yml` | Tag push (`v*`), manual dispatch | Build, publish, attest releases | | Nightly | `nightly.yml` | Daily 6am UTC, manual | Public proof harness: full test suite + retrieval + security + compile cycle + Dream report-shape validation over repo-visible artifacts | | Stale Issues | `stale.yml` | Weekly Monday 9am UTC | Auto-mark/close inactive issues and PRs | @@ -109,7 +117,7 @@ The validate workflow runs many focused jobs across 4 tiers of parallelism. Most ### The `summary` Aggregator Pattern -The final `summary` job lists every other job in its `needs` array and runs with `if: always()`. It fails when any `needs.*.result` is `failure`. Advisory and warn-only jobs avoid blocking through `continue-on-error: true` at the job or step level, so their findings remain visible without producing a failing `needs` result. This single aggregator is the rollup target for any required check on tags/PRs/manual dispatch — only `summary` needs to be required, not every individual job. Note: under the push-to-main model (ag-qidx) branch protection is **off**, so on routine `main` pushes the authoritative release gate is the local pre-push Go gate (`ao gate check`); `validate.yml`/`summary` is a CI backstop on tags, PRs, and manual dispatch, not a required main-push gate. +The final `summary` job lists every other job in its `needs` array and runs with `if: always()`. It fails when any `needs.*.result` is `failure`. Advisory and warn-only jobs avoid blocking through `continue-on-error: true` at the job or step level, so their findings remain visible without producing a failing `needs` result. This single aggregator is the rollup target for any required check on tags/PRs/manual dispatch — only `summary` needs to be required, not every individual job. Whether `summary` is required is repository policy. It never substitutes for or changes the author-distinct semantic verdict. Current non-blocking validate jobs are `doctor-check`, `factory-claim-ledger-strict`, `practice-citations`, `check-test-staleness`, `swarm-evidence`, and `executable-spec-link-integrity`. `security-toolchain-gate` is blocking. The old `agentops-eval-advisory` job is no longer part of `validate.yml`; `agentops-contract-canaries` remains the blocking deterministic test gate for the stable public canary subset. @@ -151,7 +159,8 @@ Deferred CI hardening decisions for items 1, 7, 13, 14, 21, 22, 23, 24, 27, 30, ### Blocking Gates (all others) -Every other job is blocking. If any of these fail, `summary` exits non-zero and the PR/push is rejected. +Every other job is blocking for workflows that the repository configures to +require `summary`. If any fails, `summary` exits non-zero. ## What Breaks CI @@ -173,7 +182,7 @@ Consolidated checklist of rules enforced by the pipeline: ### scripts/ci-local-release.sh -The local CI gate mirrors the remote pipeline and runs in 7 phases: +The local CI bundle can reproduce the remote deterministic pipeline in 7 phases: | Phase | Description | Parallelism | |-------|-------------|-------------| @@ -200,9 +209,10 @@ scripts/ci-local-release.sh --release-version 2.X.Y --hil-waiver 'target unavail In `--fast` mode, Phase 4 skips race tests, hook integration tests, SBOM generation, and the security gate. It still builds the binary and runs release validation. When `--release-version` is set, Phase 7 runs in official mode and fails unless the readiness score is at least 8/10 with SIL/VIL pass and HIL pass or waiver. -### Minimum Checks Before Any Push +### Minimum Focused Checks -From CLAUDE.md -- the bare minimum before pushing: +Select the commands that cover the changed surface and record them against the +exact candidate. Repository policy may run broader checks before delivery: ```bash bash skills/heal-skill/scripts/heal.sh --strict # Skill integrity @@ -238,24 +248,20 @@ One CI check is intentionally **not** wired into the local gate: |--------|--------| | `validate-learning-coherence.sh` | Fails on pre-existing frontmatter-only learning files; needs repo cleanup before local enforcement | -## Hookless by default - local gate is the release authority +## Hookless by default -AgentOps 3.0 ships **zero runtime hooks by default**. Repository contributors can -opt into the local cockpit gate by running `scripts/install-pre-push-gate.sh`, -which installs the current gate into the shared `.git/hooks` directory for the -main checkout and linked worktrees. What a session hook used to enforce -implicitly is now enforced by explicit local commands and this installed -pre-push chain, primarily `ao gate check --fast`, the push-to-main full race -suite, and the pawl pre-push check. GitHub Actions remain available as manual, -PR, and release-tag backstops, but they are not the routine release authority. -The workflow is guided by skills plus the `ao` CLI; context flows through explicit -channels (`ao inject` / context packets through ports), not hook side effects. +AgentOps 3.0 ships **zero runtime hooks by default**. Explicit commands produce +the candidate's evidence before Validate. A consumer repository may install a +small deterministic hook or rely on external CI, but that adapter owns only its +repository policy. It must not invoke a model, mutate the semantic verdict, +close tracker work, or replay an unchanged full suite. The workflow is guided by +skills plus the `ao` CLI; context flows through explicit channels, not hook side +effects. -If you want a bounded gate of your own (block a dangerous operation, bootstrap a -session, run a parity check), author it with the `hooks-authoring` skill. Do not -infer live gate behavior from tracked `.githooks/`; use `git config --get -core.hooksPath` and `scripts/install-pre-push-gate.sh` to inspect or refresh the -actual hook chain. +If you want a bounded deterministic hook of your own, author it with the +`hooks-authoring` skill and keep its authority in the repository that installs +it. Do not infer live behavior from tracked examples; inspect the repository's +actual Git and CI configuration. ## Security Gate diff --git a/docs/MIGRATION.md b/docs/MIGRATION.md index 5219b62e7..d28d4c97e 100644 --- a/docs/MIGRATION.md +++ b/docs/MIGRATION.md @@ -2,24 +2,29 @@ AgentOps is a validation gate that proves an agent's work is actually done, plus a provenance record of that proof kept in your own repo. It runs **in your session**, on your machine, against your own subscription — **hookless**: no runtime hooks to install, no daemon to run, no service to babysit. -This is the living map from every AgentOps surface that was removed or retired to what you use instead. If a command you relied on is gone, find its row below: it names the replacement and, where the old surface still exists behind a build tag, the exact command to bring it back. For 3.0-era detail see [MIGRATION-3.0.md](MIGRATION-3.0.md); for version-keyed breaking changes see [UPGRADING.md](UPGRADING.md). +This is the living map from every AgentOps surface that was removed or retired +to what you use instead. Compatibility profiles that still compile are +transitional executable truth, not a product promise: the direct-cut program +deletes each old owner in the same leaf that installs its replacement or proves +its final consumer gone. For 3.0-era detail see [MIGRATION-3.0.md](MIGRATION-3.0.md); +for version-keyed breaking changes see [UPGRADING.md](UPGRADING.md). ## If you used X, use Y now | You used | Use instead | Notes (why + restore path) | |---|---|---| | `bd` / Dolt tracker | `br` + `bv` — `BEADS_DIR="$(ao beads dir)" br ` for tracking, `bv --robot-insights` for triage | The old tracker was a single-host server with no offline lane. `br` is offline and git-JSONL-backed. Your old `.beads/` is preserved but non-authoritative. | -| Runtime hooks (the 2.x hook bundle) | Hookless skills + the `ao` CLI + the installed local pre-push gate (`scripts/install-pre-push-gate.sh`) | Hooks were deleted (ADR-0002) after an A/B showed the injected-context delta was zero. `--with-hooks` remains as an opt-in for anyone who still wants them. The gate — not a hook — is what enforces the bar before a push. | +| Runtime hooks (the 2.x hook bundle) | Hookless skills + the `ao` CLI + repository-selected deterministic checks | Hooks were deleted (ADR-0002) after an A/B showed the injected-context delta was zero. A consumer repository may choose its own small hook or external CI; AgentOps does not require either. | | `agentopsd` daemon (`ao daemon`) · `ao schedule` · `ao plans` · `ao watch` · `ao overnight` · `ao cron` | An external substrate you choose: **NTM** (a local tmux swarm) + `ao mcp serve` (MCP tool surface) + `ao agent` (managed agents) | AgentOps ships no always-on runtime (ADR-0009 — "delete, not deprecate"). Out-of-session scheduling belongs to whatever substrate you run. `ao plans` and `ao watch` drove the daemon's cron lane and are gone with it — no build tag restores any of these verbs. The `ao cron` shim was removed at `b242136ac` under ADR-0012. | | `ao rpi` · `ao evolve` command surface | The in-session operating loop + the `/rpi` skill (one turn over the loop) | `ao rpi` was deleted outright at `f61c5f0e7` (3.2); `ao evolve` earlier (#724). No build tag brings the verbs back — what `AGENTOPS_LEGACY=1 make build` restores is the archived RPI/factory machinery in the next row (`ao loop`, `ao orchestrate`, `ao operator`, …), not these verbs. | | `ao recall` · `ao memory ingest-claude` | `cass` (search your past agent sessions) + `cm` (procedural memory) | Removed at `9d5be0b9e` (3.2). AgentOps consumes these tools instead of shipping its own memory store. Session-log → provenance mining stays native (ADR-0010); only recall/memory moved out. | -| Corpus / flywheel commands (`corpus`, `curate`, `defrag`, `harvest`, `mind`, `refinery`) | `make build-flywheel` to restore them; consume knowledge via `cass` + `cm` | Archived behind `//go:build flywheel` (ADR-0012), not deleted — the code stays buildable because its revival conditions require it. A default (`spine`) build simply omits them. | -| RPI / factory commands (`autodev`, `codex`, `loop*`, `orchestrate*`, `operator*`, `tick`, `turn_verify`, `harness`) | The operating loop + an external substrate; restore the old commands with `AGENTOPS_LEGACY=1 make build` | Archived behind `//go:build legacy` (ADR-0012). Same reasoning as the flywheel set: focus the default surface, keep the satellites buildable. | +| Corpus / flywheel commands (`corpus`, `curate`, `defrag`, `harvest`, `mind`, `refinery`) | The retained `corpus` surface plus `cass` + `cm` | The current tagged profile is transitional and is deleted by the profile-cut leaf after each command receives an exact keep/merge/delete disposition. Do not add new consumers to it. | +| RPI / factory commands (`autodev`, `codex`, `loop*`, `orchestrate*`, `operator*`, `tick`, `turn_verify`, `harness`) | The operating loop + an external substrate | The current tagged profile is transitional and is deleted by the profile-cut leaf. No compatibility profile is part of the final product. | | `ao factory` | The factory *is* the loop — `crank`/`swarm` in-session, or substrate-driven dispatch (NTM / managed-agents) out-of-session | Deleted outright with its contract corpus (see [MIGRATION-3.0.md](MIGRATION-3.0.md)); it is **not** part of the legacy build-tag set above — no build tag brings it back. | | In-repo Gas City substrate (`runtime=gc`, `city.toml`, `packs/agentops`) | The external Gas City project, if you want a managed workspace | The in-repo bridge was pruned (`ag-124p`, #679); ADR-0009 re-narrated the substrate to NTM + MCP + managed-agents. `runtime=gc` is no longer a selectable mode. An AgentOps pack for Gas City is planned, not shipped (see below). | -| PR-per-change flow | **push-to-main** + the local pre-push gate | Retired `ag-qidx` (2026-06-07). Branch protection is off; run the gate locally (`ao gate check --fast --scope head`) and push the coherent arc straight to `main`. `validate.yml` is a tag/PR/manual backstop, not routine authority. | +| One prescribed Git flow | The repository's own delivery policy | Direct push, PRs, hosted CI, and dedicated mergers are equivalent delivery adapters to AgentOps. All consume the same candidate, deterministic evidence, fresh-context verdict, and Learn receipt. | | `acfs` skill | The individual wrapper skills — `ntm`, `cass`, `beads-br`, `beads-bv`, `agent-mail`, `dcg` — plus the upstream ACFS installer directly | The umbrella skill was cut 2026-07-02 at `aae1a3af9` (skill catalog 70→63). The wrappers cover each tool; the installer bundles the whole stack (see next section). | -| Mount Olympus daemon | Parked — the in-repo pawl gate is the gate | Olympus was a high-assurance multi-tenant take that was parked, not shipped. The routine release authority is the local cockpit / pawl gate in this repo. | +| Mount Olympus daemon | External orchestration, only when selected by the operator | Olympus was a high-assurance multi-tenant take that was parked, not shipped. It has no authority in the AgentOps validation or delivery loop. | ## The stack we recommend (and use ourselves) diff --git a/docs/UPGRADING.md b/docs/UPGRADING.md index 98bb65ac0..6b8e53199 100644 --- a/docs/UPGRADING.md +++ b/docs/UPGRADING.md @@ -23,9 +23,31 @@ The "Action required" callout distinguishes hard breakages (must fix before runn --- +## Direct-cut transition + +AgentOps now has four lifecycle umbrellas: Discovery, Crank, Validate, and +Learn. Premortem belongs to Discovery; Postmortem is optional after Learn. A +candidate receives one immutable verdict from fresh context, then the consumer +repository decides how local or cloud delivery works. + +The `flywheel` and `legacy` build profiles described in older sections are +transitional executable state. Do not add new dependencies on them. The final +profile cut removes old owners directly after their retained behavior has an +explicit disposition; no compatibility profile remains. + +**Action required:** remove automation that expects AgentOps to merge, push, +queue, or run semantic review from a Git hook. Retain your repository's own CI +or delivery policy and consume AgentOps candidate, verdict, Learn, and delivery +receipts as evidence. + +--- + ## Upgrading to 3.2.x -3.2 continues the 3.0 narrowing: the last CLI-orchestration verbs are removed, and the corpus/factory satellites move behind build tags so the default surface stays small. The satellites are **archived, not deleted** — each restore command below rebuilds them. +3.2 introduced build-tag profiles while removing the last CLI-orchestration +verbs. That profile decision is superseded by the direct-cut transition above; +the restore commands below document executable history and do not promise +retention. ### `ao rpi` / `ao evolve` command surface removed @@ -81,7 +103,9 @@ full map: [MIGRATION.md](MIGRATION.md) Every runtime hook was deleted (ADR-0002) after an A/B showed the injected-context delta was zero. -**Action required:** rely on hookless skills + the `ao` CLI, and install the local pre-push gate (`scripts/install-pre-push-gate.sh`) — the gate, not a hook, enforces the bar before a push. `--with-hooks` remains as an opt-in for anyone who still wants them. +**Action required:** rely on hookless skills + the `ao` CLI. Configure any +deterministic hook, PR check, or external CI in the consumer repository; it is +delivery policy, not AgentOps validation. ### `agentopsd` daemon, `ao schedule`, and `ao overnight` deleted @@ -216,8 +240,8 @@ See [`CHANGELOG.md`](CHANGELOG.md) directly. No hard breakages were introduced i ao --version ao doctor -# Re-run any local gates touched by the upgrade -scripts/pre-push-gate.sh --fast +# Run deterministic checks selected by the repository +ao gate check --fast --scope head ``` If `ao doctor` reports drift between installed skills and your repo copy, re-run the install script from [Getting Started](getting-started/index.md#install). diff --git a/docs/adr/ADR-0012-focus-surface-on-membrane-bookkeeper-archive-satellites.md b/docs/adr/ADR-0012-focus-surface-on-membrane-bookkeeper-archive-satellites.md index ae66251f4..a94ce33a9 100644 --- a/docs/adr/ADR-0012-focus-surface-on-membrane-bookkeeper-archive-satellites.md +++ b/docs/adr/ADR-0012-focus-surface-on-membrane-bookkeeper-archive-satellites.md @@ -1,98 +1,61 @@ -# ADR-0012: Focus the Surface on Membrane + Bookkeeper; Archive the Unproven Satellites Behind Build Tags +# ADR-0012: Directly Cut the Unproven Satellite Surface -- **Status:** Accepted (2026-06-30) -- **Author:** AgentOps maintainers -- **Builds on:** [ADR-0004](ADR-0004-corpus-moat-unproven-position-on-the-system.md) (corpus moat unproven), [ADR-0009](ADR-0009-daemon-deletion-in-session-only.md) (daemon deleted, in-session only), [ADR-0011](ADR-0011-escape-corpus-compounding-unproven-structural-starvation.md) (escape-corpus compounding unproven, structural starvation) -- **Tracking:** epic `age-focus-membrane-bookkeeper-m1wg` (this epic); source: a 4-agent `/idea-wizard` spike, notes in `.agents/research/2026-06-30-agentops-repo-overview.md` +- **Status:** Superseded by direct-cut execution (2026-07-14) +- **Original decision:** Archive optional command families behind build tags +- **Current decision:** Retain, merge, or delete every command through one exact + owner; remove the profile mechanism after the last disposition ## Context -The repo's own evals demote the headline story. [ADR-0004](ADR-0004-corpus-moat-unproven-position-on-the-system.md) -demoted the *knowledge corpus / flywheel* moat to **unproven** (a frontier model already -applies the doctrine unaided, so the corpus shows no marginal uplift at that altitude). -[ADR-0011](ADR-0011-escape-corpus-compounding-unproven-structural-starvation.md) demoted -the *escape-corpus compounds* claim to an **unproven hypothesis facing a structural -data-starvation headwind** (a competent membrane catches at review, so it self-starves -its own escape supply — self-improvement is anti-correlated with membrane quality). +The earlier decision reduced the default command surface by putting corpus and +factory families behind `flywheel` and `legacy` build tags. That made the +headline smaller without reducing the maintained system. It left multiple +compiled products, compatibility tests, generated projections, restoration +instructions, and old owners alive. The result was more surface to reason about +and a standing invitation to preserve behavior that the product no longer owns. -Two things, by contrast, are **proven**: - -1. **The validation membrane** — independent, fresh-context, cross-family (or - deterministic) verification: **no verdict = not done**. Measured: 0 escapes across 130 - real production verdicts; a stronger weak-producer's subtle compiling bugs still caught - 3/3. This is the product. -2. **The bookkeeper** — durable beads + a hash-chained, append-only, tamper-evident - provenance ledger that survives sessions and models. Grep-able, verifiable, and the - substrate every verdict is bound into. - -Yet today the **unproven** story is headlined (GitHub description leads with "memory … -feedback loops that compound"; `hash-chained` / `provenance ledger` appear zero times in -the README) and the **proven** bookkeeper is invisible. The maintained surface has also -sprawled — ~91 `ao` subcommands and ~75 skills — much of it serving the unproven corpus/ -flywheel/RPI/factory machinery rather than the two-core spine (~22 commands, ~15 skills). +AgentOps now has a narrower responsibility: Discovery shapes accepted behavior, +Crank implements a bounded tranche, Validate records one immutable verdict from +fresh context, and Learn records the smallest useful consequence. Deterministic +evidence supports that judgment. Delivery belongs to the consumer repository, +whether the worker is local or cloud-hosted. ## Decision -1. **Re-headline on the two proven cores.** Public surfaces (GitHub description/topics, - README, `docs/3.0.md` lede, PRODUCT.md positioning) lead with *independent verification - that records a verdict* and *the durable, hash-chained bookkeeper*. The corpus / - flywheel / escape-corpus claims are stated as named-unproven hypotheses, never as the - differentiator. A canonical "Proven / Still-measuring" honesty block is the single - source other surfaces point to. +Delete legacy code directly in the same owning leaf that installs its replacement or removes its last consumer. -2. **ARCHIVE the satellites behind build tags — never delete.** The corpus/flywheel - commands + packages move behind a `//go:build flywheel` tag; the RPI/factory commands - behind a `legacy` tag. The default `go build ./...` (and the shipped `ao`) omit them; - `make build-flywheel` and the legacy flag restore them. The code stays **buildable and - revivable** because the revival conditions below require it. +Each current command receives exactly one disposition: -3. **Shrink the maintained spine, don't destroy the optionality.** Skills collapse toward - a ~15-skill spine; non-spine skills are demoted to an experimental tier (and dropped - from Codex-twin regeneration — the ~70% regen cut), not deleted. The skill source files - remain in the tree. +- **keep** under one final root and explicit module owner; +- **merge** into a named final root while deleting the former root and owner; +- **replace** with the final behavior while deleting the old owner; or +- **delete** with its unique tests, fixtures, docs, and dependencies. -4. **The only sanctioned delete is genuinely dead code.** `ao cron` is a dead compat shim - (the daemon was already deleted in [ADR-0009](ADR-0009-daemon-deletion-in-session-only.md)); - it may be deleted outright. Everything tied to a revival condition is archived, not - removed. +No compatibility alias, alternate runtime, dormant scaffold, restoration path, +or dual owner lands between those states. An exact authority-and-consumer +manifest must prove the old and new paths belong to the same leaf before that +leaf starts. -## Why archive instead of delete (the revival conditions need the code) +## Sequencing -Each demoting ADR left an explicit door open. Deleting the satellites would weld those -doors shut, so the code must stay buildable: +This ADR changes product authority, not executable code. Later master-plan +leaves own the physical cut: -- **[ADR-0004](ADR-0004-corpus-moat-unproven-position-on-the-system.md) — corpus moat.** - Re-opens if the corpus shows measurable marginal uplift at a *weaker base-model altitude* - or on harder multi-task work than the frontier-single-task ceiling tested. Proving that - needs the corpus/forge machinery runnable. -- **[ADR-0011](ADR-0011-escape-corpus-compounding-unproven-structural-starvation.md) — - escape-corpus compounding.** Re-opens if **real production escapes accrue** over time, or - if a **deployed cheap tier with genuine blindspots** makes strong-tier catch-fuel show - demonstrable transfer value. The capture/derive path must remain wired to receive that - input. -- **[ADR-0009](ADR-0009-daemon-deletion-in-session-only.md) — out-of-session orchestration.** - The substrate is swappable and opt-in; the RPI/factory lane is load-bearing legacy that a - future substrate experiment may want to drive. Keep it behind the `legacy` tag, buildable. - -Archiving preserves every revival path at near-zero maintenance cost (the tagged code is -not compiled, regenerated, or gated by default) while removing it from the headline and the -day-to-day maintained surface. - -## Spine target - -- **Commands:** ~91 `ao` subcommands → **~22-command spine** (membrane/pawl, beads/bookkeeper, - provenance ledger, gate, session, eval, the core authoring loop). Corpus/flywheel behind - `flywheel`; RPI/factory behind `legacy`. -- **Skills:** ~75 → **~15-skill spine**; the rest demoted to experimental and dropped from - twin regeneration. +- K5, K7, and K9 remove model-driving review, repository delivery, and retired + gate implementations while installing deterministic recorders where needed; +- each exact `CLI.` leaf keeps, merges, replaces, or deletes one compiled + command root; +- F4 removes the `flywheel`, `legacy`, and combined build profiles plus their + dedicated compatibility tests; +- D2 regenerates command and skill projections only after executable ownership + is final. ## Consequences -- The **proven** claim is unchanged and now load-bearing on the front door: independent - cross-family / deterministic verification, **no verdict = not done**, plus a durable - hash-chained record. Positioning rests on the verification/control system that is proven, - not on a self-improvement flywheel the data has not shown accruing. -- No proven capability is removed. The membrane and the bookkeeper keep their full surface. -- The archived satellites are revivable in one build flag; nothing is foreclosed. -- Maintenance load drops (fewer default-compiled commands, fewer regenerated twins, a - smaller validated skill set) without deleting optionality. +- There is one final compiled product rather than hidden optional products. +- The four lifecycle umbrellas remain agent-owned; the CLI is a deterministic + transaction kernel and evidence recorder. +- Historical commits and changelog entries remain history, but no active source + promises restoration. +- Rollback reverts a complete same-owner leaf. It never restores only an old + command owner or only a compatibility route. diff --git a/docs/agent-workflow-reference.md b/docs/agent-workflow-reference.md index b0cb6ef9e..04a30a078 100644 --- a/docs/agent-workflow-reference.md +++ b/docs/agent-workflow-reference.md @@ -1,8 +1,8 @@ # Agent Workflow Reference -> Repository-specific mechanics for the canonical +> Repository-specific evidence mechanics for the canonical > [Operating Loop](architecture/operating-loop.md). Read this only for bead, -> worktree, candidate, delivery, provenance, or closeout operations. The compact +> worktree, candidate, delivery record, provenance, or closeout operations. The compact > [`AGENTS.md`](../AGENTS.md) defines the legal transitions; this file explains > how this repository performs them. @@ -124,16 +124,14 @@ orchestrator decides whether that invalidates the candidate before delivery. ## Deliver through the repository adapter -For AgentOps itself, the terminal delivery command is: - -```bash -ao land -``` - -Delivery must consume the same candidate, PASS verdict, and terminal Learn -receipt. It may check remote divergence, proof freshness, mapping/overlap, local -policy, and push outcome; it must not recreate semantic validation or rerun an -unchanged full deterministic suite merely because delivery began. +Delivery must consume the same candidate, PASS verdict, and Learn receipt. The +repository—not AgentOps—selects the adapter: direct push, pull request, hosted +CI, a dedicated merger, or a cloud-agent callback are all valid. AgentOps may +record the selected adapter, target ref, and resulting identity, but it does not +perform or authorize the Git mutation. Delivery may check remote divergence, +proof freshness, mapping/overlap, and repository policy; it must not recreate +semantic validation or rerun an unchanged full deterministic suite merely +because delivery began. If `origin/main` moved, compare the candidate's owned blobs/deletions and declared dependencies with the new base. Byte-identical owned semantics plus green @@ -141,8 +139,9 @@ overlap/mapping evidence may reuse the verdict. A changed owned blob, acceptance claim, proof dependency, or ambiguous overlap invalidates the affected proof and returns to the earliest invalidated move. -Do not close the bead because a local merge or push command exited zero. Verify -the exact remote identity: +Do not close the bead because a repository merge or push command exited zero. +The repository adapter verifies the exact remote identity and supplies that +evidence to the report: ```bash git ls-remote origin refs/heads/main diff --git a/docs/architecture/build-tags.md b/docs/architecture/build-tags.md index 660b380b8..dadcfde1e 100644 --- a/docs/architecture/build-tags.md +++ b/docs/architecture/build-tags.md @@ -1,64 +1,49 @@ -# Build tags: archiving the satellites (ADR-0012) +# Build Tags During the Direct Cut -> How AgentOps keeps the unproven corpus/flywheel and RPI/factory satellites -> **buildable but omitted by default**. Decision: [ADR-0012](../adr/ADR-0012-focus-surface-on-membrane-bookkeeper-archive-satellites.md). -> The satellites are **archived, not deleted**, because the ADR-0004/0009/0011 -> revival conditions require the code to stay compilable. +> Current executable truth and deletion ownership for the transitional command +> profiles introduced by [ADR-0012](../adr/ADR-0012-focus-surface-on-membrane-bookkeeper-archive-satellites.md). -## The two tags +## Current state -| Tag | Archives | Bead | -|-----|----------|------| -| `flywheel` | corpus/flywheel commands + packages (forge, compile, wiki, harvest, mine, pool, maturity, refinery, flywheel, dedup, defrag, curate, ratchet, …) | `…m1wg.13` | -| `legacy` | RPI/factory commands (orchestrate, codex lifecycle, tick, autodev, evolve, loop, turn, harness, operator) | `…m1wg.14` | +The current tree still compiles `flywheel`, `legacy`, and combined variants. +That fact is transitional, not a product contract. New code must not add a tag, +profile membership, restoration command, tagged fallback, or profile-specific +behavior. -The **default** `go build ./...` (and the shipped `ao`) compile **neither**. They are the spine. - -## How to build each variant +Until F4 executes, the existing diagnostic commands remain useful for proving +the inventory that must disappear: ```bash -make build # spine — archived sets omitted (default) -make build-flywheel # restore BOTH (-tags "flywheel legacy") -AGENTOPS_LEGACY=1 make build # restore the legacy (RPI/factory) set only -cd cli && go build -tags flywheel ./... # flywheel only -cd cli && go build -tags "flywheel legacy" ./... # both +make verify-buildtags +AO_DUMP_REGISTERED_CMDS=1 go -C cli test -tags=flywheel,legacy \ + ./cmd/ao -run '^TestDumpRegisteredTopLevelCommands$' -count=1 -v ``` -Introspect a binary: `ao buildtags` prints `spine` (default) or the tags it was built with. +These commands describe the old tree; they do not authorize consumers to depend +on it. -## How to archive a command behind a tag +## Cut ownership -Build tags are **file-level** in Go. To archive a command: +The exact CLI disposition manifest assigns every currently compiled top-level +root to one leaf. That leaf retains behavior under a final owner or deletes it +with its unique tests, docs, fixtures, and dependencies. K5, K7, and K9 own the +four roots coupled to verdict, delivery, and retired gate behavior. Other roots +belong to their exact `CLI.` leaves. -1. Put the command's definition + its `init()` registration (the `rootCmd.AddCommand(...)` - call) in a file carrying the tag constraint as the **first line**, followed by a blank line: +After those leaves finish, F4 deletes: - ```go - //go:build flywheel +- the `flywheel`, `legacy`, and combined profile constants; +- build-tag-only command owners and tagged fallbacks; +- profile selection and default-root pruning; +- build-profile scripts, fixtures, and compatibility tests; and +- documentation that teaches restoration. - package main - // … the cobra command var + func init(){ rootCmd.AddCommand(fooCmd) } … - ``` +D2 then regenerates the command reference and other declared projections once +from the single final executable source. - With the tag absent, the file is not compiled, so the command is neither built - nor registered — it simply isn't in the spine binary. +## Admission rule -2. **Self-containment is the rule.** Any symbol the archived command references - (helper funcs, vars, packages) must also be tag-gated, or the spine build - breaks with "undefined". Move shared helpers that the spine still needs into an - untagged file; move helpers only the archived command uses into the tagged file. - If a spine file references an archived symbol, provide a `//go:build !flywheel` - stub. - -3. Whole packages (e.g. `internal/wiki`, `internal/pool`, `internal/ratchet`) are - archived by tagging every file in the package, or by ensuring the only importers - are themselves tag-gated. - -4. Retag the disposition ledger and regenerate: `make regen-all`, then `make regen-check`. - -## Verifying the mechanism - -`make verify-buildtags` (→ `scripts/verify-buildtags.sh`) compiles the spine, -`flywheel`, `legacy`, and combined variants and asserts `ao buildtags` reports -each correctly. The default build must omit the tagged sets; the tags must restore -them. The `cmd/ao/buildtags*.go` files are the mechanism's anchor and self-test. +A command-cut leaf is not ready until its checked authority-and-consumer +manifest is complete and disjoint. The old owner and its replacement or last +consumer must share one writer, one candidate, one acceptance check, and one +rollback. No intermediate dual runtime is admitted. diff --git a/docs/architecture/go-cli-architecture-guide.md b/docs/architecture/go-cli-architecture-guide.md index d601afac4..fd2c21e50 100644 --- a/docs/architecture/go-cli-architecture-guide.md +++ b/docs/architecture/go-cli-architecture-guide.md @@ -3,7 +3,7 @@ **Audience:** Developers who have completed Go 101 and want to reason about the code, not merely invoke it. **Validated:** 2026-07-12 against `goal/go-cli-clean-architecture-repair` at `a07bc8f44675e74fad2b0703c66cd370baf26354`. -> **Current status:** The CLI is in a compatibility-first strangler migration. Ten command families are sealed as migrated, `goals` remains migrating, and the tested `cliapp.BuildRoot` target does not yet construct the production root. Revalidate the current-status and debt sections when either cutover lands. +> **Current status:** The CLI is executing an exact direct cut. The production root still uses global registration and profile pruning, while each current root now has one keep/merge/replace/delete owner. No new compatibility route or dormant owner is admitted. Related references: [Codebase Overview](codebase-overview.md) · [Go CLI Production-Readiness Audit](../audits/2026-07-12-go-cli-production-readiness.md) · [Ports and Adapters](ports-and-adapters.md) · [Operating Loop](operating-loop.md) · [Generated CLI Reference](https://github.com/boshu2/agentops/blob/main/cli/docs/COMMANDS.md) @@ -15,12 +15,12 @@ You should be able to: 2. Explain the difference between Cobra presentation, application policy, a port, and an adapter. 3. Read a command module and identify what belongs there and what does not. 4. Understand the Go idioms used for dependency injection, errors, contexts, I/O, interfaces, and deterministic behavior. -5. Distinguish the intended clean architecture from the still-live strangler scaffolding. +5. Distinguish the intended clean architecture from the transitional owners scheduled for direct deletion. 6. Add or review a command without copying transitional mistakes. ## 1. The Honest One-Paragraph Mental Model -`ao` is one Go executable built around Cobra. Today, the live executable is still assembled in the large `package main` under `cli/cmd/ao`: many files register commands through `init()`, a root pre-run negotiates global behavior, and build profiles prune the assembled tree. The refactor is strangling that shape one top-level command family at a time. A migrated family has an explicit module under `cli/internal/commands/`, application policy in an internal package, concrete effects under `cli/internal/adapters`, a tiny composition owner in `cmd/ao`, an explicit machine contract, and compatibility tests that prove the public CLI did not change. Eleven families have modules; `gate` is fully cut over; `goals` is currently a dormant replacement being built beside one live legacy owner. +`ao` is one Go executable built around Cobra. Today, the live executable is still assembled in the large `package main` under `cli/cmd/ao`: many files register commands through `init()`, a root pre-run negotiates global behavior, and build profiles prune the assembled tree. Some explicit modules, application services, adapters, and machine contracts already exist, but dormant replacements and compatibility fixtures are transitional debt rather than the migration strategy. The direct-cut program assigns every current root one keep/merge/replace/delete owner, then removes the old owner and unique consumers in that same candidate. That paragraph contains two architectures: @@ -58,7 +58,7 @@ cli/ │ ├── root.go live root, global flags, pre-run, exit mapping │ ├── *_module.go composition for some migrated families │ ├── *_composition.go composition for other migrated families -│ └── hundreds of legacy command files still being strangled +│ └── legacy command files assigned to exact direct-cut owners ├── internal/ │ ├── cliapp/ target profile/module/root assembly contract │ ├── clicontract/ explicit machine-readable command metadata @@ -155,7 +155,15 @@ type Module interface { At this commit, production has **no non-test call** to `cliapp.BuildRoot` or `ParseProfile`. The target assembly contract is proven by unit tests but is not yet the executable bootstrap. -That is the clearest example of strangler scaffolding versus live cutover. +That is the clearest gap between the tested target and live production. The +cutover leaf must install explicit composition and delete the global/pruning +owner atomically. + +Deletion work is intentionally outside this authority-doc tranche: + +- CLI implementation deletion is owned by K5, K7, K9, and the exact CLI leaves. +- Build-profile deletion is owned by F4. +- Generated command-reference deletion or regeneration is owned by D2. ## 6. The Target Command Pipeline @@ -263,14 +271,15 @@ The replacement module already owns: `TestGoalsCompositionBuildsDormantExecutableModule` executes the replacement's `validate` command and proves root ownership remains exactly one (`goals_composition_test.go:10`). -This is the strangler pattern: +This dormant replacement is transitional debt, not the final migration pattern. +The direct-cut leaf must instead own the full consumer surface: ```text -freeze old observable behavior - → build executable replacement off the live path - → move vertical use cases one group at a time - → test replacement and old compatibility together - → atomically register new owner and delete old owner +freeze observable behavior and all consumers + → finish the retained behavior under the final owner + → atomically register that owner and delete the old owner, dormant copies, + compatibility fixtures, and unique dependencies + → prove the final owner and old-surface absence ``` The placeholder `futureCommand` returns `use case not configured` (`commands/goals/module.go:428`). It is scaffolding, not delivered behavior. Do not register the replacement root until those placeholders are replaced. @@ -545,20 +554,21 @@ Files beginning with `//go:build flywheel`, `legacy`, `windows`, `linux`, or neg **Variance:** highly structured subsystems centralize renderers on the result type; smaller commands keep renderer functions in the command package. -### Pattern 5: Compatibility-First Strangler Slice +### Pattern 5: Same-Owner Direct Cut **Instances:** beads, capabilities, claim, close, config, council-gate, doctor, done, eval, gate, goals. **Invariant:** -1. freeze compiled behavior and owner scope; -2. build module/service/adapter slices; -3. keep exactly one live owner; -4. cut over atomically; -5. run family plus cumulative compatibility; -6. seal lineage at the accepted SHA. +1. freeze compiled behavior and the complete authority/consumer scope; +2. implement the retained behavior under its final module/service/adapter owner; +3. delete the former root, owner, tests, fixtures, and unique dependencies in + the same candidate; +4. prove one live owner and the old-root absence; +5. seal lineage at the accepted SHA. -**Variance:** small families cut over in one slice; large families use multiple vertical child slices; goals uses a dormant executable module before cutover. +**Variance:** a large family may need multiple behavioral leaves, but no leaf +lands an empty scaffold, dual runtime, alias, or restoration profile. ## 14. Testing Strategy @@ -607,7 +617,7 @@ This catches what unit tests miss: exact user-visible behavior of the built exec 5. **Dormant goals placeholders deliberately error.** They are command-shape scaffolding, not completed behavior. 6. **Some family contracts describe only the root container.** For example, `beads` declares `EffectPure` despite effectful children; do not assume top-level metadata fully represents descendants. 7. **Narrative text contains historical tracker wording.** Executable `trackerresolve` supports both `br` and `bd`; this repo itself tracks with `br`. -8. **Direct effects remain in `cmd/ao`.** The strangler is incomplete by measurement, not merely by style preference. +8. **Direct effects remain in `cmd/ao`.** The direct cut is incomplete by measurement, not merely by style preference. 9. **`capabilities` YAML behavior and help text disagree.** The command help says output is always JSON, but `ao --output yaml capabilities` takes a live YAML branch. Because `Document` fields currently carry only `json` tags, that YAML uses keys such as `schemaversion` rather than the JSON contract's `schema_version`. Treat JSON as the stable wire contract until this is deliberately reconciled. 10. **The `beads` command help is still one-sided despite a dual-tracker implementation.** The family description says it complements `bd`, while `beads dir` says it prints the live `br` ledger; the actual resolver and directory service deliberately support either `br` or `bd`. Treat `beads tracker --json` and the typed `trackerresolve` policy as authoritative over those stale help strings. 11. **The default compiled binary prunes its own hidden `buildtags` introspection command.** `buildtags.go` and its test describe a default result of `spine (...)`, but package test binaries skip `pruneToDefaultSpine`, while the real untagged binary removes `buildtags` because it is absent from `defaultSpineCommands`. A `flywheel legacy` build exposes the command and reports both tags; the default binary currently returns `unknown command`. This is a compiled-black-box coverage gap, not merely stale prose. @@ -753,7 +763,7 @@ func (m Module) checkCommand() *cobra.Command { | driven adapter | inside-out integration, such as filesystem or tracker | | contract | explicit machine declaration of command behavior | | profile | default/flywheel/legacy/combined compiled command membership | -| strangler | replace a legacy system incrementally while behavior stays live | +| direct cut | install retained behavior and delete its old owner in one candidate | | dormant module | executable replacement built and tested but not registered | | typed error | error value whose methods carry machine meaning such as exit code | | fixture | frozen test input/output representing public behavior | @@ -784,7 +794,7 @@ func (m Module) checkCommand() *cobra.Command { | gate registry/orchestrator/report | [`registry.go`](https://github.com/boshu2/agentops/blob/main/cli/internal/gates/registry.go), [`orchestrator.go`](https://github.com/boshu2/agentops/blob/main/cli/internal/gates/orchestrator.go), [`report.go`](https://github.com/boshu2/agentops/blob/main/cli/internal/gates/report.go) | | tracker selection/worktree policy | [`trackerresolve/resolve.go`](https://github.com/boshu2/agentops/blob/main/cli/internal/trackerresolve/resolve.go) | | typed close policy | [`done/service.go`](https://github.com/boshu2/agentops/blob/main/cli/internal/done/service.go), [`close/service.go`](https://github.com/boshu2/agentops/blob/main/cli/internal/close/service.go) | -| active strangler example | [`goals.go`](https://github.com/boshu2/agentops/blob/main/cli/cmd/ao/goals.go), [`commands/goals/module.go`](https://github.com/boshu2/agentops/blob/main/cli/internal/commands/goals/module.go) | +| transitional dual-owner debt | [`goals.go`](https://github.com/boshu2/agentops/blob/main/cli/cmd/ao/goals.go), [`commands/goals/module.go`](https://github.com/boshu2/agentops/blob/main/cli/internal/commands/goals/module.go) | | compatibility fixtures | [`families/`](https://github.com/boshu2/agentops/tree/main/cli/testdata/compatibility-baseline/families) | | architecture fitness | [`archcheck/checker.go`](https://github.com/boshu2/agentops/blob/main/cli/internal/archcheck/checker.go), [`check-go-cli-architecture.sh`](https://github.com/boshu2/agentops/blob/main/scripts/check-go-cli-architecture.sh) | @@ -859,8 +869,9 @@ Answer these before running anything: chatter is kept out of stdout-as-data. 7. A local `REFUTED` disposition does not confirm the close. If origin does not provide a matching confirmed verdict and the force flag is false, the service - returns `RefusalError` before calling the tracker. The message names `ao - verify`, `ao pawl review`, the trivial waiver, and the explicit escape hatch. + returns `RefusalError` before calling the tracker. This is legacy behavior + assigned to the verdict and retired-review deletion leaves; do not use it as + the design for a new command. 8. With no disposition and `CommitProvenanceOnly(...) == true`, the service uses `waived-trivial`, stamps `[verdict:abcdef0:waived-trivial]`, and closes. 9. With no confirmed/trivial route and `ForceNoVerdict == true`, it uses @@ -908,7 +919,7 @@ without reading help output: | Explain the current architecture honestly | Sections 1-6 distinguish the live global/init/prune bootstrap from the tested-but-unused `cliapp.BuildRoot` target and trace the intended command pipeline. | | Explain how commands work | Section 7 traces pure `capabilities`, effectful `gate run`, orchestrated `gate check`, and dormant `goals`; Sections 8-11 cover gate policy, contracts/profiles, tracker/worktree resolution, and config precedence. | | Explain Go idioms at a Go-101 graduate level | Section 12 covers consumer-side interfaces, constructor injection, method assertions, context, error wrapping, result/error separation, closure flags, injected I/O, receiver choice, defensive copies, sorting, build tags, and `init()`. | -| Extract repository patterns rather than invent them | Section 13 derives five patterns from at least three concrete command families each: fresh modules, service/port/adapter chains, typed exits, multi-renderers, and compatibility-first strangler slices. | +| Extract repository patterns rather than invent them | Section 13 derives five patterns from at least three concrete command families each: fresh modules, service/port/adapter chains, typed exits, multi-renderers, and same-owner direct cuts. | | Teach verification and safe change-making | Sections 14-17 explain the test pyramid, non-cargo-cult debt, a seven-question reading workflow, and the ideal post-cutover command recipe. | | Make the learner active rather than a passive user | Sections 16, 18-19, and 23 provide code-reading questions, implementation exercises, worked keys, and a complete `ao done` capstone with a stated mastery standard. | | Apply codebase archaeology | The guide is pinned to source `a07bc8f4`, traces `main` to adapters, distinguishes executable truth from narrative, compares the target base, and records compiled/runtime discrepancies rather than hiding them. | diff --git a/docs/architecture/operating-loop.md b/docs/architecture/operating-loop.md index 1c2d882c9..1466cbe3c 100644 --- a/docs/architecture/operating-loop.md +++ b/docs/architecture/operating-loop.md @@ -53,7 +53,8 @@ triggered by the work. Resolve these questions before mutation: - What exact behavior is requested, and what is explicitly outside scope? - Which bounded context and source owner control it? - What state already exists locally, in the tracker, and on the target remote? -- Which action is the next reversible move, and which later action is a pawl? +- Which action is the next reversible move, and which later action requires + explicit repository or operator authority? Acceptance is executable shared language, not a prose aspiration. Record: @@ -129,6 +130,9 @@ overlap/mapping proof is green. ## 5. Prove facts, then judge meaning once +A verdict is immutable evidence from fresh context. The author may supply facts +and claims, but cannot issue that verdict or mutate it after review. + Deterministic checks prove facts such as syntax, schema, identity, paths, drift, tests, and evidence integrity. Select the cheapest checks that cover the changed surface, run each selected fact once for an exact input, and retain its receipt. @@ -176,9 +180,9 @@ One run-level governor owns attempts, time, token/cost, and helper consumption. Phase-local retry multipliers are forbidden. Max-attempts, oscillation, or no-progress enters HOLD and receives exactly one helper consultation. `UNSTUCK` resumes with a new approach; helper `ESCALATE`, human-only judgment, or a genuinely -spent hard ceiling raises ANDON. The static pawl boundary is -[`docs/contracts/pawls.md`](../contracts/pawls.md); RPI's durable transitions are -the [pull-flow governor](../../skills/rpi/references/pull-flow-governor.md). +spent hard ceiling raises ANDON. The state table above owns disposition; RPI's +durable transitions are the +[pull-flow governor](../../skills/rpi/references/pull-flow-governor.md). ## 7. Learn, deliver, verify, and report diff --git a/docs/contracts/local-pre-push-gate-retirement.md b/docs/contracts/local-pre-push-gate-retirement.md index 51b0bd826..398e1bfca 100644 --- a/docs/contracts/local-pre-push-gate-retirement.md +++ b/docs/contracts/local-pre-push-gate-retirement.md @@ -1,128 +1,38 @@ -# Superseded Historical ADR: Local Pre-Push Gate Retirement +# Superseded Historical ADR: Local Push-Gate Experiments -> Superseded on 2026-06-08 by `ag-3l86`: GitHub Actions became a quota SPOF, -> so AgentOps returned release authority to the local cockpit gate and direct -> pushes to `main`. Keep this document as historical context for the older -> CI-only experiment, not as current workflow doctrine. If this file disagrees -> with `scripts/hooks/pre-push.local`, `scripts/install-pre-push-gate.sh`, or -> `docs/CI-CD.md`, those current-path surfaces win. +> **Status:** Superseded. This file preserves the disposition of two failed +> policies; it is not an active delivery contract. -`scripts/pre-push-gate.sh` is the local mirror of `.github/workflows/validate.yml`. -The mirror has drifted three times in observable ways during the 2026-05-19 -session alone, each costing a self-correction PR. This document is the -architecture decision to retire the local mirror and treat GitHub Actions as -the push-gate enforcement point. That decision is no longer current. +AgentOps tried both CI-only enforcement and a large local push hook. Each moved +the product into repository delivery and duplicated expensive proof. The local +variant also serialized mutable checks and model judgment at the moment Git was +trying to publish, which made ordinary delivery slow and fragile. -## Decision +## Current decision -The historical decision retired the local pre-push gate and moved authority to -GitHub Actions workflows under `.github/workflows/`. Current doctrine reverses -that: the local cockpit gate is the release authority for normal direct-main -work. +Validation stops after one exact candidate has deterministic evidence, one +immutable verdict from fresh context, and one Learn receipt. The consumer +repository owns delivery for local and cloud agents. It may use direct push, a +PR, hosted CI, or a small deterministic hook. -Historical authoritative gate in this superseded decision: +A repository delivery adapter may verify identity and reuse an exact-input +receipt. It must not: -- `.github/workflows/validate.yml` -- `.github/workflows/release.yml` -- the `claude-code-review` required check +- invoke a model or perform another semantic review; +- mutate or upgrade the Validate verdict; +- close tracker work as a side effect of Git; +- own a global delivery queue for AgentOps; or +- replay an unchanged full suite merely because delivery started. -Historical non-authoritative surfaces in this superseded decision: +## Deletion ownership -- `scripts/pre-push-gate.sh` -- the ~12 helper scripts under `scripts/check-*.sh` invoked only by the gate -- the ~40 bats files under `tests/scripts/` that test gate helpers in - isolation (the bats that test the gate itself stay until the gate is - deleted) +K7 deletes the old delivery command, queue, and semantic push-hook machinery +while installing deterministic delivery recording. Dedicated scripts, hooks, +tests, and fixtures disappear in that same candidate. F4 later removes the +build profiles that kept alternate command owners compilable. D2 regenerates +command projections after executable ownership is final. -`.githooks/pre-push` kept its `bd hooks run pre-push` invocation; that piece was -tracker plumbing, not the AgentOps cockpit gate. Current installs use -`.git/hooks/pre-push` chaining `scripts/hooks/pre-push.local`. +## Rollback -## Why this rather than the alternatives - -The bead (`soc-g2r9`) enumerated three options. They were considered together: - -| Option | Effort | Drift | Verdict | -|---|---|---|---| -| `accept-drift` | 30 min (1 ADR) | unchanged | rejected — legitimizes the cost we filed the bead to remove | -| `drop-local-gate` (this decision) | ~2-3h across PRs | impossible (no local) | **chosen** | -| `mirror-CI-via-act` | 1-2 days, +30s/push, +2GB Docker | impossible (Docker GH-Actions runtime) | rejected — heaviest, and the 30-90s CI feedback loop is acceptable | - -`drop-local-gate` is the option that removes the *category* of drift instead -of paying ongoing alignment cost. The cost we accept is a 30-90s CI feedback -loop per push instead of a 10-20s local one. The session of 2026-05-19 spent -several multi-minute self-correction PR cycles per local-gate-was-wrong event, -so the per-push cost is dominated by the per-incident cost we just removed. - -## What replaced the superseded decision - -The older CI-only experiment was reversed. Current normal `main` pushes are -gated locally by `.git/hooks/pre-push -> scripts/hooks/pre-push.local -> ao gate -check --fast -> go test ./... -race -shuffle=on -count=1 -> pawl pre-push`. -GitHub Actions are tag/PR/manual backstop telemetry. Specific past concerns and -how they map onto the old shape: - -- **Speed of feedback.** CI takes 30-90s on the fast path. Operators who - want a local sanity check can run `cd cli && make test` or `bats - tests/scripts/.bats` directly. The omnibus 38-check gate is the - thing being retired, not the per-tool feedback loops. -- **Pre-push hygiene.** The bd hooks invocation in `.githooks/pre-push` is - preserved (issue tracker plumbing, not gate enforcement). -- **AP#7 mechanical enforcement (soc-o5kq, PR #356).** Today's mechanical - check that verifies `Evidence:` PR-body claims against the gate log moves - to CI as a new validate.yml job. The standalone `scripts/verify-gate-claim.sh` - tool stays; only its pre-push wiring goes. Tracked as a follow-up bead so - AP#7 protection has at most a ~1-day gap. -- **Coverage ratchets and similar local-only signals.** Currently surfaced - via `pre-push-gate.sh`; will migrate to CI jobs that emit the same - signals on PRs. The signal stays; the surface changes. - -## What this PR does - -This PR locks in the decision without the deletion churn: - -- Adds this ADR. -- Edits `.githooks/pre-push` to skip the `scripts/pre-push-gate.sh` - invocation. The pre-push hook still runs `bd hooks run pre-push` so issue - tracking continues to work. -- Files four follow-up beads for the actual removal waves. - -After the historical PR landed, `git push` no longer ran the local gate and CI -was treated as the sole gate. That is no longer true. The current local gate is -installed by `scripts/install-pre-push-gate.sh` and sourced from -`scripts/hooks/pre-push.local`. - -## Follow-up work - -Tracked as discovered-from soc-g2r9: - -1. **Wave 1 (delete pre-push-gate.sh + helpers).** Delete `scripts/pre-push-gate.sh`, - `scripts/check-pre-push-gate-wired.sh`, and the ~11 gate-only helpers - under `scripts/check-*.sh`. Audit callers first; any helper with non-gate - callers stays. -2. **Wave 2 (retire gate-only bats).** Delete `tests/scripts/pre-push-gate*.bats` - and gate-helper bats. Keep `tests/scripts/verify-gate-claim.bats` (the - standalone tool stays). -3. **Wave 3 (migrate AP#7 to CI).** Add a `pr-evidence-claim-verify` job to - `.github/workflows/validate.yml` that calls `scripts/verify-gate-claim.sh` - against the PR body's `Evidence:` line(s). Closes the ~1-day mechanical - AP#7 gap this PR opens. -4. **Wave 4 (doctrine sweep).** Update `skills/ship-loop/SKILL.md`, the Codex - twin, and `skills/ship-loop/references/anti-patterns.md` to reflect the - new "CI is sole truth" stance and remove pre-push-gate references. - -## Reversibility - -The decision is fully reversible by reverting this PR. The orphaned files -(left in place by design) keep working; flipping `.githooks/pre-push` back -to invoking `scripts/pre-push-gate.sh` restores the previous behavior with -zero data migration. The deletion waves are individually reversible too, -but each progressively raises the revert cost — that's by design and matches -the operator's "decide before you delete" preference. - -## Acceptance - -- ADR exists at `docs/contracts/local-pre-push-gate-retirement.md` (this file). -- `.githooks/pre-push` no longer invokes `scripts/pre-push-gate.sh`. -- Four follow-up beads filed under `discovered-from: soc-g2r9`. -- Linked from `docs/documentation-index.md`. +Revert the complete K7 candidate before downstream consumers depend on its +receipt contract. Do not restore only a hook or only a removed delivery owner. diff --git a/docs/contracts/pawls.md b/docs/contracts/pawls.md index a72876f11..05d9221b1 100644 --- a/docs/contracts/pawls.md +++ b/docs/contracts/pawls.md @@ -1,282 +1,45 @@ -# Pawls — the one-way doors (the ratchet's static map) +# Retired One-Way-Door Gate Contract -> **Chaos + Filter + Ratchet = Progress** — see [brownian-ratchet.md](../brownian-ratchet.md). -> This file is the **Filter**: the irreversible actions where the ratchet's pawl sits — a short list -> of the common instances, governed by the [blast-radius rule](#the-blast-radius-rule-the-list-is-examples-not-the-boundary). -> Anything that trips no clause of the rule is chaos — cheap, wrong-tolerant, ungated. The router is -> a cheap classification (list + rule), **not** a heavyweight decision engine. +> **Status:** Retired as active authority on 2026-07-14. The path remains only +> until the checked K9 consumer-deletion leaf removes it. Do not cite this file +> as lifecycle, validation, escalation, or Git authority. -## The rule +## Why it was retired -1. About to take an action? Check it against the pawl list **and the [blast-radius rule](#the-blast-radius-rule-the-list-is-examples-not-the-boundary)** below. -2. **A pawl (on the list, OR it trips any clause of the blast-radius rule) → fire the gate**: [`/pawl-review`](../../skills/pawl-review/SKILL.md) obtains independent fresh-context lane evidence, then `ao pawl` applies diversity and binds the decision. Fail-closed (ambiguity → hold, never silent-proceed). -3. **Not a pawl (not on the list AND it trips no clause of the blast-radius rule) → chaos.** Just run it. No gate, no review, no ceremony. Iterate as wrong as you want between pawls — the pawls **reduce irreversible regression to the known one-way doors**, so between them you only ever touch state you can recover. (The list is the common instances; the **rule** is the authority — if an action trips a clause but isn't listed, it is still a pawl, and it's a missing list entry to add.) +The old contract began as a short reminder to obtain fresh review before an +irreversible action. It grew into a second lifecycle with separate verdict +schemas, model routing, retries, queue admission, push enforcement, and tracker +closure. That duplicated Discovery, Validate, the run governor, and repository +delivery. It also placed expensive semantic work at Git time, where upstream +movement forced repeated proof and stalled flow. -Why so few pawls: a pawl on *every* step is waterfall (validate every tread). It makes every wrong turn expensive and kills the cheap iteration that makes agents productive. The ratchet works **because** the pawls are few and sit only at the irreversible points. Adding a pawl is adding a tread you now validate — do it only when the action is genuinely one-way. +## Current authority -## The pawls (the one-way doors) +The [Operating Loop](../architecture/operating-loop.md) owns the complete state +model: -| Pawl | What it is | Why irreversible | Already guarded by | -|---|---|---|---| -| **mutate shared trunk** | Push/merge into the **shared** trunk (not a local merge); close a bead as accepted; **or rewrite a shared ref** | Shared ground-truth propagates to every consumer | pre-push gate · `/pawl-review` lane evidence · `ao pawl` CONFIRMED verdict bound to current head | -| **delete** | Destroying data/code/state: `rm -rf`, `git reset --hard`, `DROP DATABASE`, `kubectl delete`, `terraform destroy` | The thing is gone; no undo | [`dcg`](../../skills/dcg/SKILL.md) (destructive-command guard) | -| **external-send / shared-state mutation** | Anything that affects state outside your local sandbox: publish, post, deploy, email, a PR/issue to a forge, a side-effectful API call, sending to a person, **or writing to a shared/prod store** (a shared DB, a deployed service's state) | Caching / indexing / people / downstream consumers make it un-retractable even if later "deleted" | *(this list is the trigger)* | -| **schema / contract change** | Changing an interface, schema, or contract other code/agents depend on; regenerating a factory surface; repointing a contract test or canary | Downstream consumers break silently — "looks fine here" ≠ fine for them | [`scope`](../../skills/scope/SKILL.md) (frozen dirs) · contract-canary gates | -| **credential / authority change** | Granting access, rotating or overwriting a credential, changing permissions or who-can-do-what | A granted/leaked credential or authority can't be cleanly un-granted; trust changes propagate | [`dcg`](../../skills/dcg/SKILL.md) · `claude-acct` fail-closed verify | -| **spend** | Actions that cost real money or burn quota at scale: paid API runs, large agent fan-outs, deploys that bill | Money/quota is spent; you can't un-spend it | *(partial: fan-out consent)* | -| **plan-pawl** *(`multi-model`)* | Committing a **fanout-class / irreversible discovery plan** — an architecture fork, a one-way-door decision, a contract/coordination change — *before* the fan-out builds on it | Once N agents (or one expensive wave) build on the wrong plan SHAPE, the direction is costly-to-impossible to reverse; the plan is the architecture, and the architecture is the one-way door | the SAME enforcement as every pawl — the [`multi-model` diversity mode](#diversity-mode-per-pawl-fresh-context-by-default) (fresh-context floor **plus** ≥2 families) + [REFUTED→auto-redo loop + circuit-breaker](#escalation-the-circuit-breaker-model) **verbatim**, written through `schemas/pawl-verdict.v1.schema.json`. Invoked by the [`discovery`](../../skills/discovery/SKILL.md) skill's plan-pawl **duel** over the plan artifact (the consumer-side wiring is delivered by epic `age-plan-pawl-9yib`) | +- Discovery shapes acceptance and consumes Premortem when plan risk warrants it; +- Crank implements one bounded tranche and freezes one candidate; +- Validate records one immutable PASS or FAIL from author-distinct fresh + context, backed by deterministic evidence; +- Learn records one minimal consequence; +- the orchestrator classifies NOTE, REPAIR, REPLAN, HOLD, or ANDON; and +- the consumer repository owns delivery for local and cloud agents. -> **Scope note (plan-pawl).** The plan-pawl gates the plan's **SHAPE**, never behavior — it is the -> [`multi-model`](#diversity-mode-per-pawl-fresh-context-by-default) mode applied to the discovery -> *plan artifact* instead of a code diff (recombination + naming, not a new engine). It **never** -> replaces the acceptance-test layer: a clean cross-family plan review still misses defects only a -> running test catches (the 2026-06-12 auth-bypass learning). It is **risk-class-gated** — ON for -> fanout/irreversible discovery, OFF for cheap reversible MVP vertical slices (gating those is the -> waterfall this file forbids). By design it **subsumes** the discovery skill's two redundant -> cross-family-review gates (the single-judge fanout approval + the pre-mortem council) into one gate -> — that consumer-side fusion is wired into the discovery skill by epic `age-plan-pawl-9yib` (this -> contract row defines the pawl + its governance; it does not itself edit the discovery skill). The escalation governor (auto-redo on REFUTED; -> a tripped breaker takes one bounded helper pass; human only past the helper or on the -> classes that skip it) is the [circuit-breaker model](#escalation-the-circuit-breaker-model) above, unchanged. +Ordinary check failures and REFUTED work are REPAIR or REPLAN. A no-progress or +oscillation breaker enters HOLD and receives one bounded fresh-context helper. +Only helper ESCALATE, human-only judgment, or a genuinely spent hard ceiling +becomes ANDON. Retry count alone is not an operator escalation. -## The blast-radius rule (the list is examples, not the boundary) +## Deletion ownership -The table above is the *common* one-way doors, not an exhaustive taxonomy — a -static list breaks by omission (it silently misses CI/gate edits, authz/default -changes, data migrations, alert disabling, generated-registry regen, -AGENTS/skill contract edits, and "temporary" bypasses). The boundary is a -**rule**; the list is just its frequent instances: +K9 removes this file's executable consumers, model-driving commands, schemas, +scripts, embedded assets, and dedicated tests in one exact candidate. K7 +separately removes repository-delivery and queue machinery. Until those leaves +execute, executable leftovers are transitional facts and must not be used as +new design precedent. -> **An action is a pawl if ANY clause holds:** it **mutates shared state**, it -> **changes enforcement / gate logic**, it has an **external effect** (something -> leaves the machine), or it is **hard to roll back**. Otherwise it is chaos — -> run it free. +## Historical record -When you hit an action that isn't in the table, apply the rule, not the list. If -it trips any clause, it is a missing pawl: treat it as a pawl now, and add it. - -`scripts/intake.sh` applies this rule at the front door as **advisory triage** — -CHAOS routes solo, PAWL routes to the cross-family Navi for a receipt before the -door. It is a cheap early-warning (a keyword classifier, kept deliberately -simple and fail-toward-PAWL), **not** the enforcement: the un-leakable gates are -at the doors themselves — `scripts/reconcile-pr.sh` for the merge and -[`dcg`](../../skills/dcg/SKILL.md) for destructive commands. A pawl the triage -misses is still caught at the door; it just means the Navi is summoned later than -ideal, never that a one-way door ships ungated. - -## Diversity mode — per-pawl (fresh-context by default) - -The gate's **diversity requirement is per-pawl and operator-tunable** — the same way the -circuit-breaker thresholds (max-attempts, time/cost budgets) are tunable. Each pawl has a -`mode`; the verdict records it (`schemas/pawl-verdict.v1.schema.json` → `mode`) and the merge -path enforces it (`scripts/pawl-verdict.sh check`). The **fresh-context floor is the foundation -and is enforced in EVERY mode** — `multi-model` is strictly STRONGER than `fresh-context`, not a -swap: it **adds** family-diversity **on top of** the fresh-context floor, it does not waive it. -(A 2-family verdict whose refuters both ran in the author's own context is family-diverse but -has zero context-independence — a self-approval bypass — so it is refused, age-les.) Every other -guarantee (CONFIRMED, `head_sha` == the PR's live head, real non-empty reviewer evidence, -schema-validity, terminal green CI, roster-validated families) is **mode-independent and always -enforced**. - -| Mode | Requirement | Catches | Cost | Use for | -|---|---|---|---|---| -| **`fresh-context`** *(DEFAULT)* | ≥1 refuter whose `context_id` != the verdict's `author_context_id` — a genuine fresh red-team: a **separate invocation** that did not share the author's accumulated context. **Model-agnostic** — same model in a fresh context counts. | the author's **tunnel-vision / accumulated-context errors** — the dominant failure (a worker rubber-stamps its own work *because it has the author's context*). | one extra invocation | **every pawl, by default.** Cheap; keeps the ratchet's iteration cheap. | -| **`multi-model`** *(OPT-IN)* | the fresh-context floor (above) **AND** ≥2 **distinct, roster-validated model families**, all CONFIRMED — strictly stronger, not a swap. | the above **plus** a single model's **systematic blind spots** (a whole family sharing a failure mode). | ≥2 family invocations (cross-vendor) | opt up only the **highest-irreversibility doors**. | - -**Default to `fresh-context`.** A fresh-CONTEXT reviewer is the high-value, low-cost catch: -most landing misses are the author not seeing what it was too close to, and a separate -invocation — even of the same model — surfaces them. Reserve **`multi-model`** for the doors -where a model's *systematic* blind spot would be catastrophic and irreversible: e.g. **a shared -ref rewrite** (`git push --force` / history rewrite on a pushed branch) or **a schema / contract -change** that silently breaks every downstream consumer. Routine **mutate-shared-trunk** merges -ride the cheap default. (Opting a pawl up is a one-line operator choice, like raising a breaker -threshold — set the verdict's `mode` to `multi-model` for that pawl.) - -This keeps the ratchet cheap by default while letting the operator pay for the stronger door -exactly where irreversibility earns it — the same economy as the pawl list itself (gate only -where it's worth it). - -## Evidence-quality floor — a CONFIRMED must carry substance (age-rk3r.11) - -Evidence-binding proves a review file *exists and is non-empty*. It does **not** prove the -review carried **substance**: a 155-byte "no blocking defects" stub once passed `check`. The -**evidence-quality floor** (`scripts/pawl-verdict.sh check`) raises the bar — a CONFIRMED's -evidence must carry **one of**: - -- **a file:line-shaped finding/observation** — the review cites concrete code (`path.ext:NNN`, - or a `line N` reference). A genuine review of a diff does this naturally; **real reviews pass - untouched**. This is the primary signal. -- **an explicit reviewed-scope attestation** — a *files-reviewed count* plus the file names - (e.g. `Files reviewed: 2 (scripts/pawl-verdict.sh, schemas/pawl-verdict.v1.schema.json)`). - This is the **escape for a legitimately clean review** that found nothing concrete to cite: - a review that blocks nothing must still *attest what it looked at*. - -**Plus a per-adapter genuine-run marker.** Each refuter attributable to a cold reviewer adapter -must carry that adapter's genuine-run marker in its **own** evidence — `codex` = `tokens used`, -`agy` = `VERDICT:` (mirroring the reviewer-adapter contract in `scripts/lib/codex-exec.sh` -`reviewer_adapter_marker`). A family with no cold-adapter marker defined yet (`claude`, the warm -reviewer) is skipped — advisory, never a hard fail. This distinguishes a real cross-family review -from a lazy stub or an echo. - -**It measures SUBSTANCE, not correctness.** The floor proves a real, specific review *ran over -named code* — it does **not** and **cannot** certify the verdict is *right*; a substantive review -can still be wrong. `check` prints that caveat whenever the floor runs. - -**Rollout is ADVISORY-FIRST.** Until `FLOOR_ENFORCE_AFTER` (`scripts/pawl-verdict.sh`; env override -`PAWL_FLOOR_ENFORCE_AFTER`) the floor only **measures + warns** — it never changes the -authorize/refuse decision — so the false-positive rate on real reviews is observed for one cycle -before it fail-closes. On/after the flip date a violation **HOLDs** (a CONFIRMED without substance -names the floor; a refuter without its marker names the adapter). `PAWL_FLOOR_ENFORCE=1|0` forces -enforce|advisory regardless of the date (operator kill-switch). *At flip time*, bump/remove the -date **and** update any stub-evidence behavior-lock suites (their thin fixtures deliberately carry -no substance and begin to HOLD). - -## What is NOT a pawl (chaos — run free, ungated) - -Editing a file · writing a test · running a build · a local experiment · a draft · a throwaway branch · a read-only query · an intermediate RPI slice · a mock→real swap · trying an approach and discarding it. **None of these are irreversible. Do not gate them.** Iterate cheaply; the pawl catches you at the door. - -## What "good" means — the bar a change must clear to PASS the gate - -The pawl fires at a one-way door (above) and an independent reviewer must CONFIRM. But CONFIRM -against *what bar*? The wrong answer — a maximal-adversarial *"actively REFUTE anything -plausible-but-wrong"* reviewer — has a documented **infinite false-alarm tail**: on any non-trivial -change it always finds *one more* cosmetic / theoretical / pre-existing / hallucinated nit, and since -the gate is all-must-confirm fail-closed, one nit blocks forever. That is the gate eating its own -productivity (observed 2026-06: a single landing refuted ~9× with ~2/3 of findings non-blocking). -**The gate's job is to stop a *bad merge*, not to demand a *perfect* one.** - -**"Good" = would a thoughtful senior engineer BLOCK this merge?** — never *"can I find any -imperfection?"* A finding REFUTEs the change only when it clears **all three** filters: - -1. **Introduced** — the defect is created or newly *made-reachable* by THIS diff (against its - parent). A problem true of the codebase *before* this commit is a backlog note, not a merge - blocker; adjacent hardening the change merely "could have also done" is scope-creep, not a - defect in the change. -2. **Real / verifiable** — concrete, and it survives deterministic ground truth. A finding - contradicted by a green check the reviewer can actually run (`go vet`, `go test ./pkg`, - `bash -n`, the parity/regen/audit scripts) is *wrong* — drop it. No claims about a file the - reviewer did not read. (This is the hallucination kill-switch.) -3. **Blocking** — it breaks correctness or safety (**fail-open**: writes/certifies what it should - not · **data-loss / corruption** · **wrong-object**), makes a **claimed contract** false (a - documented behavior, a commit-message promise, a public interface, or a test's stated guarantee - — *including a test that would pass even if the code were wrong*), or ships **non-working** - (does not build/parse, the relevant test fails, or it provably does not do what the change says). - -A finding that fails *any* filter is the **accepted tail** — record it as an audited NOTE, do not -block: cosmetic/style, a coverage gap on otherwise-correct code, a theoretical edge-case with no -reachable path in this diff, adjacent/out-of-scope hardening, a pre-existing condition, or a -design-disagreement with a deliberate documented choice whose worst case stays fail-closed. -**CONFIRM when the only remaining findings are tail.** - -**Fail-closed is never relaxed** (the bar is calibrated, not fail-open): ambiguity holds; a reviewer -that timed out, crashed, or couldn't read the change is *no verdict*, never a CONFIRM. And there is -**no author-selectable knob** — the calibrated bar is the mandatory default posture -([`scripts/pawl-review.sh`](../../scripts/pawl-review.sh)), so an author cannot route around it to -leniency (the anti-Goodhart property council C built). When even a calibrated reviewer can't -converge — a *different* non-blocking nit every round — that is the circuit-breaker's -**no-forward-progress** signal (below): trip the breaker — one bounded helper pass, then a -human if it survives — never loop forever. - -## Escalation — the circuit-breaker model - -The canonical run-level controller is the RPI -[persistent pull-flow governor](../../skills/rpi/references/pull-flow-governor.md). -Pawl review supplies door-specific evidence to that controller; it does not -own a second retry, budget, helper, or disposition state machine. The only run -dispositions are `NOTE`, `REPAIR`, `REPLAN`, `HOLD`, and `ANDON`. -`CONFIRMED`/`REFUTED` remain review outcomes, and `UNSTUCK`/`ESCALATE` remain -helper outcomes. They are not additional dispositions. - -**The human is NOT needed at a pawl by default.** A pawl fires the pawl gate -([`/pawl-review`](../../skills/pawl-review/SKILL.md)) **autonomously — model reviews model.** -The loop self-corrects; the human is the exception a *circuit breaker* trips into, not the checkpoint. - -The model has three layers: a **default auto-redo loop**, a set of **tunable circuit breakers** that bound it, and a **bounded helper pass** that sits between a breaker trip and the human — a stuck context consults a fresh one before it consults the operator. - -- **PASS (CONFIRMED)** → proceed through the door. No human. -- **FAIL (REFUTED) → `REPAIR` or `REPLAN` (the default path, no human).** A - REFUTED review outcome means the door remains closed. The orchestrator - classifies the complete evidence as a local repair or an invalidated plan and - requests a new admission for any further work. A plain REFUTED is never an - escalation and never a disposition of its own. -- **A CIRCUIT-BREAKER trip enters `HOLD`; its first stop is the helper, not the human.** Breaker thresholds and charges live in the persistent run governor: - 1. **max-attempts** — N re-work/re-gate cycles still REFUTED (default 3, tunable). - 2. **time budget** — wall-clock with no productive forward progress (the evolve loop's existing 60-min "no productive work" breaker; tunable). - 3. **cost / quota budget** — paid API spend or usage-quota ceiling for the loop (tunable). - 4. **oscillation / no-forward-progress** — the *same* failure repeating (the evolve oscillation quarantine: a target with 3+ improved→fail transitions; tunable threshold). Also covers reviewer deadlock — refuters contradicting and staying contradicted is a no-forward-progress signal. - 5. **explicit judgment flag** — a reviewer explicitly raises a value / irreversibility judgment that models should not make alone (an immediate, hard breaker). - - These are inputs to the same persistent RPI governor used by Crank and - Validate. Pawl review may report them; it may not extend them with private - thresholds or counters. - -- **THE HELPER PASS — one bounded consult before the operator.** Breakers 1 and 4 are *stuck states*, and breaker 2's default form — wall-clock with **no productive forward progress** — is a *stall signal*, not a spent ceiling. Stuckness is usually model-adjudicable: the context that ground to a halt is in a rut a fresh one is not in. On those trips the loop takes **exactly one helper pass** — hand the blocker statement, the evidence, and what was tried to a **fresh context, a cross-family model (`codex exec`), or a [`/council`](../../skills/council/SKILL.md) panel** — which returns **UNSTUCK** (a concrete next action; the loop resumes with it, breaker counters reset for the *new* approach) or **ESCALATE** (it confirms the blocker needs a human). The helper is an *advisor, never a second driver*: it reasons about the blocker and returns a recommendation; it does not take over the work or own the loop. Bounds, so the helper cannot become its own grinder: **one pass per distinct blocker class** — a blocker class that survives its helper pass goes to the human, never to a second pass. A budget trip takes the pass only while its governing ceiling still has room (breaker 3's spend/quota ceiling, or a breaker-2 trip that is a hard operator deadline rather than the stall detector); a *spent* ceiling skips the helper entirely (next bullet). -- **`ANDON` reaches the operator only past the helper, or on classes that skip it.** Breaker 5 (explicit judgment flag), the refusal lane (money, legal, irreversible-external), and a **spent hard ceiling** — cost/quota exhaustion or a hard time deadline with no room left — skip the helper: no model consult can own those, and a spent ceiling buys no consults. Everything else reaches `ANDON` only when its one helper pass failed to unstick it or returned the `ESCALATE` helper outcome. - -**REFUTED evidence → `REPAIR`/`REPLAN`; breaker trip → `HOLD` + one helper; operator only at `ANDON`.** When a breaker trips the action does not proceed: the merge/push remains held while the one helper pass runs. A helper `UNSTUCK` result names a new approach and returns the run to `REPAIR`; it never opens the door. A helper `ESCALATE` result becomes `ANDON`. The hold lifts only after a new admitted candidate earns `CONFIRMED`. Non-convergence never auto-lands. Door-specific exit codes and legacy pawl artifacts remain enforcement details, not a second run disposition language. - -This breaker-governed escalation is the **andon** ("Hey! Listen!") — rare and *earned*, never the default. Even fully unattended, the gate runs model-to-model at every pawl and auto-redoes on REFUTED; pulling a human in is the exception that fires only when a tunable circuit breaker trips **and the helper pass could not resolve it** (or the class skips the helper) — and until the human acts, the pawl **holds**. - -> **Scope note (threat model).** The pawl verdict (`schemas/pawl-verdict.v1.schema.json`) is an **evidence-bound, commit-bound verdict that requires real reviewer runs** — it defends against a *sloppy agent that skips the real review and self-stamps CONFIRMED*. It is **not** cryptographic provenance: there are no signatures, no peercred, no OS-level writer separation, and cryptographic un-forgeability against a hostile forger is **intentionally out of scope** (single-operator trusted loop — the cut cathedral). What the gate guarantees is that a review *actually ran* (evidence files exist + non-empty), against the *current commit* (head_sha == the PR's live head), by reviewer(s) meeting the pawl's **diversity mode** — fresh-context (≥1 fresh red-team, model-agnostic) by default, or multi-model (the fresh-context floor **plus** ≥2 roster-validated families — strictly stronger) where a pawl is opted up (see [Diversity mode](#diversity-mode-per-pawl-fresh-context-by-default)). - -## Directive precedence — autonomy never overrides a human gate - -A pawl **HOLD** (the merge held on a breaker trip, above) and a **human STOP/KILL marker** both live in the -**deterministic boundary**. An **autonomous-drive directive** — `/goal`'s "do not pause to ask" Stop-hook, `/loop`'s -"keep driving", on-the-loop / NTM unattended runs — lives in the **stochastic reasoning core**. The core cannot relax -the boundary: **no drive directive overrides a HOLD or a human STOP**, and "be autonomous" is *never* authorization to -self-approve a door a human deliberately gated. - -- The two HOLD senses are distinct: a **breaker-HOLD** holds the *merge* until a breaker clears (the [Escalation](#escalation-the-circuit-breaker-model) model above); a **human STOP marker** halts the *loop* (the evolve Red Button / [`halt-check.sh`](../../scripts/evolve/halt-check.sh) — pre-cycle, mechanical, "not prose the agent can rationalize past"). Neither is overridable by a drive directive. -- This **generalizes the evolve Red Button to the in-session path**: an explicit human-authorization gate (a typed ACK on an irreversible action) is a marker in the boundary — an active drive directive does not consume or satisfy it. A drive loop may re-enter and re-present the gate; it does not cross it. Crossing requires the marker cleared by the human, not by the directive that said "keep going". - -## Adding a pawl - -A new pawl earns its place **only** if the action is genuinely irreversible — data lost, money spent, something left the machine, or a shared contract changed. If it's recoverable, it's chaos, and it stays ungated. Keep this list short: every pawl is a tread you now validate, i.e. a step back toward waterfall. - -## Warm pawl-service — REMOVED - -The optional standing warm service (`ao pawl up` / `scripts/pawl.sh` over tmux/NTM panes) -was removed. The membrane front door is cold-only: `ao pawl review` → `pawl-review.sh` -(spawning `codex exec`) → `pawl-verdict.sh` → pre-push enforcement. See the strict -two-family cold quorum below for the portable multi-model door. - -## Strict two-family cold quorum — the portable `multi-model` door (age-rk3r.13) - -The [`multi-model`](#diversity-mode-per-pawl-fresh-context-by-default) mode above is the strongest -diversity requirement. **`ao verify --strict`** (or the `strict: true` key in `.aoverify.yaml` → -`PAWL_STRICT`) is the **cold, portable** `multi-model` door: it runs **two DISTINCT strict-eligible -cold reviewer families**, requires **both** CONFIRMED, and writes ONE `multi-model` verdict recording -**both** families + **both** evidence paths (the ledger edge's `reviewer_family` is the joined label, -e.g. `gpt+gemini`). It **DOUBLES review cost**, so it is **opt-in only, never the default** — reserve -it for the highest-irreversibility doors (a shared-ref rewrite, a schema/contract change). - -**Strict REFUSES to degrade — that refusal is the whole point.** This is the load-bearing contrast -with the failover chain ([`scripts/pawl-review.sh`](../../scripts/pawl-review.sh) — the ordinary -cold path degrades on an outage: it falls over to the next family and labels the verdict -`degraded=true`, to *keep going*). **Strict does the opposite:** a single-family answer on a strict -door is exactly what strict exists to forbid, so any family OUTAGE **HOLDs** (exit 5, non-authorizing, -no verdict) rather than falling back to one family. A REFUTED from either family is FINAL (a REFUTED is -a result, never overturned by asking the other family — the same invariant the whole gate holds). - -**Eligibility is a ONE-list seam that DRIVES the voter set — and today it is honestly `codex`-only.** -`STRICT_ELIGIBLE_FAMILIES` (override `PAWL_STRICT_ELIGIBLE_FAMILIES`) is the single list of families -measured trustworthy enough to serve a strict door. In strict mode the **voters are derived from this -list** (each entry → its adapter, excluding the author family, keeping only *reachable* distinct -families) — **not** from `PAWL_REVIEWER_CHAIN`, which is the *failover*-mode ordering, a different -selection. That is what makes the seam real: **flipping ONLY `STRICT_ELIGIBLE_FAMILIES` activates the -quorum with no other change.** The set is deliberately *narrower* than the failover chain (a family -fine as a fallback is not automatically fit to be one of two independent quorum voters on a one-way -door). Right now that set is **codex only**: per the A7 bench ruling **agy is not yet strict-eligible** -(routine + degraded-fallback only until it is graduated), and there is **no cold claude-family adapter** -(LAW 0: never `claude -p`; Fable/opus are warm-only). So there is **no second strict-eligible cold -family today**, and `--strict` **DETECTS this and prints an honest UNAVAILABLE** (naming *why* + the -non-strict alternative — `ao verify` fresh-context, or `--converge`) and exits 5. It **never fakes a -strict pass and never degrades to one family**. The full two-family machinery is built and locked; the -moment a second cold family is graduated (a real measured strict certification), **flipping that one -list** turns real strict on with no other change. - -**Honesty boundary (do not overstate).** What is shipped and claimable is the **mechanism + the honest -self-report**. **Active** strict cross-family protection — a real two-family default, or *any* claim of -active strict protection in docs/marketing — gates on a second measured strict-eligible family -graduating; **do not claim active strict protection anywhere** until then. +The original text remains recoverable from Git history. Active docs and code do +not preserve a compatibility alias or restoration promise for it. diff --git a/docs/doctrine/operating-discipline.md b/docs/doctrine/operating-discipline.md index bc05db23e..129712595 100644 --- a/docs/doctrine/operating-discipline.md +++ b/docs/doctrine/operating-discipline.md @@ -1,228 +1,123 @@ -# Operating Discipline — the rules every agent factory runs on +# Operating Discipline — Rules for an Agent Software Factory -> **What this is.** The general, substrate-neutral operating rules for running a fleet of -> AI coding agents: admission control, independent validation, close discipline, and -> multi-lane coordination. Distilled from the mt-olympus *triangulated kernel* (D1–D16, -> three independent model distillations reconciled to consensus) and **folded into AgentOps -> as the surviving factory** — because AgentOps is now the one self-contained factory and the -> operating rules should live where the work runs. -> -> **Adapted, not blind-copied.** The load-bearing gate invariants — fail-closed (exit 5 on any -> non-CONFIRMED verdict), author≠reviewer by context identity, and evidence-*presence* binding — -> are **already embodied** in the shipped ratchet pawl-gate, each cited below to the exact -> mechanism. Others are weaker than the kernel's wording: single-writer is a workflow convention -> (the script doesn't check the caller), command-citation is aspiration (the gate checks evidence -> presence, not transcript content), and the auto-redo/breaker economy is orchestrator-loop -> behavior, not gate-script code — each is labeled honestly per rule. The rules that were *about the cut cathedral* -> (an OS-account privilege floor, peercred kernel identity, a daemon, a Rust gate spec) are -> intentionally **dropped** — the ratchet pawl-gate ([`pawls.md`](../contracts/pawls.md)) -> embodies them in AgentOps terms, and re-importing the floor as live doctrine would resurrect -> the cathedral. This is a reference doc, not a cathedral. +> The detailed transition model lives in the +> [Operating Loop](../architecture/operating-loop.md). This document keeps the +> substrate-neutral engineering rules. It does not define a second gate, +> retry controller, delivery system, or tracker. -## The doctrine in one line +## Doctrine in one line -**Nothing ships on a lie while you're not looking**: nothing is real until it is admitted to -the tracker; "done" is a claim until an independent, fresh-context reviewer verifies it against -the live commit with real evidence; one writer closes; everything ambiguous fails toward a HOLD; -destructive writes reconcile or refuse — and the whole machine exists to give the operator's -attention back. +Shape one behavior, let one writer build it, prove facts for one frozen +candidate, obtain one immutable verdict from fresh context, Learn once, and let +the repository deliver it. -## How the gate embodies the load-bearing rules +## The kernel rules -The shipped ratchet is the enforcement surface. Read it as: **chaos between pawls, a fail-closed -gate at each one-way door.** +### D1 — Admission before mutation -- **The pawls** ([`docs/contracts/pawls.md`](../contracts/pawls.md)) — the short static list of - irreversible actions (mutate-shared-trunk · delete · external-send · schema/contract change · - credential change · spend). Everything *not* on the list is ungated chaos. -- **The verdict** ([`scripts/pawl-verdict.sh`](../../scripts/pawl-verdict.sh), - schema [`schemas/pawl-verdict.v1.schema.json`](../../schemas/pawl-verdict.v1.schema.json)) — an - evidence-bound, commit-bound verdict that requires a real reviewer run: `disposition` ∈ - {CONFIRMED, REFUTED, ESCALATE, HOLD}, an `author_context_id`, ≥1 refuter with a distinct - `context_id`, non-empty reviewer evidence, roster-validated families. -- **The merge path** ([`scripts/reconcile-pr.sh`](../../scripts/reconcile-pr.sh)) — green CI is - necessary but **never sufficient**: a CONFIRMED verdict tied to this bead+PR with `head_sha` == - the PR's live head must exist, or the merge is refused (`exit 5` HOLD). A new commit after review - → STALE → HOLD. Lookup failure → HOLD. Fail-closed throughout. +Tracked work starts with one accepted behavior, one owner, one exact write +scope, one rollback, and one proof boundary. A goal or epic is demand, not WIP. -## The kernel rules (D1–D16) and their disposition +### D2 — Completion is a claim -Each rule: one-line statement, then **disposition** — *embodied-in-gate* (with citation), -*doctrine* (advisory; no single mechanism yet), or *dropped-as-cathedral* (floor-specific, not -imported as live doctrine). +An agent saying “done” is input to validation. Completion requires acceptance +evidence and an author-distinct verdict bound to the exact candidate. -### D1 — Admission first -No work exists until it is admitted and persisted in the tracker. Chat can propose; it cannot -admit. "Admit first, then work" — never "do work, then file." -**Doctrine** (operating rule). Embodied operationally by the beads tracker (`br`/`bd`): a bead is -the unit of admitted work; the pawl-verdict and merge path are keyed by `bead_id`, so an -un-admitted change has nothing to close against. +### D3 — Author is not judge -### D2 — Completion is a claim, not a state -A worker's "done" is an event, not a transition; only an independent typed verdict produces a -verified close. The gate is what makes "don't watch" safe. -**Embodied-in-gate.** `reconcile-pr.sh` refuses to close on a worker's say-so — it requires a -CONFIRMED verdict from `pawl-verdict.sh check`; absent it, exit 5 (HOLD). +The context that created a candidate cannot issue its binding verdict. A fresh +same-family context is sufficient by default; a council is an optional risk +tier, not a universal lifecycle. -### D3 — Author ≠ judge, by context identity -The context that produced the work never validates it; a close needs ≥1 distinct non-author -reviewer context, blind to authorship. Self-grade exclusion is by **context identity**, not model -family (cross-family is a strengthening mode, not the floor). -**Embodied-in-gate.** `pawl-verdict.sh` default `fresh-context` mode requires ≥1 refuter whose -`context_id` != `author_context_id` (model-agnostic). `multi-model` mode (≥2 roster-validated -families) is the opt-in strengthener for the highest-irreversibility doors — exactly the -context-vs-family resolution the kernel's DISPUTED-1 settled. +### D4 — One writer per leaf -### D4 — Single writer -One decision, one binding artifact, one writer. Workers propose and never close; reviewers verify -and never close; only the orchestrator writes the close, and only on verified PASS. -**Doctrine** (workflow convention). The close is funneled through a *single* mechanism — -`reconcile-pr.sh` is the one reconcile step that merges and then closes the bead — so there is one -binding write path, not competing writers. But the script does **not** verify *who* invoked it: it -performs no caller-identity check (no author/orchestrator distinction, no `whoami`). "Only the -orchestrator runs it, and the implementer subagents never do" is an operating convention of the -ship-beads/reconcile discipline, not something the gate enforces. The gate-enforced grain is -narrower (the verdict's `author_context_id` != refuter `context_id`, checked by `pawl-verdict.sh`); -single-*writer* itself is convention. +One writer owns one active leaf. Parallel writers require disjoint checked +scopes, separate worktrees, and one integration owner. -### D5 — Evidence or it didn't happen -Every close cites a proof surface. A verdict with no cited evidence is rejected as unverified. -**Embodied-in-gate as evidence *presence*.** `pawl-verdict.sh check` requires real, **non-empty** -reviewer evidence: every per-refuter evidence path that exists must point at a non-empty file, and -there must be at least one non-empty evidence file or a non-empty `council_artifact`, or the verdict -fails closed (HOLD). What the gate enforces is that *a review actually ran and left a non-empty -surface* — it does **not** parse or prove the *content* of that evidence (it does not verify the -transcript records the specific commands run, nor that those commands match the work). Green CI is -recorded but is not the proof — the reviewer evidence is. **Doctrine** rider: "every verdict carries -the commands it ran" is the aspiration for *what belongs in* that evidence file; the gate checks -presence and non-emptiness, not command-citation. +### D5 — Evidence or it did not happen -### D6 — Fail closed -Genuine uncertainty defaults to FAIL. Ties, thin councils, missing minimums → HOLD/escalate; the -resolver never synthesizes a winner. A self-grade — the **author's own context** grading the -author's own work — never counts as a verdict. (Note: a self-grade is author≠refuter *by context*, -not a head-count. A single **fresh-context** refuter — one whose `context_id` differs from the -author's — is **not** a self-grade and is the gate's accepted floor under D3; multi-model is the -opt-in strengthener, not the minimum.) -**Embodied-in-gate.** Every non-CONFIRMED disposition (REFUTED/ESCALATE/HOLD), a STALE head, an -unresolvable head, a missing verdict, missing reviewer evidence, or a fresh-context floor that is -unmet (zero refuters with a distinct `context_id`) all exit 5 (HOLD: no merge, no close) in -`reconcile-pr.sh`. Non-convergence never auto-lands. +Deterministic checks record facts for exact inputs. Validate cites those facts +and the acceptance claims it judged. Chat confidence is not evidence. -### D7 — Identity is attested, not asserted -**Dropped-as-cathedral** (mostly). The kernel's D7 was anchored to the OS privilege floor — -kernel peercred, a separate OS account, `provision-accounts.sh`. That floor is the cut cathedral; -do **not** import it as live doctrine. The *surviving* grain: a reviewer's `context_id`/`family` -in the pawl verdict is validated against a known roster (off-roster families are rejected so -"≥2 distinct families" can't be gamed) — but the threat model is explicitly a *sloppy* agent that -self-stamps, **not** a cryptographic forger (single-operator trusted loop; see the pawls.md scope -note). No peercred, no signatures, no OS writer-separation. +### D6 — Fail closed on meaning, not ceremony + +Missing or failed required proof prevents completion. Cosmetic, pre-existing, +theoretical, and out-of-scope findings are NOTE and never block. + +### D7 — Identity is recorded + +Candidate base, commit, tree, owned blobs or deletions, commands, registries, +toolchains, environments, author, and validator identities are explicit. ### D8 — No self-greening -A gate and the thing it checks are adversaries; a pass derives from observed behavior, never a -self-declared status; tightening/loosening a gate is its own reviewed change, never bundled with -the work. -**Embodied-in-gate.** The pawl gate cannot be satisfied by the author — it requires an external -fresh-context refuter and live `head_sha` binding. **Doctrine** rider: gate changes (editing the -pawl list, the verdict schema, or `reconcile-pr.sh`) ship as their own reviewed change — never in -the same PR as work they would have caught. -### D9 — One source of truth -Every declared capability has exactly one mechanical source of truth; "done" means the mechanical -check is green, not that a doc says so. -**Embodied-in-gate** + **doctrine.** AgentOps' `make regen-check` is this rule for derived -artifacts: the registry/codex/context-map are generated, never hand-asserted, and drift fails the -gate. This doc is itself an instance: it is "done" because regen-check is green, not because this -sentence claims it. +A worker may run deterministic checks but cannot convert its own semantic claim +into PASS. Any candidate edit invalidates the prior verdict. -### D10 — Typed state transitions, not narrative persuasion -Components publish and consume contract surfaces (tracker, reservations, evidence/verdict files) -and act; a decision is real only when it appears as the required state transition. -**Embodied-in-gate.** The pawl verdict is a typed JSON artifact against -`pawl-verdict.v1.schema.json`; the merge path reads *that file*, not a chat assertion. Agent -coordination rides Agent Mail locks/reservations, not narrative. +### D9 — One source of truth per concern -### D11 — Policy is executable; roles are structure -Policy is versioned, testable, default-deny, hard-reject code that travels with the repo; roles -carry duty contracts (reviewer read-only; worker write-scoped; orchestrator coordinates and never -labors). -**Embodied-in-gate** + **doctrine.** The pawl list + verdict schema + `reconcile-pr.sh` are -executable, repo-resident admission policy. The role split (worker proposes / reviewer verifies / -orchestrator closes) is the ship-beads/reconcile discipline; the orchestrator-doesn't-labor rule -is advisory doctrine for swarm runs. +Executable behavior and generated projections outrank narrative docs. Tracker, +candidate, verdict, Learn, and delivery records each have one owner; do not +mirror them into a second mutable state machine. -### D12 — Inference mines and codifies; deterministic code reconciles forever -The steady-state control loop is deterministic and cheap; inference lives in the learning loop -(mine → codify into controllers), never inside the control loop it is meant to make reliable. -**Doctrine** — and the core AgentOps shape: the knowledge flywheel (`/curate` — retired, folded into `/post-mortem`; `ao -lookup`) is the learning loop; the deterministic gates/scripts are the control loop. Keep models -out of the reconcile path; let them propose new deterministic checks, not run inside the gate. +### D10 — Typed transitions -### D13 — Atomic lease-bounded claims; idempotent ticks; precise state words -Claiming work is an atomic lock with a visible TTL lease that expired-reaps a dead worker; every -tick reads state first and does only the next undone increment; NO_READY ≠ CONVERGED. -**Doctrine.** Operating rule for the loop/swarm substrate (beads claim + Agent Mail reservations -approximate the lease; evolve/crank ticks are read-state-first). No daemon-level lease reaper is -imported — that was floor machinery. +Use READY, ACTIVE, FROZEN, VALIDATED or REFUTED, LEARNED, DELIVERED, +REMOTE_VERIFIED, and REPORTED. Use NOTE, REPAIR, REPLAN, HOLD, and ANDON for +orchestrator decisions. Narrative labels do not create transitions. + +### D11 — Roles are structure + +Discovery shapes, Crank builds, Validate judges, Learn records consequence, and +the repository delivers. An adapter may automate mechanics but cannot inherit a +role's semantic authority. + +### D12 — Inference proposes; deterministic code repeats + +Models discover and judge meaning. Stable repeated defects may become proposed +tests or checks, but enforcement requires runnable positives, negative controls, +an owner, rollback, and expiry. + +### D13 — Pull one leaf; make ticks idempotent + +Read durable state before acting and perform only the next legal transition. A +retry count is not a budget and an empty ready queue is not convergence. ### D14 — Destructive writes reconcile or refuse -Any write that would replace existing state merges against current reality or fails closed; a -close is not durable until merged to trunk. -**Embodied-in-gate.** `reconcile-pr.sh` is the named reconcile step; the STALE-head check (a new -commit after review invalidates the verdict) is exactly "reconcile against current reality or -refuse." "Mutate shared trunk" is the first pawl. **Doctrine** rider: same root applies to -tracker/notes/snapshot writes — merge, don't clobber. -### D15 — The operator's attention is the constraint -The scarcest resource is the human's attention; babysitting burns it because an unverified "done" -must be personally checked. The system subordinates everything to that constraint and spends -attention only where the human is irreplaceable (intent, acceptance, one-way doors). -**Embodied-in-gate** (the HOLD) + **doctrine** (the escalation economy). What the *scripts* enforce -is the fail-closed HOLD: on any non-CONFIRMED verdict, `reconcile-pr.sh` exits 5 — it does not merge -and does not close, so an unverified "done" can never silently land while the human is away. -`pawl-verdict.sh`/`reconcile-pr.sh` contain **no** auto-redo loop and **no** circuit breakers; they -just hold. The auto-redo-on-REFUTED loop and the tunable circuit breakers (max-attempts, time/cost -budget, oscillation, explicit-judgment-flag) are **doctrine / orchestrator-loop behavior** — -described in [`pawls.md` §Escalation](../contracts/pawls.md) and carried by the evolve loop and its -`scripts/evolve/halt-check.sh`, not by the reconcile/verdict scripts. The andon ("Hey! Listen!") is -rare and earned, never the default — but that economy lives in the loop above the gate, not inside -the gate script. +Before mutation, compare the expected identity with current reality. Changed +dependencies or overlaps return to the earliest invalidated move. Never clobber +foreign work. -### D16 — Mechanisms stay general; policy lives in its bounded context; layers meet through ports -A shared mechanism never has a context's law welded into it — the context configures it via a mode -plus a pointer to its enforcing gate; the factory layer calls the worker layer only through -external ports and never bypasses its local gates or rewrites its evidence. -**Doctrine** — and the architectural reason this fold is legitimate: the operating rules are the -*general mechanism*; the ratchet pawl-gate is AgentOps' *enforcing gate*. The per-pawl `mode` -(fresh-context vs multi-model) is exactly "the context configures the mechanism via a mode." See -[`architecture/ports-and-adapters.md`](../architecture/ports-and-adapters.md). +### D15 — Operator attention is the constraint -## What was dropped (and why) +Ordinary REFUTED work auto-routes to one consolidated REPAIR or REPLAN. A run +governor may enter HOLD and consult one bounded helper. Only genuine human +authority or a spent hard ceiling earns ANDON. -These were real in mt-olympus but are **floor/cathedral-specific** — not imported as live AgentOps -doctrine: +### D16 — Mechanisms stay general; policy stays bounded -- **The OS privilege floor** — separate OS account, kernel peercred identity, - `provision-accounts.sh --check`, the `olympusd` daemon as sole writer. The ratchet pawl-gate is - the AgentOps embodiment of "single writer / attested reviewer"; the OS floor is the cut cathedral. -- **The 55-case Rust gate spec / typestate `Accepted`** — a specific implementation of "the gate - is the only door," not a substrate-neutral rule. AgentOps' door is `reconcile-pr.sh` + the pawl - verdict. -- **Host-policy instances** (e.g. the `claude -p` LAW 0 ban) — real, mechanically enforced, but a - *host-policy instance* of D11 (forbidden-pattern admission), not a method invariant. (LAW 0 still - holds operationally; it just isn't kernel doctrine.) -- **3-family quorum / Gemini-benched specifics** — operational policy-mode detail of a particular - fleet, superseded here by the per-pawl `mode` and the context-identity floor. +AgentOps owns intent, independent judgment, evidence, and learning. Runtimes, +trackers, local shells, cloud agents, Git providers, CI systems, and release +pipelines connect through ports and remain replaceable. + +## Delivery boundary + +Validation and Git delivery are separate. Direct push, PR, hosted CI, or a +dedicated merge service may consume the same exact candidate and proof. Delivery +does not invoke another model, upgrade the verdict, or replay an unchanged full +suite. AgentOps records the resulting identity; the repository owns the action. + +## What was dropped + +The former one-way-door review lifecycle, model-driving Git checks, queue +admission, nested retry budgets, and semantic push-hook enforcement are retired. +They duplicated the four umbrellas and turned validation into a CI product. +Executable owners disappear through the checked K7/K9 direct-cut leaves; this +authority change does not pretend that code has already been removed. ## Provenance -- Source kernel: `mt-olympus/docs/doctrine/fleet-operating-discipline/corpus/specs/triangulated_kernel.md` - (D1–D16, three-model triangulation, evidence anchors `Q--`). -- Enforcement surface in this repo: [`docs/contracts/pawls.md`](../contracts/pawls.md), - [`scripts/pawl-verdict.sh`](../../scripts/pawl-verdict.sh), - [`scripts/reconcile-pr.sh`](../../scripts/reconcile-pr.sh), - [`schemas/pawl-verdict.v1.schema.json`](../../schemas/pawl-verdict.v1.schema.json). -- The structural-corpus validators (`validate-corpus.py`, `check-doctrine-drift.py`) were - **not ported** — see the note at the bottom of this fold's task record; they validate the - mt-olympus marker-bounded corpus (anchors, distillations, vendor-drift), which this single - adapted reference doc does not carry. +This doctrine distills the earlier D1–D16 corpus while replacing its repository +gate embodiment with the lean operating loop. Git history preserves the prior +mapping for forensic use. diff --git a/docs/documentation-index.md b/docs/documentation-index.md index 19abb905a..764626eb2 100644 --- a/docs/documentation-index.md +++ b/docs/documentation-index.md @@ -34,14 +34,17 @@ - [Changelog](CHANGELOG.md) — Release history - [Security](SECURITY.md) — Vulnerability reporting -## Four Product Layers +## Four Lifecycle Umbrellas -| Layer | What it does | Key surfaces | -|-------|-------------|-------------| -| **Bookkeeping** (L0) | Records agent work so attempts, decisions, verdicts, and handoffs leave evidence | `.agents/`, RPI packets, council verdicts, retros, postmortems | -| **Context Compiler** (L1) | Assembles the right context for the right phase | `ao inject`, `ao compile`, skills, execution packets | -| **Validation Gates** (L2) | Challenges plans and code before they ship | `/council`, `/vibe`, `/premortem`, `/postmortem` | -| **Knowledge Flywheel** (L3) | Extracts, scores, and resurfaces learnings | `/postmortem --quick`, `/curate --mode=forge`, `ao lookup`, `.agents/` | +| Umbrella | What it does | Key surfaces | +|----------|--------------|--------------| +| **Discovery** | Shapes accepted behavior and consumes Premortem as its plan stress-test | `/discovery`, `/plan`, `/premortem` | +| **Crank** | Implements one bounded tranche and freezes one exact candidate | `/crank`, `/implement` | +| **Validate** | Binding judgment umbrella: one author-distinct fresh context judges a frozen candidate once | `/validate` | +| **Learn** | Records one minimal consequence before optional Postmortem | `/learn`, optional `/postmortem` | + +Council is optional validator composition inside Premortem or Validate; it is +not a parallel lifecycle gate. Deep dives: [CDLC](cdlc.md) (AgentOps' context-native SDLC under token scarcity), [Knowledge Flywheel](knowledge-flywheel.md), [Context Lifecycle](context-lifecycle.md), [Assurance Profile](assurance-profile.md), [PRODUCT.md](https://github.com/boshu2/agentops/blob/main/PRODUCT.md) @@ -54,7 +57,7 @@ Bridge / framing docs: - [Codebase Overview](architecture/codebase-overview.md) — Consolidated repo map: bounded contexts, directory ownership, active CLI waist, registries, gates, knowledge flywheel, footguns, reading order - [Understanding the AgentOps Go CLI](architecture/go-cli-architecture-guide.md) — Source-pinned architecture and code-reading guide for the transitional Go CLI, including pure/effectful command traces, tracker/config policy, testing, known debt, and a worked capstone -- [Go CLI Production-Readiness Audit](audits/2026-07-12-go-cli-production-readiness.md) — Evidence-backed audit of the strangler program, proof gaps, tracker/context semantics, recursive contracts, CLI output conformance, integration risk, and goal-design inputs +- [Go CLI Production-Readiness Audit](audits/2026-07-12-go-cli-production-readiness.md) — Evidence-backed audit of the superseded incremental migration, proof gaps, tracker/context semantics, recursive contracts, CLI output conformance, integration risk, and goal-design inputs - [Postmortem: Go CLI Goal Stall and Tracker-Layer Confusion](learnings/2026-07-12-go-cli-goal-stall-tracker-layer-confusion.md) — Why the run stopped before helper adjudication, why durable `br` decomposition mattered, and the exact boundary between this repo's beads_rust ledger and Gas City's `bd`/Dolt substrate store - [How It Works](how-it-works.md) — Brownian Ratchet, Ralph Wiggum Pattern, agent backends, context windowing - [Software Factory Surface](software-factory.md) — Explicit automation surface for briefings, RPI flows, and operator-controlled closeout @@ -83,7 +86,7 @@ Bridge / framing docs: - [ADR-0009: Delete the Daemon — AgentOps Is In-Session Only](adr/ADR-0009-daemon-deletion-in-session-only.md) — Why the standalone daemon/scheduler/overnight-runner was deleted (not deprecated): AgentOps is a Gas City reference config with no core to protect, the in-session loop is the zero-dependency sovereignty floor, always-on opts into Gas City; names the rejected deprecate-keep-standalone alternative and the e2e-proof GC dispatch gap - [ADR-0010: E6 Session-Log Miner Is Build-Native](adr/ADR-0010-e6-session-log-miner-build-native.md) — The E6.0 spike decision (cross-family): build the session-JSONL→typed-PROV-O miner native over `cli/internal/parser` + the ASSAY `--mine-cmd` slot; cass/`cm` stay adopted for search/memory only (neither owns the provenance graph). Steals cass's incremental-index discipline; no langchain core dep; scopes `ao provenance mine-session` (E6.1/`...6.2`) - [ADR-0011: Escape-Corpus Compounding Unproven — Structural Data-Starvation](adr/ADR-0011-escape-corpus-compounding-unproven-structural-starvation.md) — The self-improvement *mechanism* is proven e2e (escape→check→block), but "the escape-corpus *compounds*" is demoted to an unproven hypothesis: a competent membrane catches at review, so it self-starves its own escape supply (self-improvement anti-correlated with membrane quality). Records revival conditions; the proven claim — independent verification, no verdict = not done — is unchanged -- [ADR-0012: Focus the Surface on Membrane + Bookkeeper; Archive the Satellites](adr/ADR-0012-focus-surface-on-membrane-bookkeeper-archive-satellites.md) — Re-headline the public surface on the two proven cores (validation membrane + hash-chained bookkeeper); archive the unproven corpus/flywheel (behind `//go:build flywheel`) and RPI/factory (behind `legacy`) satellites rather than delete them, because the ADR-0004/0009/0011 revival conditions require the code to stay buildable; targets a ~22-command / ~15-skill spine +- [ADR-0012: Directly Cut the Unproven Satellite Surface](adr/ADR-0012-focus-surface-on-membrane-bookkeeper-archive-satellites.md) — Give every current command one keep/merge/replace/delete owner; install retained behavior and delete the former owner, tests, fixtures, and unique dependencies in the same candidate, then remove alternate build profiles - [PDC Framework](architecture/pdc-framework.md) — Prevent, Detect, Correct quality control approach - [FAAFO Alignment](architecture/faafo-alignment.md) — FAAFO promise framework for vibe coding value - [Failure Patterns](architecture/failure-patterns.md) — The 12 failure patterns reference guide @@ -300,8 +303,8 @@ Bridge / framing docs: - [Mortem Naming Migration](contracts/mortem-naming-migration.md) — Canonical `premortem`/`postmortem` identities, permanent legacy reads, and the schema-v3/S8 writer cutover boundary - [Four-Umbrella Write Manifests](contracts/four-umbrella-write-manifests.json) — Per-slice write ownership and frozen S1 base for the validation-loop refactor - [Four-Umbrella Examples](contracts/four-umbrella-examples.md) — Executable request, execution-packet, Learn-receipt, and plan-impact examples -- [Pawls — the one-way doors](contracts/pawls.md) — The ratchet's static map: the short list of irreversible actions (mutate-shared-trunk · delete · external-send/shared-state-mutation · schema/contract change · credential/authority change · spend) where the cross-family gate fires; everything else runs as ungated chaos -- [Operating Discipline (D1–D16)](doctrine/operating-discipline.md) — The general, substrate-neutral fleet-operating rules (admission-first · author≠judge · fail-closed · evidence-bound · single-writer · typed transitions) folded from the mt-olympus triangulated kernel; each rule marked embodied-in-gate (cited to pawls.md / pawl-verdict.sh / reconcile-pr.sh), advisory doctrine, or dropped-as-cathedral +- [Retired one-way-door contract](contracts/pawls.md) — Tombstone for the removed second lifecycle; K9 owns deletion after checked consumer closure, and the file has no active validation, escalation, or Git authority +- [Operating Discipline (D1–D16)](doctrine/operating-discipline.md) — The lean, substrate-neutral factory rules: one admitted leaf, one writer, deterministic facts, one immutable fresh-context verdict, one Learn receipt, and repository-owned delivery - [Lesson Format](contracts/lesson-format.md) — Schema for `.agents/learnings/` entries with frontmatter (id/severity/trigger/verifiable/rule/falsified_by/practice/related) and graduation path (unassigned → proposed → accepted → encoded) - [Corpus Learning Seam](contracts/corpus-learning-seam.md) — Field-level public/private boundary for learning records (epic ag-k7tq9 S3): the `sensitivity` + `publishable` promote-gate fields, what crosses the seam (the abstracted lesson) vs what never does (evidence/provenance/source_session), and the `ao corpus classify` migration; cites the cross-family council verdict - [bd remember Migration Manifest](contracts/bd-remember-migration-manifest.md) — Lineage-preserving manifest contract for classifying `bd remember` notes into bead-scoped, pull-learning, or discard dispositions before migration @@ -310,7 +313,7 @@ Bridge / framing docs: - [CI Jobs Manifest (yaml)](contracts/ci-jobs.yaml) — Canonical reason+failure for every validate.yml CI job; AGENTS.md `### CI Jobs and What They Check` table is rendered from this yaml + workflow `summary.needs` via `scripts/generate-ci-jobs-table.sh` (golden-file gate enforced by `validate-ci-policy-parity`, soc-3oij) - [Scenario → Test Linkage](contracts/scenario-test-linkage.md) — Every Gherkin scenario in `skills/*/references/*.feature` must declare its covering test via a `@covered-by:` tag or be allowlisted as doc-only in `scripts/.scenario-linkage-allow`; gate is `scripts/check-scenario-test-linkage.sh` / `validate-scenario-test-linkage` (sibling to executable-spec-link-integrity; links scenarios→tests, soc-63xfx) - [@claude Bot Delegation](contracts/claude-bot-delegation.md) — Operational runbook for the `@claude` GitHub App: permissions, triggers, status decoding, gotchas, when to delegate -- [Local Pre-Push Gate Retirement](contracts/local-pre-push-gate-retirement.md) — Historical ADR superseded by the local cockpit gate posture; retained for lineage, not current release authority +- [Local Push-Gate Experiments](contracts/local-pre-push-gate-retirement.md) — Superseded historical ADR; active policy keeps semantic validation out of Git hooks and lets the consumer repository own delivery - [Skill Dispositions (yaml)](contracts/skill-dispositions.yaml) — Canonical per-skill domain/disposition/rationale data; source-of-truth for `agentops-skill-domain-map.md`. Hand-edits to the .md forbidden — edit yaml and run `scripts/generate-skill-domain-map.sh` (golden-file gate, soc-zxia.3) - [Context Map](contracts/context-map.md) — Auto-generated bounded-context map of skills by hexagonal role with relationship and data-flow views (see ADR-0001) - [Skill-Flow Connectivity](contracts/skill-flow.md) — Closed `consumes` vocabulary + cross-layer connectivity model (`consumes`/`context_rel`/`metadata.dependencies`); gate `scripts/validate-skill-flow.sh` (`validate-skill-flow`) fails on unresolved tokens or un-allowlisted orphans; standalone leaves in `scripts/skill-flow-standalone.txt` @@ -335,7 +338,7 @@ Bridge / framing docs: - [BC1 Corpus Ports Contract](contracts/bc1-corpus-ports.md) — Core BC1 corpus ports scaffolded under `cli/internal/ports/`; semantics cheat-sheet, adapter triplet pattern, soc-pm5t wire-up order - [BC Ports Inventory](contracts/bc-ports-inventory.md) — Roster of all 20 BC ports with per-port adapter contracts, the universal triplet construction pattern, and per-BC wire-up order. - [Orchestration Ports](contracts/orchestration-ports.md) — `OrchestrationPort` dual-runtime selection seam: the 3-category model (Claude Workflow / NTM swarm / plain skill), the NTM → Claude-native → beads-floor degradation ladder, `AGENTOPS_ORCHESTRATION=off` opt-out, capability detection via `ntm --robot-capabilities`, output-contract parity (`orchestration-result.v1`), and the two-ladders distinction. Paired schemas `schemas/orchestration-backend.v1.schema.json` + `schemas/orchestration-result.v1.schema.json`. -- [Orchestration Profiles (yaml)](contracts/orchestration-profiles.yaml) — SOT for portable NTM worker and pawl-review role profiles plus structured spawn arguments +- [Orchestration Profiles (yaml)](contracts/orchestration-profiles.yaml) — SOT for portable NTM worker and reviewer role profiles plus structured spawn arguments - [Orchestration Tools (yaml)](contracts/orchestration-tools.yaml) — Tool matrix contract for `ao orchestrate tools`; drift-gated via `scripts/check-orchestration-contracts.sh` - [Orchestration Instrument Schema](https://github.com/boshu2/agentops/blob/main/schemas/orchestration-instrument.v1.schema.json) — JSON schema for `ao orchestrate` preflight/verify/tools/route/status JSON output (`orchestration-instrument.v1`) - [Orchestration Backend Selection Contract](contracts/orchestration-backend.md) — wire shape of one `OrchestrationPort` selection decision (chosen/reason/considered/opt_out/pin); pairs `schemas/orchestration-backend.v1.schema.json` for structural-floor validation. diff --git a/docs/newcomer-guide.md b/docs/newcomer-guide.md index aed4e8f75..a2dbf49c4 100644 --- a/docs/newcomer-guide.md +++ b/docs/newcomer-guide.md @@ -4,14 +4,17 @@ If you're new to this repository, this guide gives you a practical mental model, ## What this repo is -AgentOps is the **operational layer for coding agents**: a skills + CLI system that provides bookkeeping, validation, primitives, and flows so sessions compound instead of restarting from zero. AgentOps 3.0 is hookless by default; this repo uses the local cockpit gate as routine release authority, with CI as an optional/manual backstop. +AgentOps is the **operational layer for coding agents**: a skills + CLI system +that provides bookkeeping, validation, primitives, and flows so sessions +compound instead of restarting from zero. AgentOps 3.0 is hookless by default; +the consumer repository owns its Git and CI delivery policy. At a high level: 1. Shape behavior through Discovery (`/discovery`, `/plan`, and `/premortem` when risk warrants it) 2. Execute small vertical slices through Crank (`/implement` or `/crank`) 3. Judge each completed slice through fresh-context `/validate` -4. Route catches and plan impact through `/learn`, with `/postmortem` as the terminal-review compatibility entry point +4. Route catches and plan impact through `/learn`, with `/postmortem` available afterward for an explicit causal question See also: @@ -30,7 +33,7 @@ Think in four layers: 1. **Product/docs layer** — `docs/` + selected repo-root entrypoints such as `README.md`, `CHANGELOG.md`, `GOALS.md`, and `PRODUCT.md` 2. **Skills layer** — `skills/`, checked-in `skills-codex/`, and `skills-codex-overrides/` (`SKILL.md` contracts + per-skill scripts/references + Codex-only tailoring) 3. **CLI layer** — `cli/` (`cli/cmd/ao/`, `cli/internal/`, generated `cli/docs/COMMANDS.md`) -4. **Validation layer** — `scripts/`, `tests/`, the local cockpit gate, and `.github/workflows/validate.yml` as an optional/manual backstop +4. **Evidence layer** — deterministic `scripts/` and `tests/`, immutable Validate verdicts, and repository-selected CI ## Source-of-truth precedence @@ -83,7 +86,8 @@ The normal explicit request sequence is: Validation completion and Git delivery are separate. Your repository may use a direct push, a PR, its own CI, or another delivery adapter after AgentOps has -recorded the verdict. +recorded the immutable fresh-context verdict and Learn receipt. This is the +same for a local agent and a cloud agent. ### 3) Issue tracking uses br, not bd @@ -98,7 +102,10 @@ Do not use `bd` or Dolt for **this repo's** tracking — `br` is AgentOps' own t ### 4) Hooks are opt-in, not a default -AgentOps 3.0 ships zero hooks; nothing auto-injects or runs at session boundaries. This repo uses the local cockpit gate as the routine gate, while CI (`.github/workflows/validate.yml`) is an optional/manual backstop. If you want a bounded local gate of your own, author one with the `hooks-authoring` skill — AgentOps does not ship one. +AgentOps 3.0 ships zero hooks; nothing auto-injects or runs at session +boundaries. If a repository wants a bounded deterministic hook, its owner can +author one with the `hooks-authoring` skill. It remains repository delivery +policy and cannot perform semantic validation. ### 5) CLI docs are generated, not hand-maintained @@ -134,10 +141,12 @@ CI validates not just builds/tests but also docs parity, skill integrity/schema, ## Practical tips -- Run the local gate before pushing: `ao gate check --fast --scope head` (Go registry; smart routing checks only what changed). Legacy bash escape hatch: `AGENTOPS_GATE_BASH=1` → `scripts/pre-push-gate.sh --fast`. +- Run the focused deterministic checks selected by your changed surface and + bind them to the frozen candidate. Your repository—not AgentOps—decides + whether to use direct push, a PR, a hook, or external CI. - Use a **git worktree** per bead when the canonical checkout is shared — see `AGENTS-RUNTIME.md`. - Trust runtime files over narrative docs when there is a mismatch. -- Keep changes small and verify with local gates before pushing. +- Keep changes small, freeze one candidate, and retain exact-input evidence. - Treat `.agents/` as a first-class part of the system behavior. - Treat Codex as a first-class runtime: when a skill change affects Codex UX or execution style, inspect `skills-codex-overrides/`, update `skills-codex-overrides/catalog.json` if treatment changes, update the checked-in `skills-codex/` copy when needed, and run the Codex validation scripts. - If you touch command surfaces or skill contracts, expect related parity checks to fail until updated. diff --git a/docs/software-factory.md b/docs/software-factory.md index 7d08c64aa..5610b24ad 100644 --- a/docs/software-factory.md +++ b/docs/software-factory.md @@ -1,122 +1,77 @@ # Software Factory Surface -Publicly, AgentOps is the operational layer for coding agents. This document -names the operator surface and software-factory mechanics beneath that public -story so users do not have to infer them from skills, hooks, CLI commands, and -internal artifacts. +AgentOps is a software-factory operating contract for coding agents. It turns +accepted intent into independently judged evidence while keeping runtimes, +trackers, and repository delivery replaceable. -## Thesis +## Four umbrellas -AgentOps gives coding agents four things by default: +| Umbrella | Factory role | Output | +|---|---|---| +| Discovery | Orchestrator shapes behavior and consumes Premortem when needed | accepted plan and tranche packet | +| Crank | One writer implements one bounded tranche | frozen candidate and deterministic receipts | +| Validate | A fresh author-distinct context judges the complete claim set once | immutable PASS or FAIL verdict | +| Learn | The orchestrator records the smallest useful consequence | no-change, plan-impact, or terminal receipt | -- bookkeeping -- validation -- primitives -- flows +Postmortem is optional after Learn and answers an explicit causal question. It +is not a fifth lifecycle gate. -This page explains the operator surface beneath that promise. Internally, -AgentOps is best understood as a **software-factory control plane**. +## Roles and runtime variants -The environment carries: +The role split is orchestrator, implementer, and validator. One model can fill +all three roles only through separate contexts; the candidate's author cannot +be its validator. One fresh validator is the default. A council or multiple +model families are explicit higher-rigor strategies. -- bounded briefing and context assembly -- tracked planning and scoped execution -- validation gates and ratchet checkpoints -- bookkeeping and flywheel closure between sessions -- isolated work lanes for long-running or parallel work +Native Codex, another local agent, NTM-managed panes, managed agents, and cloud +workers all run the same loop. Runtime adapters may provide process durability, +mailboxes, or isolation; they do not change role authority or lifecycle state. -The workers remain replaceable. The environment carries continuity. +## CLI boundary -This follows the repo's stateful-environment/stateless-agents theory and its -own lifecycle/flywheel contracts: briefings and runtime state are the operator -surface; packets, chunks, topics, and builders are substrate. +The final `ao` CLI is a deterministic transaction kernel and flight recorder. +It may pull one tracked leaf, freeze candidate identity, run factual checks, +record an external verdict, reduce Learn bookkeeping, record delivery facts, +and close a report after remote verification. It does not decide intent, drive +a model, issue semantic judgment, choose Git policy, or operate a merge queue. -## Runtime Variants +The current executable still contains transitional commands and build profiles. +They are removed through exact same-owner K, CLI, and F leaves; this document +does not treat those leftovers as product variants. -AgentOps 3.0 is **hookless**: the factory runs identically on every runtime -(Claude Code, Codex, Cursor, OpenCode) because it does not depend on any -harness-specific hook surface. Workflow is guided by skills + the `ao` CLI, and -The local pre-push Go gate (`ao gate check`) is the routine release authority (CI is a backstop). The operator lane is the same everywhere: +## Repository-owned delivery -```bash -/rpi "fix auth startup" # in-session, any harness -# the RPI CLI engine was removed in 3.0 -- the /rpi skill above is the live in-session path, driving the seven-move operating loop -``` +After Validate and Learn, the consumer repository chooses direct push, a PR, +hosted CI, a dedicated merger, or another adapter. The choice is identical for +local and cloud agents. Delivery consumes proof but cannot upgrade it. AgentOps +records the adapter, target, result, and remote identity. -What used to be hook responsibilities are now explicit, pulled surfaces: +## Concurrency -| Concern | Hookless surface | -|---------|------------------| -| Startup context | `ao knowledge brief` / `ao context assemble` (pulled, not injected on every event) | -| Validation gates | CI (`.github/workflows/validate.yml`) + skill-level checks run in-band | -| Code quality | `cd cli && make test`, `go vet`, complexity budget — enforced by CI | -| Flywheel closure | `ao flywheel close-loop` / `/retro` / `/curate --mode=forge` at session close | -| Execution discipline | Execution-packet `next_action` + skill instructions | +One writer and one active leaf are the default. An explicitly requested swarm +may parallelize read-only research. Concurrent write lanes require separate +worktrees, independently checked disjoint manifests, one owner per lane, and a +lead-owned integration order. -Both lanes run **in session** because people use Codex or they use Claude -Code — neither relies on hooks. Running the same loop **out of session** -(always-on, scheduled, unattended) is a separate concern AgentOps delegates to -an orchestration substrate; the reference is NTM + MCP + managed-agents. AgentOps 3.0 ships -no daemon, scheduler, or overnight runner of its own — those surfaces were -deleted (see [AgentOps 3.0 north star](3.0.md)). +## Learning boundary -## Surface Map +Learn runs once in the orchestrator's existing context. A repeated defect may +become a proposed check only after two distinct objectives plus runnable +positives, negative controls, shadow evidence, an owner, rollback, and expiry. +Pattern mining and promotion stay off the tranche critical path. -| Layer | Purpose | Primary surfaces | -|------|---------|------------------| -| Operator | What the human or lead agent should touch first | `ao factory start`, `/rpi` (drives the seven-move operating loop; the old RPI CLI engine was removed in 3.0), NTM + MCP Agent Mail substrate for out-of-session runs | -| Briefing + runtime | Bounded startup context and thread-time state | `ao knowledge brief`, `ao context assemble` | -| Out-of-session | Running the loop unattended (always-on, scheduled) | Delegated to an orchestration substrate (the reference is NTM + MCP + managed-agents) — not an AgentOps surface | -| Delivery line | Research, planning, execution, validation | `/discovery`, `/plan`, `/crank`, `/validation`, `/rpi` | -| Learning loop | Convert completed work into future advantage | `ao knowledge activate`, `ao flywheel close-loop`, `/retro`, `/curate --mode=forge` | -| Enforcement | Automatic quality gates and execution discipline | CI (`.github/workflows/validate.yml`), skill-level checks, `cd cli && make test` | -| Substrate | Retrieval, provenance, packetization, and promotion machinery | `.agents/packets/`, `.agents/topics/`, `.agents/briefings/`, `.agents/findings/`, builder logic | - -## Enforcement — No Hooks Required - -AgentOps 3.0 ships **zero hooks**. The factory's design rules are enforced by -explicit, pulled surfaces rather than automatic lifecycle scripts: - -- **Validation gates** — CI (`.github/workflows/validate.yml`) is the - authoritative gate; skills run their own checks in-band before claiming work - complete. -- **Ratchet checkpoints** — `ao flywheel close-loop` / `/retro` / `/curate --mode=forge` - persist learnings at session close. -- **Execution discipline** — execution-packet `next_action` and skill - instructions keep the agent producing artifacts instead of stalling. -- **Code quality** — `cd cli && make test`, `go vet`, and the complexity budget - are enforced by CI on every push. - -Operators who *want* runtime hooks can author their own with the -`hooks-authoring` skill — they are opt-in and not part of the default product -surface. - -## Why This Surface Exists - -The factory framing matters because the repo already has the hard parts: - -- RPI provides the conveyor belt. -- Context packets and briefings provide bounded work orders. -- The flywheel provides bookkeeping and closure between sessions. -- Codex lifecycle commands provide explicit runtime boundaries where hooks do - not exist. - -Without an explicit operator lane, users see a powerful collection of -primitives. With it, they see one product surface. - -## Design Rules +## Design rules - Prefer briefings over giant startup dumps. - Keep substrate and operator surfaces distinct. - Let external validation outrank self-report. - Treat thin topics as discovery-only until evidence improves. -- Keep `compile` scoped to hygiene, not full operator-surface activation. +- Keep deterministic mechanisms separate from semantic judgment. -## Related Docs +## Related docs -- [How It Works](how-it-works.md) +- [Operating Loop](architecture/operating-loop.md) +- [Agent Workflow Reference](agent-workflow-reference.md) +- [Go CLI Architecture Guide](architecture/go-cli-architecture-guide.md) - [Context Packet](context-packet.md) -- [Knowledge Flywheel](knowledge-flywheel.md) -- [Session Lifecycle](workflows/session-lifecycle.md) -- [CLI Reference](https://github.com/boshu2/agentops/blob/main/cli/docs/COMMANDS.md) diff --git a/tests/scripts/agentops-product-boundary.bats b/tests/scripts/agentops-product-boundary.bats new file mode 100644 index 000000000..76b17529f --- /dev/null +++ b/tests/scripts/agentops-product-boundary.bats @@ -0,0 +1,196 @@ +#!/usr/bin/env bats + +setup() { + REPO_ROOT="$(cd "$BATS_TEST_DIRNAME/../.." && pwd)" + ACTIVE_AUTHORITY=( + AGENTS.md + AGENTS-CI.md + PROGRAM.md + PRODUCT.md + GOALS.md + docs/CI-CD.md + docs/3.0.md + docs/MIGRATION.md + docs/UPGRADING.md + docs/agent-workflow-reference.md + docs/adr/ADR-0012-focus-surface-on-membrane-bookkeeper-archive-satellites.md + docs/architecture/build-tags.md + docs/architecture/go-cli-architecture-guide.md + docs/architecture/operating-loop.md + docs/contracts/local-pre-push-gate-retirement.md + docs/contracts/pawls.md + docs/doctrine/operating-discipline.md + docs/documentation-index.md + docs/newcomer-guide.md + docs/software-factory.md + cli/README.md + ) +} + +scan_obsolete_authority() { + local file="$1" + if [[ ! -f "$file" ]]; then + echo "invalid harness: missing authority file: $file" >&2 + return 2 + fi + + local active_text matches + active_text="$(grep -Ev \ + '^[[:space:]]*>?[[:space:]]*HISTORICAL EVIDENCE \(NON-AUTHORITATIVE\):' \ + "$file" || true)" + matches="$(printf '%s\n' "$active_text" | grep -Eni \ + 'ao[[:space:]]+land|ao[[:space:]]+pawl|/pawl-review|run[^[:cntrl:]]*pawl|pawl(-review|-land)?[[:space:]]+(gate|route|review|verdict|authority)|push-as-CI|never[[:space:]]+delete|strangl[a-z]*|archiv(e|ed|ing)[^[:cntrl:]]{0,240}(rather than|instead of|not)[^[:cntrl:]]{0,80}delet|((release[[:space:]]+)?tag[[:space:]]+push|CI)[^[:cntrl:]]{0,160}(run|produce|emit|write|record)[^[:cntrl:]]{0,120}Validate[[:space:]]+verdict|Validation[[:space:]]+Gates[^[:cntrl:]]*(premortem|postmortem|council)|Knowledge[[:space:]]+Flywheel[^[:cntrl:]]*postmortem|semantic[[:space:]]+pre-push|local[[:space:]]+gate[^[:cntrl:]]*release[[:space:]]+authority' \ + || true)" + if [[ -n "$matches" ]]; then + printf 'obsolete authority in %s:\n%s\n' "$file" "$matches" >&2 + return 1 + fi +} + +require_text() { + local relative="$1" expected="$2" + local file="$REPO_ROOT/$relative" + if [[ ! -f "$file" ]]; then + echo "invalid harness: missing authority file: $relative" >&2 + return 2 + fi + grep -Fq -- "$expected" "$file" || { + echo "$relative is missing product-boundary contract: $expected" >&2 + return 1 + } +} + +@test "active authority teaches the lean four-umbrella product boundary" { + local relative + for relative in "${ACTIVE_AUTHORITY[@]}"; do + run scan_obsolete_authority "$REPO_ROOT/$relative" + [ "$status" -eq 0 ] || { + echo "$output" >&2 + return "$status" + } + done + + require_text AGENTS.md \ + "Discovery, Crank, Validate, and Learn are the four lifecycle umbrellas." + require_text docs/architecture/operating-loop.md \ + "A verdict is immutable evidence from fresh context." + require_text docs/CI-CD.md \ + "Repositories own delivery policy for local and cloud agents." + require_text docs/adr/ADR-0012-focus-surface-on-membrane-bookkeeper-archive-satellites.md \ + "Delete legacy code directly in the same owning leaf that installs its replacement or removes its last consumer." + require_text docs/architecture/go-cli-architecture-guide.md \ + "CLI implementation deletion is owned by K5, K7, K9, and the exact CLI leaves." + require_text docs/architecture/go-cli-architecture-guide.md \ + "Build-profile deletion is owned by F4." + require_text docs/architecture/go-cli-architecture-guide.md \ + "Generated command-reference deletion or regeneration is owned by D2." + require_text docs/documentation-index.md \ + "| **Discovery** | Shapes accepted behavior and consumes Premortem as its plan stress-test |" + require_text docs/documentation-index.md \ + "| **Validate** | Binding judgment umbrella: one author-distinct fresh context judges a frozen candidate once |" + require_text docs/documentation-index.md \ + "| **Learn** | Records one minimal consequence before optional Postmortem |" + require_text docs/documentation-index.md \ + "Council is optional validator composition inside Premortem or Validate; it is" +} + +@test "negative fixture rejects a model verdict as a Git delivery gate" { + local fixture="$BATS_TEST_TMPDIR/model-gate.md" + printf '%s\n' 'Run the Pawl before Git delivery.' >"$fixture" + + run scan_obsolete_authority "$fixture" + + [ "$status" -eq 1 ] + [[ "$output" == *"Pawl"* ]] +} + +@test "negative fixture rejects repository delivery through ao land" { + local fixture="$BATS_TEST_TMPDIR/cli-delivery.md" + printf '%s\n' 'The terminal command is ao land AGE-123.' >"$fixture" + + run scan_obsolete_authority "$fixture" + + [ "$status" -eq 1 ] + [[ "$output" == *"ao land"* ]] +} + +@test "negative fixture rejects compatibility-first retention" { + local fixture="$BATS_TEST_TMPDIR/retention.md" + printf '%s\n' 'Use a compatibility-first strangler and never delete the old owner.' >"$fixture" + + run scan_obsolete_authority "$fixture" + + [ "$status" -eq 1 ] + [[ "$output" == *"compatibility-first strangler"* ]] + [[ "$output" == *"never delete"* ]] +} + +@test "negative fixture rejects semantic push-hook authority" { + local fixture="$BATS_TEST_TMPDIR/push-hook.md" + printf '%s\n' 'The local gate is the release authority; require semantic pre-push review.' >"$fixture" + + run scan_obsolete_authority "$fixture" + + [ "$status" -eq 1 ] + [[ "$output" == *"local gate is the release authority"* ]] + [[ "$output" == *"semantic pre-push"* ]] +} + +@test "negative fixture rejects strangled and strangling migration variants" { + local fixture="$BATS_TEST_TMPDIR/incremental-cut.md" + printf '%s\n' \ + 'Legacy commands are being strangled while the new root lands.' \ + 'The migration is strangling one family at a time.' >"$fixture" + + run scan_obsolete_authority "$fixture" + + [ "$status" -eq 1 ] + [[ "$output" == *"strangled"* ]] + [[ "$output" == *"strangling"* ]] +} + +@test "negative fixture rejects archive-rather-than-delete retention" { + local fixture="$BATS_TEST_TMPDIR/archive-retention.md" + printf '%s\n' \ + 'Archive the satellites behind build tags rather than delete them.' >"$fixture" + + run scan_obsolete_authority "$fixture" + + [ "$status" -eq 1 ] + [[ "$output" == *"Archive the satellites"* ]] +} + +@test "negative fixture rejects deterministic CI claiming a Validate verdict" { + local fixture="$BATS_TEST_TMPDIR/ci-verdict.md" + printf '%s\n' \ + 'Release tag pushes run a full Validate verdict for the tagged SHA.' >"$fixture" + + run scan_obsolete_authority "$fixture" + + [ "$status" -eq 1 ] + [[ "$output" == *"Validate verdict"* ]] +} + +@test "negative fixture rejects obsolete parallel umbrella routing" { + local fixture="$BATS_TEST_TMPDIR/umbrella-routing.md" + printf '%s\n' \ + '| Validation Gates | /council, /premortem, /postmortem |' \ + '| Knowledge Flywheel | /postmortem --quick, /curate |' >"$fixture" + + run scan_obsolete_authority "$fixture" + + [ "$status" -eq 1 ] + [[ "$output" == *"Validation Gates"* ]] + [[ "$output" == *"Knowledge Flywheel"* ]] +} + +@test "bounded historical evidence remains legal" { + local fixture="$BATS_TEST_TMPDIR/historical-evidence.md" + printf '%s\n' \ + 'HISTORICAL EVIDENCE (NON-AUTHORITATIVE): CI produced a Validate verdict while commands were being strangled and satellites were archived rather than deleted.' \ + >"$fixture" + + run scan_obsolete_authority "$fixture" + + [ "$status" -eq 0 ] +} diff --git a/tests/scripts/agents-operating-contract.bats b/tests/scripts/agents-operating-contract.bats index ea953780f..842b141bd 100644 --- a/tests/scripts/agents-operating-contract.bats +++ b/tests/scripts/agents-operating-contract.bats @@ -19,8 +19,10 @@ "**Build.**" \ "**Freeze and prove.**" \ "**Learn, deliver, verify, report.**" \ + "Discovery, Crank, Validate, and Learn are the four lifecycle umbrellas." \ + "Delivery is repository-owned" \ "NOTE, REPAIR, REPLAN, HOLD, or ANDON" \ - "docs/contracts/pawls.md" \ + "skills/rpi/references/pull-flow-governor.md" \ "docs/contracts/repo-execution-profile.md" \ "docs/architecture/operating-loop.md" \ "docs/agent-workflow-reference.md" \