prizmkit 1.1.153 → 1.1.155

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.
Files changed (178) hide show
  1. package/bundled/VERSION.json +3 -3
  2. package/bundled/adapters/codex/skill-adapter.js +1 -1
  3. package/bundled/adapters/pi/skill-adapter.js +2 -1
  4. package/bundled/dev-pipeline/.env.example +2 -6
  5. package/bundled/dev-pipeline/README.md +120 -113
  6. package/bundled/dev-pipeline/assets/skill-subagent-integration.md +1 -1
  7. package/bundled/dev-pipeline/prizmkit_runtime/checkpoint_state.py +355 -15
  8. package/bundled/dev-pipeline/prizmkit_runtime/cli.py +189 -110
  9. package/bundled/dev-pipeline/prizmkit_runtime/commands.py +146 -111
  10. package/bundled/dev-pipeline/prizmkit_runtime/daemon.py +4 -20
  11. package/bundled/dev-pipeline/prizmkit_runtime/gitops.py +48 -14
  12. package/bundled/dev-pipeline/prizmkit_runtime/interoperability.py +0 -1
  13. package/bundled/dev-pipeline/prizmkit_runtime/paths.py +0 -3
  14. package/bundled/dev-pipeline/prizmkit_runtime/reset.py +122 -15
  15. package/bundled/dev-pipeline/prizmkit_runtime/reset_preserve.py +1 -1
  16. package/bundled/dev-pipeline/prizmkit_runtime/runner_classification.py +50 -2
  17. package/bundled/dev-pipeline/prizmkit_runtime/runner_models.py +1 -10
  18. package/bundled/dev-pipeline/prizmkit_runtime/runner_prompts.py +3 -3
  19. package/bundled/dev-pipeline/prizmkit_runtime/runners.py +139 -74
  20. package/bundled/dev-pipeline/prizmkit_runtime/runtime_commit.py +482 -0
  21. package/bundled/dev-pipeline/prizmkit_runtime/status.py +106 -1
  22. package/bundled/dev-pipeline/prizmkit_runtime/test_result.py +64 -11
  23. package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +145 -367
  24. package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +91 -62
  25. package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +105 -69
  26. package/bundled/dev-pipeline/scripts/init-bugfix-pipeline.py +2 -2
  27. package/bundled/dev-pipeline/scripts/prompt_framework.py +36 -41
  28. package/bundled/dev-pipeline/scripts/update-bug-status.py +197 -71
  29. package/bundled/dev-pipeline/scripts/update-checkpoint.py +77 -16
  30. package/bundled/dev-pipeline/scripts/update-feature-status.py +46 -121
  31. package/bundled/dev-pipeline/scripts/update-refactor-status.py +46 -123
  32. package/bundled/dev-pipeline/scripts/utils.py +119 -0
  33. package/bundled/dev-pipeline/templates/bootstrap-prompt.md +22 -27
  34. package/bundled/dev-pipeline/templates/bootstrap-tier3.md +71 -104
  35. package/bundled/dev-pipeline/templates/bug-fix-list-schema.json +3 -2
  36. package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +59 -111
  37. package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +37 -72
  38. package/bundled/dev-pipeline/templates/sections/artifact-manifest.md +39 -0
  39. package/bundled/dev-pipeline/templates/sections/bugfix-critical-paths.md +3 -1
  40. package/bundled/dev-pipeline/templates/sections/bugfix-phase-commit-report.md +8 -25
  41. package/bundled/dev-pipeline/templates/sections/bugfix-phase-diagnose-plan.md +3 -3
  42. package/bundled/dev-pipeline/templates/sections/bugfix-phase-implement.md +2 -2
  43. package/bundled/dev-pipeline/templates/sections/bugfix-phase-review.md +3 -3
  44. package/bundled/dev-pipeline/templates/sections/bugfix-phase-test.md +2 -2
  45. package/bundled/dev-pipeline/templates/sections/bugfix-reminders.md +4 -4
  46. package/bundled/dev-pipeline/templates/sections/bugfix-session-context.md +0 -1
  47. package/bundled/dev-pipeline/templates/sections/checkpoint-system.md +7 -4
  48. package/bundled/dev-pipeline/templates/sections/context-budget-rules.md +14 -27
  49. package/bundled/dev-pipeline/templates/sections/feature-completion-summary.md +20 -0
  50. package/bundled/dev-pipeline/templates/sections/phase-commit-full.md +8 -71
  51. package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +7 -7
  52. package/bundled/dev-pipeline/templates/sections/phase-prizmkit-test.md +3 -3
  53. package/bundled/dev-pipeline/templates/sections/phase-review-full.md +4 -4
  54. package/bundled/dev-pipeline/templates/sections/phase-specify-plan-full.md +5 -17
  55. package/bundled/dev-pipeline/templates/sections/refactor-critical-paths.md +3 -1
  56. package/bundled/dev-pipeline/templates/sections/refactor-phase-commit-report.md +10 -23
  57. package/bundled/dev-pipeline/templates/sections/refactor-phase-implement.md +2 -2
  58. package/bundled/dev-pipeline/templates/sections/refactor-phase-plan.md +2 -2
  59. package/bundled/dev-pipeline/templates/sections/refactor-phase-review.md +3 -3
  60. package/bundled/dev-pipeline/templates/sections/refactor-phase-test.md +2 -2
  61. package/bundled/dev-pipeline/templates/sections/refactor-reminders.md +7 -7
  62. package/bundled/dev-pipeline/templates/sections/refactor-session-context.md +0 -1
  63. package/bundled/dev-pipeline/templates/sections/retrospective.md +12 -0
  64. package/bundled/dev-pipeline/templates/sections/runtime-commit-handoff.md +35 -0
  65. package/bundled/dev-pipeline/templates/session-status-schema.json +45 -62
  66. package/bundled/dev-pipeline/tests/test_auto_skip.py +111 -32
  67. package/bundled/dev-pipeline/tests/test_checkpoint_state.py +617 -30
  68. package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +262 -194
  69. package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +62 -23
  70. package/bundled/dev-pipeline/tests/test_generate_refactor_prompt.py +76 -28
  71. package/bundled/dev-pipeline/tests/test_python_runner_parity.py +281 -206
  72. package/bundled/dev-pipeline/tests/test_recovery_workflow.py +322 -0
  73. package/bundled/dev-pipeline/tests/test_reset_modes.py +935 -0
  74. package/bundled/dev-pipeline/tests/test_reset_preserve.py +5 -7
  75. package/bundled/dev-pipeline/tests/test_runtime_commit.py +608 -0
  76. package/bundled/dev-pipeline/tests/test_unified_cli.py +617 -188
  77. package/bundled/skills/_metadata.json +9 -9
  78. package/bundled/skills/app-planner/SKILL.md +3 -3
  79. package/bundled/skills/app-planner/references/generated-plan-review.md +2 -1
  80. package/bundled/skills/app-planner/references/rules/backend/derivation-rules.md +56 -64
  81. package/bundled/skills/app-planner/references/rules/backend/fixed-rules.md +85 -240
  82. package/bundled/skills/app-planner/references/rules/backend/question-bank.md +25 -25
  83. package/bundled/skills/app-planner/references/rules/backend/question-manifest.json +16 -7
  84. package/bundled/skills/app-planner/references/rules/backend/template.md +74 -92
  85. package/bundled/skills/app-planner/references/rules/database/derivation-rules.md +93 -93
  86. package/bundled/skills/app-planner/references/rules/database/fixed-rules.md +66 -173
  87. package/bundled/skills/app-planner/references/rules/database/question-bank.md +31 -26
  88. package/bundled/skills/app-planner/references/rules/database/question-manifest.json +13 -4
  89. package/bundled/skills/app-planner/references/rules/database/template.md +76 -98
  90. package/bundled/skills/app-planner/references/rules/frontend/derivation-rules.md +68 -95
  91. package/bundled/skills/app-planner/references/rules/frontend/fixed-rules.md +93 -166
  92. package/bundled/skills/app-planner/references/rules/frontend/question-bank.md +46 -36
  93. package/bundled/skills/app-planner/references/rules/frontend/question-manifest.json +11 -2
  94. package/bundled/skills/app-planner/references/rules/frontend/template.md +79 -257
  95. package/bundled/skills/app-planner/references/rules/mobile/derivation-rules.md +91 -99
  96. package/bundled/skills/app-planner/references/rules/mobile/fixed-rules.md +73 -246
  97. package/bundled/skills/app-planner/references/rules/mobile/question-bank.md +17 -17
  98. package/bundled/skills/app-planner/references/rules/mobile/question-manifest.json +17 -2
  99. package/bundled/skills/app-planner/references/rules/mobile/template.md +73 -85
  100. package/bundled/skills/app-planner/references/rules-configuration.md +133 -65
  101. package/bundled/skills/app-planner/scripts/validate-rules-configuration.py +291 -0
  102. package/bundled/skills/bug-planner/references/schema-validation.md +1 -1
  103. package/bundled/skills/bug-planner/scripts/validate-bug-list.py +1 -1
  104. package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +21 -13
  105. package/bundled/skills/feature-pipeline-launcher/SKILL.md +22 -14
  106. package/bundled/skills/prizmkit/SKILL.md +17 -18
  107. package/bundled/skills/prizmkit/references/workflow-state-protocol.md +22 -18
  108. package/bundled/skills/prizmkit-code-review/SKILL.md +22 -58
  109. package/bundled/skills/prizmkit-code-review/references/independent-code-review.md +6 -6
  110. package/bundled/skills/prizmkit-code-review/references/review-report-template.md +2 -2
  111. package/bundled/skills/prizmkit-committer/SKILL.md +82 -132
  112. package/bundled/skills/prizmkit-deploy/SKILL.md +27 -11
  113. package/bundled/skills/prizmkit-deploy/assets/deploy-document-template.md +89 -0
  114. package/bundled/skills/prizmkit-deploy/references/ci-cd-workflows.md +44 -14
  115. package/bundled/skills/prizmkit-deploy/references/cloud-platform-deploy.md +19 -3
  116. package/bundled/skills/prizmkit-deploy/references/database-setup.md +22 -12
  117. package/bundled/skills/prizmkit-deploy/references/deploy-config-schema.md +3 -1
  118. package/bundled/skills/prizmkit-deploy/references/deploy-history-schema.md +22 -6
  119. package/bundled/skills/prizmkit-deploy/references/deploy-metadata-schema.json +49 -0
  120. package/bundled/skills/prizmkit-deploy/references/live-validation-notes.md +1 -1
  121. package/bundled/skills/prizmkit-deploy/references/pending-input-schema.json +164 -0
  122. package/bundled/skills/prizmkit-deploy/references/ssh-adapter-flow.md +9 -8
  123. package/bundled/skills/prizmkit-deploy/references/ssh-execution-flow.md +6 -6
  124. package/bundled/skills/prizmkit-implement/SKILL.md +30 -66
  125. package/bundled/skills/prizmkit-implement/references/implementation-subagent-procedure.md +4 -4
  126. package/bundled/skills/prizmkit-init/SKILL.md +4 -0
  127. package/bundled/skills/prizmkit-plan/SKILL.md +21 -64
  128. package/bundled/skills/prizmkit-plan/references/artifact-identity.md +38 -0
  129. package/bundled/skills/prizmkit-plan/references/independent-plan-review.md +4 -4
  130. package/bundled/skills/prizmkit-plan/references/review-plan-spec-loop.md +5 -5
  131. package/bundled/skills/prizmkit-prizm-docs/SKILL.md +11 -1
  132. package/bundled/skills/prizmkit-retrospective/SKILL.md +63 -77
  133. package/bundled/skills/prizmkit-retrospective/references/knowledge-injection-steps.md +3 -3
  134. package/bundled/skills/prizmkit-retrospective/references/retrospective-result-schema.json +138 -0
  135. package/bundled/skills/prizmkit-retrospective/references/structural-sync-steps.md +17 -23
  136. package/bundled/skills/prizmkit-test/SKILL.md +64 -51
  137. package/bundled/skills/prizmkit-test/references/boundary-contract-and-test-double-guidance.md +206 -0
  138. package/bundled/skills/prizmkit-test/references/independent-test-review.md +17 -9
  139. package/bundled/skills/prizmkit-test/references/test-coverage-model.md +45 -21
  140. package/bundled/skills/prizmkit-test/references/test-report-template.md +20 -13
  141. package/bundled/skills/prizmkit-workflow/SKILL.md +35 -37
  142. package/bundled/skills/prizmkit-workflow/references/artifact-identity.md +34 -0
  143. package/bundled/skills/prizmkit-workflow/references/workflow-state-protocol.md +22 -18
  144. package/bundled/skills/recovery-workflow/SKILL.md +9 -6
  145. package/bundled/skills/recovery-workflow/evals/evals.json +2 -2
  146. package/bundled/skills/recovery-workflow/references/detection.md +7 -6
  147. package/bundled/skills/recovery-workflow/scripts/detect-recovery-state.py +16 -6
  148. package/bundled/skills/refactor-pipeline-launcher/SKILL.md +21 -13
  149. package/bundled/templates/project-memory-template.md +19 -11
  150. package/package.json +1 -1
  151. package/src/scaffold.js +33 -22
  152. package/bundled/dev-pipeline/prizmkit_runtime/runner_recovery.py +0 -228
  153. package/bundled/dev-pipeline/scripts/generate-recovery-prompt.py +0 -767
  154. package/bundled/dev-pipeline/templates/sections/bugfix-artifacts.md +0 -16
  155. package/bundled/dev-pipeline/templates/sections/bugfix-session-status.md +0 -31
  156. package/bundled/dev-pipeline/templates/sections/critical-paths-agent.md +0 -7
  157. package/bundled/dev-pipeline/templates/sections/critical-paths-lite.md +0 -7
  158. package/bundled/dev-pipeline/templates/sections/directory-convention-agent.md +0 -9
  159. package/bundled/dev-pipeline/templates/sections/directory-convention-lite.md +0 -6
  160. package/bundled/dev-pipeline/templates/sections/headless-commit-authorization.md +0 -15
  161. package/bundled/dev-pipeline/templates/sections/phase-commit.md +0 -61
  162. package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-agent-suffix.md +0 -24
  163. package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-lite-suffix.md +0 -12
  164. package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +0 -44
  165. package/bundled/dev-pipeline/templates/sections/phase-implement-lite.md +0 -25
  166. package/bundled/dev-pipeline/templates/sections/phase-plan-agent.md +0 -20
  167. package/bundled/dev-pipeline/templates/sections/phase-plan-lite.md +0 -20
  168. package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +0 -20
  169. package/bundled/dev-pipeline/templates/sections/refactor-artifacts.md +0 -17
  170. package/bundled/dev-pipeline/templates/sections/refactor-session-status.md +0 -28
  171. package/bundled/dev-pipeline/templates/sections/test-failure-recovery-agent.md +0 -52
  172. package/bundled/dev-pipeline/templates/sections/test-failure-recovery-lite.md +0 -52
  173. package/bundled/skills/prizmkit-code-review/references/workflow-state-protocol.md +0 -174
  174. package/bundled/skills/prizmkit-committer/references/workflow-state-protocol.md +0 -174
  175. package/bundled/skills/prizmkit-implement/references/workflow-state-protocol.md +0 -174
  176. package/bundled/skills/prizmkit-plan/references/workflow-state-protocol.md +0 -174
  177. package/bundled/skills/prizmkit-retrospective/references/workflow-state-protocol.md +0 -174
  178. package/bundled/skills/prizmkit-test/references/external-contract-mock-guidance.md +0 -119
