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>/.
If brainstorm.md exists, 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.md extracted 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.
- Author history. One-shot poster vs sustained contributor.
git -C source log --author=<email> --oneline and 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, or REJECT-C per the
review-checklist/SKILL.md Phase 0 rubric (summarized below).
- N concrete reasons against the design (numbered, 3-7 typical).
Each reason cites a
source/<path>:<line> invariant, a
knowledge/subsystems/<x>.md INV-tag, or a documented persona
reflex from knowledge/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.md Phase 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 to phase-N/plan.md, then §9 Test surface
pointing at tests/, §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/... or dev/... 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/a for 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 like psqlscan.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.
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.dat entries? Which file?
catversion.h bump required? (Bump if any catalog *.dat or
*.h change.)
- New on-disk format? (Page format, WAL record, file layout.) If
yes, name the upgrade path.
genbki.pl re-run needed? (Implied if catalog files changed.)
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? (
*_redo impact.)
pg_waldump desc/identify updates needed? (Implied by any record
change.)
- Hot Standby conflict generation? (Cite
knowledge/subsystems/access-nbtree.md or
knowledge/subsystems/replication.md for 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?
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 in planning/jsonpath_leak/comparison.md §F30: our
plan asserted "JsonValueListFree releases only the values[]
array, JsonbValue elements remain owned by the input jsonb"
— but executeAnyItem palloc's per-element JsonbValues via
copyJsonbValue that 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 fix 1681a70df3d68 covered only the 2 O(N)
ginEntryInsert sites 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? |
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
MemoryContextCallback as 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 to
MemoryContextCallbackFunction (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 in planning/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. See
knowledge/idioms/memory-contexts.md §"Idioms for
callback-based ownership" for concrete before/after code.
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.md with 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/*.md it follows.
- ≥1
knowledge/personas/*.md whose reviewer reflex will
evaluate this phase.
- ≥1
knowledge/idioms/*.md whose 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.
- Phase-end check (auto-scoped per R13 — see "Phase-end
check scope ladder" below): how
/pg-implement knows 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.md that 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-implement skill'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 broke pg_stat_statements/squashing. sql; the regress-only gate missed it.)
- Grammar / lexer changes (
gram.y, scan.l, pl_gram.y,
ECPG pgc.l) → --suite regress + --suite ecpg + every
contrib/* suite that may parse SQL.
- Executor / planner changes (
execExpr*.c, clauses.c,
plancache.c, etc.) → --suite regress + --suite isolation
- WAL / replication / catversion → above +
--suite recovery.
- Ruleutils / parse-tree formatting → above + a spot-check
on
CREATE VIEW, EXPLAIN VERBOSE, and pg_get_*def output.
(Sesvars F14: T_SessionVar missing from
ruleutils.c get_rule_expr broke EXPLAIN VERBOSE silently.)
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.md for 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.sgml entry needed?
- GUC documentation (if a new GUC)?
- System-catalog doc table update (if catalog changes)?
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>.md for full reflex maps; otherwise
git -C source log --pretty='%an' -- <touched-file> for recent
committers.
- Pre-mail self-review checklist:
review-checklist skill.
- First-patch-cover-letter structure.
- Upstream commit-message style:
commit-message-style skill
(NOT meta-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:line from source/. 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_VARIABLE on
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 sites block 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>.md MUST
be read before the fan-out (its ## Files owned block 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.l
for 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.c for walker-coverage sites the new node needs.
Return §3 rows.
- Agent D — catalog. Grep
src/include/catalog/ for
*.dat rows / 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 of tests/regress-cases.sql which
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.md under "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
## Context block (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 actual source/ 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_out initially
cited as provolatile='i'; actual is 's' per
source/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 when pg-anchor-refresh lands 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.
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.
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-discovers planning/<slug>/plan.md
and 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.c
function, 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//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-implement lands 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.
1---2name: pg-feature-plan3description: 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 a4---56# pg-feature-plan — Phase 2 of the PG planner78The heavy stage. Phase 1 (`pg-feature-brainstorm`) narrowed the9design space; Phase 2 makes it implementable. Output is a plan-mode10plan with file:line cites that `/pg-implement` (NOT the generic11`/implement`) executes phase-by-phase with plan-linked commits.1213## Inputs1415- **Slug** (required): the planning directory under `planning/<slug>/`.16 If `brainstorm.md` exists, read it first — the picked approach + the17 DECISION: answers are your constraints.18- **No brainstorm?** Fine — accept a direct natural-language description19 of the picked approach + any constraints the user has already locked20 down. But note in the plan's intro that Phase 1 was skipped (and21 therefore some design-space exploration may be missing).22- **Thread spec?** A `planning/<slug>/spec.md` extracted from a23 pgsql-hackers thread (shadow-implementation runs). Run the spec24 through the engagement-classification step below before treating25 any of its content as locked.2627## Context awareness — mandatory pre-step (M2)2829**Before drafting any plan content**, run a context probe. Surfaced30by the money-fx-exchange shadow run (April-1 2026 joke proposal that31the planner initially treated earnestly).32331. **Posting date.** Check the thread's first-message date:34 - April 1 → flag for joke-check (look for `[PoC]` / `[RFC]`35 wording, absence of patch attachment, deadpan replies).36 - Within 2 weeks of a release-branch cut → flag for late-cycle37 context; the realistic CF target is the *next* window, not38 this one.39 - During an open CommitFest's commit window → check if the40 author intends this CF or the next.412. **Author history.** One-shot poster vs sustained contributor.42 `git -C source log --author=<email> --oneline` and a quick43 pgsql-hackers archive search. A one-shot speculative post44 warrants different planning energy than a sustained45 contributor's serious proposal.463. **Thread engagement signal** (see M5 below for the taxonomy).47 Reply count alone is misleading; classify what kind of48 engagement the replies represent.4950Output a `## Context` block at the top of the plan that names date,51author posture, and engagement class. If the probe surfaces signal52that the proposal isn't serious (deadpan-only replies, joke53indicators, demonstrably unimplementable), the plan's recommended54verdict shifts to **REJECT** with cited reasons rather than a phased55implementation. See `.claude/skills/review-checklist/SKILL.md` Phase 056for the REJECT-A/B/C grade rubric.5758## Thread-engagement classification (M5)5960When the input includes a thread (typical for shadow-implementation61runs), classify the engagement explicitly — not just the reply count.62Surfaced by the money-fx-exchange shadow run, where the deadpan63"thanks, add to commitfest" reply was the only public signal.6465| Class | Signature | Plan implication |66|---|---|---|67| `unengaged` | No technical replies; deadpan acks; silence | Treat the spec as the *author's* unreviewed take. Don't pretend community endorsement exists. |68| `acked` | Technical replies with no objections | Spec is community-validated; proceed at normal confidence. |69| `debated` | Multiple substantive replies with disagreements + counter-proposals | Plan should enumerate the open questions as §13 risks, not paper over them. |70| `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. |7172Record the classification in the plan's `## Context` block.7374## REJECT-track output shape (when verdict is REJECT)7576When the Context-awareness probe (M2) or Engagement classification (M5)77recommends REJECT, the plan file's body becomes a **Verdict block** in78place of the standard §3-§14 implementation sections. Required contents:79801. **Verdict line.** `REJECT-A`, `REJECT-B`, or `REJECT-C` per the81 `review-checklist/SKILL.md` Phase 0 rubric (summarized below).822. **N concrete reasons against the design** (numbered, 3-7 typical).83 Each reason cites a `source/<path>:<line>` invariant, a84 `knowledge/subsystems/<x>.md` INV-tag, or a documented persona85 reflex from `knowledge/personas/<name>.md`.863. **Predicted lead reviewer** with the reflex they trigger87 (e.g. "Tom Lane — type-system + dump-determinism";88 "Andres Freund — per-row hot-path"; "Noah Misch — security /89 install-script immutability"). See `knowledge/personas/` for the90 reflex map.914. **Concrete alternative shape** if one exists (the "what they92 probably wanted" rewrite). Skip only when the proposal is93 irredeemable.945. **Hand-off line** points to `review-checklist/SKILL.md` Phase 095 ("Write a thread reply"), NOT `/pg-implement`.9697The §1 "What this plan is" + `## Context` block still appear; §2-§14 do98not. No phased implementation, no §3 files table — those would imply the99plan is implementable, which contradicts the verdict.100101### REJECT-A/B/C grade summary102103Full rubric: `.claude/skills/review-checklist/SKILL.md` Phase 0.104105| Grade | Meaning |106|---|---|107| `REJECT-A` | Identified all critical design problems + proposed correct alternative. Saves community cycles. |108| `REJECT-B` | Identified most critical problems but missed one major concern. |109| `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). |110111## Output structure — multi-file plan (v1.2 — calibration-driven)112113**Old shape (deprecated for non-trivial features):** single114`planning/<slug>/plan.md` covering all 14 sections.115116**New shape:** **orchestrator + per-phase files + supporting docs.**117The sesvars calibration showed that single-file plans force118shallow per-phase detail (the 307-line plan could only give each119of 6 phases ~30 lines, which is why scope leaked). The new shape120lets each phase be hundreds of lines deep on its own without121bloating the orchestrator.122123```124planning/<slug>/125├── plan.md — ORCHESTRATOR (§1-§4, §11-§14, phase index)126├── machinery-survey.md — §0.5 existing-PG-mechanism analysis (NEW)127├── tests/128│ ├── spec.md — §3.5 test-suite-as-spec draft (NEW)129│ ├── regress-cases.sql — drafted regression SQL the impl must pass130│ └── tap-cases.md — drafted TAP test scenarios131├── phase-0/132│ ├── plan.md — full §3 / edits / phase-end check for phase 0133│ └── notes.md — appended during /pg-implement (R8)134├── phase-1/135│ ├── plan.md136│ └── notes.md137├── phase-2/ ... phase-N/ — one dir per phase138└── comparison.md — written post-implementation by /pg-implement139 if a user reference impl exists (R15 calibration)140```141142**When to use the multi-file shape:**143- Feature touches > 15 files → multi-file required.144- Feature has > 3 phases → multi-file required.145- Feature has a user reference impl → multi-file required (§0.5 +146 tests/spec.md are load-bearing).147- Otherwise: single-file is fine. Mark it explicitly at the top:148 `Plan shape: single-file (small feature, < 15 files, ≤ 3 phases).`149150**Orchestrator file (`plan.md`) contents** when multi-file is151used:152- §1 What this plan is, §2 Scope contract, §3 Files-by-domain153 SUMMARY table (high-level — full per-phase tables live in154 `phase-N/plan.md`), §4 Catalog impact, §5 WAL, §6 Locking, §7155 Memory, then a **§8 Phase index** with a one-line summary per156 phase and a link to `phase-N/plan.md`, then §9 Test surface157 pointing at `tests/`, §10 Docs, §11-§14 as usual.158159**Per-phase file (`phase-N/plan.md`) contents:**160- Phase title + one-paragraph why.161- §3 table for THIS PHASE ONLY (files touched, change type, size,162 cited concrete edit).163- Concrete edits (the actual code shape per file).164- Phase-end check (auto-scoped per R13 based on what files the165 phase touches — see "Phase-end check scope" below).166- §13 risks for THIS PHASE.167- Inline persona + scenario + idiom citations (REQUIRED — see168 "Citations" below).169170Length scales: ~200-400 lines per phase file is normal; large171phases can be 1000+. The orchestrator itself stays ~300-500 lines172regardless of feature size.173174## Output (legacy single-file shape)175176For small features (< 15 files, ≤ 3 phases, no reference impl):177single `planning/<slug>/plan.md` following the structure below.178Length scales with the feature: ~400 lines for a small change,179~1500 lines for a medium feature, more for a major patch series.180181### Required sections (in this order)1821831. **What this plan is** (1 paragraph). State the picked approach (link184 to the brainstorm if it exists). Name the chosen scope (MVP vs185 full). State the target PG version + CF window.1861872. **Scope contract** (3-5 bullets). Hard boundaries: what this plan188 COVERS, and what's explicitly OUT of scope. The plan-mode rule is189 strict: anything not in scope here is a follow-up.1901913. **Files that change** (a table). Each row:192 - File path (under `source/...` or `dev/...` for new files).193 - Change type: `new` / `modify` / `delete` / `not edited (sync trap)`194 / `not edited (auto-generated)` / `not edited (build-time validator)`.195 - Approximate size: `tiny (<10 lines)` / `small (10-50)` / `medium196 (50-200)` / `large (>200)` / `n/a` for NOT-edited rows.197 - One-sentence summary of what changes — with a `source/<path>:<line>`198 cite for any file:line claim in the summary. Example row:199 `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 | —`200 - Per-file doc citation: `[via knowledge/files/.../X.md]` if one201 exists.202203 Aim for completeness here. Missing a file in this table is a Phase 2204 bug. If you don't know all the sites, do another grep pass.205206 **Pin contract reminder (from Method Step 0):** every file named in207 the pinned scenario's checklist MUST appear in §3, including rows208 marked `NOT edited` (build-time validators, auto-generated headers,209 sync-trap files like `psqlscan.l` / `ecpg/pgc.l` / `check_keywords.pl`).210 Listing a NOT-edited row with a one-line rationale is correct;211 silently dropping it is the failure mode the §8a coverage gate212 catches at plan-finalization time. The planner can ADD sites213 discovered by grep, but can NEVER DROP a scenario row without214 explicit user approval AND a follow-up edit to the scenario file215 itself.2162174. **Catalog + on-disk impact** (bulleted). Each item is yes/no with218 rationale:219 - New `pg_proc.dat` / `pg_operator.dat` / `pg_type.dat` / `pg_cast.dat`220 / `pg_opclass.dat` entries? Which file?221 - `catversion.h` bump required? (Bump if any catalog `*.dat` or222 `*.h` change.)223 - New on-disk format? (Page format, WAL record, file layout.) If224 yes, name the upgrade path.225 - `genbki.pl` re-run needed? (Implied if catalog files changed.)2262275. **WAL impact** (bulleted). Each yes/no with detail:228 - New rmgr or new info byte for existing rmgr?229 - Existing record extended with new fields? (Compat policy.)230 - Replay function changes? (`*_redo` impact.)231 - `pg_waldump` desc/identify updates needed? (Implied by any record232 change.)233 - Hot Standby conflict generation? (Cite234 `knowledge/subsystems/access-nbtree.md` or235 `knowledge/subsystems/replication.md` for the pattern if applicable.)2362376. **Locking + concurrency** (bulleted). Each item is "we need / we238 don't need" with cite:239 - New LWLock? (Add to `lwlocknames.h`?)240 - New heavyweight lock mode?241 - Buffer lock ordering implications? (Cite the relevant subsystem242 doc's lock-order section.)243 - Atomic-vs-spinlock decisions for shmem fields?244 - SSI predicate-lock implications?2452467. **Memory + resource management** (bulleted):247 - New `MemoryContext`? Where in the hierarchy?248 - Per-query or per-tuple allocations?249 - Long-lived state (TopMemoryContext, CacheMemoryContext)?250 - `palloc_aligned` / DSA / shmem-resident state?251 - **Ownership invariants** (REQUIRED when any "X is owned by Y"252 claim appears in this section). For every ownership claim, run253 a **grep-pass data-flow verification** and record its result254 inline:255 1. Identify every code site that produces an X — `palloc`,256 `copyObject`, `copyJsonbValue`, `pstrdup`, `makeNode`,257 constructor calls, etc.258 2. For each producer, confirm the path that hands the X to Y259 — direct assignment, append to a Y-owned collection, or260 function-call argument transfer.261 3. If ANY producer hands X to something other than Y (e.g.262 appends to Y but also retains a copy elsewhere; passes by263 borrowed reference; mixes copy-vs-borrow semantics like264 `JsonValueListAppend(found, copy ? copyJsonbValue(v) : v)`),265 the ownership claim is FALSE as stated — refine the claim266 or refine the data flow before continuing.267 4. Record the grep command(s) you ran and the file:line list268 you walked, e.g.269 `Grep "JsonValueListAppend\\|copyJsonbValue" jsonpath_exec.c → 3 producers verified to hand ownership to the surrounding JsonValueList; 1 mixed-ownership site flagged at line 1741.`270 Anchored in `planning/jsonpath_leak/comparison.md` §F30: our271 plan asserted "JsonValueListFree releases only the values[]272 array, JsonbValue elements remain owned by the input jsonb"273 — but `executeAnyItem` palloc's per-element JsonbValues via274 `copyJsonbValue` that the ownership claim missed. The leak275 was 4.9 GB even after Phase 2 freed the arrays. A 30-second276 grep-pass would have shown 3 producer sites and one mixed277 copy-vs-borrow site, surfacing the wrong invariant at plan278 time rather than at R4 phase-end check time.279280 **F40 — categorize each leak site by fire-count class.** For281 every site the grep-pass surfaces, tag it as **O(N) scaling**282 (fires N times per operation, N in input size) or **O(1)283 one-shot** (fires a bounded number of times per operation).284 The plan should treat only the O(N) sites unless an O(1)285 site carries an independent correctness concern (e.g. UAF286 risk, invariant violation). Treating O(1) sites for287 "uniform coverage" adds LOC without addressing genuine288 leak-scaling. Anchored in289 `planning/gin_parallel_merge_leak/comparison.md` §F40 —290 Vinod's upstream fix `1681a70df3d68` covered only the 2 O(N)291 `ginEntryInsert` sites inside the merge loop and skipped the292 1 O(1) final-flush site; our blind fix covered all 3 for293 uniformity and shipped +5 lines heavier without changing the294 leak-scaling outcome. Format the categorization inline in the295 plan §7 grep-pass table:296 `| site | fire-count | leak-scaling | treat? |`297 - **Callback-based approach detail (L7)**. If the recommended298 approach uses a memory-context reset callback (approach C299 under L6, or approach E when the invariant is a per-scan300 resource release), the plan MUST name three301 implementation-level design choices explicitly rather than302 leaving them for Phase 3 discovery:303 1. **Callback storage location** — embed304 `MemoryContextCallback` as a *field* of the surrounding305 state struct (F34 preferred) OR palloc separately on the306 target context (only if the state struct is off-limits).307 The embed choice removes a palloc site and the "who owns308 the callback struct?" question.309 2. **Callback function shape** — cast a well-known cleanup310 function (`PQclear`, `pfree`, `PQfinish`, `close`,311 `hash_destroy`, etc.) directly to312 `MemoryContextCallbackFunction` (F35 preferred) OR write a313 wrapper only if the cleanup needs bookkeeping the314 dispatcher can't provide (pointer-to-pointer indirection,315 conditional logic, multi-step release).316 3. **Ownership semantics** — single-owner via callback (F36317 preferred): once armed, the callback owns; every other318 release path detaches (`cb.arg = NULL`) or delegates.319 Two-owner explicit handoff is correct but heavier.320 Anchored in `planning/fdw_directmodify_leak/comparison.md`321 §F34+F35+F36 — L6 correctly flagged approach E on that run,322 but the blind plan chose the heavier variant on all three323 details, adding 25-30 LOC over Tom's actual fix without324 changing the design category. Naming the three choices at325 plan time closes that detail-vs-category gap. See326 `knowledge/idioms/memory-contexts.md` §"Idioms for327 callback-based ownership" for concrete before/after code.3283298. **Phased implementation** (the meat). Break into 3-8 phases (the330 old 3-6 range was tight for comprehensive features per R15).331 **For multi-file plan shape, each phase has its own332 `phase-N/plan.md` with the structure below; the orchestrator333 only lists the index.** Each phase entry:334335 - Phase number + title.336 - Files this phase touches (subset of §3).337 - The 5-15 concrete edits this phase makes (each with file:line338 where possible). For multi-file shape, list every site —339 don't truncate to "5-10".340 - **Inline citations** (REQUIRED — per R14 + R15 + the sesvars341 calibration F1-F15 findings). Each phase must cite:342 - ≥1 `knowledge/scenarios/*.md` it follows.343 - ≥1 `knowledge/personas/*.md` whose reviewer reflex will344 evaluate this phase.345 - ≥1 `knowledge/idioms/*.md` whose pattern it uses.346 - Any prior calibration finding F-N from347 `sessions/2026-06-16-sesvars-calibration-findings.md` (or348 successor) that this phase must heed.349 - **Phase-end check** (auto-scoped per R13 — see "Phase-end350 check scope ladder" below): how `/pg-implement` knows this351 phase is done. NOT "regress passes" alone — apply the R13352 scope ladder.353 - **Tests covered by this phase**: list the TC-* IDs from354 `tests/spec.md` that this phase makes pass.355356 A phase is self-contained enough that you could stop after it and357 the tree still builds + the declared phase-end check (R13 scope)358 passes. (This is the `/pg-implement` skill's requirement, R4.)359360### Phase-end check scope ladder (R13, applied per-phase)361362The phase-end check MUST match the phase's blast radius (R13 in363pg-implement-discipline.md v1.1):364365- **Helper-only changes** → `meson test --suite regress`.366- **Catalog changes** (`pg_operator.dat`, `pg_proc.dat`, etc.) →367 `--suite regress` + every `--suite contrib-*`. (Sesvars F12:368 Phase 0's catalog cleanup broke `pg_stat_statements/squashing.369 sql`; the regress-only gate missed it.)370- **Grammar / lexer changes** (`gram.y`, `scan.l`, `pl_gram.y`,371 ECPG `pgc.l`) → `--suite regress` + `--suite ecpg` + every372 `contrib/*` suite that may parse SQL.373- **Executor / planner changes** (`execExpr*.c`, `clauses.c`,374 `plancache.c`, etc.) → `--suite regress` + `--suite isolation`375 + every `contrib/*` suite.376- **WAL / replication / catversion** → above + `--suite recovery`.377- **Ruleutils / parse-tree formatting** → above + a spot-check378 on `CREATE VIEW`, `EXPLAIN VERBOSE`, and `pg_get_*def` output.379 (Sesvars F14: `T_SessionVar` missing from380 `ruleutils.c get_rule_expr` broke `EXPLAIN VERBOSE` silently.)381382Each phase's plan section names the EXACT command line:383`meson test -C build-debug --suite regress --suite contrib-pg_stat_statements`384— not a vague "regress passes".3853869. **Test surface** (bulleted with file paths). When multi-file387 shape is used, this section is a SUMMARY that points at388 `tests/spec.md` for the full draft (Step 1.5).389390 - **`tests/spec.md`** — structured test cases drafted from §0391 usage surface (REQUIRED per R14).392 - **Regress** (`src/test/regress/sql/`): name the per-phase393 happy-path file (e.g. `sessvar.sql`) AND the comprehensive394 own-suite file (e.g. `sessvar_advanced.sql` — REQUIRED by395 R14: identifier edges, type variety, cross-feature396 integration, adversarial). The comprehensive suite is what397 catches gaps the per-phase regress misses (sesvars F14).398 - **Isolation** (`src/test/isolation/specs/`): concurrency races399 this feature could cause? Name the spec file(s).400 - **TAP** (`src/test/recovery/t/` or similar): multi-node /401 subscriber / replication / cross-backend isolation. REQUIRED402 for features with backend-local state.403 - **`src/test/modules/`**: in-tree C test module needed?404 - **amcheck / `pg_amcheck`**: if AM-related.405 - **pgbench**: if performance-relevant.406 - **Contrib regression**: name any contrib SQL files that may407 break from this feature's changes (e.g. catalog-cleanup408 phases hit `pg_stat_statements/squashing.sql`).40941010. **Docs** (bulleted):411 - SGML page(s) to add/update under `doc/src/sgml/`?412 - `release-N.sgml` entry needed?413 - GUC documentation (if a new GUC)?414 - System-catalog doc table update (if catalog changes)?41541611. **Patch-series structure** (1 paragraph + bullets). Single patch417 or split? If split, name each patch and what depends on what.418 Default to single patch for ≤500 lines + one logical change; split419 for refactor-then-feature or multi-subsystem changes.42042112. **CommitFest landing strategy** (bulleted):422 - Which CF? (e.g. "PG20-1, open now until 2026-06-30").423 - Pre-existing thread to revive, or new thread?424 - Likely reviewers? Name 2-3 with the **reflex** each would apply.425 Anchor on the subsystem the patch touches:426 - Type-system / catalog / dump-determinism / API-back-compat → Tom Lane427 - Performance / executor hot path / parallel safety → Andres Freund428 - Security / install-script immutability / test-omission → Noah Misch429 - Parser / locale / Windows portability → Michael Paquier, Peter Eisentraut430 - Replication / logical decoding → Amit Kapila, Masahiko Sawada431 - Planner / costing → David Rowley, Richard Guo432 - Buffer manager / vacuum → Melanie Plageman, Andres Freund, Peter Geoghegan433 See `knowledge/personas/<name>.md` for full reflex maps; otherwise434 `git -C source log --pretty='%an' -- <touched-file>` for recent435 committers.436 - Pre-mail self-review checklist: `review-checklist` skill.437 - First-patch-cover-letter structure.438 - Upstream commit-message style: `commit-message-style` skill439 (NOT `meta-commit-style` — those are for the meta repo only).44044113. **Known risks + unknowns** (numbered list with severity tags).442 Each item:443 - **Severity:** blocker / high / medium / low.444 - **What:** the specific risk or open question.445 - **Mitigation / next step:** what we'd do to resolve.44644714. **Phase-zero validation** (bulleted, optional but recommended).448 Quick checks the user can run BEFORE phase 1 of implementation to449 confirm the plan's assumptions still hold:450 - "verify file foo.c:NN still has function bar() at the cited line"451 - "grep for any since-introduced uses of struct X that the plan452 didn't account for"453454### Forbidden in Phase 2455456- "We'll figure it out during implementation" for anything in §3-§10.457 Either decide it here or move it to §13 as an open question.458- Citations without `file:line` from `source/`. Vague references like459 "the executor" are Phase 1 talk.460- Skipping §13 (Known risks). Every non-trivial plan has unknowns.461- **Dropping a scenario-checklist row from §3** without explicit user462 approval AND a follow-up edit to the scenario file itself. The §8a463 coverage gate fails the plan if this happens silently. NOT-edited464 rows still belong in §3 with a one-line rationale; the pin contract465 is ADD-only, not subtract.466467## Method468469### Step 0.0 — Read the brainstorm's §0 + §0.5 + §0.7 (load-bearing inputs)470471Before the scenarios match in Step 0, **read the brainstorm's §0472usage surface, §0.5 mechanism survey, and §0.7 reference-impl473notes**. These are LOAD-BEARING:474475- §0 usage surface → the spec for `tests/spec.md` (Step 1.5476 below). Every example row becomes a regression test case.477- §0.5 mechanism survey → the source for the plan's pre-§3478 "existing machinery" section. If the brainstorm's recommended479 approach picked REUSE (e.g. `PARAM_SESSION_VARIABLE` on480 existing Param node), the plan must INHERIT THAT CHOICE — do481 not silently invent a new node in §3.482- §0.7 reference-impl notes → the upper-bound spec. If the483 brainstorm read a user reference impl, the plan's §3 file484 table must be COMPARABLE to (or a superset of) the reference's485 file footprint. Under-scoping vs reference is a R15 violation.486487If the brainstorm is from before this skill's v1.2 update and488doesn't have §0 / §0.5 / §0.7, **escalate**: ask the user489whether to (a) re-brainstorm with the updated skill, (b) extend490the existing brainstorm in-place with the missing sections, or491(c) proceed at the brainstorm's narrow scope with explicit492consent.493494### Step 0.4 — Corpus-chain scenario expansion (cheap, load-bearing)495496After Step 0 matched the brainstorm against a scenario slug, run497498```499python3 scripts/corpus-chain.py --scenario <picked-slug>500```501502The output gives you:503504- **Files touched** — the DRAFT §3 file table before the fan-out505 greps anything. This is the evidence-derived starting point;506 the fan-out expands and verifies it.507- **Idioms invoked** — direct + transitive. Every idiom in the508 chain becomes a candidate for §8's per-phase "≥1 idiom" link.509 Read each idiom's `## Call sites` block before writing §5510 (related infrastructure) — those files are examples of the511 pattern already in the tree.512- **Adjacent scenarios** — if a scenario shares 5+ files with513 this one, EXPECT a §12 (conflict risk) entry. Either bundle514 or sequence with that scenario's work.515- **Subsystems** — owning subsystems. Each becomes a §5 entry516 and each corresponding `knowledge/subsystems/<slug>.md` MUST517 be read before the fan-out (its `## Files owned` block feeds518 the fan-out target list per domain).519- **Analogous past features** — planning slugs + session logs520 with keyword or file overlap. Read the top-2 comparison.md521 files (if present) BEFORE writing §7 (memory/resource) and522 §11 (risks). Past runs encode decisions worth inheriting.523524Skip this step ONLY if there's no scenario match (brainstorm is525truly novel) — then run `--keywords` mode instead. Log the chain526map into the plan's §14 (references) so the reviewer can trace it.527528### Step 0.5 — PARALLEL FAN-OUT for §3 file enumeration529530The old single-context method greps the source tree linearly531and misses files because one agent can only hold so much in532context. The v1.2 method fans out: spawn one subagent per533source-tree domain in the same message.534535The fan-out EXPANDS on the corpus-chain draft (Step 0.4) —536if a domain agent finds zero files but the chain named files537under that domain, the agent under-searched; if the chain538was empty but an agent finds files, the chain is thin (log539as a corpus gap in `progress/coverage-gaps.md`).540541#### Fallback when nested Agent tool is unavailable542543If running inside a subagent (the Agent tool may not be in your544exposed tool set), fall back to PARALLEL Read + Bash tool calls545in a single message. Same fan-out logic, same coverage — the546subagent is the "container", and the parallel tool calls inside547one message are the "fan-out". Document this fallback in your548output so the orchestrator knows the harness limitation kicked in.549550(Why this fallback works: a single message with N parallel tool551calls is effectively a fan-out of N concurrent reads/greps, and552the model can synthesize across them in the same context. Sesvars553F16 calibration logged this approach as effective.)554555Domains to fan out (pick the ones relevant to the feature):556557- **Agent A — parser.** Grep `src/backend/parser/` +558 `src/include/parser/` + `src/pl/plpgsql/src/pl_gram.y` +559 `src/interfaces/ecpg/preproc/pgc.l` + `src/fe_utils/psqlscan.l`560 for files the feature would touch. Return a §3-row list per561 file with cited line numbers.562- **Agent B — executor + JIT.** Grep `src/backend/executor/` +563 `src/include/executor/` + `src/backend/jit/llvm/` for new564 EEOP / case-clause sites. Return §3 rows.565- **Agent C — planner + clauses.** Grep `src/backend/optimizer/`566 + `src/backend/nodes/nodeFuncs.c` + `src/backend/parser/567 parse_collate.c` for walker-coverage sites the new node needs.568 Return §3 rows.569- **Agent D — catalog.** Grep `src/include/catalog/` for570 `*.dat` rows / catversion / pg_proc / pg_operator / pg_type571 impact. Return §3 rows for catalog edits + catversion bump.572- **Agent E — PL/pgSQL integration.** Grep `src/pl/plpgsql/src/`573 for sites that would need updating IF the feature should work574 inside PL/pgSQL DO blocks / functions. Critical — sesvars575 calibration missed this entirely.576- **Agent F — ECPG.** Grep `src/interfaces/ecpg/` for sites577 that need sync if the grammar changes.578- **Agent G — Contrib + tests.** Grep `contrib/*/sql/` +579 `contrib/*/expected/` + `src/test/regress/sql/` +580 `src/test/recovery/t/` + `src/test/isolation/specs/` for581 tests that would need updating OR new tests to write.582- **Agent H — Docs + ruleutils.** Grep583 `doc/src/sgml/ref/` + `src/backend/utils/adt/ruleutils.c`584 (the parse-tree pretty-printer — F14 lesson!) for sites.585 Critical — ruleutils is forgotten by default.586587Synthesize the agent outputs into the §3 table as the UNION of588(scenario checklist rows from Step 0) + (parallel-fan-out rows589from Step 0.5) + (brainstorm §0.7 reference-impl file table590rows). Deduplicate by file path.591592**The plan's §3 file count MUST be comparable to or larger than593the brainstorm's §0.7 reference-impl file count.** If the parallel594fan-out produces fewer files than the reference, the fan-out595missed something — escalate.596597### Step 1.5 — Draft `tests/spec.md` BEFORE §8 phase planning598599The sesvars calibration showed that test-suite-as-spec is the600right shape: the test cases ARE the requirements. Drafting them601before phase planning forces the planner to think about every602usage class up-front, instead of discovering gaps phase-by-phase.603604Procedure:6056061. Take the brainstorm's §0 usage surface (20-30 example lines).607 Each example becomes one regression test case.6082. Add cross-cutting tests per R14 (the comprehensive own-test-609 suite rule): identifier edges, NULL handling, type variety,610 cross-feature integration (PL/pgSQL DO + CTEs + subqueries +611 EXPLAIN + savepoints + prepared params), adversarial.6123. Add cross-backend TAP cases for any feature with backend-613 local state (lifetime, isolation, reconnect).6144. Write `tests/spec.md` — a structured list of test cases615 (NOT yet SQL — the structured cases come first, the SQL616 transliteration is part of `tests/regress-cases.sql` which617 the implementation will land).618619 Format:620 ```621 ## Test category: Reader622 - TC-R-1: `SELECT @x` of never-set name returns NULL.623 - TC-R-2: `SELECT @x` after `SET @x := 1` returns 1 (int4).624 - TC-R-3: `SELECT @x IS NULL` after explicit `SET @x := NULL`625 returns t.626 ...627 ```6285. The phase planning in §8 then maps each test category to the629 phase that makes it pass. If a test category has no phase630 covering it, the plan is incomplete — go back to §3 + §8.631632### Step 0 — Match the brainstorm against `knowledge/scenarios/` (hard integration)633634**This is the FIRST thing the planner does, before any corpus loading.**635636The scenarios layer (`knowledge/scenarios/`) is task-shaped: one637playbook per recurring change-class, each with an authoritative file638checklist. When the brainstorm's picked approach matches a scenario,639that scenario's checklist is **load-bearing** — it becomes the640starting authoritative §3 table.641642Process:6436441. **Read `knowledge/scenarios/_index.md`** — the decision tree + the645 31-scenario inventory.6462. **Match the brainstorm's change-class** against the index:647 - **Exactly one scenario matches** → its file checklist is the648 **starting authoritative §3 table**. Every file named in the649 checklist MUST land in the plan. The planner can ADD sites650 discovered by grep but can NEVER drop sites the scenario named.651 Dropping a site requires explicit user approval AND a follow-up652 edit to the scenario itself.653 - **Multiple scenarios match (composite feature)** → union their654 checklists. The §3 table is the deduplicated union; verify each655 row still applies, but do not drop entries from the union.656 - **Zero scenarios match** → ESCALATE to the user with a flag:657 "The scenarios layer has a gap for this change-class." Record658 the gap in `progress/scenarios-coverage.md` under "Gaps659 surfaced by planner runs". Continue with grep-based discovery660 only.6613. **Check anchor drift.** Read the scenario's `last_verified_commit:`662 frontmatter. If the plan's anchor SHA ≠ `last_verified_commit`,663 emit a **"scenario stale" warning** in the plan's §1 and run a664 fresh grep pass to validate every checklist row before treating665 the table as authoritative.6664. **Record which scenario(s) the plan pins to** in the plan's667 `## Context` block (after the date / author posture / engagement668 class). Format: `Scenario(s): add-new-data-type, add-new-operator-class`.669670Step 0 is the hard contract — it's what makes the scenarios layer671load-bearing rather than advisory.672673### Subsequent steps6746751. **Read brainstorm + DECISION answers.** If they're missing or stale,676 re-run brainstorm or ask the user inline before proceeding.6776782. **Load corpus deeply.** Read the 1-3 subsystem docs from the679 brainstorm. Then walk per-file docs (`knowledge/files/src/...`) for680 the directories you'll touch. Open the actual `source/` files for681 anything not in the per-file corpus. Also load every per-file doc682 linked from the pinned scenario's checklist.6836843. **Inventory the change sites.** Run targeted greps over `source/`685 for the symbols, structs, and call sites the plan will touch. Build686 the §3 table from this. Don't skip files you "think" don't need687 changes — verify.6886894. **Decide catalog + WAL + lock + memory** (§4-§7) BEFORE writing690 §8 phases. The phases depend on these decisions.6916925. **Phase the work.** Each phase should be 1-3 sittings of editing693 for a human. Group related edits; don't intersperse unrelated694 sites.6956966. **Write tests in the plan, not in the code.** Phase-end checks (§8)697 should reference specific test files in §9.6986997. **Risk surface (§13) is mandatory.** If you genuinely can't think700 of any, you haven't probed deeply enough.7017028. **Verify every file:line cite — required final step (M3).**703 Surfaced by the money-fx-exchange shadow run (`cash_out` initially704 cited as `provolatile='i'`; actual is `'s'` per705 `source/src/include/catalog/pg_proc.dat:1954`).706707 For each cite that appears in the produced plan:708 - Resolve the file at the anchor commit (today: `e18b0cb7344`;709 update when `pg-anchor-refresh` lands the next bump).710 - Confirm the symbol / line / value matches what the plan claims.711 - For `.dat` / config cites: spot-check the actual cell value712 (`provolatile`, `proisstrict`, GUC default, etc.), not just the713 file:line.714 - Reuse `pg-quality-auditor`'s file:line discipline (already715 established for merged docs).716717 If any cite fails resolution: fix the plan inline. **Do not hand718 off a plan with stale cites.**7197208a. **Scenario-coverage gate — required (M3 extension).** For every721 scenario pinned in Step 0, cross-check that **every file in the722 scenario's checklist appears in the plan's §3 table**. Missing723 files invalidate the plan:724 - If a file from the checklist is genuinely not needed for this725 specific feature, the user must explicitly approve dropping it726 AND the scenario itself must be edited (don't paper over the727 drop). Until the scenario is edited, the file stays in §3 even728 if the plan's §8 phases skip it; the deviation is recorded in729 §13 risks.730 - If anchor-drift was flagged at Step 0 and the checklist appears731 stale, run a fresh grep pass to validate each row; update the732 scenario's `last_verified_commit:` if you do the verification.733734 The gate is binary: a plan with scenario-coverage gaps fails735 validation. Don't ship a plan that quietly drops scenario sites.7367379. **End with a one-line hand-off:** *"Run `/pg-implement <slug>` to738 start phase 1."* (Use `/pg-implement`, NOT the generic739 `/implement` — the PG version enforces plan-linked commits, per-phase740 tests, and the file:line citation rules in741 `.claude/rules/pg-implement-discipline.md`.)742743 For a REJECT-track plan (context awareness or thread engagement744 surfaced design-level problems), the hand-off is instead: *"Plan745 recommends REJECT — see Verdict block. Write a thread reply per746 `.claude/skills/review-checklist/SKILL.md` Phase 0."*747748## Boundaries vs other skills749750- **`pg-feature-brainstorm`** (Phase 1): the upstream. Re-run if scope751 shifts mid-plan.752- **`/pg-implement`** (Phase 3 — the PG-specific implementer, NOT the753 generic `/implement`): takes this plan and walks the phases754 interactively with the user. Auto-discovers `planning/<slug>/plan.md`755 and enforces the rules in `.claude/rules/pg-implement-discipline.md`756 (plan-linked commits per phase, file:line citations, etc.).757- **`patch-submission`**: takes over once code is done; this skill stops758 at the plan.759- **`review-checklist`**: pre-mail check; references in §12 but doesn't760 run here.761- **`memory-keeping`**: session log of the planning effort goes through762 this skill at end.763764## Style765766- Cite or don't claim. Every file:line in the plan must be verifiable767 with grep against current source at the anchor commit. Tag claims768 not from `source/` with `[from knowledge/...]` or `[unverified]`.769- Be specific. "We'll need to update the planner" → which `planner.c`770 function, at which line, doing what.771- Be honest about scope. If a phase is going to be a full week of772 work, say so. Don't pretend a refactor is small.773- Plans rot. Stamp the plan with the source commit it was written774 against (in §1). When the gap from current master grows, re-validate.775776## Where the artifact lives777778`planning/<slug>/plan.md`, next to `brainstorm.md` from Phase 1. Both779under `planning/<slug>/`. Also acceptable:780`planning/<slug>/notes.md` — running notes from `/implement`,781appended-to per phase.782783When the feature lands upstream, link the plan from the commit message784("see planning/<slug>/plan.md in pg-claude meta repo for design785notes") and consider archiving the brainstorm if it's no longer useful.786787## Cross-references788789- `.claude/skills/pg-feature-brainstorm/SKILL.md` — Phase 1 upstream; consumes the brainstorm + DECISION: answers.790- `.claude/skills/pg-implement/SKILL.md` — Phase 3 consumer; executes the plan phase-by-phase with the discipline rules.791- `.claude/skills/pg-patch-review/SKILL.md` — Critic E supplies the REJECT-A/B/C grade rubric this skill references.792- `.claude/skills/review-checklist/SKILL.md` — Phase 0 REJECT-track is the destination when context-awareness or engagement classification recommends REJECT.793- `.claude/skills/patch-submission/SKILL.md` — used after `/pg-implement` lands the code, not here.794- `.claude/skills/commit-message-style/SKILL.md` — referenced from §12 (CF landing strategy); upstream-PG style, not meta.795- `.claude/skills/meta-commit-style/SKILL.md` — the plan.md file itself commits to the meta repo via this style.796- `.claude/skills/memory-keeping/SKILL.md` — session log of the planning effort goes through this skill at end.797- `.claude/skills/pg-claude/SKILL.md` — master nav for picking subsystem docs.798- `knowledge/scenarios/README.md` + `knowledge/scenarios/_index.md` — the scenarios layer Step 0 pins against.799- `knowledge/shadow-implementations/money-fx-exchange/skill-gaps.md` — M2/M3/M5 origin (Phase E run 1).800- `knowledge/calibration/shadow-implementation-methodology.md` — methodology this skill participates in.801- `.claude/commands/pg-plan.md` — slash-command wrapper.