prizmkit 1.1.155 → 1.1.159

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 (35) hide show
  1. package/bundled/VERSION.json +3 -3
  2. package/bundled/dev-pipeline/prizmkit_runtime/reset.py +1 -1
  3. package/bundled/dev-pipeline/prizmkit_runtime/runner_classification.py +20 -11
  4. package/bundled/dev-pipeline/scripts/update-feature-status.py +7 -0
  5. package/bundled/dev-pipeline/tests/test_python_runner_parity.py +115 -4
  6. package/bundled/dev-pipeline/tests/test_reset_modes.py +137 -0
  7. package/bundled/dev-pipeline/tests/test_unified_cli.py +2 -1
  8. package/bundled/skills/_metadata.json +1 -1
  9. package/bundled/skills/prizmkit/SKILL.md +1 -13
  10. package/bundled/skills/prizmkit-code-review/SKILL.md +29 -10
  11. package/bundled/skills/prizmkit-code-review/references/independent-code-review.md +5 -4
  12. package/bundled/skills/prizmkit-code-review/references/review-report-template.md +15 -0
  13. package/bundled/skills/prizmkit-code-review/scripts/render_review_report.py +61 -0
  14. package/bundled/skills/prizmkit-committer/SKILL.md +22 -17
  15. package/bundled/skills/prizmkit-init/SKILL.md +21 -25
  16. package/bundled/skills/prizmkit-init/references/config-schema.md +11 -7
  17. package/bundled/skills/prizmkit-init/references/rules/layer-detection.md +3 -3
  18. package/bundled/skills/prizmkit-plan/SKILL.md +5 -4
  19. package/bundled/skills/prizmkit-plan/assets/plan-template.md +4 -1
  20. package/bundled/skills/prizmkit-plan/references/verification-checklist.md +3 -2
  21. package/bundled/skills/prizmkit-prizm-docs/SKILL.md +64 -10
  22. package/bundled/skills/prizmkit-prizm-docs/assets/prizm-docs-format.md +191 -56
  23. package/bundled/skills/prizmkit-prizm-docs/references/op-init.md +18 -18
  24. package/bundled/skills/prizmkit-prizm-docs/references/op-rebuild.md +14 -8
  25. package/bundled/skills/prizmkit-prizm-docs/references/op-status.md +12 -5
  26. package/bundled/skills/prizmkit-prizm-docs/references/op-update.md +23 -12
  27. package/bundled/skills/prizmkit-prizm-docs/references/op-validate.md +13 -9
  28. package/bundled/skills/prizmkit-retrospective/SKILL.md +72 -61
  29. package/bundled/skills/prizmkit-retrospective/references/knowledge-injection-steps.md +79 -37
  30. package/bundled/skills/prizmkit-retrospective/references/structural-sync-steps.md +109 -46
  31. package/bundled/skills/prizmkit-workflow/SKILL.md +35 -3
  32. package/bundled/skills/prizmkit-workflow/references/workflow-state-protocol.md +24 -5
  33. package/bundled/templates/hooks/validate-prizm-docs.py +124 -12
  34. package/package.json +1 -1
  35. package/bundled/skills/prizmkit/references/workflow-state-protocol.md +0 -178
@@ -1,90 +1,153 @@
1
- # Structural Sync — Detailed Steps
1
+ # Structural Sync — Capacity-Safe Detailed Steps
2
2
 
3
3
  ## 1. Validate supplied changed files
4
4
 
5
5
  Use only the caller-supplied `change_paths`. Normalize each repository-relative path, reject paths outside the checkout or under `.prizmkit/`, and verify its current added/modified/deleted/renamed state with exact pathspecs.
6
6
 
7
- Do not expand the path set through repository-wide status or diff discovery. If the validated list is empty, structural sync is not needed.
7
+ Do not expand the path set through repository-wide status or diff discovery. Never run an unconditional repository-wide documentation rewrite. If the validated list is empty, structural sync is not needed.
8
8
 
9
- ## 2. Map files to modules
9
+ ## 2. Map exact changes to a bounded target set
10
10
 
11
- Read `.prizmkit/prizm-docs/root.prizm` and map each changed file to MODULE_INDEX or MODULE_GROUPS entries.
11
+ Read `.prizmkit/prizm-docs/root.prizm` only as the project map, then map each exact changed path through its MODULE_INDEX or MODULE_GROUPS pointer to the most specific existing documentation owner.
12
12
 
13
- If a changed source file maps to no module, evaluate whether its directory qualifies as a new module:
13
+ The writable set contains only:
14
14
 
