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.
- package/bundled/VERSION.json +3 -3
- package/bundled/dev-pipeline/prizmkit_runtime/reset.py +1 -1
- package/bundled/dev-pipeline/prizmkit_runtime/runner_classification.py +20 -11
- package/bundled/dev-pipeline/scripts/update-feature-status.py +7 -0
- package/bundled/dev-pipeline/tests/test_python_runner_parity.py +115 -4
- package/bundled/dev-pipeline/tests/test_reset_modes.py +137 -0
- package/bundled/dev-pipeline/tests/test_unified_cli.py +2 -1
- package/bundled/skills/_metadata.json +1 -1
- package/bundled/skills/prizmkit/SKILL.md +1 -13
- package/bundled/skills/prizmkit-code-review/SKILL.md +29 -10
- package/bundled/skills/prizmkit-code-review/references/independent-code-review.md +5 -4
- package/bundled/skills/prizmkit-code-review/references/review-report-template.md +15 -0
- package/bundled/skills/prizmkit-code-review/scripts/render_review_report.py +61 -0
- package/bundled/skills/prizmkit-committer/SKILL.md +22 -17
- package/bundled/skills/prizmkit-init/SKILL.md +21 -25
- package/bundled/skills/prizmkit-init/references/config-schema.md +11 -7
- package/bundled/skills/prizmkit-init/references/rules/layer-detection.md +3 -3
- package/bundled/skills/prizmkit-plan/SKILL.md +5 -4
- package/bundled/skills/prizmkit-plan/assets/plan-template.md +4 -1
- package/bundled/skills/prizmkit-plan/references/verification-checklist.md +3 -2
- package/bundled/skills/prizmkit-prizm-docs/SKILL.md +64 -10
- package/bundled/skills/prizmkit-prizm-docs/assets/prizm-docs-format.md +191 -56
- package/bundled/skills/prizmkit-prizm-docs/references/op-init.md +18 -18
- package/bundled/skills/prizmkit-prizm-docs/references/op-rebuild.md +14 -8
- package/bundled/skills/prizmkit-prizm-docs/references/op-status.md +12 -5
- package/bundled/skills/prizmkit-prizm-docs/references/op-update.md +23 -12
- package/bundled/skills/prizmkit-prizm-docs/references/op-validate.md +13 -9
- package/bundled/skills/prizmkit-retrospective/SKILL.md +72 -61
- package/bundled/skills/prizmkit-retrospective/references/knowledge-injection-steps.md +79 -37
- package/bundled/skills/prizmkit-retrospective/references/structural-sync-steps.md +109 -46
- package/bundled/skills/prizmkit-workflow/SKILL.md +35 -3
- package/bundled/skills/prizmkit-workflow/references/workflow-state-protocol.md +24 -5
- package/bundled/templates/hooks/validate-prizm-docs.py +124 -12
- package/package.json +1 -1
- 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
|
|
9
|
+
## 2. Map exact changes to a bounded target set
|
|
10
10
|
|
|
11
|
-
Read `.prizmkit/prizm-docs/root.prizm`
|
|
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
|
-
|
|
13
|
+
The writable set contains only:
|
|
14
14
|
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
24
|
+
## 3. Classify eligible structural changes
|
|
28
25
|
|
|
29
|
-
|
|
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
|
-
|
|
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
|
-
|
|
33
|
+
## 4. Select the most specific detail identity
|
|
36
34
|
|
|
37
|
-
|
|
35
|
+
### Mirrored source identity
|
|
38
36
|
|
|
39
|
-
|
|
37
|
+
When identities compete, mirrored source identity takes precedence.
|
|
40
38
|
|
|
41
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
122
|
+
## 7. Re-read and validate the actual final files
|
|
66
123
|
|
|
67
|
-
|
|
124
|
+
After every write:
|
|
68
125
|
|
|
69
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
135
|
+
## 8. Capacity blocker evidence
|
|
76
136
|
|
|
77
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
147
|
+
## 9. Bounded TRAPS staleness check
|
|
86
148
|
|
|
87
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
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
|
-
|
|
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
|
|
134
|
-
return
|
|
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
|
|
137
|
-
|
|
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
|
-
|
|
199
|
-
|
|
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
|
|
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
|
-
|
|
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)
|