prizmkit 1.1.156 → 1.1.160

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 (92) hide show
  1. package/bundled/VERSION.json +3 -3
  2. package/bundled/adapters/codebuddy/settings-adapter.js +76 -25
  3. package/bundled/dev-pipeline/prizmkit_runtime/gitops.py +9 -2
  4. package/bundled/dev-pipeline/prizmkit_runtime/reset.py +1 -1
  5. package/bundled/dev-pipeline/prizmkit_runtime/runner_classification.py +20 -11
  6. package/bundled/dev-pipeline/prizmkit_runtime/runtime_commit.py +42 -15
  7. package/bundled/dev-pipeline/scripts/update-feature-status.py +7 -0
  8. package/bundled/dev-pipeline/templates/bootstrap-prompt.md +1 -1
  9. package/bundled/dev-pipeline/templates/bootstrap-tier3.md +1 -1
  10. package/bundled/dev-pipeline/templates/sections/runtime-commit-handoff.md +6 -6
  11. package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +4 -3
  12. package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +2 -2
  13. package/bundled/dev-pipeline/tests/test_generate_refactor_prompt.py +2 -2
  14. package/bundled/dev-pipeline/tests/test_python_runner_parity.py +115 -4
  15. package/bundled/dev-pipeline/tests/test_reset_modes.py +137 -0
  16. package/bundled/dev-pipeline/tests/test_runtime_commit.py +68 -13
  17. package/bundled/dev-pipeline/tests/test_unified_cli.py +12 -7
  18. package/bundled/rules/prizm/prizm-commit-workflow.md +7 -7
  19. package/bundled/rules/prizm/prizm-documentation.md +24 -65
  20. package/bundled/rules/prizm/prizm-progressive-loading.md +9 -8
  21. package/bundled/skills/_metadata.json +1 -1
  22. package/bundled/skills/prizmkit/SKILL.md +1 -13
  23. package/bundled/skills/prizmkit-code-review/SKILL.md +29 -10
  24. package/bundled/skills/prizmkit-code-review/references/independent-code-review.md +5 -4
  25. package/bundled/skills/prizmkit-code-review/references/review-report-template.md +15 -0
  26. package/bundled/skills/prizmkit-code-review/scripts/render_review_report.py +61 -0
  27. package/bundled/skills/prizmkit-committer/SKILL.md +50 -38
  28. package/bundled/skills/prizmkit-deploy/SKILL.md +172 -198
  29. package/bundled/skills/prizmkit-deploy/references/capability-contract.md +137 -0
  30. package/bundled/skills/prizmkit-deploy/references/deploy-record-schema.json +1053 -0
  31. package/bundled/skills/prizmkit-deploy/references/deployment-declaration-schema.json +291 -0
  32. package/bundled/skills/prizmkit-deploy/references/legacy-migration.md +90 -0
  33. package/bundled/skills/prizmkit-deploy/references/policy-and-execution.md +170 -0
  34. package/bundled/skills/prizmkit-deploy/references/real-resource-test-policy.md +73 -0
  35. package/bundled/skills/prizmkit-deploy/references/verification-and-recovery.md +164 -0
  36. package/bundled/skills/prizmkit-deploy/scripts/validate-deploy-artifact.py +371 -0
  37. package/bundled/skills/prizmkit-implement/SKILL.md +2 -2
  38. package/bundled/skills/prizmkit-init/SKILL.md +38 -42
  39. package/bundled/skills/prizmkit-init/references/config-schema.md +11 -7
  40. package/bundled/skills/prizmkit-init/references/rules/layer-detection.md +3 -3
  41. package/bundled/skills/prizmkit-init/references/update-supplement.md +5 -5
  42. package/bundled/skills/prizmkit-plan/SKILL.md +5 -4
  43. package/bundled/skills/prizmkit-plan/assets/plan-template.md +4 -1
  44. package/bundled/skills/prizmkit-plan/references/verification-checklist.md +3 -2
  45. package/bundled/skills/prizmkit-prizm-docs/SKILL.md +17 -11
  46. package/bundled/skills/prizmkit-prizm-docs/assets/prizm-docs-format.md +95 -155
  47. package/bundled/skills/prizmkit-prizm-docs/references/op-init.md +6 -5
  48. package/bundled/skills/prizmkit-prizm-docs/references/op-rebuild.md +4 -2
  49. package/bundled/skills/prizmkit-prizm-docs/references/op-status.md +9 -10
  50. package/bundled/skills/prizmkit-prizm-docs/references/op-update.md +6 -5
  51. package/bundled/skills/prizmkit-prizm-docs/references/op-validate.md +13 -12
  52. package/bundled/skills/prizmkit-retrospective/SKILL.md +3 -3
  53. package/bundled/skills/prizmkit-test/SKILL.md +26 -13
  54. package/bundled/skills/prizmkit-test/references/boundary-contract-and-test-double-guidance.md +8 -4
  55. package/bundled/skills/prizmkit-test/references/independent-test-review.md +7 -3
  56. package/bundled/skills/prizmkit-test/references/test-coverage-model.md +33 -10
  57. package/bundled/skills/prizmkit-test/references/test-report-template.md +33 -11
  58. package/bundled/skills/prizmkit-workflow/SKILL.md +33 -3
  59. package/bundled/skills/prizmkit-workflow/references/workflow-state-protocol.md +23 -5
  60. package/bundled/templates/hooks/commit-intent-status.py +9 -41
  61. package/bundled/templates/hooks/commit-intent.json +3 -3
  62. package/bundled/templates/hooks/diff-prizm-docs.py +3 -1
  63. package/bundled/templates/hooks/prizm-pre-commit.py +32 -6
  64. package/bundled/templates/hooks/run-python-hook.cjs +44 -0
  65. package/bundled/templates/hooks/validate-prizm-docs.py +399 -173
  66. package/bundled/templates/project-memory-template.md +19 -19
  67. package/package.json +1 -1
  68. package/src/clean.js +6 -7
  69. package/src/gitignore-template.js +8 -12
  70. package/src/scaffold.js +125 -71
  71. package/bundled/skills/prizmkit/references/workflow-state-protocol.md +0 -178
  72. package/bundled/skills/prizmkit-deploy/assets/deploy-document-template.md +0 -89
  73. package/bundled/skills/prizmkit-deploy/references/ci-cd-workflows.md +0 -145
  74. package/bundled/skills/prizmkit-deploy/references/cloud-platform-deploy.md +0 -109
  75. package/bundled/skills/prizmkit-deploy/references/data-safety-examples.md +0 -120
  76. package/bundled/skills/prizmkit-deploy/references/database-setup.md +0 -65
  77. package/bundled/skills/prizmkit-deploy/references/deploy-config-schema.md +0 -150
  78. package/bundled/skills/prizmkit-deploy/references/deploy-history-schema.md +0 -78
  79. package/bundled/skills/prizmkit-deploy/references/deploy-metadata-schema.json +0 -49
  80. package/bundled/skills/prizmkit-deploy/references/deployment-modes.md +0 -50
  81. package/bundled/skills/prizmkit-deploy/references/direct-upload.md +0 -26
  82. package/bundled/skills/prizmkit-deploy/references/dns-setup.md +0 -42
  83. package/bundled/skills/prizmkit-deploy/references/docker-deploy.md +0 -31
  84. package/bundled/skills/prizmkit-deploy/references/firewall-setup.md +0 -37
  85. package/bundled/skills/prizmkit-deploy/references/live-validation-notes.md +0 -21
  86. package/bundled/skills/prizmkit-deploy/references/nginx-blue-green.md +0 -59
  87. package/bundled/skills/prizmkit-deploy/references/pending-input-schema.json +0 -164
  88. package/bundled/skills/prizmkit-deploy/references/ssh-adapter-flow.md +0 -221
  89. package/bundled/skills/prizmkit-deploy/references/ssh-bootstrap-flow.md +0 -49
  90. package/bundled/skills/prizmkit-deploy/references/ssh-execution-flow.md +0 -41
  91. package/bundled/skills/prizmkit-deploy/references/ssh-takeover.md +0 -20
  92. package/bundled/skills/prizmkit-deploy/references/ssl-setup.md +0 -56