15
- - Contains source files forming a logical unit
16
- - Contains entry/config/interface files
17
- - Contains qualifying submodules
18
- - Is referenced by multiple modules as a dependency
15
+ - the most specific detail targets that own eligible changed paths;
16
+ - their necessary direct parent summary or pointer at each affected level;
17
+ - a new detail target only when the eligible source change proves meaningful durable behavior and deterministic identity;
18
+ - root only when module structure or its resolving module/group pointer changes.
19
19
 
20
- ## 3. Classify changes
20
+ Affected docs may be read to reconcile current content and resolve pointers, but they cannot independently add source facts or pull sibling docs into the writable set. Do not clean unrelated targets merely because they are stale or near a limit.
21
21
 
22
- - `A` added add to KEY_FILES and check for new public interfaces
23
- - `D` deleted → remove from KEY_FILES and update file counts
24
- - `M` modified → check public interfaces, dependencies, data flow, and durable traps/decisions
25
- - `R` renamed → update path references
22
+ If a changed source path maps to no module, evaluate only that path and narrowly required directory context to determine whether its directory is a real logical module with entry/config/interface files or cross-module dependency use. Do not perform a repository scan to manufacture a module.
26
23
 
27
- ## 4. Decide whether sync is needed
24
+ ## 3. Classify eligible structural changes
28
25
 
29
- Skip structural sync when changes are limited to:
26
+ - `A` added: update navigation only when the file passes the Value Gate; check source-established public/wire contracts.
27
+ - `D` deleted: remove stale owned navigation and source-invalidated knowledge.
28
+ - `M` modified: check non-obvious public/wire interfaces, dependencies, data flow, behavior, traps, rules, and decisions.
29
+ - `R` renamed: update only implicated ownership and resolving paths.
30
30
 
31
- - comments, whitespace, or formatting
32
- - internal implementation details with no interface, dependency, data-flow, or module mapping impact
33
- - test-only changes that reveal no durable boundaries, traps, interface constraints, behavior rules, or regression knowledge
31
+ Skip structural writes for comments, whitespace, formatting, internal implementation detail with no durable contract/behavior impact, and test-only changes that reveal no durable boundary. Do not skip a bug or test change when its exact source evidence changes durable behavior or constraints.
34
32
 
35
- Do not skip automatically just because the task is a bug fix or test change. Run the relevant part of retrospective when the change affects structure, interfaces, dependencies, observable behavior, or durable knowledge.
33
+ ## 4. Select the most specific detail identity
36
34
 
37
- ## 5. Update affected docs bottom-up
35
+ ### Mirrored source identity
38
36
 
39
- ### Detail documentation
37
+ When identities compete, mirrored source identity takes precedence.
40
38
 
41
- If a relevant detail document exists, update only sections affected by supplied changed files in that module.
39
+ A real source submodule uses its mirrored detail path. Mirrored source identity takes precedence over a semantic concern with the same path or meaning. Update an existing mirrored detail before considering a semantic split.
42
40
 
43
- If detail documentation does not exist and the supplied changes include Added or Modified source files with meaningful logic, create it with:
41
+ A new mirrored detail uses these required sections:
44
42
 
45
43
  ```text
46
44
  MODULE
47
45
  FILES
48
46
  RESPONSIBILITY
47
+ INTERFACES
49
48
  KEY_FILES
50
49
  DEPENDENCIES
51
- INTERFACES
52
50
  TRAPS
53
51
  ```
54
52
 