@@ -0,0 +1,35 @@
1
+ ### Runtime Commit Handoff
2
+
3
+ The Python runtime, not the AI session, executes the pipeline's local Git commit. This stage contains no prompt-level commit authorization.
4
+
5
+ After Code Review, all configured verification, `TEST_PASS`, family reports/summaries, and retrospective have completed:
6
+
7
+ 1. As the session orchestrator, validate every required stage artifact and result first. Atomic Skills do not perform this sequencing check.
8
+ 2. Invoke `/prizmkit-committer` with the same artifact root, exact readiness evidence, and request path:
9
+
10
+ ```text
11
+ /prizmkit-committer operation=prepare-runtime-commit artifact_dir={{ARTIFACT_DIR}} evidence_paths=<exact validated artifact paths> excluded_paths={{ARTIFACT_DIR}}/workflow-checkpoint.json request_path={{ARTIFACT_DIR}}/runtime-commit-request.json
12
+ ```
13
+
14
+ 3. The committer validates only the supplied evidence and final diff, then classifies paths before writing the request:
15
+ - all `.prizmkit/**` paths are PrizmKit-internal and stay outside the task commit, including config, plans, Prizm docs, lifecycle Artifacts, Runtime files, and state;
16
+ - `AGENTS.md`, `skills-lock.json`, installed platform directories, and local platform settings are support data and stay outside the task commit;
17
+ - project-specific transient data must already be covered by Git ignore rules;
18
+ - every other Git-visible path must be justified task output and included exactly, otherwise the handoff blocks.
19
+
20
+ It then rejects sensitive/unrelated/unknown paths, generates one Conventional Commit message, and writes this request without staging or committing:
21
+
22
+ ```json
23
+ {
24
+ "schema_version": 1,
25
+ "artifact_dir": "{{ARTIFACT_DIR}}",
26
+ "base_head": "<current HEAD commit hash>",
27
+ "commit_message": "<type>(<scope>): <description>",
28
+ "intended_paths": ["<exact project-relative changed path>"]
29
+ }
30
+ ```
31
+
32
+ 4. Require the stage-local result `COMMIT_REQUEST_READY`. Then this injected session—not the Skill—marks `prizmkit-committer` `in_progress` with `stage_result=COMMIT_PENDING` through the checkpoint helper. Do not mark it completed or write `COMMITTED`.
33
+ 5. Stop normal work after the valid request and checkpoint handoff exist. Do not run `git add`, `git commit`, `git commit --amend`, merge, push, or create additional files.
34
+
35
+ The runtime validates exact task-owned path coverage outside recognized internal/support namespaces, rejects a request that explicitly names one of those namespaces, stages only the requested literal paths, executes and verifies the local commit, finalizes the Runtime-owned checkpoint to `COMMITTED`, and then performs its configured merge/publication behavior. Unknown Git-visible paths are not silently ignored: they produce a mismatch and preserve the task checkout for recovery. A malformed, stale, unsafe, incomplete, or contradictory request also blocks without deleting user data.
@@ -1,83 +1,66 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
- "title": "Dev-Pipeline Session Status",
4
- "description": "Schema for session-status.json written by agent at session end",
3
+ "title": "Dev-Pipeline Runtime Session Status",
4
+ "description": "Schema for runner-owned session-status.json written after an AI process exits",
5
5
  "type": "object",