@@ -1,5 +1,5 @@
1
1
  {
2
- "frameworkVersion": "1.1.156",
3
- "bundledAt": "2026-07-27T23:46:04.550Z",
4
- "bundledFrom": "6d92126"
2
+ "frameworkVersion": "1.1.160",
3
+ "bundledAt": "2026-07-28T13:41:42.840Z",
4
+ "bundledFrom": "cd9688c"
5
5
  }
@@ -1,15 +1,78 @@
1
1
  /**
2
- * CodeBuddy Settings Adapter
3
- * Generates .codebuddy/settings.json with PrizmKit hooks and permissions.
2
+ * CodeBuddy settings adapter.
3
+ * Replaces only deterministic PrizmKit-managed hook entries and preserves user settings.
4
4
  */
5
5
 
6
6
  import { existsSync, mkdirSync } from 'node:fs';
7
7
  import { readFile, writeFile } from 'node:fs/promises';
8
- import path from 'path';
8
+ import path from 'node:path';
9
+
10
+ const MANAGED_MARKERS = [
11
+ '.prizmkit/scripts/commit-intent-status.py',
12
+ '.prizmkit/scripts/post-command-prizm-drift.py',
13
+ 'PRIZMKIT_DOC_UPDATE_REQUIRED',
14
+ ];
15
+
16
+ function isManaged(entry) {
17
+ let serialized;
18
+ try {
19
+ serialized = JSON.stringify(entry);
20
+ } catch {
21
+ return false;
22
+ }
23
+ return MANAGED_MARKERS.some(marker => serialized.includes(marker));
24
+ }
25
+
26
+ function mergeManagedHooks(existingHooks = {}, managedHooks = {}) {
27
+ if (!existingHooks || typeof existingHooks !== 'object' || Array.isArray(existingHooks)) {
28
+ throw new Error('Cannot preserve malformed CodeBuddy hooks: hooks must be an object');
29
+ }
30
+ const merged = {};
31
+ for (const [event, entries] of Object.entries(existingHooks)) {
32
+ if (!Array.isArray(entries)) {
33
+ throw new Error(`Cannot preserve malformed CodeBuddy hooks: ${event} must be an array`);
34
+ }
35
+ merged[event] = entries.filter(entry => !isManaged(entry));
36
+ }
37
+ for (const [event, entries] of Object.entries(managedHooks)) {
38
+ if (!Array.isArray(entries)) {
39
+ throw new Error(`Managed CodeBuddy hook template is invalid: ${event} must be an array`);
40
+ }
41
+ merged[event] = [
42
+ ...(Array.isArray(merged[event]) ? merged[event] : []),
43
+ ...entries,
44
+ ];
45
+ }
46
+ return merged;
47
+ }
48
+
49
+ const MANAGED_HOOKS = {
50
+ UserPromptSubmit: [
51
+ {
52
+ matcher: '(?i)\\b(commit|push|finish|ship|merge|pull request|pr)\\b|提交|推送|收尾|完成任务|合并|发版|发布',
53
+ hooks: [
54
+ {
55
+ type: 'command',
56
+ command: 'node .prizmkit/scripts/run-python-hook.cjs .prizmkit/scripts/commit-intent-status.py',
57
+ },
58
+ ],
59
+ },
60
+ ],
61
+ PostToolUse: [
62
+ {
63
+ matcher: '.*',
64
+ hooks: [
65
+ {
66
+ type: 'command',
67
+ command: 'node .prizmkit/scripts/run-python-hook.cjs .prizmkit/scripts/post-command-prizm-drift.py',
68
+ },
69
+ ],
70
+ },
71
+ ],
72
+ };
9
73
 