55
- Add DATA_FLOW, RULES, or DECISIONS only when the changed files provide durable information for those sections. Populate from the diff files and targeted source reads, not from an unbounded full-module rescan.
53
+ Add `DATA_FLOW`, `RULES`, `DECISIONS`, rejected alternatives, or domain sections only for facts that pass the Value Gate.
54
+
55
+ ### Deterministic semantic concern identity
56
+
57
+ For a flat source module, create a semantic concern detail only when current eligible source proves multiple stable product/domain behavior concerns and protected durable knowledge cannot fit one 5120B detail after safe cleanup. A semantic concern is not another documentation level.
58
+
59
+ Derive one deterministic concern slug:
60
+
61
+ 1. Choose a concise stable product/domain concern name from current source responsibility; task, change, file-count, or temporary initiative labels are invalid.
62
+ 2. Normalize the name with Unicode NFKC.
63
+ 3. Apply Unicode lowercase.
64
+ 4. Replace each maximal run of characters that is neither a Unicode letter nor a Unicode decimal digit with one ASCII hyphen.
65
+ 5. Trim leading/trailing hyphens and require one non-empty, unambiguous lowercase kebab-case result.
66
+ 6. Compare it with sibling semantic concerns, sibling `DETAILS` entries, and mirrored submodule paths. Task IDs, numeric suffixes, timestamps, and branch names are prohibited as collision workarounds.
67
+
68
+ The detail path is `.prizmkit/prizm-docs/<module>/<concern-slug>.prizm`. It has `MODULE`, `CONCERN`, `FILES`, `RESPONSIBILITY`, `INTERFACES`, `DATA_FLOW`, `KEY_FILES`, `DEPENDENCIES`, `RULES`, `TRAPS`, and `DECISIONS`; use `<SECTION>: none` rather than invented filler when a required behavioral section has no qualifying fact.
69
+
70
+ `FILES` is a non-empty exhaustive normalized source-file ownership list for the concern. Sibling semantic details require explicit non-overlapping `FILES` ownership. The direct module parent has exactly one `DETAILS` pointer:
71
+
72
+ ```text
73
+ - <concern-slug>: <concise stable behavior summary> -> .prizmkit/prizm-docs/<module>/<concern-slug>.prizm
74
+ ```
75
+
76
+ The pointer path, target `MODULE`, normalized `CONCERN` slug, and `FILES` ownership must agree. Mirrored source identity takes precedence; ambiguity, collision, or overlapping ownership blocks the split. Never add a suffix or partial semantic document to guess around it.
77
+
78
+ ## 5. Preflight every target before replacement
79
+
80
+ For each target in the bounded writable set:
81
+
82
+ 1. Read current content and resolving parent/child pointers. For an existing target, preserve its exact pre-write bytes; for a new target, record that no pre-write file exists.
83
+ 2. Measure the current target before replacement using exact raw UTF-8 bytes, never characters, lines, rounded kilobytes, or locale-dependent encoding.
84
+ 3. Establish a protected set before cleanup. It includes every still-valid public or wire contract, CRITICAL/HIGH trap, data-flow or data-integrity constraint, security/concurrency/transaction/compatibility rule, cross-module rule, non-obvious dependency, side effect, and durable decision with necessary rationale.
85
+ 4. Build the complete candidate result before replacement. Match existing and candidate facts by meaning; update the canonical entry in place, merge synonyms, remove equivalent, stale, derivable, conflicting, duplicate, or parent-copied material, and never append another version of the same knowledge.
86
+ 5. Measure the candidate as exact raw UTF-8 bytes and classify both current and candidate against the target's level.
87
+
88
+ Capacity limits and bands:
89
+
90
+ - Exact root project map: hard limit 4096B.
91
+ - Direct module index: hard limit 4096B.
92
+ - Nested mirrored or semantic detail: hard limit 5120B.
93
+ - normal: `size * 100 < limit * 80`.
94
+ - warning: `size * 100 >= limit * 80` and `size * 100 < limit * 90`.
95
+ - strong-warning: `size * 100 >= limit * 90` and `size <= limit`.
96
+ - error: `size > limit`.
97
+
98
+ When the current or candidate reaches at least 80%, perform the minimum safe cleanup or semantic split before final replacement:
99
+
100
+ 1. trim stale, source-derivable, procedural, historical, transient, and low-value wording;
101
+ 2. merge synonymous facts and remove duplicate meanings;
102
+ 3. move child-owned behavior from the root/module index into the existing or newly justified resolving detail;
103
+ 4. if one detail still cannot retain protected durable knowledge within 5120B, use the deterministic semantic split only when its stable identity and non-overlapping ownership are unambiguous.
104
+
105
+ Aim for 3277–3686B for a root/module index and 4096–4607B for a detail document, preserving approximately 10% headroom. Do not pad naturally concise output and do not trim merely to one byte below a hard limit. A post-remediation warning-range result is valid; do not force a needless split when the minimum safe cleanup establishes the target range.
106
+
107
+ Never remove protected knowledge solely to pass capacity validation. If it cannot fit after concise wording, safe movement, or an unambiguous split, do not replace that target.
108
+
109
+ ## 6. Write bottom-up
56
110
 
57
- ### Module index
111
+ Prepare all candidates before the first replacement and write only after each candidate passes its local format, identity, protected-set, and capacity preflight.
58
112
 
59
- Update FILES count, KEY_FILES, SUBDIRS, and DEPENDENCIES when module-level structure changes.
113
+ 1. Create or update the most specific detail first.
114
+ 2. Re-read and validate that detail before modifying its parent.
115
+ 3. Update the direct module index only as concise summaries and resolving pointers, using `SUBDIRS` or `DETAILS` as applicable.
116
+ 4. Update the root project map last and only when module structure or its concise resolving pointer changed.
60
117
 
61
- Module indexes do not contain INTERFACES, DATA_FLOW, TRAPS, or DECISIONS; those belong in detail documentation.
118
+ Complete `INTERFACES`, `DATA_FLOW`, `TRAPS`, `DECISIONS`, and full RULES owned by a child must not be copied into the module index or root project map. Parent docs retain the shortest useful summary and pointer. Preserve any root `PROJECT_BRIEF:` line because it is managed separately.
62
119
 
