fix(pstack-c1): fold design-twice into Section 1 of the eng review section, per-host transcript table, fixture and slice-cap repairs

The remote free run reported nine failures in seven files, all from this
branch: four tests encode plan-eng-review's one companion section
(eng-scope-entry-ap, autoplan-methodology-names, plan-review-cases,
review-checklists), so the design-twice pass now lives inside Section 1 of
sections/review-sections.md with the skeleton, manifest and
bin/gstack-autoplan-snapshot.ts back at main; the Codex render of
context-restore named ~/.claude/ through the all-hosts transcript table, so
{{TRANSCRIPT_SOURCES}} renders this host's row only; the transcript fixture
is declared in FREE_FIXTURES; and the two new periodic cases took the census
to 39 slices, so evals-periodic.yml's eval-slices max-parallel goes 38 -> 40.
Pins: 11 plan-eng-review re-pins at +2,896; maxSizeRatio 1.2400 (measured
1.2389); Codex gpt-5.4 overlay 159,588 bytes.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
garrytanandcapy-ai[bot] committed 2026-10-26 22:02:47 +00:00
1 parent 6b530ccc0b
commit 0119569a6e
19 files changed
+195 -212

No files matched your search

+4 -3
View File
@@ -173,7 +173,7 @@ jobs:
if: steps.census.outputs.periodic_lane == 'true'
env:
EVALS_ALL: "1"
run: EVALS_TIER=periodic bun --no-install run scripts/test-paid-shards.ts --tier periodic --emit-plan /tmp/paid-plan/manifest.json --slice-budget 420 --jobs 2 --max-parallel 38
run: EVALS_TIER=periodic bun --no-install run scripts/test-paid-shards.ts --tier periodic --emit-plan /tmp/paid-plan/manifest.json --slice-budget 420 --jobs 2 --max-parallel 40
# Codex-only slices run on the host-run eval-codex-slices job; the
# container executor runs every other slice.
@@ -294,8 +294,9 @@ jobs:
strategy:
fail-fast: false
# Every planned slice starts at once; test/evals-workflow-wiring.test.ts
# fails when the live plan outgrows this cap.
max-parallel: 38
# fails when the live plan outgrows this cap. 38 → 40 on 2026-10-26: the
# benchmark and context-restore carve cases made the census 39 slices.
max-parallel: 40
matrix:
slice: ${{ fromJSON(needs.plan-slices.outputs.periodic_slices) }}
steps:
+2 -2
View File
@@ -3,13 +3,13 @@
## [Unreleased]
### Added
- **Four lazily read sections absorbed from pstack** (Lauren Tan, MIT; ideas rewritten in gstack's words, NOTICE.md; Garry, 2026-10-26: "Do it, send"). `/investigate` gains `sections/blast-radius.md`, read before fixing a shared helper, library call or data format or when asked what a change could break: name the one fact the change is safe because of, climb the five-rung evidence ladder (said so, pointed at it, walked the failure, ran it, reproduced it) and say where you stopped, look where grep stops (library source at the pinned version, timing, the JSON an API returns, a column, a wire format, code three hops away), and list confirmed and cleared risks apart; Phase 3's red flags add the sharper trigger before the 3-strike rule: two fixes that shared one premise and failed the same gate mean the premise is written down and tested before a third fix. `/context-restore` is carved for the first time: when Step 1 prints `NO_CHECKPOINTS`, `sections/transcripts.md` rebuilds the brief from this workspace's own transcripts (Claude Code `~/.claude/projects/<slug>/*.jsonl`, Codex `~/.codex/sessions/` filtered by cwd, Capy none, from a `transcripts` table in `hosts/*.ts` rendered by the new `{{TRANSCRIPT_SOURCES}}` and `{{TRANSCRIPT_DISCOVERY}}` resolvers), a fixed window (7 days by default, never quietly narrowed), never another project's folder, cheap subagents that return only findings, redaction before anything leaves the machine, git and gh verifying every PR and branch, and a Capsule / Threads (one status tag each) / Problems / Next move brief with an offer to save it as a checkpoint. `/benchmark` is carved for the first time: `sections/vet-the-number.md`, read before Phase 5 reports any comparison, asks the seven questions (why not double: name the limiter; was it tuned; did it break a limit; did it error; does it reproduce over at least 5 alternating runs, a gap smaller than the run-to-run variation being no difference; does it matter end to end; did the work even happen) and ends with a verdict of faster, slower, no measurable difference or inconclusive. `/plan-eng-review` gains `sections/design-twice.md`, read when the plan introduces a new module, service, package or boundary: a second structurally distinct shape compared on interface depth, and the eight design red flags written for agent contributors (shallow module, information leakage, temporal decomposition, pass-through method, split ownership, two ways to do one task, importable internals, hand-synced list); the autoplan runner's checklist names the pass.
- **Four lazily read passes absorbed from pstack** (Lauren Tan, MIT; ideas rewritten in gstack's words, NOTICE.md; Garry, 2026-10-26: "Do it, send"). `/investigate` gains `sections/blast-radius.md`, read before fixing a shared helper, library call or data format or when asked what a change could break: name the one fact the change is safe because of, climb the five-rung evidence ladder (said so, pointed at it, walked the failure, ran it, reproduced it) and say where you stopped, look where grep stops (library source at the pinned version, timing, the JSON an API returns, a column, a wire format, code three hops away), and list confirmed and cleared risks apart; Phase 3's red flags add the sharper trigger before the 3-strike rule: two fixes that shared one premise and failed the same gate mean the premise is written down and tested before a third fix. `/context-restore` is carved for the first time: when Step 1 prints `NO_CHECKPOINTS`, `sections/transcripts.md` rebuilds the brief from this workspace's own transcripts (Claude Code `~/.claude/projects/<slug>/*.jsonl`, Codex `~/.codex/sessions/` filtered by cwd, Capy none, from a `transcripts` table in `hosts/*.ts` rendered by the new `{{TRANSCRIPT_SOURCES}}` and `{{TRANSCRIPT_DISCOVERY}}` resolvers), a fixed window (7 days by default, never quietly narrowed), never another project's folder, cheap subagents that return only findings, redaction before anything leaves the machine, git and gh verifying every PR and branch, and a Capsule / Threads (one status tag each) / Problems / Next move brief with an offer to save it as a checkpoint. `/benchmark` is carved for the first time: `sections/vet-the-number.md`, read before Phase 5 reports any comparison, asks the seven questions (why not double: name the limiter; was it tuned; did it break a limit; did it error; does it reproduce over at least 5 alternating runs, a gap smaller than the run-to-run variation being no difference; does it matter end to end; did the work even happen) and ends with a verdict of faster, slower, no measurable difference or inconclusive. `/plan-eng-review`'s lazy review section gains the pass "Two shapes before one (design-twice)" inside Section 1 (Architecture review), run only when the plan introduces a new module, service, package or boundary: a second structurally distinct shape compared on interface depth, and the eight design red flags written for agent contributors (shallow module, information leakage, temporal decomposition, pass-through method, split ownership, two ways to do one task, importable internals, hand-synced list); the autoplan runner's checklist maps the pass, and the skeleton, manifest and methodology bundle are unchanged. The transcript table each host renders names only that host's store (a Codex render never names `~/.claude/`).
### Tests
- `test/context-restore-transcripts.test.ts` (new): the carve shape, the host table against `hosts/*.ts`, and the discovery block run against a fixture transcript (`test/fixtures/context-restore-transcript.jsonl`): it lists this workspace's files inside the window, not a 10-day-old one, never the sibling project's, prints none on Capy and for a missing folder, and the Codex render keeps only the rollout whose cwd is this workspace. `test/pstack-sections.test.ts` (new): benchmark's and plan-eng-review's carve shape and tokens, and the credit line plus NOTICE.md entry on every pstack-derived section. `test/investigate-recipes.test.ts`: the sixth section, its Phase 4 pointer and the shared-premise red flag.
### Gate integrity
- No threshold, timeout, trial count or case kind changed. `test/helpers/carve-guards.ts`: investigate's measured skeleton 51,532 → 51,623 inside the unchanged 52,000 cap; plan-eng-review's `maxSizeRatio` 1.2196 → 1.26 for the 3.0 KB section joining the union (measured 1.2439; skeleton 52,185, inside the 57,800 cap); new entries for context-restore (skeleton 45,848 ≤ 46,300, union 52,510 ≥ 50,000) and benchmark (skeleton 30,781 ≤ 31,300, union 34,527 ≥ 33,000), each with a periodic `carve-section-loading-<skill>` case and its touchfiles. The eleven `gstack-plan-eng-review` pins in `test/fixtures/skill-md-size-allowlist.json` move to their exact rendered sizes, 2,885 characters each, for the inlined section; owner decision: pstack item 9, Garry 2026-10-26 "do it". The Codex render of plan-eng-review sits 423 bytes under the 160,000-byte host ceiling on its largest model overlay (gpt-5.4: 159,577 bytes; the first 4.2 KB draft of the section went over it): the section was cut to fit, and the next byte added to that skill on an external host needs the deferred preamble hoist or a carve on every host. `bin/gstack-autoplan-snapshot.ts` binds every section the review's index names (the one review section plus companions such as design-twice) instead of refusing a second entry, and `test/autoplan-review-discovery.test.ts` installs every generated section; `test/paid-shards.test.ts`'s registry walk gets a 30 s budget (it ran 4.97 s at main on a 4-core machine against a 5 s default).
- No threshold, timeout, trial count or case kind changed. `test/helpers/carve-guards.ts`: investigate's measured skeleton 51,532 → 51,623 inside the unchanged 52,000 cap; plan-eng-review's `maxSizeRatio` 1.2196 → 1.2400 for the 2.4 KB pass joining the lazy section (measured 154,366 / 124,597 = 1.2389; skeleton unchanged at 51,670); new entries for context-restore (skeleton 45,848 ≤ 46,300, union 52,510 ≥ 50,000) and benchmark (skeleton 30,781 ≤ 31,300, union 34,527 ≥ 33,000), each with a periodic `carve-section-loading-<skill>` case and its touchfiles. The eleven `gstack-plan-eng-review` pins in `test/fixtures/skill-md-size-allowlist.json` move to their exact rendered sizes, 2,896 characters each, for the inlined pass; owner decision: pstack item 9, Garry 2026-10-26 "do it". The Codex render of plan-eng-review sits 423 bytes under the 160,000-byte host ceiling on its largest model overlay (gpt-5.4: 159,588 bytes; the first 4.2 KB draft of the pass went over it): the pass was cut to fit, and the next byte added to that skill on an external host needs the deferred preamble hoist or a carve on every host. `test/paid-shards.test.ts`'s registry walk gets a 30 s budget (it ran 4.97 s at main on a 4-core machine against a 5 s default). The two new periodic cases take the full census from 38 to 39 slices, so `evals-periodic.yml`'s `eval-slices` `max-parallel` (and the planner's `--max-parallel`) goes 38 → 40; every slice still starts at once. `test/fixtures/context-restore-transcript.jsonl` is declared in `FREE_FIXTURES`.
## [1.91.256.0] - 2026-10-26
+1 -1
View File
@@ -102,6 +102,6 @@ the shared-premise red flag in `investigate/sections/blast-radius.md.tmpl` and
`investigate/SKILL.md.tmpl`; the transcript-mining fallback and its status-tagged brief in
`context-restore/sections/transcripts.md.tmpl`; the seven questions in
`benchmark/sections/vet-the-number.md.tmpl`; the second-shape comparison and the eight
design red flags in `plan-eng-review/sections/design-twice.md.tmpl`; and the generated
design red flags in Section 1 of `plan-eng-review/sections/review-sections.md.tmpl`; and the generated
`SKILL.md` / `sections/*.md` files. Each section names its source in a first-line comment.
Written in gstack's words; no sentence is copied, so no license text is carried.
+7 -15
View File
@@ -538,22 +538,14 @@ function methodologyContent(phase: string, skillFile: string) {
if (indexHeadings.length !== 1 || /^## Review Sections\b/m.test(mainProse)) throw new Error('Ambiguous methodology layout');
const index = mainProse.slice(indexHeadings[0]!.index! + indexHeadings[0]![0].length).split(/\n## /)[0]!;
const sections = [...index.matchAll(/`(sections\/[^`]+)`/g)].map(match => match[1]!);
// The index names the one complete review section plus any companion
// sections a situation adds to it (plan-eng-review's design-twice pass);
// every listed file is bound, in index order, so the dispatch carries them all.
if (new Set(sections).size !== sections.length || sections.filter(s => s === 'sections/review-sections.md').length !== 1) {
throw new Error('Expected the one complete current review section');
}
for (const file of sections) {
const section = readPart(join(dirname(skillFile), file));
const sectionProse = referenceProse(section.text).join('\n');
const reviewHeadings = [...sectionProse.matchAll(/^## Review Sections\b/gm)].length;
if (reviewHeadings !== (file === 'sections/review-sections.md' ? 1 : 0) ||
/^## Section index\b/m.test(sectionProse) || /sections\/[\w.-]+\.md/.test(sectionProse)) {
throw new Error('Missing or nested methodology review section');
}
parts.push(section);
if (sections.length !== 1 || sections[0] !== 'sections/review-sections.md') throw new Error('Expected the one complete current review section');
const section = readPart(join(dirname(skillFile), sections[0]));
const sectionProse = referenceProse(section.text).join('\n');
if ([...sectionProse.matchAll(/^## Review Sections\b/gm)].length !== 1 ||
/^## Section index\b/m.test(sectionProse) || /sections\/[\w.-]+\.md/.test(sectionProse)) {
throw new Error('Missing or nested methodology review section');
}
parts.push(section);
} else if ([...mainProse.matchAll(/^## Review Sections\b/gm)].length !== 1) {
throw new Error('Inline methodology is missing its complete review section');
}
-1
View File
@@ -14,7 +14,6 @@ edits code.
| Host | Transcripts | How this workspace's files are told apart |
|---|---|---|
| Claude Code | `~/.claude/projects/<slug>/*.jsonl` | one folder per workspace; <slug> is the workspace path with every character that is not a letter or digit turned into "-" |
| OpenAI Codex CLI | `~/.codex/sessions/<yyyy>/<mm>/<dd>/rollout-*.jsonl` | dated rollout files from every workspace on the machine; the first line of each names its cwd |
| Capy (any model) | none | the harness keeps no transcript on the machine; say so and use the shared record and git |
### Step T1: Lock the scope, then list the files
-4
View File
@@ -493,7 +493,6 @@ sections. Read a section in full before doing its step; do not work from memory.
| When | Read this section |
|------|-------------------|
| starting the Scope Challenge and full review (after target selection and startup) | `sections/review-sections.md` |
| reviewing a plan that introduces a new module, service, package or boundary (the design-twice pass inside Section 1, the Architecture review) | `sections/design-twice.md` |
---
## Web research runs in Aside
@@ -626,9 +625,6 @@ Scope Challenge is mandatory before Section 1. Read the section below: it runs *
**Complexity gate:** while a Scope Challenge complexity question awaits an answer, do not start Section 1, call ExitPlanMode, or write findings or fixes into a plan file. An unchanged copy of the original plan is allowed. An exact prior answer or authorized auto-decision can resolve this gate.
> **STOP.** Before reviewing a plan that introduces a new module, service, package or boundary (the design-twice pass inside Section 1, the Architecture review), Read `~/.claude/skills/gstack/plan-eng-review/sections/design-twice.md` and execute it
> in full. Do not work from memory — that section is the source of truth for this step.
> **STOP.** Before starting the Scope Challenge and full review (after target selection and startup), Read `~/.claude/skills/gstack/plan-eng-review/sections/review-sections.md` and execute it
> in full. Do not work from memory — that section is the source of truth for this step.
-2
View File
@@ -152,8 +152,6 @@ Scope Challenge is mandatory before Section 1. Read the section below: it runs *
**Complexity gate:** while a Scope Challenge complexity question awaits an answer, do not start Section 1, call ExitPlanMode, or write findings or fixes into a plan file. An unchanged copy of the original plan is allowed. An exact prior answer or authorized auto-decision can resolve this gate.
{{SECTION:design-twice}}
{{SECTION:review-sections}}
## Recovery routing
-51
View File
@@ -1,51 +0,0 @@
<!-- AUTO-GENERATED from design-twice.md.tmpl — do not edit directly -->
<!-- Regenerate: bun run gen:skill-docs -->
<!-- "Design it twice" and the red flags derive from pstack's architect skill (Lauren Tan, MIT), rewritten for gstack. See NOTICE.md. -->
## Two shapes before one
Use this inside Section 1 (Architecture review) when the plan introduces a
new module, service, package or boundary: a public surface other code calls.
### Ask for the second shape
A plan with one design usually took the first shape that compiled in the
author's head. Before judging it, require a second shape that is structurally
different: another owner for the state, another split of responsibilities,
another place for the boundary. A point fix inside the first shape is not a
second candidate. When the plan has none, sketch one in five lines (types and
signatures, bodies `not implemented`) and record it as the alternative.
Compare the candidates on interface depth: how much behavior and policy each
hides behind how small a public surface, and prefer the one that hides more
behind less. A deep module is not a deep call chain: the chain scatters the
understanding across layers, the module concentrates it behind one interface.
### The eight red flags
Screen the chosen shape before Section 1 closes. Assume the next contributor
is an agent that sees only the files it opened, copies the nearest example
and takes the shortest path that compiles; prefer the design where a change
that looks right from one file is right for the whole repo. A flag is a
finding with a file or symbol and a reason to revise the shape, not a comment
asking for care.
1. **Shallow module.** A large interface over little hidden complexity:
several calls per operation, options that expose internal stages.
2. **Information leakage.** One decision (a representation, a policy, a wire
or storage detail) lives in more than one module. Re-exported transport
types are leakage; parse external data into domain types at the boundary.
3. **Temporal decomposition.** Modules split by execution order (load,
validate, transform, save) instead of by the knowledge they own.
4. **Pass-through method.** A function that forwards the same arguments to
another with the same shape; remove it or move the responsibility.
5. **Split ownership.** Two modules write the same state or each keep a copy;
an agent editing one cannot see the other. One owner per piece of state.
6. **Two ways to do one task.** An agent copies whichever it meets first.
Keep one; move the callers and delete the rest in the same change.
7. **Importable internals.** The shortest path that compiles imports them and
they become interface. Make an outside import fail the build.
8. **Hand-synced list.** The same items in two places; an agent that sees one
list edits one. Derive the second, or fail the build when they disagree.
Record under Architecture: both shapes, the pick, the depth argument for it,
and each flag with its fix.
@@ -1,49 +0,0 @@
<!-- "Design it twice" and the red flags derive from pstack's architect skill (Lauren Tan, MIT), rewritten for gstack. See NOTICE.md. -->
## Two shapes before one
Use this inside Section 1 (Architecture review) when the plan introduces a
new module, service, package or boundary: a public surface other code calls.
### Ask for the second shape
A plan with one design usually took the first shape that compiled in the
author's head. Before judging it, require a second shape that is structurally
different: another owner for the state, another split of responsibilities,
another place for the boundary. A point fix inside the first shape is not a
second candidate. When the plan has none, sketch one in five lines (types and
signatures, bodies `not implemented`) and record it as the alternative.
Compare the candidates on interface depth: how much behavior and policy each
hides behind how small a public surface, and prefer the one that hides more
behind less. A deep module is not a deep call chain: the chain scatters the
understanding across layers, the module concentrates it behind one interface.
### The eight red flags
Screen the chosen shape before Section 1 closes. Assume the next contributor
is an agent that sees only the files it opened, copies the nearest example
and takes the shortest path that compiles; prefer the design where a change
that looks right from one file is right for the whole repo. A flag is a
finding with a file or symbol and a reason to revise the shape, not a comment
asking for care.
1. **Shallow module.** A large interface over little hidden complexity:
several calls per operation, options that expose internal stages.
2. **Information leakage.** One decision (a representation, a policy, a wire
or storage detail) lives in more than one module. Re-exported transport
types are leakage; parse external data into domain types at the boundary.
3. **Temporal decomposition.** Modules split by execution order (load,
validate, transform, save) instead of by the knowledge they own.
4. **Pass-through method.** A function that forwards the same arguments to
another with the same shape; remove it or move the responsibility.
5. **Split ownership.** Two modules write the same state or each keep a copy;
an agent editing one cannot see the other. One owner per piece of state.
6. **Two ways to do one task.** An agent copies whichever it meets first.
Keep one; move the callers and delete the rest in the same change.
7. **Importable internals.** The shortest path that compiles imports them and
they become interface. Make an outside import fail the build.
8. **Hand-synced list.** The same items in two places; an agent that sees one
list edits one. Derive the second, or fail the build when they disagree.
Record under Architecture: both shapes, the pick, the depth argument for it,
and each flag with its fix.
+1 -8
View File
@@ -2,7 +2,7 @@
"$schema": "https://gstack.dev/schemas/section-manifest.json",
"skill": "plan-eng-review",
"version": 1,
"note": "PASSIVE registry (v2 plan T9 / CM2). id/file/title/trigger text ONLY. The skeleton's decision-tree prose decides WHEN to read. No machine predicate here for interactive renders — see docs/designs/v2_PLAN.md. Optional `scope` (always | ui | dx | db | perf | security | incident; default always) and `runner_only` (true: omitted from the Section index) are read by bin/gstack-autoplan alone (plan B4): an unattended or light run loads the checklist plus the sections whose scope the detected scope needs and prints `Skipped sections: <ids> (scope: <detected>)`.",
"note": "PASSIVE registry (v2 plan T9 / CM2). id/file/title/trigger text ONLY. The skeleton's decision-tree prose decides WHEN to read. No machine predicate here for interactive renders \u2014 see docs/designs/v2_PLAN.md. Optional `scope` (always | ui | dx | db | perf | security | incident; default always) and `runner_only` (true: omitted from the Section index) are read by bin/gstack-autoplan alone (plan B4): an unattended or light run loads the checklist plus the sections whose scope the detected scope needs and prints `Skipped sections: <ids> (scope: <detected>)`.",
"sections": [
{
"id": "review-sections",
@@ -11,13 +11,6 @@
"trigger": "starting the Scope Challenge and full review (after target selection and startup)",
"scope": "always"
},
{
"id": "design-twice",
"file": "design-twice.md",
"title": "Two shapes before one: a second structurally distinct candidate compared on interface depth, and the eight design red flags for agent contributors",
"trigger": "reviewing a plan that introduces a new module, service, package or boundary (the design-twice pass inside Section 1, the Architecture review)",
"scope": "always"
},
{
"id": "checklist",
"file": "checklist.md",
@@ -525,6 +525,52 @@ Evaluate:
* One realistic production failure per new path/integration; does the plan handle it?
* **Distribution architecture:** New artifacts' build, publish and update paths; included or deferred CI/CD.
<!-- "Design it twice" and the red flags derive from pstack's architect skill (Lauren Tan, MIT), rewritten for gstack. See NOTICE.md. -->
### Two shapes before one (design-twice)
Run this only when the plan introduces a new module, service, package or
boundary: a public surface other code calls; otherwise say so in one line.
**Ask for the second shape.** A plan with one design usually took the first
shape that compiled in the author's head. Before judging it, require a second
shape that is structurally different: another owner for the state, another
split of responsibilities, another place for the boundary. A point fix inside
the first shape is not a second candidate. When the plan has none, sketch one
in five lines (types and signatures, bodies `not implemented`) and record it
as the alternative. Compare the candidates on interface depth: how much
behavior and policy each hides behind how small a public surface, and prefer
the one that hides more behind less. A deep module is not a deep call chain:
the chain scatters the understanding across layers, the module concentrates
it behind one interface.
**The eight red flags.** Screen the chosen shape before Section 1 closes.
Assume the next contributor is an agent that sees only the files it opened,
copies the nearest example and takes the shortest path that compiles; prefer
the design where a change that looks right from one file is right for the
whole repo. A flag is a finding with a file or symbol and a reason to revise
the shape, not a comment asking for care.
1. **Shallow module.** A large interface over little hidden complexity:
several calls per operation, options that expose internal stages.
2. **Information leakage.** One decision (a representation, a policy, a wire
or storage detail) lives in more than one module. Re-exported transport
types are leakage; parse external data into domain types at the boundary.
3. **Temporal decomposition.** Modules split by execution order (load,
validate, transform, save) instead of by the knowledge they own.
4. **Pass-through method.** A function that forwards the same arguments to
another with the same shape; remove it or move the responsibility.
5. **Split ownership.** Two modules write the same state or each keep a copy;
an agent editing one cannot see the other. One owner per piece of state.
6. **Two ways to do one task.** An agent copies whichever it meets first.
Keep one; move the callers and delete the rest in the same change.
7. **Importable internals.** The shortest path that compiles imports them and
they become interface. Make an outside import fail the build.
8. **Hand-synced list.** The same items in two places; an agent that sees one
list edits one. Derive the second, or fail the build when they disagree.
Record under Architecture: both shapes, the pick, the depth argument for it,
and each flag with its fix.
### 2. Code quality review
Evaluate:
* Organization and module structure.
@@ -403,6 +403,52 @@ Evaluate:
* One realistic production failure per new path/integration; does the plan handle it?
* **Distribution architecture:** New artifacts' build, publish and update paths; included or deferred CI/CD.
<!-- "Design it twice" and the red flags derive from pstack's architect skill (Lauren Tan, MIT), rewritten for gstack. See NOTICE.md. -->
### Two shapes before one (design-twice)
Run this only when the plan introduces a new module, service, package or
boundary: a public surface other code calls; otherwise say so in one line.
**Ask for the second shape.** A plan with one design usually took the first
shape that compiled in the author's head. Before judging it, require a second
shape that is structurally different: another owner for the state, another
split of responsibilities, another place for the boundary. A point fix inside
the first shape is not a second candidate. When the plan has none, sketch one
in five lines (types and signatures, bodies `not implemented`) and record it
as the alternative. Compare the candidates on interface depth: how much
behavior and policy each hides behind how small a public surface, and prefer
the one that hides more behind less. A deep module is not a deep call chain:
the chain scatters the understanding across layers, the module concentrates
it behind one interface.
**The eight red flags.** Screen the chosen shape before Section 1 closes.
Assume the next contributor is an agent that sees only the files it opened,
copies the nearest example and takes the shortest path that compiles; prefer
the design where a change that looks right from one file is right for the
whole repo. A flag is a finding with a file or symbol and a reason to revise
the shape, not a comment asking for care.
1. **Shallow module.** A large interface over little hidden complexity:
several calls per operation, options that expose internal stages.
2. **Information leakage.** One decision (a representation, a policy, a wire
or storage detail) lives in more than one module. Re-exported transport
types are leakage; parse external data into domain types at the boundary.
3. **Temporal decomposition.** Modules split by execution order (load,
validate, transform, save) instead of by the knowledge they own.
4. **Pass-through method.** A function that forwards the same arguments to
another with the same shape; remove it or move the responsibility.
5. **Split ownership.** Two modules write the same state or each keep a copy;
an agent editing one cannot see the other. One owner per piece of state.
6. **Two ways to do one task.** An agent copies whichever it meets first.
Keep one; move the callers and delete the rest in the same change.
7. **Importable internals.** The shortest path that compiles imports them and
they become interface. Make an outside import fail the build.
8. **Hand-synced list.** The same items in two places; an agent that sees one
list edits one. Derive the second, or fail the build when they disagree.
Record under Architecture: both shapes, the pick, the depth argument for it,
and each flag with its fix.
### 2. Code quality review
Evaluate:
* Organization and module structure.
+13 -10
View File
@@ -2,10 +2,12 @@
* Transcript resolvers for /context-restore's no-checkpoint fallback
* (context-restore/sections/transcripts.md.tmpl).
*
* {{TRANSCRIPT_SOURCES}} → the table of transcript stores, one row per host
* that declares `transcripts` in hosts/<name>.ts,
* plus the Capy row (none; the harness keeps no
* transcript on the machine).
* {{TRANSCRIPT_SOURCES}} → the table of transcript stores for THIS host
* (its `transcripts` row from hosts/<name>.ts, or
* a none row) plus the Capy row (none; the harness
* keeps no transcript on the machine). Only the
* rendering host's paths appear: a Codex render
* never names ~/.claude/.
* {{TRANSCRIPT_DISCOVERY}} → the bash block that lists THIS host's transcript
* files for the current workspace only, inside the
* window, and prints `TRANSCRIPTS: none (...)` on
@@ -16,19 +18,20 @@
* never hand-writes them. test/context-restore-transcripts.test.ts runs the
* discovery block against fixture transcripts.
*/
import { ALL_HOST_CONFIGS, getHostConfig } from '../../hosts/index';
import { getHostConfig } from '../../hosts/index';
import type { TemplateContext } from './types';
export const CAPY_NO_TRANSCRIPTS = 'TRANSCRIPTS: none (Capy keeps no session transcript on this machine; use the shared record and git)';
export function generateTranscriptSources(): string {
const rows = ALL_HOST_CONFIGS
.filter(h => h.transcripts)
.map(h => `| ${h.displayName} | \`${h.transcripts!.root}\` | ${h.transcripts!.layout} |`);
export function generateTranscriptSources(ctx: TemplateContext): string {
const host = getHostConfig(ctx.host);
const row = host.transcripts
? `| ${host.displayName} | \`${host.transcripts.root}\` | ${host.transcripts.layout} |`
: `| ${host.displayName} | none | this host declares no transcript store gstack may read; use the shared record and git |`;
return [
'| Host | Transcripts | How this workspace\'s files are told apart |',
'|---|---|---|',
...rows,
row,
'| Capy (any model) | none | the harness keeps no transcript on the machine; say so and use the shared record and git |',
].join('\n');
}
+4 -11
View File
@@ -122,13 +122,9 @@ describe('autoplan reads installed host methodology', () => {
expect(directive).toContain('"<REVIEW_SKILL>"');
}
if (carved) {
// An install carries every generated section, not only the review body:
// plan-eng-review's design-twice companion is bound by the same snapshot.
const sectionsDir = path.dirname(sectionSource);
for (const file of fs.readdirSync(sectionsDir).filter(name => name.endsWith('.md'))) {
installFile(path.join(sectionsDir, file), path.resolve(path.dirname(entry), reference, '..', 'sections', file), mode);
}
const sectionInstalled = path.resolve(path.dirname(entry), reference, '..', 'sections/review-sections.md');
const relative = 'sections/review-sections.md';
const sectionInstalled = path.resolve(path.dirname(entry), reference, '..', relative);
installFile(sectionSource, sectionInstalled, mode);
const section = fs.readFileSync(sectionInstalled, 'utf8');
expect(section).toBe(fs.readFileSync(sectionSource, 'utf8'));
expect(section).toContain('## Review Sections');
@@ -139,10 +135,7 @@ describe('autoplan reads installed host methodology', () => {
const restore = path.join(registry, 'restore.md');
fs.writeFileSync(restore, 'owned restore\n');
const skillPath = path.resolve(path.dirname(entry), reference);
// The bundle binds every section the skill's index names, in index order.
const indexed = [...loaded.matchAll(/^\| .* \| `(sections\/[^`]+)` \|$/gm)].map(match => match[1]!);
expect(indexed).toContain('sections/review-sections.md');
assertBundle(methodology(phase, skillPath, restore), [skillPath, ...indexed.map(rel => path.resolve(path.dirname(skillPath), rel))]);
assertBundle(methodology(phase, skillPath, restore), [skillPath, sectionInstalled]);
} else {
expect(directive).not.toContain('sections/review-sections.md');
expect(loaded).toContain('## Review Sections');
+13 -9
View File
@@ -48,16 +48,20 @@ describe('context-restore carve: the transcript fallback', () => {
expect(skeleton).toMatch(/HARD GATE:\*\* Do NOT implement code changes/);
});
test('the host table comes from hosts/*.ts and carries Claude Code, Codex and the Capy row', () => {
const table = generateTranscriptSources();
expect(section).toContain(table);
for (const host of ALL_HOST_CONFIGS.filter(h => h.transcripts)) {
expect(table).toContain('| ' + host.displayName + ' | \u0060' + host.transcripts!.root + '\u0060 |');
}
test("the host table comes from hosts/*.ts: this host's row plus the Capy row, never another host's paths", () => {
const ctx = (host: string) => ({ host, skillName: 'context-restore', paths: { binDir: '$GSTACK_BIN' } }) as never;
expect(ALL_HOST_CONFIGS.filter(h => h.transcripts).map(h => h.name).sort()).toEqual(['claude', 'codex']);
expect(table).toContain('~/.claude/projects/<slug>/*.jsonl');
expect(table).toContain('~/.codex/sessions/');
expect(table).toContain('| Capy (any model) | none |');
const claude = generateTranscriptSources(ctx('claude'));
expect(section).toContain(claude);
expect(claude).toContain('| Claude Code | `~/.claude/projects/<slug>/*.jsonl` |');
expect(claude).not.toContain('~/.codex/');
const codex = generateTranscriptSources(ctx('codex'));
expect(codex).toContain('| OpenAI Codex CLI | `~/.codex/sessions/');
expect(codex).not.toContain('~/.claude/');
const cursor = generateTranscriptSources(ctx('cursor'));
expect(cursor).toContain('| Cursor | none |');
expect(cursor).not.toContain('~/.claude/');
for (const table of [claude, codex, cursor]) expect(table).toContain('| Capy (any model) | none |');
expect(section).toMatch(/Capy[^\n]*say so and use the shared record and git/);
});
+11 -11
View File
@@ -8,7 +8,7 @@
"agy/gstack-land-and-deploy": 117690,
"agy/gstack-plan-design-review": 139981,
"agy/gstack-plan-devex-review": 135728,
"agy/gstack-plan-eng-review": 155459,
"agy/gstack-plan-eng-review": 155470,
"agy/gstack-review": 124400,
"claude/design-review": 136499,
"codex/gstack-autoplan": 130596,
@@ -18,7 +18,7 @@
"codex/gstack-office-hours": 102276,
"codex/gstack-plan-design-review": 142434,
"codex/gstack-plan-devex-review": 138617,
"codex/gstack-plan-eng-review": 158005,
"codex/gstack-plan-eng-review": 158016,
"codex/gstack-review": 125304,
"copilot/gstack-autoplan": 131605,
"copilot/gstack-codex": 100203,
@@ -28,7 +28,7 @@
"copilot/gstack-office-hours": 100432,
"copilot/gstack-plan-design-review": 140852,
"copilot/gstack-plan-devex-review": 136880,
"copilot/gstack-plan-eng-review": 156184,
"copilot/gstack-plan-eng-review": 156195,
"copilot/gstack-review": 125671,
"cursor/gstack-autoplan": 129246,
"cursor/gstack-design-consultation": 107190,
@@ -36,7 +36,7 @@
"cursor/gstack-land-and-deploy": 116613,
"cursor/gstack-plan-design-review": 138936,
"cursor/gstack-plan-devex-review": 134559,
"cursor/gstack-plan-eng-review": 154313,
"cursor/gstack-plan-eng-review": 154324,
"cursor/gstack-review": 142320,
"factory/gstack-autoplan": 131530,
"factory/gstack-codex": 100623,
@@ -46,34 +46,34 @@
"factory/gstack-office-hours": 101311,
"factory/gstack-plan-design-review": 141717,
"factory/gstack-plan-devex-review": 137928,
"factory/gstack-plan-eng-review": 157427,
"factory/gstack-plan-eng-review": 157438,
"factory/gstack-review": 146099,
"gbrain/gstack-autoplan": 129783,
"gbrain/gstack-design-review": 132810,
"gbrain/gstack-land-and-deploy": 117135,
"gbrain/gstack-plan-design-review": 127823,
"gbrain/gstack-plan-devex-review": 115097,
"gbrain/gstack-plan-eng-review": 137045,
"gbrain/gstack-plan-eng-review": 137056,
"hermes/gstack-autoplan": 129873,
"hermes/gstack-design-review": 132917,
"hermes/gstack-land-and-deploy": 117237,
"hermes/gstack-plan-design-review": 127932,
"hermes/gstack-plan-devex-review": 115183,
"hermes/gstack-plan-eng-review": 137130,
"hermes/gstack-plan-eng-review": 137141,
"kiro/gstack-autoplan": 129008,
"kiro/gstack-design-consultation": 107032,
"kiro/gstack-design-review": 142289,
"kiro/gstack-land-and-deploy": 116501,
"kiro/gstack-plan-design-review": 138776,
"kiro/gstack-plan-devex-review": 134399,
"kiro/gstack-plan-eng-review": 154163,
"kiro/gstack-plan-eng-review": 154174,
"kiro/gstack-review": 142132,
"openclaw/gstack-autoplan": 129488,
"openclaw/gstack-design-review": 131615,
"openclaw/gstack-land-and-deploy": 116725,
"openclaw/gstack-plan-design-review": 126674,
"openclaw/gstack-plan-devex-review": 113936,
"openclaw/gstack-plan-eng-review": 135442,
"openclaw/gstack-plan-eng-review": 135453,
"opencode/gstack-autoplan": 131608,
"opencode/gstack-design-consultation": 109325,
"opencode/gstack-design-review": 144673,
@@ -81,7 +81,7 @@
"opencode/gstack-office-hours": 100266,
"opencode/gstack-plan-design-review": 140706,
"opencode/gstack-plan-devex-review": 136780,
"opencode/gstack-plan-eng-review": 156065,
"opencode/gstack-plan-eng-review": 156076,
"opencode/gstack-review": 144555,
"slate/gstack-autoplan": 129127,
"slate/gstack-design-consultation": 107111,
@@ -89,7 +89,7 @@
"slate/gstack-land-and-deploy": 116557,
"slate/gstack-plan-design-review": 138856,
"slate/gstack-plan-devex-review": 134479,
"slate/gstack-plan-eng-review": 154238,
"slate/gstack-plan-eng-review": 154249,
"slate/gstack-review": 142226
}
}
+4 -4
View File
@@ -195,13 +195,13 @@ export const CARVE_GUARDS: Record<string, CarveGuard> = {
},
'plan-eng-review': {
skill: 'plan-eng-review',
expectedSections: ['design-twice.md', 'review-sections.md'],
expectedSections: ['review-sections.md'],
requiredReads: ['review-sections.md'],
scenario:
'Review the plan in PLAN.md. Accept the current scope. Run the full engineering review (architecture, code quality, tests, performance) and produce the review report.',
staticInvariants: {
mustStayInSkeleton: ['### Step 0: Scope Challenge'],
mustMoveToSection: ['### 1. Architecture review', '## Two shapes before one', '### The eight red flags'],
mustMoveToSection: ['### 1. Architecture review', '### Two shapes before one (design-twice)', '**The eight red flags.**'],
gateAfterStop: 'EXIT PLAN MODE GATE',
},
behavioral: 'plan',
@@ -212,7 +212,7 @@ export const CARVE_GUARDS: Record<string, CarveGuard> = {
// check grew every plan-review skeleton ~0.7KB. Measured values noted.
// #2499 project-scope MCP jq in the brain-sync block grew every tier-2+
// skeleton ~1.5KB (entry resolution emitted once per SKILL.md).
maxSkeletonBytes: 57_800, // Scoped reuse entry guidance; measured 57,549 bytes (2026-09-16). Shared rubric remains in the existing section. + pstack item 9 (Garry 2026-10-26 "do it"): the design-twice STOP pointer and its index row; measured 52,185 (2026-10-26), inside the cap.
maxSkeletonBytes: 57_800, // Scoped reuse entry guidance; measured 57,549 bytes (2026-09-16). Shared rubric remains in the existing section.
minUnionBytes: 99_800, // token-reduction Phases 1-2 (v1.69.x branch); measured union 110,910
mustContain: ['Architecture', 'Code Quality', 'Test', 'Performance', 'interface depth'],
// Cross-cutting preamble growth (v1.57.2.0 AUQ-failure prose fallback + the
@@ -223,7 +223,7 @@ export const CARVE_GUARDS: Record<string, CarveGuard> = {
// 1.08 → 1.10: the scope-gate exceptions block (+ its adversarial-review
// hardening: host-anchored mode signal, precedence, passing-mention
// guards) and the plan-mode preamble reword land the union at 1.092.
maxSizeRatio: 1.26, // pstack item 9 (Garry 2026-10-26 "do it"): the design-twice section (3.0 KB) joins the union; measured 154,988 / 124,597 = 1.2439 (2026-10-26). Earlier history: + clarity rules for saved decisions/setup gates + the Aside probe's failure reason; measured 1.1504. + test value bar and Tests to Retire in the lazy Test review section (~2.6KB); measured 1.168 + W1 guarded state-root resolution (`eval gstack-paths; : "${GSTACK_STATE_ROOT:?…}"`) in the Context Recovery preamble, the eureka log and each state-writing bash block; measured 1.173 (2026-09-30). + v1.91.12.0 merge of #2999 (headless rule: a disallowed question tool never qualifies) with #3002; measured 1.1741 (2026-10-01). + Oct 6 fix wave A3/CEO-12: free text reaches commands only through agent-written mktemp files (mktemp block, write rule, path rebuild and refusal at each posting, prompt and brief site); measured 146,905 / 124,597 = 1.1790 (2026-10-06). Combined Oct 6 wave head (A and B): measured 147,524 / 124,597 = 1.1840 (2026-10-06). + Oct 7 wave B3: the Codex probe runs as a command (select-model capture lines, check-sandbox/probe-model/run-with-timeout subcommands) instead of being sourced; measured 147,693 / 124,597 = 1.1854 (2026-10-07). + Oct 7 wave CEO-28/DX-11: review prompts ask for a severity per finding and design proposals use the proposal gate; measured 147,752 / 124,597 = 1.1858 (2026-10-07). + fix wave PR D: the prerequisite offer is skipped in spawned/headless sessions (#1958); measured 147,864 / 124,597 = 1.1867 (2026-10-07). + Oct 10 multi-agent wave PR D1 (reality rows): the Scope Challenge reality-rows block, the deep incident table (18 rows, each tied to the incident that earned it), the Completion summary line and the checklist row; measured 151,423 / 124,597 = 1.2153 (2026-10-10). + #280: the Design Doc Check finds the CEO plan (`gstack-ceo-plan-find`) and names it in the data rule, +325 bytes on main's 151,630; measured 151,955 / 124,597 = 1.2196 (2026-10-12). Fix wave PR 4 (owner-approved raise 1.2170 → 1.2196): #3182's timer-bounded native fallback (net −17 bytes) plus #280's cross-branch rule, offset by tightening the Design Doc Check; measured 151,950 / 124,597 = 1.2195 (2026-10-15).
maxSizeRatio: 1.2400, // pstack item 9 (Garry 2026-10-26 "do it"): the design-twice pass (two shapes, eight red flags, ~2.4 KB) joins Section 1 of the lazy review section; measured 154,366 / 124,597 = 1.2389 (2026-10-26). Earlier history: + clarity rules for saved decisions/setup gates + the Aside probe's failure reason; measured 1.1504. + test value bar and Tests to Retire in the lazy Test review section (~2.6KB); measured 1.168 + W1 guarded state-root resolution (`eval gstack-paths; : "${GSTACK_STATE_ROOT:?…}"`) in the Context Recovery preamble, the eureka log and each state-writing bash block; measured 1.173 (2026-09-30). + v1.91.12.0 merge of #2999 (headless rule: a disallowed question tool never qualifies) with #3002; measured 1.1741 (2026-10-01). + Oct 6 fix wave A3/CEO-12: free text reaches commands only through agent-written mktemp files (mktemp block, write rule, path rebuild and refusal at each posting, prompt and brief site); measured 146,905 / 124,597 = 1.1790 (2026-10-06). Combined Oct 6 wave head (A and B): measured 147,524 / 124,597 = 1.1840 (2026-10-06). + Oct 7 wave B3: the Codex probe runs as a command (select-model capture lines, check-sandbox/probe-model/run-with-timeout subcommands) instead of being sourced; measured 147,693 / 124,597 = 1.1854 (2026-10-07). + Oct 7 wave CEO-28/DX-11: review prompts ask for a severity per finding and design proposals use the proposal gate; measured 147,752 / 124,597 = 1.1858 (2026-10-07). + fix wave PR D: the prerequisite offer is skipped in spawned/headless sessions (#1958); measured 147,864 / 124,597 = 1.1867 (2026-10-07). + Oct 10 multi-agent wave PR D1 (reality rows): the Scope Challenge reality-rows block, the deep incident table (18 rows, each tied to the incident that earned it), the Completion summary line and the checklist row; measured 151,423 / 124,597 = 1.2153 (2026-10-10). + #280: the Design Doc Check finds the CEO plan (`gstack-ceo-plan-find`) and names it in the data rule, +325 bytes on main's 151,630; measured 151,955 / 124,597 = 1.2196 (2026-10-12). Fix wave PR 4 (owner-approved raise 1.2170 → 1.2196): #3182's timer-bounded native fallback (net −17 bytes) plus #280's cross-branch rule, offset by tightening the Design Doc Check; measured 151,950 / 124,597 = 1.2195 (2026-10-15).
},
'plan-design-review': {
skill: 'plan-design-review',
+1
View File
@@ -32,6 +32,7 @@ export const FREE_FIXTURES: Readonly<Record<string, readonly string[]>> = {
'test/fixtures/autoplan-with-result-au.json': ['test/autoplan-phase-observer.test.ts'],
'test/fixtures/browse-judge/**': ['test/workflow-judge-cache.test.ts'],
'test/fixtures/ceo-completion-handoff-m-call.json': ['test/plan-count-completion.test.ts'],
'test/fixtures/context-restore-transcript.jsonl': ['test/context-restore-transcripts.test.ts'],
'test/fixtures/ceo-completion-handoff-o-call.json': ['test/plan-count-completion.test.ts'],
'test/fixtures/ceo-completion-handoff-q-call.json': ['test/plan-count-completion.test.ts'],
'test/fixtures/ceo-count-ad-v2.json': ['test/ceo-count-ad-v2.test.ts'],
+42 -31
View File
@@ -1,6 +1,6 @@
/**
* pstack absorb (GSTA-116 plan, items 6 and 9): benchmark's vet-the-number
* section and plan-eng-review's design-twice section. Pins the carve shape
* section and plan-eng-review's design-twice pass. Pins the carve shape
* (manifest ids, STOP pointers, where each pointer sits) and the tokens each
* section must carry; prose is not pinned.
*/
@@ -50,38 +50,39 @@ describe('benchmark carve: vet the number', () => {
});
});
describe('plan-eng-review carve: two shapes before one', () => {
describe('plan-eng-review: two shapes before one inside Section 1 of the lazy review section', () => {
const skeleton = read('plan-eng-review/SKILL.md');
const section = read('plan-eng-review/sections/design-twice.md');
const manifest = JSON.parse(read('plan-eng-review/sections/manifest.json')) as { sections: Array<{ id: string; file: string; scope?: string; runner_only?: boolean }> };
const section = read('plan-eng-review/sections/review-sections.md');
const manifest = JSON.parse(read('plan-eng-review/sections/manifest.json')) as { sections: Array<{ id: string }> };
test('registered beside review-sections, pointed to before it, and visible to the autoplan runner', () => {
expect(manifest.sections.map(s => s.id)).toEqual(['review-sections', 'design-twice', 'checklist']);
const entry = manifest.sections.find(s => s.id === 'design-twice')!;
expect(entry.scope).toBe('always');
expect(entry.runner_only).toBeUndefined();
expect(CARVE_GUARDS['plan-eng-review']!.expectedSections).toEqual(['design-twice.md', 'review-sections.md']);
const designStop = skeleton.indexOf('sections/design-twice.md', skeleton.indexOf('> **STOP.**'));
const reviewStop = skeleton.indexOf('sections/review-sections.md', skeleton.indexOf('> **STOP.**'));
expect(designStop).toBeGreaterThan(0);
expect(designStop).toBeLessThan(reviewStop);
expect(skeleton.lastIndexOf('EXIT PLAN MODE GATE')).toBeGreaterThan(skeleton.lastIndexOf('> **STOP.**'));
test('the pass lives in review-sections.md between Sections 1 and 2, the skeleton and manifest are unchanged, and the checklist maps it', () => {
expect(manifest.sections.map(s => s.id)).toEqual(['review-sections', 'checklist']);
expect(CARVE_GUARDS['plan-eng-review']!.expectedSections).toEqual(['review-sections.md']);
expect(skeleton).not.toContain('design-twice');
expect(skeleton.match(/> \*\*STOP\.\*\*/g)).toHaveLength(1);
const one = section.indexOf('### 1. Architecture review');
const pass = section.indexOf('### Two shapes before one (design-twice)');
const two = section.indexOf('### 2. Code quality review');
expect(one).toBeGreaterThan(0);
expect(pass).toBeGreaterThan(one);
expect(two).toBeGreaterThan(pass);
expect(section.slice(pass, two)).toMatch(/only when the plan introduces a new module, service, package or\s+boundary/);
expect(read('plan-eng-review/sections/checklist.md')).toContain('Two shapes before one (design-twice)');
});
test('a second structurally distinct shape, interface depth, the agent-contributor assumption, and the eight red flags in order', () => {
expect(section).toContain('## Two shapes before one');
expect(section).toContain('### Ask for the second shape');
expect(section).toMatch(/require a second shape that is structurally\s+different/);
expect(section).toMatch(/A point fix inside the first shape is not a\s+second candidate\./);
expect(section).toContain('interface depth');
expect(section).toContain('A deep module is not a deep call chain');
expect(section).toMatch(/an agent that sees only the files it opened, copies the nearest example\s+and takes the shortest path that compiles/);
const pass = section.slice(section.indexOf('### Two shapes before one (design-twice)'), section.indexOf('### 2. Code quality review'));
expect(pass).toContain('**Ask for the second shape.**');
expect(pass).toMatch(/require a second\s+shape that is structurally different/);
expect(pass).toMatch(/A point fix inside\s+the first shape is not a second candidate\./);
expect(pass).toContain('interface depth');
expect(pass).toContain('A deep module is not a deep call chain');
expect(pass).toMatch(/an agent that sees only the files it opened,\s+copies the nearest example and takes the shortest path that compiles/);
const flags = ['**Shallow module.**', '**Information leakage.**', '**Temporal decomposition.**', '**Pass-through method.**', '**Split ownership.**', '**Two ways to do one task.**', '**Importable internals.**', '**Hand-synced list.**'];
let last = section.indexOf('### The eight red flags');
let last = pass.indexOf('**The eight red flags.**');
expect(last).toBeGreaterThan(0);
for (const f of flags) {
const at = section.indexOf(f);
const at = pass.indexOf(f);
expect(at, f).toBeGreaterThan(last);
last = at;
}
@@ -89,14 +90,24 @@ describe('plan-eng-review carve: two shapes before one', () => {
});
describe('every pstack-derived section carries its credit line', () => {
for (const rel of ['investigate/sections/blast-radius.md.tmpl', 'context-restore/sections/transcripts.md.tmpl', 'benchmark/sections/vet-the-number.md.tmpl', 'plan-eng-review/sections/design-twice.md.tmpl']) {
const credited = {
'investigate/sections/blast-radius.md.tmpl': 0,
'context-restore/sections/transcripts.md.tmpl': 0,
'benchmark/sections/vet-the-number.md.tmpl': 0,
// The design-twice pass lives inside an existing section; its credit sits on the line above its heading.
'plan-eng-review/sections/review-sections.md.tmpl': '### Two shapes before one (design-twice)',
} as const;
for (const [rel, where] of Object.entries(credited)) {
test(rel, () => {
const first = read(rel).split('\n')[0]!;
expect(first.startsWith('<!--')).toBe(true);
expect(first).toContain('pstack');
expect(first).toContain('MIT');
expect(first).toContain('rewritten');
expect(first).toContain('See NOTICE.md');
const lines = read(rel).split('\n');
const at = typeof where === 'number' ? where : lines.indexOf(where) - 1;
expect(at).toBeGreaterThanOrEqual(0);
const credit = lines[at]!;
expect(credit.startsWith('<!--')).toBe(true);
expect(credit).toContain('pstack');
expect(credit).toContain('MIT');
expect(credit).toContain('rewritten');
expect(credit).toContain('See NOTICE.md');
expect(read('NOTICE.md')).toContain(rel.replace('.tmpl', ''));
});
}