prizmkit 1.1.114 → 1.1.115
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundled/VERSION.json +3 -3
- package/bundled/dev-pipeline/.env.example +0 -1
- package/bundled/dev-pipeline/README.md +4 -6
- package/bundled/dev-pipeline/SCHEMA_ANALYSIS.md +40 -518
- package/bundled/dev-pipeline/assets/prizm-dev-team-integration.md +27 -99
- package/bundled/dev-pipeline/prizmkit_runtime/checkpoint_state.py +283 -0
- package/bundled/dev-pipeline/prizmkit_runtime/daemon.py +3 -13
- package/bundled/dev-pipeline/prizmkit_runtime/heartbeat.py +0 -1
- package/bundled/dev-pipeline/prizmkit_runtime/runner_classification.py +25 -31
- package/bundled/dev-pipeline/prizmkit_runtime/runner_models.py +0 -8
- package/bundled/dev-pipeline/prizmkit_runtime/runner_prompts.py +0 -3
- package/bundled/dev-pipeline/prizmkit_runtime/runners.py +13 -7
- package/bundled/dev-pipeline/prizmkit_runtime/sessions.py +13 -1
- package/bundled/dev-pipeline/scripts/continuation.py +8 -40
- package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +76 -261
- package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +16 -35
- package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +15 -34
- package/bundled/dev-pipeline/scripts/init-bugfix-pipeline.py +6 -0
- package/bundled/dev-pipeline/scripts/init-pipeline.py +6 -0
- package/bundled/dev-pipeline/scripts/init-refactor-pipeline.py +6 -0
- package/bundled/dev-pipeline/scripts/parse-stream-progress.py +1 -1
- package/bundled/dev-pipeline/scripts/prompt_framework.py +114 -63
- package/bundled/dev-pipeline/scripts/update-bug-status.py +3 -7
- package/bundled/dev-pipeline/scripts/update-checkpoint.py +54 -22
- package/bundled/dev-pipeline/scripts/update-feature-status.py +3 -7
- package/bundled/dev-pipeline/scripts/update-refactor-status.py +3 -7
- package/bundled/dev-pipeline/scripts/utils.py +6 -37
- package/bundled/dev-pipeline/templates/bootstrap-prompt.md +1 -1
- package/bundled/dev-pipeline/templates/bootstrap-tier1.md +1 -1
- package/bundled/dev-pipeline/templates/bootstrap-tier2.md +9 -91
- package/bundled/dev-pipeline/templates/bootstrap-tier3.md +9 -66
- package/bundled/dev-pipeline/templates/bug-fix-list-schema.json +10 -16
- package/bundled/dev-pipeline/templates/feature-list-schema.json +32 -17
- package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +0 -16
- package/bundled/dev-pipeline/templates/refactor-list-schema.json +10 -16
- package/bundled/dev-pipeline/templates/sections/bugfix-session-context.md +1 -1
- package/bundled/dev-pipeline/templates/sections/context-budget-rules.md +1 -1
- package/bundled/dev-pipeline/templates/sections/critical-paths-agent.md +0 -1
- package/bundled/dev-pipeline/templates/sections/critical-paths-full.md +0 -1
- package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +1 -1
- package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +1 -1
- package/bundled/dev-pipeline/templates/sections/refactor-session-context.md +1 -1
- package/bundled/dev-pipeline/tests/conftest.py +1 -0
- package/bundled/dev-pipeline/tests/test_checkpoint_state.py +164 -0
- package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +48 -76
- package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +25 -3
- package/bundled/dev-pipeline/tests/test_generate_refactor_prompt.py +25 -5
- package/bundled/dev-pipeline/tests/test_python_runner_parity.py +128 -10
- package/bundled/dev-pipeline/tests/test_unified_cli.py +40 -9
- package/bundled/skills/_metadata.json +1 -1
- package/bundled/skills/bug-planner/SKILL.md +5 -4
- package/bundled/skills/bug-planner/references/verification.md +29 -0
- package/bundled/skills/bug-planner/scripts/validate-bug-list.py +8 -0
- package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +2 -2
- package/bundled/skills/bugfix-pipeline-launcher/references/configuration.md +1 -6
- package/bundled/skills/feature-pipeline-launcher/SKILL.md +6 -12
- package/bundled/skills/feature-pipeline-launcher/references/configuration.md +0 -1
- package/bundled/skills/feature-planner/SKILL.md +13 -12
- package/bundled/skills/feature-planner/assets/planning-guide.md +2 -2
- package/bundled/skills/feature-planner/scripts/validate-and-generate.py +8 -11
- package/bundled/skills/prizmkit-plan/SKILL.md +15 -1
- package/bundled/skills/prizmkit-plan/references/review-plan-spec-loop.md +101 -0
- package/bundled/skills/refactor-pipeline-launcher/SKILL.md +5 -5
- package/bundled/skills/refactor-pipeline-launcher/references/configuration.md +2 -7
- package/bundled/skills/refactor-planner/SKILL.md +10 -8
- package/bundled/skills/refactor-planner/scripts/validate-and-generate-refactor.py +9 -0
- package/bundled/team/prizm-dev-team.json +2 -9
- package/package.json +1 -1
- package/bundled/agents/prizm-dev-team-critic.md +0 -179
- package/bundled/dev-pipeline/templates/agent-prompts/critic-plan-challenge.md +0 -8
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-critic.md +0 -22
- package/bundled/dev-pipeline/templates/sections/phase-critic-plan-full.md +0 -61
- package/bundled/dev-pipeline/templates/sections/phase-critic-plan.md +0 -38
- package/bundled/dev-pipeline/templates/sections/refactor-phase-critic.md +0 -22
- package/bundled/skills/bug-planner/references/critic-and-verification.md +0 -44
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"high",
|
|
76
76
|
"critical"
|
|
77
77
|
],
|
|
78
|
-
"description": "Estimated implementation complexity. Determines pipeline execution tier: low/medium → lite (single agent), high → standard (orchestrator +
|
|
78
|
+
"description": "Estimated implementation complexity. Determines pipeline execution tier: low/medium → lite (single agent), high → standard (orchestrator + reviewer), critical → full (orchestrator + stronger guardrails)."
|
|
79
79
|
},
|
|
80
80
|
"dependencies": {
|
|
81
81
|
"type": "array",
|
|
@@ -145,19 +145,6 @@
|
|
|
145
145
|
"type": "string",
|
|
146
146
|
"description": "AI model ID for this feature. Overrides $MODEL env var."
|
|
147
147
|
},
|
|
148
|
-
"critic": {
|
|
149
|
-
"type": "boolean",
|
|
150
|
-
"description": "Enable adversarial plan challenge before implementation. Default: false.",
|
|
151
|
-
"default": false
|
|
152
|
-
},
|
|
153
|
-
"critic_count": {
|
|
154
|
-
"type": "integer",
|
|
155
|
-
"description": "Number of parallel critic agents. 1 = single critic, 3 = multi-critic voting. Default: 1.",
|
|
156
|
-
"enum": [
|
|
157
|
-
1,
|
|
158
|
-
3
|
|
159
|
-
]
|
|
160
|
-
},
|
|
161
148
|
"completion_notes": {
|
|
162
149
|
"type": "array",
|
|
163
150
|
"items": {
|
|
@@ -167,7 +154,9 @@
|
|
|
167
154
|
},
|
|
168
155
|
"user_context": {
|
|
169
156
|
"type": "array",
|
|
170
|
-
"items": {
|
|
157
|
+
"items": {
|
|
158
|
+
"type": "string"
|
|
159
|
+
},
|
|
171
160
|
"description": "User-provided supplementary materials, preserved verbatim. Each entry is either inline content/rules (stored as-is) or a file reference (e.g. 'src/auth/login.ts:42-78', 'src/utils/ — focus on validation logic')."
|
|
172
161
|
},
|
|
173
162
|
"browser_interaction": {
|
|
@@ -176,7 +165,11 @@
|
|
|
176
165
|
"properties": {
|
|
177
166
|
"tool": {
|
|
178
167
|
"type": "string",
|
|
179
|
-
"enum": [
|
|
168
|
+
"enum": [
|
|
169
|
+
"playwright-cli",
|
|
170
|
+
"opencli",
|
|
171
|
+
"auto"
|
|
172
|
+
],
|
|
180
173
|
"default": "auto",
|
|
181
174
|
"description": "Browser tool to use. 'auto' (default) = AI chooses at runtime. 'playwright-cli' = local dev server verification in isolated browser. 'opencli' = reuses Chrome logged-in session, ideal for verifying third-party integrations or OAuth flows."
|
|
182
175
|
},
|
|
@@ -188,8 +181,30 @@
|
|
|
188
181
|
}
|
|
189
182
|
}
|
|
190
183
|
}
|
|
184
|
+
},
|
|
185
|
+
"testing": {
|
|
186
|
+
"type": "object",
|
|
187
|
+
"description": "Testing expectations for this feature. Used by planning and scoped test gates.",
|
|
188
|
+
"properties": {
|
|
189
|
+
"required": {
|
|
190
|
+
"type": "boolean"
|
|
191
|
+
},
|
|
192
|
+
"coverage_target": {
|
|
193
|
+
"type": "integer"
|
|
194
|
+
},
|
|
195
|
+
"strategy": {
|
|
196
|
+
"type": "string"
|
|
197
|
+
},
|
|
198
|
+
"focus": {
|
|
199
|
+
"type": "array",
|
|
200
|
+
"items": {
|
|
201
|
+
"type": "string"
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
191
205
|
}
|
|
192
|
-
}
|
|
206
|
+
},
|
|
207
|
+
"additionalProperties": false
|
|
193
208
|
}
|
|
194
209
|
},
|
|
195
210
|
"global_context": {
|
|
@@ -118,22 +118,6 @@ If `DEV_PORT` is unknown, discover it from project config; do not guess port 300
|
|
|
118
118
|
|
|
119
119
|
---
|
|
120
120
|
|
|
121
|
-
{{IF_CRITIC_ENABLED}}
|
|
122
|
-
### Phase 2: Critic — Behavior Preservation Review
|
|
123
|
-
|
|
124
|
-
Challenge the plan before implementation. Focus on:
|
|
125
|
-
- behavior preservation gaps;
|
|
126
|
-
- unsafe task ordering;
|
|
127
|
-
- missing rollback strategy;
|
|
128
|
-
- insufficient test evidence.
|
|
129
|
-
|
|
130
|
-
Write the critic result into `.prizmkit/refactor/{{REFACTOR_ID}}/context-snapshot.md` or the plan notes, then update any unsafe plan details before implementation.
|
|
131
|
-
|
|
132
|
-
**Checkpoint update**: set step `critic-plan-review` to `completed` in `{{CHECKPOINT_PATH}}`.
|
|
133
|
-
|
|
134
|
-
---
|
|
135
|
-
|
|
136
|
-
{{END_IF_CRITIC_ENABLED}}
|
|
137
121
|
### Phase 3: Implement — Behavior-Preserving Refactoring
|
|
138
122
|
|
|
139
123
|
Run `/prizmkit-implement` with `artifact_dir=.prizmkit/refactor/{{REFACTOR_ID}}/`.
|
|
@@ -186,29 +186,22 @@
|
|
|
186
186
|
},
|
|
187
187
|
"user_context": {
|
|
188
188
|
"type": "array",
|
|
189
|
-
"items": {
|
|
189
|
+
"items": {
|
|
190
|
+
"type": "string"
|
|
191
|
+
},
|
|
190
192
|
"description": "User-provided supplementary materials, preserved verbatim. Each entry is either inline content/rules (stored as-is) or a file reference (e.g. 'src/auth/login.ts:42-78', 'src/utils/ — focus on validation logic')."
|
|
191
193
|
},
|
|
192
|
-
"critic": {
|
|
193
|
-
"type": "boolean",
|
|
194
|
-
"description": "Enable adversarial plan challenge before implementation. Default: true for critical/high priority refactors, false for others.",
|
|
195
|
-
"default": false
|
|
196
|
-
},
|
|
197
|
-
"critic_count": {
|
|
198
|
-
"type": "integer",
|
|
199
|
-
"description": "Number of parallel critic agents. 1 = single critic, 3 = multi-critic voting. Default: 3 for critical, 1 for high, omit for others.",
|
|
200
|
-
"enum": [
|
|
201
|
-
1,
|
|
202
|
-
3
|
|
203
|
-
]
|
|
204
|
-
},
|
|
205
194
|
"browser_interaction": {
|
|
206
195
|
"type": "object",
|
|
207
196
|
"description": "Browser verification config for refactors affecting UI behavior. Supports playwright-cli and opencli. AI auto-detects dev server command, URL, and port from project config at runtime.",
|
|
208
197
|
"properties": {
|
|
209
198
|
"tool": {
|
|
210
199
|
"type": "string",
|
|
211
|
-
"enum": [
|
|
200
|
+
"enum": [
|
|
201
|
+
"playwright-cli",
|
|
202
|
+
"opencli",
|
|
203
|
+
"auto"
|
|
204
|
+
],
|
|
212
205
|
"default": "auto",
|
|
213
206
|
"description": "Browser tool to use. 'auto' (default) = AI chooses at runtime. 'playwright-cli' = local dev server verification in isolated browser. 'opencli' = reuses Chrome logged-in session, ideal for verifying refactors involving third-party integrations or OAuth flows."
|
|
214
207
|
},
|
|
@@ -221,7 +214,8 @@
|
|
|
221
214
|
}
|
|
222
215
|
}
|
|
223
216
|
}
|
|
224
|
-
}
|
|
217
|
+
},
|
|
218
|
+
"additionalProperties": false
|
|
225
219
|
}
|
|
226
220
|
},
|
|
227
221
|
"global_context": {
|
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
- **Bug ID**: {{BUG_ID}} | **Session**: {{SESSION_ID}} | **Run**: {{RUN_ID}}
|
|
4
4
|
- **Bug Title**: {{BUG_TITLE}}
|
|
5
5
|
- **Severity**: {{SEVERITY}}
|
|
6
|
-
- **Mode**: {{PIPELINE_MODE}}
|
|
6
|
+
- **Mode**: {{PIPELINE_MODE}}
|
|
7
7
|
- **Verification Type**: {{VERIFICATION_TYPE}}
|
|
@@ -6,7 +6,7 @@ You are running in **headless non-interactive mode** with a FINITE context windo
|
|
|
6
6
|
|
|
7
7
|
1. **context-snapshot.md is your single source of truth** — After it is built, ALWAYS read context-snapshot.md instead of re-reading individual source files
|
|
8
8
|
2. **Never re-read your own writes** — After you create/modify a file, do NOT read it back to verify. Trust your write was correct.
|
|
9
|
-
3. **Never re-read unmodified files** — Once you have read a file into context, do NOT read it again unless it was modified by an Edit/Write operation after your last read. Use platform file/search tools for targeted lookup; when shell-free helper lookup is needed, run `{{RUNTIME_HELPER_CMD}} text search <file> --pattern "<pattern>" --json`, then read only the smallest bounded range with the platform file-reading tool instead of full-file Read. Before issuing a Read, ask yourself: "Have I read this file before, and has it changed since?" If the answer is "no, it hasn't changed" — do NOT read it. This applies to all files including those summarized in context-snapshot.md Section 4.
|
|
9
|
+
3. **Never re-read unmodified files** — Once you have read a file into context, do NOT read it again unless it was modified by an Edit/Write operation after your last read. Use platform file/search tools for targeted lookup; when shell-free helper lookup is needed, run `{{RUNTIME_HELPER_CMD}} text search <file> --pattern "<pattern>" --json`, then read only the smallest bounded range with the platform file-reading tool instead of full-file Read. Before issuing a Read, ask yourself: "Have I read this file before, and has it changed since?" If the answer is "no, it hasn't changed" — do NOT read it. This applies to all files including those summarized in context-snapshot.md Section 4. Reviewer subagents must receive context-snapshot.md and rely on it rather than independently re-reading the same files the orchestrator already read.
|
|
10
10
|
4. **Stay focused** — Do NOT explore code unrelated to this feature. No curiosity-driven reads.
|
|
11
11
|
5. **One task at a time** — Complete and test one task before starting the next.
|
|
12
12
|
6. **Minimize tool output** — Never load full command output into context. First capture command output to a temp file using the command/tool output option or the host-appropriate redirection, then inspect only the final relevant lines and use targeted search helpers to extract the information needed for the current task. Only read the filtered result — never the raw full output.
|
|
@@ -5,5 +5,4 @@
|
|
|
5
5
|
| Feature Artifacts Dir | `.prizmkit/specs/{{FEATURE_SLUG}}/` |
|
|
6
6
|
| Context Snapshot | `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md` |
|
|
7
7
|
| Reviewer Agent Def | {{REVIEWER_SUBAGENT_PATH}} |
|
|
8
|
-
| Critic Agent Def (if enabled) | {{CRITIC_SUBAGENT_PATH}} |
|
|
9
8
|
| Project Root | {{PROJECT_ROOT}} |
|
|
@@ -6,6 +6,5 @@
|
|
|
6
6
|
| Context Snapshot | `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md` |
|
|
7
7
|
| Team Config | `{{TEAM_CONFIG_PATH}}` |
|
|
8
8
|
| Reviewer Agent Def | {{REVIEWER_SUBAGENT_PATH}} |
|
|
9
|
-
| Critic Agent Def | {{CRITIC_SUBAGENT_PATH}} |
|
|
10
9
|
| Project Root | {{PROJECT_ROOT}} |
|
|
11
10
|
| Feature List Path | {{FEATURE_LIST_PATH}} |
|
|
@@ -17,7 +17,7 @@ Before starting, check plan.md Tasks:
|
|
|
17
17
|
- Implements task-by-task, marking each `[x]` immediately
|
|
18
18
|
- Creates/updates L2 `.prizm` docs when creating new modules
|
|
19
19
|
- Defers scoped/full test execution until after the code-review loop completes
|
|
20
|
-
- Preserves Reviewer
|
|
20
|
+
- Preserves Reviewer behavior; only the top-level implementation Dev handoff is removed
|
|
21
21
|
- If plan.md has >5 tasks: update checkpoints after every 3 tasks
|
|
22
22
|
|
|
23
23
|
**3b. Focused checks only (no test gate here)**:
|
|
@@ -17,7 +17,7 @@ Before starting, check plan.md Tasks:
|
|
|
17
17
|
- Implements task-by-task, marking each `[x]` immediately
|
|
18
18
|
- Creates/updates L2 `.prizm` docs when creating new modules
|
|
19
19
|
- Defers scoped/full test execution until after the code-review loop completes
|
|
20
|
-
- Preserves Reviewer
|
|
20
|
+
- Preserves Reviewer behavior; only the top-level implementation Dev handoff is removed
|
|
21
21
|
- If plan.md has >5 tasks: update checkpoints after every 3 tasks
|
|
22
22
|
|
|
23
23
|
**3b. Focused checks only (no test gate here)**:
|
|
@@ -26,3 +26,4 @@ _load_hyphenated_module("generate_bootstrap_prompt", "generate-bootstrap-prompt.
|
|
|
26
26
|
_load_hyphenated_module("generate_bugfix_prompt", "generate-bugfix-prompt.py")
|
|
27
27
|
_load_hyphenated_module("generate_refactor_prompt", "generate-refactor-prompt.py")
|
|
28
28
|
_load_hyphenated_module("update_feature_status", "update-feature-status.py")
|
|
29
|
+
_load_hyphenated_module("update_checkpoint", "update-checkpoint.py")
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"""Tests for shared workflow checkpoint state semantics."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
|
|
7
|
+
from prizmkit_runtime.checkpoint_state import load_checkpoint_state, read_checkpoint_cursor
|
|
8
|
+
from update_checkpoint import update_checkpoint
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _checkpoint(steps):
|
|
12
|
+
return {"version": 1, "workflow_type": "feature-pipeline", "steps": steps}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _step(step_id, skill="skill", name="Step", status="pending", depends_on=None):
|
|
16
|
+
return {
|
|
17
|
+
"id": step_id,
|
|
18
|
+
"skill": skill,
|
|
19
|
+
"name": name,
|
|
20
|
+
"status": status,
|
|
21
|
+
"required_artifacts": [],
|
|
22
|
+
"depends_on": depends_on,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _write(path, data):
|
|
27
|
+
path.write_text(json.dumps(data), encoding="utf-8")
|
|
28
|
+
return path
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_valid_checkpoint_current_step_uses_first_non_terminal(tmp_path):
|
|
32
|
+
path = _write(tmp_path / "workflow-checkpoint.json", _checkpoint([
|
|
33
|
+
_step("S01", "plan", "Plan", "completed"),
|
|
34
|
+
_step("S02", "implement", "Implement", "in_progress", "S01"),
|
|
35
|
+
_step("S03", "review", "Review", "pending", "S02"),
|
|
36
|
+
]))
|
|
37
|
+
|
|
38
|
+
state = load_checkpoint_state(path)
|
|
39
|
+
|
|
40
|
+
assert state.valid is True
|
|
41
|
+
assert state.current_step_name == "Implement"
|
|
42
|
+
assert state.cursor == 2
|
|
43
|
+
assert state.cursor_signature == "S02:implement:in_progress"
|
|
44
|
+
assert read_checkpoint_cursor(path) == 2
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_all_completed_checkpoint_has_complete_cursor(tmp_path):
|
|
48
|
+
path = _write(tmp_path / "workflow-checkpoint.json", _checkpoint([
|
|
49
|
+
_step("S01", "plan", "Plan", "completed"),
|
|
50
|
+
_step("S02", "commit", "Commit", "skipped", "S01"),
|
|
51
|
+
]))
|
|
52
|
+
|
|
53
|
+
state = load_checkpoint_state(path)
|
|
54
|
+
|
|
55
|
+
assert state.valid is True
|
|
56
|
+
assert state.all_completed is True
|
|
57
|
+
assert state.current_step is None
|
|
58
|
+
assert state.current_step_name == ""
|
|
59
|
+
assert state.cursor == 2
|
|
60
|
+
assert state.cursor_signature == "complete"
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def test_missing_and_malformed_checkpoints_are_invalid(tmp_path):
|
|
64
|
+
missing = load_checkpoint_state(tmp_path / "missing.json")
|
|
65
|
+
assert missing.valid is False
|
|
66
|
+
assert missing.exists is False
|
|
67
|
+
assert missing.error_code == "missing"
|
|
68
|
+
assert missing.current_step_name == ""
|
|
69
|
+
|
|
70
|
+
malformed_path = tmp_path / "bad.json"
|
|
71
|
+
malformed_path.write_text("{not-json", encoding="utf-8")
|
|
72
|
+
malformed = load_checkpoint_state(malformed_path)
|
|
73
|
+
assert malformed.valid is False
|
|
74
|
+
assert malformed.exists is True
|
|
75
|
+
assert malformed.error_code == "malformed_json"
|
|
76
|
+
assert malformed.current_step_name == ""
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def test_structural_validation_error_codes(tmp_path):
|
|
80
|
+
cases = [
|
|
81
|
+
("missing_steps", {}),
|
|
82
|
+
("empty_steps", {"steps": []}),
|
|
83
|
+
("duplicate_step_id", _checkpoint([_step("S01"), _step("S01")])),
|
|
84
|
+
("invalid_status", _checkpoint([_step("S01", status="done")])),
|
|
85
|
+
("invalid_depends_on", _checkpoint([_step("S01", depends_on="S99")])),
|
|
86
|
+
("invalid_depends_on", _checkpoint([_step("S01", depends_on="S02"), _step("S02")])),
|
|
87
|
+
("malformed_step_id", _checkpoint([_step("one")])),
|
|
88
|
+
("invalid_step", {"steps": ["not-object"]}),
|
|
89
|
+
]
|
|
90
|
+
for expected_code, payload in cases:
|
|
91
|
+
path = _write(tmp_path / f"{expected_code}.json", payload)
|
|
92
|
+
state = load_checkpoint_state(path)
|
|
93
|
+
assert state.valid is False
|
|
94
|
+
assert state.error_code == expected_code
|
|
95
|
+
assert state.current_step_name == ""
|
|
96
|
+
assert read_checkpoint_cursor(path) is None
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def test_failed_checkpoint_step_is_current_cursor(tmp_path):
|
|
100
|
+
path = _write(tmp_path / "workflow-checkpoint.json", _checkpoint([
|
|
101
|
+
_step("S01", "plan", "Plan", "completed"),
|
|
102
|
+
_step("S02", "review", "Review", "failed", "S01"),
|
|
103
|
+
]))
|
|
104
|
+
|
|
105
|
+
state = load_checkpoint_state(path)
|
|
106
|
+
|
|
107
|
+
assert state.valid is True
|
|
108
|
+
assert state.current_step_name == "Review"
|
|
109
|
+
assert state.cursor == 2
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def test_duplicate_skills_are_reported_but_exact_ids_remain_valid(tmp_path):
|
|
113
|
+
path = _write(tmp_path / "workflow-checkpoint.json", _checkpoint([
|
|
114
|
+
_step("S01", "prizmkit-committer", "Commit First", "pending"),
|
|
115
|
+
_step("S02", "prizmkit-committer", "Commit Second", "pending", "S01"),
|
|
116
|
+
]))
|
|
117
|
+
|
|
118
|
+
state = load_checkpoint_state(path)
|
|
119
|
+
|
|
120
|
+
assert state.valid is True
|
|
121
|
+
assert state.duplicate_skills == {"prizmkit-committer": ("S01", "S02")}
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def test_update_checkpoint_rejects_ambiguous_skill_without_mutation(tmp_path):
|
|
125
|
+
path = _write(tmp_path / "workflow-checkpoint.json", _checkpoint([
|
|
126
|
+
_step("S01", "prizmkit-committer", "Commit First", "pending"),
|
|
127
|
+
_step("S02", "prizmkit-committer", "Commit Second", "pending", "S01"),
|
|
128
|
+
]))
|
|
129
|
+
before = path.read_text(encoding="utf-8")
|
|
130
|
+
|
|
131
|
+
result = update_checkpoint(str(path), "prizmkit-committer", "completed")
|
|
132
|
+
|
|
133
|
+
assert result["ok"] is False
|
|
134
|
+
assert "matches multiple checkpoint steps" in result["error"]
|
|
135
|
+
assert "Use an explicit step ID" in result["error"]
|
|
136
|
+
assert path.read_text(encoding="utf-8") == before
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def test_update_checkpoint_exact_id_updates_one_duplicate_skill_step(tmp_path):
|
|
140
|
+
path = _write(tmp_path / "workflow-checkpoint.json", _checkpoint([
|
|
141
|
+
_step("S01", "prizmkit-committer", "Commit First", "pending"),
|
|
142
|
+
_step("S02", "prizmkit-committer", "Commit Second", "pending", "S01"),
|
|
143
|
+
]))
|
|
144
|
+
|
|
145
|
+
result = update_checkpoint(str(path), "S02", "completed")
|
|
146
|
+
data = json.loads(path.read_text(encoding="utf-8"))
|
|
147
|
+
|
|
148
|
+
assert result["ok"] is True
|
|
149
|
+
assert result["step_id"] == "S02"
|
|
150
|
+
assert data["steps"][0]["status"] == "pending"
|
|
151
|
+
assert data["steps"][1]["status"] == "completed"
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def test_update_checkpoint_invalid_checkpoint_fails_without_mutation(tmp_path):
|
|
155
|
+
path = _write(tmp_path / "workflow-checkpoint.json", _checkpoint([
|
|
156
|
+
_step("S01", "plan", "Plan", "done"),
|
|
157
|
+
]))
|
|
158
|
+
before = path.read_text(encoding="utf-8")
|
|
159
|
+
|
|
160
|
+
result = update_checkpoint(str(path), "S01", "completed")
|
|
161
|
+
|
|
162
|
+
assert result["ok"] is False
|
|
163
|
+
assert "invalid_status" in result["error"]
|
|
164
|
+
assert path.read_text(encoding="utf-8") == before
|