Pg feature plan
Skill matejformanek/postgres-claude/.claude/skills/pg-feature-plan
Turn Claude Code into a long-term collaborator on PostgreSQL internals — cited knowledge corpus, agent skills, slash commands, and task-shaped scenarios for backend hacking.
npx -y skills add matejformanek/postgres-claude --skill pg-feature-planAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Drop a heavy, citation-rich implementation plan for a scoped PostgreSQL backend feature — Phase 2 of the two-phase PG planner, the bridge from a brainstorm-with-picked-approach to /pg-implement. Names every src/backend or src/include file that must change with file:line cites at a pinned anchor, enumerates catalog / CATALOG_VERSION_NO / WAL / on-disk / lock-order / extension-ABI risks, proposes the test surface (regress / iso / TAP), structures the patch into independently-reviewable phases, picks a CommitFest landing strategy, and emits the plan-mode plan that /pg-implement executes phase-by-phase with plan-linked commits. **Use proactively whenever the user invokes /pg-plan, says "plan this PG feature", "make a plan for X in PG", "drop a heavy plan", "plan-mode plan for [PG feature]", "i picked option [A/B/C] in the brainstorm, now plan it", "we settled on the [approach] for the [PG topic], write me the phase plan with file:line cites", "spec-to-plan this pgsql-hackers thread", "shadow-implementation plan against [hackers URL]", "REJECT-track plan for CF NNNN", or has a brainstorm doc + a picked approach for a PostgreSQL backend change and wants the file-by-file rollout — even when they don't use the literal word "plan".** Skip when the idea is still exploratory and no approach is picked (use pg-feature-brainstorm first), for product / sprint / Q4 / roadmap / Jira / OKR planning, application architecture planning, Terraform / k8s / Helm / Ansible / CI infrastructure plans, React / Redux / Zustand / Vue / Angular frontend refactor plans, migration plans between non-PG databases (MySQL→PG migration is a DBA migration plan, not a PG feature plan), generic non-PG database feature planning (SQLite, DuckDB, MongoDB, MySQL features), and code-review of an already-submitted patch (use pg-patch-review or review-checklist).
SKILL.md
42.4 KB, ~10.2k tokens by cl100k_base, as published. Nobody here has run it
pg-feature-plan — Phase 2 of the PG planner
The heavy stage. Phase 1 (pg-feature-brainstorm) narrowed the
design space; Phase 2 makes it implementable. Output is a plan-mode
plan with file:line cites that /pg-implement (NOT the generic
/implement) executes phase-by-phase with plan-linked commits.
Inputs
- Slug (required): the planning directory under
planning/<slug>/. Ifbrainstorm.mdexists, read it first — the picked approach + the DECISION: answers are your constraints. - No brainstorm? Fine — accept a direct natural-language description of the picked approach + any constraints the user has already locked down. But note in the plan's intro that Phase 1 was skipped (and therefore some design-space exploration may be missing).
- Thread spec? A
planning/<slug>/spec.mdextracted from a pgsql-hackers thread (shadow-implementation runs). Run the spec through the engagement-classification step below before treating any of its content as locked.
Context awareness — mandatory pre-step (M2)
Before drafting any plan content, run a context probe. Surfaced by the money-fx-exchange shadow run (April-1 2026 joke proposal that the planner initially treated earnestly).
- Posting date. Check the thread's first-message date:
- April 1 → flag for joke-check (look for
[PoC]/[RFC]wording, absence of patch attachment, deadpan replies). - Within 2 weeks of a release-branch cut → flag for late-cycle context; the realistic CF target is the next window, not this one.
- During an open CommitFest's commit window → check if the author intends this CF or the next.
- April 1 → flag for joke-check (look for
- Author history. One-shot poster vs sustained contributor.
git -C source log --author=<email> --onelineand a quick pgsql-hackers archive search. A one-shot speculative post warrants different planning energy than a sustained contributor's serious proposal. - Thread engagement signal (see M5 below for the taxonomy). Reply count alone is misleading; classify what kind of engagement the replies represent.
Output a ## Context block at the top of the plan that names date,
author posture, and engagement class. If the probe surfaces signal
that the proposal isn't serious (deadpan-only replies, joke
indicators, demonstrably unimplementable), the plan's recommended
verdict shifts to REJECT with cited reasons rather than a phased
implementation. See .claude/skills/review-checklist/SKILL.md Phase 0
for the REJECT-A/B/C grade rubric.
Thread-engagement classification (M5)
When the input includes a thread (typical for shadow-implementation runs), classify the engagement explicitly — not just the reply count. Surfaced by the money-fx-exchange shadow run, where the deadpan "thanks, add to commitfest" reply was the only public signal.
| Class | Signature | Plan implication |
|---|---|---|
unengaged | No technical replies; deadpan acks; silence | Treat the spec as the author's unreviewed take. Don't pretend community endorsement exists. |
acked | Technical replies with no objections | Spec is community-validated; proceed at normal confidence. |
debated | Multiple substantive replies with disagreements + counter-proposals | Plan should enumerate the open questions as §13 risks, not paper over them. |
contested | Named senior contributors raising correctness / design objections | Plan should NOT proceed to implementation phases until the objections are addressed. Output may be a REJECT or a brainstorm-revival pointer. |
Record the classification in the plan's ## Context block.
REJECT-track output shape (when verdict is REJECT)
When the Context-awareness probe (M2) or Engagement classification (M5) recommends REJECT, the plan file's body becomes a Verdict block in place of the standard §3-§14 implementation sections. Required contents:
- Verdict line.
REJECT-A,REJECT-B, orREJECT-Cper thereview-checklist/SKILL.mdPhase 0 rubric (summarized below). - N concrete reasons against the design (numbered, 3-7 typical).
Each reason cites a
source/<path>:<line>invariant, aknowledge/subsystems/<x>.mdINV-tag, or a documented persona reflex fromknowledge/personas/<name>.md. - Predicted lead reviewer with the reflex they trigger
(e.g. "Tom Lane — type-system + dump-determinism";
"Andres Freund — per-row hot-path"; "Noah Misch — security /
install-script immutability"). See
knowledge/personas/for the reflex map. - Concrete alternative shape if one exists (the "what they probably wanted" rewrite). Skip only when the proposal is irredeemable.
- Hand-off line points to
review-checklist/SKILL.mdPhase 0 ("Write a thread reply"), NOT/pg-implement.
The §1 "What this plan is" + ## Context block still appear; §2-§14 do
not. No phased implementation, no §3 files table — those would imply the
plan is implementable, which contradicts the verdict.
REJECT-A/B/C grade summary
Full rubric: .claude/skills/review-checklist/SKILL.md Phase 0.
| Grade | Meaning |
|---|---|
REJECT-A | Identified all critical design problems + proposed correct alternative. Saves community cycles. |
REJECT-B | Identified most critical problems but missed one major concern. |
REJECT-C | Rejected for the wrong reasons OR rejected when the proposal was actually sound. Self-correct: re-open and run the seven-phase review (or this skill's standard track). |
Output structure — multi-file plan (v1.2 — calibration-driven)
Old shape (deprecated for non-trivial features): single
planning/<slug>/plan.md covering all 14 sections.
New shape: orchestrator + per-phase files + supporting docs. The sesvars calibration showed that single-file plans force shallow per-phase detail (the 307-line plan could only give each of 6 phases ~30 lines, which is why scope leaked). The new shape lets each phase be hundreds of lines deep on its own without bloating the orchestrator.
planning/<slug>/
├── plan.md — ORCHESTRATOR (§1-§4, §11-§14, phase index)
├── machinery-survey.md — §0.5 existing-PG-mechanism analysis (NEW)
├── tests/
│ ├── spec.md — §3.5 test-suite-as-spec draft (NEW)
│ ├── regress-cases.sql — drafted regression SQL the impl must pass
│ └── tap-cases.md — drafted TAP test scenarios
├── phase-0/
│ ├── plan.md — full §3 / edits / phase-end check for phase 0
│ └── notes.md — appended during /pg-implement (R8)
├── phase-1/
│ ├── plan.md
│ └── notes.md
├── phase-2/ ... phase-N/ — one dir per phase
└── comparison.md — written post-implementation by /pg-implement
if a user reference impl exists (R15 calibration)
When to use the multi-file shape:
- Feature touches > 15 files → multi-file required.
- Feature has > 3 phases → multi-file required.
- Feature has a user reference impl → multi-file required (§0.5 + tests/spec.md are load-bearing).
- Otherwise: single-file is fine. Mark it explicitly at the top:
Plan shape: single-file (small feature, < 15 files, ≤ 3 phases).
Orchestrator file (plan.md) contents when multi-file is
used:
- §1 What this plan is, §2 Scope contract, §3 Files-by-domain
SUMMARY table (high-level — full per-phase tables live in
phase-N/plan.md), §4 Catalog impact, §5 WAL, §6 Locking, §7 Memory, then a §8 Phase index with a one-line summary per phase and a link tophase-N/plan.md, then §9 Test surface pointing attests/, §10 Docs, §11-§14 as usual.
Per-phase file (phase-N/plan.md) contents:
- Phase title + one-paragraph why.
- §3 table for THIS PHASE ONLY (files touched, change type, size, cited concrete edit).
- Concrete edits (the actual code shape per file).
- Phase-end check (auto-scoped per R13 based on what files the phase touches — see "Phase-end check scope" below).
- §13 risks for THIS PHASE.
- Inline persona + scenario + idiom citations (REQUIRED — see "Citations" below).
Length scales: ~200-400 lines per phase file is normal; large phases can be 1000+. The orchestrator itself stays ~300-500 lines regardless of feature size.
Output (legacy single-file shape)
For small features (< 15 files, ≤ 3 phases, no reference impl):
single planning/<slug>/plan.md following the structure below.
Length scales with the feature: ~400 lines for a small change,
~1500 lines for a medium feature, more for a major patch series.
Required sections (in this order)
-
What this plan is (1 paragraph). State the picked approach (link to the brainstorm if it exists). Name the chosen scope (MVP vs full). State the target PG version + CF window.
-
Scope contract (3-5 bullets). Hard boundaries: what this plan COVERS, and what's explicitly OUT of scope. The plan-mode rule is strict: anything not in scope here is a follow-up.
-
Files that change (a table). Each row:
- File path (under
source/...ordev/...for new files). - Change type:
new/modify/delete/not edited (sync trap)/not edited (auto-generated)/not edited (build-time validator). - Approximate size:
tiny (<10 lines)/small (10-50)/medium (50-200)/large (>200)/n/afor NOT-edited rows. - One-sentence summary of what changes — with a
source/<path>:<line>cite for any file:line claim in the summary. Example row:src/backend/utils/adt/lockfuncs.c | modify | small | Add PG_FUNCTION_INFO_V1 + body, model after pg_advisory_lock at source/src/backend/utils/adt/lockfuncs.c:624 | — - Per-file doc citation:
[via knowledge/files/.../X.md]if one exists.
Aim for completeness here. Missing a file in this table is a Phase 2 bug. If you don't know all the sites, do another grep pass.
Pin contract reminder (from Method Step 0): every file named in the pinned scenario's checklist MUST appear in §3, including rows marked
NOT edited(build-time validators, auto-generated headers, sync-trap files likepsqlscan.l/ecpg/pgc.l/check_keywords.pl). Listing a NOT-edited row with a one-line rationale is correct; silently dropping it is the failure mode the §8a coverage gate catches at plan-finalization time. The planner can ADD sites discovered by grep, but can NEVER DROP a scenario row without explicit user approval AND a follow-up edit to the scenario file itself. - File path (under
-
Catalog + on-disk impact (bulleted). Each item is yes/no with rationale:
- New
pg_proc.dat/pg_operator.dat/pg_type.dat/pg_cast.dat/pg_opclass.datentries? Which file? catversion.hbump required? (Bump if any catalog*.dator*.hchange.)- New on-disk format? (Page format, WAL record, file layout.) If yes, name the upgrade path.
genbki.plre-run needed? (Implied if catalog files changed.)
- New
-
WAL impact (bulleted). Each yes/no with detail:
- New rmgr or new info byte for existing rmgr?
- Existing record extended with new fields? (Compat policy.)
- Replay function changes? (
*_redoimpact.) pg_waldumpdesc/identify updates needed? (Implied by any record change.)- Hot Standby conflict generation? (Cite
knowledge/subsystems/access-nbtree.mdorknowledge/subsystems/replication.mdfor the pattern if applicable.)
-
Locking + concurrency (bulleted). Each item is "we need / we don't need" with cite:
- New LWLock? (Add to
lwlocknames.h?) - New heavyweight lock mode?
- Buffer lock ordering implications? (Cite the relevant subsystem doc's lock-order section.)
- Atomic-vs-spinlock decisions for shmem fields?
- SSI predicate-lock implications?
- New LWLock? (Add to
-
Memory + resource management (bulleted):
-
New
MemoryContext? Where in the hierarchy? -
Per-query or per-tuple allocations?
-
Long-lived state (TopMemoryContext, CacheMemoryContext)?
-
palloc_aligned/ DSA / shmem-resident state? -
Ownership invariants (REQUIRED when any "X is owned by Y" claim appears in this section). For every ownership claim, run a grep-pass data-flow verification and record its result inline:
- Identify every code site that produces an X —
palloc,copyObject,copyJsonbValue,pstrdup,makeNode, constructor calls, etc. - For each producer, confirm the path that hands the X to Y — direct assignment, append to a Y-owned collection, or function-call argument transfer.
- If ANY producer hands X to something other than Y (e.g.
appends to Y but also retains a copy elsewhere; passes by
borrowed reference; mixes copy-vs-borrow semantics like
JsonValueListAppend(found, copy ? copyJsonbValue(v) : v)), the ownership claim is FALSE as stated — refine the claim or refine the data flow before continuing. - Record the grep command(s) you ran and the file:line list
you walked, e.g.
Grep "JsonValueListAppend\\|copyJsonbValue" jsonpath_exec.c → 3 producers verified to hand ownership to the surrounding JsonValueList; 1 mixed-ownership site flagged at line 1741.Anchored inplanning/jsonpath_leak/comparison.md§F30: our plan asserted "JsonValueListFree releases only the values[] array, JsonbValue elements remain owned by the input jsonb" — butexecuteAnyItempalloc's per-element JsonbValues viacopyJsonbValuethat the ownership claim missed. The leak was 4.9 GB even after Phase 2 freed the arrays. A 30-second grep-pass would have shown 3 producer sites and one mixed copy-vs-borrow site, surfacing the wrong invariant at plan time rather than at R4 phase-end check time.
F40 — categorize each leak site by fire-count class. For every site the grep-pass surfaces, tag it as O(N) scaling (fires N times per operation, N in input size) or O(1) one-shot (fires a bounded number of times per operation). The plan should treat only the O(N) sites unless an O(1) site carries an independent correctness concern (e.g. UAF risk, invariant violation). Treating O(1) sites for "uniform coverage" adds LOC without addressing genuine leak-scaling. Anchored in
planning/gin_parallel_merge_leak/comparison.md§F40 — Vinod's upstream fix1681a70df3d68covered only the 2 O(N)ginEntryInsertsites inside the merge loop and skipped the 1 O(1) final-flush site; our blind fix covered all 3 for uniformity and shipped +5 lines heavier without changing the leak-scaling outcome. Format the categorization inline in the plan §7 grep-pass table:| site | fire-count | leak-scaling | treat? | - Identify every code site that produces an X —
-
Callback-based approach detail (L7). If the recommended approach uses a memory-context reset callback (approach C under L6, or approach E when the invariant is a per-scan resource release), the plan MUST name three implementation-level design choices explicitly rather than leaving them for Phase 3 discovery:
- Callback storage location — embed
MemoryContextCallbackas a field of the surrounding state struct (F34 preferred) OR palloc separately on the target context (only if the state struct is off-limits). The embed choice removes a palloc site and the "who owns the callback struct?" question. - Callback function shape — cast a well-known cleanup
function (
PQclear,pfree,PQfinish,close,hash_destroy, etc.) directly toMemoryContextCallbackFunction(F35 preferred) OR write a wrapper only if the cleanup needs bookkeeping the dispatcher can't provide (pointer-to-pointer indirection, conditional logic, multi-step release). - Ownership semantics — single-owner via callback (F36
preferred): once armed, the callback owns; every other
release path detaches (
cb.arg = NULL) or delegates. Two-owner explicit handoff is correct but heavier. Anchored inplanning/fdw_directmodify_leak/comparison.md§F34+F35+F36 — L6 correctly flagged approach E on that run, but the blind plan chose the heavier variant on all three details, adding 25-30 LOC over Tom's actual fix without changing the design category. Naming the three choices at plan time closes that detail-vs-category gap. Seeknowledge/idioms/memory-contexts.md§"Idioms for callback-based ownership" for concrete before/after code.
- Callback storage location — embed
-
-
Phased implementation (the meat). Break into 3-8 phases (the old 3-6 range was tight for comprehensive features per R15). For multi-file plan shape, each phase has its own
phase-N/plan.mdwith the structure below; the orchestrator only lists the index. Each phase entry:- Phase number + title.
- Files this phase touches (subset of §3).
- The 5-15 concrete edits this phase makes (each with file:line where possible). For multi-file shape, list every site — don't truncate to "5-10".
- Inline citations (REQUIRED — per R14 + R15 + the sesvars
calibration F1-F15 findings). Each phase must cite:
- ≥1
knowledge/scenarios/*.mdit follows. - ≥1
knowledge/personas/*.mdwhose reviewer reflex will evaluate this phase. - ≥1
knowledge/idioms/*.mdwhose pattern it uses. - Any prior calibration finding F-N from
sessions/2026-06-16-sesvars-calibration-findings.md(or successor) that this phase must heed.
- ≥1
- Phase-end check (auto-scoped per R13 — see "Phase-end
check scope ladder" below): how
/pg-implementknows this phase is done. NOT "regress passes" alone — apply the R13 scope ladder. - Tests covered by this phase: list the TC-* IDs from
tests/spec.mdthat this phase makes pass.
A phase is self-contained enough that you could stop after it and the tree still builds + the declared phase-end check (R13 scope) passes. (This is the
/pg-implementskill's requirement, R4.)
Phase-end check scope ladder (R13, applied per-phase)
The phase-end check MUST match the phase's blast radius (R13 in pg-implement-discipline.md v1.1):
- Helper-only changes →
meson test --suite regress. - Catalog changes (
pg_operator.dat,pg_proc.dat, etc.) →--suite regress+ every--suite contrib-*. (Sesvars F12: Phase 0's catalog cleanup brokepg_stat_statements/squashing. sql; the regress-only gate missed it.) - Grammar / lexer changes (
gram.y,scan.l,pl_gram.y, ECPGpgc.l) →--suite regress+--suite ecpg+ everycontrib/*suite that may parse SQL. - Executor / planner changes (
execExpr*.c,clauses.c,plancache.c, etc.) →--suite regress+--suite isolation- every
contrib/*suite.
- every
- WAL / replication / catversion → above +
--suite recovery. - Ruleutils / parse-tree formatting → above + a spot-check
on
CREATE VIEW,EXPLAIN VERBOSE, andpg_get_*defoutput. (Sesvars F14:T_SessionVarmissing fromruleutils.c get_rule_exprbrokeEXPLAIN VERBOSEsilently.)
Each phase's plan section names the EXACT command line:
meson test -C build-debug --suite regress --suite contrib-pg_stat_statements
— not a vague "regress passes".
-
Test surface (bulleted with file paths). When multi-file shape is used, this section is a SUMMARY that points at
tests/spec.mdfor the full draft (Step 1.5).tests/spec.md— structured test cases drafted from §0 usage surface (REQUIRED per R14).- Regress (
src/test/regress/sql/): name the per-phase happy-path file (e.g.sessvar.sql) AND the comprehensive own-suite file (e.g.sessvar_advanced.sql— REQUIRED by R14: identifier edges, type variety, cross-feature integration, adversarial). The comprehensive suite is what catches gaps the per-phase regress misses (sesvars F14). - Isolation (
src/test/isolation/specs/): concurrency races this feature could cause? Name the spec file(s). - TAP (
src/test/recovery/t/or similar): multi-node / subscriber / replication / cross-backend isolation. REQUIRED for features with backend-local state. src/test/modules/: in-tree C test module needed?- amcheck /
pg_amcheck: if AM-related. - pgbench: if performance-relevant.
- Contrib regression: name any contrib SQL files that may
break from this feature's changes (e.g. catalog-cleanup
phases hit
pg_stat_statements/squashing.sql).
-
Docs (bulleted):
- SGML page(s) to add/update under
doc/src/sgml/? release-N.sgmlentry needed?- GUC documentation (if a new GUC)?
- System-catalog doc table update (if catalog changes)?
- SGML page(s) to add/update under
-
Patch-series structure (1 paragraph + bullets). Single patch or split? If split, name each patch and what depends on what. Default to single patch for ≤500 lines + one logical change; split for refactor-then-feature or multi-subsystem changes.
-
CommitFest landing strategy (bulleted):
- Which CF? (e.g. "PG20-1, open now until 2026-06-30").
- Pre-existing thread to revive, or new thread?
- Likely reviewers? Name 2-3 with the reflex each would apply.
Anchor on the subsystem the patch touches:
- Type-system / catalog / dump-determinism / API-back-compat → Tom Lane
- Performance / executor hot path / parallel safety → Andres Freund
- Security / install-script immutability / test-omission → Noah Misch
- Parser / locale / Windows portability → Michael Paquier, Peter Eisentraut
- Replication / logical decoding → Amit Kapila, Masahiko Sawada
- Planner / costing → David Rowley, Richard Guo
- Buffer manager / vacuum → Melanie Plageman, Andres Freund, Peter Geoghegan
See
knowledge/personas/<name>.mdfor full reflex maps; otherwisegit -C source log --pretty='%an' -- <touched-file>for recent committers.
- Pre-mail self-review checklist:
review-checklistskill. - First-patch-cover-letter structure.
- Upstream commit-message style:
commit-message-styleskill (NOTmeta-commit-style— those are for the meta repo only).
-
Known risks + unknowns (numbered list with severity tags). Each item:
- Severity: blocker / high / medium / low.
- What: the specific risk or open question.
- Mitigation / next step: what we'd do to resolve.
-
Phase-zero validation (bulleted, optional but recommended). Quick checks the user can run BEFORE phase 1 of implementation to confirm the plan's assumptions still hold:
- "verify file foo.c:NN still has function bar() at the cited line"
- "grep for any since-introduced uses of struct X that the plan didn't account for"
Forbidden in Phase 2
- "We'll figure it out during implementation" for anything in §3-§10. Either decide it here or move it to §13 as an open question.
- Citations without
file:linefromsource/. Vague references like "the executor" are Phase 1 talk. - Skipping §13 (Known risks). Every non-trivial plan has unknowns.
- Dropping a scenario-checklist row from §3 without explicit user approval AND a follow-up edit to the scenario file itself. The §8a coverage gate fails the plan if this happens silently. NOT-edited rows still belong in §3 with a one-line rationale; the pin contract is ADD-only, not subtract.
Method
Step 0.0 — Read the brainstorm's §0 + §0.5 + §0.7 (load-bearing inputs)
Before the scenarios match in Step 0, read the brainstorm's §0 usage surface, §0.5 mechanism survey, and §0.7 reference-impl notes. These are LOAD-BEARING:
- §0 usage surface → the spec for
tests/spec.md(Step 1.5 below). Every example row becomes a regression test case. - §0.5 mechanism survey → the source for the plan's pre-§3
"existing machinery" section. If the brainstorm's recommended
approach picked REUSE (e.g.
PARAM_SESSION_VARIABLEon existing Param node), the plan must INHERIT THAT CHOICE — do not silently invent a new node in §3. - §0.7 reference-impl notes → the upper-bound spec. If the brainstorm read a user reference impl, the plan's §3 file table must be COMPARABLE to (or a superset of) the reference's file footprint. Under-scoping vs reference is a R15 violation.
If the brainstorm is from before this skill's v1.2 update and doesn't have §0 / §0.5 / §0.7, escalate: ask the user whether to (a) re-brainstorm with the updated skill, (b) extend the existing brainstorm in-place with the missing sections, or (c) proceed at the brainstorm's narrow scope with explicit consent.
Step 0.4 — Corpus-chain scenario expansion (cheap, load-bearing)
After Step 0 matched the brainstorm against a scenario slug, run
python3 scripts/corpus-chain.py --scenario <picked-slug>
The output gives you:
- Files touched — the DRAFT §3 file table before the fan-out greps anything. This is the evidence-derived starting point; the fan-out expands and verifies it.
- Idioms invoked — direct + transitive. Every idiom in the
chain becomes a candidate for §8's per-phase "≥1 idiom" link.
Read each idiom's
## Call sitesblock before writing §5 (related infrastructure) — those files are examples of the pattern already in the tree. - Adjacent scenarios — if a scenario shares 5+ files with this one, EXPECT a §12 (conflict risk) entry. Either bundle or sequence with that scenario's work.
- Subsystems — owning subsystems. Each becomes a §5 entry
and each corresponding
knowledge/subsystems/<slug>.mdMUST be read before the fan-out (its## Files ownedblock feeds the fan-out target list per domain). - Analogous past features — planning slugs + session logs with keyword or file overlap. Read the top-2 comparison.md files (if present) BEFORE writing §7 (memory/resource) and §11 (risks). Past runs encode decisions worth inheriting.
Skip this step ONLY if there's no scenario match (brainstorm is
truly novel) — then run --keywords mode instead. Log the chain
map into the plan's §14 (references) so the reviewer can trace it.
Step 0.5 — PARALLEL FAN-OUT for §3 file enumeration
The old single-context method greps the source tree linearly and misses files because one agent can only hold so much in context. The v1.2 method fans out: spawn one subagent per source-tree domain in the same message.
The fan-out EXPANDS on the corpus-chain draft (Step 0.4) —
if a domain agent finds zero files but the chain named files
under that domain, the agent under-searched; if the chain
was empty but an agent finds files, the chain is thin (log
as a corpus gap in progress/coverage-gaps.md).
Fallback when nested Agent tool is unavailable
If running inside a subagent (the Agent tool may not be in your exposed tool set), fall back to PARALLEL Read + Bash tool calls in a single message. Same fan-out logic, same coverage — the subagent is the "container", and the parallel tool calls inside one message are the "fan-out". Document this fallback in your output so the orchestrator knows the harness limitation kicked in.
(Why this fallback works: a single message with N parallel tool calls is effectively a fan-out of N concurrent reads/greps, and the model can synthesize across them in the same context. Sesvars F16 calibration logged this approach as effective.)
Domains to fan out (pick the ones relevant to the feature):
- Agent A — parser. Grep
src/backend/parser/+src/include/parser/+src/pl/plpgsql/src/pl_gram.y+src/interfaces/ecpg/preproc/pgc.l+src/fe_utils/psqlscan.lfor files the feature would touch. Return a §3-row list per file with cited line numbers. - Agent B — executor + JIT. Grep
src/backend/executor/+src/include/executor/+src/backend/jit/llvm/for new EEOP / case-clause sites. Return §3 rows. - Agent C — planner + clauses. Grep
src/backend/optimizer/src/backend/nodes/nodeFuncs.c+src/backend/parser/ parse_collate.cfor walker-coverage sites the new node needs. Return §3 rows.
- Agent D — catalog. Grep
src/include/catalog/for*.datrows / catversion / pg_proc / pg_operator / pg_type impact. Return §3 rows for catalog edits + catversion bump. - Agent E — PL/pgSQL integration. Grep
src/pl/plpgsql/src/for sites that would need updating IF the feature should work inside PL/pgSQL DO blocks / functions. Critical — sesvars calibration missed this entirely. - Agent F — ECPG. Grep
src/interfaces/ecpg/for sites that need sync if the grammar changes. - Agent G — Contrib + tests. Grep
contrib/*/sql/+contrib/*/expected/+src/test/regress/sql/+src/test/recovery/t/+src/test/isolation/specs/for tests that would need updating OR new tests to write. - Agent H — Docs + ruleutils. Grep
doc/src/sgml/ref/+src/backend/utils/adt/ruleutils.c(the parse-tree pretty-printer — F14 lesson!) for sites. Critical — ruleutils is forgotten by default.
Synthesize the agent outputs into the §3 table as the UNION of (scenario checklist rows from Step 0) + (parallel-fan-out rows from Step 0.5) + (brainstorm §0.7 reference-impl file table rows). Deduplicate by file path.
The plan's §3 file count MUST be comparable to or larger than the brainstorm's §0.7 reference-impl file count. If the parallel fan-out produces fewer files than the reference, the fan-out missed something — escalate.
Step 1.5 — Draft tests/spec.md BEFORE §8 phase planning
The sesvars calibration showed that test-suite-as-spec is the right shape: the test cases ARE the requirements. Drafting them before phase planning forces the planner to think about every usage class up-front, instead of discovering gaps phase-by-phase.
Procedure:
-
Take the brainstorm's §0 usage surface (20-30 example lines). Each example becomes one regression test case.
-
Add cross-cutting tests per R14 (the comprehensive own-test- suite rule): identifier edges, NULL handling, type variety, cross-feature integration (PL/pgSQL DO + CTEs + subqueries + EXPLAIN + savepoints + prepared params), adversarial.
-
Add cross-backend TAP cases for any feature with backend- local state (lifetime, isolation, reconnect).
-
Write
tests/spec.md— a structured list of test cases (NOT yet SQL — the structured cases come first, the SQL transliteration is part oftests/regress-cases.sqlwhich the implementation will land).Format:
## Test category: Reader - TC-R-1: `SELECT @x` of never-set name returns NULL. - TC-R-2: `SELECT @x` after `SET @x := 1` returns 1 (int4). - TC-R-3: `SELECT @x IS NULL` after explicit `SET @x := NULL` returns t. ... -
The phase planning in §8 then maps each test category to the phase that makes it pass. If a test category has no phase covering it, the plan is incomplete — go back to §3 + §8.
Step 0 — Match the brainstorm against knowledge/scenarios/ (hard integration)
This is the FIRST thing the planner does, before any corpus loading.
The scenarios layer (knowledge/scenarios/) is task-shaped: one
playbook per recurring change-class, each with an authoritative file
checklist. When the brainstorm's picked approach matches a scenario,
that scenario's checklist is load-bearing — it becomes the
starting authoritative §3 table.
Process:
- Read
knowledge/scenarios/_index.md— the decision tree + the 31-scenario inventory. - Match the brainstorm's change-class against the index:
- Exactly one scenario matches → its file checklist is the starting authoritative §3 table. Every file named in the checklist MUST land in the plan. The planner can ADD sites discovered by grep but can NEVER drop sites the scenario named. Dropping a site requires explicit user approval AND a follow-up edit to the scenario itself.
- Multiple scenarios match (composite feature) → union their checklists. The §3 table is the deduplicated union; verify each row still applies, but do not drop entries from the union.
- Zero scenarios match → ESCALATE to the user with a flag:
"The scenarios layer has a gap for this change-class." Record
the gap in
progress/scenarios-coverage.mdunder "Gaps surfaced by planner runs". Continue with grep-based discovery only.
- Check anchor drift. Read the scenario's
last_verified_commit:frontmatter. If the plan's anchor SHA ≠last_verified_commit, emit a "scenario stale" warning in the plan's §1 and run a fresh grep pass to validate every checklist row before treating the table as authoritative. - Record which scenario(s) the plan pins to in the plan's
## Contextblock (after the date / author posture / engagement class). Format:Scenario(s): add-new-data-type, add-new-operator-class.
Step 0 is the hard contract — it's what makes the scenarios layer load-bearing rather than advisory.
Subsequent steps
-
Read brainstorm + DECISION answers. If they're missing or stale, re-run brainstorm or ask the user inline before proceeding.
-
Load corpus deeply. Read the 1-3 subsystem docs from the brainstorm. Then walk per-file docs (
knowledge/files/src/...) for the directories you'll touch. Open the actualsource/files for anything not in the per-file corpus. Also load every per-file doc linked from the pinned scenario's checklist. -
Inventory the change sites. Run targeted greps over
source/for the symbols, structs, and call sites the plan will touch. Build the §3 table from this. Don't skip files you "think" don't need changes — verify. -
Decide catalog + WAL + lock + memory (§4-§7) BEFORE writing §8 phases. The phases depend on these decisions.
-
Phase the work. Each phase should be 1-3 sittings of editing for a human. Group related edits; don't intersperse unrelated sites.
-
Write tests in the plan, not in the code. Phase-end checks (§8) should reference specific test files in §9.
-
Risk surface (§13) is mandatory. If you genuinely can't think of any, you haven't probed deeply enough.
-
Verify every file:line cite — required final step (M3). Surfaced by the money-fx-exchange shadow run (
cash_outinitially cited asprovolatile='i'; actual is's'persource/src/include/catalog/pg_proc.dat:1954).For each cite that appears in the produced plan:
- Resolve the file at the anchor commit (today:
e18b0cb7344; update whenpg-anchor-refreshlands the next bump). - Confirm the symbol / line / value matches what the plan claims.
- For
.dat/ config cites: spot-check the actual cell value (provolatile,proisstrict, GUC default, etc.), not just the file:line. - Reuse
pg-quality-auditor's file:line discipline (already established for merged docs).
If any cite fails resolution: fix the plan inline. Do not hand off a plan with stale cites.
- Resolve the file at the anchor commit (today:
8a. Scenario-coverage gate — required (M3 extension). For every scenario pinned in Step 0, cross-check that every file in the scenario's checklist appears in the plan's §3 table. Missing files invalidate the plan:
- If a file from the checklist is genuinely not needed for this specific feature, the user must explicitly approve dropping it AND the scenario itself must be edited (don't paper over the drop). Until the scenario is edited, the file stays in §3 even if the plan's §8 phases skip it; the deviation is recorded in §13 risks.
- If anchor-drift was flagged at Step 0 and the checklist appears
stale, run a fresh grep pass to validate each row; update the
scenario's
last_verified_commit:if you do the verification.
The gate is binary: a plan with scenario-coverage gaps fails
validation. Don't ship a plan that quietly drops scenario sites.
9. End with a one-line hand-off: "Run /pg-implement <slug> to
start phase 1." (Use /pg-implement, NOT the generic
/implement — the PG version enforces plan-linked commits, per-phase
tests, and the file:line citation rules in
.claude/rules/pg-implement-discipline.md.)
For a REJECT-track plan (context awareness or thread engagement
surfaced design-level problems), the hand-off is instead: "Plan
recommends REJECT — see Verdict block. Write a thread reply per
.claude/skills/review-checklist/SKILL.md Phase 0."
Boundaries vs other skills
pg-feature-brainstorm(Phase 1): the upstream. Re-run if scope shifts mid-plan./pg-implement(Phase 3 — the PG-specific implementer, NOT the generic/implement): takes this plan and walks the phases interactively with the user. Auto-discoversplanning/<slug>/plan.mdand enforces the rules in.claude/rules/pg-implement-discipline.md(plan-linked commits per phase, file:line citations, etc.).patch-submission: takes over once code is done; this skill stops at the plan.review-checklist: pre-mail check; references in §12 but doesn't run here.memory-keeping: session log of the planning effort goes through this skill at end.
Style
- Cite or don't claim. Every file:line in the plan must be verifiable
with grep against current source at the anchor commit. Tag claims
not from
source/with[from knowledge/...]or[unverified]. - Be specific. "We'll need to update the planner" → which
planner.cfunction, at which line, doing what. - Be honest about scope. If a phase is going to be a full week of work, say so. Don't pretend a refactor is small.
- Plans rot. Stamp the plan with the source commit it was written against (in §1). When the gap from current master grows, re-validate.
Where the artifact lives
planning/<slug>/plan.md, next to brainstorm.md from Phase 1. Both
under planning/<slug>/. Also acceptable:
planning/<slug>/notes.md — running notes from /implement,
appended-to per phase.
When the feature lands upstream, link the plan from the commit message ("see planning/<slug>/plan.md in pg-claude meta repo for design notes") and consider archiving the brainstorm if it's no longer useful.
Cross-references
.claude/skills/pg-feature-brainstorm/SKILL.md— Phase 1 upstream; consumes the brainstorm + DECISION: answers..claude/skills/pg-implement/SKILL.md— Phase 3 consumer; executes the plan phase-by-phase with the discipline rules..claude/skills/pg-patch-review/SKILL.md— Critic E supplies the REJECT-A/B/C grade rubric this skill references..claude/skills/review-checklist/SKILL.md— Phase 0 REJECT-track is the destination when context-awareness or engagement classification recommends REJECT..claude/skills/patch-submission/SKILL.md— used after/pg-implementlands the code, not here..claude/skills/commit-message-style/SKILL.md— referenced from §12 (CF landing strategy); upstream-PG style, not meta..claude/skills/meta-commit-style/SKILL.md— the plan.md file itself commits to the meta repo via this style..claude/skills/memory-keeping/SKILL.md— session log of the planning effort goes through this skill at end..claude/skills/pg-claude/SKILL.md— master nav for picking subsystem docs.knowledge/scenarios/README.md+knowledge/scenarios/_index.md— the scenarios layer Step 0 pins against.knowledge/shadow-implementations/money-fx-exchange/skill-gaps.md— M2/M3/M5 origin (Phase E run 1).knowledge/calibration/shadow-implementation-methodology.md— methodology this skill participates in..claude/commands/pg-plan.md— slash-command wrapper.