63
- ### Root project map
120
+ Before each replacement, compare candidate bytes with current bytes. A byte-identical candidate is not written, reordered, or reported as an update.
64
121
 
65
- Update MODULE_INDEX or MODULE_GROUPS only when module structure changed. Preserve any `PROJECT_BRIEF:` line because it is managed separately.
122
+ ## 7. Re-read and validate the actual final files
66
123
 
67
- ## 6. New module handling
124
+ After every write:
68
125
 
69
- If a new directory qualifies as a module and matches no existing module:
126
+ 1. Re-read the actual bytes from disk and recompute exact raw UTF-8 size.
127
+ 2. Reapply the 4096B/4096B/5120B hard limit and 80%/90% band formulas.
128
+ 3. Validate required KEY/value format and memory hygiene.
129
+ 4. Resolve every affected `MODULE_INDEX`, `MODULE_GROUPS`, `SUBDIRS`, and `DETAILS` pointer; validate both each changed target and its affected direct parent/child.
130
+ 5. Confirm semantic `MODULE`, `CONCERN`, path, slug, and `FILES` ownership agree and do not collide or overlap.
131
+ 6. Review only the targeted documentation diff for duplicate meanings, copied child behavior, unstable reorder, and unintended paths.
70
132
 
71
- 1. Create its module index immediately.
72
- 2. Add it to MODULE_INDEX or MODULE_GROUPS.
73
- 3. Create detail documentation only when the supplied changes include meaningful Added or Modified source files for the module.
133
+ If any post-write check fails, restore every replaced target from its preserved exact pre-write bytes and remove any invalid newly created target. Re-read the restored affected set and ensure no invalid oversized final document remains. Restoration is a bounded file operation; never use Git reset, checkout, or stash.
74
134
 
75
- ## 7. Size limits
135
+ ## 8. Capacity blocker evidence
76
136
 
77
- - Root project map > 4KB consolidate MODULE_INDEX or convert to MODULE_GROUPS when module count is high
78
- - Module index > 4KB → trim KEY_FILES descriptions and keep RULES concise
79
- - Detail document > 5KB → remove derived detail or stale entries; keep durable knowledge only
137
+ When no safe compression or stable split exists, stop with no invalid candidate left in place. The blocked result's `reason` must include:
80
138
 
81
- ## 8. TRAPS staleness check
139
+ - exact target path;
140
+ - measured current bytes and/or candidate bytes, hard limit, and band;
141
+ - protected knowledge that prevented trimming;
142
+ - why attempted cleanup, movement, or identity/ownership checks could not establish a safe split;
143
+ - a concrete recommended split boundary that a future manual decision can evaluate.
82
144
 
83
- Run only when a detail document's TRAPS section has more than 10 entries.
145
+ Its `validation` contains only checks actually attempted. Its `documentation_paths` follows the result schema and never invents a change. `RETRO_COMPLETE` is prohibited after any unresolved capacity, pointer, format, or restoration check.
84
146
 
85
- Process at most 5 oldest TRAPS per detail document:
147
+ ## 9. Bounded TRAPS staleness check
86
148
 
87
- 1. If a TRAP has `STALE_IF:` and matched files no longer exist, delete the TRAP.
88
- 2. If a TRAP has `REF:` and the referenced file is gone or the commit is older than the review horizon, mark it `[REVIEW]` for the next knowledge pass.
149
+ Run only for an affected detail target whose `TRAPS` section has more than 10 entries. Process at most five oldest traps:
89
150
 
90
- This bounds context cost and prevents unbounded trap accumulation.
151
+ 1. Delete a trap only when eligible source evidence proves it stale, including a `STALE_IF` path that no longer exists within the exact scope.
152
+ 2. If a `REF` cannot be validated from eligible evidence, retain the trap or mark it `[REVIEW]`; do not mine repository history or unrelated source to decide.
153
+ 3. Never remove a still-valid CRITICAL/HIGH trap merely for capacity.
@@ -96,10 +96,12 @@ Expected transitions:
96
96
  | `prizmkit-plan` | `PLAN_READY` plus valid `spec.md`/`plan.md` | `prizmkit-implement` |
97
97
  | `prizmkit-implement` | `IMPLEMENTED` plus completed task markers | `prizmkit-code-review` |
98
98
  | `prizmkit-code-review` | `PASS` plus valid `review-report.md` | `prizmkit-test` |
99
- | `prizmkit-test` | `TEST_PASS` plus consistent report/result pair | `prizmkit-retrospective` |
99
+ | `prizmkit-test` | `TEST_PASS` plus a consistent report/result pair with `production_changed=false` | `prizmkit-retrospective` |
100
100
  | `prizmkit-retrospective` | `RETRO_COMPLETE` plus an artifact whose `outcome` and `result` agree | `prizmkit-committer` |
