mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-08 17:58:13 +01:00
fix: bind Autoplan reviews to full ordered phase inputs
This commit is contained in:
1 parent
a2e59255ee
commit
2ab4912635
13 files changed
+365
-141
No files matched your search
+19
-11
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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.**
|
||||
|
||||
@@ -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.**
|
||||
|
||||
@@ -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.**
|
||||
|
||||
@@ -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.**
|
||||
|
||||
@@ -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.**
|
||||
|
||||
@@ -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.**
|
||||
|
||||
@@ -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.**
|
||||
|
||||
@@ -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.**
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user