@jeffober/thatch 0.1.15 → 0.1.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -15
- package/artifacts/skills/pr-description.md +360 -0
- package/artifacts/skills/split-overlarge-pr.md +112 -0
- package/artifacts/skills/thatch-change-walkthrough.md +211 -0
- package/artifacts/skills/thatch-code-walkthrough.md +194 -0
- package/artifacts/skills/ticket-description.md +399 -0
- package/bin/thatch +1 -1
- package/docs/dev/README.md +42 -18
- package/docs/dev/gotchas.md +27 -0
- package/docs/dev/mcp-parity.md +17 -10
- package/docs/dev/setup-and-hooks.md +4 -4
- package/docs/dev/skills.md +8 -3
- package/docs/qa/README.md +1 -1
- package/docs/qa/use-cases/README.md +4 -2
- package/docs/qa/use-cases/UC-003-extraction-nudge.md +17 -4
- package/docs/qa/use-cases/UC-005-setup-install.md +2 -2
- package/docs/qa/use-cases/UC-006-cursor-hook-lifecycle.md +4 -3
- package/docs/qa/use-cases/UC-009-flush-tools-tiers.md +3 -1
- package/docs/qa/use-cases/UC-014-skill-install-drift.md +3 -3
- package/docs/qa/use-cases/UC-016-concurrent-session-isolation.md +4 -3
- package/docs/qa/use-cases/UC-019-archived-memory-lifecycle.md +36 -0
- package/docs/qa/use-cases/UC-020-extraction-escalation.md +38 -0
- package/docs/user/README.md +27 -5
- package/package.json +3 -2
- package/src/index.ts +15 -15
- package/src/mcp.ts +1 -1
- package/src/prompts.ts +41 -1
- package/src/setup.ts +1 -1
- package/src/skills.ts +11 -3
package/README.md
CHANGED
|
@@ -8,15 +8,16 @@ Persistent memory and useful dev skills for AI coding agents that requires zero
|
|
|
8
8
|
manual config.
|
|
9
9
|
|
|
10
10
|
Works with **OpenCode** (as a plugin), **Claude Code** (as an MCP server), and
|
|
11
|
-
**Cursor** (as
|
|
11
|
+
**Cursor** (as a local `stdio` MCP server).
|
|
12
12
|
|
|
13
13
|
Each session inherits the accumulated knowledge of every session before it —
|
|
14
14
|
project architecture, conventions, gotchas, user preferences — so your agent
|
|
15
15
|
starts with context instead of a blank slate. Stores are per-repo with a shared
|
|
16
16
|
`global` store.
|
|
17
17
|
|
|
18
|
-
On top of the memory layer, thatch ships a suite of skills for managing
|
|
19
|
-
performing in-depth, structured code reviews,
|
|
18
|
+
On top of the memory layer, thatch ships a suite of skills for managing
|
|
19
|
+
memories, performing in-depth, structured code reviews, managing the software
|
|
20
|
+
development life cycle, and researching your code base.
|
|
20
21
|
|
|
21
22
|
No API keys, no cloud services; everything runs on your machine.
|
|
22
23
|
|
|
@@ -72,8 +73,8 @@ thatch setup --claude
|
|
|
72
73
|
`setup` does four things:
|
|
73
74
|
1. Writes `.mcp.json` — registers the MCP server (Claude Code spawns `thatch mcp` as a stdio process)
|
|
74
75
|
2. Appends instructions to `CLAUDE.md` — session startup, when to write, what to store
|
|
75
|
-
3. Installs hooks in `.claude/settings.json` — `SessionStart` runs `thatch reminder` (recall nudge + hygiene), `UserPromptSubmit`
|
|
76
|
-
4. Installs skill files to `~/.claude/skills/` — memory workflow skills (project primer, fact extractor, dedup classifier, session reflection)
|
|
76
|
+
3. Installs hooks in `.claude/settings.json` — `SessionStart` runs `thatch reminder` (recall nudge + hygiene), `PostToolBatch` feeds the extraction queue, `UserPromptSubmit` peeks the queue and nudges you to save new knowledge
|
|
77
|
+
4. Installs skill files to `~/.claude/skills/` — memory workflow skills (project primer, fact extractor, dedup classifier, session reflection), code review skills (6 review specialists + synthesizer + context + workflow research), walkthrough skills, and writing skills. See [Skills](#skills) below.
|
|
77
78
|
|
|
78
79
|
Restart Claude Code and thatch's tools are available as `mcp__thatch__*`.
|
|
79
80
|
|
|
@@ -109,6 +110,7 @@ the bare `thatch` command so the config survives updates.
|
|
|
109
110
|
| `thatch_store_list` | `mcp__thatch__store_list` | List all stores |
|
|
110
111
|
| `thatch_find_duplicates` | `mcp__thatch__find_duplicates` | Surface pairs of suspiciously similar memories |
|
|
111
112
|
| `thatch_dedup_mark_checked` | `mcp__thatch__dedup_mark_checked` | Record a reviewed pair so it stops being re-reported |
|
|
113
|
+
| `thatch_extraction_done` | `mcp__thatch__extraction_done` | Acknowledge extraction nudge was dispatched to a sub-agent; drains the buffer |
|
|
112
114
|
|
|
113
115
|
## Skills
|
|
114
116
|
|
|
@@ -133,12 +135,28 @@ agent follows to maintain its own memory and review code systematically.
|
|
|
133
135
|
| `thatch-review-state-flow` | Data flow and contracts — module boundaries, implicit state machines, error propagation |
|
|
134
136
|
| `thatch-review-no-slop` | AI writing anti-pattern detection — change narration, fourth wall breaks, hedging |
|
|
135
137
|
| `thatch-review-breadcrumbs` | Comment narrative — do comments form a coherent outline of the code's behavior? |
|
|
138
|
+
| `thatch-review-mark-and-sweep` | Mechanical change completeness — whole-repo sweep for stragglers after renames, flag removals, API substitutions |
|
|
136
139
|
| `thatch-review-synthesizer` | Verify specialist findings against actual code, deduplicate, produce severity-grouped report |
|
|
137
140
|
| `thatch-review-context` | Gather project/feature context (PRs, tickets, TODOs, deferred work) before a review |
|
|
138
141
|
| `thatch-workflow-research` | Research code workflows affected by a change or planned change, before reviewing or planning |
|
|
139
|
-
| `thatch-
|
|
142
|
+
| `thatch-change-walkthrough` | Explain a change as a teaching walkthrough with file:line citations |
|
|
143
|
+
| `thatch-code-walkthrough` | Explain a feature, module, or workflow as a teaching walkthrough; also drafts high-level docs |
|
|
140
144
|
|
|
141
|
-
|
|
145
|
+
### Writing
|
|
146
|
+
|
|
147
|
+
| Skill | What it does |
|
|
148
|
+
|-------|-------------|
|
|
149
|
+
| `pr-description` | Draft PR descriptions using instructional-design scaffolding with bold/italic emphasis for scanning |
|
|
150
|
+
| `ticket-description` | Draft ticket or issue descriptions (Linear or Jira) with instructional-design scaffolding |
|
|
151
|
+
| `split-overlarge-pr` | Split already-completed work from an overlarge PR into human-reviewable, release-safe PRs |
|
|
152
|
+
|
|
153
|
+
### opencode-only
|
|
154
|
+
|
|
155
|
+
| Skill | What it does |
|
|
156
|
+
|-------|-------------|
|
|
157
|
+
| `thatch-code-review` | Multi-agent review coordinator — triage, partition, dispatch specialists in parallel |
|
|
158
|
+
|
|
159
|
+
The six review specialists run independently and can be used standalone. The
|
|
142
160
|
synthesizer verifies their findings against the actual code — reading each
|
|
143
161
|
cited location to confirm the evidence matches — before producing a final
|
|
144
162
|
report. The coordinator (opencode only) orchestrates the full pipeline by
|
|
@@ -156,10 +174,13 @@ thatch list [store] List memory labels in a store
|
|
|
156
174
|
thatch show <label> [store] Display a memory by label
|
|
157
175
|
thatch forget <label> [store] Remove a memory by label
|
|
158
176
|
thatch search <query> [store] Semantic search (cosine similarity)
|
|
159
|
-
thatch prime Prime project memory (runs via opencode or claude)
|
|
160
|
-
thatch mcp Start the stdio MCP server (for Claude Code)
|
|
161
|
-
thatch reminder
|
|
177
|
+
thatch prime Prime project memory (runs via opencode, Cursor, or claude)
|
|
178
|
+
thatch mcp Start the stdio MCP server (for Claude Code and Cursor)
|
|
179
|
+
thatch reminder [--json] Print session-start reminder (for hooks)
|
|
162
180
|
thatch hygiene Print the hygiene report (standalone)
|
|
181
|
+
thatch buffer-batch Append Claude Code PostToolBatch output to extraction queue
|
|
182
|
+
thatch buffer-tool Append Cursor postToolUse output to extraction queue
|
|
183
|
+
thatch flush-tools [--json] Peek extraction queue; print extraction + recall nudges
|
|
163
184
|
thatch setup --claude [--cursor] [--global] Install config + instructions + hooks + skills
|
|
164
185
|
```
|
|
165
186
|
|
|
@@ -176,7 +197,7 @@ cd /path/to/your/project
|
|
|
176
197
|
thatch prime
|
|
177
198
|
```
|
|
178
199
|
|
|
179
|
-
This detects `opencode
|
|
200
|
+
This detects `opencode`, Cursor, or `claude` on your PATH and runs the
|
|
180
201
|
`thatch-project-primer` skill, which guides the agent to:
|
|
181
202
|
|
|
182
203
|
1. Recall any existing project memories
|
|
@@ -204,9 +225,10 @@ interactions and nudges the host agent to persist durable knowledge itself,
|
|
|
204
225
|
using the `thatch-fact-extractor` skill. The agent's own model decides what's
|
|
205
226
|
worth remembering — keeping thatch dependency-free and the agent in control.
|
|
206
227
|
On OpenCode, the plugin hooks `tool.execute.after` and `chat.message` to
|
|
207
|
-
buffer and
|
|
208
|
-
hooks drive a file-backed
|
|
209
|
-
|
|
228
|
+
buffer and peek (the buffer persists until the agent writes a memory). On
|
|
229
|
+
Claude Code, `PostToolBatch` and `UserPromptSubmit` hooks drive a file-backed
|
|
230
|
+
queue with the same peek-not-drain semantics. Both paths produce the same
|
|
231
|
+
payload for the fact-extractor skill.
|
|
210
232
|
|
|
211
233
|
## OpenCode vs Claude Code vs Cursor parity
|
|
212
234
|
|
|
@@ -218,7 +240,7 @@ fact-extractor skill.
|
|
|
218
240
|
| Compaction context | `experimental.session.compacting` hook | **Gap**: no equivalent (CLAUDE.md persists) | **Gap**: no equivalent |
|
|
219
241
|
| Extraction nudge | `tool.execute.after` + `chat.message` | `PostToolBatch` + `UserPromptSubmit` (file-backed queue) | `postToolUse` + `beforeSubmitPrompt` (file-backed queue) |
|
|
220
242
|
| Setup detection at startup | n/a (plugin auto-installs) | `checkSetup` in MCP server: detects missing/broken instructions | Same as Claude Code |
|
|
221
|
-
| Skills |
|
|
243
|
+
| Skills | 19 (18 shared + coordinator) | 18 (shared only) | 18 (shared only) |
|
|
222
244
|
| Store detection | `worktree` param from plugin | `CLAUDE_PROJECT_DIR` env var | `CURSOR_PROJECT_DIR` then `CLAUDE_PROJECT_DIR` |
|
|
223
245
|
|
|
224
246
|
See [docs/dev/mcp-parity.md](docs/dev/mcp-parity.md) for the full analysis.
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pr-description
|
|
3
|
+
description: Draft a PR description using instructional-design scaffolding (SYNOPSIS / PURPOSE / DESCRIPTION / WALK-THROUGH / NOTES) with bold and italic emphasis on the phrases that carry the meaning, so a reviewer skimming only the emphasized fragments still gets the story. Use when the user asks you to write, draft, or update a PR description or PR body, or when running `gh pr create` and no body has been supplied. Do NOT use for commit messages, release notes, or changelog entries.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Writing PR descriptions
|
|
7
|
+
|
|
8
|
+
## The reader
|
|
9
|
+
|
|
10
|
+
You are writing for a senior engineer who knows the tech stack and general engineering vocabulary but has never touched this feature, subsystem, or branch. They may not know subsystem-specific jargon or acronyms: a crypto term like DEK, an auth term like the SAML assertion, a scanning term like a ScanRun, a results term like the frozen materialized view. Their goal is to review the diff. Your goal is to raise their baseline understanding just enough that the diff becomes self-explanatory, without making them check out the branch or open a design doc.
|
|
11
|
+
|
|
12
|
+
The description is not a design doc, changelog, or implementation journal. It is a scaffold that front-loads the context the reviewer needs, didactically layered so they absorb it in the order that makes the diff land.
|
|
13
|
+
|
|
14
|
+
This is **instructional design**, not documentation. Each section has a cognitive goal for the reader:
|
|
15
|
+
- SYNOPSIS: orient to the class of change and affected area.
|
|
16
|
+
- PURPOSE: make the reader agree there is a problem worth solving.
|
|
17
|
+
- DESCRIPTION: teach the system's current behavior and how this change alters it.
|
|
18
|
+
- WALK-THROUGH (when needed): walk the reviewer through the changed workflow step by step.
|
|
19
|
+
- NOTES: flag scope limits, intentional regressions, and things AI reviewers will misread.
|
|
20
|
+
- robots.txt (when needed): dense, machine-addressed context that heads off recurring false positives from automated reviewers.
|
|
21
|
+
|
|
22
|
+
Layer the knowledge so each section builds on the previous one. The reader should never encounter a concept in layer N that was not introduced in layer N-1.
|
|
23
|
+
|
|
24
|
+
AI-authored PRs tend to be large. The description is the reader's lever against that: a good one lets them say "small description, easy to scan" and then read the code critically. A bad one makes them skip the description, wade through the diff cold, and miss intent.
|
|
25
|
+
|
|
26
|
+
## Structure
|
|
27
|
+
|
|
28
|
+
Sections, in order: SYNOPSIS, PURPOSE, DESCRIPTION, WALK-THROUGH (conditional), NOTES (conditional), robots.txt (conditional, always last).
|
|
29
|
+
|
|
30
|
+
**SYNOPSIS, PURPOSE, and DESCRIPTION are mandatory** - even for a one-line, single-concern change. A tiny PR gets short sections, not fewer sections. WALK-THROUGH and NOTES appear only when warranted; omit them when empty. robots.txt appears only after an automated reviewer has produced a false positive worth heading off (see its section); it is always the final section.
|
|
31
|
+
|
|
32
|
+
**Scale the body to the diff's conceptual size**, not its structure's capacity. A 2-file, single-concern change (add a flag, guard a branch, rename a symbol, bump a constant) is a few lines per section. SYNOPSIS one line, PURPOSE one to three, DESCRIPTION one short paragraph, NOTES if needed. The layered DESCRIPTION machinery below is for changes with real before/after mechanics to teach; when the diff is self-evident once you know the intent, collapse it. If your draft for a small change runs past ~15 lines of body, you are padding. Cut until each remaining line earns its place. Most of this skill's apparatus exists to tame large PRs; applying it wholesale to a small one produces exactly the bloat the skill warns against.
|
|
33
|
+
|
|
34
|
+
### SYNOPSIS
|
|
35
|
+
|
|
36
|
+
One to two lines. Orient only. The reader should come away knowing the class of change (bugfix, refactor, feature, revert, infra, cleanup) and the affected area.
|
|
37
|
+
|
|
38
|
+
SYNOPSIS may use subsystem-specific terms as scan anchors (that is its job). It does not define them. The first teaching section (PURPOSE or DESCRIPTION) picks up that burden. An outsider who does not know the terms should still be able to orient from the plain-English nouns around them.
|
|
39
|
+
|
|
40
|
+
Include a ticket link if one exists. Format: `Ticket: [PLAT-139](https://<host>/browse/PLAT-139)` on its own line directly under the SYNOPSIS text.
|
|
41
|
+
|
|
42
|
+
Ticket resolution order (stop at first hit):
|
|
43
|
+
1. Branch name (e.g. `plat-139-m3` -> `PLAT-139`). Case-insensitive; ignore trailing `-mN`, `-partN`, `-wip` segments.
|
|
44
|
+
2. Commit messages in the PR range (`git log $MERGE_BASE..HEAD` - look for `PROJ-123` patterns or `Refs:`/`Fixes:` trailers).
|
|
45
|
+
3. An open draft PR description or linked branch metadata, if available via `gh`.
|
|
46
|
+
4. If none of the above yields a ticket, ask the user once: "Ticket for this PR? (or 'none')". Accept `none` to skip, a bare ID (resolve against the project's tracker base URL), or a full URL.
|
|
47
|
+
|
|
48
|
+
Do not fabricate ticket IDs. If no signal exists and the user says `none`, omit the line entirely rather than leaving a placeholder.
|
|
49
|
+
|
|
50
|
+
### PURPOSE
|
|
51
|
+
|
|
52
|
+
Frame the problem. Lead with the conclusion, then provide the evidence, not the other way around. State what is wrong, then explain why. For example:
|
|
53
|
+
|
|
54
|
+
- "The export endpoint loads every row into memory before serializing, so a large tenant runs the pod out of memory" not "the endpoint allocates a slice per row, and with enough rows... which is why the pod runs out of memory."
|
|
55
|
+
- "This handler runs one query per result row, so a page of 50 items fires 51 queries" not "the handler loops over results issuing a query each time... resulting in an N+1 query pattern."
|
|
56
|
+
- "The retry loop has no cap, so a persistent failure spins forever" not "the loop re-enters on error without a counter... meaning it never terminates."
|
|
57
|
+
|
|
58
|
+
The reader should know what the problem is before they read why it happens.
|
|
59
|
+
|
|
60
|
+
No solution yet. The reader should finish this section agreeing there is something to address, even with zero code knowledge.
|
|
61
|
+
|
|
62
|
+
Separate the problem from its context. The problem statement is one paragraph. Hazard rating and prior-work context go in a separate paragraph. The reader who already agrees there is a problem can skip the rating; the reader who does not should not have to wade through it to find the problem.
|
|
63
|
+
|
|
64
|
+
If the change is preventive (no current defect), say why it is worth fixing despite the low risk. "No incident has hit this shape" is a demotivation, not a motivation. Answer "why now?": a prior PR identified it as a follow-up, the API still permits a failure shape, or the next planned change would make it worse. The reviewer's question is "should I spend time on this?" - give them the answer.
|
|
65
|
+
|
|
66
|
+
When a ticket description is available, use its problem statement as the seed for PURPOSE. But verify it against the actual code. Ticket descriptions can be stale or wrong. If the ticket says "the frobnicator crashes on null input" but the diff shows you fixing a race condition in the frobnicator, the PURPOSE describes the race condition, not the null input. Flag the discrepancy to the user.
|
|
67
|
+
|
|
68
|
+
### DESCRIPTION
|
|
69
|
+
|
|
70
|
+
How much structure DESCRIPTION needs depends on the change's conceptual size.
|
|
71
|
+
|
|
72
|
+
**Small, self-evident change** (add a flag, guard a branch, rename a symbol, bump a constant): collapse to a sentence or two stating what the PR adds/changes. Do not manufacture a "how the code behaves today" paragraph for a change whose intent already makes the diff obvious. That is padding, not scaffolding.
|
|
73
|
+
|
|
74
|
+
**Medium change with non-obvious before/after mechanics**: three layers, in order. Each layer is as short as possible while remaining honest.
|
|
75
|
+
|
|
76
|
+
1. **How the existing code behaves.** High-level narrative, not a function walk. Name the key components, their contract, and the specific behavior that matters for this change. Introduce decision points explicitly - they become anchors for layer 2.
|
|
77
|
+
2. **What this PR changes.** For each decision point named in layer 1, say what it does now. Keep parallelism: same names, same order. The reader's mental model from layer 1 is the load-bearing structure here.
|
|
78
|
+
3. **Why that fixes PURPOSE.** One or two sentences linking the mechanics in layer 2 to the harm named in PURPOSE. If the fix has limits (doesn't cover case Z, follow-up needed), call them out here in one line.
|
|
79
|
+
|
|
80
|
+
The didactic spine: PURPOSE names a harm, layer 1 names the mechanism, layer 2 changes the mechanism, layer 3 shows the harm is gone. Names carry through. The reader builds one model, not four.
|
|
81
|
+
|
|
82
|
+
**Large change with a workflow or lifecycle**: keep DESCRIPTION to root-cause and design concept only (what is wrong, what is the approach). Use a separate WALK-THROUGH section for the step-by-step mechanics.
|
|
83
|
+
|
|
84
|
+
Organize by **workflow or data-flow**, not by touched symbol. A bullet list of API changes reads as disconnected touchpoints. A walkthrough following one object through the system reads as a story. If the change touches a request lifecycle, follow the request. If it touches a data pipeline, follow the data.
|
|
85
|
+
|
|
86
|
+
### WALK-THROUGH
|
|
87
|
+
|
|
88
|
+
When the change has a sequence of steps - a lifecycle, a workflow, a data flow through the system - split the mechanics into a numbered WALK-THROUGH. Keep DESCRIPTION to root-cause + design concept only.
|
|
89
|
+
|
|
90
|
+
Default to a numbered outline. A flat list of steps, with an occasional inline branch ("if the path is not in the registry, return a 404; otherwise continue to step 6"), covers almost every workflow. The bar for a diagram or Mermaid chart is high: reach for one only when the flow genuinely needs two dimensions to read - a graph network with many nodes and edges, or a workflow that recurses, forks, and rejoins in ways a linear outline cannot follow without constant back-references. If the flow is one or two levels deep and does not recurse or redirect, an outline is clearer and cheaper to maintain than a diagram.
|
|
91
|
+
|
|
92
|
+
Each numbered step states what changed at that stage of the workflow. Bold the **key phrase** that identifies the step (the scan anchor). The rest of the step is plain prose.
|
|
93
|
+
|
|
94
|
+
Format:
|
|
95
|
+
|
|
96
|
+
1. **Request enters the handler** - the new guard checks the tenant scope before dispatching.
|
|
97
|
+
2. **Validation runs** - the validator now rejects empty payloads that previously passed through.
|
|
98
|
+
3. **Database write** - the write happens inside the transaction boundary, not after it.
|
|
99
|
+
|
|
100
|
+
Rules:
|
|
101
|
+
- One step per workflow stage, in execution order.
|
|
102
|
+
- State what changed, not what you did. "The handler now checks tenant scope" not "I added a tenant scope check."
|
|
103
|
+
- Cut parenthetical API-symbol asides. The diff carries symbol detail.
|
|
104
|
+
- Cut rationale asides from steps. If the why matters, it goes in DESCRIPTION layer 3 or NOTES.
|
|
105
|
+
- Italics for orientation asides: _This is where the deadlock lived._
|
|
106
|
+
|
|
107
|
+
### NOTES
|
|
108
|
+
|
|
109
|
+
Always a `## NOTES` markdown header. Never a bare `Notes:` line ending a section.
|
|
110
|
+
|
|
111
|
+
Use NOTES for:
|
|
112
|
+
- Intentional behavior changes that look like regressions.
|
|
113
|
+
- Scope disclaimers (what this PR does NOT do) - max two sentences, no hedging.
|
|
114
|
+
- Deferred follow-up items (`Remaining work:` bullet list).
|
|
115
|
+
- Ticket scope mismatches (when the PR partially addresses the ticket).
|
|
116
|
+
- Anything AI reviewers (Cursor BugBot, CodeRabbit) will misread.
|
|
117
|
+
|
|
118
|
+
One bullet per item. Bold the **leading noun** in each bullet as the scan anchor.
|
|
119
|
+
|
|
120
|
+
Each bullet is either a short flag or a self-contained explanation. A short flag names the thing and points to where the full rationale lives: "no singleflight on the load path - see the `mu` field comment." A self-contained explanation states the thing and its reason in plain English, in one or two sentences that a reader with no prior context can parse. Do not compress a paragraph into a subordinate clause. If the rationale needs more than two sentences, it belongs in code comments or the ticket, not in NOTES.
|
|
121
|
+
|
|
122
|
+
If there are no notes, omit the section entirely. Do not emit an empty `## NOTES` header.
|
|
123
|
+
|
|
124
|
+
### robots.txt
|
|
125
|
+
|
|
126
|
+
The final section, and the only one addressed to machines rather than people. Its purpose: head off false positives from automated reviewers (Cursor BugBot, CodeRabbit, a local LLM review pass) that keep misreading the same part of the diff. When a bot flags something that is not a bug because it failed to trace a path upstream or downstream, and a code comment cannot carry enough context to prevent the misread, record the missing context here so the next review round has it.
|
|
127
|
+
|
|
128
|
+
Render it as a collapsed GitHub details block, not a normal visible section. The summary is literally `robots.txt`. A bot still sees the content in the PR body, and a human can leave it collapsed unless they are broken in the precise way this section requires.
|
|
129
|
+
|
|
130
|
+
Format:
|
|
131
|
+
|
|
132
|
+
```md
|
|
133
|
+
<details>
|
|
134
|
+
<summary>robots.txt</summary>
|
|
135
|
+
|
|
136
|
+
<!-- robots.txt: context for automated reviewers to prevent recurring false positives.
|
|
137
|
+
Add entries as dense as you like; human-legibility rules do not apply below the human-warning line.
|
|
138
|
+
Explain what the flagged code does and the intent behind it; never instruct a reviewer to ignore or skip a finding.
|
|
139
|
+
Accumulate entries across review rounds. Keep the human-warning line first. -->
|
|
140
|
+
|
|
141
|
+
Human reader: this section is written for automated reviewers, not people. It will not help you review the diff. Skip it unless you are the specific kind of person who reads terms-of-service agreements for pleasure.
|
|
142
|
+
|
|
143
|
+
<dense machine-directed entries here>
|
|
144
|
+
|
|
145
|
+
</details>
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
After the human-warning line, human-legibility rules are suspended. Write for LLM consumption in whatever is densest: no prose scaffolding, no bold, no one-idea-per-sentence, no plain-ASCII constraint. Fragments, symbol soup, and abbreviations are all fine. The only goal is maximum context per token for a machine reader.
|
|
149
|
+
|
|
150
|
+
What goes here is *explanation and intent*, never suppression. Do not write "ignore the finding about X." Write what X actually does, the invariant it upholds, and the upstream or downstream fact the bot missed, so the bot can re-evaluate and clear its own false positive. A blanket "skip checking X" is a rubber-stamp lever and a prompt-injection surface; refuting a specific misread with a verifiable fact is not.
|
|
151
|
+
|
|
152
|
+
Entries accumulate. Each review round that surfaces a new false positive adds an entry, so the section grows into a standing set of clarifications that pre-empt the same misreads on the next round.
|
|
153
|
+
|
|
154
|
+
Because this section is usually added while responding to a bot's comment (not while running this skill end to end), the hidden HTML comment at the top carries editing guidance for the next LLM, which will not have this skill loaded.
|
|
155
|
+
|
|
156
|
+
Omit the whole section unless there is at least one real false positive to address. It is not scaffolding to fill in preemptively.
|
|
157
|
+
|
|
158
|
+
## Emphasis for scanning: bold and italics
|
|
159
|
+
|
|
160
|
+
Bold and italicize the "save points" - the phrases that carry meaning - not whole sentences. A reader who skims *only* the bold and italic fragments should get the story; full prose is for when they want detail.
|
|
161
|
+
|
|
162
|
+
**What to bold:** phrases that name the **change itself** - the component, the failure mode, the mechanism, the behavior after the change. These are the nouns and verbs that would appear in a diff of the design, not a diff of the code. "There is a **circular wait** in the **KeyManager**" names the failure mode and the component. "**store the result in the in-memory cache**" names the action and the destination.
|
|
163
|
+
|
|
164
|
+
**What to italicize:** phrases that orient the reader to **significance** - the conclusion a paragraph is building toward, or the outcome that makes the change matter. _There is a circular wait in the KeyManager_ in PURPOSE. _the circular wait cannot form_ in DESCRIPTION's payoff paragraph. Italics mark the load-bearing insight; bolds mark the load-bearing nouns and verbs.
|
|
165
|
+
|
|
166
|
+
**What NOT to bold or italicize:** history ("PLAT-134 removed the deadlock"), hazard detail ("it only triggers during the first key fetch"), justification ("they are idempotent and cost pennies"), or connective tissue ("the reader should finish this section"). These are context and support; they do not carry the story.
|
|
167
|
+
|
|
168
|
+
**Where formatting goes:**
|
|
169
|
+
- SYNOPSIS: bold the key noun phrases (scan anchor for the whole PR).
|
|
170
|
+
- PURPOSE: bold and italicize the conclusion phrase (the problem statement), then bold key nouns in the explanation. Italicize the hazard-motivation insight if there is one.
|
|
171
|
+
- DESCRIPTION: bold the mechanism nouns and verbs in each paragraph. Italicize the payoff phrase in the final paragraph (the "why that fixes PURPOSE" sentence).
|
|
172
|
+
- WALK-THROUGH step leads: bold the phrase that identifies each step.
|
|
173
|
+
- NOTES bullets: bold the leading noun.
|
|
174
|
+
|
|
175
|
+
Rules:
|
|
176
|
+
- Bold once per concept per section. If `rate limiter` appears three times, bold only the first.
|
|
177
|
+
- Prefer bolding things (components, states, thresholds, identifiers) and verbs of change (replaces, removes, guards, moves) over adjectives.
|
|
178
|
+
- Italicize at most one phrase per paragraph. If two phrases compete, pick the one that carries the paragraph's point.
|
|
179
|
+
- Never bold a whole sentence. Never italicize a whole sentence. Never bold a whole bullet.
|
|
180
|
+
- In WALK-THROUGH steps and NOTES bullets, the leading noun is usually the right anchor; bold it, leave the qualifier plain.
|
|
181
|
+
- A phrase may be both bold and italicized when it is both a change-naming noun and the paragraph's load-bearing insight: **_circular wait_**. Use sparingly.
|
|
182
|
+
|
|
183
|
+
Scan check before submitting: read only the bold and italic fragments top-to-bottom. If that reading does not convey the shape of the change, you bolded the wrong words (or the prose is padding around them).
|
|
184
|
+
|
|
185
|
+
## Prose style
|
|
186
|
+
|
|
187
|
+
These are hard rules, not suggestions.
|
|
188
|
+
|
|
189
|
+
1. **One idea per sentence.** Split clause-chains. If a sentence has more than one comma separating independent clauses, it is two sentences. One topic per paragraph: if a paragraph shifts from the problem to its risk rating, split it. The reader who skims paragraph leads should get the section's structure.
|
|
190
|
+
2. **Literal phrasing beats compressed idiom.** Write for an unfamiliar reader: "assigned at construction" not "baked in". Spell out "perform database operations against a new connection within a transaction" rather than "hidden connection acquisition mid-transaction". Implementation verbs are compressed idiom: do not use method names as verbs in prose. "store the result in the in-memory cache" not "publish it". "check the cache" not "peek the cache". Prefer plain English nouns over code-domain nouns, even when the code-domain noun is technically correct: "reading the row from the database" not "the row read"; "a request waiting for a worker" not "a waiter"; "overwritten with zeros" not "zeroized"; "the queued scan jobs" not "the backlog". If a word sounds like it belongs in a source file rather than a sentence, replace it.
|
|
191
|
+
3. **Define subsystem-specific terms on first use.** If a term is specific to this subsystem (not general engineering vocabulary), expand or briefly gloss it the first time it appears in prose. "the DEK (the symmetric key used to encrypt secrets at rest)" not just "the DEK". "the SAML assertion (the signed XML document an identity provider returns to prove who the user is)" not just "the assertion". After the first definition, use the term freely. Definitions go in DESCRIPTION layer 1 or PURPOSE, not SYNOPSIS.
|
|
192
|
+
4. **No design-narration phrases.** Delete "it anchors the design", "the fix", "this change", "the new approach". State the fact plainly.
|
|
193
|
+
5. **No authoring-sequence narration.** Never describe the order you assembled things in, which commit does what, or what a later commit will add. Describe the PR as it stands. Pending work goes in a `Remaining work:` bullet list under NOTES.
|
|
194
|
+
6. **Italics for orientation asides.** Use `_italics_` for a one-phrase aside that orients the reader: _This is where the deadlock lived_. Not for emphasis.
|
|
195
|
+
7. **Plain ASCII only.** No smart quotes, smart apostrophes, em dashes, en dashes, ellipsis glyphs, or arrow glyphs. Use plain hyphens (sparingly) for asides; semicolons are often better.
|
|
196
|
+
8. **No buzzwordy abstractions.** If a phrase sounds like it is trying to sound smart, cut or replace it. Name the code and behavior directly. "identity contract" -> "the struct field that identifies the owner". "canonical hash" -> "the SHA-256 we compute on ingestion".
|
|
197
|
+
9. **Avoid loaded language.** Use neutral, current terminology unless the repo's established name is different. Prefer allowlist/blocklist over whitelist/blacklist, primary/replica over master/slave, and precise role names over moralized labels like "bad" or "evil".
|
|
198
|
+
10. **No parenthetical API-symbol asides in WALK-THROUGH steps.** The diff carries symbol detail. If the reader needs the function name, they will find it in the diff.
|
|
199
|
+
|
|
200
|
+
## Length and style
|
|
201
|
+
|
|
202
|
+
Target: the reader can take in the whole description in under 60 seconds. Err on the shorter side.
|
|
203
|
+
|
|
204
|
+
Scale the body to the diff's conceptual size:
|
|
205
|
+
- Trivial 2-file change: ~15-line ceiling. SYNOPSIS one line, PURPOSE one to three, DESCRIPTION one short paragraph, NOTES if needed.
|
|
206
|
+
- Moderate refactor: one tight paragraph or bullet set per section.
|
|
207
|
+
- Large change with WALK-THROUGH: as long as the walkthrough needs, but no longer. Each step earns its place.
|
|
208
|
+
|
|
209
|
+
If your draft for a small change runs past ~15 lines of body, you are padding. Cut until each remaining line earns its place.
|
|
210
|
+
|
|
211
|
+
Inside sections, telegraphic bullet style is fine: lowercase start, abbreviations (`w/`, `1x`, `~`), parenthetical shorthand. Full sentences only when required for clarity. The section headers are the only formal structure.
|
|
212
|
+
|
|
213
|
+
**GitHub rendering**: GitHub renders a single newline as a visible hard line break, not a soft-wrap join. Put each narrative paragraph on one physical line. Separate paragraphs with a blank line. Bullets stay one per line. Do not split a paragraph across multiple physical lines; GitHub will render each line break as a separate visible line.
|
|
214
|
+
|
|
215
|
+
## Ticket context and plan changes
|
|
216
|
+
|
|
217
|
+
When a ticket is resolved (see SYNOPSIS ticket resolution order), fetch its description before drafting. The ticket is context for the PR description, not a checklist for code review. Use it to understand the original plan, then explain only the differences a reviewer needs to know.
|
|
218
|
+
|
|
219
|
+
Context process:
|
|
220
|
+
1. Fetch the ticket description. Resolution order by tracker:
|
|
221
|
+
- **Linear**: use the `linear_get_issue` MCP tool if the Linear server is connected.
|
|
222
|
+
- **Jira**: use `webfetch` on the Jira URL, or the Jira MCP tools if connected.
|
|
223
|
+
- **No MCP or CLI access**: ask the user to paste the ticket description.
|
|
224
|
+
2. Use the ticket's problem statement as the seed for PURPOSE, but verify it against the actual code. Ticket descriptions can be stale or wrong.
|
|
225
|
+
3. Treat the ticket's proposed approach and acceptance criteria as the original plan. Look for reviewer-relevant changes from that plan:
|
|
226
|
+
- revisions over the original approach;
|
|
227
|
+
- pivots caused by the actual state of the code;
|
|
228
|
+
- things learned after the ticket was written;
|
|
229
|
+
- ticket items intentionally deferred or made unnecessary by implementation reality.
|
|
230
|
+
4. Include only the plan changes that help a reviewer understand the diff. Put them where they belong: PURPOSE if they change the problem framing, DESCRIPTION if they change the design concept, WALK-THROUGH if they change the workflow, NOTES if they are scope boundaries or follow-ups.
|
|
231
|
+
5. If the PR truly does not match the ticket at all, stop and ask the user before drafting. That is a coordination issue, not PR-description material.
|
|
232
|
+
|
|
233
|
+
Do not turn this into a code-review checklist. The PR description does not need to prove every acceptance criterion was met. It needs to explain how the PR as implemented relates to the plan reviewers saw in the ticket.
|
|
234
|
+
|
|
235
|
+
When there is no ticket, skip this step. The rest of the process works the same; PURPOSE is seeded from the diff and commit messages instead.
|
|
236
|
+
|
|
237
|
+
## Link verification
|
|
238
|
+
|
|
239
|
+
Before posting or updating a PR body, verify every link you can. Broken links in PR descriptions waste reviewer time and make the surrounding prose less trustworthy.
|
|
240
|
+
|
|
241
|
+
- **Ticket and PR links** - verify the ID and title match the thing being referenced.
|
|
242
|
+
- **Repo file links** - prefer GitHub links when the PR description needs to send reviewers to a file outside the diff; verify the path exists on the relevant branch.
|
|
243
|
+
- **External docs** - if tooling can fetch the URL, confirm it resolves and appears to be the intended doc. If you cannot verify a user-provided doc link, keep it but do not claim you verified it.
|
|
244
|
+
- **Reference-style footers** - avoid stale auto-generated Jira/GitHub reference footers. If a Linear ticket link would create a stale Jira footer for `[PLAT-123]`, use link text like `[Linear PLAT-123](...)` instead.
|
|
245
|
+
|
|
246
|
+
## Defensive phrasing for AI reviewers
|
|
247
|
+
|
|
248
|
+
Cursor BugBot, CodeRabbit, and similar will read the description and judge the diff against it. Pre-empt misreads by calling out in NOTES:
|
|
249
|
+
|
|
250
|
+
- Intentional behavior changes that look like regressions ("old fallback path is gone on purpose - see PURPOSE").
|
|
251
|
+
- Deletions that might look like accidental losses.
|
|
252
|
+
- Renames where grep for the old name returns nothing.
|
|
253
|
+
- Scope disclaimers (what this PR does NOT do) - max two sentences, no hedging.
|
|
254
|
+
|
|
255
|
+
One line each. Fold into NOTES as bullets.
|
|
256
|
+
|
|
257
|
+
## What does NOT belong in the description
|
|
258
|
+
|
|
259
|
+
- File inventories (`modified X, Y, Z`). The diff shows this.
|
|
260
|
+
- "Notable design decisions" sections. Rationale goes in code comments at the decision site.
|
|
261
|
+
- Line-by-line commentary. That is PR review, not description.
|
|
262
|
+
- Test plans, unless the reviewer cannot infer them.
|
|
263
|
+
- AI attribution, co-author lines, "generated with" footers.
|
|
264
|
+
- Backstory that does not affect review ("we explored approach A then B then landed on C").
|
|
265
|
+
- **Authoring-process / commit-sequence narration.** e.g. "this first commit pins the naming; the instrumentation lands as follow-up commits", "first I... then...", "as a next step this branch will...". This is the single most common AI tell. Describe the change as it stands, never the order in which you assembled it. If a draft has pending work worth flagging, use a trailing `Remaining work:` bullet list under NOTES.
|
|
266
|
+
|
|
267
|
+
## Worked examples
|
|
268
|
+
|
|
269
|
+
### Small change (collapsed DESCRIPTION)
|
|
270
|
+
|
|
271
|
+
## SYNOPSIS
|
|
272
|
+
Narrow the **rotation advisory lock** to DB writes only; release across KMS I/O.
|
|
273
|
+
|
|
274
|
+
Ticket: [PLAT-412](https://example.atlassian.net/browse/PLAT-412)
|
|
275
|
+
|
|
276
|
+
## PURPOSE
|
|
277
|
+
The secret rotation worker currently holds a Postgres advisory lock for the full rotation batch, including network I/O to KMS. A batch of 500 keys blocks all other rotations for ~3 min, stalling unrelated tenants sharing the worker pool.
|
|
278
|
+
|
|
279
|
+
## DESCRIPTION
|
|
280
|
+
`rotateBatch` acquires `pg_advisory_lock(rotation_ns)` once, then loops: read key, call KMS encrypt, write ciphertext, advance cursor. The lock spans the whole loop.
|
|
281
|
+
|
|
282
|
+
This PR moves the lock acquisition inside the loop, around only the DB read+write. KMS calls run unlocked. Cursor advancement unchanged.
|
|
283
|
+
|
|
284
|
+
Net effect: concurrent rotations for other tenants no longer block on KMS I/O, removing the stall in PURPOSE. A crash mid-batch resumes from the cursor, which was already the behavior on any non-lock failure.
|
|
285
|
+
|
|
286
|
+
## NOTES
|
|
287
|
+
- **lock is no longer held across KMS** - intentional narrowing, not a regression.
|
|
288
|
+
|
|
289
|
+
### Large change (with WALK-THROUGH)
|
|
290
|
+
|
|
291
|
+
## SYNOPSIS
|
|
292
|
+
Move **connection acquisition** inside the transaction boundary to prevent **lock leaks across retry loops**.
|
|
293
|
+
|
|
294
|
+
Ticket: [PLAT-501](https://example.atlassian.net/browse/PLAT-501)
|
|
295
|
+
|
|
296
|
+
## PURPOSE
|
|
297
|
+
The batch processor opens a database connection before entering the retry loop, then begins a transaction inside each retry attempt. If a retry fails and the loop continues, the connection is reused for the next attempt without releasing the transaction savepoint. This holds locks from the failed attempt across the retry, blocking concurrent writers.
|
|
298
|
+
|
|
299
|
+
## DESCRIPTION
|
|
300
|
+
The root cause is a mismatch between connection lifecycle and transaction lifecycle. The connection is acquired once and held for the whole batch. The transaction is per-attempt but the savepoint release is skipped on error. The fix is to acquire a fresh connection per attempt, so each retry starts with a clean connection and a clean transaction boundary.
|
|
301
|
+
|
|
302
|
+
## WALK-THROUGH
|
|
303
|
+
|
|
304
|
+
1. **Batch processor receives work item** - the handler now calls `acquireConnection` per attempt instead of once at the top.
|
|
305
|
+
2. **Connection enters transaction** - `BEGIN` is issued immediately after acquisition, so the connection and transaction lifecycles are aligned.
|
|
306
|
+
3. **Work executes** - the batch runs its queries inside the transaction. _This is where the lock leak originated: the old code held the connection open across retries, dragging the previous transaction's locks into the next attempt._
|
|
307
|
+
4. **Retry on failure** - on error, the connection is released and a new one is acquired for the next attempt. The savepoint from the failed attempt is gone with the connection.
|
|
308
|
+
5. **Commit on success** - the transaction commits and the connection is released. Clean exit.
|
|
309
|
+
|
|
310
|
+
## NOTES
|
|
311
|
+
- **connection pool pressure** - acquiring per attempt increases pool churn under heavy retry load. Acceptable because retries are rare (observed <0.1% in prod).
|
|
312
|
+
- **PLAT-501 scope** - this addresses the lock leak. The retry backoff strategy described in the ticket is deferred to a follow-up.
|
|
313
|
+
|
|
314
|
+
Scan the bolds only:
|
|
315
|
+
> rotation advisory lock ... KMS I/O ... connection acquisition ... lock leaks across retry loops ... Batch processor receives work item ... Connection enters transaction ... Work executes ... Retry on failure ... Commit on success ... lock is no longer held across KMS ... connection pool pressure ... PLAT-501 scope
|
|
316
|
+
|
|
317
|
+
That reading alone conveys the shape and scope of both changes. The prose is for when the reader wants the full picture.
|
|
318
|
+
|
|
319
|
+
## Process
|
|
320
|
+
|
|
321
|
+
1. **Gather**: `git log $MERGE_BASE..HEAD`, `git diff $MERGE_BASE..HEAD --stat`, commit messages, current branch name. Apply the ticket resolution order (SYNOPSIS section) - infer first, ask only if nothing matches. Skim the diff; identify decision points (components or branches where behavior differs before vs after). Identify the workflow or lifecycle path if the change has one.
|
|
322
|
+
2. **Read ticket context**: if a ticket is resolved, fetch its description. Use it to seed PURPOSE and identify reviewer-relevant plan changes: revisions, pivots caused by code reality, discoveries after the ticket was written, and deferred or unnecessary ticket items.
|
|
323
|
+
3. **Draft PURPOSE first**, in one breath, without looking at code. If you cannot state the harm in two sentences, you do not understand the PR yet. Go back and read. When a ticket is available, seed PURPOSE from its problem statement, but verify against the code.
|
|
324
|
+
4. **Write DESCRIPTION**: choose the right depth (collapsed for small, three-layer for medium, root-cause + concept for large with WALK-THROUGH). Name everything you will refer to later. Organize by workflow/data-flow, not by touched symbol.
|
|
325
|
+
5. **Write WALK-THROUGH** (if needed): numbered steps in execution order. Bold the step leads. State what changed, not what you did.
|
|
326
|
+
6. **Write SYNOPSIS last** - it is a compression of PURPOSE + the core mechanic.
|
|
327
|
+
7. **Bold and italicize the save points** in the allowed locations. Bold phrases that name the change (components, mechanisms, behaviors). Italicize phrases that orient to significance (conclusions, payoffs), at most one per paragraph. Apply the scan check: read only the bold and italic fragments and verify the shape comes through.
|
|
328
|
+
8. **Add NOTES** for AI-reviewer defensive lines, scope disclaimers, ticket scope mismatches, and remaining work. Use `## NOTES` header. Omit if empty.
|
|
329
|
+
9. **robots.txt only when earned**: do not add it during initial authoring. It is added later, in response to an automated reviewer's false positive (see its section). When you do add it, use the collapsed `<details>` format with `<summary>robots.txt</summary>`, keep the editing HTML comment at the top of the block, and keep the human-warning line first after the comment.
|
|
330
|
+
10. **Verify links**: check ticket/PR links, repo file links, and external docs where tooling allows. Do not claim an unverified link was verified.
|
|
331
|
+
11. **Verify prose style**: check each rule in Prose style. Cut design-narration, authoring-sequence, and buzzwordy abstractions. Verify plain ASCII. Verify first-use definitions for subsystem jargon. Verify plain English nouns (no code-domain nouns in prose). Verify conclusion-first in PURPOSE. Verify NOTES bullets are either short pointers or self-contained. Verify one-paragraph-one-physical-line for GitHub rendering. The robots.txt section is exempt from these prose rules below its human-warning line.
|
|
332
|
+
12. **Verify length**: if the body exceeds the ceiling for its conceptual size, cut until each line earns its place.
|
|
333
|
+
13. **Submit** via `gh pr create --body "$(cat <<'EOF' ... EOF)"` to preserve formatting.
|
|
334
|
+
|
|
335
|
+
## Anti-patterns
|
|
336
|
+
|
|
337
|
+
- **Burying the harm.** If PURPOSE is a paragraph of setup before the actual problem, rewrite. Problem first.
|
|
338
|
+
- **Layer 2 introduces new names.** If layer 2 mentions components layer 1 never named, the scaffold broke. Go back, add them to layer 1, or drop them from layer 2.
|
|
339
|
+
- **Emphasizing filler words.** Bolding "this", "the", "we", or adjectives produces scan noise. Bold only nouns and verbs that carry meaning.
|
|
340
|
+
- **Bolding filler or context.** Bolding history, hazard detail, justification, or connective tissue creates scan noise. Bold the change itself (components, mechanisms, behaviors); italicize the significance (conclusions, payoffs). Not the scaffolding around them.
|
|
341
|
+
- **Over-italicizing.** More than one italicized phrase per paragraph dilutes the signal. Pick the one phrase that carries the paragraph's point.
|
|
342
|
+
- **Design-doc DESCRIPTION.** If layer 1 is a function walkthrough or architecture essay, you are writing for yourself, not the reviewer. Compress to the decision points.
|
|
343
|
+
- **Matching the diff line-by-line.** The description is orthogonal to the diff, not a prose projection of it.
|
|
344
|
+
- **Over-claiming scope.** A fix for a sloppy implementation is "fix a sloppy implementation," not "harden the foo subsystem." Match energy to reality.
|
|
345
|
+
- **Narrating your own process.** Any sentence about the order you did things, which commit does what, or what a later commit will add. Reads as AI slop. Change-as-it-stands only.
|
|
346
|
+
- **Orphaned synopsis.** A bold lead paragraph with no `## SYNOPSIS` header above a body that does use headers. Add the header; it is mandatory.
|
|
347
|
+
- **Bare `Notes:` line.** Use `## NOTES` header or omit the section entirely.
|
|
348
|
+
- **Organizing by touched symbol.** A bullet list of "changed X in file A, changed Y in file B" reads as disconnected touchpoints. Follow the data flow.
|
|
349
|
+
- **Buzzwordy abstractions.** "identity contract", "canonical hash", "check in isolation" - if it sounds like it is trying to sound smart, replace it with plain concrete wording.
|
|
350
|
+
- **Loaded language.** Using avoidable loaded terms when neutral terms exist. Prefer allowlist/blocklist, primary/replica, and precise role names.
|
|
351
|
+
- **Smart punctuation.** Em dashes, smart quotes, ellipsis glyphs. Use plain ASCII.
|
|
352
|
+
- **Splitting paragraphs across lines.** GitHub renders each line break as a visible break. One paragraph = one physical line.
|
|
353
|
+
- **Ungrounded jargon.** Subsystem-specific terms used in SYNOPSIS but never defined in PURPOSE or DESCRIPTION. An outsider reads "frozen matview reverification" in SYNOPSIS and hits a wall. Define on first use in the teaching sections.
|
|
354
|
+
- **Implementation verbs in prose.** "Publish the key" reads as jargon to someone who does not know the method is called `publish`. Say "store the key in the in-memory cache".
|
|
355
|
+
- **Code-domain nouns in prose.** "Row read", "waiter", "zeroized", "backlog" (as jargon) are technically English but belong in source files, not sentences. Replace with plain English: "reading the row from the database", "a request waiting for a worker", "overwritten with zeros", "the queued scan jobs".
|
|
356
|
+
- **Conclusion buried at the end.** PURPOSE that builds to its point in the last sentence forces the reader to absorb the explanation before knowing what is being explained. Lead with the problem, then explain why.
|
|
357
|
+
- **Hazard rating without motivation.** "No incident has hit this shape" answers "how bad?" but not "why review this?" Answer "why now?" so the reviewer can decide whether to invest time.
|
|
358
|
+
- **NOTES bullets that are both wordy and terse.** A bullet that compresses a paragraph of rationale into one dense sentence reads as a private note. Either flag the thing and point to the full explanation, or write a self-contained sentence or two. Not the middle thing.
|
|
359
|
+
- **robots.txt as a suppression lever.** Writing "ignore the finding about X" or "skip checking X" in robots.txt turns it into a rubber stamp and a prompt-injection surface. Explain what X does and the intent behind it so the reviewer clears its own false positive; never instruct it to stop looking.
|
|
360
|
+
- **Preemptive robots.txt.** Adding the section before any automated reviewer has actually produced a false positive. It is a response to a demonstrated misread, not scaffolding.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: split-overlarge-pr
|
|
3
|
+
description: Split already-completed work from an overlarge PR into human-reviewable, release-safe PRs. Use when the user asks to split a large existing branch/PR, break up completed work, or turn an oversized PR into multiple PRs. Do NOT use for planning brand-new work before code exists.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Splitting an overlarge PR
|
|
7
|
+
|
|
8
|
+
Use this skill when the work is already done and the PR is too large for a human to review well. The job is not to redesign the feature. The job is to cut the completed diff into human-digestible PRs with safe seams.
|
|
9
|
+
|
|
10
|
+
The key constraint: **do not create a stacked PR chain**. Every PR should target the main branch. Some PRs may have to merge before others, but the dependency is merge order, not branch topology. After each part merges, the next part rebases or is rebuilt onto main.
|
|
11
|
+
|
|
12
|
+
The second key constraint: **every seam must be release-safe**. Assume a release can happen after any part merges and before the next part lands. If two parts need each other bidirectionally to be correct in prod, the split is invalid. Redesign the seam or keep that work in one PR.
|
|
13
|
+
|
|
14
|
+
## Definitions
|
|
15
|
+
|
|
16
|
+
- **Part** - one PR produced by the split.
|
|
17
|
+
- **Seam** - the boundary between two parts.
|
|
18
|
+
- **Release-safe seam** - the repo can ship after the earlier part merges, before the later part lands, without broken behavior, broken schema, broken generated artifacts, or operator confusion.
|
|
19
|
+
- **Merge order** - the order parts should land in. Merge order is allowed.
|
|
20
|
+
- **Stacked PR** - a PR whose base is another feature branch. Do not do this for this workflow.
|
|
21
|
+
|
|
22
|
+
## Split goals
|
|
23
|
+
|
|
24
|
+
Optimize for human review first. A good split gives reviewers one coherent idea at a time: schema scaffold, write path, read path, cleanup, docs, tests, or tooling. Avoid splitting by arbitrary file count. Avoid "all backend in one PR, all tests in another" unless both are independently meaningful and release-safe.
|
|
25
|
+
|
|
26
|
+
Each part should be:
|
|
27
|
+
|
|
28
|
+
- **coherent** - one reviewable purpose;
|
|
29
|
+
- **idempotent** - safe if applied once, retried, or observed in prod before the next part;
|
|
30
|
+
- **mergeable to main** - target main, not another feature branch;
|
|
31
|
+
- **release-safe** - production remains valid if release happens after this part;
|
|
32
|
+
- **bounded** - small enough that a reviewer can understand it without reading the whole original diff.
|
|
33
|
+
|
|
34
|
+
## Process
|
|
35
|
+
|
|
36
|
+
1. **Inventory the completed diff** - compare the oversized branch/PR against main. Identify files changed, commits, generated artifacts, tests, docs, migrations, flags, APIs, and operational wiring. Do not start moving code yet.
|
|
37
|
+
2. **Build a dependency graph** - list what depends on what. Mark hard dependencies (cannot work without), soft dependencies (nice ordering), and bidirectional dependencies (invalid seam unless redesigned).
|
|
38
|
+
3. **Choose release-safe seams** - cut only where the intermediate repo state can ship. For each proposed seam, ask: if a release happens right here, what breaks? If the answer is anything user-visible, data-corrupting, migration-breaking, or operator-confusing, move the seam.
|
|
39
|
+
4. **Order the parts** - choose merge order from low-level to high-level when possible: scaffolding, compatibility shims, write paths, read paths, behavior switch, cleanup. The order may be strict, but each part still targets main.
|
|
40
|
+
5. **Extract parts mechanically** - create branches or commits for each part from main. Use cherry-pick, restore, or patch extraction; do not hand-rewrite behavior unless the seam requires it. Preserve generated artifacts with the source change that needs them.
|
|
41
|
+
6. **Validate each part independently** - run the relevant tests for that part against its own branch. If a part only passes when a later part is present, the seam is wrong.
|
|
42
|
+
7. **Write PR descriptions with project context** - every part needs its own normal PR description plus a final `## PROJECT PARTS` section linking the other pieces and stating merge order.
|
|
43
|
+
|
|
44
|
+
## Designing release-safe seams
|
|
45
|
+
|
|
46
|
+
Good seams usually look like this:
|
|
47
|
+
|
|
48
|
+
- **nullable schema before writes** - add nullable columns or tables before code writes them;
|
|
49
|
+
- **dual-read or fallback read before switch** - teach readers to handle both old and new shapes before writers change behavior;
|
|
50
|
+
- **dual-write before read switch** - write both representations while old readers still exist;
|
|
51
|
+
- **feature flag or no-op scaffold before enablement** - merge inert wiring before the behavior flips;
|
|
52
|
+
- **cleanup last** - remove shims, flags, dead code, and compatibility paths only after the new state is live and no rollback path needs them.
|
|
53
|
+
|
|
54
|
+
Bad seams usually look like this:
|
|
55
|
+
|
|
56
|
+
- **bidirectional dependency** - PR A only works if PR B is also present and PR B only works if PR A is present;
|
|
57
|
+
- **required generated artifact split from source** - generated models, migration SQL, OpenAPI output, or snapshots land without the source change that makes them true;
|
|
58
|
+
- **schema requires code not yet merged** - NOT NULL, unique indexes, enum narrowing, or data assumptions land before the data/code can satisfy them;
|
|
59
|
+
- **code writes data old code cannot read** - a release between parts would strand readers;
|
|
60
|
+
- **cleanup before consumers are gone** - deleting shims, flags, or old paths while earlier release states can still need them.
|
|
61
|
+
|
|
62
|
+
## No stacked PRs
|
|
63
|
+
|
|
64
|
+
Do not target part 2 at part 1's branch. Do not build a tower where reviewers must read PR 1 before GitHub can even compute PR 2 against main.
|
|
65
|
+
|
|
66
|
+
Allowed: "Part 2 should merge after Part 1." Part 2 still targets main when opened. If Part 1 has not merged yet, keep Part 2 local or open it as draft against main knowing it may include temporary overlap; update/rebase it after Part 1 lands.
|
|
67
|
+
|
|
68
|
+
Use merge order to communicate sequencing. Use branch topology only for isolation during local extraction, not as the review shape.
|
|
69
|
+
|
|
70
|
+
## Project parts section
|
|
71
|
+
|
|
72
|
+
Every split PR should end with a final section called `## PROJECT PARTS`. This is for humans. It is not a stacked-PR instruction; it is the map for a multi-part change.
|
|
73
|
+
|
|
74
|
+
Each entry should be a mini didactic build-up, not just a link. The reader should understand how the system state advances from one part to the next: what this PR adds, what state it leaves behind, and what gate must be satisfied before the next part can land or ship.
|
|
75
|
+
|
|
76
|
+
Format:
|
|
77
|
+
|
|
78
|
+
```md
|
|
79
|
+
## PROJECT PARTS
|
|
80
|
+
|
|
81
|
+
1. [PLAT-123 / Part 1: nullable schema + generated artifacts](https://github.com/org/repo/pull/111) - adds `foo_id` as nullable and regenerates models; release-safe scaffold, no behavior uses it yet.
|
|
82
|
+
2. [PLAT-124 / Part 2: backfill existing rows](https://github.com/org/repo/pull/112) - fills `foo_id` for existing data; **IMPORTANT:** must deploy and complete in prod before Part 3.
|
|
83
|
+
3. [PLAT-125 / Part 3: enforce non-NULL](https://github.com/org/repo/pull/113) - adds the non-NULL constraint once Part 2's backfill reports zero missing rows in prod.
|
|
84
|
+
4. [PLAT-126 / Part 4: cleanup compatibility paths](https://github.com/org/repo/pull/114) - removes temporary fallback code after the constrained shape is live.
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Rules:
|
|
88
|
+
|
|
89
|
+
- Include all parts, including the current PR.
|
|
90
|
+
- Mark not-yet-open PRs as `TBD` until links exist.
|
|
91
|
+
- State merge order, release-safety, and deploy/runtime gates inline. If a later PR depends on a production condition (backfill complete, flag enabled, old jobs drained), say so in the entry.
|
|
92
|
+
- Use `**IMPORTANT:**` for hard gates that reviewers must not miss.
|
|
93
|
+
- Keep this section final. Nothing follows it except an optional `# robots.txt` section if automated reviewers need machine-only context.
|
|
94
|
+
|
|
95
|
+
## Review checklist before opening the split PRs
|
|
96
|
+
|
|
97
|
+
- Every part targets main.
|
|
98
|
+
- Every part has one coherent review purpose.
|
|
99
|
+
- Every part can pass its own relevant tests without later parts.
|
|
100
|
+
- Every intermediate merge state can be released.
|
|
101
|
+
- No generated artifact is separated from the source change that requires it.
|
|
102
|
+
- No cleanup happens before all consumers of the old path are gone.
|
|
103
|
+
- The `## PROJECT PARTS` section appears in every PR description and links every known part.
|
|
104
|
+
|
|
105
|
+
## Anti-patterns
|
|
106
|
+
|
|
107
|
+
- **Stacked PR by another name** - using base branches to enforce order. Use merge order, not branch topology.
|
|
108
|
+
- **Review-size split only** - splitting by file count while leaving behavior coupled across parts.
|
|
109
|
+
- **Tests later** - a part lands without the tests that prove its own behavior.
|
|
110
|
+
- **Cleanup early** - deleting compatibility before the new state is fully live.
|
|
111
|
+
- **Release-blind seam** - "it works once all parts merge" is not enough. It must work after each part merges.
|
|
112
|
+
- **Bidirectional dependency** - if PR A and PR B both require each other, they are one PR or the seam must be redesigned.
|