6
- "required": ["session_id", "feature_id", "status", "timestamp"],
6
+ "required": [
7
+ "session_id",
8
+ "task_id",
9
+ "task_type",
10
+ "status",
11
+ "base_branch",
12
+ "active_dev_branch"
13
+ ],
7
14
  "properties": {
8
15
  "session_id": {
9
16
  "type": "string",
10
17
  "minLength": 1
11
18
  },
12
- "feature_id": {
19
+ "task_id": {
13
20
  "type": "string",
14
- "pattern": "^F-\\d{3}(-[A-Z])?$"
21
+ "pattern": "^[FBR]-\\d{3}(?:-[A-Z])?$"
15
22
  },
16
- "status": {
23
+ "task_type": {
17
24
  "type": "string",
18
- "enum": ["success", "partial", "failed", "crashed", "timed_out", "infra_error", "commit_missing", "docs_missing", "merge_conflict", "context_overflow", "stalled_context_continuation", "workflow_blocked", "workflow_skipped"]
19
- },
20
- "completed_phases": {
21
- "type": "array",
22
- "items": {
23
- "type": "integer",
24
- "minimum": 0,
25
- "maximum": 7
26
- }
27
- },
28
- "current_phase": {
29
- "type": "integer",
30
- "minimum": 0,
31
- "maximum": 7
25
+ "enum": ["feature", "bugfix", "refactor"]
32
26
  },
33
- "checkpoint_reached": {
27
+ "status": {
34
28
  "type": "string",
35
- "pattern": "^CP-[0-3]$"
36
- },
37
- "tasks_completed": {
38
- "type": "integer",
39
- "minimum": 0
40
- },
41
- "tasks_total": {
42
- "type": "integer",
43
- "minimum": 0
29
+ "enum": [
30
+ "success",
31
+ "failed",
32
+ "crashed",
33
+ "timed_out",
34
+ "infra_error",
35
+ "commit_missing",
36
+ "docs_missing",
37
+ "merge_conflict",
38
+ "context_overflow",
39
+ "stalled_context_continuation",
40
+ "workflow_blocked",
41
+ "workflow_skipped"
42
+ ]
44
43
  },
45
- "errors": {
46
- "type": "array",
47
- "items": {
48
- "type": "object",
49
- "required": ["message"],
50
- "properties": {
51
- "phase": { "type": "integer" },
52
- "type": { "type": "string" },
53
- "message": { "type": "string" },
54
- "recoverable": { "type": "boolean" }
55
- }
56
- }
57
- },
58
- "can_resume": {
59
- "type": "boolean"
44
+ "base_branch": {
45
+ "type": "string",
46
+ "minLength": 1
60
47
  },
61
- "docs_maintained": {
62
- "type": "boolean"
48
+ "active_dev_branch": {
49
+ "type": "string",
50
+ "minLength": 1
63
51
  },
64
- "retrospective_done": {
65
- "type": "boolean"
52
+ "worktree_path": {
53
+ "type": "string"
66
54
  },
67
- "resume_from_phase": {
68
- "type": ["integer", "null"]
55
+ "reason": {
56
+ "type": "string"
69
57
  },
70
- "artifacts": {
71
- "type": "object",
72
- "properties": {
73
- "spec_path": { "type": "string" },
74
- "plan_path": { "type": "string" },
75
- "context_snapshot_path": { "type": "string" }
76
- }
58
+ "fatal_error_code": {
59
+ "type": "string"
77
60
  },
78
- "timestamp": {
79
- "type": "string",
80
- "format": "date-time"
61
+ "checkpoint_state": {
62
+ "type": "object"
81
63
  }
82
- }
64
+ },
65
+ "additionalProperties": false
83
66
  }
@@ -1,4 +1,4 @@
1
- """Tests for auto-skip and unskip functionality in update-feature-status.py."""
1
+ """Tests for auto-skip and reset_state functionality in update-feature-status.py."""
2
2
 
3
3
  import json
4
4
  import os
@@ -221,6 +221,76 @@ class TestContextOverflowRetrySemantics:
221
221
  ]:
222
222
  assert key not in status
223
223
 
224
+ def test_start_and_update_persist_effective_retry_budgets_without_charging_workflow_skip(self, tmp_path):
225
+ scripts_dir = Path(__file__).resolve().parents[1] / "scripts"
226
+
227
+ for case in self._script_cases(scripts_dir):
228
+ case_dir = tmp_path / f"budgets-{case['id']}"
229
+ state_dir = case_dir / "state"
230
+ list_path = case_dir / case["list_name"]
231
+ payload = json.loads(json.dumps(case["list_payload"]))
232
+ payload[case["collection"]][0]["status"] = "pending"
233
+ write_json_file(str(list_path), payload)
234
+
235
+ start = subprocess.run(
236
+ [
237
+ "python3",
238
+ str(case["script"]),
239
+ case["list_option"],
240
+ str(list_path),
241
+ "--state-dir",
242
+ str(state_dir),
243
+ case["id_option"],
244
+ case["id"],
245
+ "--action",
246
+ "start",
247
+ "--max-retries",
248
+ "7",
249
+ "--max-infra-retries",
250
+ "4",
251
+ ],
252
+ text=True,
253
+ capture_output=True,
254
+ check=True,
255
+ )
256
+ assert json.loads(start.stdout)["new_status"] == "in_progress"
257
+ started = self._runtime_status(state_dir, case["id"])
258
+ assert started["max_retries"] == 7
259
+ assert started["max_infra_retries"] == 4
260
+
261
+ skipped = subprocess.run(
262
+ [
263
+ "python3",
264
+ str(case["script"]),
265
+ case["list_option"],
266
+ str(list_path),
267
+ "--state-dir",
268
+ str(state_dir),
269
+ case["id_option"],
270
+ case["id"],
271
+ "--session-id",
272
+ "sess-skip",
273
+ "--session-status",
274
+ "workflow_skipped",
275
+ "--action",
276
+ "update",
277
+ "--max-retries",
278
+ "5",
279
+ "--max-infra-retries",
280
+ "2",
281
+ ],
282
+ text=True,
283
+ capture_output=True,
284
+ check=True,
285
+ )
286
+ summary = json.loads(skipped.stdout)
287
+ runtime = self._runtime_status(state_dir, case["id"])
288
+ assert summary["new_status"] == "skipped"
289
+ assert runtime["max_retries"] == 5
290
+ assert runtime["max_infra_retries"] == 2
291
+ assert runtime["retry_count"] == 0
292
+ assert runtime["infra_error_count"] == 0
293
+
224
294
  def test_context_overflow_consumes_retry_and_records_bounded_continuation_metadata(self, tmp_path):
225
295
  scripts_dir = Path(__file__).resolve().parents[1] / "scripts"
226
296
 
@@ -441,10 +511,10 @@ class TestContextOverflowRetrySemantics:
441
511
  assert runtime["context_overflow_count"] == 2
442
512
  assert runtime["continuation_count"] == 2
443
513
 
444
- def test_manual_reset_clean_and_unskip_clear_all_continuation_state(self, tmp_path):
514
+ def test_manual_reset_clean_and_reset_state_clear_all_continuation_state(self, tmp_path):
445
515
  scripts_dir = Path(__file__).resolve().parents[1] / "scripts"
446
516
 
447
- for action in ["reset", "clean", "unskip"]:
517
+ for action in ["reset", "clean", "reset_state"]:
448
518
  for case in self._script_cases(scripts_dir):
449
519
  case_dir = tmp_path / f"{action}-{case['id']}"
450
520
  state_dir = case_dir / "state"
@@ -503,7 +573,7 @@ class TestContextOverflowRetrySemantics:
503
573
  ]
504
574
  if action in ("reset", "clean"):
505
575
  cmd.extend([case["id_option"], case["id"]])
506
- elif action == "unskip":
576
+ elif action == "reset_state":
507
577
  cmd.extend([case["id_option"], case["id"]])
508
578
  if action == "clean":
509
579
  cmd.extend(["--project-root", str(case_dir)])
@@ -515,7 +585,15 @@ class TestContextOverflowRetrySemantics:
515
585
  for continuation_file in continuation_files:
516
586
  assert not continuation_file.exists()
517
587
  runtime = self._runtime_status(state_dir, case["id"])
518
- self._assert_no_continuation_runtime_state(runtime)
588
+ if action == "reset_state":
589
+ assert runtime["active_dev_branch"] == "dev/existing-branch"
590
+ assert runtime["base_branch"] == "main"
591
+ continuation_only = dict(runtime)
592
+ continuation_only.pop("active_dev_branch")
593
+ continuation_only.pop("base_branch")
594
+ self._assert_no_continuation_runtime_state(continuation_only)
595
+ else:
596
+ self._assert_no_continuation_runtime_state(runtime)
519
597
  assert runtime["retry_count"] == 0
520
598
  assert runtime["infra_error_count"] == 0
521
599
  assert runtime["last_infra_error_session_id"] is None
@@ -601,6 +679,7 @@ class TestContextOverflowRetrySemantics:
601
679
  "reset",
602
680
  case["target"],
603
681
  case["item_id"],
682
+ "--fresh-checkout",
604
683
  str(prizmkit_dir / "plans" / case["list_name"]),
605
684
  ],
606
685
  cwd=case_dir,
@@ -758,7 +837,7 @@ def _run_status_snapshot_action(case, list_path, state_dir, action, session_stat
758
837
  "--action",
759
838
  action,
760
839
  ]
761
- if action in {"update", "reset", "clean", "unskip"}:
840
+ if action in {"update", "reset", "clean", "reset_state"}:
762
841
  cmd.extend([case["id_option"], case["id"]])
763
842
  if action == "update":
764
843
  cmd.extend([
@@ -1200,7 +1279,7 @@ class TestAutoSkipEdgeCases:
1200
1279
 
1201
1280
 
1202
1281
  # ---------------------------------------------------------------------------
1203
- # action_unskip — via subprocess (tests the full CLI interface)
1282
+ # action_reset_state — via subprocess (tests the full CLI interface)
1204
1283
  # ---------------------------------------------------------------------------
1205
1284
 
1206
1285
  import subprocess
@@ -1210,12 +1289,12 @@ _SCRIPT = os.path.join(
1210
1289
  )
1211
1290
 
1212
1291
 
1213
- def _run_unskip(fl_path, state_dir, feature_id=None):
1292
+ def _run_reset_state(fl_path, state_dir, feature_id=None):
1214
1293
  cmd = [
1215
1294
  "python3", _SCRIPT,
1216
1295
  "--feature-list", fl_path,
1217
1296
  "--state-dir", state_dir,
1218
- "--action", "unskip",
1297
+ "--action", "reset_state",
1219
1298
  ]
1220
1299
  if feature_id:
1221
1300
  cmd += ["--feature-id", feature_id]
@@ -1344,7 +1423,7 @@ class TestInfraErrorUpdate:
1344
1423
  assert fs["last_infra_error_session_id"] is None
1345
1424
  assert _read_statuses(fl_path)["F-001"] == "pending"
1346
1425
 
1347
- def test_unskip_clears_infra_retry_counters(self, tmp_path):
1426
+ def test_reset_state_clears_infra_retry_counters(self, tmp_path):
1348
1427
  features = [_make_feature("F-001", "Root", status="failed")]
1349
1428
  fl_path = _write_fl(tmp_path, features)
1350
1429
  state_dir = _init_state(tmp_path, ["F-001"])
@@ -1355,7 +1434,7 @@ class TestInfraErrorUpdate:
1355
1434
  fs["last_infra_error_session_id"] = "session-infra-final"
1356
1435
  write_json_file(status_path, fs)
1357
1436
 
1358
- _run_unskip(fl_path, state_dir, "F-001")
1437
+ _run_reset_state(fl_path, state_dir, "F-001")
1359
1438
 
1360
1439
  fs = load_feature_status(state_dir, "F-001")
1361
1440
  assert fs["retry_count"] == 0
@@ -1363,10 +1442,10 @@ class TestInfraErrorUpdate:
1363
1442
  assert fs["last_infra_error_session_id"] is None
1364
1443
  assert _read_statuses(fl_path)["F-001"] == "pending"
1365
1444
 
1366
- class TestUnskipByFeatureId:
1367
- """Unskip with --feature-id targets a specific failed feature + downstream."""
1445
+ class TestResetStateByFeatureId:
1446
+ """ResetState with --feature-id targets a specific failed feature + downstream."""
1368
1447
 
1369
- def test_unskip_failed_root_resets_all(self, tmp_path):
1448
+ def test_reset_state_failed_root_resets_all(self, tmp_path):
1370
1449
  features = [
1371
1450
  _make_feature("F-001", "Root", status="failed"),
1372
1451
  _make_feature("F-002", "Mid", deps=["F-001"], status="auto_skipped"),
@@ -1375,14 +1454,14 @@ class TestUnskipByFeatureId:
1375
1454
  fl_path = _write_fl(tmp_path, features)
1376
1455
  state_dir = _init_state(tmp_path, ["F-001", "F-002", "F-003"])
1377
1456
 
1378
- result = _run_unskip(fl_path, state_dir, "F-001")
1457
+ result = _run_reset_state(fl_path, state_dir, "F-001")
1379
1458
 
1380
1459
  assert result["reset_count"] == 3
1381
1460
  statuses = _read_statuses(fl_path)
1382
1461
  assert all(s == "pending" for s in statuses.values())
1383
1462
 
1384
- def test_unskip_auto_skipped_leaf_resets_upstream(self, tmp_path):
1385
- """C2 fix: unskip F-003 must also find and reset F-001 (failed root)."""
1463
+ def test_reset_state_auto_skipped_leaf_resets_upstream(self, tmp_path):
1464
+ """C2 fix: reset_state F-003 must also find and reset F-001 (failed root)."""
1386
1465
  features = [
1387
1466
  _make_feature("F-001", "Root", status="failed"),
1388
1467
  _make_feature("F-002", "Mid", deps=["F-001"], status="auto_skipped"),
@@ -1391,14 +1470,14 @@ class TestUnskipByFeatureId:
1391
1470
  fl_path = _write_fl(tmp_path, features)
1392
1471
  state_dir = _init_state(tmp_path, ["F-001", "F-002", "F-003"])
1393
1472
 
1394
- result = _run_unskip(fl_path, state_dir, "F-003")
1473
+ result = _run_reset_state(fl_path, state_dir, "F-003")
1395
1474
 
1396
1475
  assert result["reset_count"] == 3
1397
1476
  reset_ids = {f["feature_id"] for f in result["features"]}
1398
1477
  assert "F-001" in reset_ids # transitive upstream reset
1399
1478
  assert all(s == "pending" for s in _read_statuses(fl_path).values())
1400
1479
 
1401
- def test_unskip_preserves_completed_features(self, tmp_path):
1480
+ def test_reset_state_preserves_completed_features(self, tmp_path):
1402
1481
  features = [
1403
1482
  _make_feature("F-001", "Done", status="completed"),
1404
1483
  _make_feature("F-002", "Failed", deps=["F-001"], status="failed"),
@@ -1407,7 +1486,7 @@ class TestUnskipByFeatureId:
1407
1486
  fl_path = _write_fl(tmp_path, features)
1408
1487
  state_dir = _init_state(tmp_path, ["F-001", "F-002", "F-003"])
1409
1488
 
1410
- result = _run_unskip(fl_path, state_dir, "F-002")
1489
+ result = _run_reset_state(fl_path, state_dir, "F-002")
1411
1490
 
1412
1491
  assert result["reset_count"] == 2
1413
1492
  statuses = _read_statuses(fl_path)
@@ -1415,8 +1494,8 @@ class TestUnskipByFeatureId:
1415
1494
  assert statuses["F-002"] == "pending"
1416
1495
  assert statuses["F-003"] == "pending"
1417
1496
 
1418
- def test_unskip_skipped_feature_resets_downstream(self, tmp_path):
1419
- """Unskip a manually-skipped feature should also reset its auto_skipped downstream."""
1497
+ def test_reset_state_skipped_feature_resets_downstream(self, tmp_path):
1498
+ """ResetState a manually-skipped feature should also reset its auto_skipped downstream."""
1420
1499
  features = [
1421
1500
  _make_feature("F-001", "Skipped", status="skipped"),
1422
1501
  _make_feature("F-002", "Child", deps=["F-001"], status="auto_skipped"),
@@ -1424,7 +1503,7 @@ class TestUnskipByFeatureId:
1424
1503
  fl_path = _write_fl(tmp_path, features)
1425
1504
  state_dir = _init_state(tmp_path, ["F-001", "F-002"])
1426
1505
 
1427
- result = _run_unskip(fl_path, state_dir, "F-001")
1506
+ result = _run_reset_state(fl_path, state_dir, "F-001")
1428
1507
 
1429
1508
  assert result["reset_count"] == 2
1430
1509
  statuses = _read_statuses(fl_path)
@@ -1432,8 +1511,8 @@ class TestUnskipByFeatureId:
1432
1511
  assert statuses["F-002"] == "pending"
1433
1512
 
1434
1513
 
1435
- class TestUnskipAll:
1436
- """Unskip without --feature-id resets all failed + auto_skipped."""
1514
+ class TestResetStateAll:
1515
+ """ResetState without --feature-id resets all failed + auto_skipped."""
1437
1516
 
1438
1517
  def test_resets_all_failed_and_auto_skipped(self, tmp_path):
1439
1518
  features = [
@@ -1445,7 +1524,7 @@ class TestUnskipAll:
1445
1524
  fl_path = _write_fl(tmp_path, features)
1446
1525
  state_dir = _init_state(tmp_path, ["F-001", "F-002", "F-003", "F-004"])
1447
1526
 
1448
- result = _run_unskip(fl_path, state_dir)
1527
+ result = _run_reset_state(fl_path, state_dir)
1449
1528
 
1450
1529
  assert result["reset_count"] == 2
1451
1530
  statuses = _read_statuses(fl_path)
@@ -1456,11 +1535,11 @@ class TestUnskipAll:
1456
1535
 
1457
1536
 
1458
1537
  # ---------------------------------------------------------------------------
1459
- # Integration: auto-skip → get_next → unskip → get_next
1538
+ # Integration: auto-skip → get_next → reset_state → get_next
1460
1539
  # ---------------------------------------------------------------------------
1461
1540
 
1462
1541
  class TestAutoSkipIntegration:
1463
- """Full lifecycle: fail → auto-skip → pipeline complete → unskip → resume."""
1542
+ """Full lifecycle: fail → auto-skip → pipeline complete → reset_state → resume."""
1464
1543
 
1465
1544
  def test_full_lifecycle(self, tmp_path):
1466
1545
  features = [
@@ -1477,8 +1556,8 @@ class TestAutoSkipIntegration:
1477
1556
  # 2. get_next should return PIPELINE_COMPLETE
1478
1557
  assert _run_get_next(fl_path, state_dir) == "PIPELINE_COMPLETE"
1479
1558
 
1480
- # 3. Unskip recovers everything
1481
- _run_unskip(fl_path, state_dir, "F-001")
1559
+ # 3. ResetState recovers everything
1560
+ _run_reset_state(fl_path, state_dir, "F-001")
1482
1561
  statuses = _read_statuses(fl_path)
1483
1562
  assert statuses["F-001"] == "pending"
1484
1563
  assert statuses["F-002"] == "pending"
@@ -1488,7 +1567,7 @@ class TestAutoSkipIntegration:
1488
1567
  data = json.loads(output)
1489
1568
  assert data["feature_id"] == "F-001"
1490
1569
 
1491
- def test_retry_count_reset_after_unskip(self, tmp_path):
1570
+ def test_retry_count_reset_after_reset_state(self, tmp_path):
1492
1571
  features = [
1493
1572
  _make_feature("F-001", "Root", status="failed"),
1494
1573
  ]
@@ -1502,7 +1581,7 @@ class TestAutoSkipIntegration:
1502
1581
  with open(fs_path, "w") as f:
1503
1582
  json.dump(fs, f)
1504
1583
 
1505
- _run_unskip(fl_path, state_dir, "F-001")
1584
+ _run_reset_state(fl_path, state_dir, "F-001")
1506
1585
 
1507
1586
  with open(fs_path) as f:
1508
1587
  fs = json.load(f)