101
101
  | `prizmkit-committer` | `COMMITTED` after explicit interactive confirmation | end |
102
102
 
103
+ Before accepting a Test transition, require `production_changed` to be a boolean and agree between `test-report.md` and `test-result.json`. A passing result with `production_changed=true` follows the bounded production-repair route below and is not final Test authority for Retrospective.
104
+
103
105
  Before invoking `prizmkit-retrospective`, derive the exact changed project paths outside `.prizmkit/` and pass them as `change_paths` with a concise `change_summary`. Do not ask that atomic Skill to infer scope from this composite's state or earlier artifacts.
104
106
 
105
107
  `TEST_NOT_APPLICABLE` is not a valid lifecycle success. Lightweight changes must execute deterministic verification and return `TEST_PASS`.
@@ -132,6 +134,28 @@ prizmkit-implement
132
134
 
133
135
  The Main-Agent review skill owns its internal review repairs and its internal ten-round limit before returning its terminal result. The outer workflow repair counter is separate.
134
136
 
137
+ ### Passing Test with Production Repair
138
+
139
+ A `TEST_PASS` whose consistent final artifacts report `production_changed=true` proves the Test stage repaired production code after prior Code Review. It does not authorize Retrospective or Committer.
140
+
141
+ ```text
142
+ TEST_PASS + production_changed=true + repair_round < 3
143
+ → preserve the Test artifacts as repair evidence
144
+ → increment the outer repair round
145
+ → invalidate prior final Code Review/Test completion in coordinator state
146
+ → clear stale stage_result before re-entry
147
+ → invoke prizmkit-code-review review_scope=delta
148
+ → require a fresh prizmkit-test result
149
+
150
+ fresh TEST_PASS + production_changed=false
151
+ → prizmkit-retrospective
152
+
153
+ TEST_PASS + production_changed=true + repair_round >= 3
154
+ → WORKFLOW_BLOCKED
155
+ ```
156
+
157
+ On re-entry, retain only stages that remain authoritative before Code Review in `completed_stages`, set `repair_scope=production`, and set the next/resume entry to delta Code Review without inventing a new atomic result. Repeated Test production repairs consume the same existing outer repair budget; they do not create an unbounded success loop.
158
+
135
159
  ### Test Non-Pass
136
160
 
137
161
  `prizmkit-test` already performs bounded test construction, execution-failure repair, mandatory Main-Agent review, and optional independent review before returning. The composite consumes its terminal artifacts without recreating those loops.
@@ -187,9 +211,17 @@ The internal `prizmkit-code-review` limit of ten completed review rounds remains
187
211
 
188
212
  The composite reaches `/prizmkit-committer operation=interactive-commit` but must not silently create a Git commit.
189
213
 
190
- The composite must validate all prior stage artifacts, derive exact non-`.prizmkit/` change paths for the retrospective input, and validate its result. It then invokes the committer with the same `artifact_dir`, exact `evidence_paths`, caller-state paths in `excluded_paths`, and `operation=interactive-commit`. The committer inspects the supplied final change, presents the exact commit, waits for confirmation, and creates it only after approval.
214
+ The composite must validate all prior stage artifacts, derive exact non-`.prizmkit/` change paths for the retrospective input, and validate its result. For interactive commit it then assembles one exact `intended_paths` manifest from:
215
+
216
+ - final validated requirement paths outside default support namespaces;
217
+ - exact `.prizmkit/prizm-docs/**` paths listed by a consistent `RETRO_COMPLETE` + `DOCS_UPDATED` result;
218
+ - exact support paths explicitly owned by the spec/plan, separately labeled in the preview, covered by the support validation below, and subject to the user's confirmation of that exact manifest.
219
+
220
+ For each explicit support path, select and execute its applicable semantic contract before invoking Committer: instruction files require readable structure, resolvable project references, consistency with the exact requirement and applicable project conventions, and secret scanning; lockfiles require parse/schema checks plus owning-installer or deterministic-regeneration parity; any other support class requires an exact project-native semantic validator named by the spec/plan. User confirmation alone is not support validation. If no applicable validator exists or evidence is non-passing, block support admission. Pass one exact `support_validation_evidence` record per admitted support path, including its path, contract, completed validation, `PASS` result, and exact evidence path.
221
+
222
+ All other `.prizmkit/**`, generated support, transient, installed, secret, unknown, or unrelated paths remain excluded or blocking. Invoke the committer with the same `artifact_dir`, exact `evidence_paths`, caller-state paths in `excluded_paths`, the exact `intended_paths`, conditional one-to-one `support_validation_evidence`, and `operation=interactive-commit`. The committer validates the manifest, presents the exact commit, waits for confirmation, and creates it only after approval.
191
223
 
