From 26c116c6220e734fc3081a69284ed13f502acf9f Mon Sep 17 00:00:00 2001 From: REPPL <77722411+REPPL@users.noreply.github.com> Date: Sun, 12 Jul 2026 15:14:41 +0100 Subject: [PATCH 1/3] docs: design /abcd:run autonomous-run loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Record the design for /abcd:run — the ADR-27 host-workflow autonomous-run loop: SOTA-researched against primary sources, reviewed against abcd principles + the current CLI, and reconciled with itd-29 (which owns this surface and reserves the 'run' name). Includes the seed learnings note + adversarial panel, and the SOTA-verdict and itd-29 naming decisions in DECISIONS.md. Assisted-by: Claude:claude-opus-4-8 --- .../plans/2026-07-12-abcd-auto-loop-skill.md | 497 ++++++++++++++++++ ...6-07-12-autonomous-loop-skill-learnings.md | 194 +++++++ .abcd/work/DECISIONS.md | 22 + 3 files changed, 713 insertions(+) create mode 100644 .abcd/development/plans/2026-07-12-abcd-auto-loop-skill.md create mode 100644 .abcd/development/research/notes/2026-07-12-autonomous-loop-skill-learnings.md diff --git a/.abcd/development/plans/2026-07-12-abcd-auto-loop-skill.md b/.abcd/development/plans/2026-07-12-abcd-auto-loop-skill.md new file mode 100644 index 00000000..ff07516c --- /dev/null +++ b/.abcd/development/plans/2026-07-12-abcd-auto-loop-skill.md @@ -0,0 +1,497 @@ +# `/abcd:auto-loop` — design plan for a generic autonomous burst-mode loop + +**Status:** design plan recorded 2026-07-12 for **sign-off, not yet built**. This +doc is the design deliverable requested before any skill code is written. It +synthesises three inputs: the candidate prompt +(`Desktop/generic-start-prompt.md`, a strong base), the learnings note +([`../research/notes/2026-07-12-autonomous-loop-skill-learnings.md`](../research/notes/2026-07-12-autonomous-loop-skill-learnings.md)), +and its three-reviewer adversarial panel (verdicts: mechanics FLAWED, safety +UNSAFE, assessment OVERSTATED). The panel's MUST-FIX / CORRECTIONS / +Lower-severity sections are treated as **requirements**, resolved concretely +below. A `sota-researcher` pass backs the external-practice claims (§10). + +## 1. What the capability is + +A **generic** command that drives one repository through a run PLAN autonomously, +in timeboxed bursts, one PR per milestone, resuming from a durable handoff with no +memory of prior bursts. It is launched under the harness loop: + +``` +/loop 90m /abcd:auto-loop .abcd/development/plans/.md +``` + +The command takes **exactly one argument: a path to a run PLAN** under +`.abcd/development/plans/`. Everything repo- or run-specific lives in the plan; +the command is the invariant protocol. This is the same generic/plan separation +the candidate prompt already nails — we keep it and push it further: the candidate +still had two placeholders baked into the prompt text (`{{PLAN_FILE}}`, +`{{TEST_COMMANDS}}`); here **the plan is the only placeholder** and the plan +itself carries the gate commands, DoD, ledger verb, reviewers, and STOP set. + +## 2. Surface placement — where it lives (decided, with rationale) + +**Decision: `/abcd:run`, the host-delegated realization of itd-29's surface** (see +§14 for the full sequencing decision — itd-29 already owns this surface and reserves +the `run` name; §13.0 for the ADR-27 reframe). When formalised (sequence step A), it +is a host-delegated command file `commands/abcd/run.md`, reconciled into itd-29. Until +then (step C) it lives as a run PLAN + protocol invoked under the harness loop. + +- The repo's `/abcd:*` surface is `commands/abcd/.md` + ([`commands/README.md`](../../../commands/README.md)). Most verbs are thin + binary wrappers, but there is firm precedent for **prose-only agent-instruction + commands** that call no binary: `prepare-this-repo.md`, `consult.md`, + `ingest.md`. `/abcd:auto-loop` is that kind — an orchestration protocol, not a + wrapper over an `abcd` sub-verb. +- It is *not* core behaviour (`internal/core` stays transport-agnostic and never + orchestrates an LLM loop). The loop is host-delegated by design — consistent + with the "host-delegated by default" boundary in AGENTS.md. + +Rejected alternative — a `.claude/skills/` skill: that surface is harness-private +and not part of the published plugin marketplace; the whole point is that this +ships on the `/abcd:` surface like the others. + +## 3. The two-part contract: what is generic vs what the plan carries + +**Generic (in `auto-loop.md`, never parameterised):** the burst protocol (recover +state → pick next item → research-if-needed → TDD write+test+commit → +gate → risk-gated adversarial review → PR → checkpoint → stop); the STOP +conditions' *machinery*; the Attempts write-ahead journal; the delegation +discipline (lean orchestrator; workers return terse structured verdicts); the +chained-branch merge-commit-only mechanics and their fragility STOPs; the secret +scrub; the changelog-fragment convention; the NEXT.md handoff shape; the +per-burst time + token/fan-out budget. + +**Plan-carried (a required template, §4):** Definition of Done / success criteria; +the exact gate commands; the ledger verb (`abcd capture …`); the review agents to +invoke; branch/PR/commit-trailer policy; the run-specific STOP conditions; the +backlog source; irreversible-step declarations; the milestone/item list with +**stable ids**. + +## 4. Required run-PLAN shape (the template the command validates) + +The command **refuses to start** if the plan lacks any mandatory block. The plan +is a normal dated design-record file; these headed sections are its contract: + +```markdown +## Run contract (MANDATORY — the command aborts if absent/malformed) +backlog: milestones | ledger # §5 — where the work-list comes from +gate: # the green bar, e.g. `make preflight` +definition_of_done: +ledger_verb: abcd capture # or "none" +reviewers: + correctness: ruthless-reviewer # always-on, every non-trivial diff + security: security-reviewer # trust-boundary diffs (default-on, §7.4) +branch_policy: /; merge-commit-only; never force-push; never commit to default +commit_trailer: Assisted-by: Claude: # this repo's rule; "none" elsewhere +pr_policy: one PR per milestone; do not merge; do not enable auto-merge +budget: 30m wall | worker-agents | orchestrator-tokens # §6 +stop_conditions: # run-specific, ADDED to the generic set (§7) + - +irreversible: # §7.2 — always human-checkpointed + - + +## Milestones (MANDATORY when backlog: milestones) +- id: M1 name: <...> base: main depends_on: [] +- id: M2 name: <...> base: M1 depends_on: [M1] + # `id` is the STABLE strike-counter key (§7.1). `base` drives the chain (§7.5). +``` + +When `backlog: ledger`, the milestone list is replaced by a query the command runs +each burst (`abcd capture list --open --json`); each open `iss-N` is an item and +`iss-N` is its stable strike key. `depends_on` comes from the ledger's +`blocked_by`. + +`GOAL.md` (candidate's authority doc) maps to the plan's `definition_of_done` + +this repo's durable record; there is no separate read-only GOAL file — the plan is +authoritative and revisable-but-not-in-premise (candidate's PLAN REVISION rule, +kept). + +## 5. Backlog source — a real fork (recommendation inside) + +Both real runs used a different source: the candidate prompt drives a +**plan-embedded milestone list** (greenfield feature work); the 2026-07-12 +clean-slate run drained the **`abcd capture` ledger** (hardening/issue-burndown). +Rather than pick one, the plan declares `backlog:` and the command supports both: + +- `backlog: milestones` — ordered milestone list in the plan; chain per `base`. +- `backlog: ledger` — `abcd capture list --open --json` each burst; + derived-priority order; fold the `resolve` into the fix branch so the issue + auto-resolves on merge (a hard-won learning — no trailing chore PR). + +**Recommendation: support both, default to `milestones`.** Ledger mode reuses the +existing structured ledger (stable ids, dependency ordering, folder-as-status) we +already ship — no new machinery. + +## 6. Budgets — bound context, not just time (resolves Lower-severity + note gap) + +The candidate bounds only wall-clock (30 min). A burst that *implements several +milestones itself* accumulates context regardless of the clock — the exact +overflow the clean-slate run hit. So the plan declares three bounds and the burst +stops cleanly at the **first** one reached: + +- **Time:** ≤30 min wall-clock (finish the current atomic unit, never truncate mid-change). +- **Fan-out:** ≤N concurrent/total worker agents per burst. +- **Tokens:** a soft orchestrator-context ceiling; on approach, write NEXT.md and stop. + +Stopping on a budget is a *clean* stop (green, committed, handed off), never a STOP +condition (no human needed) — the next burst resumes. + +## 7. Every MUST-FIX, resolved concretely + +### 7.1 Dangling/died entry counts toward 3-strikes; strike key is a STABLE id + +The candidate's 3-strikes counts only `→ FAILED` lines, so a step that reliably +**hangs/crashes** leaves an outcome-less line — treated as "investigate", never +counted — and loops forever. Fix, in the generic protocol: + +- On burst start, read `## Attempts` **before** `## Next steps`. For the item about + to be worked, count both `→ FAILED` lines **and** dangling (no-outcome) lines + against the limit. **3 combined strikes → STOP.** A *second* consecutive dangling + entry for the same id is itself a STOP (a reliable hang is not a flake). +- The counter is keyed on the item's **stable `id`** (`M3`, `iss-42`), never the + free-text description (Lower-severity fix). The plan/ledger supplies the id; + Attempts lines are `- [] — trying: …`. + +### 7.2 Irreversible changes ALWAYS get a human checkpoint + rehearsed rollback + +The candidate exempts migrations "part of the plan" — but its own example M6 *is* a +backfill migration, so it would ship unattended. Fix: **naming a step in the plan +does not grant unattended execution.** Any step matching the plan's `irreversible:` +list — or the generic set (DB migration, data backfill, history rewrite, +destructive cutover, dropping/renaming persisted state) — triggers a **STOP with a +rollback rehearsal**: the burst prepares the change on a branch, writes the exact +forward + rollback commands into NEXT.md, and stops for a human. Never a +dual-write, never an untested revert (AGENTS.md risky-cutover rule). + +### 7.3 Scrub secrets / local paths from pasted test output before it enters a PR + +"Paste real test output" is kept (evidence beats assertion) but gated by a **scrub +pass** before any output reaches a PR body, commit, or issue: strip absolute local +paths (`/Users/…`, `/home/…`, `C:\…` → repo-relative), tokens/keys, real +hostnames/usernames/emails, and any `private-names.txt` match. This enforces the +non-negotiable privacy invariant. Mechanics that make it safe: always +`gh pr create --body-file` (inline `--body` shell-mangles backticks — a hard-won +learning), and the scrub runs on the file before it is passed. + +### 7.4 Default-ON adversarial review gate before each PR + +Green tests are not enough — the clean-slate run had **three** diffs pass TDD that +the security reviewer then BLOCKED. Before every PR: + +- **Correctness reviewer (`ruthless-reviewer`) on every non-trivial diff** — always. +- **Adversarial security reviewer (`security-reviewer`) on trust-boundary diffs** — + secrets, subprocess, network, input-parsing, file/DB, auth. The classifier is + **conservative: default-to-review; only pure docs/comment/formatting diffs skip; + when unsure, run it.** Mis-tagging must fail toward *more* review (the real + same-line secret leak came from a diff nobody would pre-tag). +- Reviewers return a **terse structured verdict** (PROMOTE/HOLD + confirmed findings + + `file:line`), never prose (§8), persisted as a **VSA receipt** under + `.abcd/work/reviews//` (pinned judge model + detector version), the shape abcd + already uses. **The LLM verdict does not itself block** — per abcd's + `verifier-selects-gates-decide`, admission stays deterministic: the release-gate + (`record-lint --release-gate --require-gate `) is **fail-closed on a + PROMOTE receipt**, so a HOLD (or missing receipt) deterministically withholds the + PR. Same effect as "BLOCK stops the PR", but the authority is the deterministic + gate, never the probabilistic reviewer. Unresolved after the strike limit → STOP. + See §13.2 — this corrects a conflict in the first draft. + +### 7.5 Chain-fragility states → STOP-and-report, never a knowingly-broken chain + +The chained-branch model is kept (merge-commit-only, GitHub auto-retarget — the +candidate's reasoning is sound), but three fragile states are added as STOPs +instead of "move on": + +- **Upstream fix needed on an already-branched chain** (rebase forbidden): do not + rewrite history to propagate it. Record in NEXT.md and STOP — a human decides. +- **Base PR closed-not-merged:** the downstream base vanished — STOP, do not retarget blindly. +- **Unpushed base** (its push failed twice): a chained child on a local-only base + cannot open a valid PR. Record under `## Unpushed`, do not open the child PR, STOP if + it blocks progress. +- **Squash/rebase-merge re-enabled on the repo:** the chain is no longer safe — STOP + (candidate already had this; kept). + +## 8. Corrected context principle — lean orchestrator, delegate reads/reviews (NOT implementation) + +The note's first-draft headline "delegate ALL implementation" is **wrong** and the +panel was right: delegating the code-writing breaks TDD watched-fail (the +orchestrator would assert a red→green it never observed), the orchestrator-local +Attempts journal (workers don't share it, so 3-strikes dies), and commit +atomicity. The corrected principle, which the command encodes: + +- **The orchestrator still writes, tests, and commits the code itself** — so it + *observes* the watched-fail→pass, owns the Attempts journal, and keeps commits atomic. +- It **delegates read-heavy exploration and all REVIEW** to short-lived subagents + that return a **terse structured verdict** (verdict + confirmed findings + + `file:line`), never full prose. This is what bounds orchestrator context growth — + not delegating implementation, and not "one issue per window" (a crude fallback, + kept only as the budget-triggered fresh-context handoff of §6). +- Reviewers are subagents with **fresh context + external signal** (lint/SAST), never + the implementer re-reading its own diff in the same context — Huang et al. (§10) + show intrinsic self-review yields no gain or regresses; CriticGPT's benefit needs a + *separate* lens. This is why review is delegated, not done in-orchestrator. +- **NEXT.md is written early and continuously**, not only at burst end — burst-end + is the most cut-off-prone moment. Every attempt line gets an outcome before the + burst yields. + +## 9. Genuinely-good candidate parts kept intact + +- **Attempts write-ahead journal** (record the approach *before* trying; dangling = + died; never repeat a FAILED approach) — kept, with §7.1's dangling-counts fix. + Lineage: Reflexion's episodic reflective memory (the don't-repeat-failures half) + + database WAL semantics (the write-ahead-so-a-crash-is-recoverable half) — §10. +- **changelog.d/ fragments** (one file per change) — kept, but the false + "structurally impossible [to conflict]" claim is corrected: **slug collisions are + possible**, so the command guards them (suffix `-2`, `-3` on collision; the + fragment README notes it). +- **Chained merge-commit-only branches + GitHub auto-retarget** — kept, with §7.5's + fragility STOPs. +- **Two-placeholder → one-placeholder design, STOP conditions, research-first, TDD + watched-fail, wired-or-dead reporting, paste-real-test-output** — all kept + (research-first via `sota-researcher`; output scrubbed per §7.3). +- **Asymmetric marking** (delete completed items; keep FAILED attempts) — kept, but + the Milestones `[PR #N]` ticks vs delete-completed two-regime drift + (Lower-severity) is resolved: milestone status is **derived from git/PR state**, + not hand-ticked; NEXT.md keeps only live items + the Attempts journal. + +## 10. SOTA backing for adopted external practices + +From a `sota-researcher` pass (primary sources, evidence-tiered). Verdicts recorded +in `.abcd/work/DECISIONS.md`; on build, the sources graduate to `ACKNOWLEDGEMENTS.md` +(inspirations/references) in the same change. The pass tempers, not overturns, the +design — three findings sharpen specific sections (flagged inline). Titles marked +[house convention] are ours, defensibly extrapolated, not directly measured. + +- **Durable handoff + fresh-context resume — ADOPT (strongest-backed).** Anthropic + *Effective harnesses for long-running agents* states compaction "isn't sufficient" + for cross-window consistency and prescribes durable artifacts (progress log, git + history, feature registry) that each burst re-reads — exactly our NEXT.md + git + + ledger model. RAG-over-ledger is *rejected* below single-milestone-exceeds-context + scale (adds a retrieval-miss failure mode, no source recommends it here). + **Sharpening (new):** the same source finds models corrupt Markdown state more + readily than JSON. Our handoff is Markdown by repo convention (NEXT.md) — see + fork §11.4: keep Markdown, or store the *strike-critical* Attempts state as a JSON + block the loop treats as append-only. +- **Delegate reads/reviews, keep implementation in ONE agent — ADOPT.** Both sides + of the multi-agent debate converge: Cognition *Don't Build Multi-Agents* ("actions + carry implicit decisions; conflicting decisions carry bad results"; Claude Code + uses subagents for "answering a question, not writing any code") and Anthropic + *Multi-agent research system* ("coding… fewer truly parallelizable tasks"; + many-dependency/shared-context tasks are a poor fit). The read/write boundary is + SOTA-endorsed; the TDD-watched-fail / journal-ownership rationale (§8) is our house + extension on top. +- **Orchestrator–worker with bounded structured output — ADOPT-WITH-CAVEATS.** + Anthropic *Multi-agent research system*: subagents as "intelligent filters" + returning results under an explicit "objective + output format + boundaries" + contract. Caveat: ~15× token cost, ~80% of eval variance from token use — worth it + only for genuinely read-heavy/parallel work, which is why our budget (§6) caps + fan-out. "Return a verdict enum, not prose" is [house convention] atop their + structured-output finding. +- **Adversarial/ensemble review before commit — ADOPT-WITH-CAVEATS.** OpenAI + *CriticGPT* (arXiv 2407.00215): a critic lens catches more inserted bugs than paid + human reviewers, and human+critic beats either alone. **Boundary condition + (sharpens §7.4/§8):** Huang et al. *LLMs Cannot Self-Correct Reasoning Yet* (arXiv + 2310.01798, ICLR'24) — *intrinsic* self-correction (the implementer re-reading its + own diff, same context) yields no gain or regresses. So reviewers **must** be + separate-lens subagents with fresh context + external signal (lint/SAST), which + §8 already mandates — now it's the cited reason, not just a preference. The + *content-gating* of the security lens is [house convention] (cost control), not + measured. +- **Bounded autonomy + HITL for irreversible actions — ADOPT (consensus, guidance- + grade).** Anthropic guidance: pause at checkpoints/blockers; "unacceptable to + remove or edit tests." **Sharpening (confirms §7.2):** gate on *action class* (DB + migration, history rewrite, publish), never on the agent's self-rated confidence — + RLHF models are miscalibrated (verbal confidence ↛ correctness). Our irreversible + gate is action-class by construction. No controlled eval quantifies the incident + reduction — adopt as consensus, claim no number. +- **Write-ahead attempt journal / N-strikes — ADOPT-WITH-CAVEATS (a composite).** The + *reflect-so-you-don't-repeat* half has canonical prior art: Shinn et al. + *Reflexion* (NeurIPS 2023), episodic reflective memory, ~8% absolute gain — cite as + our lineage. The *write-ahead, dangling-entry-means-crashed* half is the database + **WAL** pattern ported to an amnesiac agent — [house convention], well-grounded + analogy, no agent-specific paper names it. N-strikes ↔ loop-detection is + practitioner consensus, no strong eval. + +**Rejected after investigation:** parallel multi-agent *implementation* (both +sources steer away; 15× cost buys nothing at one-PR-per-milestone); compaction as +the *primary* continuity mechanism ("isn't sufficient"); RAG-over-ledger at this +scale; confidence-threshold escalation (miscalibration). + +## 13. Review against abcd (principles + current CLI) — tensions, must/should/could + +Three read-heavy passes (CLI capability map, principles-vs-SOTA, review-surface +inventory) cross-checked this design against abcd itself. The headline: **abcd is +mostly ahead of the SOTA here and already owns the run contract** — but it forces +three corrections and adds a set of obligations. Everything is recorded below and +classified MUST / SHOULD / COULD for *this* build. + +### 13.0 The load-bearing reframe (MUST) + +**ADR-27 (`autonomous-run-pluggable-seam`) already defines what an autonomous run +IS:** iterate ready work → gate each step on a **receipt** → apply a **safety guard** +with shared stop conditions, and the loop is a pluggable **adapter** (host workflow / +companion harness / thin native Go fallback). Receipt-gating is **report-don't-block** +at each iteration boundary. So `/abcd:loop` is **the host-workflow adapter onto that +seam**, not a bespoke prompt. Consequence: the design must speak ADR-27's vocabulary +(run / ready-work / receipt / safety-guard / stop-conditions) and reuse its +artefacts, not invent parallel ones. + +### 13.1 Tension table — every SOTA finding × abcd, resolved + +| SOTA finding | abcd verdict | Resolution | Tier | +|---|---|---|---| +| (A) durable handoff + fresh-context resume | ALIGNED (receipts, directory-as-truth) | reuse the seam's durable artefacts | MUST | +| (A′) JSON > Markdown for corruptible state | **CONFLICT** with Markdown-handoff convention | **split**: prose handoff = Markdown (ADR-30/docs-lint); machine-parsed journal/strike state = JSON, matching abcd's own machine-state-is-JSON rule | MUST | +| (B) keep implementation in one orchestrator | ALIGNED (ADR-25 host-delegated; ADR-27 thin loop) | orchestrator = the run adapter; never embeds model access itself | MUST | +| (C) terse structured worker output | ALIGNED (VSA receipts, `verifier-selects-gates-decide`) | verdicts persist as receipts, advisory not authoritative | MUST | +| (D) separate-lens adversarial review before commit | ALIGNED in shape, **CONFLICT on authority** | LLM review may **not** be the blocking gate; it emits a PROMOTE/HOLD **receipt**, the *deterministic* release-gate is fail-closed on it (§13.2) | MUST | +| (E) action-class STOP + human checkpoint | STRONGLY ALIGNED (ADR-27 safety-guard; global rules) | keep; **add** sota-per-intent's two hard-stops: new dependency, bespoke-no-seam | MUST | +| (F) write-ahead journal + N-strikes | ALIGNED, constrained | journal = working-tier `.abcd/.work.local/` (gitignored, per-worktree), JSON strike state, append-only; N-strikes limit *is* a stop condition | MUST | + +### 13.2 The three genuine conflicts (and how each is resolved) + +1. **Review-as-authority (was §7.4 "a BLOCK stops the PR").** abcd's + `verifier-selects-gates-decide` + `enforcement-claims-are-facts` forbid a + probabilistic verdict from deciding admission. **Fixed:** the reviewer writes a + PROMOTE/HOLD **VSA receipt** under `.abcd/work/reviews//`; the *deterministic* + `record-lint --release-gate --require-gate ` is fail-closed on a PROMOTE + receipt. Same protective effect, abcd-correct authority. (§7.4 amended.) +2. **Markdown state corruption (the user's NEXT example).** Resolved as the A′ split + above — not "Markdown vs JSON" but "prose vs machine-state", which is already how + abcd draws the line. (§10, §11.4 amended.) +3. **Reviewers don't travel with the repo.** `ruthless-reviewer`, `security-reviewer`, + and the `code-review` **Standards** axis are **USER-level**, not repo-committed; + only `intent-fidelity-reviewer` + the deterministic gates ship in-repo. A loop that + assumes them violates **wired-or-it-isn't-done**. **Fixed:** the plan *declares* its + reviewers; the command resolves them via ADR-25 host-delegation and **degrades + loudly** (`loud-staging`) to the deterministic gates + `intent-fidelity-reviewer` + + security-review slash-command when a named reviewer is absent — never silently + skips the lens. + +### 13.3 Should the loop add a "review against repo conventions" lens? — YES, as a SHOULD + +The `code-review` skill's **Standards axis** *is* the repo-conventions LLM lens (reads +`AGENTS.md`/`CONTRIBUTING.md` + a Fowler-smell baseline; explicitly skips what tooling +already enforces). Against abcd's deterministic gates (`gofmt`, `vet`, `record-lint`, +`docs-lint`) + a correctness reviewer it is **not redundant** — it catches naming that +reveals intent, module-boundary/altitude conventions, API-shape consistency, and +"documented convention X but code does Y" where X isn't machine-checkable. + +Recommendation: **add a Standards/conventions lens as a third reviewer** — but (i) +advisory receipt, not a blocking authority (same as §13.2.1); (ii) gated to +non-trivial code diffs; (iii) told to skip anything the deterministic gates cover; +(iv) it partly overlaps the correctness reviewer, so it is a **SHOULD**, not a MUST — +worth it because abcd's whole value proposition is convention-conformance, but the +first cut can ship with correctness + security and add Standards next. Note the +repo-committed structured cousin already exists for the **Spec** half: +`intent-fidelity-reviewer` (per-criterion MET/NOT_MET, ingested by `abcd intent review +ingest`) — the loop should use *that* for spec-fidelity rather than a prose Spec pass. + +### 13.4 `/abcd:loop` gated vs `--dangerously-skip-gates` — reshaped, not adopted as-worded + +Your instinct is right that there are **two modes**, but the axis is **human-checkpoint +cadence, not gate-skipping**. In abcd "gates" = the *deterministic* gates (build / vet +/ test / record-lint / docs-lint); skipping those is exactly `--no-verify`, which +AGENTS.md forbids without exception, and would gut `guards-prove-themselves`. So a flag +literally named `--dangerously-skip-gates` is a **hard no** — it names the one thing +that must never be skipped. + +The coherent two-mode design (recommended): + +- **`/abcd:loop` (default = supervised).** Bounded autonomy: runs the full pipeline but + **stops for a human at each PR / milestone boundary** (and at every STOP condition). + This is ADR-27's report-**and-pause** posture — the safe default. +- **`/abcd:loop --dangerously-unattended` (the candidate's burst mode).** Keeps opening + chained PRs across milestones without pausing at each boundary — "the human is not at + the machine." What it skips is the **per-milestone human checkpoint**, never a + deterministic gate and never a review receipt. + +**Invariant across both modes (non-negotiable):** deterministic gates run every commit; +review receipts are emitted; and the **irreversible-action checkpoint (§7.2) always +fires regardless of the flag** — `--dangerously-unattended` cannot buy through a +migration/history-rewrite/publish. The `dangerously` prefix mirrors the ecosystem's +`--dangerously-skip-permissions` convention: it means "I accept unattended shipping", +not "I accept unverified code". (Fork §11.4 records the naming choice.) + +### 13.5 abcd obligations the design must also honor + +| Obligation (principle) | What it requires of this build | Tier | +|---|---|---| +| **wired-or-it-isn't-done** | reachable + demonstrated from CLI **and** plugin markdown surface; reviewer-absence degrades loudly (§13.2.3) | MUST | +| **spec-moves-with-the-surface** | land the brief row (`brief/04-surfaces/`) + `surface_coverage` in the same change | MUST | +| **prefer-sota / sota-per-intent** | the loop is itself an intent: carry a `## SOTA` block (the 6 findings + maturity + adopt/seam/bespoke), each having passed the adversarial fit-challenge (this review *is* that) | MUST | +| **guards-prove-themselves** | every STOP condition + the safety guard ships a test watching it refuse (must-pass/must-flag corpus) | MUST | +| **enforcement-claims-are-facts / loud-staging** | don't describe any gate/stop as running until it does; stage unwired parts loudly | MUST | +| **personas Alice/Bob/Carol + they/them** | any example/story in the command or plan template | SHOULD | +| **host-agnostic prose (docs-lint)** | command's user-facing text names no specific harness without the `allow` escape | SHOULD | +| **one-canonical-primitive** | reuse `internal/fsutil` durable-write/frontmatter for the JSON journal; don't fork atomic-write | SHOULD | +| **fix-the-detector** | stop-condition escapes arm a detector with the escaping case as fixture, not hand-patched | COULD | +| **capture→intent, in-progress/claim, priority field, changelog-fragment, NEXT verb** | CLI gaps the loop must work *around* today (derive ordering from `blocked_by_open`; no concurrent claim; fragment tooling is the loop's, not the binary's) | COULD (note as gaps) | + +### 13.6 Net effect on the earlier sections + +§7.4 (review authority) and §10/§11.4 (handoff format) are **amended above**. §2 +(surface + naming), §5–§9 stand. The build surface is now: `commands/abcd/loop.md` +(the ADR-27 host adapter), a run-plan template, the brief-row + `surface_coverage` +registration, `commands/README.md` line, `ACKNOWLEDGEMENTS.md` entries, and STOP/guard +tests — no new dependency, no core change, no binary sub-verb (the seam is host-side). + +## 11. Open decisions for sign-off + +1. **Backlog source default** (§5): support both, default `milestones`? *(rec: yes)* +2. **Budget defaults** (§6): 30 min kept; fan-out cap *(rec ≤6 workers/burst)* + soft + token ceiling *(tune on first run)* — your numbers. +3. **Reviewers** (§7.4, §13.2/§13.3): correctness + security *(rec: declared in plan, + host-delegated, degrade loudly)*; **add the Standards/conventions lens now or + next?** *(rec: next — ship correctness+security first)*; use + `intent-fidelity-reviewer` for the Spec half *(rec: yes, it's repo-committed)*. +4. **Mode + naming** (§13.4): two modes `/abcd:loop` (supervised default) + + `--dangerously-unattended` *(rec)*; reject a literal `--dangerously-skip-gates`. +5. **Command name** (§2): `/abcd:loop` vs `/abcd:run` (ADR-27 vocabulary; avoids + loop-under-`/loop` confusion). *(rec: lean `/abcd:run`, your call)* +6. **Handoff format** (§13.1 A′): resolved — prose Markdown + JSON machine-state split. + Confirm. + +## 14. Blocking discovery — itd-29 already owns this surface (build paused) + +Surfaced at build time, before any command code was written: the autonomous-run +surface is **already planned as itd-29 (`autonomous-run-resilience`, `intents/planned/`)** +and the brief registry **reserves the name `run`** for it (operator-internal; +`status/pause/resume/preflight` v1 cut; no `commands/abcd/run.md` shipped). itd-29: + +- is a **binary** operator surface (`abcd spec start/status/pause/resume/rewind/ship`), + not a host-delegated markdown command; +- is **deliberately deferred** — "failure modes of a system that doesn't yet exist… + design against real evidence, not guesses"; implementation waits on substrate + + revisit triggers; +- already scopes the **out-of-band-merge/chain reconciliation** (this plan's §7.5 — + resolved there as host-owns-git MVP → a future read-only `abcd run reconcile --json`) + and **429/quota** handling (delivered by spc-35); +- names as **revisit trigger #5**: "two consecutive autonomous runs succeed + end-to-end, proving the run seam works" — i.e. exactly the evidence a working loop + generates. + +**Consequence:** this loop is best understood as the **ADR-27 host-workflow engine +over the seam** — the manual precedent itd-29 says must run first — *not* a competing +surface. **Naming decided (maintainer, 2026-07-12): `/abcd:run`** — consciously the +**host-delegated realization of itd-29's surface**, taking its reserved `run` name +rather than inventing a parallel `loop`. Because itd-29's binary operator surface is +deliberately deferred pending real evidence, the sequence is **C→A**: + +- **C (now):** run the loop as a **plan + protocol under the harness loop** (no shipped + command yet) to dogfood on abcd-cli and generate itd-29's evidence (revisit trigger + #5). This ships nothing ahead of evidence — honouring itd-29's own discipline. +- **A (after 1–2 successful runs):** formalise `commands/abcd/run.md` as the + host-delegated realization, reconciled into itd-29 (link the shipped host-workflow + cut; keep the deferred binary verbs — budget preflight, rewind, ship, + `abcd run reconcile --json` — deferred), with its brief row + `surface_coverage`. + +The host-delegated `/abcd:run` v0 does **not** reimplement itd-29's deferred binary +bits; chain reconciliation uses host-side `gh`+`git` (the "host owns the git" MVP +itd-29 already blesses). + +## 12. Scope guard — what this design does NOT do yet + +No skill/command code is written until this design is signed off. Everything above is +design. When approved, the build is one command file plus template + registration + +acknowledgements + guard tests, on one branch/PR, following this repo's commit/PR/ +attribution rules. diff --git a/.abcd/development/research/notes/2026-07-12-autonomous-loop-skill-learnings.md b/.abcd/development/research/notes/2026-07-12-autonomous-loop-skill-learnings.md new file mode 100644 index 00000000..298f278f --- /dev/null +++ b/.abcd/development/research/notes/2026-07-12-autonomous-loop-skill-learnings.md @@ -0,0 +1,194 @@ +# Autonomous hardening loop — learnings + SOTA principles for `/abcd:auto-loop` + +Source: the 2026-07-12 clean-slate hardening run (9 issues fixed/merged in one +session; run log in `.work.local/clean-slate-run-prompt.md`). Purpose: distil what +a *generic* autonomous-loop skill must encode, separated from repo-specific config, +and record where a run-prompt drifts from SOTA. Feeds the proposed `/abcd:auto-loop`. + +## What a generic auto-loop skill owns (vs. what stays repo-specific) + +**Generic (belongs in the skill):** +- The *loop protocol*: STEP 0 discovery/triage → per-item pipeline (fix → gate → + adversarial-verify → PR) → checkpoint → fresh-context handoff → resume. +- Explicit **STOP conditions** (design decision, contract/API change, new dependency, + red gate not self-caused, an "issue" that is really a new feature). +- The **review discipline** (test-first; two-lens adversarial verify; a BLOCK stops + the change) and the **gates** (build/test/lint before every commit). +- The **context/handoff protocol** (the big gap this run hit — see below). +- Merge-pickup mechanics (fetch/prune, ff, delete branch, rebase-forward, re-gate). + +**Repo-specific (must be PARAMETERS the skill takes, not hard-coded):** +- Success criteria / Definition of Done, the gate commands (`make preflight`, + `make record-lint`), the ledger verb (`abcd capture`), branch/PR/commit-trailer + policy, the reviewer agents available, the toolchain. The current run-prompt bakes + these in — a generic skill must lift them into a small config block the caller fills. + +## SOTA assessment (what the run-prompt got right, and gaps) + +SOTA for autonomous coding agents (orchestrator–worker loops, agentic harnesses): +short-lived worker contexts + durable external memory; adversarial/ensemble +verification before commit; deterministic gates over prose; test/detector-first; +bounded autonomy with loud STOP conditions; structured cross-session handoff. + +**Aligned (keep):** +- Detector/test-first with a *watched-fail-then-pass* rule — SOTA and it worked + (every fix pinned; reverts verified). +- **Two-lens adversarial verification** (a correctness reviewer AND an adversarial + security reviewer) — earned its keep repeatedly: the security lens caught THREE + real BLOCKs the correctness pass *and* the tests missed (a same-line secret + cross-leak, a FIFO-leaf hang in a hot hook path, a spec_id validator diverging + from the lint contract). Single-reviewer or tests-only would have shipped them. +- Deterministic gates before every commit; STOP conditions; ledger-as-truth. + +**Gaps vs SOTA (the run-prompt under-specifies these; they caused the failure mode):** +1. **No per-slice context budget → context-window overflow.** The run did ~12 + checkpoints/9 issues in ONE window. SOTA is short-lived contexts: the skill MUST + mandate **one issue per context window, then a genuine fresh-context resume**, not + a same-window continuation. The `ScheduleWakeup` pause must be a handoff boundary. +2. **Unbounded reviewer output.** Each of ~20 review subagents returned full multi-KB + analyses into the main context. SOTA: workers return a **terse structured verdict** + (verdict + only confirmed findings + file:line), not prose. Use a schema. +3. **Whole-file echoes on branch churn.** Switching main↔branch made the harness + re-echo entire 1000+ line files. SOTA: **one branch per session**, minimise + switches, and delegate file-heavy reading to subagents (conclusions only return). + +## Session learnings (operational, hard-won) + +- **Fold the ledger resolve into the fix branch** so an issue auto-resolves on merge + (no trailing chore PR). One-time catch-up PR only for already-merged fixes. +- **CHANGELOG merge conflicts** from parallel fix-PRs: resolve by **merging main into + the branch** (not rebase — avoids force-push, honours the no-force-push rule), keep + both bullets. Root fix is **changelog fragments** (towncrier-style; already iss-24) + so parallel PRs never touch one file — a generic loop over many small PRs needs it. +- `gh pr create` with backticks/`~` in an **inline `--body` gets shell-mangled** — + always `--body-file`. +- A **branch-delete `git push` mid-TDD hits the pre-push gate hook** (runs the full + test suite, which is red mid-TDD) — delete via the host API + (`gh api -X DELETE repos///git/refs/heads/`). +- **Interactive `cp -i` silently declines** in the non-interactive shell — a + restore-after-revert-verify can leave the file in the reverted state; re-apply with + the editor, and re-run gates to confirm restoration. +- **Partial resolution is honest**: a multi-instance issue (iss-30) can land its + clear subset and STAY OPEN with the remainder recorded in DECISIONS.md — do not + fold a false full-resolve. +- **Scope the security fix to the actual invariant**: an over-broad validator that + *diverges from an existing gate* (spec-store anchored id-regex vs record-lint's + prefix rule) is itself a BLOCK — it bricks a lint-green record. Make cooperating + gates agree. + +## Proposed `/abcd:auto-loop` shape (sketch) + +The skill is GENERIC and takes **one argument: a path to a run PLAN doc** under +`.abcd/development/plans/`. That plan (the per-run contract, versioned in the design +record) carries the repo/plan-specific parts: the Definition of Done / success +criteria, the gate commands, the ledger verb, the review agents, the branch/PR/commit +policy, the STOP conditions, and the backlog source. The skill reads the plan and runs +the protocol above with a **hard per-slice budget**: STEP 0 once, then **exactly one +issue per invocation**, ending each turn by writing the handoff and stopping — the +caller (or a scheduled wakeup) re-invokes with a fresh context. Durability lives in +the plan + the ledger + the `NEXT.md` handoff, never in a single long context. (This +also means the run log / learnings should graduate back into the plan or a research +note, not only a gitignored `.work.local` file.) + +## Adversary review — accepted corrections (the verdict above was OVERSTATED) + +An adversary pass challenged the SOTA claims; these corrections stand: + +- **The real root fix is a LEAN ORCHESTRATOR, not "one issue per window."** The + overflow's causes were unbounded reviewer prose and whole-file echoes, not + issue-count. Correct primary principle: **delegate ALL implementation + heavy + reading to workers; the orchestrator holds only structured verdicts + ledger + state** — then many issues per window scale fine. "One issue per window" is a + crude fallback, not the design. (This directly indicts how *this* run was + driven: the main loop did the implementation itself.) +- **Add context compaction/summarisation and RAG-over-the-ledger** — "fresh-context + resume" is the crudest member of that family, not the SOTA one. +- **Two-lens review is not a universal default — RISK-GATE it.** Security lens only + on trust-boundary diffs (secrets/subprocess/network/parsing/auth); docs and + pure-refactor slices should not pay for an adversarial security pass. (This run + already did this partially — iss-72 got ruthless only.) The "caught 3 BLOCKs" + point is suggestive, not a proven base rate (n=1; no count of clean diffs paid + for). +- **Detector-first / gates-over-prose / ledger-as-truth are abcd conventions**, not + established universal SOTA — present them as *our opinionated defaults*, not law. +- **Missing dimensions a generic auto-loop needs:** a per-slice token/cost budget; + an eval of the loop's OWN output quality (revert rate, regression rate, review + turnaround); a kill-switch / rollback path; a human-in-the-loop checkpoint when a + STOP fires; and non-determinism handling (flaky-gate policy, reviewer-disagreement + arbitration). + +**Revised verdict:** the operational learnings are solid, but the SOTA framing was +overstated. The skill's headline principle should be **lean-orchestrator delegation +with bounded worker output + risk-gated review**, with fresh-context handoff as a +safety net, not the main mechanism. + +## Assessment of the candidate generic prompt (Desktop/generic-start-prompt.md) + +**Strong — already ahead of our clean-slate run-prompt on:** +- Two placeholders only ({{PLAN_FILE}}, {{TEST_COMMANDS}}); acceptance criteria live + in the plan. Exactly the generic/plan separation we want. +- **Attempts journal** (write-ahead, survives bursts; never repeat a FAILED approach; + a dangling entry means the prior burst died) — solves cross-burst amnesia; SOTA-grade. +- **Asymmetric marking** (delete completed, keep failed attempts) — avoids NEXT.md drift. +- **changelog.d/ fragments** — structurally removes the CHANGELOG conflicts we hit (our iss-24). +- **Chained milestone branches, merge-commit-only, GitHub auto-retarget** — correctly + reasoned (squash strands the chain + needs a forbidden force-push). +- STOP conditions, GOAL.md read-only, plan-revision-but-not-premise, research-first, TDD + watched-fail, wired-or-dead reporting, paste-real-test-output. + +**Two MATERIAL gaps — both confirmed by this session:** +1. **No lean-orchestrator / delegation mandate → it WILL overflow context on a + multi-milestone burst, exactly as this run did.** The 30-min limit bounds TIME, not + CONTEXT; a burst that implements several milestones itself accumulates the same way. + ADD: "Delegate implementation and file-heavy reading to subagents; the orchestrating + burst holds only conclusions + NEXT.md state. Subagents/reviewers return a TERSE + structured verdict (verdict + confirmed findings + file:line), never full prose." +2. **No adversarial review before the PR — it trusts TDD alone.** This session's TDD + PASSED on three diffs the security reviewer then BLOCKED (same-line secret leak, a + FIFO-leaf hang, a spec_id validator diverging from the lint gate). ADD a RISK-GATED + review step: a correctness (ruthless) reviewer on every non-trivial diff, PLUS an + adversarial security reviewer on trust-boundary diffs only (secrets / subprocess / + network / input-parsing / auth); a BLOCK stops the PR. + +**Minor:** add a per-burst token/cost budget (complements the time bound); a +reviewer-disagreement/flaky-gate arbitration rule; and when it becomes /abcd:auto-loop, +map .work/ → abcd tiers (.abcd/.work.local/NEXT.md, .abcd/development/plans/, +.abcd/work/DECISIONS.md) and optionally source the backlog from the `abcd capture` ledger. + +## Three-reviewer adversarial panel on the prompt (verdicts: mechanics FLAWED · safety UNSAFE · assessment OVERSTATED) + +**MUST-FIX before it becomes /abcd:auto-loop:** +1. (mechanics, high) **Dangling-entry infinite loop**: 3-strikes counts only FAILED + lines; a step that reliably hangs/crashes leaves an outcome-less line treated as + "investigate", never counted → loops forever — the exact wedge the journal exists + to stop. Fix: a died/dangling entry counts toward the strike limit (or 2nd dangling + → STOP). +2. (safety, high) **Irreversible migration ships unattended**: STOP-3 exempts + migrations "part of the plan"; the example M6 IS a backfill migration. Migrations + need a human checkpoint / rehearsed rollback regardless of the plan. +3. (safety, high) **No secret scrub on "paste real test output"** → local paths/tokens + leak into PR bodies (violates our privacy invariant). Redact before pasting. +4. (safety+mechanics+ours) **No adversarial diff review before PR** — green tests + aren't enough (this run: 3 BLOCKs past TDD). Add review with a DEFAULT-ON gate. +5. (mechanics) **Upstream fix can't propagate to an already-branched chain** (rebase + forbidden) → knowingly-broken downstream; and **base-PR-closed-not-merged / unpushed + base** strand the chain. Handle these states (STOP-and-report, don't "move on"). + +**CORRECTIONS to this note's own two headline additions (the panel was right):** +- "Delegate ALL implementation" is WRONG — it breaks TDD watched-fail (orchestrator + asserts red→green it never saw), the orchestrator-local Attempts journal (workers + don't share it → 3-strikes dies), and commit atomicity. CORRECT: delegate read-heavy + exploration and REVIEW to workers (bounded output); the orchestrator still + writes+tests+commits, so it observes watched-fail and owns the journal. The context + fix is bounded worker OUTPUT + delegated READS/REVIEWS, not delegated implementation. +- "Risk-gate the security reviewer" needs a CONSERVATIVE classifier — mis-tagging skips + the lens that caught the real bugs (the same-line secret leak came from a diff nobody + would pre-tag). CORRECT: default-to-review; only pure docs/comment diffs skip; when + unsure, run it. + +**Lower-severity:** free-text item name keys the strike counter (use stable ids); +changelog.d slug collisions are possible (the "structurally impossible" claim is +false); STOP-5 is a whitelist (silent on rm of generated dirs, the "didn't create THIS +burst" loophole, mass codemods); the plan itself is trusted (a harmful plan step runs +unchecked); no token/fan-out budget; NEXT.md written at burst-END is the most +cut-off-prone point; two marking regimes (delete-completed vs Milestones [PR#] ticks) drift. diff --git a/.abcd/work/DECISIONS.md b/.abcd/work/DECISIONS.md index ea49e22a..cc7b464d 100644 --- a/.abcd/work/DECISIONS.md +++ b/.abcd/work/DECISIONS.md @@ -249,3 +249,25 @@ parallel-agent merge contention bites. instances (the larger "ingest test-suite" effort): the --keep-original partial-failure reporting, CRLF parser-parity (parseFrontmatter vs splitFileFrontmatter), and broader URL-ingest/content-type/PDF path coverage. +- 2026-07-12 — /abcd:auto-loop design recorded (plans/2026-07-12-abcd-auto-loop-skill.md, + pending sign-off, not built). SOTA pass (sota-researcher, primary sources) backs the + design: durable handoff + fresh-context resume over compaction/RAG (Anthropic + long-running-harnesses — compaction "isn't sufficient"); delegate reads/reviews but + keep implementation in ONE agent (Cognition "Don't Build Multi-Agents" + Anthropic + multi-agent — converging read/write boundary); reviewers must be a SEPARATE fresh- + context lens, not intrinsic self-review (Huang et al. 2310.01798; CriticGPT + 2407.00215); gate irreversible actions on action-class not self-confidence (RLHF + miscalibration); attempt-journal lineage = Reflexion (NeurIPS 2023) + database WAL. + Rejected: parallel multi-agent implementation, compaction-as-primary-continuity, + RAG-over-ledger at single-milestone scale. +- 2026-07-12 — autonomous-run surface named /abcd:run, taking itd-29's reserved + name as the host-delegated realization of its operator surface (not a parallel + /abcd:loop). Discovery: itd-29 (autonomous-run-resilience, planned) already owns + this surface over the ADR-27 run seam, already scopes out-of-band-merge/chain + reconciliation (host-owns-git MVP → future read-only `abcd run reconcile --json`) + and 429/quota (spc-35), and is deliberately deferred pending real evidence + (revisit trigger #5: two end-to-end autonomous runs). Sequence C→A: run the loop + as a plan+protocol under the harness loop now to dogfood + generate that evidence; + formalize commands/abcd/run.md + brief row + surface_coverage, reconciled into + itd-29, after 1-2 successful runs. Binary operator verbs (budget preflight, rewind, + ship, run reconcile) stay deferred in itd-29. From b3c4e6a826979b3f69cacec4536e952e39f49d45 Mon Sep 17 00:00:00 2001 From: REPPL <77722411+REPPL@users.noreply.github.com> Date: Sun, 12 Jul 2026 15:14:42 +0100 Subject: [PATCH 2/3] docs: add /abcd:run protocol and abcd-cli ledger-drain run-plan The generic run protocol (future commands/abcd/run.md, C-phase draft) plus the first dogfood run-plan draining abcd-cli's open ledger. The protocol encodes lean-orchestrator delegation, a JSON attempt-journal where a dangling entry counts toward the strike limit, advisory review with the deterministic gate as authority, action-class STOP checkpoints, chain-fragility stops, and a secret scrub. The run-plan is backlog:ledger, detector-first, and skips iss-35 (a maintainer design-STOP). Assisted-by: Claude:claude-opus-4-8 --- .../2026-07-12-abcd-cli-ledger-drain-run.md | 82 ++++++++ .../plans/2026-07-12-abcd-run-protocol.md | 179 ++++++++++++++++++ 2 files changed, 261 insertions(+) create mode 100644 .abcd/development/plans/2026-07-12-abcd-cli-ledger-drain-run.md create mode 100644 .abcd/development/plans/2026-07-12-abcd-run-protocol.md diff --git a/.abcd/development/plans/2026-07-12-abcd-cli-ledger-drain-run.md b/.abcd/development/plans/2026-07-12-abcd-cli-ledger-drain-run.md new file mode 100644 index 00000000..3275ecde --- /dev/null +++ b/.abcd/development/plans/2026-07-12-abcd-cli-ledger-drain-run.md @@ -0,0 +1,82 @@ +# Run plan — abcd-cli open-ledger drain (first `/abcd:run` dogfood) + +**Status:** the first C-phase dogfood run of the `/abcd:run` protocol +([`2026-07-12-abcd-run-protocol.md`](2026-07-12-abcd-run-protocol.md)) against +abcd-cli's own open issue ledger. Purpose: shake out the loop mechanics + handoff on +real, self-contained fixes, and generate itd-29's real-evidence (revisit trigger #5). + +Invoke: + +``` +/loop 90m Follow the protocol in .abcd/development/plans/2026-07-12-abcd-run-protocol.md + for the run plan at .abcd/development/plans/2026-07-12-abcd-cli-ledger-drain-run.md. +``` + +## Run contract + +``` +backlog: ledger # abcd capture list --open --json; ready = blocked_by_open empty +gate: make preflight # build + vet + test + race + record-lint + docs-lint + lint-reviews +definition_of_done: per issue — detector-first (fix-the-detector). Arm the issue's + named detector against its stated acceptance corpus, watch it flag, then drain the + fix behind it. The issue's own "Detector"/"Acceptance corpus" lines ARE the bar; a + green gate is only the floor. Fold `abcd capture resolve ` into the fix branch. +ledger_verb: abcd capture +reviewers: + correctness: ruthless-reviewer # every non-trivial diff + security: security-reviewer # trust-boundary diffs (default-on; most of this backlog qualifies) +branch_policy: fix/- from main; merge-commit-only; never force-push; + never commit to main; delete branch after merge (via gh api, not a gate-tripping push) +commit_trailer: Assisted-by: Claude:claude-opus-4-8 +pr_policy: one PR per issue; Closes # only if the ledger issue maps to one; + do not merge; do not enable auto-merge +budget: 30m wall | 6 worker-agents/burst | write NEXT.md + run-journal.json continuously +strike_limit: 3 # failed + died entries combined, keyed on iss-N +stop_conditions: + - An issue is a maintainer DESIGN-STOP / adjudication, not a self-contained fix — + SKIP it (do not autonomously decide it). iss-35 is exactly this: its body records + a design-STOP held for maintainer sign-off (record-lint-graduation adjudication + items 5 & 6). Never "reconcile" or "fix" iss-35 in this run. + - A fix would need a new dependency, a bespoke no-seam solution, a DB migration, or + a CI-config change not already in scope. + - A fix turns out to be a feature/contract change rather than the stated bug. +irreversible: + - none expected in this backlog; if a fix touches persisted-state format or the + schema_version of ledger/spec/memory records, treat as irreversible (human + checkpoint + rollback), even though named here. +``` + +## Ready backlog (snapshot 2026-07-12 — the loop re-queries each burst) + +Self-contained, detector-first fixes, all trust-boundary (security reviewer applies): + +- **iss-29** `fail-closed-capture-surface` (major, bug) — misspelled subcommand writes + a ledger entry; `--json` errors emit raw Go text. Detector: malformed-input + + did-you-mean + `--json` error-shape tests (`unrecognized-input-never-writes`). +- **iss-30** `memory-ingest-boundary` (major, bug) — **partially resolved** (PR #38); + remainder: `--keep-original` partial-failure reporting, CRLF parser-parity, URL / + content-type / PDF coverage. Land the clear subset, keep open with remainder recorded. +- **iss-31** `launch-dogfood-gate` (major, bug) — identity scanner false-positive on + `/dev/null`; launch payload omits `skills/`; unsynchronised `globRegexpCache` (race). + Detector: a `launch --dry-run` dogfood gate + `-race` on the resolver. +- **iss-32** `atomic-write-consolidation` (major, tech-debt) — four divergent + `writeFileAtomic`; `internal/fsutil` untested. Detector: a lint flagging non-canonical + redefinitions + an fsutil crash-safety suite; consolidate behind it + (`one-canonical-primitive`). +- **iss-28** `hermetic-git-test-env` (major, future-work-seed) — larger; a hermetic-git + test helper. Assess scope on pickup; if it is a cross-repo scaffolding feature rather + than a self-contained fix, it may hit the feature/contract STOP — report, don't force. + +## Explicit skips + +- **iss-35** `brief-surface-reconciliation` (critical) — **SKIP.** It is open *only* + for a maintainer design-STOP (record-lint-graduation options + adjudication items 5 + & 6). Not autonomously actionable. + +## Why this is a safe first run + +Every ready item is a self-contained defect with a pre-stated detector + acceptance +corpus, on a repo with a strong deterministic gate (`make preflight`) and merge-commit +history. No irreversible actions expected. The risky/ambiguous items (iss-28, iss-35) +are pre-marked assess-or-skip, so the loop cannot wander into a design decision. This +is the evidence itd-29 asked for before its binary operator surface is designed. diff --git a/.abcd/development/plans/2026-07-12-abcd-run-protocol.md b/.abcd/development/plans/2026-07-12-abcd-run-protocol.md new file mode 100644 index 00000000..6a51ca98 --- /dev/null +++ b/.abcd/development/plans/2026-07-12-abcd-run-protocol.md @@ -0,0 +1,179 @@ +# `/abcd:run` protocol — the generic autonomous-run loop (C-phase draft) + +**Status:** the reusable protocol for the ADR-27 host-workflow run adapter, drawn +from [`2026-07-12-abcd-auto-loop-skill.md`](2026-07-12-abcd-auto-loop-skill.md) (the +design + its abcd review). This is the **generic** half — it takes one argument, a +path to a run PLAN, and the plan carries every repo/run-specific value. In C-phase it +is invoked under the harness loop: + +``` +/loop 90m Follow the protocol in .abcd/development/plans/2026-07-12-abcd-run-protocol.md + for the run plan at . +``` + +In A-phase this file's body becomes `commands/abcd/run.md`, reconciled into itd-29. +Nothing here is repo-specific; if you find yourself hard-coding a gate command or a +reviewer name, it belongs in the PLAN, not here. + +--- + +## ROLE + +You execute the run PLAN in the current repository, autonomously, in timeboxed +bursts, across multiple work items — one PR per item. The human is not at the +machine. Read the repo's `AGENTS.md`/`CLAUDE.md` first; its rules override anything +here. Read the PLAN's `## Run contract` — if any mandatory field is missing or +malformed, **STOP** and report (fail-closed; never guess a gate or policy). + +You are a **lean orchestrator**: you write, test, and commit the code yourself (so +you observe TDD watched-fail, own the attempt journal, and keep commits atomic), and +you **delegate read-heavy exploration and all review to subagents that return a terse +structured verdict** (verdict + confirmed findings + `file:line`), never prose. Do not +delegate implementation. Bound each burst by the PLAN's `budget` (time AND +fan-out/token), stopping cleanly at the first bound reached. + +## RECOVER STATE FIRST (every burst) + +You have no memory of prior bursts. Begin by reading, in this order: + +1. `.abcd/.work.local/NEXT.md` — the prose handoff (current item, branch, chain). +2. `.abcd/.work.local/run-journal.json` — the **machine-state attempt journal** + (JSON, not Markdown — machine-parsed strike state must not be corrupted). Its + shape: `{ "": [ {ts, approach, outcome: "done"|"failed"|null, + note} ] }`. A `null` outcome means the previous burst **died mid-attempt**. +3. The PLAN's backlog source, to pick the next ready item (below). + +Resolve the branch at the start of every burst: on the item's feature branch → stay +on it (the resume case); on the default branch → cut the item's branch; on an +unrelated feature branch with uncommitted work → **STOP** (never touch work you did +not create this burst). + +## PICK THE NEXT READY ITEM + +Per the PLAN's `backlog:`: + +- **`ledger`:** `abcd capture list --open --json`; take the highest-priority item + whose `blocked_by_open` is empty (ready). Its stable id is `iss-N`. +- **`milestones`:** the next undone milestone whose `depends_on` are all merged; its + stable id is `M`, its base is `base`. + +Before starting an item, apply the **skip/stop filter**: if the item is a **design +decision, adjudication, or premise change** rather than a self-contained fix (the PLAN +names how to tell — e.g. a ledger issue whose body records a maintainer design-STOP), +do **not** work it. Record why and move to the next; if none remain, STOP and report. + +## ATTEMPT JOURNAL — write-ahead, JSON, strike-keyed on the stable id + +1. **Before** touching an item, append to `run-journal.json` under its stable id: + `{ts, approach, outcome: null}`. Write this first — if you crash, the null outcome + is the record that you died here. +2. **After** the attempt, set `outcome` to `"done"` or `"failed"` (+ `note`: root + cause / what was ruled out). +3. On burst start, before working an item, count against the PLAN's strike limit + (default 3) **both** `failed` entries **and** `null` (died) entries for that id. At + the limit → **STOP** (you are guessing or reliably crashing). A second consecutive + `null` for the same id is itself a STOP (a reliable hang is not a flake). Never + repeat an approach already recorded `failed`. + +Completed items: delete from NEXT.md's live list (git is the record of what shipped). +Failed/died attempts: keep in the journal (nothing else records what was tried). + +## RESEARCH BEFORE NON-OBVIOUS WORK + +For any non-obvious technique, API, or "best practice" claim: research first (the +`sota-researcher` agent; prefer primary sources), don't implement from memory. Record +the verdict as one dated line in `.abcd/work/DECISIONS.md`. If research contradicts +the PLAN, revise the PLAN's mechanics (not its premise) and say so; a false premise is +a STOP. + +## TDD — you write + test + commit + +Every new behaviour gets a test you **watched fail** before the change and pass after; +every bug fix starts with a failing reproduction. Where the repo follows +detector-first (`fix-the-detector`), that means: arm the detector against the issue's +acceptance corpus, watch it flag, then drain behind it — never hand-fix ahead of the +armed detector. Never skip/mark-flaky/loop-retry/delete a failing test; never +`--no-verify`. Validate external inputs; do not re-validate internal calls. + +After each change run the PLAN's **`gate`** (the deterministic authority). If red: +diagnose the root cause, fix, re-run — up to the strike limit, then STOP. Do not +proceed while the gate is red. + +## REVIEW BEFORE THE PR — advisory verdict, deterministic authority + +When an item's diff is complete and the gate is green, delegate review to +**fresh-context subagents** (never re-read your own diff in-context — intrinsic +self-review does not work): + +- **Correctness** (the PLAN's correctness reviewer) on every non-trivial diff. +- **Security** (the PLAN's security reviewer) on **trust-boundary** diffs — secrets, + subprocess, network, input-parsing, file/DB, auth. Classifier is **conservative: + default-to-review; only pure docs/comment/formatting diffs skip; when unsure, run + it.** + +Each returns `PROMOTE`/`HOLD` + confirmed findings + `file:line`. The **deterministic +gate is the admission authority**, never the reviewer: a `HOLD` pauses the PR — fix +and re-review, or if unresolved at the strike limit, STOP. (A-phase records this as a +fail-closed PROMOTE receipt under `.abcd/work/reviews//`; C-phase treats the +verdict as an advisory gate-and-report.) If a named reviewer is unavailable, **degrade +loudly** — fall back to the repo-committed reviewers + deterministic gates and say so; +never silently skip the lens. + +## GIT, BRANCHES, PR + +- Commit at every atomic unit; conventional prefixes, no scopes; body says WHY; + behaviour-preserving refactors and fixes are separate commits. Follow the PLAN's + `commit_trailer`. Never force-push; never `reset --hard`/`checkout -- .`/`clean` + over work you did not create this burst; never commit to the default branch. +- **Changelog fragment** per user-facing change: `changelog.d/.md` with one + line. **Guard slug collisions** (suffix `-2`, `-3`) — fragments are not immune to + collision. Purely-internal changes get none. +- **Ledger auto-resolve:** fold `abcd capture resolve ` into the fix branch so + the issue resolves on merge (no trailing chore PR). Partial resolution is honest — + land the clear subset, keep the issue open with the remainder recorded. +- **Chained branches** (merge-commit-only; GitHub auto-retargets): item N+1 branches + from N when dependent, else from default. State the chain in the PR body. +- **Chain-fragility → STOP-and-report, never a knowingly-broken chain:** an upstream + fix needed on an already-branched chain (rebase forbidden); a base PR + closed-not-merged; an unpushed base; squash/rebase-merge re-enabled on the repo. +- **PR:** always `gh pr create --body-file` (inline `--body` mangles backticks). + **Scrub the body first** (below). Do not merge, do not enable auto-merge. Then move + to the next item — do not stop. + +## SECRET / PATH SCRUB before anything leaves the machine + +Before any test output, error, or diff enters a PR body, commit, or issue: strip +absolute local paths (→ repo-relative), tokens/keys, real hostnames/usernames/emails, +and any `private-names.txt` match. Reuse the repo's redaction primitive where one +exists (e.g. `abcd history capture` runs a scanner) rather than reimplementing it. + +## STOP CONDITIONS — end the loop (`ScheduleWakeup stop:true`), report, wait for the human + +1. A mandatory PLAN field is missing/malformed, or the PLAN's premise turns out false. +2. A **new dependency** is needed (any new `go.mod`/lockfile entry, incl. dev/test). +3. A **bespoke, no-seam** solution is required (per `sota-per-intent`) — or any DB + migration / CI-config change not explicitly in the PLAN. +4. An **irreversible action** (migration, data backfill, history rewrite, destructive + cutover, dropping/renaming persisted state): **always a human checkpoint**, even if + the PLAN names it — prepare it on a branch, write the exact forward + rollback + commands to NEXT.md, and stop. Gate on the **action class**, never on your + self-rated confidence. `--dangerously-unattended` (if the PLAN sets it) skips only + the per-item human checkpoint — never this one, never a gate, never a review. +5. The strike limit is hit (failed + died) on one item. +6. A chain-fragility state (above). +7. Anything destructive to work you did not create. + +Anything the PLAN adds to this set also stops the loop. + +## HANDOFF — write NEXT.md early and continuously, not only at burst end + +Burst-end is the most cut-off-prone moment. Keep NEXT.md current throughout: current +item + branch + chain; the live next-steps (delete completed); every journal entry has +an outcome before you yield. `run-journal.json` stays valid JSON. Append any +non-obvious decision to `.abcd/work/DECISIONS.md`. + +End the loop only when every item has a PR (or is committed locally with the push +recorded failed), or a STOP fires. Report every PR opened, everything left unpushed or +undone, every item skipped and why. Lead with the outcome; never present partial +success as success; a feature is done only when it is reachable and demonstrably runs +(wired-or-dead); performance claims need numbers. From 09cb28adcb2255928a4448d68f49d6b2dc9f7524 Mon Sep 17 00:00:00 2001 From: REPPL <77722411+REPPL@users.noreply.github.com> Date: Sun, 12 Jul 2026 15:14:42 +0100 Subject: [PATCH 3/3] docs: add local plugin dogfooding runbook A maintainer runbook for dogfooding abcd locally: an always-latest binary wrapper (rebuilds from source each call, fails loudly on a broken build) plus a private local plugin marketplace, and how to iterate. Developer-facing (under .abcd/development/) because it names the agent harness, which the host-agnostic docs/ rule forbids. Assisted-by: Claude:claude-opus-4-8 --- .../notes/2026-07-12-dogfood-abcd-locally.md | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 .abcd/development/research/notes/2026-07-12-dogfood-abcd-locally.md diff --git a/.abcd/development/research/notes/2026-07-12-dogfood-abcd-locally.md b/.abcd/development/research/notes/2026-07-12-dogfood-abcd-locally.md new file mode 100644 index 00000000..3cf91e29 --- /dev/null +++ b/.abcd/development/research/notes/2026-07-12-dogfood-abcd-locally.md @@ -0,0 +1,114 @@ +# Runbook — dogfood abcd locally as a plugin (private, always-latest) + +Maintainer runbook (developer-facing, so it names the harness — unlike `docs/`, +which stays host-agnostic). Goal: install and use abcd yourself from a local +checkout, **without publishing anything**, and have it always track live +development so a broken build shows up immediately. + +abcd has **two halves** and you install both: + +1. the **`abcd` Go binary** the slash-commands shell out to, and +2. the **plugin surface** (`commands/`, `agents/`, `hooks/`) the harness loads. + +## 1. The binary — an always-latest wrapper + +The commands call `abcd` on `PATH`. To make that always the newest source (and to +surface breakage the moment it happens), put a wrapper on `PATH` that rebuilds from +the checkout on every call. `go build` is incremental, so an unchanged call is fast; +a source change that no longer compiles fails loudly here instead of running a stale +binary. + +Wrapper at `~/.local/bin/abcd` (any `PATH` dir works; this file is local machine +setup, never committed — so an absolute checkout path is fine *there*): + +```sh +#!/bin/sh +set -e +REPO= +BIN="${TMPDIR:-/tmp}/abcd-dogfood-bin" +go build -C "$REPO" -o "$BIN" ./cmd/abcd +exec "$BIN" "$@" +``` + +```sh +chmod +x ~/.local/bin/abcd +abcd # from the checkout → the status board; git repo: true +abcd version # from any dir → builds latest, runs it +``` + +Two properties this buys: it works from **any** working directory (it does not rely +on a `go.mod` in the current directory, so it runs against another repo too), and a +red build anywhere in the module stops the wrapper with the compiler error. + +To uninstall: `rm ~/.local/bin/abcd`. For a faster, pinned install instead, use +`make build` and symlink the produced `bin/abcd--` onto `PATH`, or +`abcd ahoy install` — at the cost of manual rebuilds. + +## 2. The plugin — a local, private marketplace + +The repo already declares itself a single-plugin marketplace +(`.claude-plugin/marketplace.json`, `source: "./"`). A filesystem marketplace +publishes nothing. + +In the harness: + +``` +/plugin marketplace add +/plugin install abcd@abcd-marketplace +``` + +Choose **local** scope when prompted (writes `.claude/settings.local.json`, which is +gitignored) to keep it to yourself and out of the repo. User scope +(`~/.claude/settings.json`) also avoids a per-project workspace-trust prompt. + +Confirm it loaded: + +``` +/plugin list +/plugin details abcd +``` + +`commands/abcd/.md` become `/abcd:` (namespaced by the plugin name). + +## 3. Iterating + +- **Binary:** nothing to do — the wrapper rebuilds each call. +- **Command / agent markdown:** a local marketplace is copied to a cache on install, + so edits to the checkout are **not** live until you refresh it: + + ``` + /plugin marketplace update abcd-marketplace + /reload-plugins + ``` + + Command bodies often re-read immediately after the update; agents and hooks need + the reload. + +Because `plugin.json` carries no `version`, the harness treats each commit as a new +version, which suits active development. + +## 4. Testing it on another repo you own + +The point of a host-agnostic core is that abcd manages repositories other than its +own. To exercise that: + +1. From a repo you own that is **not yet abcd-managed**, run + `/abcd:prepare-this-repo` — it refuses on repos you do not own, audits the repo, + then adopts the three-tier `.abcd/` layout and the conventions section. +2. Author a run PLAN under that repo's `.abcd/development/plans/` (the `/abcd:loop` + contract — see the loop's own plan template). +3. Run the loop against it. + +The binary wrapper already works from any directory, so no reinstall is needed to +switch repos — only the target repo's own `.abcd/` scaffold and plan. + +## 5. Gotchas + +- **Cache staleness** is the main friction — after editing commands, run + `/plugin marketplace update` + `/reload-plugins`, or the old copy keeps serving. +- **Wrapper latency** is one incremental `go build` per call (sub-second when + unchanged). Swap for a pinned binary if that ever bites. +- **No remote or commit required** — a working tree on disk is enough; nothing is + pushed. +- **Trust prompt** appears once per project at project scope; user/local scope + sidesteps it.