prizmkit 1.1.155 → 1.1.156
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/skills/_metadata.json +1 -1
- 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/templates/hooks/validate-prizm-docs.py +124 -12
- package/package.json +1 -1
|
@@ -1,51 +1,93 @@
|
|
|
1
|
-
# Knowledge Injection —
|
|
1
|
+
# Knowledge Injection — Exact-Scope Value and Cleanup Steps
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## 1. Establish candidate fact authority
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
- Current Main-Agent context for the requirement — reuse it rather than rereading artifacts by default
|
|
7
|
-
- Targeted unchanged source, interfaces, callers, dependents, or tests only when an eligible diff raises a concrete ambiguity
|
|
8
|
-
- The affected Prizm docs only as update targets and existing-knowledge checks, never as changed project input
|
|
5
|
+
Gather candidate knowledge only from actual project changes in the exact validated non-`.prizmkit/` input paths:
|
|
9
6
|
|
|
10
|
-
|
|
7
|
+
- `git diff HEAD -- <exact validated change_paths>` using literal pathspecs is the source of truth for eligible changes; never broaden the diff to `.` or use repository-wide status/discovery to add paths.
|
|
8
|
+
- Current source content at those exact paths may clarify the diff.
|
|
9
|
+
- Narrowly required unchanged source context (an interface, direct caller, direct dependent, or test) may be read only when an eligible diff raises a concrete ambiguity that cannot be resolved from the changed path itself.
|
|
10
|
+
- Existing affected Prizm docs may be read only as update targets, pointer maps, protected-current-knowledge evidence, and duplicate/staleness checks.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
Generated artifacts, caller metadata, and existing Prizm text must not independently establish a candidate fact, expand `change_paths`, or turn an unrelated document into a target. `change_summary` is supporting context only. Reuse current Main-Agent source understanding when available, but do not treat lifecycle artifacts, completion notes, task IDs, or prior narrative as source evidence.
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
- Minimal format: `- [SEVERITY] <description> | FIX: <approach>`
|
|
16
|
-
- Full format: `- [SEVERITY] <description> | FIX: <approach> | REF: <hash> | STALE_IF: <glob>`
|
|
17
|
-
- Source: actual bugs hit, surprising behavior discovered in code, non-obvious coupling
|
|
14
|
+
## 2. Apply the future-incorrect-modification Value Gate
|
|
18
15
|
|
|
19
|
-
|
|
20
|
-
- `[CRITICAL]`: data loss, security, financial error, system crash
|
|
21
|
-
- `[HIGH]`: functional failure, silent error, interface incompatibility
|
|
22
|
-
- `[LOW]`: misleading naming, non-intuitive API, minor performance issue
|
|
16
|
+
For every candidate, ask exactly:
|
|
23
17
|
|
|
24
|
-
|
|
25
|
-
- Severity prefix is MANDATORY (e.g., `[CRITICAL]`, `[HIGH]`, `[LOW]`)
|
|
26
|
-
- OPTIONAL: append `| REF: <7-char-hash>` when you know the relevant commit (for traceability)
|
|
27
|
-
- OPTIONAL: append `| STALE_IF: <glob>` when the TRAP is tightly coupled to specific files (for auto-expiry detection)
|
|
18
|
+
> Could a future AI that lacks this fact make an incorrect modification?
|
|
28
19
|
|
|
29
|
-
|
|
30
|
-
- If you encounter a TRAP prefixed with `[REVIEW]` (e.g., `[REVIEW][HIGH] ...`), verify whether the trap is still valid by checking the current code. If still valid: remove the `[REVIEW]` prefix, keeping the severity. If no longer relevant: delete the TRAP entry.
|
|
20
|
+
Retain it only when the answer is yes and current eligible source proves that it is durable, non-obvious, actionable for future modification, and owned by the target level.
|
|
31
21
|
|
|
32
|
-
|
|
33
|
-
- Format: `- MUST/NEVER/PREFER: <rule>`
|
|
34
|
-
- Source: patterns that proved necessary during implementation
|
|
22
|
+
High-value candidate classes include:
|
|
35
23
|
|
|
36
|
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
40
|
-
-
|
|
24
|
+
- non-obvious public interfaces and wire contracts;
|
|
25
|
+
- data flow, side effects, transactions, integrity boundaries, or surprising coupling;
|
|
26
|
+
- cross-module constraints and non-obvious dependencies;
|
|
27
|
+
- security, data-integrity, concurrency, transaction, and compatibility rules;
|
|
28
|
+
- actual traps, race conditions, failure modes, or unsafe-looking alternatives;
|
|
29
|
+
- architectural rules or durable decisions with rationale;
|
|
30
|
+
- observable behavior boundaries whose omission could cause a regression;
|
|
31
|
+
- rejected alternatives that future sessions are likely to propose again.
|
|
41
32
|
|
|
42
|
-
|
|
33
|
+
For a likely-to-recur rejected alternative, retain the alternative and its reason only when current eligible source establishes both. Do not retain a rejected option merely as design history.
|
|
43
34
|
|
|
44
|
-
|
|
35
|
+
Reject candidates that are source-derivable structure or signatures, transient implementation conclusions, historical task/change narrative, duplicate meanings, stale/conflicting statements, test inventories, coverage lists, routine file inventories, long procedures, low-value wording, or behavior already complete in a more specific child.
|
|
45
36
|
|
|
46
|
-
|
|
47
|
-
- Module-level TRAPS/RULES/DECISIONS → the affected detail `.prizm` file. If the target detail document does not exist, create it from the detail-document generation template before injecting knowledge. These sections belong in detail documentation, not the module index.
|
|
48
|
-
- Project-level RULES/PATTERNS → `root.prizm` (respect the current format — MODULE_INDEX or MODULE_GROUPS — do not convert between them during injection)
|
|
49
|
-
- Cross-module concerns spanning 2+ modules → `root.prizm` CROSS_CUTTING section
|
|
37
|
+
## 3. Extract only observed durable knowledge
|
|
50
38
|
|
|
51
|
-
|
|
39
|
+
### TRAPS
|
|
40
|
+
|
|
41
|
+
Use `- [SEVERITY] <description> | FIX: <approach>` and include only source-established non-obvious failure risks.
|
|
42
|
+
|
|
43
|
+
- `[CRITICAL]`: data loss, security failure, financial error, or crash.
|
|
44
|
+
- `[HIGH]`: functional failure, silent error, data-integrity risk, or interface incompatibility.
|
|
45
|
+
- `[LOW]`: misleading naming, non-intuitive API, or minor quality/performance risk that still passes the Value Gate.
|
|
46
|
+
|
|
47
|
+
Optional `REF` or `STALE_IF` metadata is allowed only when it is durable and source-relevant. For an affected `[REVIEW]` trap, remove the marker only when exact eligible source proves it still valid; delete it only when that source proves it obsolete. Lack of narrow evidence is not permission to delete it.
|
|
48
|
+
|
|
49
|
+
### RULES
|
|
50
|
+
|
|
51
|
+
Use `- MUST/NEVER/PREFER: <rule>`. Keep only constraints that a future modification must obey and that eligible source establishes.
|
|
52
|
+
|
|
53
|
+
### DECISIONS and rejected alternatives
|
|
54
|
+
|
|
55
|
+
Use `- <decision> — <durable rationale>` or `- REJECTED: <likely recurring alternative> — <why it remains rejected>`. Do not record obvious implementation choices or historical deliberation.
|
|
56
|
+
|
|
57
|
+
### Interfaces and behavior
|
|
58
|
+
|
|
59
|
+
Retain only non-obvious public/wire contracts, data flow, side effects, dependencies, and observable boundaries whose absence could cause an incorrect modification. Omit signatures and structure that direct source reading makes obvious.
|
|
60
|
+
|
|
61
|
+
## 4. Reconcile the current target before insertion
|
|
62
|
+
|
|
63
|
+
For every bounded affected target:
|
|
64
|
+
|
|
65
|
+
1. Read its current content and the necessary resolving direct parent/child pointers.
|
|
66
|
+
2. Build the protected set defined by the structural sync procedure before removing anything.
|
|
67
|
+
3. Match by semantic meaning, not exact wording.
|
|
68
|
+
4. Update the canonical entry in place when source changes an equivalent or conflicting fact; merge synonyms into one concise meaning.
|
|
69
|
+
5. Remove only source-proven obsolete facts plus stale, derivable, duplicate, low-value, or parent-copied material outside the protected set.
|
|
70
|
+
6. Add a candidate only when it passes the Value Gate and no equivalent canonical entry remains.
|
|
71
|
+
7. Preserve stable section and entry order; do not reorder unchanged entries or append alternate wording merely to make a diff.
|
|
72
|
+
|
|
73
|
+
Append-only injection is prohibited. Cleanup remains limited to the exact affected targets and their necessary direct parent summaries/pointers; do not opportunistically clean siblings.
|
|
74
|
+
|
|
75
|
+
## 5. Place knowledge at the lowest owning level
|
|
76
|
+
|
|
77
|
+
- Module behavioral details, `INTERFACES`, `DATA_FLOW`, `TRAPS`, complete `RULES`, `DECISIONS`, and rejected alternatives belong in the most specific mirrored or deterministic semantic detail.
|
|
78
|
+
- A real source-submodule boundary uses mirrored detail identity first.
|
|
79
|
+
- A flat module uses a semantic concern detail only when the structural procedure proves stable deterministic identity, explicit non-overlapping source-file ownership, capacity need, complete terminal shape, and a resolving direct-module `DETAILS` pointer.
|
|
80
|
+
- A direct module index keeps concise structure, navigation, critical summaries, and pointers; it does not copy complete child behavior.
|
|
81
|
+
- The root project map keeps only concise navigation and genuinely project-wide/cross-module summaries. An exact eligible change must establish the project-wide fact; existing root text cannot create one.
|
|
82
|
+
|
|
83
|
+
When one eligible change truly spans multiple affected modules, place complete knowledge in the lowest owning details and retain only the shortest useful cross-module summary/pointers at root. Do not infer cross-module scope from unrelated existing documentation.
|
|
84
|
+
|
|
85
|
+
## 6. Hand candidate results to capacity preflight
|
|
86
|
+
|
|
87
|
+
Do not write directly from extraction. Hand the complete cleaned candidate, protected set, exact target identity, and affected direct pointers to `structural-sync-steps.md` for raw UTF-8 size measurement, minimum safe cleanup or semantic split, bottom-up replacement, re-read validation, and safe restoration.
|
|
88
|
+
|
|
89
|
+
If no candidate survives the Value Gate and structural reconciliation produces no byte change, return a truthful `NO_DOC_CHANGE`. A repeated run over identical source and inputs must preserve byte-identical documentation and must not create duplicate, reorder-only, or synonym-only churn.
|
|
90
|
+
|
|
91
|
+
## 7. Enforce memory hygiene
|
|
92
|
+
|
|
93
|
+
Before final candidate validation, remove CHANGELOG sections/files, UPDATED/date metadata, feature/bug/refactor/task/session/run/pipeline/workflow IDs, branch names, absolute worktree paths, and `.prizmkit/specs` or `.prizmkit/dev-pipeline` artifact paths. Never trade protected durable product/domain knowledge for traceability noise.
|
|
@@ -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.
|
|
@@ -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)
|