192
- External headless orchestration supplies explicit evidence to `operation=prepare-runtime-commit`, maps `COMMIT_REQUEST_READY` to its own pending state, and lets Python Runtime validate and execute the request. Remote publication remains separate.
224
+ External headless orchestration supplies explicit evidence to `operation=prepare-runtime-commit`, maps `COMMIT_REQUEST_READY` to its own pending state, and lets Python Runtime validate and execute the request. Preparation mode preserves the existing automated contract: the complete `.prizmkit/**` tree remains outside Runtime `intended_paths`. Remote publication remains separate.
193
225
 
194
226
  ## Automatic Handoff and Manual Fallback
195
227
 
@@ -96,7 +96,8 @@ implementation IMPLEMENTED → status=completed, stage_result=IMPLEMENTED
96
96
  implementation repair/block → status=failed, stage_result=IMPLEMENT_REPAIR or IMPLEMENT_BLOCKED
97
97
  review-report PASS → status=completed, stage_result=REVIEW_PASS
98
98
  review-report NEEDS_FIXES → status=failed, stage_result=REVIEW_NEEDS_FIXES
99
- test-result TEST_PASS → status=completed, stage_result=TEST_PASS
99
+ test-result TEST_PASS, production_changed=false → status=completed, stage_result=TEST_PASS
100
+ test-result TEST_PASS, production_changed=true → bounded re-entry; clear stale stage_result before pending delta Code Review
100
101
  test-result TEST_NEEDS_FIXES → status=failed, stage_result=TEST_NEEDS_FIXES
101
102
  test-result TEST_BLOCKED → status=failed, stage_result=TEST_BLOCKED
102
103
  retrospective outcome=RETRO_COMPLETE, result=DOCS_UPDATED → status=completed, stage_result=RETRO_COMPLETE
@@ -109,7 +110,20 @@ commit blocked → status=failed, stage_result=COMMIT_BLOC
109
110
 
110
111
  `DOCS_UPDATED` and `NO_DOC_CHANGE` remain retrospective artifact `result` values. The workflow `stage_result` is the retrospective stage result `RETRO_COMPLETE`.
111
112
 
112
- `TEST_PASS` requires both `test-report.md` and a consistent `test-result.json`. No manifest, attestation, evidence package, or test-internal checkpoint is part of this contract.
113
+ `TEST_PASS` requires both `test-report.md` and a consistent `test-result.json`. Their `production_changed` diagnostics must agree. Only `production_changed=false` is final Test authority for Retrospective. No manifest, attestation, evidence package, or test-internal checkpoint is part of this contract.
114
+
115
+ ## Passing Production-Repair Re-entry
116
+
117
+ When consistent Test artifacts return `TEST_PASS` with `production_changed=true`, the atomic Test result remains truthful but the prior Code Review no longer covers the final production state. If `repair_round < 3`, the coordinator:
118
+
119
+ 1. preserves the Test artifacts as repair evidence;
120
+ 2. increments `repair_round`;
121
+ 3. removes invalidated `code-review` and `test` entries from `completed_stages` while preserving authoritative predecessors;
122
+ 4. sets `stage=code-review`, `status=pending`, and `stage_result=null` so no stale result survives re-entry;
123
+ 5. sets `repair_scope=production`, `next_stage=code-review`, and `resume_from=prizmkit-code-review`;
124
+ 6. invokes delta Code Review and then a fresh Test.
125
+
126
+ A fresh `TEST_PASS` with `production_changed=false` may complete Test and advance. Another production-changing pass repeats this route within the same outer budget. When `repair_round >= 3`, set `WORKFLOW_BLOCKED` without Retrospective or commit progression.
113
127
 
114
128
  ## Non-Pass Results and Routing Boundary
115
129
 
@@ -144,11 +158,16 @@ Any outer repair or continuation policy is independently owned by the caller and
144
158
  Interactive execution:
145
159
 
146
160
  ```text
147
- committer previews intended files and message
161
+ coordinator assembles exact intended_paths from final requirement paths
162
+ + exact validated Retrospective .prizmkit/prizm-docs paths
163
+ + separately labeled explicitly owned support paths with one-to-one passing support_validation_evidence
164
+ → committer validates and previews the exact files and message
148
165
  → waits for explicit current-user confirmation
149
- → stages, creates, and verifies the local commit
166
+ → stages exact pathspecs, creates, and verifies the local commit
150
167
  ```
151
168
 
169
+ All other `.prizmkit/**`, generated support, transient, installed, secret, unknown, or unrelated paths remain excluded or blocking. Exact durable Prizm documentation admission is an interactive exception backed by the Retrospective result, not a general `.prizmkit` allowlist. User confirmation alone is not support validation: instruction files require structure/reference/requirement-consistency/secret checks, lockfiles require parse/schema plus installer or deterministic-regeneration parity, and any other support class requires the exact project-native semantic validator named by the spec/plan.
170
+
152
171
  Pipeline execution:
