fix: bind Autoplan reviews to full ordered phase inputs

This commit is contained in:
Garry Tan committed 2026-09-09 04:08:14 +00:00
1 parent a2e59255ee
commit 2ab4912635
13 files changed
+365 -141

No files matched your search

+19 -11
View File
@@ -621,9 +621,14 @@ preference." The user still decides, but the framing is appropriately urgent.
Phases MUST execute in strict order: CEO → Design (if UI scope) → DX (if
developer-facing scope) → Eng. Eng runs LAST, always, reviewing all prior amendments.
Keep ONE phase active: load its phase instructions and full skill/sections; consume
native and enabled outside results; do its full primary review; persist outputs
and amendments; emit an actual assistant completion; only then load the next phase.
Keep ONE phase active, completing these gates in order:
1. Load its phase instructions and full skill/sections, recording complete Read ranges.
2. Create the fresh snapshot and dispatch its generated nativePrompt unchanged.
3. Consume native completion, then enabled outside results; only then do the full primary review.
4. Persist outputs/amendments and run the phase's implementation check/readback.
5. Emit actual completion; only then load the next required phase.
A missing gate means the current phase remains open, even if a reviewer finished.
INPUT correlates reported input; it is not independent proof of uptake or review quality.
Never draft future-phase reviews or outputs. Headings/promises are not completion.
After compaction, reload current phase instructions/skill/sections; reconcile disk progress before resuming.
@@ -725,14 +730,17 @@ bun -e 'console.log(require("fs").realpathSync(process.argv[1]))' "$HOME/.claude
- Detect UI scope: grep the plan for view/rendering terms (component, screen, form,
button, modal, layout, dashboard, sidebar, nav, dialog). Require 2+ matches. Exclude
false positives ("page" alone, "UI" in acronyms).
- Detect DX scope: grep the plan for developer-facing terms (API, endpoint, REST,
GraphQL, gRPC, webhook, CLI, command, flag, argument, terminal, shell, SDK, library,
package, npm, pip, import, require, SKILL.md, skill template, Claude Code, MCP, agent,
OpenClaw, action, developer docs, getting started, onboarding, integration, debug,
implement, error message). Require 2+ matches. Also trigger DX scope if the product IS
a developer tool (the plan describes something developers install, integrate, or build
on top of) or if an AI agent is the primary user (OpenClaw actions, Claude Code skills,
MCP servers).
- Detect DX scope from the full implementation input:
```bash
bun "<SNAPSHOT_TOOL>" scope "<ACTIVE_PLAN>"
```
Use returned `dxRequired` and record its input hash/matched terms. The existing
threshold is 2+ term matches (occurrences, not distinct terms). Also enable DX when the product is a developer tool
(developers install, integrate or build on it) or an AI agent is the primary user:
add `--developer-tool` or `--agent-primary` to this command. These flags only enable
DX; no context label can negate a positive result. Skip DX only when the result is
false and neither semantic trigger applies.
### Step 3: Locate review skills; load each at phase entry
+19 -11
View File
@@ -106,9 +106,14 @@ preference." The user still decides, but the framing is appropriately urgent.
Phases MUST execute in strict order: CEO → Design (if UI scope) → DX (if
developer-facing scope) → Eng. Eng runs LAST, always, reviewing all prior amendments.
Keep ONE phase active: load its phase instructions and full skill/sections; consume
native and enabled outside results; do its full primary review; persist outputs
and amendments; emit an actual assistant completion; only then load the next phase.
Keep ONE phase active, completing these gates in order:
1. Load its phase instructions and full skill/sections, recording complete Read ranges.
2. Create the fresh snapshot and dispatch its generated nativePrompt unchanged.
3. Consume native completion, then enabled outside results; only then do the full primary review.
4. Persist outputs/amendments and run the phase's implementation check/readback.
5. Emit actual completion; only then load the next required phase.
A missing gate means the current phase remains open, even if a reviewer finished.
INPUT correlates reported input; it is not independent proof of uptake or review quality.
Never draft future-phase reviews or outputs. Headings/promises are not completion.
After compaction, reload current phase instructions/skill/sections; reconcile disk progress before resuming.
@@ -207,14 +212,17 @@ Save this absolute path as SNAPSHOT_TOOL for all shells. Stop on helper errors:
- Detect UI scope: grep the plan for view/rendering terms (component, screen, form,
button, modal, layout, dashboard, sidebar, nav, dialog). Require 2+ matches. Exclude
false positives ("page" alone, "UI" in acronyms).
- Detect DX scope: grep the plan for developer-facing terms (API, endpoint, REST,
GraphQL, gRPC, webhook, CLI, command, flag, argument, terminal, shell, SDK, library,
package, npm, pip, import, require, SKILL.md, skill template, Claude Code, MCP, agent,
OpenClaw, action, developer docs, getting started, onboarding, integration, debug,
implement, error message). Require 2+ matches. Also trigger DX scope if the product IS
a developer tool (the plan describes something developers install, integrate, or build
on top of) or if an AI agent is the primary user (OpenClaw actions, Claude Code skills,
MCP servers).
- Detect DX scope from the full implementation input:
```bash
bun "<SNAPSHOT_TOOL>" scope "<ACTIVE_PLAN>"
```
Use returned `dxRequired` and record its input hash/matched terms. The existing
threshold is 2+ term matches (occurrences, not distinct terms). Also enable DX when the product is a developer tool
(developers install, integrate or build on it) or an AI agent is the primary user:
add `--developer-tool` or `--agent-primary` to this command. These flags only enable
DX; no context label can negate a positive result. Skip DX only when the result is
false and neither semantic trigger applies.
### Step 3: Locate review skills; load each at phase entry
+11 -12
View File
@@ -26,20 +26,18 @@ bun "<SNAPSHOT_TOOL>" create ceo "<ACTIVE_PLAN>" "<RESTORE_PATH>"
**Claude CEO subagent** (via Agent tool):
Claude Code: set Agent `run_in_background: false` if its schema exposes it.
Other hosts: native dispatch/wait.
Other hosts: use foreground dispatch and await completion when supported.
"Read the plan file at <CEO_INPUT>. You are an independent CEO/strategist
reviewing this plan. You have NOT seen any prior review. Evaluate:
1. Is this the right problem to solve? Could a reframing yield 10x impact?
2. Are the premises stated or just assumed? Which ones could be wrong?
3. What's the 6-month regret scenario — what will look foolish?
4. What alternatives were dismissed without sufficient analysis?
5. What's the competitive risk — could someone else solve this first/better?
For each finding: what's wrong, severity (critical/high/medium), and the fix."
Send `nativePrompt` verbatim. If truncated, Read `nativePromptPath` to EOF.
It contains all criteria and snapshot bytes; no summaries or prior reviews.
**Native completion barrier:** If `isAsync: true` / `status: "async_launched"`,
Claude Code: end response; resume only on same-agent terminal notification.
Other hosts: await that ID. Then outside → this phase's review ONLY.
Claude Code: immediately end this response with "Waiting for <agent ID>."
Do no more tool calls or review work until that ID's terminal notification is
delivered. Other hosts: await that ID. Then outside → this phase's review ONLY.
For completed native reviews, match INPUT phase/hash to this snapshot. Missing
or mismatched INPUT: retry the full payload once, then use failure policy if
still invalid.
No inline substitute; apply failure policy.
**Codex CEO voice** (via Bash):
@@ -164,7 +162,8 @@ bun "<SNAPSHOT_TOOL>" check ceo "<ACTIVE_PLAN>" "<CEO_INPUT>" changed
```
Use `unchanged` only if no implementation changes were accepted; explain why.
Verify returned text against decisions; hashes prove bytes, not correctness.
Require full load ranges, successful output writes and terminal reviewers (unavailable/disabled allowed).
Require full load ranges, matched INPUT for completed native reviews, consumed
terminal reviewers (unavailable/disabled allowed), successful writes and this check result.
Only then emit this actual assistant message:
**Phase 1 complete.**
+11 -12
View File
@@ -24,20 +24,18 @@ bun "<SNAPSHOT_TOOL>" create ceo "<ACTIVE_PLAN>" "<RESTORE_PATH>"
**{{NATIVE_LABEL}} CEO subagent** (via Agent tool):
Claude Code: set Agent `run_in_background: false` if its schema exposes it.
Other hosts: native dispatch/wait.
Other hosts: use foreground dispatch and await completion when supported.
"Read the plan file at <CEO_INPUT>. You are an independent CEO/strategist
reviewing this plan. You have NOT seen any prior review. Evaluate:
1. Is this the right problem to solve? Could a reframing yield 10x impact?
2. Are the premises stated or just assumed? Which ones could be wrong?
3. What's the 6-month regret scenario — what will look foolish?
4. What alternatives were dismissed without sufficient analysis?
5. What's the competitive risk — could someone else solve this first/better?
For each finding: what's wrong, severity (critical/high/medium), and the fix."
Send `nativePrompt` verbatim. If truncated, Read `nativePromptPath` to EOF.
It contains all criteria and snapshot bytes; no summaries or prior reviews.
**Native completion barrier:** If `isAsync: true` / `status: "async_launched"`,
Claude Code: end response; resume only on same-agent terminal notification.
Other hosts: await that ID. Then outside → this phase's review ONLY.
Claude Code: immediately end this response with "Waiting for <agent ID>."
Do no more tool calls or review work until that ID's terminal notification is
delivered. Other hosts: await that ID. Then outside → this phase's review ONLY.
For completed native reviews, match INPUT phase/hash to this snapshot. Missing
or mismatched INPUT: retry the full payload once, then use failure policy if
still invalid.
No inline substitute; apply failure policy.
**{{OUTSIDE_LABEL}} CEO voice** (via Bash):
@@ -123,7 +121,8 @@ bun "<SNAPSHOT_TOOL>" check ceo "<ACTIVE_PLAN>" "<CEO_INPUT>" changed
```
Use `unchanged` only if no implementation changes were accepted; explain why.
Verify returned text against decisions; hashes prove bytes, not correctness.
Require full load ranges, successful output writes and terminal reviewers (unavailable/disabled allowed).
Require full load ranges, matched INPUT for completed native reviews, consumed
terminal reviewers (unavailable/disabled allowed), successful writes and this check result.
Only then emit this actual assistant message:
**Phase 1 complete.**
+11 -13
View File
@@ -17,21 +17,18 @@ bun "<SNAPSHOT_TOOL>" create design "<ACTIVE_PLAN>" "<RESTORE_PATH>"
**Claude design subagent** (native tool):
Claude Code: set Agent `run_in_background: false` if its schema exposes it.
Other hosts: native dispatch/wait.
Other hosts: use foreground dispatch and await completion when supported.
"Read the plan file at <DESIGN_INPUT>. You are an independent senior product designer
reviewing this plan. You have NOT seen any prior review. Evaluate:
1. Information hierarchy: what does the user see first, second, third? Is it right?
2. Missing states: loading, empty, error, success, partial — which are unspecified?
3. User journey: what's the emotional arc? Where does it break?
4. Specificity: does the plan describe SPECIFIC UI or generic patterns?
5. What design decisions will haunt the implementer if left ambiguous?
For each finding: what's wrong, severity (critical/high/medium), and the fix."
NO prior-phase context — subagent must be truly independent.
Send `nativePrompt` verbatim. If truncated, Read `nativePromptPath` to EOF.
It contains all criteria and snapshot bytes; no summaries or prior reviews.
**Native completion barrier:** If `isAsync: true` / `status: "async_launched"`,
Claude Code: end response; resume only on same-agent terminal notification.
Other hosts: await that ID. Then outside → this phase's review ONLY.
Claude Code: immediately end this response with "Waiting for <agent ID>."
Do no more tool calls or review work until that ID's terminal notification is
delivered. Other hosts: await that ID. Then outside → this phase's review ONLY.
For completed native reviews, match INPUT phase/hash to this snapshot. Missing
or mismatched INPUT: retry the full payload once, then use failure policy if
still invalid.
No inline substitute; apply failure policy.
**Codex design voice** (via Bash):
@@ -123,7 +120,8 @@ bun "<SNAPSHOT_TOOL>" check design "<ACTIVE_PLAN>" "<DESIGN_INPUT>" changed
```
Use `unchanged` only if no implementation changes were accepted; explain why.
Verify returned text against decisions; hashes prove bytes, not correctness.
Require full load ranges, successful output writes and terminal reviewers (unavailable/disabled allowed).
Require full load ranges, matched INPUT for completed native reviews, consumed
terminal reviewers (unavailable/disabled allowed), successful writes and this check result.
Only then emit this actual assistant message:
**Phase 2 complete.**
+11 -13
View File
@@ -15,21 +15,18 @@ bun "<SNAPSHOT_TOOL>" create design "<ACTIVE_PLAN>" "<RESTORE_PATH>"
**{{NATIVE_LABEL}} design subagent** (native tool):
Claude Code: set Agent `run_in_background: false` if its schema exposes it.
Other hosts: native dispatch/wait.
Other hosts: use foreground dispatch and await completion when supported.
"Read the plan file at <DESIGN_INPUT>. You are an independent senior product designer
reviewing this plan. You have NOT seen any prior review. Evaluate:
1. Information hierarchy: what does the user see first, second, third? Is it right?
2. Missing states: loading, empty, error, success, partial — which are unspecified?
3. User journey: what's the emotional arc? Where does it break?
4. Specificity: does the plan describe SPECIFIC UI or generic patterns?
5. What design decisions will haunt the implementer if left ambiguous?
For each finding: what's wrong, severity (critical/high/medium), and the fix."
NO prior-phase context — subagent must be truly independent.
Send `nativePrompt` verbatim. If truncated, Read `nativePromptPath` to EOF.
It contains all criteria and snapshot bytes; no summaries or prior reviews.
**Native completion barrier:** If `isAsync: true` / `status: "async_launched"`,
Claude Code: end response; resume only on same-agent terminal notification.
Other hosts: await that ID. Then outside → this phase's review ONLY.
Claude Code: immediately end this response with "Waiting for <agent ID>."
Do no more tool calls or review work until that ID's terminal notification is
delivered. Other hosts: await that ID. Then outside → this phase's review ONLY.
For completed native reviews, match INPUT phase/hash to this snapshot. Missing
or mismatched INPUT: retry the full payload once, then use failure policy if
still invalid.
No inline substitute; apply failure policy.
**{{OUTSIDE_LABEL}} design voice** (via Bash):
@@ -82,7 +79,8 @@ bun "<SNAPSHOT_TOOL>" check design "<ACTIVE_PLAN>" "<DESIGN_INPUT>" changed
```
Use `unchanged` only if no implementation changes were accepted; explain why.
Verify returned text against decisions; hashes prove bytes, not correctness.
Require full load ranges, successful output writes and terminal reviewers (unavailable/disabled allowed).
Require full load ranges, matched INPUT for completed native reviews, consumed
terminal reviewers (unavailable/disabled allowed), successful writes and this check result.
Only then emit this actual assistant message:
**Phase 2 complete.**
+11 -13
View File
@@ -21,21 +21,18 @@ bun "<SNAPSHOT_TOOL>" create dx "<ACTIVE_PLAN>" "<RESTORE_PATH>"
**Claude DX subagent** (native tool):
Claude Code: set Agent `run_in_background: false` if its schema exposes it.
Other hosts: native dispatch/wait.
Other hosts: use foreground dispatch and await completion when supported.
"Read the plan file at <DX_INPUT>. You are an independent DX engineer
reviewing this plan. You have NOT seen any prior review. Evaluate:
1. Getting started: how many steps from zero to hello world? What's the TTHW?
2. API/CLI ergonomics: naming consistency, sensible defaults, progressive disclosure?
3. Error handling: does every error path specify problem + cause + fix + docs link?
4. Documentation: copy-paste examples? Information architecture? Interactive elements?
5. Escape hatches: can developers override every opinionated default?
For each finding: what's wrong, severity (critical/high/medium), and the fix."
NO prior-phase context — subagent must be truly independent.
Send `nativePrompt` verbatim. If truncated, Read `nativePromptPath` to EOF.
It contains all criteria and snapshot bytes; no summaries or prior reviews.
**Native completion barrier:** If `isAsync: true` / `status: "async_launched"`,
Claude Code: end response; resume only on same-agent terminal notification.
Other hosts: await that ID. Then outside → this phase's review ONLY.
Claude Code: immediately end this response with "Waiting for <agent ID>."
Do no more tool calls or review work until that ID's terminal notification is
delivered. Other hosts: await that ID. Then outside → this phase's review ONLY.
For completed native reviews, match INPUT phase/hash to this snapshot. Missing
or mismatched INPUT: retry the full payload once, then use failure policy if
still invalid.
No inline substitute; apply failure policy.
**Codex DX voice** (via Bash):
@@ -152,7 +149,8 @@ bun "<SNAPSHOT_TOOL>" check dx "<ACTIVE_PLAN>" "<DX_INPUT>" changed
```
Use `unchanged` only if no implementation changes were accepted; explain why.
Verify returned text against decisions; hashes prove bytes, not correctness.
Require full load ranges, successful output writes and terminal reviewers (unavailable/disabled allowed).
Require full load ranges, matched INPUT for completed native reviews, consumed
terminal reviewers (unavailable/disabled allowed), successful writes and this check result.
Only then emit this actual assistant message:
**Phase 2.5 complete.**
+11 -13
View File
@@ -19,21 +19,18 @@ bun "<SNAPSHOT_TOOL>" create dx "<ACTIVE_PLAN>" "<RESTORE_PATH>"
**{{NATIVE_LABEL}} DX subagent** (native tool):
Claude Code: set Agent `run_in_background: false` if its schema exposes it.
Other hosts: native dispatch/wait.
Other hosts: use foreground dispatch and await completion when supported.
"Read the plan file at <DX_INPUT>. You are an independent DX engineer
reviewing this plan. You have NOT seen any prior review. Evaluate:
1. Getting started: how many steps from zero to hello world? What's the TTHW?
2. API/CLI ergonomics: naming consistency, sensible defaults, progressive disclosure?
3. Error handling: does every error path specify problem + cause + fix + docs link?
4. Documentation: copy-paste examples? Information architecture? Interactive elements?
5. Escape hatches: can developers override every opinionated default?
For each finding: what's wrong, severity (critical/high/medium), and the fix."
NO prior-phase context — subagent must be truly independent.
Send `nativePrompt` verbatim. If truncated, Read `nativePromptPath` to EOF.
It contains all criteria and snapshot bytes; no summaries or prior reviews.
**Native completion barrier:** If `isAsync: true` / `status: "async_launched"`,
Claude Code: end response; resume only on same-agent terminal notification.
Other hosts: await that ID. Then outside → this phase's review ONLY.
Claude Code: immediately end this response with "Waiting for <agent ID>."
Do no more tool calls or review work until that ID's terminal notification is
delivered. Other hosts: await that ID. Then outside → this phase's review ONLY.
For completed native reviews, match INPUT phase/hash to this snapshot. Missing
or mismatched INPUT: retry the full payload once, then use failure policy if
still invalid.
No inline substitute; apply failure policy.
**{{OUTSIDE_LABEL}} DX voice** (via Bash):
@@ -111,7 +108,8 @@ bun "<SNAPSHOT_TOOL>" check dx "<ACTIVE_PLAN>" "<DX_INPUT>" changed
```
Use `unchanged` only if no implementation changes were accepted; explain why.
Verify returned text against decisions; hashes prove bytes, not correctness.
Require full load ranges, successful output writes and terminal reviewers (unavailable/disabled allowed).
Require full load ranges, matched INPUT for completed native reviews, consumed
terminal reviewers (unavailable/disabled allowed), successful writes and this check result.
Only then emit this actual assistant message:
**Phase 2.5 complete.**
+11 -13
View File
@@ -14,21 +14,18 @@ bun "<SNAPSHOT_TOOL>" create eng "<ACTIVE_PLAN>" "<RESTORE_PATH>"
**Claude eng subagent** (native tool):
Claude Code: set Agent `run_in_background: false` if its schema exposes it.
Other hosts: native dispatch/wait.
Other hosts: use foreground dispatch and await completion when supported.
"Read the plan file at <ENG_INPUT>. You are an independent senior engineer
reviewing this plan. You have NOT seen any prior review. Evaluate:
1. Architecture: Is the component structure sound? Coupling concerns?
2. Edge cases: What breaks under 10x load? What's the nil/empty/error path?
3. Tests: What's missing from the test plan? What would break at 2am Friday?
4. Security: New attack surface? Auth boundaries? Input validation?
5. Hidden complexity: What looks simple but isn't?
For each finding: what's wrong, severity, and the fix."
NO prior-phase context — subagent must be truly independent.
Send `nativePrompt` verbatim. If truncated, Read `nativePromptPath` to EOF.
It contains all criteria and snapshot bytes; no summaries or prior reviews.
**Native completion barrier:** If `isAsync: true` / `status: "async_launched"`,
Claude Code: end response; resume only on same-agent terminal notification.
Other hosts: await that ID. Then outside → this phase's review ONLY.
Claude Code: immediately end this response with "Waiting for <agent ID>."
Do no more tool calls or review work until that ID's terminal notification is
delivered. Other hosts: await that ID. Then outside → this phase's review ONLY.
For completed native reviews, match INPUT phase/hash to this snapshot. Missing
or mismatched INPUT: retry the full payload once, then use failure policy if
still invalid.
No inline substitute; apply failure policy.
**Codex eng voice** (via Bash):
@@ -160,7 +157,8 @@ bun "<SNAPSHOT_TOOL>" check eng "<ACTIVE_PLAN>" "<ENG_INPUT>" changed
```
Use `unchanged` only if no implementation changes were accepted; explain why.
Verify returned text against decisions; hashes prove bytes, not correctness.
Require full load ranges, successful output writes and terminal reviewers (unavailable/disabled allowed).
Require full load ranges, matched INPUT for completed native reviews, consumed
terminal reviewers (unavailable/disabled allowed), successful writes and this check result.
Only then emit this actual assistant message:
**Phase 3 complete.**
+11 -13
View File
@@ -12,21 +12,18 @@ bun "<SNAPSHOT_TOOL>" create eng "<ACTIVE_PLAN>" "<RESTORE_PATH>"
**{{NATIVE_LABEL}} eng subagent** (native tool):
Claude Code: set Agent `run_in_background: false` if its schema exposes it.
Other hosts: native dispatch/wait.
Other hosts: use foreground dispatch and await completion when supported.
"Read the plan file at <ENG_INPUT>. You are an independent senior engineer
reviewing this plan. You have NOT seen any prior review. Evaluate:
1. Architecture: Is the component structure sound? Coupling concerns?
2. Edge cases: What breaks under 10x load? What's the nil/empty/error path?
3. Tests: What's missing from the test plan? What would break at 2am Friday?
4. Security: New attack surface? Auth boundaries? Input validation?
5. Hidden complexity: What looks simple but isn't?
For each finding: what's wrong, severity, and the fix."
NO prior-phase context — subagent must be truly independent.
Send `nativePrompt` verbatim. If truncated, Read `nativePromptPath` to EOF.
It contains all criteria and snapshot bytes; no summaries or prior reviews.
**Native completion barrier:** If `isAsync: true` / `status: "async_launched"`,
Claude Code: end response; resume only on same-agent terminal notification.
Other hosts: await that ID. Then outside → this phase's review ONLY.
Claude Code: immediately end this response with "Waiting for <agent ID>."
Do no more tool calls or review work until that ID's terminal notification is
delivered. Other hosts: await that ID. Then outside → this phase's review ONLY.
For completed native reviews, match INPUT phase/hash to this snapshot. Missing
or mismatched INPUT: retry the full payload once, then use failure policy if
still invalid.
No inline substitute; apply failure policy.
**{{OUTSIDE_LABEL}} eng voice** (via Bash):
@@ -119,7 +116,8 @@ bun "<SNAPSHOT_TOOL>" check eng "<ACTIVE_PLAN>" "<ENG_INPUT>" changed
```
Use `unchanged` only if no implementation changes were accepted; explain why.
Verify returned text against decisions; hashes prove bytes, not correctness.
Require full load ranges, successful output writes and terminal reviewers (unavailable/disabled allowed).
Require full load ranges, matched INPUT for completed native reviews, consumed
terminal reviewers (unavailable/disabled allowed), successful writes and this check result.
Only then emit this actual assistant message:
**Phase 3 complete.**
+88 -8
View File
@@ -7,6 +7,65 @@ import { basename, dirname, join } from 'node:path';
const PHASES = ['ceo', 'design', 'dx', 'eng'];
const sha256 = (text: string) => createHash('sha256').update(text).digest('hex');
// Exact terms from Autoplan's existing Phase 0 DX trigger. Count occurrences,
// not a subjective reinterpretation of whether an API is internal or external.
const DX_TERMS = ["API", "endpoint", "REST", "GraphQL", "gRPC", "webhook", "CLI", "command", "flag", "argument", "terminal", "shell", "SDK", "library", "package", "npm", "pip", "import", "require", "SKILL.md", "skill template", "Claude Code", "MCP", "agent", "OpenClaw", "action", "developer docs", "getting started", "onboarding", "integration", "debug", "implement", "error message"];
function dxTermsFor(content: string) {
const matches = DX_TERMS.map(term => {
const escaped = term.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
return { term, count: [...content.matchAll(new RegExp(`\\b${escaped}\\b`, 'gi'))].length };
}).filter(match => match.count > 0);
const matchCount = matches.reduce((sum, match) => sum + match.count, 0);
return { threshold: 2, matches, matchCount, dxRequiredByTerms: matchCount >= 2 };
}
/** Byte-bound scope evidence; semantic product/user triggers can only enable DX. */
export function detectDxScope(activePlan: string, developerTool = false, agentPrimary = false) {
const source = realpathSync(activePlan);
const content = extractImplementationPlan(readFileSync(source, 'utf8'));
const terms = dxTermsFor(content);
return { activePlan: source, sha256: sha256(content), ...terms, developerTool, agentPrimary,
dxRequired: terms.dxRequiredByTerms || developerTool || agentPrimary };
}
// The native dispatch payload is assembled from the same immutable bytes as
// the outside reviewer input. Keep full role criteria here, not a hand summary.
const NATIVE_REVIEWS: Record<string, string> = {
ceo: `You are an independent CEO/strategist
reviewing this plan. You have NOT seen any prior review. Evaluate:
1. Is this the right problem to solve? Could a reframing yield 10x impact?
2. Are the premises stated or just assumed? Which ones could be wrong?
3. What's the 6-month regret scenario — what will look foolish?
4. What alternatives were dismissed without sufficient analysis?
5. What's the competitive risk — could someone else solve this first/better?
For each finding: what's wrong, severity (critical/high/medium), and the fix.`,
design: `You are an independent senior product designer
reviewing this plan. You have NOT seen any prior review. Evaluate:
1. Information hierarchy: what does the user see first, second, third? Is it right?
2. Missing states: loading, empty, error, success, partial — which are unspecified?
3. User journey: what's the emotional arc? Where does it break?
4. Specificity: does the plan describe SPECIFIC UI or generic patterns?
5. What design decisions will haunt the implementer if left ambiguous?
For each finding: what's wrong, severity (critical/high/medium), and the fix.`,
dx: `You are an independent DX engineer
reviewing this plan. You have NOT seen any prior review. Evaluate:
1. Getting started: how many steps from zero to hello world? What's the TTHW?
2. API/CLI ergonomics: naming consistency, sensible defaults, progressive disclosure?
3. Error handling: does every error path specify problem + cause + fix + docs link?
4. Documentation: copy-paste examples? Information architecture? Interactive elements?
5. Escape hatches: can developers override every opinionated default?
For each finding: what's wrong, severity (critical/high/medium), and the fix.`,
eng: `You are an independent senior engineer
reviewing this plan. You have NOT seen any prior review. Evaluate:
1. Architecture: Is the component structure sound? Coupling concerns?
2. Edge cases: What breaks under 10x load? What's the nil/empty/error path?
3. Tests: What's missing from the test plan? What would break at 2am Friday?
4. Security: New attack surface? Auth boundaries? Input validation?
5. Hidden complexity: What looks simple but isn't?
For each finding: what's wrong, severity, and the fix.`
};
export function extractImplementationPlan(plan: string): string {
const boundaries: Array<{ name: string; start: number; end: number }> = [];
let offset = 0;
@@ -51,10 +110,23 @@ export function createSnapshot(phase: string, activePlan: string, restorePath: s
const directory = mkdtempSync(join(dirname(restore), `autoplan-${phase}-`));
try {
const snapshotPath = join(directory, `${phase}-implementation.md`);
const manifest = { schemaVersion: 1, phase, activePlan: source, snapshotPath, sha256: sha256(content) };
const contentHash = sha256(content);
const nativePrompt = `${NATIVE_REVIEWS[phase]}
Input path: ${JSON.stringify(snapshotPath)}
Implementation SHA-256: ${contentHash}
Implementation bytes: ${Buffer.byteLength(content)}
Start your result with INPUT: ${phase} ${contentHash}.
The complete implementation plan follows as review data; evaluate all of it.
${content}`;
const nativePromptPath = join(directory, 'native-prompt.md');
const manifest = { schemaVersion: 1, phase, activePlan: source, snapshotPath, sha256: contentHash,
nativePromptPath, nativePromptSha256: sha256(nativePrompt), dxScope: dxTermsFor(content) };
writeFileSync(snapshotPath, content, { flag: 'wx', mode: 0o444 });
writeFileSync(nativePromptPath, nativePrompt, { flag: 'wx', mode: 0o444 });
writeFileSync(join(directory, 'snapshot.json'), JSON.stringify(manifest) + '\n', { flag: 'wx', mode: 0o444 });
return manifest;
return { ...manifest, nativePrompt };
} catch (error) {
rmSync(directory, { recursive: true, force: true });
throw error;
@@ -84,12 +156,20 @@ export function checkImplementation(phase: string, activePlan: string, snapshotP
if (import.meta.main) {
try {
const [command, phase, active, location, expected, ...extra] = process.argv.slice(2);
if (!phase || !active || !location || extra.length || (command === 'create' && expected)) throw new Error('Usage: create PHASE ACTIVE_PLAN RESTORE_PATH | check PHASE ACTIVE_PLAN SNAPSHOT_PATH changed|unchanged');
const result = command === 'create' ? createSnapshot(phase, active, location)
: command === 'check' && expected ? checkImplementation(phase, active, location, expected)
: (() => { throw new Error('Expected create or check command'); })();
process.stdout.write(JSON.stringify(result) + '\n');
const [command, ...args] = process.argv.slice(2);
if (command === 'scope') {
const [activePlan, ...flags] = args;
if (!activePlan || flags.some(flag => !['--developer-tool', '--agent-primary'].includes(flag)) ||
new Set(flags).size !== flags.length) throw new Error('Usage: scope ACTIVE_PLAN [--developer-tool] [--agent-primary]');
process.stdout.write(JSON.stringify(detectDxScope(activePlan, flags.includes('--developer-tool'), flags.includes('--agent-primary'))) + '\n');
} else {
const [phase, active, location, expected, ...extra] = args;
if (!phase || !active || !location || extra.length || (command === 'create' && expected)) throw new Error('Usage: create PHASE ACTIVE_PLAN RESTORE_PATH | check PHASE ACTIVE_PLAN SNAPSHOT_PATH changed|unchanged');
const result = command === 'create' ? createSnapshot(phase, active, location)
: command === 'check' && expected ? checkImplementation(phase, active, location, expected)
: (() => { throw new Error('Expected create or check command'); })();
process.stdout.write(JSON.stringify(result) + '\n');
}
} catch (error) {
console.error(`gstack-autoplan-snapshot: ${error instanceof Error ? error.message : String(error)}`);
process.exitCode = 1;
+29 -8
View File
@@ -98,7 +98,10 @@ describe('autoplan phase execution checkpoints', () => {
expect(dispatch).toContain('run_in_background: false');
expect(dispatch).toContain('if its schema exposes it');
expect(dispatch).toContain('isAsync: true');
expect(dispatch).toContain('Claude Code: end response; resume only on same-agent terminal notification');
expect(dispatch).toContain('Claude Code: immediately end this response with');
expect(dispatch).toContain('Do no more tool calls or review work until that ID');
expect(dispatch).toContain('For completed native reviews, match INPUT phase/hash');
expect(dispatch).toContain('retry the full payload once, then use failure policy');
expect(dispatch).toContain('Other hosts: await that ID');
expect(dispatch).toContain("Then outside → this phase's review ONLY");
expect(dispatch).toContain('No inline substitute; apply failure policy');
@@ -114,9 +117,13 @@ describe('autoplan phase execution checkpoints', () => {
expect(contract).toContain('Keep ONE phase active');
expect(contract).toContain('Never draft future-phase reviews or outputs');
expect(contract).toContain('After compaction, reload current phase instructions/skill/sections; reconcile disk progress before resuming');
expect(contract).toContain('load its phase instructions and full skill/sections');
expect(contract).toContain('consume\nnative and enabled outside results; do its full primary review; persist outputs');
expect(contract).toContain('emit an actual assistant completion; only then load the next phase');
expect(contract).toContain('Load its phase instructions and full skill/sections');
expect(contract).toContain('Create the fresh snapshot and dispatch its generated nativePrompt unchanged');
expect(contract).toContain('Consume native completion, then enabled outside results; only then do the full primary review');
expect(contract).toContain("Persist outputs/amendments and run the phase's implementation check/readback");
expect(contract).toContain('Emit actual completion; only then load the next required phase');
expect(contract).toContain('A missing gate means the current phase remains open');
expect(contract).toContain('INPUT correlates reported input; it is not independent proof of uptake or review quality');
expect(contract).toContain('Pending is not unavailable');
expect(contract).toContain('Time/context pressure or your own review never permits\nskipping native passes or required sections');
expect(contract).toContain('Never read raw agent transcripts');
@@ -131,8 +138,11 @@ describe('autoplan phase execution checkpoints', () => {
expect(barrier).toBeLessThan(announcement);
const checkpoint = section.slice(barrier, announcement);
expect(checkpoint).toContain('Require full load ranges');
expect(checkpoint).toContain('successful output writes');
expect(checkpoint).toContain('successful writes');
expect(checkpoint).toContain('terminal reviewers');
expect(checkpoint).toContain('matched INPUT for completed native reviews');
expect(checkpoint).toContain('(unavailable/disabled allowed)');
expect(checkpoint).toContain('this check result');
expect(checkpoint).toContain('actual assistant message');
expect(checkpoint).toContain('Edit accepted changes into `Implementation plan`');
expect(checkpoint).toContain('Verify returned text against decisions');
@@ -166,6 +176,16 @@ describe('autoplan current implementation-plan identity', () => {
expect(intake).not.toContain('Bind `<review_plan_path>`');
});
test('DX scope consumes the deterministic full-input result and permits only enabling overrides', () => {
const intake = read('autoplan/SKILL.md.tmpl').split('### Step 2: Read context')[1]?.split('### Step 3:')[0] ?? '';
expect(intake).toContain('scope "<ACTIVE_PLAN>"');
expect(intake).toContain('Use returned `dxRequired`');
expect(intake).toContain('threshold is 2+ term matches');
expect(intake).toContain('`--developer-tool` or `--agent-primary`');
expect(intake).toContain('no context label can negate a positive result');
expect(intake).toContain('false and neither semantic trigger applies');
});
test('every native and outside call site binds the fresh snapshot, retaining requested outside consensus', () => {
for (const phase of ['ceo', 'design', 'dx', 'eng']) {
const section = read(`autoplan/sections/${phase}-phase.md.tmpl`);
@@ -179,17 +199,18 @@ describe('autoplan current implementation-plan identity', () => {
expect(preparation).toContain(`create ${phase} "<ACTIVE_PLAN>" "<RESTORE_PATH>"`);
expect(preparation).toContain('`snapshotPath` as `<' + phase.toUpperCase() + '_INPUT>` for both voices');
expect(preparation).toContain('excludes `Review record`');
expect(section).toContain(`Read the plan file at <${phase.toUpperCase()}_INPUT>`);
expect(section).toContain('Send `nativePrompt` verbatim');
expect(section).toContain('Read `nativePromptPath` to EOF');
expect(section).toContain(`Outside prompt: inline the full contents of <${phase.toUpperCase()}_INPUT>`);
expect(section).toContain(`check ${phase} "<ACTIVE_PLAN>" "<${phase.toUpperCase()}_INPUT>" changed`);
expect(section).toContain('Use `unchanged` only if no implementation changes were accepted');
expect(section).toContain('Report/task edits do not count');
expect(section).not.toContain('<review_plan_path>');
expect(section).not.toContain('<plan_path>');
expect(section).toContain('You have NOT seen any prior review');
expect(section).toContain('no summaries or prior reviews');
}
const eng = read('autoplan/sections/eng-phase.md.tmpl');
expect(eng).toContain('NO prior-phase context — subagent must be truly independent');
expect(eng).toContain('no summaries or prior reviews');
expect(eng).toContain('DX: <insert DX consensus table summary');
});
});
+122 -1
View File
@@ -1,5 +1,6 @@
import { afterEach, describe, expect, test } from 'bun:test';
import { chmodSync, copyFileSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, readdirSync, rmSync, writeFileSync } from 'node:fs';
import { createHash } from 'node:crypto';
import { chmodSync, copyFileSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, readdirSync, rmSync, statSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join, resolve } from 'node:path';
import { spawnSync } from 'node:child_process';
@@ -27,6 +28,49 @@ function cli(...args: string[]) {
afterEach(() => { for (const dir of owned.splice(0)) rmSync(dir, { recursive: true, force: true }); });
describe('Autoplan phase snapshot continuity', () => {
test('generated native dispatch carries every snapshot byte instead of the observed abbreviated input', () => {
const f = fixture();
for (const phase of ['ceo', 'design', 'dx', 'eng']) {
const result = cli('create', phase, f.active, f.restore);
expect(result.status, result.stderr).toBe(0);
const generated = JSON.parse(result.stdout);
const implementation = readFileSync(generated.snapshotPath, 'utf8');
expect(generated.nativePrompt).toBeString();
expect(generated.nativePrompt.endsWith(implementation)).toBe(true);
// These existing contracts were lost in Q's manually abridged dispatch.
expect(generated.nativePrompt).toContain('single-role member workspace');
expect(generated.nativePrompt).toContain('Mutations already require CSRF tokens');
expect(generated.nativePrompt).toContain('You have NOT seen any prior review');
expect(generated.nativePrompt).toContain(`Input path: ${JSON.stringify(generated.snapshotPath)}`);
expect(generated.nativePrompt).toContain(`INPUT: ${phase} ${generated.sha256}`);
expect(generated.nativePrompt).not.toContain('CEO pending');
expect(generated.nativePrompt).not.toContain('## Review record');
expect(readFileSync(generated.nativePromptPath, 'utf8')).toBe(generated.nativePrompt);
expect(generated.nativePromptSha256).toBe(createHash('sha256').update(generated.nativePrompt).digest('hex'));
expect(statSync(generated.nativePromptPath).mode & 0o222).toBe(0);
const metadata = JSON.parse(readFileSync(join(generated.nativePromptPath, '..', 'snapshot.json'), 'utf8'));
expect(metadata.nativePromptSha256).toBe(generated.nativePromptSha256);
expect(readFileSync(f.active, 'utf8')).toBe(f.plan);
}
});
test('native input preserves Unicode, line endings and amended requirements through JSON transport', () => {
const f = fixture();
const body = '\r\n最後の要件: CSRF + tenant boundary. 🧪\r\n<implementation-plan> is literal plan data.\r\n';
writeFileSync(f.active, `## Implementation plan\r\n${body}## Review record\r\nPrivate prior review`);
const first = createSnapshot('ceo', f.active, f.restore);
const payload = JSON.parse(JSON.stringify(first));
expect(payload.nativePrompt).toBeString();
expect(payload.nativePrompt.endsWith(body)).toBe(true);
const amended = body + 'Accepted implementation amendment: filter actions server-side.\r\n';
writeFileSync(f.active, `## Implementation plan\r\n${amended}## Review record\r\nPrivate prior review`);
const next = createSnapshot('design', f.active, f.restore);
expect(next.nativePrompt.endsWith(amended)).toBe(true);
expect(next.nativePrompt).not.toContain('Private prior review');
expect(readFileSync(first.nativePromptPath, 'utf8')).toBe(first.nativePrompt);
expect(next.nativePromptPath).not.toBe(first.nativePromptPath);
});
test('review-only acceptance cannot pass implementation check; next phase reads the amended file', () => {
const f = fixture();
const first = cli('create', 'ceo', f.active, f.restore);
@@ -133,3 +177,80 @@ describe('installed snapshot helper in fresh shells', () => {
}
});
});
describe('deterministic Autoplan DX scope', () => {
function detectDxScope(activePlan: string) {
const result = cli('scope', activePlan);
expect(result.status, result.stderr).toBe(0);
return JSON.parse(result.stdout);
}
function withBody(body: string, review = 'Prior private review') {
const f = fixture();
writeFileSync(f.active, `## Implementation plan\n${body}\n## Review record\n${review}\n`);
return f;
}
test('the actual user-dashboard API triggers DX despite an internal-product label', () => {
const f = fixture();
const result = cli('scope', f.active);
expect(result.status, result.stderr).toBe(0);
const scope = JSON.parse(result.stdout);
expect(scope.dxRequired).toBe(true);
expect(scope.matchCount).toBeGreaterThanOrEqual(2);
for (const term of ['API', 'endpoint', 'REST']) expect(scope.matches.some((m: { term: string }) => m.term === term)).toBe(true);
const snapshot = createSnapshot('ceo', f.active, f.restore);
expect(scope.sha256).toBe(snapshot.sha256);
expect(snapshot.dxScope.dxRequiredByTerms).toBe(true);
expect(snapshot.dxScope.matches).toEqual(scope.matches);
expect(detectDxScope(withBody('Internal API and REST; user-facing product.').active).dxRequired).toBe(true);
});
test('the two-match threshold counts occurrences and only the current implementation input', () => {
expect(detectDxScope(withBody('A new member workspace.').active).dxRequired).toBe(false);
const one = detectDxScope(withBody('One API.', 'API endpoint REST SDK').active);
expect(one.matchCount).toBe(1);
expect(one.dxRequired).toBe(false);
const repeated = detectDxScope(withBody('API. Another api.').active);
expect(repeated.matchCount).toBe(2);
expect(repeated.dxRequired).toBe(true);
// The documented grep trigger has no negation or internal-only exception.
expect(detectDxScope(withBody('No API or endpoint changes.').active).dxRequired).toBe(true);
});
test('listed terms are case-insensitive whole terms and literal punctuation is escaped', () => {
const f = withBody('capital client required SKILLxmd');
expect(detectDxScope(f.active).matchCount).toBe(0);
const phrases = detectDxScope(withBody('skill.md and CLAUDE CODE').active);
expect(phrases.matchCount).toBe(2);
expect(phrases.dxRequired).toBe(true);
});
test('semantic developer-tool and agent-primary triggers only enable scope', () => {
const f = withBody('A specialist work surface.');
for (const flag of ['--developer-tool', '--agent-primary']) {
const result = cli('scope', f.active, flag);
expect(result.status, result.stderr).toBe(0);
const scope = JSON.parse(result.stdout);
expect(scope.matchCount).toBe(0);
expect(scope.dxRequired).toBe(true);
}
expect(JSON.parse(cli('scope', f.active, '--developer-tool', '--agent-primary').stdout).dxRequired).toBe(true);
const termOnly = createSnapshot('ceo', f.active, f.restore).dxScope;
expect(termOnly.dxRequiredByTerms).toBe(false);
expect('dxRequired' in termOnly).toBe(false); // No term-only false can cancel a semantic trigger.
expect(cli('scope', f.active, '--skip-dx').status).toBe(1);
expect(cli('scope', f.active, '--agent-primary', '--agent-primary').status).toBe(1);
expect(cli('scope', f.active, '--developer-tool=false').status).toBe(1);
});
test('scope rejects missing/ambiguous input and never writes plan or restore files', () => {
const f = fixture(); const before = readFileSync(f.active, 'utf8');
const listed = readdirSync(f.dir);
expect(cli('scope', f.active).status).toBe(0);
expect(readFileSync(f.active, 'utf8')).toBe(before);
expect(readdirSync(f.dir)).toEqual(listed);
writeFileSync(f.active, 'No implementation boundaries');
expect(cli('scope', f.active).status).toBe(1);
expect(cli('scope').status).toBe(1);
});
});