diff --git a/skills/stage-chapters/SKILL.md b/skills/stage-chapters/SKILL.md index 23d0224..550bb88 100644 --- a/skills/stage-chapters/SKILL.md +++ b/skills/stage-chapters/SKILL.md @@ -69,7 +69,113 @@ This skill scopes review to *committed* work. If the user has uncommitted change ## Step 3 — Cluster + narrate -> **TODO:** See Issue 11 for the chapter generation prompt port. For now, leave this step as a placeholder. The next revision of this skill will produce a `chapters` array shaped per the schema documented in Step 4. +Using the full diff from Step 2, produce a `chapters` array. Each chapter groups related hunks into a coherent story beat, narrates them for a reviewer unfamiliar with this part of the codebase, and flags judgment calls that need human input. + +### 3a — Clustering rules + +Group hunks by **causal relationship** — changes that set up or enable later changes belong together. + +- Spanning multiple files is expected and correct (e.g., schema + API + UI for one feature = one chapter). +- Moves and refactors are a single chapter — when code is removed from one file and added to another (or a file is deleted and a similar one created), group the deletion and addition hunks together as one "Move/Refactor" chapter, not separate "Remove" and "Add" chapters. +- Split only when changes are truly independent — a reviewer could understand one without knowing about the other. +- Tests belong with their implementation chapter. +- Config/dependency changes can be their own chapter if unrelated to a feature chapter. + +**Chapter ordering:** + +1. Foundation first: types, interfaces, schemas, utilities that others depend on +2. Core logic next: main implementation +3. Integration last: wiring, configuration, tests + +Consider symbol dependencies between chapters — a chapter that introduces a type another chapter uses must come first. + +**Hunk ordering within a chapter:** + +- Group all hunks from the same file together — do not interleave hunks from different files. +- Within the same file, list hunks in ascending `oldStart` order (matching file layout). + +### 3b — Self-validation rules + +Every hunk in the diff **must** appear in exactly one chapter. No hunk may be omitted and no hunk may appear in more than one chapter. + +Identify each hunk by its exact `(filePath, oldStart)` tuple from the unified-diff `@@ -X,Y +A,B @@` header. Use the EXACT `oldStart` value from the `@@` header — do not recount lines yourself. + +- `filePath` is the path after `b/` in the `diff --git a/... b/...` line. +- `oldStart` is the `X` in `@@ -X,Y +A,B @@`. For newly created files the header is `@@ -0,0 +1,N @@`, so `oldStart` is `0`. + +After building the chapters array, verify: +1. The total number of `hunkRefs` across all chapters equals the total number of `@@` headers in the diff. +2. Every `(filePath, oldStart)` pair from the diff appears in exactly one chapter's `hunkRefs`. + +### 3c — Narration rules + +Write each chapter as a story beat — a meaningful step that moves the branch forward, not a summary of files changed. + +- **Title:** action-oriented verb phrase, max 8 words (e.g., "Wire org ID through the API layer"). No filler like "Add support for". +- **Summary:** 2–3 sentences covering what this chapter enables and why. Lead with impact, then connect to the broader purpose. When a chapter builds on a previous one, open with that causal link explicitly (e.g., "Now that X is in place…"). + - Keep paragraphs short. Prefer splitting distinct points into separate short paragraphs (separated by a blank line) rather than writing one long dense paragraph. Each paragraph should convey a single idea. + - Markdown allowed: `**bold**` for emphasis, `*italics*` for nuance, `` `backticks` `` for inline code references, and fenced code blocks when a short snippet (≤ 6 lines) helps illustrate the change. + +### 3d — Key change rules + +Key changes are **judgment calls only a human reviewer can make** — things that require product context, team conventions, or knowledge of the author's intent. Linters, type checkers, and code-review bots already cover correctness and style; skip anything they can catch. Ignore auto-generated files. + +Return an **empty array** when nothing needs human input — do **not** invent items to fill the list. When a chapter is a straightforward rename, type fix, or mechanical refactor with no judgment calls, `keyChanges` should be `[]`. + +Frame each item as a **question**. + +Each key change includes `lineRefs`: one line range per distinct spot the question depends on. Most questions touch a single location, so use one range; only add more when the judgment genuinely spans related code in different places. + +- Use OLD-column line numbers for `side: "deletions"` (left side of the diff). +- Use NEW-column line numbers for `side: "additions"` (right side of the diff). +- Keep ranges tight — point to the specific lines the question is about, not the entire hunk. +- `startLine` and `endLine` must both be positive integers with `endLine >= startLine`. + +**Good examples:** + +- "Should `retryCount` reset when the user switches orgs?" +- "Is a 60-minute session timeout appropriate for this user base, or would 30 minutes be safer?" +- "Does this new index cover the query patterns the team actually uses in production?" + +**Bad examples:** + +- "Check that the auth logic is correct." — vague, verifiable by reading the code +- "The function now handles errors." — changelog item, not a question +- "Make sure the tests pass." — CI catches this, not a human judgment call + +### 3e — Output format + +Produce an array of chapter objects. Each chapter: + +```jsonc +{ + "id": "chapter-1", // unique within the run, e.g. "chapter-1", "chapter-2", … + "order": 1, // positive integer, 1-indexed + "title": "Short imperative title", + "summary": "Why this chapter matters to the reviewer.", + "hunkRefs": [ + // one entry per hunk in the chapter + { "filePath": "path/to/file.ts", "oldStart": 42 } + ], + "keyChanges": [ + // zero or more judgment-call questions + { + "content": "A judgment-call question for the reviewer.", + "lineRefs": [ + { + "filePath": "path/to/file.ts", + "side": "additions", + "startLine": 50, + "endLine": 55 + } + ] + } + ] +} +``` + +- Do **not** invent `hunkRefs` — only use `(filePath, oldStart)` tuples that actually appear in the diff's `@@` headers. +- `keyChanges[].lineRefs` must have at least one entry per key change. ## Step 4 — Write JSON file