From 1e1b003650a8a0dbb90d1fead85d225611fc929f Mon Sep 17 00:00:00 2001 From: Justin Forth Date: Sun, 6 Sep 2026 20:23:52 -0600 Subject: [PATCH 01/38] =?UTF-8?q?docs(plan):=20harvest=203=20P4=20?= =?UTF-8?q?=E2=80=94=20the=20github-issues=20axis,=20after=20the=20draft,?= =?UTF-8?q?=20decision=20records,=20hygiene,=20what=20the=20phases=20emit?= =?UTF-8?q?=20(C5=E2=80=93C7,=20C9,=20C10)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5.1 --- ...09-06-harvest-3-p4-axis-records-hygiene.md | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 docs/superpowers/plans/2026-09-06-harvest-3-p4-axis-records-hygiene.md diff --git a/docs/superpowers/plans/2026-09-06-harvest-3-p4-axis-records-hygiene.md b/docs/superpowers/plans/2026-09-06-harvest-3-p4-axis-records-hygiene.md new file mode 100644 index 0000000..ea6feaa --- /dev/null +++ b/docs/superpowers/plans/2026-09-06-harvest-3-p4-axis-records-hygiene.md @@ -0,0 +1,116 @@ +# Harvest 3 — P4: the github-issues axis, after the draft, decision records, hygiene, what the phases emit — Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task, inline, with a checkpoint after each task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Land P4 of harvest 3 — clusters C5 (the github-issues axis), C6 (after the draft opens), C7 (decision records, corrections, multi-surface facts), C9 (supply chain, hygiene, the issue-less branch, the licence) and C10 (what the producing phases emit) — as one PR against `main` that closes #17 #18 #19 #20 #21 #22 #23 #24 #26 #27 #28 #29 #31 #32 #35 #36 #37 #38 #39 #46 #47 #50 #51 #52. + +**Architecture:** Every artifact the exercised runs settled on ships as a **template** (bracketed project block, dated platform claims, reasons at the site): the `.github/` starters, the roadmap, the two review workflows, the dependabot example, the corrections register, the frozen-corpus ingestion pattern, the cascade-events index. Every rule the runs settled on lands **once**, in the conventions template or its reference half, with the surfaces that restate it swept in the same commit (that is the discipline C7 states; this PR instantiates it). The three producing phases gain the emitted sections the runs found missing. Nothing here re-opens P3's contracts beyond the roadmap clause P3 deferred. + +**Register:** the P3 plan inlined every artifact; this plan names each edit and its check and authors the bodies at execution — the executor is this session, the sibling artifacts are read, and the review pass is the same floor. Every task still ends in a green suite and its own commit. + +**Tech Stack:** Markdown, YAML (workflow and issue-form bodies), bash (the verification block). No new scripts. + +**Spec:** `docs/superpowers/specs/2026-09-06-cascade-kit-harvest-3-design.md` § C5, § C6, § C7, § C9, § C10 (read in full before Task 1); § Governing constraints; decisions D22–D27. + +## Global Constraints + +Identical to P3's, restated for the executor: + +- **Sanitized, one-way.** No sibling repository, package, product, issue number or run id lands in kit content (the two public runs are named nowhere; the private instance never). Every lifted body is generalized to bracketed placeholders before it lands. Sibling repositories are read, never modified. +- **Portability greps are the hard gate.** The verification block (`cbk-conventions-reference.md § Verification`, kit sub-block) must be green after every task, extracted and run as in P3: + + ```bash + awk '/^## Verification/{p=1} p' .claude/rules/cbk-conventions-reference.md | awk '/^```bash/{c=1;next} /^```/{c=0} c' > /tmp/claude-1000/cbk-verify.sh && bash -e /tmp/claude-1000/cbk-verify.sh + ``` + + New checks are plain lines inside the single fence; must-be-absent checks use `absent` with a self-splitting literal; positive chains are wrapped `{ … } || { echo …; exit 1; }`. The adr-starters mirror is diffed byte-for-byte against `docs/adr/` — any starter change lands in both. +- **Never commit on `main`; branch and first commit in separate tool calls.** No `[skip ci]`. One commit per task, Conventional Commits, the `Co-Authored-By: Claude Fable 5.1 ` trailer. +- **No unsourced platform claims**: a GitHub or Claude Code behaviour lands with its page and date, or as a dated field observation. The three the issues flag: the required-check path-filter cause (GitHub's troubleshooting page), the check-run rename consequence (field-observed — dated as such), the linguist generated-file list (`generated.rb` and `docs/overrides.md`). +- **Bounded fan-outs.** Task 10's sweep stays at or under 25 planned agents; no research workflow is launched (the research is the issue bodies and the sibling artifacts, already read). +- **Every `SKILL.md` stays under 500 lines** (the block enforces it); every always-loaded rule edit is measured and recorded in the PR body. + +## Decisions taken while planning (for the PR body) + +- **D-P4-1 — the `.github/` starters ship in one reference file** (`scaffold/references/github-starter-templates.md`) with the literal bodies, plus a kit-root `.github/dependabot.yml.example` (the kit itself has only the actions ecosystem; the example carries the floor for it and inactive stubs for the common lockfile ecosystems). The kit does not adopt a PR template or issue forms for itself — the kit's own PRs are `gh pr create --body-file` runs. +- **D-P4-2 — the review workflows are blueprint templates**, not scaffold starters: they need the project block (rules to check, guarded surfaces, docs-only paths, model and effort) that only blueprint knows. Scaffold's PR/review answer gates whether blueprint emits them. +- **D-P4-3 — the roadmap is emitted by blueprint on the github-issues and in-repo-markdown axes** (not on linear, whose projects carry sequence), read by framing, appended by framing, flipped by rough-in and by `/finish` on the PR's own branch as the last commit (P3's deferred clause), with the post-merge checklist as the fallback flip when the spec did not name it. No `/land` command (D23). +- **D-P4-4 — corrections.md is a starter in both homes**: `docs/adr/corrections.md` (the kit's own register, empty) and `scaffold/references/adr-starters/corrections.md` (byte-identical; the block already diffs the two trees). +- **D-P4-5 — the frozen-corpus pattern ships as prose plus a pointer to the ADR hook as the enforcement exemplar**; no `protect-frozen-corpus.sh` ships, because the kit cannot know a corpus path. Scaffold registers the enforcement set when consultation designated a corpus. +- **D-P4-6 — one MCP-configuration section lives in `tooling.md`** (the template), covering committed config with env-var references, the example env file, phase-justified wiring and the list-valued-keys rule; `workflows.md`'s optional cost section names money and agent-run quota separately. +- **D-P4-7 — #47's spike-record method** ("draft → a script asserting the frozen table byte-identical → one adversarial pass → fold") lands as the measurement variant's completeness check, sized to one pass plus a delta, in the spec template, not as a new command. + +--- + +### Task 0: Branch and plan + +- [ ] `git switch main && git pull --ff-only` → `git switch -c feat/harvest-3-p4-axis-records-hygiene` (own tool call) → run the block (baseline: note `always-loaded total:`) → commit this plan: `docs(plan): harvest 3 P4 — the github-issues axis, after the draft, decision records, hygiene, what the phases emit (C5–C7, C9, C10)`. + +### Task 1: The `.github/` starters and the label taxonomy (C5, C9 half) — #19 #36, part of #22 + +**Files:** create `.claude/skills/scaffold/references/github-starter-templates.md`; create `.github/dependabot.yml.example`; modify `scaffold/references/github_only_profile.md` (line 19 citation; § label taxonomy; the `.gitignore` bullet at 77 and checklist clause at 18 — see Task 7), `scaffold/SKILL.md` § Reference files (add the new file and the missing `backends.md` row), `scaffold/references/bootstrap_checklist_template.md` (the "created with README, .gitignore, MIT license" line points at the conventions). + +- [ ] **The starter file**, generalized from the exercised body: a provenance note (the templates were promised and cited at a file that never held them); `bug_report.yml` and `feature_request.yml` as issue **forms** applying the provenance label (`source:github`) and the holding label (`enhancement` for requests; `triage` for bugs) at creation and telling the reporter the issue is not executable as filed; `config.yml` with blank issues **enabled** and the reason (cascade-native bodies); `pull_request_template.md` carrying `## Review gate` and `## Triage` empty with the not-a-`/finish`-run instruction ("mark the lines *not run* with the reason"); `CODEOWNERS` as a routing declaration that enforces nothing without a ruleset; `ci.yml` as a stub with the two promotion traps at its site (no `paths:` on a required check; the job name is the immutable API); `dependabot.yml` with `cooldown` per ecosystem, the three invariants as comments, `groups` as the anti-spam lever, inactive-ecosystem stubs commented in **with the floor** (Task 7's rule: an inactive stub carries the floor so enabling it cannot drop it), and the toolchain-pins-are-not-exempt paragraph. Bracket every project-specific value (ecosystem, directories, username). +- [ ] **The label taxonomy as an axis structure**, in `github_only_profile.md` § label taxonomy (and the one-line summary in `scaffold/SKILL.md`): cascade depth (`cascade-depth:framed`, `cascade-depth:roughed-in`), awaiting cascade work (`enhancement`), provenance (`source:github`, `source:`), type (`bug`, `feature`, `improvement`, `chore`, `documentation`, `tech-debt`), workstream (`workstream:` — created by blueprint when it creates the parent issues, and by framing for a slug blueprint did not), meta (`meta`), review control (`skip-claude`, `claude-review-again`, `claude-fast-review`, `claude-deep-review`), and the optional labour axis (`labour:`; the default lane unlabelled — C10). Scaffold creates the full set; the handoff docs stop naming labels scaffold does not create (`cascade-depth:rough` and `chore` — resolve by creating `chore` and dropping `cascade-depth:rough`). +- [ ] `.github/dependabot.yml.example`: the kit's own example — `github-actions` with the floor, plus commented stubs for `npm`, `pip`, `cargo`, `pub`, `gomod`, `bundler`, `mix`, each carrying `cooldown` so uncommenting cannot drop it; the header names the settle-window section and the three invariants. +- [ ] Checks: the block gains `[ -f .claude/skills/scaffold/references/github-starter-templates.md ]`, a grep that `github_only_profile.md` cites it and no longer cites `scaffold_output_template.md` for the templates, a grep that the starter file's PR template carries `## Review gate` and `## Triage`, and `absent grep -rn "cascade-depth:roug[h]\b" .claude/`. Commit: `feat(scaffold): the .github starters with their bodies — issue forms with provenance and holding labels, the PR template with the gate blocks, CODEOWNERS, the CI stub with its traps, dependabot with the floor; the label taxonomy as an axis structure`. + +### Task 2: The required-checks trap, the always-run lint, rulesets over `gh api` (C5) — #20 #21, #50 (d), #52's deliverable direction + +**Files:** modify `.claude/rules/cbk-conventions.md` § `[skip ci]` rule (the required-checks paragraph; the deliverable trap; § ADR index sync note), `.github/workflows/adr-immutability-check.yml`, `scaffold/references/manual_steps.md`, `scaffold/references/github_only_profile.md:51` (branch protection is not UI-only), `scaffold/references/bootstrap_checklist_template.md:44`, `blueprint/references/templates/standards.md:183`. + +- [ ] Rewrite the trap as **one symptom, three causes**: the CI-skip marker on HEAD (existing); a `paths:`-filtered workflow backing a required check never reports (cite GitHub's troubleshooting page on required checks skipped by path, branch or commit-message filtering; cross-link § Exclusion is not exemption); a promoted check-run's name changing orphans the context (dated field observation, not a documented claim). Rule: a required-check workflow carries no trigger filter and a stable explicit `name:` set before promotion. +- [ ] `adr-immutability-check.yml`: drop the `paths:` filter, name the job explicitly, the reasons as comments at the site; the job still exits 0 in seconds when no ADR changed. +- [ ] `manual_steps.md`: scope the list against **tool availability and preference, never detection state**; the branch-protection entry attempts a ruleset via `gh api repos/{owner}/{repo}/rulesets --method POST` when a `repo`-scoped token exists, wiring `required_status_checks` to the check-run context **read off a real run** (`gh run view`), `strict_required_status_checks_policy` set deliberately with the trap cross-linked, disclosing the result, falling back to the branch-settings UI only when the call fails or no token exists. Sweep `github_only_profile.md:51` and `bootstrap_checklist_template.md:44` in the same commit; `standards.md:183` inherits the always-reports rule. +- [ ] § Deliverable trap gains both directions: a red run whose review posted is a pass, a green run with no comment is a failure; the artifact decides. § ADR index sync notes the lint must be always-run to be a required check. +- [ ] Checks: `absent grep -n "paths:" .github/workflows/adr-immutability-check.yml`; `grep -q "name:" … ` on the job; `absent grep -n "regardless of detection stat[e]" .claude/skills/scaffold/references/manual_steps.md`. Commit: `fix(conventions): the required-checks trap as one symptom with three causes; the ADR lint always runs under a pinned job name; rulesets over gh api with the context read off a real run; the deliverable trap in both directions`. + +### Task 3: The roadmap (C5) and the post-merge checklist (C6) — #35, #50 (a)(b)(c), P3's deferred clause + +**Files:** create `.claude/skills/blueprint/references/templates/roadmap.md`; modify `blueprint/SKILL.md` (emit on github-issues and in-repo-markdown; the outputs list; § Handoff contract), `blueprint/references/blueprint-output-template.md` (the roadmap named), `framing/SKILL.md` § Producing … (the row in the same atomic commit) and `framing/references/planning-backend-commit.md`, `rough-in/references/procedure.md` § Step 6 (the flip), `.claude/commands/finish.md` items 8 and 9 and § What this command does not do, `.claude/commands/finish-procedure.md` Steps 10 and 11 and § What `/finish` does NOT do, both bundled templates (re-spliced byte-parallel), `cbk-conventions.md` § Mutation discipline (a `docs/cbk/ROADMAP.md` row: freely mutable status surface, not the audit trail; the status-surface carve-out sentence naming who flips what) and § Quick reference. + +- [ ] **The template**: line one states the mutation class; `## Now` paragraph; `## The sequence` table (`# | Step | Workstream | What "done" is | Depends on | Status | Where`) with the status vocabulary (*now · planned · framed · roughed-in · in progress · done · horizon · retired*); `## Cascade position`; `## Seeing the same thing from the tracker` with the `gh issue list` queries; who keeps it current, phase by phase, including the `/finish` rule below. +- [ ] **`/finish`**: item 8 gains the roadmap clause — where the project keeps a roadmap and the spec names the flip, the row and the `## Now` paragraph are updated on this branch as the last commit before `gh pr create`, as one `docs(cascade):` commit with no CI-skip marker; the PR number is predicted from the repository's shared issue-and-PR sequence (`gh api 'repos/{owner}/{repo}/issues?state=all&sort=created&direction=desc&per_page=1'` plus one), checked against the number `gh pr create` returns, one correcting commit on mismatch; never a separate PR. § does not do carves out the status surfaces (the roadmap row; a frame's `## Rough-in events` table) from the cascade-artifact ban and names who flips them: in-PR when the spec names it, the post-merge checklist otherwise. Item 9's hand-off ends with the **post-merge checklist**: sync and prune; post the drafted roll-forwards; close the metas the close marker did not; append the frame's rough-in-events row when the PR is a milestone's capstone; flip the roadmap row if it was not flipped in-PR; the next runnable command from the roadmap. The procedure's Steps 10–11 carry the same in procedure form; both bundled templates re-spliced; the block's two byte-parallel checks stay green. +- [ ] Checks: the block gains `[ -f .claude/skills/blueprint/references/templates/roadmap.md ]`, `grep -q 'ROADMAP.md' .claude/rules/cbk-conventions.md`, and a grep that `finish.md` names the roadmap flip and the post-merge checklist. Commit: `feat(cascade): the roadmap — a freely mutable status surface blueprint emits, framing appends, rough-in and /finish flip (on the PR's own branch, last commit, number predicted); the post-merge checklist in the hand-off`. + +### Task 4: Review automation and the `gh` shape (C5, C10 tooling) — #39 #46 #52, #36 (blueprint half) + +**Files:** create `blueprint/references/templates/claude-review.yml` and `claude.yml`; modify `scaffold/references/github_only_profile.md:104` and `scaffold/SKILL.md` (the PR/review question names its consequence and offers "solo-merge with automated review"), `blueprint/SKILL.md` § Foundation document production (tooling step: the skip surfaced as a one-line notice; the workflows emitted when the answer allows; `workstream:` labels created with the parent issues), `blueprint/references/handoff-issue.md` (the `/install-github-app` line conditional; toolchain pins named as bot-uncovered — #22), `blueprint/references/templates/tooling.md` (Q6/Q7 gain the toolchain-pin question — #22), `.claude/rules/tooling.md` § Planning backend (a `gh` row and the "one connection among several" rule) and a new `## Automated review on the git host` section shape pointing at the templates (C10), `blueprint/references/planning-backend-commit.md`, `framing/references/planning-backend-commit.md`, `rough-in/references/planning-backend-commit.md` and the three `planning-backend-matrix.md` § github-issues (a `gh` subsection each: the five commands, the parent-object return, the create-then-edit placeholder pattern as one script; `gh` is the default, the MCP one connection among several; phase skills read and write the working tree by default). + +- [ ] **The two workflow templates**, generalized from the exercised pair with the project block bracketed (the rules to check, the guarded surfaces and their review block, the docs-only paths, the model and effort per label) and the **seven authoring constraints at their sites** as comments: (1) the action cannot review the PR that introduces it — verify on the next PR; (2) no author-controlled input interpolated into `run:` — labels through `env:` as JSON, read as quoted variables; (3) a job-level timeout; (4) the posted artifact is the deliverable in both directions — the prompt makes the summary an explicit `gh pr comment` and names it first; (5) label-driven proportionality (`claude-fast-review`, `claude-deep-review`, `claude-review-again`) that does not re-fire on `synchronize`; (6) permissions scoped to the job; (7) no orphanable sub-dispatch (`--disallowedTools Agent` on the default and fast paths). Plus the two things the run learned: `gh pr checks` is usually unreadable from the action's token — say nothing about CI rather than report the permission error; `track_progress` is unsupported on `labeled` events. Actions pinned to a full SHA with a version comment (the settle-window rule), values bracketed where the project decides. +- [ ] Checks: both templates exist; `grep -c "cannot review the PR that introduces it\|--disallowedTools Agent\|timeout-minutes"` ≥ 1 each; `grep -q "solo-merge with automated review" github_only_profile.md`; `grep -q "create-then-edit" rough-in/references/planning-backend-commit.md`. Commit: `feat(blueprint): the review workflows as templates with their seven constraints at the site; scaffold's review question names its consequence; the gh shape at every planning-backend commit, gh the default and the MCP one connection among several`. + +### Task 5: After the draft opens (C6) — #47 items 1–2, #50 (a), #51 + +**Files:** modify `.claude/commands/finish.md` (item 8: the body is the audit surface for the PR's whole life, a `## Triage — round N` block appended by `/pr-respond`; item 9: the **backward sweep** beside the roll-forward; § tests: the measurement test — "for a measurement issue the verdict rule's commit precedes the first measurement commit, the capstone shows the table unchanged against the base branch, the departures are weighed in the verdict"), `.claude/commands/finish-procedure.md` Step 11 (the backward sweep in procedure form: the closed candidate set — open siblings under the parent carrying `cascade-depth:roughed-in`, one call, capped by the R-count; absence claims only, each verified by running the body's own command; falsified-by-landing separated from false-when-written; default to not reporting; the repair is rough-in's in-place body refresh; an empty sweep is a one-line pass), both bundled templates re-spliced, `.claude/commands/pr-respond.md` Step 7 (append the round's triage to the PR body, not only a comment), `rough-in/references/templates/rough-in-spec-template.md` (the **measurement variant** of § Acceptance criteria and § Done signal: the verdict rule committed before any number exists as the first criterion; the findings table frozen against the base branch; rows as value / method / date; a by-hand completeness checker that never runs in the CI gate; commit order as evidence; the row-verification pass sized to one pass plus a delta), `rough-in/references/contract.md` item 4's Done signal (names the loop **and** the record's completeness check), `.claude/skills/rough-in/references/test_cases.md` (one line in Test 9's criteria). + +- [ ] Checks: `grep -q "Backward sweep\|backward sweep" .claude/commands/finish.md .claude/commands/finish-procedure.md`; `grep -q "verdict rule" .claude/skills/rough-in/references/templates/rough-in-spec-template.md .claude/commands/finish.md`; byte-parallel checks green. Commit: `feat(finish): the PR body is the audit surface for the PR's life; the backward sweep beside the roll-forward; the measurement variant of a spec with the verdict rule committed first`. + +### Task 6: Decision records, corrections, facts stated more than once (C7) — #17 #18 #29 #37 #26 + +**Files:** modify `cbk-conventions.md` § Mutation discipline (the `Extends:` grain with the disambiguation test — removes a permitted reading → Refines; adds an obligation beside a satisfied clause → Extends; the reviewer sentence names Extends and its asymmetry; a `docs/adr/corrections.md` row; a reference-register row; the status cell carries grain and parent inline; a clause-scoped supersession annotates the parent's index row while the file stays untouched) and a new `## Multi-surface facts` section immediately before § ADR index sync (stated once: every restatement records where the fact's other statements live and an edit sweeps every recorded location in one commit; asymmetric back-pointers — the immutable source never points forward, the companion points back; a re-check trigger reachable from the line that fires it; closed sets machine-maintained where the tree can; § ADR index sync reframed as the first instance) with the **companion vocabulary** (immutable source plus append-only companion) and its three instances; create `docs/adr/corrections.md` and `scaffold/references/adr-starters/corrections.md` (identical; header: what it is, what it is not, mutation discipline, the four genres — wrong when written / right then stale / orphaned attribution / defective formula — the entry shape with evidence classed and annotated when its meaning goes stale, "how to add an entry"); modify `docs/adr/template.md` (relation slots: `Supersedes:` / `Refines:` / `Extends:` / `Promotes:`, one line each with the grain's meaning) and its starter mirror, `docs/adr/README.md` (step 6 pointer; a footer pointing at the register) and its mirror, `docs/adr/0000-…md` line 30 (decision revision vs claim correction) and its mirror, `.claude/hooks/protect-immutable-adrs.sh` (the block message names `docs/adr/corrections.md`; the `Allowed:` header lists it), `.claude/skills/adr-new/SKILL.md` (three relationships plus `Promotes:`; the `Extends?` and `Refines?` inputs; defers to the conventions for the sync targets, states no count, names one surface canonical on drift, treats the blueprint stack table as append-only — a one-line bullet only when a stack decision changes; a see-also to the register), `.claude/agents/adr-conformance-reviewer.md` (step 3 follows `Extends:`; the guard's asymmetric case; the register consulted so a flagged-wrong claim is not restated), `.claude/rules/testing.md` (a drift-guard test whose subject is the consistency itself, named as a fourth shape under § Three regimes' quick reference), `pr-review.md`'s sweep clause and `knowledge-backend.md`'s companion-material paragraph point at § Multi-surface facts (the sweep's mirror is already gone), `CLAUDE.md` § Architectural principles (a bullet), create `consultation/references/frozen_corpus_ingestion.md` (trigger: an operator points at a directory of planning material; the freeze discipline — read in full, cite verbatim in `## Pre-cascade sources`, never edit the source; the lazily created `-errata.md` companion — append-only, dated, "amends; never edits"; a `Promotes:` field on a decision lifted from the corpus; the enforcement set scaffold registers — a hook plus a CI job on the ADR pattern with a block message naming the errata, `.gitattributes` `linguist-documentation=false`, editor trim/newline unsets, a formatter skip entry), modify `consultation/SKILL.md` § Incoming context (the directory branch; the reference row), `consultation/references/notion_ingestion.md` (its own scope narrowed to Notion), `consultation/references/problem_brief_template.md` (§ Pre-cascade sources names the corpus path; a `## Handoff notes for later phases` section addressed to scaffold, blueprint, framing, rough-in by name), `scaffold/references/brownfield_audit.md` and `backend_selection.md` (inherit a designated corpus path; land the files and the errata companion; register the enforcement set), `cbk-conventions.md` § Surface inventory (the upstream-docs placeholder points at the pattern). + +- [ ] Checks: `diff -rq docs/adr .claude/skills/scaffold/references/adr-starters` (already in the block) stays green; the block gains `grep -q '^## Multi-surface facts' .claude/rules/cbk-conventions.md`, `grep -q 'Extends:' .claude/rules/cbk-conventions.md .claude/skills/adr-new/SKILL.md .claude/agents/adr-conformance-reviewer.md docs/adr/template.md` (each), `grep -q 'corrections.md' .claude/hooks/protect-immutable-adrs.sh docs/adr/README.md`, `[ -f .claude/skills/consultation/references/frozen_corpus_ingestion.md ]` with the SKILL.md routing to it. Commit: `feat(records): the Extends grain and the relation slots; the corrections register as a starter in both homes; multi-surface facts stated once with the companion vocabulary; the frozen-corpus ingestion pattern; adr-new defers to the conventions for its sync targets`. + +### Task 7: Supply chain, hygiene, the issue-less branch, the licence (C9) — #22 #23 #24 #31 #32 + +**Files:** modify `cbk-conventions-reference.md` § Dependency settle-window (age is necessary, not sufficient — the merged-but-unreleased-fix check, the git-rev pin with a retire trigger, the gated promote-at-registry-version path; toolchain and single-binary pins take the floor by hand with the settled age in the commit and a named tracking mechanism; inactive ecosystem stubs carry the floor; metadata-only lockfile diffs are discarded; a self-merge rule for bot PRs; behaviour deltas in security bumps accommodated narrowly; the `.gitattributes` counter-line rule with linguist's `generated.rb` and `docs/overrides.md` cited and dated, the `rust-lang/rust` precedent, the `text=auto` pre-check recorded inline) and a new `## .gitignore anchoring` section between it and § Methodology (anchor by default; deliberate any-depth entries marked in a comment; per-language sections scoped to the language's directory home once one is declared; a commit body for a `.gitignore` change states its pin assertions; harness transients ignored by anchored path; the note that no shipped reviewer restates this), `cbk-conventions.md` § Branch naming (the issue-less form `/` with the required PR-body statement "operator-directed maintenance; no cascade issue", the scope fence back to § Contribution intake, and the gate line rule: what stands in for the floor on such a PR is written as *not run* with the reason) and a new `## Licensing` section (a recorded choice including "none yet — all rights reserved"; the relicensing constraint at the second contributor; third-party asset licences bind independently; scaffold confirms the licence the way it confirms visibility), `.claude/hooks/protect-main-branch.sh` (the remediation names both branch forms), `blueprint/references/templates/contributing.md` § Branches and `scaffold/references/scaffold_output_template.md` § Working conventions (the issue-less form; a License row in Cascade metadata), `scaffold/references/github_only_profile.md` (Stage 2 licence confirmation; the `.gitignore` bullet at 77 and clause at 18), `scaffold/references/bootstrap_checklist_template.md` (line 20 points at the conventions; the licence row already there), `.claude/agents/cascade-rule-reviewer.md` (scope bullet gains Licensing and .gitignore anchoring), `.claude/rules/pr-review.md` § Pre-filters (the lock-file exclusion presumes the human can see the diff — cross-reference), `.claude/rules/tooling.md` (a `## MCP configuration` section: committed config with env-var references plus an example env file; servers wired by the phase that justifies them; list-valued keys never repeated in the local settings file; linter exclusions only where nothing could be actioned), `.claude/rules/workflows.md` § Cost+scope-explicit (money and agent-run quota named separately). + +- [ ] Checks: the block gains `grep -q '^## Licensing' .claude/rules/cbk-conventions.md`, `grep -q '^## .gitignore anchoring' .claude/rules/cbk-conventions-reference.md`, `grep -q 'short-slug>\` with' .claude/rules/cbk-conventions.md` (the issue-less form), `grep -q 'short-slug' .claude/hooks/protect-main-branch.sh`, `grep -q 'linguist-generated=false' .claude/rules/cbk-conventions-reference.md`. Commit: `feat(conventions): settle-window depth — age is necessary not sufficient, toolchain pins by hand, lockfile diffs kept visible; .gitignore anchoring; the issue-less branch with its PR statement; a licensing section scaffold confirms; MCP configuration in tooling`. + +### Task 8: What the producing phases emit (C10) — #27 #38 #28, the template halves of #26 #35 + +**Files:** create `scaffold/references/templates/cascade-events-index-template.md` (header with the append-only note; `## Index` table `# | Date | Phase | Artifact | Status` seeded with consultation and scaffold rows; `## Phase notes` with execution facts per note and the next runnable command; a `## Non-cascade surfaces` table); modify `scaffold/SKILL.md` § commit order (creates `docs/cbk/README.md` from the template beside `problem_brief.md` and `scaffold.md`) and § Reference files, `framing/SKILL.md` § Producing (check-if-exists, append the row and the note; create only as a brownfield fallback), `framing/references/test_cases.md` lines 12 and 22, `framing/references/inheritance.md` line 17 (the index is always present), the rough-in surfaces that misname the index `framing.md` (`planning-backend-commit.md:68,83`, `planning-backend-matrix.md:103`, `test_cases.md:26,34,80,88,152`) and the appenders' entry shapes reconciled (row plus note; rough-in's compression rationale and departures go in the note), `cbk-conventions.md`/`-reference.md` (§ Cascade artifact layout points at the template; § Mutation discipline's README row and § Quick reference name the creator and the appenders), `blueprint/SKILL.md` § Foundation document production (a canonical home per shared artifact — schema → the data-model ADR, interface → the seam ADR — before drafting, other drafters reference or splice; a cross-document critic on five axes — schema, interface, check names, versions, terminology — required when the drafting fanned out, skipped when one context drafted), `blueprint/references/blueprint-output-template.md` (an append-only `## Amendments` section; a retired-justifications table; a numbered PR lifecycle; a newcomer-traps section gated on the operator's tool comfort; a source-precedence order over non-cascade documents; an operator-runbook directory as a fifth foundation surface; a domain label with a body contract), `blueprint/references/handoff-issue.md` (the credential model extended to credentials not yet held), `framing/references/templates/frame-output-template.md` and `milestone-template.md` (a status column separating deferred metas from framing-time checks; absorbed-issue disposition completed, not cancelled; hard edges versus soft consumes-edges; prior verdicts bind; numbered rough issues naming their criterion; out-of-scope entries with reason and owner or reopen condition; re-sequencing pre-authorized; interface commitments numbered continuously and amendable with a dated note; findings marked as the grounding corpus with single-probe items flagged; deliberate non-decisions; a meta-issue names what does not land in it; orphaned obligations placed and recorded; charters at two blast radii — workstream-wide stays a pre-flight meta, milestone-wide becomes the first R-issue; the fourth spike outcome, retired as unsatisfiable), `framing/references/research-phase.md` and `rough-in/references/research-phase.md` (verdict-first committed corpus; three verdicts with unverifiable kept and labelled; verification targets the specifics; a gaps block; an attempted-URL log; refutations by consequence; usable-versus-raw counts; reproduction as the strongest check; interface over prose; a spec-verification stage — format, grounding, coverage — before the one-way commit; one research agent on the executor's own contract; a design doc's grounding line and anticipated-wrong-fix note; out-of-scope split into deferred and unverified; no-regression criteria name every reason; telemetry verified at its sink), `.claude/rules/tooling.md` § Code intelligence (the built-in LSP tool first-line, enabled by the official per-language plugin plus the language server on `PATH`, the cloud-session caveat; an MCP only for a language without a plugin; `Grep` last; the deferred-integrations table with trigger and expiry; the read-versus-write boundary per data integration) and `cbk-conventions.md` § Surface inventory's tooling line, the three commands' symbol-tooling sentences (`intake.md:33`, `pr-respond.md:73`, `enrich.md:44`), `pr-review.md` § What NOT to flag and `pr-review-reference.md` § anti-patterns (a docs-only PR is not automatically light where the docs are one-way doors — cascade artifacts, ADRs, the conventions). + +- [ ] Checks: the template exists and `scaffold/SKILL.md` cites it; `absent grep -rn "framing\.md index\|framing\.md event" .claude/skills/rough-in/`; `grep -q 'Amendments' blueprint-output-template.md`; `grep -q 'LSP' .claude/rules/tooling.md`; the framing template still carries `## Rough-in events` and `## Pre-flight checks` (existing pins). Commit: `feat(phases): the cascade-events index template scaffold creates and the appenders share; blueprint's canonical homes, critic, amendments and lifecycle sections; the framing template's emitted sections; the research phase's verdict-first corpus; LSP first-line in tooling`. + +### Task 9: Verification pins, indexes, test cases + +- [ ] Fold every check named in Tasks 1–8 into the block (kit sub-block; plain lines; `absent` with split literals). Sweep `CLAUDE.md` § Repo layout (the new templates and references; `docs/adr/corrections.md`) and § Architectural principles (multi-surface facts; the companion vocabulary), `README.md` (the tree; phase 2/3 outputs: the events index, the roadmap, the starters, the review workflows). Test cases: scaffold's `test_cases.md` (the index created; the licence confirmed; the label taxonomy full), blueprint's (the roadmap emitted on the right axes; the critic conditional), framing's (the roadmap row; the index appended not created), rough-in's Test 9 line (the completeness check). Run the block; record `always-loaded total:`. Commit: `chore(kit): verification pins for P4, index and README sweep, test cases`. + +### Task 10: Review pass and the PR + +- [ ] `/simplify` as a skill on `main...HEAD`; triage; Apply commits. Then `pr-review-toolkit:review-pr` (no args) concurrently with `review-sweep` (`base: main`, the changed-path list, no caller finder unless a dimension is missing; ≤ 25 planned) and one direct finder for **platform-claim sourcing** (every GitHub, linguist and Claude Code behaviour the diff asserts carries a page or a dated observation). Triage all; commit per surface. PR body in P3's shape: summary; `Closes` lines for the 24 issues; basis and declined asks (D-P4-1…7; #50's `/land` declined per D23; #19's stale caveat about the review gate, now moot); the review-gate block; the instruction budget; the triage block; the hand-off (the two audit flags from P3 remain; P2's real-dispatch row). `git push -u origin`, `gh pr create --draft --base main --title "feat: harvest 3 P4 — the github-issues axis, after the draft, decision records, hygiene, what the phases emit (C5–C7, C9, C10)"`. + +## Self-review against the spec + +C5 — starters (T1), traps and rulesets (T2), the roadmap (T3), the taxonomy (T1), the review question and notice (T4), the `gh` column (T4), the workflows (T4). C6 — the contract items (T5; three already landed in P3), the backward sweep (T5), the measurement variant (T5), the post-merge checklist and the capstone verdict (T3, T5). C7 — Extends, corrections, companion vocabulary, multi-surface facts, adr-new, the reference-register row and the handoff-notes companion (T6). C9 — settle-window, gitattributes, gitignore, the issue-less branch, licensing, MCP config and the cost line (T7). C10 — the index template, blueprint's sections, the framing template, the research phase, tooling, docs-only review (T8). Every task ends in the block and one commit; every artifact is generalized before it lands; every platform claim carries a source or a date. From e654e949d878d964cbe6ead352787b375dd08275 Mon Sep 17 00:00:00 2001 From: Justin Forth Date: Sun, 6 Sep 2026 20:25:44 -0600 Subject: [PATCH 02/38] =?UTF-8?q?feat(scaffold):=20the=20.github=20starter?= =?UTF-8?q?s=20with=20their=20bodies=20=E2=80=94=20issue=20forms=20with=20?= =?UTF-8?q?provenance=20and=20holding=20labels,=20the=20PR=20template=20wi?= =?UTF-8?q?th=20the=20gate=20blocks,=20CODEOWNERS,=20the=20CI=20stub=20wit?= =?UTF-8?q?h=20its=20traps,=20dependabot=20with=20the=20floor;=20the=20lab?= =?UTF-8?q?el=20taxonomy=20as=20an=20axis=20structure;=20the=20kit's=20dep?= =?UTF-8?q?endabot=20example?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5.1 --- .claude/skills/scaffold/SKILL.md | 4 +- .../bootstrap_checklist_template.md | 2 +- .../references/github-starter-templates.md | 279 ++++++++++++++++++ .../references/github_only_profile.md | 4 +- .github/dependabot.yml.example | 59 ++++ 5 files changed, 344 insertions(+), 4 deletions(-) create mode 100644 .claude/skills/scaffold/references/github-starter-templates.md create mode 100644 .github/dependabot.yml.example diff --git a/.claude/skills/scaffold/SKILL.md b/.claude/skills/scaffold/SKILL.md index 61d8b41..908a5b8 100644 --- a/.claude/skills/scaffold/SKILL.md +++ b/.claude/skills/scaffold/SKILL.md @@ -143,7 +143,7 @@ What gets provisioned depends on the operator's two-axis choice and detection st - **Branch naming**: propose a format based on team identifier from discovery, e.g. `{team-id}-{issue-number}-{short-description}`. Confirm with user. - **Commit format**: propose Conventional Commits as default unless the user has a preference. Confirm. -- **Label taxonomy**: propose the cascade standard set (bug, feature, improvement, tech-debt, documentation) plus area labels derived from the problem brief. Confirm, then walk the user through manual creation. +- **Label taxonomy**: propose the full set as an axis structure — cascade depth, awaiting-cascade-work, provenance, type, workstream, meta, review control, and the optional labour lane (`references/github_only_profile.md` § State 1 step 3 lists every label). Confirm, then create them (`gh label create` when a token exists, otherwise walk the user through the labels page). **HITL gate**: user confirms what was created, walks verification matrix. @@ -320,6 +320,8 @@ Auto-checkable, fires after gate 6 and before scaffold declares itself complete. - `references/linear_planning.md` — provisioning when planning = `linear` - `references/notion_knowledge.md` — provisioning when knowledge = `notion` (hub-row creation, brownfield detection, lazy sub-pages) - `references/brownfield_audit.md` — workspace audit for operators with existing repos / workspaces / Notion structures +- `references/github-starter-templates.md` — the literal `.github/` starter bodies pushed on the github-issues axis (issue forms, `config.yml`, the PR template with the gate blocks, `CODEOWNERS`, the CI stub with its traps, `dependabot.yml` with the floor, the `.gitattributes` counter-line) +- `references/backends.md` — the backend interface mapping for the phase (both axes) - `references/scaffold_output_template.md` — template and worked example for `docs/cbk/scaffold.md` - `references/bootstrap_checklist_template.md` — template for the session checklist - `references/manual_steps.md` — canonical list of always-manual operations diff --git a/.claude/skills/scaffold/references/bootstrap_checklist_template.md b/.claude/skills/scaffold/references/bootstrap_checklist_template.md index 32b67ae..8da7e64 100644 --- a/.claude/skills/scaffold/references/bootstrap_checklist_template.md +++ b/.claude/skills/scaffold/references/bootstrap_checklist_template.md @@ -17,7 +17,7 @@ Resources provisioned via MCP, with links and a one-line description each. Forma ```markdown ## ✅ Completed (via MCP) -- **Repository**: — created with README, .gitignore, MIT license +- **Repository**: — created with README, a `.gitignore` anchored per `cbk-conventions-reference.md` § .gitignore anchoring, and the licence the operator confirmed (`cbk-conventions.md` § Licensing; "none yet" is a valid answer) - **Issue templates**: bug report and feature request templates added under `.github/ISSUE_TEMPLATE/` - **PR template**: added at `.github/pull_request_template.md` - **Scaffold output doc**: committed at `/docs/cbk/scaffold.md` diff --git a/.claude/skills/scaffold/references/github-starter-templates.md b/.claude/skills/scaffold/references/github-starter-templates.md new file mode 100644 index 0000000..ccf38f6 --- /dev/null +++ b/.claude/skills/scaffold/references/github-starter-templates.md @@ -0,0 +1,279 @@ +# GitHub starter templates + +The `.github/` starter files scaffold pushes on the **github-issues** planning axis. `github_only_profile.md` § State 1 step 2 cites this file; `bootstrap_checklist_template.md` lists what landed. + +> **Provenance.** Scaffold promised these files for two harvest passes and cited `references/scaffold_output_template.md` for them — where they never existed; a repo-wide grep for their content returned nothing, so step 2 was an instruction to copy files that were not there. This file holds the literal bodies. Do not re-point the citation without checking the target actually holds them. + +Each block below is the literal file body. Adapt the bracketed parts; leave the structure. The bodies encode rules that live elsewhere and say so at the site — the review-gate block (`.claude/rules/pr-review.md` § The floor), the promotion traps (`cbk-conventions.md` § `[skip ci]` rule), the settle window (`cbk-conventions-reference.md` § Dependency settle-window). + +--- + +## `.github/ISSUE_TEMPLATE/bug_report.yml` + +An issue **form**, not a markdown template, so the labels are applied at creation: the provenance label (`source:github`) is what makes the external-versus-cascade-native distinction queryable, and the holding label (`triage`) says the issue is not executable as filed — `/intake` investigates, reproduces and shapes it (`cbk-conventions-reference.md` § Contribution intake). + +```yaml +name: Bug report +description: Something is broken +labels: ["bug", "source:github", "triage"] +body: + - type: markdown + attributes: + value: | + This lands in triage, not in the cascade. `/intake` investigates it, + reproduces it, and shapes it into a `/finish`-able issue. Describe data + by shape, not contents — no secrets, tokens or raw payloads. + - type: textarea + id: what-happened + attributes: + label: What happened + description: What you observed, and what you expected instead. + validations: { required: true } + - type: textarea + id: repro + attributes: + label: Steps to reproduce + description: The smallest sequence that shows the problem. A failing test beats prose. + placeholder: | + 1. + 2. + 3. + validations: { required: true } + - type: input + id: version + attributes: + label: Version / commit + description: Tag, release, or commit SHA, and where you saw it. + validations: { required: true } + - type: dropdown + id: area + attributes: + label: Affected area + description: Best guess; the cascade's workstreams are the options. + options: + - "[]" + - "[]" + - Unsure + - type: textarea + id: environment + attributes: + label: Environment + description: OS, platform target, device, and anything else that scopes it. +``` + +## `.github/ISSUE_TEMPLATE/feature_request.yml` + +The holding label here is `enhancement` — the awaiting-cascade-work marker `/intake` reads (`cbk-conventions-reference.md` § Contribution intake › Awaiting cascade work). The form tells the reporter which lane the request can take and that it is not `/finish`-able as filed. + +```yaml +name: Feature request +description: Suggest a capability +labels: ["feature", "source:github", "enhancement"] +body: + - type: markdown + attributes: + value: | + `/intake` classifies this as a small capability (enhancement lane, + `/enrich` → `/finish`) or a large one (framing backlog). It is not + `/finish`-able as filed — a clear problem and outcome matter more than + an implementation sketch. + - type: textarea + id: problem + attributes: + label: The problem + description: What you're unable to do today. Describe the problem, not the solution. + validations: { required: true } + - type: textarea + id: outcome + attributes: + label: Desired outcome + description: What "done" looks like from a user's point of view. + validations: { required: true } + - type: textarea + id: proposal + attributes: + label: What you have in mind + description: Optional. A sketch is fine; the design step decides. + - type: textarea + id: alternatives + attributes: + label: What you tried instead + description: Workarounds you've used, and why they fall short. +``` + +## `.github/ISSUE_TEMPLATE/config.yml` + +```yaml +blank_issues_enabled: true +contact_links: + - name: How work is structured + url: https://github.com///blob/main/.claude/rules/cbk-conventions.md + about: Lanes, labels, branch naming — the cascade conventions. + - name: What has been decided and built + url: https://github.com///blob/main/docs/cbk/README.md + about: The cascade events index. +``` + +Keep blank issues **enabled**. Cascade-native issues (`[:F<#>:R<#>]` and the other title forms) are created by the cascade skills with their own bodies; a forced form would corrupt them. + +## `.github/pull_request_template.md` + +The `## Review gate` block is not decoration — `.claude/rules/pr-review.md` § The floor treats a PR body without it as having had **no review pass**, whatever the hand-off claims. Shipping it in the template makes the gate auditable by default rather than by memory. + +```markdown +## Summary + + + +Closes # + +## Review gate + + + +- `/simplify` — +- `pr-review-toolkit:review-pr` — +- `review-sweep` — + +## Triage + + + +- **Apply (0)** — +- **Apply with care (0)** — +- **Surface (0)** — +- **Defer (0)** — +- **Reject (0)** — + +## Notes + + +``` + +## `.github/CODEOWNERS` + +``` +* @ +``` + +Solo default; ask before assuming a team. CODEOWNERS is a **routing declaration** — it enforces nothing on its own. Enforcement is a ruleset requiring Code Owner review (`manual_steps.md` § Repository administration). + +## `.github/workflows/ci.yml` + +A stub only. Real CI is blueprint's job (`blueprint/references/templates/tooling.md`). + +```yaml +name: CI +on: + pull_request: + push: + branches: [main] + +jobs: + check: + # `name:` is the check-run context a ruleset will require. Set it before the job + # is promoted and never rename it afterwards — matching is by name, and a rename + # orphans the required context (cbk-conventions.md § [skip ci] rule, the + # required-checks trap, cause 3). + name: check + runs-on: ubuntu-latest + steps: + - run: echo "CI stub — blueprint wires the real gate" +``` + +**Two traps to respect the moment this job is promoted to a required check** (`cbk-conventions.md` § `[skip ci]` rule): + +1. **A required-check workflow carries no `paths:` filter.** A filtered workflow does not run on a PR that touches nothing matching — the required context never reports, and the PR is blocked on a check that will never arrive. Required checks are always-run by construction; any narrowing happens inside the job as a fast no-op exit. +2. **The check-run name is the immutable API.** Rename the *workflow* if you must, never the job. + +## `.github/dependabot.yml` + +`cbk-conventions-reference.md` § Dependency settle-window is prose; this file is the mechanism. Three invariants are encoded here and must survive edits: + +- **`cooldown` gates version updates only — security advisories still patch immediately.** A platform guarantee, not a convention ("The cooldown option is only available for version updates, not security updates" — `docs.github.com/en/code-security/dependabot/working-with-dependabot/dependabot-options-reference`, read 2026-09-06). Never widen a window to delay a security fix; that is not what the knob does. +- **`groups` is the anti-spam lever; `schedule.interval` is the volume lever.** Raising a floor does not reduce update volume — an update fires on a new release, not on the floor value. +- **Every ecosystem entry carries the floor — including the inactive stubs.** An entry without `cooldown` is a policy violation, not an oversight; a stub that is later uncommented must not be able to drop the floor by omission. + +```yaml +version: 2 +updates: + # ── CI actions ──────────────────────────────────────────────────────────── + # Workflow actions are dependencies too, and a tag ref (`uses: vendor/x@v4`) is + # mutable. Every `uses:` is pinned to a full commit SHA with a trailing version + # comment; this entry maintains those pins under the same floor as everything else. + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" + cooldown: + default-days: 7 # the settle window + groups: + ci-actions: + patterns: ["*"] + applies-to: "version-updates" + open-pull-requests-limit: 3 + commit-message: + prefix: "chore(deps)" + + # ── The project's lockfile-managed ecosystem(s) ─────────────────────────── + # One block per ecosystem with a lockfile in the repo. `directories` names every + # tree that carries one (a workspace with per-package lockfiles needs each path; + # a single "/" covers none of them). + - package-ecosystem: "" + directories: + - "/" + schedule: + interval: "monthly" + cooldown: + default-days: 7 + groups: + prod: + patterns: ["*"] + dependency-type: "production" + applies-to: "version-updates" + dev: + patterns: ["*"] + dependency-type: "development" + applies-to: "version-updates" + open-pull-requests-limit: 5 + commit-message: + prefix: "chore(deps)" + + # ── Inactive stubs carry the floor ──────────────────────────────────────── + # An ecosystem the repo does not use yet stays commented out WITH its cooldown, + # so enabling it later is an uncomment, never a re-derivation of the policy. + # - package-ecosystem: "docker" + # directory: "/" + # schedule: { interval: "monthly" } + # cooldown: { default-days: 7 } +``` + +**Not covered by any bot, and therefore not exempt:** toolchain and single-binary pins (`mise.toml` `[tools]`, `.tool-versions`, `rust-toolchain.toml`, a bare `.nvmrc`), container base-image tags, standalone binaries. They install the compilers that build everything else. Apply the same floor by hand, record the settle evidence in the commit (`" is the newest build clearing the 7-day window as of "`), and name the tracking mechanism (an open question in the frame, or a project automation) — silent exemption is how the highest-privilege dependency surface in the repo ends up unaudited (`cbk-conventions-reference.md` § Dependency settle-window). + +## `.gitattributes` + +Ships only when the repo has a lockfile the settle window audits. The git host marks recognised lockfiles as generated and collapses their diffs — hiding exactly the review the settle-window rule mandates. The rule and its sources are in `cbk-conventions-reference.md` § Dependency settle-window › Keep the lockfile diff visible. + +``` +# Only if the pre-check passes: zero CRLF files in the tree, no prior .gitattributes, +# core.autocrlf and core.eol unset — renormalizing a tree that already holds CRLF +# content rewrites history-visible bytes. Verified . +* text=auto eol=lf + +# Counter-line per audited lockfile the host would collapse (linguist's generated +# list is per-name; check it — the line is harmless where the name is not listed). + linguist-generated=false +``` diff --git a/.claude/skills/scaffold/references/github_only_profile.md b/.claude/skills/scaffold/references/github_only_profile.md index 05c672c..6f88407 100644 --- a/.claude/skills/scaffold/references/github_only_profile.md +++ b/.claude/skills/scaffold/references/github_only_profile.md @@ -16,10 +16,10 @@ MCP can create the repo and push files. Labels, milestones, and project boards * **Via MCP:** 1. **Create the repository.** Use the `create_repository` tool. Inputs: name (derived from problem brief, in kebab-case, confirm with user), visibility (ask: public or private — solo defaults to private, team to whatever the org standard is), initialize with README, add a sensible `.gitignore` for the rough stack the user mentioned in the brief (or skip if no signal), and a license (MIT default for solo, ask for team). -2. **Push starter `.github/` files.** Commit via the file-creation tool: an issue template for bug reports, an issue template for features, a PR template, a `CODEOWNERS` file (single owner = the user, for solo; ask for team), and one CI workflow stub (`.github/workflows/ci.yml`) that runs an empty job — real CI gets configured in blueprint. Templates live in `references/scaffold_output_template.md`. +2. **Push starter `.github/` files.** Commit via the file-creation tool: an issue template for bug reports, an issue template for features, a PR template, a `CODEOWNERS` file (single owner = the user, for solo; ask for team), and one CI workflow stub (`.github/workflows/ci.yml`) that runs an empty job — real CI gets configured in blueprint. The literal bodies live in `references/github-starter-templates.md` — the issue forms (provenance and holding labels applied at creation), `config.yml` (blank issues enabled), the PR template (the `## Review gate` and `## Triage` blocks, empty), `CODEOWNERS`, the CI stub with its promotion traps, `dependabot.yml` with the floor, and the `.gitattributes` counter-line when a lockfile exists. **Manual (generate instructions inline, user completes in browser tabs):** -3. **Create the label taxonomy.** Visit `/labels`. Delete or rename GitHub's auto-generated defaults (`bug`, `enhancement`, etc.) to avoid collisions with the cascade taxonomy, then create the standard set: `bug`, `feature`, `improvement`, `tech-debt`, `documentation`, plus area labels from the brief. Provide the full list with hex colors so the user can copy-paste. +3. **Create the label taxonomy — the full set, as an axis structure.** Visit `/labels` (or run `gh label create` per label when a token exists — the same list either way). Delete or rename GitHub's auto-generated defaults (`bug`, `enhancement`, `question`, …) first so they cannot collide, then create every axis: **cascade depth** — `cascade-depth:rough` (the workstream parent blueprint creates), `cascade-depth:framed`, `cascade-depth:roughed-in`; **awaiting cascade work** — `enhancement` (the transient holding marker `/intake` reads; see `cbk-conventions-reference.md` § Contribution intake); **provenance** — `source:github`, plus one `source:` per external channel the project takes reports from; **type** — `bug`, `feature`, `improvement`, `chore`, `documentation`, `tech-debt`; **workstream** — `workstream:` for every slug the brief already names (blueprint creates the rest when it creates the parent issues; framing creates one for a slug blueprint did not); **meta** — `meta`; **review control** — `skip-claude`, `claude-review-again`, `claude-fast-review`, `claude-deep-review` (read by the auto-review workflow blueprint may emit; harmless when it does not); and the optional **labour** axis — `labour:` only where the project distinguishes lanes, the default lane unlabelled. Every label a handoff doc or template names must be in this set; a label named nowhere is not created. 4. **Create the project board.** Visit `/projects` → "New project". **Template choice**: pick "Board" (basic kanban) unless the user has a reason for another layout — Board is the simplest and maps cleanly to the cascade's issue-state flow. Project name is goal-based and matches the repo name (e.g. "notes-cli"), not date-based. Link the project to the repo. 5. **Skip milestones and issues.** Milestones are planning artifacts that belong in rough-in (phase 5). Issues belong in finish (phase 6). Do not create either in scaffold, even as "starters." diff --git a/.github/dependabot.yml.example b/.github/dependabot.yml.example new file mode 100644 index 0000000..59442f4 --- /dev/null +++ b/.github/dependabot.yml.example @@ -0,0 +1,59 @@ +# Dependency update policy — the kit's own example of the mechanism behind +# .claude/rules/cbk-conventions-reference.md § Dependency settle-window. Copy to +# .github/dependabot.yml in a target project and fill the ecosystem blocks; the +# scaffold starter (.claude/skills/scaffold/references/github-starter-templates.md) +# carries the same body with its reasons. +# +# Three invariants: +# 1. `cooldown` gates VERSION updates only — never security updates (platform +# guarantee: docs.github.com … dependabot-options-reference, read 2026-09-06). +# 2. `groups` is the anti-spam lever; `schedule.interval` is the volume lever. +# 3. Every ecosystem entry — including an inactive stub — carries the floor. +# +# The kit itself has one ecosystem: the actions its workflows use. + +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" + cooldown: + default-days: 7 + groups: + ci-actions: + patterns: ["*"] + applies-to: "version-updates" + open-pull-requests-limit: 3 + commit-message: + prefix: "chore(deps)" + + # Inactive stubs — uncomment the one the project uses; the floor is already there. + # - package-ecosystem: "npm" + # directory: "/" + # schedule: { interval: "monthly" } + # cooldown: { default-days: 7 } + # - package-ecosystem: "pip" + # directory: "/" + # schedule: { interval: "monthly" } + # cooldown: { default-days: 7 } + # - package-ecosystem: "cargo" + # directory: "/" + # schedule: { interval: "monthly" } + # cooldown: { default-days: 7 } + # - package-ecosystem: "pub" + # directory: "/" + # schedule: { interval: "monthly" } + # cooldown: { default-days: 7 } + # - package-ecosystem: "gomod" + # directory: "/" + # schedule: { interval: "monthly" } + # cooldown: { default-days: 7 } + # - package-ecosystem: "bundler" + # directory: "/" + # schedule: { interval: "monthly" } + # cooldown: { default-days: 7 } + # - package-ecosystem: "mix" + # directory: "/" + # schedule: { interval: "monthly" } + # cooldown: { default-days: 7 } From 1cc4f6c7ad51fea933b91b8fe68347f824c3b1e7 Mon Sep 17 00:00:00 2001 From: Justin Forth Date: Sun, 6 Sep 2026 20:26:55 -0600 Subject: [PATCH 03/38] fix(conventions): the required-checks trap as one symptom with three causes; the ADR lint always runs under a pinned job name; rulesets over gh api with the context read off a real run; the deliverable trap in both directions Co-Authored-By: Claude Fable 5.1 --- .claude/rules/cbk-conventions.md | 10 +++++++--- .../skills/blueprint/references/templates/standards.md | 2 ++ .../references/bootstrap_checklist_template.md | 2 +- .../skills/scaffold/references/github_only_profile.md | 2 +- .claude/skills/scaffold/references/manual_steps.md | 6 +++--- .github/workflows/adr-immutability-check.yml | 9 +++++++-- 6 files changed, 21 insertions(+), 10 deletions(-) diff --git a/.claude/rules/cbk-conventions.md b/.claude/rules/cbk-conventions.md index d5595e8..2ace63b 100644 --- a/.claude/rules/cbk-conventions.md +++ b/.claude/rules/cbk-conventions.md @@ -123,13 +123,17 @@ How to avoid: - When `/finish` (or any branch-prep flow) ends with marker-carrying docs commits, **end the branch on a non-marker commit** before flipping to ready. An empty commit (`git commit --allow-empty -m "ci: trigger auto-review workflow"`) is the cleanest fix when no other change is queued. - Order commits so the last one is a code/test commit (which can't carry the marker per the rules above) — when feasible, it removes the foot-gun automatically. -**Deliverable trap — an unattended CI agent's deliverable is the posted artifact, not its exit code.** An auto-review workflow that runs green but posts no comment has failed silently: the run's success condition is its side-effect (the posted review), so the workflow should assert the artifact actually landed — and a green-run-no-comment symptom is investigated as a failure, not shrugged off. +**Deliverable trap — an unattended CI agent's deliverable is the posted artifact, not its exit code, in both directions.** An auto-review workflow that runs green but posts no comment has failed silently: the run's success condition is its side-effect (the posted review), so the workflow should assert the artifact actually landed — and a green-run-no-comment symptom is investigated as a failure, not shrugged off. The converse holds too: a run that ends red *after* posting its complete review has succeeded (an exercised run did exactly that — the exit code was wrong in the direction the first sentence does not cover). The artifact decides; the exit code is evidence, not the verdict. **Exclusion is not exemption — linter-excluded surfaces get their own CI gate.** When a surface is deliberately excluded from the generic linter (a dialect the linter can't parse, generated-but-checked files, a DSL), it still gets a dedicated CI check of its own; otherwise the exclusion quietly becomes a standing exemption from all verification. **Substring trap — quoting the literal marker token in a commit-message body re-triggers the matcher.** GitHub's match is a substring scan across the entire message, not anchored to the subject line or the end. A commit whose body explains *why* it's a fix for this trap, but quotes the literal token while explaining, is itself skipped. Use a paraphrase (e.g., "the CI-skip marker", "the conventional skip-tag") in prose; reserve the literal `[skip ci]` for the actual flag at the end of the subject line where you intend it to fire. -**Required-checks-block-merge trap — a skip-marked HEAD commit can't merge under strict branch protection.** When `main` requires status-check contexts with "require branches to be up to date" (strict), the CI-skip marker suppresses the CI workflow entirely, so those required contexts **never report** — the platform parks them as "Expected — Waiting for status to be reported" and the merge stays blocked indefinitely. (A separate always-on workflow can still run, making the PR *look* green while it stays unmergeable.) Net: `[skip ci]` saves nothing for a PR that has to merge through branch protection. For a docs-only PR bound for `main`, either (a) skip the marker on the final commit so CI runs and reports, or (b) keep the marker on the content commits but end the branch on a non-marker commit (`git commit --allow-empty -m "ci: run gates to satisfy required checks"`) before requesting merge. Same root cause and fix as the auto-review trap; the marker still earns its keep on intermediate WIP commits that don't open a PR to `main`. +**Required-checks-block-merge trap — one symptom, three causes.** Under strict branch protection or a ruleset that requires status-check contexts, a PR parks on "Expected — Waiting for status to be reported" and stays unmergeable indefinitely (a separate always-on workflow can still run, making the PR *look* green). GitHub names the family in its troubleshooting page for required checks — a required check "skipped by path filtering, branch filtering, or a commit message" never reports (`docs.github.com/en/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/troubleshooting-required-status-checks`, read 2026-09-06). The three causes, with the fix at each: + +1. **The CI-skip marker on the HEAD commit** suppresses the workflow, so its required contexts never report. For a docs-only PR bound for `main`, either drop the marker on the final commit so CI runs, or end the branch on a non-marker commit (`git commit --allow-empty -m "ci: run gates to satisfy required checks"`). The marker still earns its keep on intermediate commits that open no PR to `main`. +2. **A `paths:`-filtered workflow backing a required check** does not run on a diff that matches nothing, so its context never reports. A required-check workflow carries **no trigger filter**; any narrowing happens inside the job as a fast no-op exit — § Exclusion is not exemption, applied to trigger filters. The kit's own ADR-immutability lint is written this way for that reason. +3. **A promoted check-run's name changes.** Matching is by name: a job renamed after promotion, or a job with no explicit `name:` whose default shifts, orphans the required context under its old name (a dated field observation, 2026-09-06, from two exercised runs — not a documented platform claim; re-verify against the page above before relying on the exact wording). A job destined for promotion carries an explicit, stable `name:` set *before* promotion; after it, the name is immutable API — rename the workflow, never the job. ## Dependency settle-window — supply-chain discipline @@ -156,7 +160,7 @@ The `adr-new` skill (at `.claude/skills/adr-new/SKILL.md`) automates the cross-i ADR immutability should be enforced two ways: - **A PreToolUse hook** at `.claude/hooks/protect-immutable-adrs.sh` blocks Claude Code edits to existing ADR files -- **A CI lint** at `.github/workflows/adr-immutability-check.yml` diffs `docs/adr/[0-9]{4}-*.md` files in PRs and fails on changes to existing ADRs (closes the raw-git-access gap that the hook can't catch) +- **A CI lint** at `.github/workflows/adr-immutability-check.yml` diffs `docs/adr/[0-9]{4}-*.md` files in PRs and fails on changes to existing ADRs (closes the raw-git-access gap that the hook can't catch). It carries no `paths:` filter and a pinned job name, so it can be a required check — § `[skip ci]` rule, the required-checks trap, causes 2 and 3 Both belong in any project that takes ADRs seriously; the kit's `adr-new` skill assumes both exist. diff --git a/.claude/skills/blueprint/references/templates/standards.md b/.claude/skills/blueprint/references/templates/standards.md index c6031fd..d03fe4f 100644 --- a/.claude/skills/blueprint/references/templates/standards.md +++ b/.claude/skills/blueprint/references/templates/standards.md @@ -180,6 +180,8 @@ The exemption must be specific: name the gate, name the commits or sub-batch, an **When this section appears**: only when blueprint's stack decisions or scaffold's setup added a CI gate that didn't exist on day one of the repo. If the repo had its full CI from the first commit, no bootstrap exemption section is needed. +**A required check always reports**: a workflow promoted to a required check carries no `paths:` trigger filter and a stable, explicit job `name:` set before promotion — a skipped or renamed check parks every PR (`cbk-conventions.md` § `[skip ci]` rule, the required-checks trap); STANDARDS.md states this rule where it lists the gates. + **Surface this proactively**: if blueprint's stack decisions include adding a new gate during this phase (new CI workflow, new pre-commit hook, new required check), the skill should explicitly tell the user at the relevant HITL gate: *"This means the commit that adds can't itself be reviewed by — that's a known bootstrap exemption. I'll document it in STANDARDS.md so it doesn't surprise anyone later."* ## Quality bar calibration diff --git a/.claude/skills/scaffold/references/bootstrap_checklist_template.md b/.claude/skills/scaffold/references/bootstrap_checklist_template.md index 8da7e64..bde76b6 100644 --- a/.claude/skills/scaffold/references/bootstrap_checklist_template.md +++ b/.claude/skills/scaffold/references/bootstrap_checklist_template.md @@ -42,7 +42,7 @@ Steps the user must complete themselves in browser tabs. Each item has an exact These are operations scaffold cannot automate. Do them in browser tabs: -- **Branch protection**: Visit /settings/branches → "Add rule" → branch name pattern `main` → enable "Require pull request before merging" and "Require status checks to pass". Expected outcome: main is protected from direct pushes. +- **Branch protection** (only when scaffold could not create the ruleset over `gh api`): Visit /settings/rules → "New branch ruleset" → target `main` → require a pull request and the status checks by their check-run names (read them off a real run; a `paths:`-filtered or renamed check never reports — `cbk-conventions.md` § `[skip ci]` rule, the required-checks trap). Expected outcome: main is protected from direct pushes. - **Repository secrets** (if needed): Visit /settings/secrets/actions → "New repository secret" for any deployment tokens or API keys. Expected outcome: secrets visible in the secrets list. - **Team member invites** (team only): Visit /settings/access → "Invite a collaborator". Expected outcome: invitees receive email. - **OAuth integrations** (only when planning = `linear` or knowledge = `notion`): see axis-specific instructions in `manual_steps.md`. diff --git a/.claude/skills/scaffold/references/github_only_profile.md b/.claude/skills/scaffold/references/github_only_profile.md index 6f88407..6fc4129 100644 --- a/.claude/skills/scaffold/references/github_only_profile.md +++ b/.claude/skills/scaffold/references/github_only_profile.md @@ -48,7 +48,7 @@ Same flow regardless of detection state. Build the scaffold output doc from `sca ## What this profile does *not* do -- **Does not configure branch protection.** That's an admin operation that requires UI clicks. Add it to the manual instructions section of the bootstrap checklist with a link and recommended settings. +- **Does not configure branch protection without a token.** With a `repo`-scoped `gh` token it creates the ruleset over `gh api` and discloses it (`manual_steps.md` § Repository administration — the check context read off a real run); without one, the bootstrap checklist carries the ruleset-page fallback with the recommended settings. - **Does not set up GitHub Actions beyond a stub workflow file.** Real CI configuration depends on stack decisions that happen in blueprint. - **Does not create the org-level project board.** Even when the user is in an org, scaffold creates a repo-scoped project. Org-level projects are an explicit user request, not a default. - **Does not create milestones, issues, or any planning content.** Milestones belong in rough-in (phase 5), issues in finish (phase 6). Scaffold provisions the *workspace*; planning artifacts come later. diff --git a/.claude/skills/scaffold/references/manual_steps.md b/.claude/skills/scaffold/references/manual_steps.md index b6abb21..3f4cb84 100644 --- a/.claude/skills/scaffold/references/manual_steps.md +++ b/.claude/skills/scaffold/references/manual_steps.md @@ -1,6 +1,6 @@ # Manual steps reference -The canonical list of operations that scaffold **never automates**, regardless of detection state, MCP availability, or user preference. These are operations that either cannot be automated technically (UI-only, OAuth browser flows, billing) or that scaffold deliberately keeps in human hands for safety reasons (admin permissions, security tokens, irreversible workflow customization). +The canonical list of operations that scaffold does not automate. The list is scoped against **tool availability and the operator's preference** — never against detection state: where a tool the session has (a `repo`-scoped `gh` token, a connected MCP) can do the operation and the operator has not asked to keep it in hand, scaffold does it and discloses the result, and the entry below says what it tries first and what the fallback is. The rest are operations that cannot be automated technically (UI-only, OAuth browser flows, billing) or that scaffold deliberately keeps in human hands for safety (admin permissions, security tokens, irreversible workflow customization). When generating manual instructions in the bootstrap checklist's section 2, use this file as the source. Do not invent new manual steps. If the project genuinely needs something not listed here, surface it as an exception and flag the gap. @@ -22,7 +22,7 @@ When generating manual instructions in the bootstrap checklist's section 2, use ### Repository administration -- **Branch protection rules**: Visit `/settings/branches` → "Add branch protection rule" → pattern `main` → enable "Require a pull request before merging" and "Require status checks to pass before merging". For team profiles, also enable "Require approvals" with at least 1 reviewer. Expected outcome: direct pushes to main are rejected. +- **Branch protection (a ruleset)**: **try first** — when a `gh` token with `repo` scope exists, create a ruleset with `gh api repos/{owner}/{repo}/rulesets --method POST` (target `branch`, includes `refs/heads/main`; rules: `pull_request` with the approving reviews the team shape needs — 0 for solo — and `required_status_checks` naming the check-run context **read off a real run** (`gh run view --json jobs` on the stub CI's first run; never guessed from the workflow file), with `strict_required_status_checks_policy` set deliberately — `true` blocks a stale branch and interacts with the CI-skip marker per `cbk-conventions.md` § `[skip ci]` rule, the required-checks trap). Disclose the created ruleset (`gh api repos/{owner}/{repo}/rulesets`). **Fallback** — only when the call fails or no token exists: `/settings/rules` → "New branch ruleset" → target `main` → require a pull request and the status checks by their context names; for team profiles, at least one approving review. Expected outcome: direct pushes to `main` rejected; a PR whose required contexts have not reported cannot merge. - **Reviewer agent-memory**: decided in the bootstrap checklist § Rule-file disposition (`project` = committed, `local` = never committed) and recorded in `cbk-conventions.md` § Surface inventory; with `project`, delete the kit's `.claude/agent-memory/` line from `.gitignore`. - **Repository secrets**: Visit `/settings/secrets/actions` → "New repository secret" for any deployment tokens, API keys, or credentials. Scaffold never handles secret values directly. - **Repository visibility changes**: visibility set at create time. Changing later is at `/settings` → "Danger Zone". Scaffold never changes visibility after creation. @@ -33,7 +33,7 @@ When generating manual instructions in the bootstrap checklist's section 2, use - **Linear workflow state customization** (when planning = `linear`): Visit `https://linear.app//settings/teams//workflow` → customize states. Linear ships with sensible defaults (Backlog → Todo → In Progress → In Review → Done) which scaffold recommends keeping unchanged for the first few cycles. - **GitHub Projects custom fields**: Visit the project board → "..." → "Settings" → "Custom fields". Scaffold creates the board with default fields only; custom fields are user-added later if needed. -- **GitHub Actions workflows beyond the stub**: scaffold creates an empty CI workflow file as a structural placeholder. Real CI configuration depends on stack decisions that happen in blueprint, so it's deliberately deferred. +- **GitHub Actions workflows beyond the stub**: scaffold creates the CI stub as a structural placeholder and, with the operator's PR/review answer allowing it, blueprint emits the review workflows (`blueprint/references/templates/claude-review.yml`, `claude.yml`); the ADR-immutability lint ships with the ADR starters. Real CI gates depend on stack decisions that happen in blueprint, so they are deferred there — not to the operator. ### Enterprise-only operations diff --git a/.github/workflows/adr-immutability-check.yml b/.github/workflows/adr-immutability-check.yml index c1d92f5..02224df 100644 --- a/.github/workflows/adr-immutability-check.yml +++ b/.github/workflows/adr-immutability-check.yml @@ -6,14 +6,19 @@ name: ADR immutability check # `docs/adr/[0-9]{4}-*.md` file has been modified (additions of new ADR # files are allowed; deletions and modifications are not). +# No `paths:` filter, on purpose: a required check that is skipped by a path +# filter never reports and parks the PR forever (cbk-conventions.md § [skip ci] +# rule, the required-checks trap, cause 2). The job exits 0 in seconds when no +# ADR changed, so always-run costs nothing. on: pull_request: branches: [main] - paths: - - 'docs/adr/**' jobs: immutability: + # The check-run context a ruleset requires. Pinned before promotion and never + # renamed afterwards — matching is by name (the trap's cause 3). + name: ADR immutability runs-on: ubuntu-latest steps: - name: Checkout PR branch From e6ca6db6b330bee8a4e18a4d4e8a2731d8b7e148 Mon Sep 17 00:00:00 2001 From: Justin Forth Date: Sun, 6 Sep 2026 20:28:50 -0600 Subject: [PATCH 04/38] =?UTF-8?q?feat(cascade):=20the=20roadmap=20?= =?UTF-8?q?=E2=80=94=20a=20freely=20mutable=20status=20surface=20blueprint?= =?UTF-8?q?=20emits,=20framing=20appends,=20rough-in=20and=20/finish=20fli?= =?UTF-8?q?p=20(on=20the=20PR's=20own=20branch,=20last=20commit,=20number?= =?UTF-8?q?=20predicted);=20the=20post-merge=20checklist=20in=20the=20hand?= =?UTF-8?q?-off?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5.1 --- .claude/commands/finish-procedure.md | 6 ++- .claude/commands/finish.md | 6 +-- .claude/rules/cbk-conventions.md | 4 +- .claude/skills/blueprint/SKILL.md | 6 ++- .../references/blueprint-output-template.md | 3 ++ .../blueprint/references/templates/roadmap.md | 54 +++++++++++++++++++ .../references/planning-backend-commit.md | 4 ++ .../rough-in/references/finish-command.md | 6 +-- .../rough-in/references/finish-procedure.md | 6 ++- .../skills/rough-in/references/procedure.md | 2 +- 10 files changed, 86 insertions(+), 11 deletions(-) create mode 100644 .claude/skills/blueprint/references/templates/roadmap.md diff --git a/.claude/commands/finish-procedure.md b/.claude/commands/finish-procedure.md index c065a40..68eb1b8 100644 --- a/.claude/commands/finish-procedure.md +++ b/.claude/commands/finish-procedure.md @@ -183,6 +183,8 @@ The principle for Steps 8–9: **the executor handles findings the codebase need - **Defer (N)** — ` — conflicts with `. - **Reject (N)** — one-line dismissal. + **The roadmap row, before `gh pr create`** — where the project keeps `docs/cbk/ROADMAP.md` and the spec names the flip: update the row and `## Now` on this branch as the last commit (`docs(cascade):`, no CI-skip marker — it is HEAD at the flip), with the PR number predicted from the shared issue-and-PR sequence (`gh api 'repos/{owner}/{repo}/issues?state=all&sort=created&direction=desc&per_page=1'` plus one) and checked against the number `gh pr create` returns; one correcting commit on a mismatch; never a separate PR (the contract, item 8). + If `gh pr create --draft` fails (auth, missing scope, draft PRs disabled, rate limit, PR already exists for this branch), stop and surface the failure with per-step status. ## Step 11: Hand off @@ -201,6 +203,8 @@ If any finding was classified **Defer** because it would conflict with an ADR or **Optional learning-runbook write to Notion** (only when knowledge backend = `notion` is configured for this repo, per `.cascade/backends.toml`): if this execution surfaced a learning that would be a useful durable cross-project runbook entry (e.g., a non-obvious gotcha with the stack, a recipe for a recurring task spanning repos, a corrected understanding of an external system's behavior), prompt the operator: *"Want to promote this learning to a Notion runbook page under the Engineering Wiki? Defaults to SKIP."* Defaults to **SKIP**. Per `.claude/rules/knowledge-backend.md` § "When to write" — this is the rare opt-in path; HITL-gated; never default. If the operator opts in, announce the planned write (title, parent, body preview) before committing. This step is gated to genuinely cross-project learnings only — local-to-the-PR observations stay in the PR body and the hand-off summary, not in Notion. +**Post-merge checklist** (the hand-off ends with it; the operator runs it after the merge): `git switch main && git pull --ff-only && git fetch --prune`; post the drafted roll-forwards; close the meta-issues the close marker did not; append the frame's `## Rough-in events` row when this PR was the milestone's capstone; flip the roadmap row if Step 10 did not; the next runnable command, read off the roadmap. A research milestone's capstone is the verdict artifact — name it and its owner. + Do not call `gh pr ready` and do not merge — those remain the user's calls. The user's draft-review pass is where Surface findings get decided; they can ask you to apply any of them in the PR-feedback-loop turn, or wave them through. ## What `/finish` does NOT do @@ -209,7 +213,7 @@ Do not call `gh pr ready` and do not merge — those remain the user's calls. Th - **Does not handle re-rough-in.** Surface the need and return to chat for the rough-in skill. - **Does not auto-create dependent issues.** If the work reveals a missing sub-sub-issue, surface and return to chat for rough-in. - **Does not bypass dependencies.** Refuse to proceed when dependencies are unmet. -- **Does not modify cascade artifacts** (`docs/cbk/blueprint.md`, `docs/cbk/frame-NN.md`, etc.). Those are produced by chat-skill cascade phases. +- **Does not modify cascade artifacts** (`docs/cbk/blueprint.md`, `docs/cbk/frame-NN.md`, etc.). Those are produced by chat-skill cascade phases. *The status surfaces are carved out: `docs/cbk/ROADMAP.md`'s row and a frame's `## Rough-in events` table are not cascade events; Step 10 flips the row on this branch when the spec names it, the post-merge checklist otherwise (the contract wins where the two differ).* - **Does not modify ADRs.** ADRs are immutable once accepted; revisions happen via new ADRs that supersede the old (chat-skill territory, not `/finish`). - **Does not make workstream-level or framing-level decisions.** Those belong to upstream cascade phases (blueprint, framing, rough-in). - **Does not skip `/simplify` or `pr-review-toolkit:review-pr`.** The simplify and review passes both run before the PR opens; the simplify pass is non-negotiable per `docs/STANDARDS.md` § Step 4, and the review-toolkit findings are auto-triaged with the four-class rubric (Apply for correctness/validity/defensive; Surface for taste/style; Defer/Reject for conflicts and agent errors). The one exception is an explicit break-glass marker (Step 1), which waives exactly the `pr-review-toolkit:review-pr` half and is recorded on that skill's `## Review gate` line. The orchestrated sweep supplements the two skills and never substitutes for either. diff --git a/.claude/commands/finish.md b/.claude/commands/finish.md index b472b23..fa8354c 100644 --- a/.claude/commands/finish.md +++ b/.claude/commands/finish.md @@ -32,8 +32,8 @@ This command is contract-first. On 2026-09-03 an A/B gave two workhorse-tier exe 5. **Atomic commits** in Conventional Commits form with the workstream's scope: the red tests, the implementation, each simplify Apply, each review Apply — one focused commit each, never amended across a logical boundary, never squashed on the branch. The squash happens at merge on the base branch. No code or test commit carries the CI-skip marker (`cbk-conventions.md` § `[skip ci]` rule). 6. **The gate, green.** The project's `check` task passes before simplify and review run, and again after every applied finding. Unrelated red is surfaced, not muted — never skipped, expected-failed or commented out to pass. 7. **The review floor, actually run, with the bounded sweep beside it, then triage — once.** First **`/simplify`**, as a skill invocation; triage its findings by the four-class rubric and land its Apply items one commit each with `check` re-run after each. Then, **concurrently**: **`pr-review-toolkit:review-pr`** with no arguments, as a skill invocation, and — where a multi-agent orchestration surface exists — **the review workflow** (`.claude/workflows/review-sweep.js`), sized to the diff and never to the session's effort setting, with the pre-filtered changed-path list passed as `files`. The project-local reviewers ride in it from the roster the workflow reads at runtime (`.claude/rules/pr-review.md` § Project-local agents); beyond them you name the finders this diff needs — none on a small single-surface change the two skills already cover, several on a cross-layer one — and the workflow logs its planned agent count before it finds anything and returns its own gate line. Without an orchestration surface, dispatch the project-local reviewers directly and record `skipped — no orchestration surface` on the sweep's line. The sweep supplements the two skills and never substitutes for either. Triage waits for both to return and stays with you (`pr-review.md` § Triage rubric; the reference half's calibration read at triage): Apply and Apply-with-care land as their own commits with `check` re-run; Surface, Defer and Reject are recorded, never applied. A skill that is uninstalled or errors is a stop-and-surface. A skill that runs without its agent fan-out because the Agent tool is unavailable in your context counts as invoked, and its dropped dimensions are recorded on its `## Review gate` line — never described as equivalent. A failed review agent is dropped coverage, not zero findings. **Describing a review is not running one**: a claimed invocation that did not happen fails this contract outright. The floor runs when the known work is complete and is not run again on a later delta — the reviewer round on the flip covers that, and `/pr-respond` answers it. -8. **A draft PR** on the pushed branch: title in Conventional Commits with the workstream's scope; body with the planning axis's close marker (`Closes #$1` on github-issues, `Closes $1` on linear — in the body, not only the title; `cbk-conventions.md` § Closes-keyword conventions); a summary of what changed and why, with the ADRs, frame milestone and rules it relies on; a **`## Review gate`** block, written before `## Triage`, in the shape `.claude/rules/pr-review.md` § The floor states — one line each for `/simplify`, `pr-review-toolkit:review-pr` and the sweep, each stating run-or-not with counts and dropped coverage, a waived skill on its line with the break-glass reason, the sweep's line transcribed from the record the workflow returns; a **`## Triage`** block listing every finding under its class — Apply and Apply-with-care as `SHA: fix`, Surface and Defer with the agent's verbatim rationale, Reject with a one-line dismissal; and any review block or label the project's conventions require when the diff touches a surface they guard. A docs commit that would be HEAD at the flip carries no CI-skip marker (`cbk-conventions.md` § Auto-review trap). The body's close markers name every issue the run resolves — a pre-flight meta-issue the work settles as well as `$1`. The PR is never flipped to ready and never merged by this run; both are the operator's. -9. **A hand-off** that stands on its own: the PR URL; the triage counts in one line; the three `## Review gate` lines verbatim — an invocation the transcript does not show was not made; the Surface and Defer entries verbatim; every operational criterion still open with what the operator must do; the one next action; an offer to post roll-forward context wherever it is relevant — the next issue, a sibling, a meta-issue, a new follow-up — post-merge unless it blocks another issue's start; an offer to sweep the open sibling issues for absence claims this run made false. Deferred conflicts with an ADR lead the hand-off. A learning that should outlive the PR is offered to the knowledge backend only where one is configured, HITL-gated and default-skip (`.claude/rules/knowledge-backend.md` § When to write); otherwise it goes into a rule file or an ADR. +8. **A draft PR** on the pushed branch: title in Conventional Commits with the workstream's scope; body with the planning axis's close marker (`Closes #$1` on github-issues, `Closes $1` on linear — in the body, not only the title; `cbk-conventions.md` § Closes-keyword conventions); a summary of what changed and why, with the ADRs, frame milestone and rules it relies on; a **`## Review gate`** block, written before `## Triage`, in the shape `.claude/rules/pr-review.md` § The floor states — one line each for `/simplify`, `pr-review-toolkit:review-pr` and the sweep, each stating run-or-not with counts and dropped coverage, a waived skill on its line with the break-glass reason, the sweep's line transcribed from the record the workflow returns; a **`## Triage`** block listing every finding under its class — Apply and Apply-with-care as `SHA: fix`, Surface and Defer with the agent's verbatim rationale, Reject with a one-line dismissal; and any review block or label the project's conventions require when the diff touches a surface they guard. **The roadmap row rides this branch, as its last commit before the PR** — where the project keeps `docs/cbk/ROADMAP.md` and the spec names the flip: after the floor (item 7) and before `gh pr create`, the row for this step and the `## Now` paragraph are updated to cite this issue and this PR — *done* when this is the milestone's last R-issue, the progress note otherwise — as one `docs(cascade):` commit with no CI-skip marker (it is HEAD at the flip, and the marker would suppress the auto-review and the required checks — `cbk-conventions.md` § Auto-review trap). The PR number is the next in the repository's shared issue-and-PR sequence (`gh api 'repos/{owner}/{repo}/issues?state=all&sort=created&direction=desc&per_page=1'` plus one) and is checked against the number `gh pr create` returns; a mismatch is one correcting commit. Never a separate PR: a one-row flip with its own PR costs a CI run for nothing, and a flip committed after `gh pr create` costs the same run on the open PR. The row reads *done* on this branch while the PR is open; it reaches the base branch only through this PR, which is what makes it true. Where the spec did not name the flip, the post-merge checklist (item 9) flips it. Any other docs commit that would be HEAD at the flip carries no CI-skip marker either. The body's close markers name every issue the run resolves — a pre-flight meta-issue the work settles as well as `$1`. The PR is never flipped to ready and never merged by this run; both are the operator's. +9. **A hand-off** that stands on its own: the PR URL; the triage counts in one line; the three `## Review gate` lines verbatim — an invocation the transcript does not show was not made; the Surface and Defer entries verbatim; every operational criterion still open with what the operator must do; the one next action; an offer to post roll-forward context wherever it is relevant — the next issue, a sibling, a meta-issue, a new follow-up — post-merge unless it blocks another issue's start; an offer to sweep the open sibling issues for absence claims this run made false. Deferred conflicts with an ADR lead the hand-off. The hand-off ends with the **post-merge checklist** the operator runs after the merge: sync and prune (`git switch main && git pull --ff-only && git fetch --prune`); post the roll-forwards the hand-off drafted; close the meta-issues the close marker did not; append the frame's `## Rough-in events` row when the PR is a milestone's capstone; flip the roadmap row if this run did not (item 8); and the next runnable command, read off the roadmap. A research milestone's capstone is the verdict artifact, owned by name in the checklist. A learning that should outlive the PR is offered to the knowledge backend only where one is configured, HITL-gated and default-skip (`.claude/rules/knowledge-backend.md` § When to write); otherwise it goes into a rule file or an ADR. ## The tests every finish must pass @@ -50,4 +50,4 @@ This command is contract-first. On 2026-09-03 an A/B gave two workhorse-tier exe ## What this command does not do -It does not modify the issue body, re-rough-in, create dependent issues, bypass dependencies, modify cascade artifacts or ADRs, make workstream- or framing-level decisions, skip either skill of the floor (the break-glass marker waives exactly the toolkit half, recorded), run the floor twice, flip the PR to ready, merge, or respond to auto-review comments (that is `/pr-respond`). It does not write to the knowledge backend as a side effect of anything above. +It does not modify the issue body, re-rough-in, create dependent issues, bypass dependencies, modify cascade artifacts or ADRs — the **status surfaces** are carved out of that ban: `docs/cbk/ROADMAP.md`'s row and a frame's `## Rough-in events` table are not cascade events, and item 8 says who flips them (this run, on its own branch, when the spec names the flip; the post-merge checklist otherwise) — make workstream- or framing-level decisions, skip either skill of the floor (the break-glass marker waives exactly the toolkit half, recorded), run the floor twice, flip the PR to ready, merge, or respond to auto-review comments (that is `/pr-respond`). It does not write to the knowledge backend as a side effect of anything above. diff --git a/.claude/rules/cbk-conventions.md b/.claude/rules/cbk-conventions.md index 2ace63b..f492dc5 100644 --- a/.claude/rules/cbk-conventions.md +++ b/.claude/rules/cbk-conventions.md @@ -177,13 +177,14 @@ Both belong in any project that takes ADRs seriously; the kit's `adr-new` skill | `docs/cbk/frame-NN.md` | **Append-only for `## Rough-in events` table**; otherwise immutable post-commit | Re-framing creates `frame-MM.md` with `Supersedes: frame-NN` field; old frame's status → "Superseded" | Frames are cascade events; rough-in events are the timeline log | | `docs/cbk/frame-MM.md` (additive increment) | **New file** (next sequential number); the prior frame is not mutated and stays `Active` | *No* supersession — an additive increment carries a `Builds on: frame-NN` header (not `Supersedes`); both frames stay `Active` and their open milestones coexist | Not every new framing replaces: an increment extends a workstream whose prior milestones are still valid and open, so the prior frame must not flip to `Superseded` (see the framing skill's `references/procedure.md` § Step 2 pattern D) | | `docs/cbk/frame-MM.md` (milestone-scoped re-frame) | **New file** (next sequential number); the prior frame is not mutated | Header states `Supersedes only milestone M of frame-NN`; the prior frame's index status is annotated `Active (M superseded by frame-MM)` via the permitted status-column mutation; the retired milestone's acceptance-criteria set is recorded as retired-un-executed in the new frame | One milestone's shape can fail while its siblings are built and Done; whole-frame supersession would falsify the siblings' history (see the framing skill's `references/procedure.md` § Step 2 pattern E) | +| `docs/cbk/ROADMAP.md` (github-issues and in-repo-markdown axes) | **Freely mutable** — a status surface, not a cascade event | n/a — a wrong row is fixed in place; a superseded row reads *retired* | Where we are and what is next; blueprint writes it, framing appends rows in the frame's commit, rough-in flips to *roughed-in*, `/finish` flips to *done* on the PR's own branch or the post-merge checklist does (`commands/finish.md` item 8). The audit trail is the index and git history, never this file | | `docs/cbk/README.md` | **Append-only for new entries**; status column updates allowed | Status updates are mutations to single column, not whole-file rewrites | Status changes (Active → Superseded → Completed) need to flow | | `docs/STANDARDS.md`, `docs/ARCHITECTURE.md`, `CLAUDE.md` | **Freely mutable** | n/a — living docs | Project-context docs evolve with the project; git history is the version archive | | `.claude/rules/*.md` | **Freely mutable** | n/a | Operational rules; mutations are routine | | `.claude/skills/*` | **Freely mutable** within the local copy | n/a | Tooling content; mutations refine the cascade | | Code | **Freely mutable** | n/a | Standard code evolution | -Cascade events being append-only is structurally important: the cascade IS the audit trail of decisions. A new framing supersedes an old one with a new file; the old one stays in `docs/cbk/` for future readers to understand "we used to think X, now we think Y." +Cascade events being append-only is structurally important: the cascade IS the audit trail of decisions. **Two status surfaces are carved out of the executor's cascade-artifact ban** — the roadmap row and a frame's `## Rough-in events` table — because they record state, not decisions; the row above and `commands/finish.md` item 8 say who flips them and when. A new framing supersedes an old one with a new file; the old one stays in `docs/cbk/` for future readers to understand "we used to think X, now we think Y." **The table and the hook registry are two views of one list.** A row enforced by a hook names it: ADRs → `protect-immutable-adrs.sh` (plus the CI lint); lock files → `protect-lock-files.sh`. A hook that enforces a rule clause rather than a table row names the clause: `protect-main-branch.sh` → § Branch naming; `require-repo-root-for-agents.sh` and `detect-forked-agent-memory.sh` → `pr-review.md` § Reviewer precedent memory (one home for the memory tree); `guard-pr-state.sh` → the PR-state one-way door in `cbk-conventions-reference.md` § HITL gate load-bearing heuristics; `require-knowledge-backend-ok.sh` → `knowledge-backend.md` § HITL announcement discipline. Rows with no hook (the append-only cascade artifacts, the index's status column) are instruction-enforced and carry a deferred-hardening note per § HITL gate load-bearing heuristics. The registry in `.claude/settings.json` lists the same hooks under their tiers, and the verification block checks the registry against the files. The authoring shape lives in `cbk-conventions-reference.md` § Hook authoring. **ADR supersession has more than one grain.** The `docs/adr/*` row above shows whole-ADR supersession; two finer-grained relationships sit alongside it, both preserving the parent's immutability (neither edits the parent file): @@ -215,6 +216,7 @@ Cascade events being append-only is structurally important: the cascade IS the a |---|---| | Naming a cascade event | Flat `docs/cbk/.md`, sequential numbering | | Updating the cascade-events index | `docs/cbk/README.md` (status column) | +| Flipping the roadmap row | `docs/cbk/ROADMAP.md` — framing appends, rough-in flips to *roughed-in*, `/finish` flips to *done* on the PR's own branch (`commands/finish.md` item 8) or the post-merge checklist does | | Naming a planning-backend issue | `[:F<#>:R<#>] ` | | Naming a branch | `/--` | | Closing an issue from a PR | `Closes -N` (Linear) or `Closes #N` (GitHub) in PR body | diff --git a/.claude/skills/blueprint/SKILL.md b/.claude/skills/blueprint/SKILL.md index 48a6e24..8721658 100644 --- a/.claude/skills/blueprint/SKILL.md +++ b/.claude/skills/blueprint/SKILL.md @@ -185,6 +185,7 @@ Blueprint produces six prose foundation docs plus tooling configs. The order is | 4 | CONTRIBUTING.md | root | Branch/commit/PR norms — mostly inherits from scaffold.md, lighter lift | | 5 | README.md update | root | Updates the existing README with stack info; do not rewrite from scratch | | 6 | docs/cbk/blueprint.md | docs/cbk/ | The cascade artifact — written last so it can reference all the others | +| 7 | docs/cbk/ROADMAP.md | docs/cbk/ | On the `github-issues` and `in-repo-markdown` axes only: the freely mutable status surface (`references/templates/roadmap.md`) — where we are and what is next; seeded from § Core Projects with every row *planned* and the bootstrap row pointing at the handoff issue | **Plus tooling configs** (not prose docs, real config files): - CI workflow files in `.github/workflows/` @@ -233,7 +234,7 @@ Detailed templates and production guidance: Blueprint's behavior differs along **two independent axes** set by scaffold: the planning backend (`github-issues` / `linear` / `in-repo-markdown`) and the knowledge backend (`notion` / `none`). The per-axis differences are documented in `references/planning-backend-matrix.md` (planning axis) and `.claude/rules/knowledge-backend.md` (knowledge axis). Short version: **Planning axis** (read `references/planning-backend-matrix.md` for full detail): -- `github-issues`: all foundation docs + `blueprint.md` commit to the GitHub repo via MCP; workstream parent Issues created via GitHub MCP; no Linear initiative entity. Methodology selection is informational only. +- `github-issues`: all foundation docs + `blueprint.md` + `ROADMAP.md` commit to the GitHub repo (`gh` or the git-host MCP — `references/planning-backend-commit.md`); workstream parent Issues created with their `workstream:` labels; no Linear initiative entity. Methodology selection is informational only. - `linear`: foundation docs + `blueprint.md` still commit to GitHub; `blueprint.md` also mirrors as a Linear initiative; Linear Projects created per workstream via Linear MCP. Methodology selection may inform Linear cycle length. - `in-repo-markdown`: only the markdown commits happen; no external planning entities are created. Setup steps that would be a GitHub handoff issue (or Linear initiative description) move into `blueprint.md` § Manual setup. @@ -283,6 +284,7 @@ When blueprint is complete, framing inherits: - **Six foundation docs** at known locations, all reviewed and committed - **Tooling configs** in `.github/workflows/` and the appropriate task runner location - **`docs/cbk/blueprint.md`** containing stack decisions, methodology selection, success criteria, workstreams, dependencies, not-in-scope, and open questions +- **`docs/cbk/ROADMAP.md`** on the `github-issues` and `in-repo-markdown` axes — framing reads it as an input and appends its rows in the same atomic commit as the frame - **All prior cascade artifacts** still readable: `problem_brief.md`, `scaffold.md` **What blueprint must not pass to framing**: actual project plans (that's framing), milestones (rough-in), issues (finish), or implementation code. Blueprint stops at "workstreams with one-sentence purpose each" — turning workstreams into project plans is framing's job. @@ -320,6 +322,8 @@ Auto-checkable, fires after the final gate and before blueprint declares itself ## Reference files +- `references/templates/roadmap.md` — the `docs/cbk/ROADMAP.md` template (github-issues and in-repo-markdown axes): the sequence table, the `## Now` paragraph, the status vocabulary, the tracker queries, and who flips what + - `references/planning-backend-commit.md` — the Milestone-per-workstream creation step, atomic transition pattern with the markdown commit, slug collision handling, profile-aware behavior (read this in tandem with `backends.md` from the cascade meta-doc set) - `references/inheritance.md` — how to read scaffold.md and problem_brief.md, what to extract, edge cases diff --git a/.claude/skills/blueprint/references/blueprint-output-template.md b/.claude/skills/blueprint/references/blueprint-output-template.md index 032ec4a..5998e1b 100644 --- a/.claude/skills/blueprint/references/blueprint-output-template.md +++ b/.claude/skills/blueprint/references/blueprint-output-template.md @@ -201,6 +201,9 @@ Earlier versions of this template had a "Manual setup runlist" section with the ## Planning-axis-aware behavior +On the `github-issues` and `in-repo-markdown` axes blueprint also writes `docs/cbk/ROADMAP.md` from `templates/roadmap.md`, seeded from § Core Projects: one *planned* row per project, the bootstrap row pointing at the handoff issue, `## Now` naming the first runnable command. It is a status surface, freely mutable, never the audit trail. + + **`github-issues` planning**: this file is the *only* place the initiative content lives. There's no Linear initiative entity. Framing will read this file, decompose the workstreams into proper project specs, and create the GitHub workstream parent Issues + framing sub-issues from there. **`linear` planning**: this file still gets committed to `docs/cbk/blueprint.md`, AND a Linear initiative entity gets created via Linear MCP with the same Goal, Success Criteria, Not In Scope, and Dependencies content. The file is the source of truth; the Linear entity is a queryable mirror. Framing reads the file; Linear is for human navigation and roll-up reporting. diff --git a/.claude/skills/blueprint/references/templates/roadmap.md b/.claude/skills/blueprint/references/templates/roadmap.md new file mode 100644 index 0000000..89c6bb2 --- /dev/null +++ b/.claude/skills/blueprint/references/templates/roadmap.md @@ -0,0 +1,54 @@ +# Roadmap template — `docs/cbk/ROADMAP.md` + +Emitted by blueprint on the **github-issues** and **in-repo-markdown** planning axes (on `linear`, the planner's projects carry the sequence). It answers the question those axes otherwise cannot: *where are we, and what is next* — issues carry the detail, labels carry state, a saved filter shows a pool, but none of them shows the order the work happens in or which step is current. Framing reads it as an input and appends a row per milestone in the same atomic commit as the frame; rough-in flips a row to *roughed-in*; `/finish` flips a row to *done* on the PR's own branch (`.claude/commands/finish.md` item 8) or the post-merge checklist does. The kit's conventions record its mutation class (`cbk-conventions.md` § Mutation discipline). + +## The template + +```markdown +# Roadmap — where we are, where we are going + +**A living status surface, freely mutable** (unlike the cascade events index, which is append-only). Read it first when returning cold; the issue it points at has the detail. **Who keeps it current:** blueprint wrote it; **framing** adds a row per milestone it cuts and links the `F` issue, in the same commit as the frame; **rough-in** flips a row to *roughed-in* and links the `R` issues; **`/finish`** flips a row to *done* and links the PR — on the PR's own branch, as the last commit before the PR opens, with the PR number read ahead from the repository's shared issue-and-PR sequence and checked at creation (`.claude/commands/finish.md` item 8), or the post-merge checklist flips it when the spec did not name the flip. An `R` issue short of the milestone's capstone updates the row's progress note and the `## Now` paragraph the same way. Anything else that changes the sequence — a milestone re-cut, a horizon item pulled forward — edits the table in the same PR. A row that is wrong is fixed in place; this is not an audit trail (that is `docs/cbk/README.md` and git history). + +## Now + +**Step <#> — , .** `, `rough-in `, `framing `); what is blocked and on what.> **▶ Next: .** + +## The sequence + +Ordered by dependency, not by preference. + +| # | Step | Workstream | What "done" is | Depends on | Status | Where | +|---|---|---|---|---|---|---| +| 0 | **Bootstrap** — | — | | blueprint merged | planned | | +| 1 | **** — | `` | | 0 | planned | | +| 2 | … | | | | | | + +**Status vocabulary**: *now* · *planned* (blueprint only) · *framed* (an `F` issue exists) · *roughed-in* (`R` issues exist, `/finish`-able) · *in progress* (a branch is open) · *done* (merged — or written by `/finish` on the merging PR's own branch, per the paragraph above) · *horizon* (tracked, no timeline) · *retired* (superseded; say by what). + +## Cascade position + +| Phase | State | +|---|---| +| consultation | done — `problem_brief.md` | +| scaffold | done — `scaffold.md` | +| blueprint | done — `blueprint.md`, the ADRs, the foundation docs, the tooling | +| framing | ` framed (`frame-NN.md`) · …> | +| rough-in | | +| `/finish` | | + +## Seeing the same thing from the tracker + +```bash +gh issue list --state open --label 'cascade-depth:framed' # milestones cut, not yet roughed-in +gh issue list --state open --label 'cascade-depth:roughed-in' # /finish-able now +gh issue list --state open --label enhancement # shaped by /intake, awaiting cascade work +gh issue list --search 'Blueprint handoff in:title' # step 0 +``` +``` + +## Authoring guidance + +- **One row per step the sequence needs to show**, not per issue: a workstream's milestones are rows once framing cuts them; before that the workstream is one *planned* row pointing at its blueprint entry. +- **`## Now` is a paragraph, not a table** — it carries the narrative a returning reader needs (what landed, what is next, what is blocked), with links; keep it current every time a row flips. +- **On `in-repo-markdown`** the `## Seeing the same thing from the tracker` section is dropped and the `Where` column points at the markdown issue records. +- **Never let the roadmap become the audit trail**: a superseded row reads *retired — superseded by *; the events index and git history hold what happened. diff --git a/.claude/skills/framing/references/planning-backend-commit.md b/.claude/skills/framing/references/planning-backend-commit.md index b056495..d636901 100644 --- a/.claude/skills/framing/references/planning-backend-commit.md +++ b/.claude/skills/framing/references/planning-backend-commit.md @@ -41,6 +41,10 @@ Framing constructs each sub-issue's body from one of two templates depending on Section heading names from both templates are preserved verbatim — do not rename, reorder, or omit sections that the templates provide. Adding additional sections after the template-provided ones is permitted if the capability or meta-issue has content that doesn't fit the standard sections. +### The roadmap row (github-issues and in-repo-markdown axes) + +Where `docs/cbk/ROADMAP.md` exists, the markdown half of the transition also appends one row per milestone to § The sequence (status *framed*, `Where` linking the `F` issue) and updates `## Now` — in the **same commit** as `frame-NN.md` and the index row, never a separate one. The roadmap is a status surface (`cbk-conventions.md` § Mutation discipline); a row that is wrong is fixed in place. + ## Atomic transition pattern (two-step per sub-issue) Framing's planning-backend commit uses GitHub's two-step sub-issue creation: diff --git a/.claude/skills/rough-in/references/finish-command.md b/.claude/skills/rough-in/references/finish-command.md index 5231dee..df05454 100644 --- a/.claude/skills/rough-in/references/finish-command.md +++ b/.claude/skills/rough-in/references/finish-command.md @@ -115,8 +115,8 @@ This command is contract-first. On 2026-09-03 an A/B gave two workhorse-tier exe 5. **Atomic commits** in Conventional Commits form with the workstream's scope: the red tests, the implementation, each simplify Apply, each review Apply — one focused commit each, never amended across a logical boundary, never squashed on the branch. The squash happens at merge on the base branch. No code or test commit carries the CI-skip marker (`cbk-conventions.md` § `[skip ci]` rule). 6. **The gate, green.** The project's `check` task passes before simplify and review run, and again after every applied finding. Unrelated red is surfaced, not muted — never skipped, expected-failed or commented out to pass. 7. **The review floor, actually run, with the bounded sweep beside it, then triage — once.** First **`/simplify`**, as a skill invocation; triage its findings by the four-class rubric and land its Apply items one commit each with `check` re-run after each. Then, **concurrently**: **`pr-review-toolkit:review-pr`** with no arguments, as a skill invocation, and — where a multi-agent orchestration surface exists — **the review workflow** (`.claude/workflows/review-sweep.js`), sized to the diff and never to the session's effort setting, with the pre-filtered changed-path list passed as `files`. The project-local reviewers ride in it from the roster the workflow reads at runtime (`.claude/rules/pr-review.md` § Project-local agents); beyond them you name the finders this diff needs — none on a small single-surface change the two skills already cover, several on a cross-layer one — and the workflow logs its planned agent count before it finds anything and returns its own gate line. Without an orchestration surface, dispatch the project-local reviewers directly and record `skipped — no orchestration surface` on the sweep's line. The sweep supplements the two skills and never substitutes for either. Triage waits for both to return and stays with you (`pr-review.md` § Triage rubric; the reference half's calibration read at triage): Apply and Apply-with-care land as their own commits with `check` re-run; Surface, Defer and Reject are recorded, never applied. A skill that is uninstalled or errors is a stop-and-surface. A skill that runs without its agent fan-out because the Agent tool is unavailable in your context counts as invoked, and its dropped dimensions are recorded on its `## Review gate` line — never described as equivalent. A failed review agent is dropped coverage, not zero findings. **Describing a review is not running one**: a claimed invocation that did not happen fails this contract outright. The floor runs when the known work is complete and is not run again on a later delta — the reviewer round on the flip covers that, and `/pr-respond` answers it. -8. **A draft PR** on the pushed branch: title in Conventional Commits with the workstream's scope; body with the planning axis's close marker (`Closes #$1` on github-issues, `Closes $1` on linear — in the body, not only the title; `cbk-conventions.md` § Closes-keyword conventions); a summary of what changed and why, with the ADRs, frame milestone and rules it relies on; a **`## Review gate`** block, written before `## Triage`, in the shape `.claude/rules/pr-review.md` § The floor states — one line each for `/simplify`, `pr-review-toolkit:review-pr` and the sweep, each stating run-or-not with counts and dropped coverage, a waived skill on its line with the break-glass reason, the sweep's line transcribed from the record the workflow returns; a **`## Triage`** block listing every finding under its class — Apply and Apply-with-care as `SHA: fix`, Surface and Defer with the agent's verbatim rationale, Reject with a one-line dismissal; and any review block or label the project's conventions require when the diff touches a surface they guard. A docs commit that would be HEAD at the flip carries no CI-skip marker (`cbk-conventions.md` § Auto-review trap). The body's close markers name every issue the run resolves — a pre-flight meta-issue the work settles as well as `$1`. The PR is never flipped to ready and never merged by this run; both are the operator's. -9. **A hand-off** that stands on its own: the PR URL; the triage counts in one line; the three `## Review gate` lines verbatim — an invocation the transcript does not show was not made; the Surface and Defer entries verbatim; every operational criterion still open with what the operator must do; the one next action; an offer to post roll-forward context wherever it is relevant — the next issue, a sibling, a meta-issue, a new follow-up — post-merge unless it blocks another issue's start; an offer to sweep the open sibling issues for absence claims this run made false. Deferred conflicts with an ADR lead the hand-off. A learning that should outlive the PR is offered to the knowledge backend only where one is configured, HITL-gated and default-skip (`.claude/rules/knowledge-backend.md` § When to write); otherwise it goes into a rule file or an ADR. +8. **A draft PR** on the pushed branch: title in Conventional Commits with the workstream's scope; body with the planning axis's close marker (`Closes #$1` on github-issues, `Closes $1` on linear — in the body, not only the title; `cbk-conventions.md` § Closes-keyword conventions); a summary of what changed and why, with the ADRs, frame milestone and rules it relies on; a **`## Review gate`** block, written before `## Triage`, in the shape `.claude/rules/pr-review.md` § The floor states — one line each for `/simplify`, `pr-review-toolkit:review-pr` and the sweep, each stating run-or-not with counts and dropped coverage, a waived skill on its line with the break-glass reason, the sweep's line transcribed from the record the workflow returns; a **`## Triage`** block listing every finding under its class — Apply and Apply-with-care as `SHA: fix`, Surface and Defer with the agent's verbatim rationale, Reject with a one-line dismissal; and any review block or label the project's conventions require when the diff touches a surface they guard. **The roadmap row rides this branch, as its last commit before the PR** — where the project keeps `docs/cbk/ROADMAP.md` and the spec names the flip: after the floor (item 7) and before `gh pr create`, the row for this step and the `## Now` paragraph are updated to cite this issue and this PR — *done* when this is the milestone's last R-issue, the progress note otherwise — as one `docs(cascade):` commit with no CI-skip marker (it is HEAD at the flip, and the marker would suppress the auto-review and the required checks — `cbk-conventions.md` § Auto-review trap). The PR number is the next in the repository's shared issue-and-PR sequence (`gh api 'repos/{owner}/{repo}/issues?state=all&sort=created&direction=desc&per_page=1'` plus one) and is checked against the number `gh pr create` returns; a mismatch is one correcting commit. Never a separate PR: a one-row flip with its own PR costs a CI run for nothing, and a flip committed after `gh pr create` costs the same run on the open PR. The row reads *done* on this branch while the PR is open; it reaches the base branch only through this PR, which is what makes it true. Where the spec did not name the flip, the post-merge checklist (item 9) flips it. Any other docs commit that would be HEAD at the flip carries no CI-skip marker either. The body's close markers name every issue the run resolves — a pre-flight meta-issue the work settles as well as `$1`. The PR is never flipped to ready and never merged by this run; both are the operator's. +9. **A hand-off** that stands on its own: the PR URL; the triage counts in one line; the three `## Review gate` lines verbatim — an invocation the transcript does not show was not made; the Surface and Defer entries verbatim; every operational criterion still open with what the operator must do; the one next action; an offer to post roll-forward context wherever it is relevant — the next issue, a sibling, a meta-issue, a new follow-up — post-merge unless it blocks another issue's start; an offer to sweep the open sibling issues for absence claims this run made false. Deferred conflicts with an ADR lead the hand-off. The hand-off ends with the **post-merge checklist** the operator runs after the merge: sync and prune (`git switch main && git pull --ff-only && git fetch --prune`); post the roll-forwards the hand-off drafted; close the meta-issues the close marker did not; append the frame's `## Rough-in events` row when the PR is a milestone's capstone; flip the roadmap row if this run did not (item 8); and the next runnable command, read off the roadmap. A research milestone's capstone is the verdict artifact, owned by name in the checklist. A learning that should outlive the PR is offered to the knowledge backend only where one is configured, HITL-gated and default-skip (`.claude/rules/knowledge-backend.md` § When to write); otherwise it goes into a rule file or an ADR. ## The tests every finish must pass @@ -133,4 +133,4 @@ This command is contract-first. On 2026-09-03 an A/B gave two workhorse-tier exe ## What this command does not do -It does not modify the issue body, re-rough-in, create dependent issues, bypass dependencies, modify cascade artifacts or ADRs, make workstream- or framing-level decisions, skip either skill of the floor (the break-glass marker waives exactly the toolkit half, recorded), run the floor twice, flip the PR to ready, merge, or respond to auto-review comments (that is `/pr-respond`). It does not write to the knowledge backend as a side effect of anything above. +It does not modify the issue body, re-rough-in, create dependent issues, bypass dependencies, modify cascade artifacts or ADRs — the **status surfaces** are carved out of that ban: `docs/cbk/ROADMAP.md`'s row and a frame's `## Rough-in events` table are not cascade events, and item 8 says who flips them (this run, on its own branch, when the spec names the flip; the post-merge checklist otherwise) — make workstream- or framing-level decisions, skip either skill of the floor (the break-glass marker waives exactly the toolkit half, recorded), run the floor twice, flip the PR to ready, merge, or respond to auto-review comments (that is `/pr-respond`). It does not write to the knowledge backend as a side effect of anything above. diff --git a/.claude/skills/rough-in/references/finish-procedure.md b/.claude/skills/rough-in/references/finish-procedure.md index 4b2d735..2f07533 100644 --- a/.claude/skills/rough-in/references/finish-procedure.md +++ b/.claude/skills/rough-in/references/finish-procedure.md @@ -194,6 +194,8 @@ The principle for Steps 8–9: **the executor handles findings the codebase need - **Defer (N)** — ` — conflicts with `. - **Reject (N)** — one-line dismissal. + **The roadmap row, before `gh pr create`** — where the project keeps `docs/cbk/ROADMAP.md` and the spec names the flip: update the row and `## Now` on this branch as the last commit (`docs(cascade):`, no CI-skip marker — it is HEAD at the flip), with the PR number predicted from the shared issue-and-PR sequence (`gh api 'repos/{owner}/{repo}/issues?state=all&sort=created&direction=desc&per_page=1'` plus one) and checked against the number `gh pr create` returns; one correcting commit on a mismatch; never a separate PR (the contract, item 8). + If `gh pr create --draft` fails (auth, missing scope, draft PRs disabled, rate limit, PR already exists for this branch), stop and surface the failure with per-step status. ## Step 11: Hand off @@ -212,6 +214,8 @@ If any finding was classified **Defer** because it would conflict with an ADR or **Optional learning-runbook write to Notion** (only when knowledge backend = `notion` is configured for this repo, per `.cascade/backends.toml`): if this execution surfaced a learning that would be a useful durable cross-project runbook entry (e.g., a non-obvious gotcha with the stack, a recipe for a recurring task spanning repos, a corrected understanding of an external system's behavior), prompt the operator: *"Want to promote this learning to a Notion runbook page under the Engineering Wiki? Defaults to SKIP."* Defaults to **SKIP**. Per `.claude/rules/knowledge-backend.md` § "When to write" — this is the rare opt-in path; HITL-gated; never default. If the operator opts in, announce the planned write (title, parent, body preview) before committing. This step is gated to genuinely cross-project learnings only — local-to-the-PR observations stay in the PR body and the hand-off summary, not in Notion. +**Post-merge checklist** (the hand-off ends with it; the operator runs it after the merge): `git switch main && git pull --ff-only && git fetch --prune`; post the drafted roll-forwards; close the meta-issues the close marker did not; append the frame's `## Rough-in events` row when this PR was the milestone's capstone; flip the roadmap row if Step 10 did not; the next runnable command, read off the roadmap. A research milestone's capstone is the verdict artifact — name it and its owner. + Do not call `gh pr ready` and do not merge — those remain the user's calls. The user's draft-review pass is where Surface findings get decided; they can ask you to apply any of them in the PR-feedback-loop turn, or wave them through. ## What `/finish` does NOT do @@ -220,7 +224,7 @@ Do not call `gh pr ready` and do not merge — those remain the user's calls. Th - **Does not handle re-rough-in.** Surface the need and return to chat for the rough-in skill. - **Does not auto-create dependent issues.** If the work reveals a missing sub-sub-issue, surface and return to chat for rough-in. - **Does not bypass dependencies.** Refuse to proceed when dependencies are unmet. -- **Does not modify cascade artifacts** (`docs/cbk/blueprint.md`, `docs/cbk/frame-NN.md`, etc.). Those are produced by chat-skill cascade phases. +- **Does not modify cascade artifacts** (`docs/cbk/blueprint.md`, `docs/cbk/frame-NN.md`, etc.). Those are produced by chat-skill cascade phases. *The status surfaces are carved out: `docs/cbk/ROADMAP.md`'s row and a frame's `## Rough-in events` table are not cascade events; Step 10 flips the row on this branch when the spec names it, the post-merge checklist otherwise (the contract wins where the two differ).* - **Does not modify ADRs.** ADRs are immutable once accepted; revisions happen via new ADRs that supersede the old (chat-skill territory, not `/finish`). - **Does not make workstream-level or framing-level decisions.** Those belong to upstream cascade phases (blueprint, framing, rough-in). - **Does not skip `/simplify` or `pr-review-toolkit:review-pr`.** The simplify and review passes both run before the PR opens; the simplify pass is non-negotiable per `docs/STANDARDS.md` § Step 4, and the review-toolkit findings are auto-triaged with the four-class rubric (Apply for correctness/validity/defensive; Surface for taste/style; Defer/Reject for conflicts and agent errors). The one exception is an explicit break-glass marker (Step 1), which waives exactly the `pr-review-toolkit:review-pr` half and is recorded on that skill's `## Review gate` line. The orchestrated sweep supplements the two skills and never substitutes for either. diff --git a/.claude/skills/rough-in/references/procedure.md b/.claude/skills/rough-in/references/procedure.md index 830ee7e..e65fa74 100644 --- a/.claude/skills/rough-in/references/procedure.md +++ b/.claude/skills/rough-in/references/procedure.md @@ -243,7 +243,7 @@ The deferred meta-issue for the automation recommender pass will revise the **te ## Step 6 — Planning-backend commit (atomic transition) -After all specs are drafted and approved, commit the sub-sub-issues to the planning backend atomically with the markdown event log update. Same discipline as blueprint and framing: capture every operation, execute planning ops first, commit markdown second, rollback on failure, handle partial failure by stopping and surfacing state to the user. +After all specs are drafted and approved, commit the sub-sub-issues to the planning backend atomically with the markdown event log update — and, where the project keeps `docs/cbk/ROADMAP.md`, the milestone's row flipped to *roughed-in* with the `R` issues linked, in the same commit. Same discipline as blueprint and framing: capture every operation, execute planning ops first, commit markdown second, rollback on failure, handle partial failure by stopping and surfacing state to the user. Detailed commit step, slug inheritance, profile-aware behavior, atomic transition pattern, partial failure recovery, and failure modes live in `references/planning-backend-commit.md`. From 9f3173d9d1ad46a0cc997183fa21f4750b06ba0f Mon Sep 17 00:00:00 2001 From: Justin Forth Date: Sun, 6 Sep 2026 20:33:57 -0600 Subject: [PATCH 05/38] feat(blueprint): the review workflows as templates with their seven constraints at the site; scaffold's review question names its consequence; the gh shape at every planning-backend commit, gh the default and the MCP one connection among several Co-Authored-By: Claude Fable 5.1 --- .claude/rules/tooling.md | 16 +- .claude/skills/blueprint/SKILL.md | 1 + .../blueprint/references/handoff-issue.md | 5 +- .../references/planning-backend-commit.md | 17 ++ .../references/planning-backend-matrix.md | 2 + .../references/templates/claude-review.yml | 233 ++++++++++++++++++ .../blueprint/references/templates/claude.yml | 86 +++++++ .../blueprint/references/templates/tooling.md | 5 +- .../references/planning-backend-commit.md | 17 ++ .../references/planning-backend-matrix.md | 2 + .../references/planning-backend-commit.md | 17 ++ .../references/planning-backend-matrix.md | 2 + .claude/skills/scaffold/SKILL.md | 2 +- 13 files changed, 399 insertions(+), 6 deletions(-) create mode 100644 .claude/skills/blueprint/references/templates/claude-review.yml create mode 100644 .claude/skills/blueprint/references/templates/claude.yml diff --git a/.claude/rules/tooling.md b/.claude/rules/tooling.md index 02aa77b..5188a34 100644 --- a/.claude/rules/tooling.md +++ b/.claude/rules/tooling.md @@ -38,7 +38,8 @@ |---|---|---| | Read a cascade issue | `` | The planning backend is the source of truth for cascade sub-issues | | Create / update an issue or comment | `` | Same | -| Create / read / comment on a PR | `` or `Bash` with `gh` | The git host is the source of truth for PRs, code review, repo state | +| Create / read / comment on a PR | `Bash` with `gh` (default) or `` | The git host is the source of truth for PRs, code review, repo state | +| Create or link a cascade issue on the github-issues axis | `Bash` with `gh` — five commands as one script (the phase's `references/planning-backend-commit.md` § The `gh` shape) | `gh` is the default interface; a git-host MCP is one connection among several, and the phase reads and writes the working tree by default | **Decision rule**: cascade issues live on the planning backend; PRs and code review live on the git host. `/finish` reads the planning backend for the spec and writes a PR with the close marker from `cbk-conventions.md` § Closes-keyword conventions. @@ -66,6 +67,19 @@ [One section per stack surface the project wires — database client, cloud CLI, observability, domain services — each with the same table shape, a decision rule, and any **gotchas the build has actually proved out** (recorded here so they aren't re-discovered; date them per the conventions' dated-rails principle). Delete this placeholder once real sections exist.] +## Automated review on the git host + +*(Delete if scaffold's PR/review answer was self-reviewed or straight-to-main.)* + +| You want to … | Reach for | Why | +|---|---|---| +| A review on every PR flipped to ready | The auto-review workflow (`.github/workflows/claude-review.yml`, from blueprint's template) | Fires once per readiness cycle; re-trigger with `claude-review-again`; `skip-claude` opts a PR out | +| A deeper or cheaper review on one PR | The `claude-deep-review` / `claude-fast-review` labels | Label-driven proportionality — the model and effort are explicit per label, never inherited | +| Ask a question on a PR or issue | `@claude` in a comment (`.github/workflows/claude.yml`) | Interactive; least-privilege tool list | +| Answer the review's findings | `/pr-respond ` | The feedback loop; every finding a SHA and a reply | + +**Decision rule**: the posted artifact is the deliverable (`cbk-conventions.md` § Deliverable trap) — a green run with no comment is investigated, a red run whose review posted is a pass. The workflow cannot review the PR that introduces it; verify on the next one. Record here which labels the project actually created. + ## Plugins | Plugin / skill | When | Cite | diff --git a/.claude/skills/blueprint/SKILL.md b/.claude/skills/blueprint/SKILL.md index 8721658..e0f5150 100644 --- a/.claude/skills/blueprint/SKILL.md +++ b/.claude/skills/blueprint/SKILL.md @@ -189,6 +189,7 @@ Blueprint produces six prose foundation docs plus tooling configs. The order is **Plus tooling configs** (not prose docs, real config files): - CI workflow files in `.github/workflows/` +- The review workflows from `references/templates/claude-review.yml` and `references/templates/claude.yml`, **only when scaffold's PR/review answer allows review automation** (`scaffold.md` § Working conventions: *reviewed* or *solo-merge with automated review*); otherwise a one-line HITL notice — *"no review automation — scaffold said self-reviewed; say the word to add it"* — never a silent omission - Task runner config (mise.toml, Makefile, justfile, package.json scripts — depends on stack) - `.env.example` if applicable diff --git a/.claude/skills/blueprint/references/handoff-issue.md b/.claude/skills/blueprint/references/handoff-issue.md index 35ccdef..a52266e 100644 --- a/.claude/skills/blueprint/references/handoff-issue.md +++ b/.claude/skills/blueprint/references/handoff-issue.md @@ -70,7 +70,8 @@ The cascade cannot automate these. See `docs/cbk/blueprint.md` § "Credential model" for background on why each is needed. - [ ] Run `/install-github-app` inside Claude Code (or equivalent for - whatever review automation was chosen) + whatever review automation was chosen) — this line only when + scaffold's PR/review answer allowed review automation; drop it otherwise - [ ] Create the local PAT and run `` to wire up MCP access - [ ] [Any other manual steps from blueprint's stack decisions] @@ -97,7 +98,7 @@ When generating section 2, blueprint walks every config file it just committed a Files to walk for the inventory: - The language-specific manifest (Cargo.toml workspace deps, package.json deps, pyproject.toml deps, etc.) -- Toolchain pinning (mise.toml, .tool-versions, .nvmrc, rust-toolchain.toml, etc.) +- Toolchain pinning (mise.toml, .tool-versions, .nvmrc, rust-toolchain.toml, etc.) — settle-window-covered but bot-uncovered: no dependabot ecosystem maintains these, so the auto-update bot's presence does not imply they are handled - CI workflow files for action refs (`.github/workflows/*.yml`, `.gitlab-ci.yml`, etc.) - Any other config file blueprint committed that contains version strings diff --git a/.claude/skills/blueprint/references/planning-backend-commit.md b/.claude/skills/blueprint/references/planning-backend-commit.md index bb5fb77..d4e11f4 100644 --- a/.claude/skills/blueprint/references/planning-backend-commit.md +++ b/.claude/skills/blueprint/references/planning-backend-commit.md @@ -46,6 +46,23 @@ Blueprint constructs each parent Issue's body from the **`cascade-workstream.md` ## Atomic transition pattern +### The `gh` shape (github-issues) + +`gh` is the default interface for this axis; a git-host MCP is one connection among several, used when it is what the session has. Phase skills read and write the working tree by default and push through `gh` or `git`. The five commands, run as **one script** per transition so the placeholders resolve in the same pass: + +```bash +url=$(gh issue create --title "$title" --body-file "$body" --label "$labels" --repo "$repo") # returns the URL; the number is its last path segment +n=${url##*/} +id=$(gh api "repos/$repo/issues/$n" --jq .id) # the numeric id the link needs (not the number) +gh api -X POST "repos/$repo/issues/$parent/sub_issues" -F sub_issue_id="$id" >/dev/null # link under a parent (blueprint's parents have none; framing and rough-in use this line) +gh api "repos/$repo/issues/$parent/sub_issues" --jq '[.[].number]' # verify +gh issue edit "$n" --body-file "$body_resolved" # create-then-edit: resolve cross-references to sibling parents once the numbers exist +``` + +Two rough edges the exercised run recorded: the link call returns the **parent** issue object, so a status line built from its `.number` prints "#N under #N" — read the child's number from the create step, never from the link response; and a body carrying a literal placeholder cannot be final at creation, because an issue's own number is not known until it exists — the create-then-edit pass is the mechanism, not a workaround. + + + The planning-backend commit and the markdown commit must be **atomic** — either both succeed or neither does. Order of operations: 1. **Capture** every operation as a planned transition diff --git a/.claude/skills/blueprint/references/planning-backend-matrix.md b/.claude/skills/blueprint/references/planning-backend-matrix.md index c66a5cb..208dd8c 100644 --- a/.claude/skills/blueprint/references/planning-backend-matrix.md +++ b/.claude/skills/blueprint/references/planning-backend-matrix.md @@ -21,6 +21,8 @@ The planning backend is determined by `scaffold.md`'s Cascade metadata section. ## `github-issues` planning behavior +**Interface**: `gh` by default (`references/planning-backend-commit.md` § The `gh` shape — five commands as one script, the parent-object return, the create-then-edit placeholder pattern); a git-host MCP is one connection among several. The phase reads and writes the working tree by default. + **The most common case.** If scaffold picked `github-issues`, blueprint operates entirely against the GitHub repo for planning. There is no Linear, no external project tool. The structural fact that shapes everything: **`github-issues` is three-level** (project board → sub-issue → sub-sub-issue, via GitHub's native sub-issue API), with no native concept of "initiative." This was surfaced and explicitly acknowledged in scaffold's backend selection. Blueprint's job under this constraint is to produce the initiative content **as a markdown document at `docs/cbk/blueprint.md`** rather than as a planning entity. Framing then reads that document as context for project decomposition. diff --git a/.claude/skills/blueprint/references/templates/claude-review.yml b/.claude/skills/blueprint/references/templates/claude-review.yml new file mode 100644 index 0000000..6f0c470 --- /dev/null +++ b/.claude/skills/blueprint/references/templates/claude-review.yml @@ -0,0 +1,233 @@ +# Claude PR auto-review — blueprint template. Copy to .github/workflows/claude-review.yml +# and fill every [bracketed] value; the seven authoring constraints below are stated at +# their sites and survive edits. Emitted only when scaffold's PR/review answer allows +# review automation (scaffold.md § Working conventions); otherwise blueprint surfaces the +# skip as a one-line notice and this file is not written. +# +# Fires ONCE per readiness cycle: opened (non-draft) · ready_for_review (the common +# trigger — /finish ends at draft, the author flips ready) · reopened · labeled (a manual +# re-trigger, gated to `claude-review-again`). NOT on `synchronize`: follow-up pushes do +# not re-fire a review (constraint 5 — label-driven proportionality); re-trigger with +# the label. Model and effort are explicit, never inherited (orchestration.md). +# +# Constraint 1 — the action cannot review the PR that introduces it: the action +# validates this file against the default branch and exits green without running on +# any PR that adds or changes it. Verify on the next PR, not this one. +# +# Constraint 4 — the posted artifact is the deliverable, in both directions: a green run +# with no summary comment is a failure to investigate; a red run whose review posted is a +# pass (cbk-conventions.md § Deliverable trap). The prompt makes the summary an explicit +# `gh pr comment` and names it first. +# +# GOTCHA: the CI-skip marker on the HEAD commit at the draft→ready flip silently blocks +# this workflow — end the branch on a non-marker commit before flipping +# (cbk-conventions.md § [skip ci] rule, the auto-review trap). +# +# Two things the exercised runs learned: `gh pr checks` is usually NOT readable from the +# action's token ("Resource not accessible by integration") — the prompt says to say +# nothing about CI rather than report the permission error as a finding; and +# `track_progress` is unsupported on `labeled` events (the action fails), hence the +# expression on that input. +# +# Needs the `CLAUDE_CODE_OAUTH_TOKEN` Actions secret (`/install-github-app` in Claude Code). +# +# Constraint 2 — SAFETY: no author-controlled input (title, body, commits, branch name, +# labels) is interpolated into a `run:` command. Labels arrive through `env:` as JSON and +# are read as quoted shell variables. The action is pinned to a full commit SHA with a +# version comment (cbk-conventions-reference.md § Dependency settle-window); dependabot's +# github-actions sweep maintains the pin under the floor. +# https://github.blog/security/vulnerability-research/how-to-catch-github-actions-workflow-injections-before-attackers-do/ + +name: Claude PR Auto-Review + +on: + pull_request: + types: [opened, ready_for_review, reopened, labeled] + # Docs-only and cascade-artifact PRs are not reviewed by the bot. This is NOT a + # required check, so a paths filter is safe here (unlike ci.yml — cbk-conventions.md + # § [skip ci] rule, the required-checks trap). A docs-only PR whose docs are one-way + # doors (ADRs, the conventions) is reviewed by a human, not skipped by everyone. + paths-ignore: + - 'docs/cbk/**' + - '**/*.md' + - '.gitignore' + - '.gitattributes' + - '.editorconfig' + - '.github/dependabot.yml' + # [add the project's other prose-only paths] + +concurrency: + group: claude-review-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + auto-review: + name: Auto-review (inline + summary) + if: | + (github.event.action != 'labeled' || github.event.label.name == 'claude-review-again') && + !github.event.pull_request.draft && + !contains(github.event.pull_request.labels.*.name, 'skip-claude') && + github.event.pull_request.user.login != 'dependabot[bot]' && + github.event.pull_request.user.login != 'renovate[bot]' && + github.event.pull_request.user.login != 'claude[bot]' + runs-on: ubuntu-latest + # Constraint 3 — a job-level timeout: the action has no timeout input of its own. + timeout-minutes: 30 + # Constraint 6 — permissions scoped to the job. `id-token: write` is required by the + # action even in OAuth-token mode; `checks: read` for the prompt's `gh pr checks`. + permissions: + contents: read + pull-requests: write + issues: read + actions: read + checks: read + id-token: write + steps: + - name: Remove claude-review-again label (so it can be re-added next time) + if: github.event.action == 'labeled' && github.event.label.name == 'claude-review-again' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} + REPO: ${{ github.repository }} + run: | + set -uo pipefail + # --repo because this step runs BEFORE checkout. + if ! err="$(gh pr edit "$PR_NUMBER" --repo "$REPO" --remove-label claude-review-again 2>&1)"; then + if printf '%s' "$err" | grep -qiE 'not found|does not have|does not exist'; then + echo "Label already removed (benign concurrent run)." + else + echo "::error::Failed to remove claude-review-again label: $err" + exit 1 + fi + fi + + - name: Checkout PR HEAD + uses: actions/checkout@[full-commit-sha] # v[version] — [newest release clearing the settle window as of ] + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + + - name: Pick model + effort from labels + id: model + # Constraint 5 — label-driven proportionality. Precedence: claude-deep-review > + # claude-fast-review > default. Matches the QUOTED JSON token so a stray + # `claude-deep-review-wip` label cannot false-trigger the heavy path. + # Constraint 7 — no orphanable sub-dispatch: the default and fast paths keep the + # review in one session (`--disallowedTools Agent`); only the deep path fans out. + env: + LABELS_JSON: ${{ toJSON(github.event.pull_request.labels.*.name) }} + run: | + set -uo pipefail + labels="${LABELS_JSON:-[]}" + if printf '%s' "$labels" | grep -qF '"claude-deep-review"'; then + echo "model=[]" >> "$GITHUB_OUTPUT" + echo "effort=xhigh" >> "$GITHUB_OUTPUT" + echo "settings_arg=--settings '{\"ultracode\":true}'" >> "$GITHUB_OUTPUT" + echo "disallow_arg=" >> "$GITHUB_OUTPUT" + elif printf '%s' "$labels" | grep -qF '"claude-fast-review"'; then + echo "model=[]" >> "$GITHUB_OUTPUT" + echo "effort=high" >> "$GITHUB_OUTPUT" + echo "settings_arg=" >> "$GITHUB_OUTPUT" + echo "disallow_arg=--disallowedTools Agent" >> "$GITHUB_OUTPUT" + else + echo "model=[]" >> "$GITHUB_OUTPUT" + echo "effort=high" >> "$GITHUB_OUTPUT" + echo "settings_arg=" >> "$GITHUB_OUTPUT" + echo "disallow_arg=--disallowedTools Agent" >> "$GITHUB_OUTPUT" + fi + + - name: Auto-review + uses: anthropics/claude-code-action@[full-commit-sha] # v[version] — [newest release clearing the settle window as of ] + with: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + # Full SDK output so an auth or stream failure is diagnosable from the run log. + show_full_output: true + # track_progress is unsupported on `labeled` events (the action fails). + track_progress: ${{ github.event.action != 'labeled' && 'true' || 'false' }} + additional_permissions: | + actions: read + prompt: | + You are reviewing a pull request against []. Read `CLAUDE.md` first + []. + + ## What to do + + Enumerate every changed file (`gh pr diff ${{ github.event.pull_request.number }} --name-only`) + and walk each one; read the surrounding file, not only the hunk, when context matters. + + Then post, **in this order**: + + 1. **One summary comment** at the top of the PR, with `gh pr comment` — the verdict and the + finding counts (format below). Post it FIRST; it is the durable output. + 2. **Inline comments** for specific code-level findings, via the inline-comment MCP tool + (`mcp__github_inline_comment__create_inline_comment`). + + **Your deliverable is the posted comments, not your reply.** A review that never ran + `gh pr comment` for its summary produced nothing. If you are low on turns, post the + summary before adding more inline comments. Do the review in this one session — do not + dispatch subagents and wait on them. + + ## Rubric (from `.claude/rules/pr-review.md`) + + Classify every finding into exactly one class: **Apply** (a behavior-preserving fix with + concrete evidence — a reproducible failing path, a factually wrong comment, dead code, a + low-risk change under about 15 lines), **Apply with care** (a cross-file refactor or a + non-obvious correctness fix), **Surface** (a genuine design or taste call — inline only + when tied to a file and line), **Defer** (conflicts with an ADR or is out of scope), + **Reject** (a misreading of the codebase or a finding that contradicts the project's + rules — one line in the summary, never inline). Tag inline comments with the class. + + ## Project-level rules to check against (read the ones the diff touches) + + - `.claude/rules/testing.md` — [] + - `.claude/rules/logging.md` — [] + - `.claude/rules/cbk-conventions.md` — branch naming, commit format, the label taxonomy, + the CI-skip-marker rule, mutation discipline (ADRs immutable; cascade artifacts append-only) + - `.claude/rules/simplification.md` — dead code, unnecessary indirection, over-clever expressions + - [] + + Architectural commitments live in the ADRs (`docs/adr/`, immutable). Read `docs/adr/README.md` + — the always-current index — and the ADRs the diff plausibly touches, following each + `Refines:` / `Extends:` chain; check the change against their Decision and Consequences. + Do not rely on a hard-coded ADR list in this prompt. Known citation defects live in + `docs/adr/corrections.md`; do not restate a claim already flagged wrong there. + + Project-local reviewer agents in `.claude/agents/` encode extra checks. Apply them + **inline yourself** (one session, no subagents): read the ones whose scope the diff + touches, per `.claude/rules/pr-review.md` § Project-local agents. + + ## How to format the summary comment + + One-line verdict: **APPROVE** / **APPROVE WITH NITS** / **REQUEST CHANGES** / **NEEDS DISCUSSION**. + Then a counts table (Apply / Apply with care / Surface / Defer / Reject). Then three to + seven lines on the most important findings and any cross-cutting concern. CI status is + usually NOT readable from your token (`gh pr checks` fails with "Resource not accessible + by integration"); if it is, reference a failed check, otherwise say nothing about CI — + never report the permission error as a finding. End with one line on what is NOT in + scope of this review. + + ## What to skip + + - Docs-only or cascade-artifact PRs (`docs/cbk/`, `*.md` only): post the one-line summary + `Docs-only PR — auto-review skipped per rule` and exit — unless the docs are one-way + doors (ADRs, the conventions), which a human reviews. + - Issues in unchanged code; speculative future-risk warnings with no concrete failing path; + restating what a function name already says; library or framework swaps (blueprint's job); + stylistic nits without a strong rationale (those are Reject, one line). + + ## Context + + `gh pr view ${{ github.event.pull_request.number }}` for metadata, `gh pr diff` for the diff, + and the inline-comment MCP tool for line-specific findings. + + Model in use: ${{ steps.model.outputs.model }} (effort: ${{ steps.model.outputs.effort }}) + claude_args: | + --model ${{ steps.model.outputs.model }} + --fallback-model [] + --effort ${{ steps.model.outputs.effort }} + ${{ steps.model.outputs.settings_arg }} + --max-turns 60 + --allowedTools "Read,Grep,Glob,Bash(gh pr view:*),Bash(gh pr diff:*),Bash(gh pr comment:*),Bash(gh pr checks:*),Bash(gh run view:*),Bash(gh run list:*),mcp__github_inline_comment__create_inline_comment" + ${{ steps.model.outputs.disallow_arg }} diff --git a/.claude/skills/blueprint/references/templates/claude.yml b/.claude/skills/blueprint/references/templates/claude.yml new file mode 100644 index 0000000..5334e33 --- /dev/null +++ b/.claude/skills/blueprint/references/templates/claude.yml @@ -0,0 +1,86 @@ +# Claude Code GitHub Action — the interactive @claude mention handler. Blueprint +# template: copy to .github/workflows/claude.yml and fill the [bracketed] values. +# Ships beside claude-review.yml under the same scaffold PR/review answer. +# +# Fires when @claude is mentioned in a PR or issue comment, a review, or an issue body. +# - concurrency + cancel-in-progress so a rapid back-and-forth does not queue +# - skips bots and the `skip-claude` label (avoids @claude loops; the opt-out) +# - explicit --allowedTools (least privilege at the tool level) +# - the workhorse model at its default effort: mentions are interactive and quota-sensitive +# +# Needs the `CLAUDE_CODE_OAUTH_TOKEN` Actions secret (`/install-github-app`). +# +# SAFETY (constraint 2): no untrusted input (issue title, PR body, comment body) is +# interpolated into `run:` — ACTOR and the label JSON arrive through `env:` and are read +# as quoted shell variables. The action is pinned to a full commit SHA (constraint: the +# settle window, cbk-conventions-reference.md). A job timeout (constraint 3) and job-scoped +# permissions (constraint 6) as in claude-review.yml. + +name: Claude (@claude mention) + +on: + issue_comment: + types: [created] + pull_request_review_comment: + types: [created] + pull_request_review: + types: [submitted] + issues: + types: [opened, assigned] + +concurrency: + group: claude-mention-${{ github.event.issue.number || github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + claude: + name: Claude responds to @mention + permissions: + contents: read + pull-requests: read + issues: read + actions: read + id-token: write + if: | + (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || + (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || + (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || + (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - name: Skip if bot author or skip-claude label + id: gate + env: + ACTOR: ${{ github.actor }} + ISSUE_LABELS_JSON: ${{ toJSON(github.event.issue.labels.*.name) }} + PR_LABELS_JSON: ${{ toJSON(github.event.pull_request.labels.*.name) }} + run: | + set -uo pipefail + ALL_LABELS="${ISSUE_LABELS_JSON:-[]} ${PR_LABELS_JSON:-[]}" + if [[ "$ACTOR" == "claude[bot]" || "$ACTOR" == "dependabot[bot]" || "$ACTOR" == "renovate[bot]" ]]; then + echo "skip=true" >> "$GITHUB_OUTPUT" + elif printf '%s' "$ALL_LABELS" | grep -qF '"skip-claude"'; then + echo "skip=true" >> "$GITHUB_OUTPUT" + else + echo "skip=false" >> "$GITHUB_OUTPUT" + fi + + - name: Checkout + if: steps.gate.outputs.skip == 'false' + uses: actions/checkout@[full-commit-sha] # v[version] + with: + fetch-depth: 1 + + - name: Run Claude Code + if: steps.gate.outputs.skip == 'false' + uses: anthropics/claude-code-action@[full-commit-sha] # v[version] + with: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + additional_permissions: | + actions: read + claude_args: | + --model [] + --fallback-model [] + --max-turns 60 + --allowedTools "Bash(gh issue view:*),Bash(gh issue comment:*),Bash(gh pr view:*),Bash(gh pr diff:*),Bash(gh pr comment:*),Bash(gh pr checks:*),Bash(gh run view:*),Bash(gh run list:*),mcp__github_inline_comment__create_inline_comment" diff --git a/.claude/skills/blueprint/references/templates/tooling.md b/.claude/skills/blueprint/references/templates/tooling.md index 78218e5..eb93df7 100644 --- a/.claude/skills/blueprint/references/templates/tooling.md +++ b/.claude/skills/blueprint/references/templates/tooling.md @@ -40,7 +40,7 @@ The set depends on stack decisions. Default set: - Skip entirely if the project has no env config 4. **Optional**: review automation - - `claude-code-action` workflow if scaffold.md's PR/review process said to use it (e.g., a "CI must trigger Claude code review on PRs" preference) + - the review workflows from `templates/claude-review.yml` and `templates/claude.yml` if scaffold.md's PR/review process said to use them (*reviewed* or *solo-merge with automated review*); otherwise surface the skip as a one-line notice - Skip if scaffold didn't ask for it ## Rules @@ -89,6 +89,7 @@ The sanity pass asks eight questions. Each is **stack-agnostic**; the user bring 4. **License / advisory checker** — Will the license allowlist and advisory rules match what gets pulled transitively once dependencies are installed? Do you want to run the checker once now against a populated dependency tree and amend the allowlist, or ship defaults and fix at first CI run? 5. **Stack-decision contradictions** — Any tooling config rules we wrote that contradict stack decisions from earlier in this session? (Example: a ban on a system library that a storage decision requires.) This is a cross-check: read the bans / denies / allow-lists in the tooling configs and verify none contradict the stack decisions list. 6. **Automated review bot workflows** — **If we're committing an automated review bot as a merge gate** (claude-code-action, CodeRabbit, Copilot review, or equivalent): the out-of-the-box workflows these tools ship are usually wrong for any specific project. They over-review, under-review, comment on the wrong things, or apply generic rules that don't match your standards. Retuning them is a real authoring task — see the "Automated review bot prompt construction" section below for the full treatment. Sanity-pass-level decisions to make right now: (a) do you want the review bot to skip docs-only and template-only PRs to save tokens? (b) do you want concurrency cancellation so a burst of pushes only pays for the final review? (c) what wall-clock cap on the review job? (d) read-only tool permissions, or can the bot commit/push? (e) which PR authors should be skipped (drafts, dependabot, renovate, etc.)? **Also**: how will you verify the review bot actually ran and commented on your first post-blueprint PR? A bot gate that's silently broken is worse than no gate. +6b. **Toolchain pins the bot does not cover** — the toolchain manager's pins (`mise.toml` `[tools]`, `.tool-versions`, `rust-toolchain.toml`, `.nvmrc`) and container base-image tags are outside every dependabot ecosystem: the settle window applies by hand (`cbk-conventions-reference.md` § Dependency settle-window). Decide now how the project records the settled age at pin time and what tracks the next bump — an open question in the frame, or a project automation. 7. **Coupled dependency pairs** — Are there dependency pairs in your stack that are coupled upstream (library A caps library B's version, or they need to be bumped together)? If yes, your automated dependency bump config should group them so a single coordinated PR lands instead of two conflicting ones that can't both merge. 8. **Temporary workarounds and trip-wires** — Any workarounds we're shipping from questions 1–7 just to get CI green on empty scaffolding? For each, we'll capture it in a **Cleanup tracking** section in `blueprint.md` with an explicit trip-wire condition for removal. Example trip-wires: *"remove when the first real test binary lands"*, *"remove when each ignored dep gets actually wired up"*, *"remove when upstream library X drops dependency Y"*. @@ -210,6 +211,6 @@ If the user invoked light mode: - **Task runner config has the minimum set**: setup, check, test. Skip lint/typecheck/dev/fix/etc. unless they were explicitly chosen during stack decisions. - **CI workflow has 1–3 jobs** instead of 5+ - **Skip env template** unless the project clearly has env vars -- **Skip review automation** unless explicitly requested +- **Surface a skipped review automation as a one-line notice**, never a silent omission Even in light mode, the "every CLAUDE.md command = actual task" rule still applies. Non-negotiable. diff --git a/.claude/skills/framing/references/planning-backend-commit.md b/.claude/skills/framing/references/planning-backend-commit.md index d636901..cd914ba 100644 --- a/.claude/skills/framing/references/planning-backend-commit.md +++ b/.claude/skills/framing/references/planning-backend-commit.md @@ -47,6 +47,23 @@ Where `docs/cbk/ROADMAP.md` exists, the markdown half of the transition also app ## Atomic transition pattern (two-step per sub-issue) +### The `gh` shape (github-issues) + +`gh` is the default interface for this axis; a git-host MCP is one connection among several, used when it is what the session has. Phase skills read and write the working tree by default and push through `gh` or `git`. The five commands, run as **one script** per transition so the placeholders resolve in the same pass: + +```bash +url=$(gh issue create --title "$title" --body-file "$body" --label "$labels" --repo "$repo") # returns the URL; the number is its last path segment +n=${url##*/} +id=$(gh api "repos/$repo/issues/$n" --jq .id) # the numeric id the link needs (not the number) +gh api -X POST "repos/$repo/issues/$parent/sub_issues" -F sub_issue_id="$id" >/dev/null # link under the parent +gh api "repos/$repo/issues/$parent/sub_issues" --jq '[.[].number]' # verify +gh issue edit "$n" --body-file "$body_resolved" # create-then-edit: resolve the F<#> placeholders and meta-issue cross-references once the numbers exist +``` + +Two rough edges the exercised run recorded: the link call returns the **parent** issue object, so a status line built from its `.number` prints "#N under #N" — read the child's number from the create step, never from the link response; and a body carrying a literal placeholder cannot be final at creation, because an issue's own number is not known until it exists — the create-then-edit pass is the mechanism, not a workaround. + + + Framing's planning-backend commit uses GitHub's two-step sub-issue creation: 1. Create the sub-issue via `issue_write` (returns issue number + id) 2. Link it to the parent via `sub_issue_write` with method `add` and the parent's issue_number + the new sub-issue's id diff --git a/.claude/skills/framing/references/planning-backend-matrix.md b/.claude/skills/framing/references/planning-backend-matrix.md index 15951cf..785b51d 100644 --- a/.claude/skills/framing/references/planning-backend-matrix.md +++ b/.claude/skills/framing/references/planning-backend-matrix.md @@ -26,6 +26,8 @@ For project-specific overrides (workstream slugs, label schemes, Linear team nam ## `github-issues` planning behavior +**Interface**: `gh` by default (`references/planning-backend-commit.md` § The `gh` shape — five commands as one script, the parent-object return, the create-then-edit placeholder pattern); a git-host MCP is one connection among several. The phase reads and writes the working tree by default. + The most common case. When scaffold picked `github-issues`, framing reads inputs from the GitHub repo via GitHub MCP, produces `frame-NN.md` + `docs/cbk/README.md` index update, and commits them back via GitHub MCP. No Linear, no cross-tool integration. The structural fact that shapes everything: **GitHub's three-level planning hierarchy (parent Issue → sub-issue → sub-sub-issue) maps onto framing's output without needing a fourth level**. Framing's output IS the project-level content — it lives as markdown in `docs/cbk/` plus framing sub-issues parented under the workstream's parent Issue (already created by blueprint). diff --git a/.claude/skills/rough-in/references/planning-backend-commit.md b/.claude/skills/rough-in/references/planning-backend-commit.md index 6b92b25..0d83424 100644 --- a/.claude/skills/rough-in/references/planning-backend-commit.md +++ b/.claude/skills/rough-in/references/planning-backend-commit.md @@ -39,6 +39,23 @@ Rough-in constructs each sub-sub-issue's body from the **`cascade-rough-in.md`** ## Atomic transition pattern (two-step per sub-sub-issue) +### The `gh` shape (github-issues) + +`gh` is the default interface for this axis; a git-host MCP is one connection among several, used when it is what the session has. Phase skills read and write the working tree by default and push through `gh` or `git`. The five commands, run as **one script** per transition so the placeholders resolve in the same pass: + +```bash +url=$(gh issue create --title "$title" --body-file "$body" --label "$labels" --repo "$repo") # returns the URL; the number is its last path segment +n=${url##*/} +id=$(gh api "repos/$repo/issues/$n" --jq .id) # the numeric id the link needs (not the number) +gh api -X POST "repos/$repo/issues/$parent/sub_issues" -F sub_issue_id="$id" >/dev/null # link under the parent +gh api "repos/$repo/issues/$parent/sub_issues" --jq '[.[].number]' # verify +gh issue edit "$n" --body-file "$body_resolved" # create-then-edit: resolve the R<#> / F<#> placeholders once the numbers exist +``` + +Two rough edges the exercised run recorded: the link call returns the **parent** issue object, so a status line built from its `.number` prints "#N under #N" — read the child's number from the create step, never from the link response; and a body carrying a literal placeholder cannot be final at creation, because an issue's own number is not known until it exists — the create-then-edit pass is the mechanism, not a workaround. + + + Rough-in's planning-backend commit uses GitHub's two-step sub-issue creation, same as framing's pattern: 1. Create the sub-sub-issue via `issue_write` (returns issue number + id) diff --git a/.claude/skills/rough-in/references/planning-backend-matrix.md b/.claude/skills/rough-in/references/planning-backend-matrix.md index e6152bb..1d9785f 100644 --- a/.claude/skills/rough-in/references/planning-backend-matrix.md +++ b/.claude/skills/rough-in/references/planning-backend-matrix.md @@ -6,6 +6,8 @@ The cascade ships three planning axes defined in scaffold and documented in `ref ## `github-issues` planning axis (default) +**Interface**: `gh` by default (`references/planning-backend-commit.md` § The `gh` shape — five commands as one script, the parent-object return, the create-then-edit placeholder pattern); a git-host MCP is one connection among several. The phase reads and writes the working tree by default. + This is the planning axis rough-in is built to run cleanly against, with full atomic transition, partial failure recovery, and inherit-from-disk discipline. **Hierarchy**: rough-in creates **sub-sub-issues** parented under the framing capability sub-issue via GitHub's native sub-issue API. The full Issue tree per workstream is three deep: diff --git a/.claude/skills/scaffold/SKILL.md b/.claude/skills/scaffold/SKILL.md index 908a5b8..9538e5a 100644 --- a/.claude/skills/scaffold/SKILL.md +++ b/.claude/skills/scaffold/SKILL.md @@ -101,7 +101,7 @@ This is where scaffold captures the team shape and working preferences that blue 1. *"Is this solo or team? If team — how many people, what roles, and who makes the call when there's a disagreement?"* 2. *"What's your quality bar for this project — move fast and iterate, or get it right from the start?"* (Single highest-value question scaffold can ask. Shapes testing, review, and CI decisions downstream.) -3. *"How do you want PRs to work? Reviewed by someone else, self-reviewed, or straight-to-main?"* +3. *"How do you want PRs to work? Reviewed by someone else, self-reviewed, solo-merge **with automated review**, or straight-to-main?"* — the answer gates blueprint: only *reviewed* and *solo-merge with automated review* let blueprint emit the review workflows (the blueprint skill's `references/templates/claude-review.yml` and `claude.yml`); on *self-reviewed* and *straight-to-main* blueprint surfaces the skip as a one-line notice and the handoff issue's `/install-github-app` step is omitted. Say so when asking. 4. *"How comfortable are you with the tools we're setting up? First time with GitHub Actions / project boards, or veteran?"* 5. *"What pace are you working at — full-time, part-time, evenings-and-weekends?"* (Appetite was captured in consultation, but confirming here is cheap and the answer may have changed.) From 326367e0a129625929a8f39ae52f6042b8f16e82 Mon Sep 17 00:00:00 2001 From: Justin Forth Date: Sun, 6 Sep 2026 20:35:04 -0600 Subject: [PATCH 06/38] feat(finish): the PR body is the audit surface for the PR's life; the backward sweep beside the roll-forward; the measurement variant of a spec with the verdict rule committed first Co-Authored-By: Claude Fable 5.1 --- .claude/commands/finish-procedure.md | 2 ++ .claude/commands/finish.md | 5 ++-- .claude/commands/pr-respond.md | 6 +++-- .../skills/rough-in/references/contract.md | 5 +++- .../rough-in/references/finish-command.md | 5 ++-- .../rough-in/references/finish-procedure.md | 2 ++ .../templates/rough-in-spec-template.md | 27 +++++++++++++++++++ .../skills/rough-in/references/test_cases.md | 1 + 8 files changed, 46 insertions(+), 7 deletions(-) diff --git a/.claude/commands/finish-procedure.md b/.claude/commands/finish-procedure.md index 68eb1b8..b7500f9 100644 --- a/.claude/commands/finish-procedure.md +++ b/.claude/commands/finish-procedure.md @@ -201,6 +201,8 @@ If any finding was classified **Defer** because it would conflict with an ADR or **Roll-forward offer** (HITL). If the run surfaced deferred context that a *later* unit of work will need — TODOs, contract facts the next issue depends on, intentional omissions, or a follow-up worth its own issue — **offer** to post a roll-forward comment **wherever it's relevant**: the next issue, a sibling, a downstream milestone issue, a meta-issue, or a brand-new follow-up. Do **not** hardwire it to "the next issue." Default to posting **post-merge** unless the deferred context blocks another issue's start. If nothing was deferred, skip this silently. +**Backward sweep** (HITL offer, beside the roll-forward). What this run landed can make a sibling spec's *absence* claim false — "no adapter exists yet", "the table is not wired". The candidate set is closed: the open siblings under the same parent issue carrying `cascade-depth:roughed-in`, read in **one** call (`gh api repos/{owner}/{repo}/issues/{parent}/sub_issues` on github-issues, the parent's children on linear) and capped by the milestone's R-count — never the whole backlog. Check absence claims only, and verify each by **running the body's own command** (its grep, its test, its probe), not by recalling what this run did. Separate the two kinds: a claim this landing falsified (report it, with the commit) from a claim that was false when written (report it as a spec defect). **Default to not reporting** — a claim that still holds is not mentioned. The repair is rough-in's in-place body refresh, offered to the operator; this run never edits an issue body. An empty sweep is a one-line pass — `backward sweep: N siblings, no absence claim falsified` — never an omitted line. + **Optional learning-runbook write to Notion** (only when knowledge backend = `notion` is configured for this repo, per `.cascade/backends.toml`): if this execution surfaced a learning that would be a useful durable cross-project runbook entry (e.g., a non-obvious gotcha with the stack, a recipe for a recurring task spanning repos, a corrected understanding of an external system's behavior), prompt the operator: *"Want to promote this learning to a Notion runbook page under the Engineering Wiki? Defaults to SKIP."* Defaults to **SKIP**. Per `.claude/rules/knowledge-backend.md` § "When to write" — this is the rare opt-in path; HITL-gated; never default. If the operator opts in, announce the planned write (title, parent, body preview) before committing. This step is gated to genuinely cross-project learnings only — local-to-the-PR observations stay in the PR body and the hand-off summary, not in Notion. **Post-merge checklist** (the hand-off ends with it; the operator runs it after the merge): `git switch main && git pull --ff-only && git fetch --prune`; post the drafted roll-forwards; close the meta-issues the close marker did not; append the frame's `## Rough-in events` row when this PR was the milestone's capstone; flip the roadmap row if Step 10 did not; the next runnable command, read off the roadmap. A research milestone's capstone is the verdict artifact — name it and its owner. diff --git a/.claude/commands/finish.md b/.claude/commands/finish.md index fa8354c..1545534 100644 --- a/.claude/commands/finish.md +++ b/.claude/commands/finish.md @@ -32,8 +32,8 @@ This command is contract-first. On 2026-09-03 an A/B gave two workhorse-tier exe 5. **Atomic commits** in Conventional Commits form with the workstream's scope: the red tests, the implementation, each simplify Apply, each review Apply — one focused commit each, never amended across a logical boundary, never squashed on the branch. The squash happens at merge on the base branch. No code or test commit carries the CI-skip marker (`cbk-conventions.md` § `[skip ci]` rule). 6. **The gate, green.** The project's `check` task passes before simplify and review run, and again after every applied finding. Unrelated red is surfaced, not muted — never skipped, expected-failed or commented out to pass. 7. **The review floor, actually run, with the bounded sweep beside it, then triage — once.** First **`/simplify`**, as a skill invocation; triage its findings by the four-class rubric and land its Apply items one commit each with `check` re-run after each. Then, **concurrently**: **`pr-review-toolkit:review-pr`** with no arguments, as a skill invocation, and — where a multi-agent orchestration surface exists — **the review workflow** (`.claude/workflows/review-sweep.js`), sized to the diff and never to the session's effort setting, with the pre-filtered changed-path list passed as `files`. The project-local reviewers ride in it from the roster the workflow reads at runtime (`.claude/rules/pr-review.md` § Project-local agents); beyond them you name the finders this diff needs — none on a small single-surface change the two skills already cover, several on a cross-layer one — and the workflow logs its planned agent count before it finds anything and returns its own gate line. Without an orchestration surface, dispatch the project-local reviewers directly and record `skipped — no orchestration surface` on the sweep's line. The sweep supplements the two skills and never substitutes for either. Triage waits for both to return and stays with you (`pr-review.md` § Triage rubric; the reference half's calibration read at triage): Apply and Apply-with-care land as their own commits with `check` re-run; Surface, Defer and Reject are recorded, never applied. A skill that is uninstalled or errors is a stop-and-surface. A skill that runs without its agent fan-out because the Agent tool is unavailable in your context counts as invoked, and its dropped dimensions are recorded on its `## Review gate` line — never described as equivalent. A failed review agent is dropped coverage, not zero findings. **Describing a review is not running one**: a claimed invocation that did not happen fails this contract outright. The floor runs when the known work is complete and is not run again on a later delta — the reviewer round on the flip covers that, and `/pr-respond` answers it. -8. **A draft PR** on the pushed branch: title in Conventional Commits with the workstream's scope; body with the planning axis's close marker (`Closes #$1` on github-issues, `Closes $1` on linear — in the body, not only the title; `cbk-conventions.md` § Closes-keyword conventions); a summary of what changed and why, with the ADRs, frame milestone and rules it relies on; a **`## Review gate`** block, written before `## Triage`, in the shape `.claude/rules/pr-review.md` § The floor states — one line each for `/simplify`, `pr-review-toolkit:review-pr` and the sweep, each stating run-or-not with counts and dropped coverage, a waived skill on its line with the break-glass reason, the sweep's line transcribed from the record the workflow returns; a **`## Triage`** block listing every finding under its class — Apply and Apply-with-care as `SHA: fix`, Surface and Defer with the agent's verbatim rationale, Reject with a one-line dismissal; and any review block or label the project's conventions require when the diff touches a surface they guard. **The roadmap row rides this branch, as its last commit before the PR** — where the project keeps `docs/cbk/ROADMAP.md` and the spec names the flip: after the floor (item 7) and before `gh pr create`, the row for this step and the `## Now` paragraph are updated to cite this issue and this PR — *done* when this is the milestone's last R-issue, the progress note otherwise — as one `docs(cascade):` commit with no CI-skip marker (it is HEAD at the flip, and the marker would suppress the auto-review and the required checks — `cbk-conventions.md` § Auto-review trap). The PR number is the next in the repository's shared issue-and-PR sequence (`gh api 'repos/{owner}/{repo}/issues?state=all&sort=created&direction=desc&per_page=1'` plus one) and is checked against the number `gh pr create` returns; a mismatch is one correcting commit. Never a separate PR: a one-row flip with its own PR costs a CI run for nothing, and a flip committed after `gh pr create` costs the same run on the open PR. The row reads *done* on this branch while the PR is open; it reaches the base branch only through this PR, which is what makes it true. Where the spec did not name the flip, the post-merge checklist (item 9) flips it. Any other docs commit that would be HEAD at the flip carries no CI-skip marker either. The body's close markers name every issue the run resolves — a pre-flight meta-issue the work settles as well as `$1`. The PR is never flipped to ready and never merged by this run; both are the operator's. -9. **A hand-off** that stands on its own: the PR URL; the triage counts in one line; the three `## Review gate` lines verbatim — an invocation the transcript does not show was not made; the Surface and Defer entries verbatim; every operational criterion still open with what the operator must do; the one next action; an offer to post roll-forward context wherever it is relevant — the next issue, a sibling, a meta-issue, a new follow-up — post-merge unless it blocks another issue's start; an offer to sweep the open sibling issues for absence claims this run made false. Deferred conflicts with an ADR lead the hand-off. The hand-off ends with the **post-merge checklist** the operator runs after the merge: sync and prune (`git switch main && git pull --ff-only && git fetch --prune`); post the roll-forwards the hand-off drafted; close the meta-issues the close marker did not; append the frame's `## Rough-in events` row when the PR is a milestone's capstone; flip the roadmap row if this run did not (item 8); and the next runnable command, read off the roadmap. A research milestone's capstone is the verdict artifact, owned by name in the checklist. A learning that should outlive the PR is offered to the knowledge backend only where one is configured, HITL-gated and default-skip (`.claude/rules/knowledge-backend.md` § When to write); otherwise it goes into a rule file or an ADR. +8. **A draft PR** on the pushed branch: title in Conventional Commits with the workstream's scope; body with the planning axis's close marker (`Closes #$1` on github-issues, `Closes $1` on linear — in the body, not only the title; `cbk-conventions.md` § Closes-keyword conventions); a summary of what changed and why, with the ADRs, frame milestone and rules it relies on; a **`## Review gate`** block, written before `## Triage`, in the shape `.claude/rules/pr-review.md` § The floor states — one line each for `/simplify`, `pr-review-toolkit:review-pr` and the sweep, each stating run-or-not with counts and dropped coverage, a waived skill on its line with the break-glass reason, the sweep's line transcribed from the record the workflow returns; a **`## Triage`** block listing every finding under its class — Apply and Apply-with-care as `SHA: fix`, Surface and Defer with the agent's verbatim rationale, Reject with a one-line dismissal — **the body is the audit surface for the PR's whole life**: each later feedback round appends its own `## Triage — round N` block there through `/pr-respond`, never a comment alone, so a reader of the merged PR sees every finding and its disposition in one place; and any review block or label the project's conventions require when the diff touches a surface they guard. **The roadmap row rides this branch, as its last commit before the PR** — where the project keeps `docs/cbk/ROADMAP.md` and the spec names the flip: after the floor (item 7) and before `gh pr create`, the row for this step and the `## Now` paragraph are updated to cite this issue and this PR — *done* when this is the milestone's last R-issue, the progress note otherwise — as one `docs(cascade):` commit with no CI-skip marker (it is HEAD at the flip, and the marker would suppress the auto-review and the required checks — `cbk-conventions.md` § Auto-review trap). The PR number is the next in the repository's shared issue-and-PR sequence (`gh api 'repos/{owner}/{repo}/issues?state=all&sort=created&direction=desc&per_page=1'` plus one) and is checked against the number `gh pr create` returns; a mismatch is one correcting commit. Never a separate PR: a one-row flip with its own PR costs a CI run for nothing, and a flip committed after `gh pr create` costs the same run on the open PR. The row reads *done* on this branch while the PR is open; it reaches the base branch only through this PR, which is what makes it true. Where the spec did not name the flip, the post-merge checklist (item 9) flips it. Any other docs commit that would be HEAD at the flip carries no CI-skip marker either. The body's close markers name every issue the run resolves — a pre-flight meta-issue the work settles as well as `$1`. The PR is never flipped to ready and never merged by this run; both are the operator's. +9. **A hand-off** that stands on its own: the PR URL; the triage counts in one line; the three `## Review gate` lines verbatim — an invocation the transcript does not show was not made; the Surface and Defer entries verbatim; every operational criterion still open with what the operator must do; the one next action; an offer to post roll-forward context wherever it is relevant — the next issue, a sibling, a meta-issue, a new follow-up — post-merge unless it blocks another issue's start; and the **backward sweep** beside it — the open siblings under the same parent carrying `cascade-depth:roughed-in`, read in one call and capped by the milestone's R-count; their *absence* claims only ("no X exists yet", "Y is not wired"), each verified by running the body's own command rather than by recollection; a claim this run's landing falsified is separated from one that was false when written; the default is to report nothing — a claim that still holds is not mentioned — and the repair is rough-in's in-place body refresh, never an edit from this run; an empty sweep is a one-line pass, not an omission. Deferred conflicts with an ADR lead the hand-off. The hand-off ends with the **post-merge checklist** the operator runs after the merge: sync and prune (`git switch main && git pull --ff-only && git fetch --prune`); post the roll-forwards the hand-off drafted; close the meta-issues the close marker did not; append the frame's `## Rough-in events` row when the PR is a milestone's capstone; flip the roadmap row if this run did not (item 8); and the next runnable command, read off the roadmap. A research milestone's capstone is the verdict artifact, owned by name in the checklist. A learning that should outlive the PR is offered to the knowledge backend only where one is configured, HITL-gated and default-skip (`.claude/rules/knowledge-backend.md` § When to write); otherwise it goes into a rule file or an ADR. ## The tests every finish must pass @@ -45,6 +45,7 @@ This command is contract-first. On 2026-09-03 an A/B gave two workhorse-tier exe - **Claims match code.** No comment, commit message or PR-body sentence asserts something the diff contradicts. - **Honesty of the gate.** The three `## Review gate` lines are literally true — an invocation the transcript does not show was not made — and every Apply commit named in `## Triage` exists on the branch with the stated SHA, one finding per commit. - **Green.** The project's `check` task passes at the branch head. +- **Measurement issues.** For an issue whose criteria are measurements, the **verdict rule**'s commit precedes the first measurement commit on the branch (`git log --reverse`), the capstone shows the findings table unchanged against the base branch, and every departure from the rule is weighed in the verdict rather than folded into it. - **No improvisation past the spec.** A spec defect — unverifiable criterion, ADR conflict, missing dependency, drifted doc — is surfaced and the run stops; it is not patched in flight. - **Partial failure surfaces.** A failed external call — `git`, `gh`, an MCP call, the check task, a skill — stops the run, and the hand-off states what reached the remote and what did not, with the choices and their consequences. No blind retry. diff --git a/.claude/commands/pr-respond.md b/.claude/commands/pr-respond.md index b516bc1..fc270a0 100644 --- a/.claude/commands/pr-respond.md +++ b/.claude/commands/pr-respond.md @@ -98,9 +98,11 @@ git push origin If the push fails (auth, network, branch protection that requires being up-to-date with base), stop and surface per § Partial failure handling. Local commits with no remote means the reviewer sees replies citing commit SHAs that aren't visible — confusing. -## Step 7: Top-level summary comment +## Step 7: Top-level summary comment — and the body's round block -Post one top-level comment on the PR (an issue comment, not a review) summarizing the response cycle: +**Append the round to the PR body first.** The PR body is the audit surface for the PR's whole life (`finish.md` item 8): append a `## Triage — round N` block — N the count of feedback rounds so far — listing every thread of this round under its class in the same `SHA: fix` / verbatim-rationale / one-line-dismissal shape as the original `## Triage`, via `gh pr edit $1 --body-file` on the fetched body (append, never rewrite; the original `## Review gate` and `## Triage` blocks stay as they were). A comment alone scrolls away; the body is what a reader of the merged PR opens. + +Then post one top-level comment on the PR (an issue comment, not a review) summarizing the response cycle: ```markdown ## /pr-respond summary diff --git a/.claude/skills/rough-in/references/contract.md b/.claude/skills/rough-in/references/contract.md index 6fe1630..2a25a22 100644 --- a/.claude/skills/rough-in/references/contract.md +++ b/.claude/skills/rough-in/references/contract.md @@ -75,7 +75,10 @@ open-questions list is a different list with its own numbering, cited by its own parsed value present) and flag the rest as operational, in an explicit list. - **Done signal**: one command or observation; an operational signal flagged as such. For a spike-shaped R-issue — one whose criteria are the operator's runs — the signal names the run-and-revise loop (the rows - filled from the runs, with the harness fixed on the same branch until they are), not the draft PR. + filled from the runs, with the harness fixed on the same branch until they are) **and** the record's completeness + check (the by-hand checker that confirms every planned row is present, run by hand and never in the CI gate), + not the draft PR. A measurement-shaped spec commits its verdict rule before any number exists; the + template's measurement variant is the shape. - **Dependencies**: identifiers only — `#N` for existing issues, `R<#>` placeholders for sibling R-issues, which the commit resolves — with one line on what each is *for*; or `None`. Never name an open issue in prose here unless it is a dependency: the executor refuses to proceed on any open issue it finds listed. diff --git a/.claude/skills/rough-in/references/finish-command.md b/.claude/skills/rough-in/references/finish-command.md index df05454..a9086cf 100644 --- a/.claude/skills/rough-in/references/finish-command.md +++ b/.claude/skills/rough-in/references/finish-command.md @@ -115,8 +115,8 @@ This command is contract-first. On 2026-09-03 an A/B gave two workhorse-tier exe 5. **Atomic commits** in Conventional Commits form with the workstream's scope: the red tests, the implementation, each simplify Apply, each review Apply — one focused commit each, never amended across a logical boundary, never squashed on the branch. The squash happens at merge on the base branch. No code or test commit carries the CI-skip marker (`cbk-conventions.md` § `[skip ci]` rule). 6. **The gate, green.** The project's `check` task passes before simplify and review run, and again after every applied finding. Unrelated red is surfaced, not muted — never skipped, expected-failed or commented out to pass. 7. **The review floor, actually run, with the bounded sweep beside it, then triage — once.** First **`/simplify`**, as a skill invocation; triage its findings by the four-class rubric and land its Apply items one commit each with `check` re-run after each. Then, **concurrently**: **`pr-review-toolkit:review-pr`** with no arguments, as a skill invocation, and — where a multi-agent orchestration surface exists — **the review workflow** (`.claude/workflows/review-sweep.js`), sized to the diff and never to the session's effort setting, with the pre-filtered changed-path list passed as `files`. The project-local reviewers ride in it from the roster the workflow reads at runtime (`.claude/rules/pr-review.md` § Project-local agents); beyond them you name the finders this diff needs — none on a small single-surface change the two skills already cover, several on a cross-layer one — and the workflow logs its planned agent count before it finds anything and returns its own gate line. Without an orchestration surface, dispatch the project-local reviewers directly and record `skipped — no orchestration surface` on the sweep's line. The sweep supplements the two skills and never substitutes for either. Triage waits for both to return and stays with you (`pr-review.md` § Triage rubric; the reference half's calibration read at triage): Apply and Apply-with-care land as their own commits with `check` re-run; Surface, Defer and Reject are recorded, never applied. A skill that is uninstalled or errors is a stop-and-surface. A skill that runs without its agent fan-out because the Agent tool is unavailable in your context counts as invoked, and its dropped dimensions are recorded on its `## Review gate` line — never described as equivalent. A failed review agent is dropped coverage, not zero findings. **Describing a review is not running one**: a claimed invocation that did not happen fails this contract outright. The floor runs when the known work is complete and is not run again on a later delta — the reviewer round on the flip covers that, and `/pr-respond` answers it. -8. **A draft PR** on the pushed branch: title in Conventional Commits with the workstream's scope; body with the planning axis's close marker (`Closes #$1` on github-issues, `Closes $1` on linear — in the body, not only the title; `cbk-conventions.md` § Closes-keyword conventions); a summary of what changed and why, with the ADRs, frame milestone and rules it relies on; a **`## Review gate`** block, written before `## Triage`, in the shape `.claude/rules/pr-review.md` § The floor states — one line each for `/simplify`, `pr-review-toolkit:review-pr` and the sweep, each stating run-or-not with counts and dropped coverage, a waived skill on its line with the break-glass reason, the sweep's line transcribed from the record the workflow returns; a **`## Triage`** block listing every finding under its class — Apply and Apply-with-care as `SHA: fix`, Surface and Defer with the agent's verbatim rationale, Reject with a one-line dismissal; and any review block or label the project's conventions require when the diff touches a surface they guard. **The roadmap row rides this branch, as its last commit before the PR** — where the project keeps `docs/cbk/ROADMAP.md` and the spec names the flip: after the floor (item 7) and before `gh pr create`, the row for this step and the `## Now` paragraph are updated to cite this issue and this PR — *done* when this is the milestone's last R-issue, the progress note otherwise — as one `docs(cascade):` commit with no CI-skip marker (it is HEAD at the flip, and the marker would suppress the auto-review and the required checks — `cbk-conventions.md` § Auto-review trap). The PR number is the next in the repository's shared issue-and-PR sequence (`gh api 'repos/{owner}/{repo}/issues?state=all&sort=created&direction=desc&per_page=1'` plus one) and is checked against the number `gh pr create` returns; a mismatch is one correcting commit. Never a separate PR: a one-row flip with its own PR costs a CI run for nothing, and a flip committed after `gh pr create` costs the same run on the open PR. The row reads *done* on this branch while the PR is open; it reaches the base branch only through this PR, which is what makes it true. Where the spec did not name the flip, the post-merge checklist (item 9) flips it. Any other docs commit that would be HEAD at the flip carries no CI-skip marker either. The body's close markers name every issue the run resolves — a pre-flight meta-issue the work settles as well as `$1`. The PR is never flipped to ready and never merged by this run; both are the operator's. -9. **A hand-off** that stands on its own: the PR URL; the triage counts in one line; the three `## Review gate` lines verbatim — an invocation the transcript does not show was not made; the Surface and Defer entries verbatim; every operational criterion still open with what the operator must do; the one next action; an offer to post roll-forward context wherever it is relevant — the next issue, a sibling, a meta-issue, a new follow-up — post-merge unless it blocks another issue's start; an offer to sweep the open sibling issues for absence claims this run made false. Deferred conflicts with an ADR lead the hand-off. The hand-off ends with the **post-merge checklist** the operator runs after the merge: sync and prune (`git switch main && git pull --ff-only && git fetch --prune`); post the roll-forwards the hand-off drafted; close the meta-issues the close marker did not; append the frame's `## Rough-in events` row when the PR is a milestone's capstone; flip the roadmap row if this run did not (item 8); and the next runnable command, read off the roadmap. A research milestone's capstone is the verdict artifact, owned by name in the checklist. A learning that should outlive the PR is offered to the knowledge backend only where one is configured, HITL-gated and default-skip (`.claude/rules/knowledge-backend.md` § When to write); otherwise it goes into a rule file or an ADR. +8. **A draft PR** on the pushed branch: title in Conventional Commits with the workstream's scope; body with the planning axis's close marker (`Closes #$1` on github-issues, `Closes $1` on linear — in the body, not only the title; `cbk-conventions.md` § Closes-keyword conventions); a summary of what changed and why, with the ADRs, frame milestone and rules it relies on; a **`## Review gate`** block, written before `## Triage`, in the shape `.claude/rules/pr-review.md` § The floor states — one line each for `/simplify`, `pr-review-toolkit:review-pr` and the sweep, each stating run-or-not with counts and dropped coverage, a waived skill on its line with the break-glass reason, the sweep's line transcribed from the record the workflow returns; a **`## Triage`** block listing every finding under its class — Apply and Apply-with-care as `SHA: fix`, Surface and Defer with the agent's verbatim rationale, Reject with a one-line dismissal — **the body is the audit surface for the PR's whole life**: each later feedback round appends its own `## Triage — round N` block there through `/pr-respond`, never a comment alone, so a reader of the merged PR sees every finding and its disposition in one place; and any review block or label the project's conventions require when the diff touches a surface they guard. **The roadmap row rides this branch, as its last commit before the PR** — where the project keeps `docs/cbk/ROADMAP.md` and the spec names the flip: after the floor (item 7) and before `gh pr create`, the row for this step and the `## Now` paragraph are updated to cite this issue and this PR — *done* when this is the milestone's last R-issue, the progress note otherwise — as one `docs(cascade):` commit with no CI-skip marker (it is HEAD at the flip, and the marker would suppress the auto-review and the required checks — `cbk-conventions.md` § Auto-review trap). The PR number is the next in the repository's shared issue-and-PR sequence (`gh api 'repos/{owner}/{repo}/issues?state=all&sort=created&direction=desc&per_page=1'` plus one) and is checked against the number `gh pr create` returns; a mismatch is one correcting commit. Never a separate PR: a one-row flip with its own PR costs a CI run for nothing, and a flip committed after `gh pr create` costs the same run on the open PR. The row reads *done* on this branch while the PR is open; it reaches the base branch only through this PR, which is what makes it true. Where the spec did not name the flip, the post-merge checklist (item 9) flips it. Any other docs commit that would be HEAD at the flip carries no CI-skip marker either. The body's close markers name every issue the run resolves — a pre-flight meta-issue the work settles as well as `$1`. The PR is never flipped to ready and never merged by this run; both are the operator's. +9. **A hand-off** that stands on its own: the PR URL; the triage counts in one line; the three `## Review gate` lines verbatim — an invocation the transcript does not show was not made; the Surface and Defer entries verbatim; every operational criterion still open with what the operator must do; the one next action; an offer to post roll-forward context wherever it is relevant — the next issue, a sibling, a meta-issue, a new follow-up — post-merge unless it blocks another issue's start; and the **backward sweep** beside it — the open siblings under the same parent carrying `cascade-depth:roughed-in`, read in one call and capped by the milestone's R-count; their *absence* claims only ("no X exists yet", "Y is not wired"), each verified by running the body's own command rather than by recollection; a claim this run's landing falsified is separated from one that was false when written; the default is to report nothing — a claim that still holds is not mentioned — and the repair is rough-in's in-place body refresh, never an edit from this run; an empty sweep is a one-line pass, not an omission. Deferred conflicts with an ADR lead the hand-off. The hand-off ends with the **post-merge checklist** the operator runs after the merge: sync and prune (`git switch main && git pull --ff-only && git fetch --prune`); post the roll-forwards the hand-off drafted; close the meta-issues the close marker did not; append the frame's `## Rough-in events` row when the PR is a milestone's capstone; flip the roadmap row if this run did not (item 8); and the next runnable command, read off the roadmap. A research milestone's capstone is the verdict artifact, owned by name in the checklist. A learning that should outlive the PR is offered to the knowledge backend only where one is configured, HITL-gated and default-skip (`.claude/rules/knowledge-backend.md` § When to write); otherwise it goes into a rule file or an ADR. ## The tests every finish must pass @@ -128,6 +128,7 @@ This command is contract-first. On 2026-09-03 an A/B gave two workhorse-tier exe - **Claims match code.** No comment, commit message or PR-body sentence asserts something the diff contradicts. - **Honesty of the gate.** The three `## Review gate` lines are literally true — an invocation the transcript does not show was not made — and every Apply commit named in `## Triage` exists on the branch with the stated SHA, one finding per commit. - **Green.** The project's `check` task passes at the branch head. +- **Measurement issues.** For an issue whose criteria are measurements, the **verdict rule**'s commit precedes the first measurement commit on the branch (`git log --reverse`), the capstone shows the findings table unchanged against the base branch, and every departure from the rule is weighed in the verdict rather than folded into it. - **No improvisation past the spec.** A spec defect — unverifiable criterion, ADR conflict, missing dependency, drifted doc — is surfaced and the run stops; it is not patched in flight. - **Partial failure surfaces.** A failed external call — `git`, `gh`, an MCP call, the check task, a skill — stops the run, and the hand-off states what reached the remote and what did not, with the choices and their consequences. No blind retry. diff --git a/.claude/skills/rough-in/references/finish-procedure.md b/.claude/skills/rough-in/references/finish-procedure.md index 2f07533..7f50e3d 100644 --- a/.claude/skills/rough-in/references/finish-procedure.md +++ b/.claude/skills/rough-in/references/finish-procedure.md @@ -212,6 +212,8 @@ If any finding was classified **Defer** because it would conflict with an ADR or **Roll-forward offer** (HITL). If the run surfaced deferred context that a *later* unit of work will need — TODOs, contract facts the next issue depends on, intentional omissions, or a follow-up worth its own issue — **offer** to post a roll-forward comment **wherever it's relevant**: the next issue, a sibling, a downstream milestone issue, a meta-issue, or a brand-new follow-up. Do **not** hardwire it to "the next issue." Default to posting **post-merge** unless the deferred context blocks another issue's start. If nothing was deferred, skip this silently. +**Backward sweep** (HITL offer, beside the roll-forward). What this run landed can make a sibling spec's *absence* claim false — "no adapter exists yet", "the table is not wired". The candidate set is closed: the open siblings under the same parent issue carrying `cascade-depth:roughed-in`, read in **one** call (`gh api repos/{owner}/{repo}/issues/{parent}/sub_issues` on github-issues, the parent's children on linear) and capped by the milestone's R-count — never the whole backlog. Check absence claims only, and verify each by **running the body's own command** (its grep, its test, its probe), not by recalling what this run did. Separate the two kinds: a claim this landing falsified (report it, with the commit) from a claim that was false when written (report it as a spec defect). **Default to not reporting** — a claim that still holds is not mentioned. The repair is rough-in's in-place body refresh, offered to the operator; this run never edits an issue body. An empty sweep is a one-line pass — `backward sweep: N siblings, no absence claim falsified` — never an omitted line. + **Optional learning-runbook write to Notion** (only when knowledge backend = `notion` is configured for this repo, per `.cascade/backends.toml`): if this execution surfaced a learning that would be a useful durable cross-project runbook entry (e.g., a non-obvious gotcha with the stack, a recipe for a recurring task spanning repos, a corrected understanding of an external system's behavior), prompt the operator: *"Want to promote this learning to a Notion runbook page under the Engineering Wiki? Defaults to SKIP."* Defaults to **SKIP**. Per `.claude/rules/knowledge-backend.md` § "When to write" — this is the rare opt-in path; HITL-gated; never default. If the operator opts in, announce the planned write (title, parent, body preview) before committing. This step is gated to genuinely cross-project learnings only — local-to-the-PR observations stay in the PR body and the hand-off summary, not in Notion. **Post-merge checklist** (the hand-off ends with it; the operator runs it after the merge): `git switch main && git pull --ff-only && git fetch --prune`; post the drafted roll-forwards; close the meta-issues the close marker did not; append the frame's `## Rough-in events` row when this PR was the milestone's capstone; flip the roadmap row if Step 10 did not; the next runnable command, read off the roadmap. A research milestone's capstone is the verdict artifact — name it and its owner. diff --git a/.claude/skills/rough-in/references/templates/rough-in-spec-template.md b/.claude/skills/rough-in/references/templates/rough-in-spec-template.md index 46bd84a..145f80a 100644 --- a/.claude/skills/rough-in/references/templates/rough-in-spec-template.md +++ b/.claude/skills/rough-in/references/templates/rough-in-spec-template.md @@ -178,6 +178,23 @@ test, command, or observation that proves the criterion. - [ ] _Specific outcome 2_ - [ ] _Specific outcome 3_ + + ## Test plan + ## Dependencies