153
172
 
154
173
  ```text
@@ -159,7 +178,7 @@ external coordinator validates its required gates and supplies exact readiness e
159
178
  → remote publication remains separate
160
179
  ```
161
180
 
162
- The preparation request is data for runtime validation, not prompt-level authorization. The committer must not stage, commit, or predeclare COMMITTED in pipeline preparation mode.
181
+ The preparation request is data for runtime validation, not prompt-level authorization. The committer must not stage, commit, or predeclare COMMITTED in pipeline preparation mode. Preparation preserves the existing automated path contract: the complete `.prizmkit/**` tree remains outside Runtime `intended_paths` in this protocol version.
163
182
 
164
183
  ## Recovery
165
184
 
@@ -6,6 +6,8 @@ from __future__ import annotations
6
6
  import re
7
7
  import subprocess
8
8
  import sys
9
+ from dataclasses import dataclass
10
+ from functools import cmp_to_key
9
11
  from pathlib import Path, PurePosixPath
10
12
 
11
13
  DOCS_ROOT = Path(".prizmkit/prizm-docs")
@@ -124,24 +126,129 @@ def read_check_content(file_path: str, mode: str) -> tuple[bytes, str] | None:
124
126
  return raw, raw.decode("utf-8", errors="replace")
125
127
 
126
128
 
129
+ @dataclass(frozen=True)
130
+ class CapacityDiagnostic:
131
+ file_path: str
132
+ level: str
133
+ size: int
134
+ limit: int
135
+ band: str
136
+ target_low: int
137
+ target_high: int
138
+ actions: str
139
+
140
+
141
+ def is_root_doc(file_path: str) -> bool:
142
+ return PurePosixPath(file_path) == PurePosixPath(ROOT_PRIZM.as_posix())
143
+
144
+
127
145
  def is_l1_doc(file_path: str) -> bool:
128
146
  parent = PurePosixPath(file_path).parent.as_posix()
129
147
  return parent == DOCS_ROOT.as_posix()
130
148
 
131
149
 
132
150
  def size_limit(file_path: str) -> tuple[int, str, str]:
133
- if file_path.endswith("root.prizm"):
134
- return 4096, "L0", "Consolidate MODULE_INDEX, keep top-5 RULES."
151
+ if is_root_doc(file_path):
152
+ return (
153
+ 4096,
154
+ "L0",
155
+ "trim: lower-priority global wording; "
156
+ "deduplicate: repeated RULES or module summaries; "
157
+ "move-to-child: module detail into an L1 document; "
158
+ "semantic-split: broad module groups into focused L1 documents",
159
+ )
135
160
  if is_l1_doc(file_path):
136
- return 3072, "L1", "Move implementation details to L2."
137
- return 5120, "L2", "Remove stale or trivially derivable entries."
161
+ return (
162
+ 4096,
163
+ "L1",
164
+ "trim: low-value module summaries; "
165
+ "deduplicate: repeated interfaces, rules, or traps; "
166
+ "move-to-child: implementation detail into an L2 document; "
167
+ "semantic-split: distinct submodules into focused L2 documents",
168
+ )
169
+ return (
170
+ 5120,
171
+ "L2",
172
+ "trim: stale or derivable detail; "
173
+ "deduplicate: repeated implementation notes; "
174
+ "move-to-child: one coherent detail set into a focused child document; "
175
+ "semantic-split: unrelated responsibilities into focused L2 documents",
176
+ )
177
+
178
+
179
+ def ceil_percent(limit: int, percent: int) -> int:
180
+ return (limit * percent + 99) // 100
181
+
182
+
183
+ def capacity_band(size: int, limit: int) -> str:
184
+ if size > limit:
185
+ return "error"
186
+ if size * 100 >= limit * 90:
187
+ return "strong-warning"
188
+ if size * 100 >= limit * 80:
189
+ return "warning"
190
+ return "normal"
191
+
192
+
193
+ def capacity_diagnostic(file_path: str, size: int) -> CapacityDiagnostic | None:
194
+ limit, level, actions = size_limit(file_path)
195
+ band = capacity_band(size, limit)
196
+ if band == "normal":
197
+ return None
198
+ return CapacityDiagnostic(
199
+ file_path=file_path,
200
+ level=level,
201
+ size=size,
202
+ limit=limit,
203
+ band=band,
204
+ target_low=ceil_percent(limit, 80),
205
+ target_high=ceil_percent(limit, 90) - 1,
206
+ actions=actions,
207
+ )
208
+
209
+
210
+ def compare_capacity(left: CapacityDiagnostic, right: CapacityDiagnostic) -> int:
211
+ left_ratio = left.size * right.limit
212
+ right_ratio = right.size * left.limit
213
+ if left_ratio > right_ratio:
214
+ return -1
215
+ if left_ratio < right_ratio:
216
+ return 1
217
+ if left.file_path < right.file_path:
218
+ return -1
219
+ if left.file_path > right.file_path:
220
+ return 1
221
+ return 0
222
+
223
+
224
+ def utilization_percent(size: int, limit: int) -> str:
225
+ hundredths = (size * 10000) // limit
226
+ return f"{hundredths // 100}.{hundredths % 100:02d}%"
227
+
228
+
229
+ def emit_capacity(diagnostic: CapacityDiagnostic) -> None:
230
+ severity = {
231
+ "warning": "WARNING",
232
+ "strong-warning": "STRONG WARNING",
233
+ "error": "ERROR",
234
+ }[diagnostic.band]
235
+ print(
236
+ f"{severity}: {diagnostic.file_path} capacity "
237
+ f"level={diagnostic.level} bytes={diagnostic.size}B limit={diagnostic.limit}B "
238
+ f"utilization={diagnostic.size}/{diagnostic.limit} "
239
+ f"({utilization_percent(diagnostic.size, diagnostic.limit)}) "
240
+ f"band={diagnostic.band} "
241
+ f"target={diagnostic.target_low}-{diagnostic.target_high}B (80% to <90%) "
242
+ f"actions={diagnostic.actions}",
243
+ file=sys.stderr,
244
+ )
138
245
 