10
74
  /**
11
- * Generate CodeBuddy settings.json for a PrizmKit-enabled project.
12
- * @param {string} targetRoot - Target project root
75
+ * @param {string} targetRoot
13
76
  * @param {Object} options - { hooks: boolean }
14
77
  */
15
78
  export async function generateSettings(targetRoot, options = {}) {
@@ -20,28 +83,16 @@ export async function generateSettings(targetRoot, options = {}) {
20
83
  if (existsSync(settingsPath)) {
21
84
  try {
22
85
  existing = JSON.parse(await readFile(settingsPath, 'utf8'));
23
- } catch {
24
- existing = {};
86
+ } catch (error) {
87
+ throw new Error(`Cannot preserve malformed CodeBuddy settings: ${error.message}`);
25
88
  }
26
- }
27
-
28
- // Merge PrizmKit hooks
29
- if (options.hooks !== false) {
30
- if (!existing.hooks) existing.hooks = {};
31
- if (!existing.hooks.UserPromptSubmit) {
32
- existing.hooks.UserPromptSubmit = [
33
- {
34
- matcher: '(?i)\\b(commit|push|finish|ship|merge|pull request|pr)\\b|提交|推送|收尾|完成任务|合并|发版|发布',
35
- hooks: [
36
- {
37
- type: 'prompt',
38
- prompt: 'You are a commit-intent detector for PrizmKit. Analyze the user prompt and determine if the user intends to COMMIT, PUSH, FINISH, SHIP, MERGE, or create a PULL REQUEST.\n\nUser prompt: $ARGUMENTS\n\nIF commit intent detected, respond with:\n{"ok": true, "reason": "PRIZMKIT_DOC_UPDATE_REQUIRED: Before committing, you MUST update .prizmkit/prizm-docs/ per Prizm auto-update protocol. Steps: 1) Run git diff --cached --name-status. 2) Map changed files to modules via root.prizm MODULE_INDEX. 3) Read and update affected .prizm files (only changed sections). 4) Append to changelog.prizm. 5) Stage .prizm files with git add .prizmkit/prizm-docs/. 6) Then proceed with commit using prizmkit-committer workflow. RULES: Never rewrite entire .prizm files. Never add prose. Only update affected sections."}\n\nIF no commit intent, respond with:\n{"ok": true}\n\nRespond with JSON only. No explanation.',
39
- },
40
- ],
41
- },
42
- ];
89
+ if (!existing || typeof existing !== 'object' || Array.isArray(existing)) {
90
+ throw new Error('Cannot preserve malformed CodeBuddy settings: root must be an object');
43
91
  }
44
92
  }
45
93
 
46
- await writeFile(settingsPath, JSON.stringify(existing, null, 2));
94
+ const settings = options.hooks === false
95
+ ? existing
96
+ : { ...existing, hooks: mergeManagedHooks(existing.hooks, MANAGED_HOOKS) };
97
+ await writeFile(settingsPath, JSON.stringify(settings, null, 2));
47
98
  }
@@ -17,8 +17,15 @@ PIPELINE_METADATA_EXCLUDES = (
17
17
  ":(top,exclude,glob).*/worktree/**",
18
18
  ":(top,exclude,glob).*/worktrees",
19
19
  ":(top,exclude,glob).*/worktrees/**",
20
- ":(top,exclude).prizmkit",
21
- ":(top,exclude,glob).prizmkit/**",
20
+ ":(top,exclude).prizmkit/dev-pipeline",
21
+ ":(top,exclude,glob).prizmkit/dev-pipeline/**",
22
+ ":(top,exclude).prizmkit/state",
23
+ ":(top,exclude,glob).prizmkit/state/**",
24
+ ":(top,exclude).prizmkit/scripts",
25
+ ":(top,exclude,glob).prizmkit/scripts/**",
26
+ ":(top,exclude).prizmkit/manifest.json",
27
+ ":(top,exclude,glob).prizmkit/specs/**/workflow-checkpoint.json",
28
+ ":(top,exclude,glob).prizmkit/specs/**/runtime-commit-request.json",
22
29
  )
23
30
 
24
31
  HIDDEN_TOOL_WORKTREE_EXCLUDES = (
@@ -115,7 +115,7 @@ def run_reset_command(kind: str, legacy_args: tuple[str, ...], paths) -> Command
115
115
  list_path = _resolve_list_path(options.list_path, paths.project_root)
116
116
  if not list_path.is_file():
117
117
  return CommandResult(1, f"Python {kind} reset", f"{kind} list not found: {list_path}")
118
- if (options.fresh_checkout or options.clean) and not (family.state_dir / "pipeline.json").is_file():
118
+ if options.fresh_checkout and not (family.state_dir / "pipeline.json").is_file():
119
119
  return CommandResult(1, f"Python {kind} reset", f"No pipeline state found. Run the {kind} pipeline first to initialize.")
120
120
 
121
121
  options = ResetOptions(
@@ -92,17 +92,7 @@ def classify_session(
92
92
  )
93
93
 
94
94
  semantic = checkpoint.semantic_snapshot if checkpoint is not None else {}
95
- if _is_terminal_success(result):
96
- reason = "no_semantic_completion"
97
- if checkpoint is not None and checkpoint.semantic.error_code:
98
- reason = f"{reason}:{checkpoint.semantic.error_code}"
99
- return SessionClassification(
100
- WORKFLOW_SKIPPED,
101
- reason=reason,
102
- progress_fingerprint=fingerprint,
103
- checkpoint_state=semantic,
104
- )
105
- if _is_context_overflow(result):
95
+ if _is_recoverable_context_interruption(result):
106
96
  no_progress_count = _next_no_progress_count(previous_fingerprint, fingerprint, previous_no_progress_count)
107
97
  if no_progress_count >= 2:
108
98
  return SessionClassification(
@@ -121,6 +111,16 @@ def classify_session(
121
111
  no_progress_count=no_progress_count,
122
112
  checkpoint_state=semantic,
123
113
  )
114
+ if _is_terminal_success(result):
115
+ reason = "no_semantic_completion"
116
+ if checkpoint is not None and checkpoint.semantic.error_code:
117
+ reason = f"{reason}:{checkpoint.semantic.error_code}"
118
+ return SessionClassification(
119
+ WORKFLOW_SKIPPED,
120
+ reason=reason,
121
+ progress_fingerprint=fingerprint,
122
+ checkpoint_state=semantic,
123
+ )
124
124
 
125
125
  if result.termination_reason == "stale_session":
126
126
  return SessionClassification(
@@ -275,6 +275,15 @@ def _next_no_progress_count(previous: object | None, current: object, count: int
275
275
  return 0
276
276
 
277
277
 
278
+ def _is_recoverable_context_interruption(result: AISessionResult) -> bool:
279
+ """Recognize provider limits that should continue an incomplete workflow."""
280
+ if _is_terminal_success(result):
281
+ # Pi reports a provider token/length limit as a successful result event.
282
+ # Semantic completion was already handled before this helper is called.
283
+ return result.progress_summary.stop_reason.strip().lower() == "length"
284
+ return _is_context_overflow(result)
285
+
286
+
278
287
  def _is_context_overflow(result: AISessionResult) -> bool:
279
288
  if (result.fatal_error_code or "").lower() == CONTEXT_OVERFLOW:
280
289
  return True
@@ -106,9 +106,9 @@ def finalize_runtime_commit(
106
106
  return RuntimeCommitResult("not_ready", "runtime_commit_already_finalized")
107
107
  return RuntimeCommitResult("failed", error or "invalid_commit_request")
108
108
 
109
- if any(_is_tracked(root, path) for path in (request_path, checkpoint)):
110
- return RuntimeCommitResult("failed", "runtime_metadata_must_be_untracked")
111
-
109
+ # Request/checkpoint paths are excluded by their exact Runtime bookkeeping role.
110
+ # They may be project-tracked; commit verification below ensures their pre/post-
111
+ # commit writes never enter the prepared snapshot.
112
112
  current_head = _git(root, "rev-parse", "HEAD")
113
113
  if current_head.return_code != 0:
114
114
  return RuntimeCommitResult("failed", "git_head_unavailable")
@@ -133,7 +133,15 @@ def finalize_runtime_commit(
133
133
  staged = _stage_intended_paths(root, request.intended_paths)
134
134
  if staged.return_code != 0:
135
135
  return RuntimeCommitResult("failed", "git_stage_failed")
136
- if _git(root, "diff", "--cached", "--quiet", "--exit-code").return_code == 0:
136
+ staged_paths = _git(
137
+ root, "diff", "--cached", "--name-only", "--no-renames", "-z",
138
+ )
139
+ if staged_paths.return_code != 0:
140
+ return RuntimeCommitResult("failed", "git_staged_set_unavailable")
141
+ staged_set = {path for path in staged_paths.stdout.split("\0") if path}
142
+ if staged_set != set(request.intended_paths):
143
+ return RuntimeCommitResult("failed", "staged_paths_mismatch")
144
+ if not staged_set:
137
145
  return RuntimeCommitResult("failed", "empty_staged_change")
138
146
  committed = _git(
139
147
  root,
@@ -320,7 +328,21 @@ def _known_support_path(lower_path: str) -> bool:
320
328
  and parts[1] in {"worktree", "worktrees"}
321
329
  ):
322
330
  return True
323
- return lower_path == ".prizmkit" or lower_path.startswith(".prizmkit/")
331
+ if lower_path in {".prizmkit/manifest.json"}:
332
+ return True
333
+ if any(
334
+ lower_path == prefix or lower_path.startswith(prefix + "/")
335
+ for prefix in (
336
+ ".prizmkit/dev-pipeline",
337
+ ".prizmkit/state",
338
+ ".prizmkit/scripts",
339
+ )
340
+ ):
341
+ return True
342
+ return (
343
+ lower_path.startswith(".prizmkit/specs/")
344
+ and path.name in {REQUEST_FILENAME, "workflow-checkpoint.json"}
345
+ )
324
346
 
325
347
 
326
348
  def _status_record_paths(stdout: str) -> tuple[str, ...]:
@@ -342,8 +364,21 @@ def _status_record_paths(stdout: str) -> tuple[str, ...]:
342
364
 
343
365
 
344
366
  def _stage_intended_paths(project_root: Path, paths: Sequence[str]) -> _GitResult:
345
- pathspecs = tuple(f":(top,literal){path}" for path in paths)
346
- return _git(project_root, "add", "-A", "--", *pathspecs)
367
+ tracked: list[str] = []
368
+ untracked: list[str] = []
369
+ for path in paths:
370
+ pathspec = f":(top,literal){path}"
371
+ indexed = _git(project_root, "ls-files", "--error-unmatch", "--", pathspec)
372
+ (tracked if indexed.return_code == 0 else untracked).append(pathspec)
373
+ if tracked:
374
+ updated = _git(project_root, "add", "-u", "--", *tracked)
375
+ if updated.return_code != 0:
376
+ return updated
377
+ if untracked:
378
+ added = _git(project_root, "add", "--", *untracked)
379
+ if added.return_code != 0:
380
+ return added
381
+ return _GitResult(0, "", "")
347
382
 
348
383
 
349
384
  def _matches_prepared_commit(project_root: Path, request: RuntimeCommitRequest, head: str) -> bool:
@@ -378,14 +413,6 @@ def _record_runtime_commit_hash(path: Path, commit_hash: str) -> str:
378
413
  return "commit_request_hash_record_failed" if error else ""
379
414
 
380
415
 
381
- def _is_tracked(project_root: Path, path: Path) -> bool:
382
- try:
383
- relative = path.relative_to(project_root).as_posix()
384
- except ValueError:
385
- return True
386
- return _git(project_root, "ls-files", "--error-unmatch", "--", relative).return_code == 0
387
-
388
-
389
416
  def _finalize_checkpoint(
390
417
  path: Path,
391
418
  *,
@@ -1726,6 +1726,13 @@ def action_clean(args, feature_list_path, state_dir):
1726
1726
  fs["last_session_id"] = None
1727
1727
  fs["resume_from_phase"] = None
1728
1728
  reset_continuation_metadata(fs)
1729
+ for stale_field in (
1730
+ "repair_scope",
1731
+ "repair_round",
1732
+ "blocked_reason",
1733
+ "terminal_status",
1734
+ ):
1735
+ fs.pop(stale_field, None)
1729
1736
  fs["updated_at"] = now_iso()
1730
1737
 
1731
1738
  err = save_feature_status(state_dir, feature_id, fs)
@@ -38,7 +38,7 @@ Complete the feature in headless non-interactive mode using the active atomic sk
38
38
  5. Invoke `/prizmkit-test scope=this-change artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/`. Validate its report/result pair. For `TEST_NEEDS_FIXES`, classify the concrete correction into an allowed `repair_scope`; unknown/unsafe scope blocks, while a safe in-budget route re-enters Implement and requires fresh Review, configured verification, and Test. Do not duplicate the Skill's internal repair loop.
39
39
  6. Write `completion-summary.json` before retrospective and commit preparation.
40
40
  7. Invoke `/prizmkit-retrospective` with the exact artifact root, non-`.prizmkit/` `change_paths`, and `change_summary`; validate `outcome=RETRO_COMPLETE`.
41
- 8. Before commit preparation, all `.prizmkit/**` paths are PrizmKit-internal and stay outside `intended_paths` together with recognized platform support; project-specific transient data must already be Git-ignored, while unknown Git-visible paths block. After validating every required artifact, invoke `/prizmkit-committer operation=prepare-runtime-commit artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/ evidence_paths=<exact paths> excluded_paths=.prizmkit/specs/{{FEATURE_SLUG}}/workflow-checkpoint.json request_path=.prizmkit/specs/{{FEATURE_SLUG}}/runtime-commit-request.json`. Require `COMMIT_REQUEST_READY`; this session then records `COMMIT_PENDING` and stops. The Python runtime executes and verifies the local commit.
41
+ 8. Before commit preparation, classify paths by semantic role rather than a blanket `.prizmkit/**` rule. Safe Git-visible framework paths may be exact task output; ignored paths remain absent, and exact Runtime bookkeeping/installed support, host support, Secrets, unrelated, or unknown paths remain excluded or blocking. No path is force-added and no ignore policy is changed. After validating every required artifact, invoke `/prizmkit-committer operation=prepare-runtime-commit artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/ evidence_paths=<exact paths> excluded_paths=.prizmkit/specs/{{FEATURE_SLUG}}/workflow-checkpoint.json request_path=.prizmkit/specs/{{FEATURE_SLUG}}/runtime-commit-request.json`. Require `COMMIT_REQUEST_READY`; this session then records `COMMIT_PENDING` and stops. The Python runtime executes and verifies the local commit.
42
42
 
43
43
  ## Failure Capture
44
44
 
@@ -448,7 +448,7 @@ Invoke `/prizmkit-retrospective` with the exact artifact root, exact non-`.prizm
448
448
 
449
449
  **6c. Runtime commit preparation**
450
450
 
451
- Before commit preparation, all `.prizmkit/**` paths are PrizmKit-internal and stay outside `intended_paths`, together with `AGENTS.md`, `skills-lock.json`, installed platform directories, and local platform settings. Project-specific transient data must already be covered by Git ignore rules. Unknown Git-visible paths are not silently ignored: justify and include them as task output or block.
451
+ Before commit preparation, classify paths by semantic role rather than a blanket `.prizmkit/**` exclusion. Safe Git-visible framework paths may be justified and included as exact task output; ignored paths remain naturally absent. Exact Runtime request/checkpoint/state and installed Runtime/host support stay outside `intended_paths`; Secrets, unrelated, and unknown Git-visible paths block. Never force-add or change/interpret project ignore policy.
452
452
 
453
453
  After this injected session validates every required artifact, invoke `/prizmkit-committer operation=prepare-runtime-commit artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/ evidence_paths=<exact paths> excluded_paths=.prizmkit/specs/{{FEATURE_SLUG}}/workflow-checkpoint.json request_path=.prizmkit/specs/{{FEATURE_SLUG}}/runtime-commit-request.json`. Require `COMMIT_REQUEST_READY`; this session records `COMMIT_PENDING` and stops. The Python runtime validates the request, executes/verifies the local commit, and finalizes checkpoint `COMMITTED`.
454
454
 
@@ -11,11 +11,11 @@ After Code Review, all configured verification, `TEST_PASS`, family reports/summ
11
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
12
  ```
13
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.
14
+ 3. The committer validates only the supplied evidence and final diff, then classifies paths by semantic role before writing the request:
15
+ - safe Git-visible `.prizmkit/**` requirement output is admitted like any other exact task path and needs no documentation-specific evidence;
16
+ - ignored paths remain absent and are never force-added; project ignore policy is not changed or interpreted;
17
+ - exact Runtime request/checkpoint/state, installed Runtime/host payloads, and local host settings remain support/bookkeeping outside the task commit;
18
+ - global Secret checks still apply, and every unrelated or unknown Git-visible path blocks rather than disappearing.
19
19
 
20
20
  It then rejects sensitive/unrelated/unknown paths, generates one Conventional Commit message, and writes this request without staging or committing:
21
21
 
@@ -32,4 +32,4 @@ After Code Review, all configured verification, `TEST_PASS`, family reports/summ
32
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
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
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.
35
+ The Runtime validates exact task-owned path coverage outside recognized semantic support/bookkeeping, does not reject a safe path solely because it is under `.prizmkit/**`, stages only requested literal paths, verifies staged/committed set equality and the Git receipt, and only then writes the Runtime-owned receipt/checkpoint and performs configured integration. Those post-commit writes are never inserted retroactively into the committed snapshot or allowed to falsify integration. 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.
@@ -1556,9 +1556,10 @@ class TestFeatureBootstrapShellExtraction:
1556
1556
  assert "/prizmkit-committer operation=prepare-runtime-commit" in tier3
1557
1557
  assert "Require `COMMIT_REQUEST_READY`; this session records `COMMIT_PENDING`" in tier3
1558
1558
  assert "The Python runtime validates the request" in tier3
1559
- assert "all `.prizmkit/**` paths are PrizmKit-internal" in tier3
1560
- assert "project-specific transient data must already be covered by git ignore rules" in tier3.lower()
1561
- assert "Unknown Git-visible paths are not silently ignored" in tier3
1559
+ assert "classify paths by semantic role rather than a blanket `.prizmkit/**` exclusion" in tier3
1560
+ assert "Safe Git-visible framework paths" in tier3
1561
+ assert "Never force-add or change/interpret project ignore policy" in tier3
1562
+ assert "unknown Git-visible paths block" in tier3
1562
1563
  assert "git add" not in tier3
1563
1564
  assert "git commit" not in tier3
1564
1565
 
@@ -596,8 +596,8 @@ class TestBugfixCheckpointGeneration:
596
596
  assert "operation=prepare-runtime-commit" in prompt
597
597
  assert "NEVER ask for user confirmation" in prompt
598
598
  assert "The Python runtime, not the AI session, executes" in prompt
599
- assert "all `.prizmkit/**` paths are PrizmKit-internal" in prompt
600
- assert "Unknown Git-visible paths are not silently ignored" in prompt
599
+ assert "safe Git-visible `.prizmkit/**` requirement output is admitted" in prompt
600
+ assert "unknown Git-visible path blocks" in prompt
601
601
  assert "push_authorized\": true" not in prompt
602
602
  assert ".prizmkit/bugfix/B-001/" in prompt
603
603
  assert "write the session status" not in prompt.lower()
@@ -435,8 +435,8 @@ class TestRefactorCheckpointGeneration:
435
435
  assert "local_commit_authorized" not in prompt
436
436
  assert "operation=prepare-runtime-commit" in prompt
437
437
  assert "The Python runtime, not the AI session, executes" in prompt
438
- assert "all `.prizmkit/**` paths are PrizmKit-internal" in prompt
439
- assert "Unknown Git-visible paths are not silently ignored" in prompt
438
+ assert "safe Git-visible `.prizmkit/**` requirement output is admitted" in prompt
439
+ assert "unknown Git-visible path blocks" in prompt
440
440
  assert "automatic push" not in prompt.lower()
441
441
  assert "push_authorized\": true" not in prompt
442
442
  assert "write the session status" not in prompt.lower()
@@ -4015,7 +4015,7 @@ def test_pi_length_stop_with_nonzero_exit_uses_bounded_crash_path(tmp_path):
4015
4015
  assert classification.fatal_error_code == ""
4016
4016
 
4017
4017
 
4018
- def test_pi_length_stop_with_zero_exit_and_no_checkpoint_uses_no_completion_policy(tmp_path):
4018
+ def test_pi_length_stop_with_zero_exit_and_no_checkpoint_uses_recoverable_continuation(tmp_path):
4019
4019
  from dataclasses import replace
4020
4020
 
4021
4021
  from prizmkit_runtime.runner_classification import classify_session
@@ -4029,9 +4029,120 @@ def test_pi_length_stop_with_zero_exit_and_no_checkpoint_uses_no_completion_poli
4029
4029
 
4030
4030
  classification = classify_session(raw, project_root=tmp_path, base_head=base_head)
4031
4031
 
4032
- assert classification.session_status == "workflow_skipped"
4033
- assert classification.reason == "no_semantic_completion"
4034
- assert classification.fatal_error_code == ""
4032
+ assert classification.session_status == "context_overflow"
4033
+ assert classification.reason == "context_overflow"
4034
+ assert classification.fatal_error_code == "context_overflow"
4035
+
4036
+
4037
+ def test_pi_length_stop_with_in_progress_checkpoint_uses_recoverable_continuation(tmp_path):
4038
+ from dataclasses import replace
4039
+
4040
+ from prizmkit_runtime.runner_classification import classify_session
4041
+ from prizmkit_runtime.runner_models import PromptGenerationResult
4042
+ from prizmkit_runtime.status import ProgressSummary
4043
+
4044
+ base_head = _init_git_repo_for_invalid_checkpoint_test(tmp_path)
4045
+ artifact_dir = tmp_path / ".prizmkit" / "specs" / "001-length-in-progress"
4046
+ artifact_dir.mkdir(parents=True)
4047
+ checkpoint = artifact_dir / "workflow-checkpoint.json"
4048
+ checkpoint.write_text(
4049
+ json.dumps({
4050
+ "version": 1,
4051
+ "workflow_type": "feature-pipeline",
4052
+ "steps": [
4053
+ {
4054
+ "id": "S01",
4055
+ "skill": "context-snapshot-and-plan",
4056
+ "name": "Specify & Plan",
4057
+ "status": "completed",
4058
+ "required_artifacts": [],
4059
+ "depends_on": None,
4060
+ "stage_result": "PLAN_READY",
4061
+ },
4062
+ {
4063
+ "id": "S02",
4064
+ "skill": "prizmkit-implement",
4065
+ "name": "Implement",
4066
+ "status": "completed",
4067
+ "required_artifacts": [],
4068
+ "depends_on": "S01",
4069
+ "stage_result": "IMPLEMENTED",
4070
+ },
4071
+ {
4072
+ "id": "S03",
4073
+ "skill": "prizmkit-code-review",
4074
+ "name": "Code Review",
4075
+ "status": "in_progress",
4076
+ "required_artifacts": [],
4077
+ "depends_on": "S02",
4078
+ },
4079
+ {
4080
+ "id": "S04",
4081
+ "skill": "prizmkit-test",
4082
+ "name": "Test",
4083
+ "status": "pending",
4084
+ "required_artifacts": [],
4085
+ "depends_on": "S03",
4086
+ },
4087
+ {
4088
+ "id": "S05",
4089
+ "skill": "completion-summary",
4090
+ "name": "Completion Summary",
4091
+ "status": "pending",
4092
+ "required_artifacts": [],
4093
+ "depends_on": "S04",
4094
+ },
4095
+ {
4096
+ "id": "S06",
4097
+ "skill": "prizmkit-retrospective",
4098
+ "name": "Retrospective",
4099
+ "status": "pending",
4100
+ "required_artifacts": [],
4101
+ "depends_on": "S05",
4102
+ },
4103
+ {
4104
+ "id": "S07",
4105
+ "skill": "prizmkit-committer",
4106
+ "name": "Runtime Commit Handoff",
4107
+ "status": "pending",
4108
+ "required_artifacts": [],
4109
+ "depends_on": "S06",
4110
+ },
4111
+ ],
4112
+ "feature_state": {
4113
+ "stage": "code-review",
4114
+ "current_stage": "prizmkit-code-review",
4115
+ "status": "in_progress",
4116
+ "repair_scope": None,
4117
+ "repair_round": 0,
4118
+ "next_stage": "prizmkit-code-review",
4119
+ "blocked_reason": None,
4120
+ "terminal_status": None,
4121
+ },
4122
+ }),
4123
+ encoding="utf-8",
4124
+ )
4125
+ prompt = PromptGenerationResult(
4126
+ output_path=tmp_path / "prompt.md",
4127
+ checkpoint_path=checkpoint,
4128
+ artifact_path=artifact_dir,
4129
+ )
4130
+ raw = replace(
4131
+ _terminal_success_result(tmp_path),
4132
+ progress_summary=ProgressSummary(result_subtype="success", stop_reason="length"),
4133
+ )
4134
+
4135
+ classification = classify_session(
4136
+ raw,
4137
+ project_root=tmp_path,
4138
+ base_head=base_head,
4139
+ prompt=prompt,
4140
+ )
4141
+
4142
+ assert classification.session_status == "context_overflow"
4143
+ assert classification.reason == "context_overflow"
4144
+ assert classification.fatal_error_code == "context_overflow"
4145
+ assert classification.checkpoint_state["current_stage"] == "prizmkit-code-review"
4035
4146
 
4036
4147
 
4037
4148
  def test_pi_length_stop_does_not_override_completed_checkpoint(tmp_path):