139
246
 
140
247
  def contains_root_field(text: str, field: str) -> bool:
141
248
  return re.search(rf"^{re.escape(field)}:", text, re.MULTILINE) is not None
142
249
 
143
250
 
144
- def validate_file(file_path: str, raw: bytes, text: str) -> int:
251
+ def validate_file(file_path: str, raw: bytes, text: str) -> tuple[int, CapacityDiagnostic | None]:
145
252
  errors = 0
146
253
 
147
254
  if re.search(r"^#{1,6} ", text, re.MULTILINE):
@@ -195,13 +302,11 @@ def validate_file(file_path: str, raw: bytes, text: str) -> int:
195
302
  emit_error(file_path, "contains branch names. Describe durable product/domain context instead.")
196
303
  errors += 1
197
304
 
198
- limit, level, hint = size_limit(file_path)
199
- size = len(raw)
200
- if size > limit:
201
- emit_error(file_path, f"exceeds {level} limit ({size}B > {limit}B). {hint}")
305
+ diagnostic = capacity_diagnostic(file_path, len(raw))
306
+ if diagnostic is not None and diagnostic.band == "error":
202
307
  errors += 1
203
308
 
204
- if file_path.endswith("root.prizm"):
309
+ if is_root_doc(file_path):
205
310
  for field in ["PRIZM_VERSION", "PROJECT", "LANG", "RULES"]:
206
311
  if not contains_root_field(text, field):
207
312
  emit_error(file_path, f"missing required field {field}:")
@@ -210,7 +315,7 @@ def validate_file(file_path: str, raw: bytes, text: str) -> int:
210
315
  emit_error(file_path, "missing required field MODULE_INDEX: or MODULE_GROUPS:")
211
316
  errors += 1
212
317
 
213
- return errors
318
+ return errors, diagnostic
214
319
 
215
320
 
216
321
  def main(argv: list[str]) -> int:
@@ -223,12 +328,19 @@ def main(argv: list[str]) -> int:
223
328
  return 0
224
329
 
225
330
  errors = 0
331
+ capacity_entries: list[CapacityDiagnostic] = []
226
332
  for file_path in collect_files(mode):
227
333
  content = read_check_content(file_path, mode)
228
334
  if content is None:
229
335
  continue
230
336
  raw, text = content
231
- errors += validate_file(file_path, raw, text)
337
+ file_errors, diagnostic = validate_file(file_path, raw, text)
338
+ errors += file_errors
339
+ if diagnostic is not None:
340
+ capacity_entries.append(diagnostic)
341
+
342
+ for diagnostic in sorted(capacity_entries, key=cmp_to_key(compare_capacity)):
343
+ emit_capacity(diagnostic)
232
344
 
233
345
  if errors > 0:
234
346
  print(f"PrizmKit: {errors} format error(s) in .prizm files. Fix before committing.", file=sys.stderr)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prizmkit",
3
- "version": "1.1.155",
3
+ "version": "1.1.159",
4
4
  "description": "Create a new PrizmKit-powered project with clean initialization — no framework dev files, just what you need.",
5
5
  "type": "module",
6
6
  "bin": {