devrites 5.4.0 → 5.5.0

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 (213) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +1 -1
  3. package/docs/command-map.md +2 -2
  4. package/docs/engine/state-schema.md +12 -0
  5. package/docs/flow.md +4 -0
  6. package/docs/orchestration.md +5 -2
  7. package/engine/commands.go +2 -2
  8. package/engine/internal/devritespaths/paths.go +15 -0
  9. package/engine/internal/gate/gate.go +78 -0
  10. package/engine/internal/gate/gate_test.go +118 -0
  11. package/engine/internal/lib/candidate.go +7 -3
  12. package/engine/internal/lib/manifest_union.go +326 -0
  13. package/engine/internal/lib/manifest_union_test.go +214 -0
  14. package/engine/internal/lib/observe_budgets.go +73 -0
  15. package/engine/internal/lib/observe_budgets_test.go +142 -0
  16. package/engine/internal/lib/observe_summary.go +74 -13
  17. package/engine/internal/lib/workspace_read.go +11 -6
  18. package/engine/internal/state/budgets.go +163 -0
  19. package/engine/internal/state/budgets_test.go +42 -0
  20. package/engine/internal/state/cursor.go +16 -10
  21. package/engine/internal/state/observation.go +50 -4
  22. package/engine/internal/state/status.go +38 -26
  23. package/engine/internal/state/taskgraph.go +23 -0
  24. package/engine/main.go +32 -13
  25. package/engine/root_routing_test.go +3 -1
  26. package/pack/.claude/agents/devrites-code-reviewer.md +9 -6
  27. package/pack/.claude/agents/devrites-doubt-reviewer.md +6 -0
  28. package/pack/.claude/agents/devrites-plan-reviewer.md +7 -1
  29. package/pack/.claude/agents/devrites-slice-wright.md +42 -46
  30. package/pack/.claude/agents/devrites-test-analyst.md +9 -4
  31. package/pack/.claude/agents/devrites-upgrade-planner.md +9 -1
  32. package/pack/.claude/settings.json +17 -0
  33. package/pack/.claude/skills/devrites-api-interface/SKILL.md +2 -2
  34. package/pack/.claude/skills/devrites-doubt/SKILL.md +9 -17
  35. package/pack/.claude/skills/devrites-lib/reference/candidate-integrity.md +34 -35
  36. package/pack/.claude/skills/devrites-lib/reference/parallel-dispatch.md +11 -12
  37. package/pack/.claude/skills/devrites-lib/reference/standards/afk-hitl.md +104 -51
  38. package/pack/.claude/skills/devrites-lib/reference/standards/agents.md +1 -0
  39. package/pack/.claude/skills/devrites-lib/reference/standards/context-hygiene.md +45 -25
  40. package/pack/.claude/skills/devrites-lib/reference/standards/core.md +1 -1
  41. package/pack/.claude/skills/devrites-lib/reference/workspace-artifact-schema.md +80 -41
  42. package/pack/.claude/skills/rite-autocomplete/SKILL.md +19 -8
  43. package/pack/.claude/skills/rite-autocomplete/reference/loop.md +33 -1
  44. package/pack/.claude/skills/rite-build/SKILL.md +26 -19
  45. package/pack/.claude/skills/rite-build/reference/afk-discipline.md +1 -1
  46. package/pack/.claude/skills/rite-build/reference/parallel-batch.md +90 -40
  47. package/pack/.claude/skills/rite-build/reference/phase-contract.md +79 -59
  48. package/pack/.claude/skills/rite-build/reference/spec-drift-guard.md +14 -15
  49. package/pack/.claude/skills/rite-build/reference/wright-dispatch.md +8 -8
  50. package/pack/.claude/skills/rite-define/SKILL.md +4 -1
  51. package/pack/.claude/skills/rite-plan/SKILL.md +4 -1
  52. package/pack/.claude/skills/rite-plan/reference/replan-and-repair.md +21 -0
  53. package/pack/.claude/skills/rite-plan/reference/slicing.md +117 -15
  54. package/pack/.claude/skills/rite-prove/SKILL.md +20 -22
  55. package/pack/.claude/skills/rite-review/SKILL.md +23 -16
  56. package/pack/.claude/skills/rite-seal/SKILL.md +8 -8
  57. package/pack/.claude/skills/rite-seal/reference/final-evidence.md +6 -5
  58. package/pack/.claude/skills/rite-seal/reference/phase-contract.md +13 -13
  59. package/pack/.claude/skills/rite-ship/SKILL.md +3 -0
  60. package/pack/.claude/skills/rite-ship/reference/close-out.md +16 -2
  61. package/pack/.claude/skills/rite-ship/reference/git-ship.md +14 -5
  62. package/pack/.claude/skills/rite-spec/SKILL.md +6 -0
  63. package/pack/.claude/skills/rite-spec/reference/state-workspace.md +6 -0
  64. package/pack/.claude/skills/rite-status/SKILL.md +4 -1
  65. package/pack/.claude/skills/rite-temper/SKILL.md +14 -11
  66. package/pack/.claude/skills/rite-temper/reference/anti-patterns.md +14 -13
  67. package/pack/.claude/skills/rite-temper/reference/review-dimensions.md +3 -4
  68. package/pack/.claude/skills/rite-upgrade/SKILL.md +11 -2
  69. package/pack/.claude/skills/rite-vet/SKILL.md +22 -15
  70. package/pack/.claude/skills/rite-vet/reference/anti-patterns.md +11 -9
  71. package/pack/.claude/skills/rite-vet/reference/depth.md +6 -7
  72. package/pack/.claude/skills/rite-vet/reference/review-axes.md +39 -14
  73. package/pack/generated/claude/agents/devrites-code-reviewer.md +9 -6
  74. package/pack/generated/claude/agents/devrites-doubt-reviewer.md +6 -0
  75. package/pack/generated/claude/agents/devrites-plan-reviewer.md +7 -1
  76. package/pack/generated/claude/agents/devrites-slice-wright.md +42 -46
  77. package/pack/generated/claude/agents/devrites-test-analyst.md +9 -4
  78. package/pack/generated/claude/agents/devrites-upgrade-planner.md +9 -1
  79. package/pack/generated/claude/settings.json +17 -0
  80. package/pack/generated/claude/skills/devrites-api-interface/SKILL.md +2 -2
  81. package/pack/generated/claude/skills/devrites-doubt/SKILL.md +9 -17
  82. package/pack/generated/claude/skills/devrites-lib/reference/candidate-integrity.md +34 -35
  83. package/pack/generated/claude/skills/devrites-lib/reference/parallel-dispatch.md +11 -12
  84. package/pack/generated/claude/skills/devrites-lib/reference/standards/afk-hitl.md +104 -51
  85. package/pack/generated/claude/skills/devrites-lib/reference/standards/agents.md +1 -0
  86. package/pack/generated/claude/skills/devrites-lib/reference/standards/context-hygiene.md +45 -25
  87. package/pack/generated/claude/skills/devrites-lib/reference/standards/core.md +1 -1
  88. package/pack/generated/claude/skills/devrites-lib/reference/workspace-artifact-schema.md +80 -41
  89. package/pack/generated/claude/skills/rite-autocomplete/SKILL.md +19 -8
  90. package/pack/generated/claude/skills/rite-autocomplete/reference/loop.md +33 -1
  91. package/pack/generated/claude/skills/rite-build/SKILL.md +26 -19
  92. package/pack/generated/claude/skills/rite-build/reference/afk-discipline.md +1 -1
  93. package/pack/generated/claude/skills/rite-build/reference/parallel-batch.md +90 -40
  94. package/pack/generated/claude/skills/rite-build/reference/phase-contract.md +79 -59
  95. package/pack/generated/claude/skills/rite-build/reference/spec-drift-guard.md +14 -15
  96. package/pack/generated/claude/skills/rite-build/reference/wright-dispatch.md +8 -8
  97. package/pack/generated/claude/skills/rite-define/SKILL.md +4 -1
  98. package/pack/generated/claude/skills/rite-plan/SKILL.md +4 -1
  99. package/pack/generated/claude/skills/rite-plan/reference/replan-and-repair.md +21 -0
  100. package/pack/generated/claude/skills/rite-plan/reference/slicing.md +117 -15
  101. package/pack/generated/claude/skills/rite-prove/SKILL.md +20 -22
  102. package/pack/generated/claude/skills/rite-review/SKILL.md +23 -16
  103. package/pack/generated/claude/skills/rite-seal/SKILL.md +8 -8
  104. package/pack/generated/claude/skills/rite-seal/reference/final-evidence.md +6 -5
  105. package/pack/generated/claude/skills/rite-seal/reference/phase-contract.md +13 -13
  106. package/pack/generated/claude/skills/rite-ship/SKILL.md +3 -0
  107. package/pack/generated/claude/skills/rite-ship/reference/close-out.md +16 -2
  108. package/pack/generated/claude/skills/rite-ship/reference/git-ship.md +14 -5
  109. package/pack/generated/claude/skills/rite-spec/SKILL.md +6 -0
  110. package/pack/generated/claude/skills/rite-spec/reference/state-workspace.md +6 -0
  111. package/pack/generated/claude/skills/rite-status/SKILL.md +4 -1
  112. package/pack/generated/claude/skills/rite-temper/SKILL.md +14 -11
  113. package/pack/generated/claude/skills/rite-temper/reference/anti-patterns.md +14 -13
  114. package/pack/generated/claude/skills/rite-temper/reference/review-dimensions.md +3 -4
  115. package/pack/generated/claude/skills/rite-upgrade/SKILL.md +11 -2
  116. package/pack/generated/claude/skills/rite-vet/SKILL.md +22 -15
  117. package/pack/generated/claude/skills/rite-vet/reference/anti-patterns.md +11 -9
  118. package/pack/generated/claude/skills/rite-vet/reference/depth.md +6 -7
  119. package/pack/generated/claude/skills/rite-vet/reference/review-axes.md +39 -14
  120. package/pack/generated/codex/agents/devrites-code-reviewer.toml +9 -6
  121. package/pack/generated/codex/agents/devrites-doubt-reviewer.toml +6 -0
  122. package/pack/generated/codex/agents/devrites-plan-reviewer.toml +7 -1
  123. package/pack/generated/codex/agents/devrites-slice-wright.toml +42 -46
  124. package/pack/generated/codex/agents/devrites-test-analyst.toml +9 -4
  125. package/pack/generated/codex/agents/devrites-upgrade-planner.toml +9 -1
  126. package/pack/generated/codex/skills/devrites-api-interface/SKILL.md +2 -2
  127. package/pack/generated/codex/skills/devrites-doubt/SKILL.md +9 -17
  128. package/pack/generated/codex/skills/devrites-lib/reference/candidate-integrity.md +34 -35
  129. package/pack/generated/codex/skills/devrites-lib/reference/parallel-dispatch.md +11 -12
  130. package/pack/generated/codex/skills/devrites-lib/reference/standards/afk-hitl.md +104 -51
  131. package/pack/generated/codex/skills/devrites-lib/reference/standards/agents.md +1 -0
  132. package/pack/generated/codex/skills/devrites-lib/reference/standards/context-hygiene.md +45 -25
  133. package/pack/generated/codex/skills/devrites-lib/reference/standards/core.md +1 -1
  134. package/pack/generated/codex/skills/devrites-lib/reference/workspace-artifact-schema.md +80 -41
  135. package/pack/generated/codex/skills/rite-autocomplete/SKILL.md +19 -8
  136. package/pack/generated/codex/skills/rite-autocomplete/reference/loop.md +33 -1
  137. package/pack/generated/codex/skills/rite-build/SKILL.md +26 -19
  138. package/pack/generated/codex/skills/rite-build/reference/afk-discipline.md +1 -1
  139. package/pack/generated/codex/skills/rite-build/reference/parallel-batch.md +90 -40
  140. package/pack/generated/codex/skills/rite-build/reference/phase-contract.md +79 -59
  141. package/pack/generated/codex/skills/rite-build/reference/spec-drift-guard.md +14 -15
  142. package/pack/generated/codex/skills/rite-build/reference/wright-dispatch.md +8 -8
  143. package/pack/generated/codex/skills/rite-define/SKILL.md +4 -1
  144. package/pack/generated/codex/skills/rite-plan/SKILL.md +4 -1
  145. package/pack/generated/codex/skills/rite-plan/reference/replan-and-repair.md +21 -0
  146. package/pack/generated/codex/skills/rite-plan/reference/slicing.md +117 -15
  147. package/pack/generated/codex/skills/rite-prove/SKILL.md +20 -22
  148. package/pack/generated/codex/skills/rite-review/SKILL.md +23 -16
  149. package/pack/generated/codex/skills/rite-seal/SKILL.md +8 -8
  150. package/pack/generated/codex/skills/rite-seal/reference/final-evidence.md +6 -5
  151. package/pack/generated/codex/skills/rite-seal/reference/phase-contract.md +13 -13
  152. package/pack/generated/codex/skills/rite-ship/SKILL.md +3 -0
  153. package/pack/generated/codex/skills/rite-ship/reference/close-out.md +16 -2
  154. package/pack/generated/codex/skills/rite-ship/reference/git-ship.md +14 -5
  155. package/pack/generated/codex/skills/rite-spec/SKILL.md +6 -0
  156. package/pack/generated/codex/skills/rite-spec/reference/state-workspace.md +6 -0
  157. package/pack/generated/codex/skills/rite-status/SKILL.md +4 -1
  158. package/pack/generated/codex/skills/rite-temper/SKILL.md +14 -11
  159. package/pack/generated/codex/skills/rite-temper/reference/anti-patterns.md +14 -13
  160. package/pack/generated/codex/skills/rite-temper/reference/review-dimensions.md +3 -4
  161. package/pack/generated/codex/skills/rite-upgrade/SKILL.md +11 -2
  162. package/pack/generated/codex/skills/rite-vet/SKILL.md +22 -15
  163. package/pack/generated/codex/skills/rite-vet/reference/anti-patterns.md +11 -9
  164. package/pack/generated/codex/skills/rite-vet/reference/depth.md +6 -7
  165. package/pack/generated/codex/skills/rite-vet/reference/review-axes.md +39 -14
  166. package/pack/generated/omp/agents/devrites-code-reviewer.md +9 -6
  167. package/pack/generated/omp/agents/devrites-doubt-reviewer.md +6 -0
  168. package/pack/generated/omp/agents/devrites-plan-reviewer.md +7 -1
  169. package/pack/generated/omp/agents/devrites-slice-wright.md +42 -46
  170. package/pack/generated/omp/agents/devrites-test-analyst.md +9 -4
  171. package/pack/generated/omp/agents/devrites-upgrade-planner.md +9 -1
  172. package/pack/generated/omp/skills/devrites-api-interface/SKILL.md +2 -2
  173. package/pack/generated/omp/skills/devrites-doubt/SKILL.md +9 -17
  174. package/pack/generated/omp/skills/devrites-lib/reference/candidate-integrity.md +34 -35
  175. package/pack/generated/omp/skills/devrites-lib/reference/parallel-dispatch.md +11 -12
  176. package/pack/generated/omp/skills/devrites-lib/reference/standards/afk-hitl.md +104 -51
  177. package/pack/generated/omp/skills/devrites-lib/reference/standards/agents.md +1 -0
  178. package/pack/generated/omp/skills/devrites-lib/reference/standards/context-hygiene.md +45 -25
  179. package/pack/generated/omp/skills/devrites-lib/reference/standards/core.md +1 -1
  180. package/pack/generated/omp/skills/devrites-lib/reference/workspace-artifact-schema.md +80 -41
  181. package/pack/generated/omp/skills/rite-autocomplete/SKILL.md +19 -8
  182. package/pack/generated/omp/skills/rite-autocomplete/reference/loop.md +33 -1
  183. package/pack/generated/omp/skills/rite-build/SKILL.md +26 -19
  184. package/pack/generated/omp/skills/rite-build/reference/afk-discipline.md +1 -1
  185. package/pack/generated/omp/skills/rite-build/reference/parallel-batch.md +90 -40
  186. package/pack/generated/omp/skills/rite-build/reference/phase-contract.md +79 -59
  187. package/pack/generated/omp/skills/rite-build/reference/spec-drift-guard.md +14 -15
  188. package/pack/generated/omp/skills/rite-build/reference/wright-dispatch.md +8 -8
  189. package/pack/generated/omp/skills/rite-define/SKILL.md +4 -1
  190. package/pack/generated/omp/skills/rite-plan/SKILL.md +4 -1
  191. package/pack/generated/omp/skills/rite-plan/reference/replan-and-repair.md +21 -0
  192. package/pack/generated/omp/skills/rite-plan/reference/slicing.md +117 -15
  193. package/pack/generated/omp/skills/rite-prove/SKILL.md +20 -22
  194. package/pack/generated/omp/skills/rite-review/SKILL.md +23 -16
  195. package/pack/generated/omp/skills/rite-seal/SKILL.md +8 -8
  196. package/pack/generated/omp/skills/rite-seal/reference/final-evidence.md +6 -5
  197. package/pack/generated/omp/skills/rite-seal/reference/phase-contract.md +13 -13
  198. package/pack/generated/omp/skills/rite-ship/SKILL.md +3 -0
  199. package/pack/generated/omp/skills/rite-ship/reference/close-out.md +16 -2
  200. package/pack/generated/omp/skills/rite-ship/reference/git-ship.md +14 -5
  201. package/pack/generated/omp/skills/rite-spec/SKILL.md +6 -0
  202. package/pack/generated/omp/skills/rite-spec/reference/state-workspace.md +6 -0
  203. package/pack/generated/omp/skills/rite-status/SKILL.md +4 -1
  204. package/pack/generated/omp/skills/rite-temper/SKILL.md +14 -11
  205. package/pack/generated/omp/skills/rite-temper/reference/anti-patterns.md +14 -13
  206. package/pack/generated/omp/skills/rite-temper/reference/review-dimensions.md +3 -4
  207. package/pack/generated/omp/skills/rite-upgrade/SKILL.md +11 -2
  208. package/pack/generated/omp/skills/rite-vet/SKILL.md +22 -15
  209. package/pack/generated/omp/skills/rite-vet/reference/anti-patterns.md +11 -9
  210. package/pack/generated/omp/skills/rite-vet/reference/depth.md +6 -7
  211. package/pack/generated/omp/skills/rite-vet/reference/review-axes.md +39 -14
  212. package/package.json +1 -1
  213. package/scripts/codex-generate.sh +6 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  All notable changes to DevRites are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and DevRites adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Releases are generated automatically by [semantic-release](https://semantic-release.gitbook.io/) from Conventional Commits on `main`.
4
4
 
5
+ ## [5.5.0](https://github.com/ViktorsBaikers/DevRites/compare/v5.4.0...v5.5.0) (2026-09-13)
6
+
7
+ ### Added
8
+
9
+ * **rite:** cap parallel batch width and chain deferred ship ([#68](https://github.com/ViktorsBaikers/DevRites/issues/68)) ([d023dfa](https://github.com/ViktorsBaikers/DevRites/commit/d023dfa742d5b6f5a9775c21308cd4731d6858f9))
10
+
5
11
  ## [5.4.0](https://github.com/ViktorsBaikers/DevRites/compare/v5.3.0...v5.4.0) (2026-09-13)
6
12
 
7
13
  ### Added
package/README.md CHANGED
@@ -33,7 +33,7 @@ project-conventional push, tag, or PR action, and archive the workspace.
33
33
  Unattended runs may create local WIP checkpoint commits along the way, but they
34
34
  remain local unless Ship's disclosed plan includes an approved remote action.
35
35
 
36
- **Status:** [`v5.4.0`](https://github.com/ViktorsBaikers/DevRites/releases/tag/v5.4.0): see [`CHANGELOG.md`](CHANGELOG.md) for release notes.
36
+ **Status:** [`v5.5.0`](https://github.com/ViktorsBaikers/DevRites/releases/tag/v5.5.0): see [`CHANGELOG.md`](CHANGELOG.md) for release notes.
37
37
 
38
38
  This is the latest published release; `main` may contain unreleased work.
39
39
 
@@ -41,8 +41,8 @@ The Go surface is intentionally closed and deterministic:
41
41
  | Lane | Commands | Owner |
42
42
  |---|---|---|
43
43
  | Candidate and deterministic checks | `check candidate`, `check readiness [--emit-binding]`, `check seal`, `check task-graph`, `check path-disjoint`, `check skill-trust`, `check indexes` | Candidate validates/hashes the strict project manifest; readiness checks phase files, the required `tasks.md` slice graph, or emits the vetted Build-input binding; seal checks final files/open gates, that graph and binding, then exact candidate bindings. `check indexes` reports install manifest and optional code-index directory presence as JSON. |
44
- | Workspace observation | `observe summary`, `orient` | JSON workspace snapshot for agents; `orient` is an alias for `observe summary`. |
45
- | Atomic workspace state | `state resolve`, `state close`, `migrate [--dry-run] [--answer id=choice]` | Go owns answer/drop/batch resolution, transactional close, and fail-closed v5 schema normalization. |
44
+ | Workspace observation | `observe summary`, `orient`, `observe slice <slug> <SLICE-ID>` | JSON workspace snapshot for agents (cursor, task graph, `artifact_budgets`, `bulk_files`); `orient` is an alias for `observe summary`. `observe slice` prints one `SLICE-###` section of `tasks.md` so Build reads a slice, not the file. |
45
+ | Atomic workspace state | `state resolve`, `state merge-manifest`, `state close`, `migrate [--dry-run] [--answer id=choice]` | Go owns answer/drop/batch resolution, the recorded predecessor-chain manifest union for a release milestone, transactional close, and fail-closed v5 schema normalization. |
46
46
  | Security | `secret-scan` | `/rite-ship`, safe hooks, or an operator scans staged blobs, stdin, or touched files. |
47
47
  | Install/operator | `install`, `update`, `uninstall`, `version` | Direct update acquires latest; npm/bootstrap may supply local candidates; the engine performs manifest-owned local changes. |
48
48
  | Native policy | no engine command | Skills/root own spec grammar re-read, qid allocation, Clarify cursor edits, AFK/recovery accounting, and read-only `/rite-doctor`. |
@@ -147,6 +147,18 @@ There is no recovery-counter artifact. The caller and recovery loop count at
147
147
  most three failed attempts per causal fingerprint from current context and the
148
148
  recorded `## Dead ends` / `evidence.md`, then stop before a fourth.
149
149
 
150
+ For a deferred-ship continuation chain (`.devrites/AFK` `continue_sequence`),
151
+ three optional cursor fields carry the chain: `sequence_parent` (the immediately
152
+ preceding workspace slug), `sequence_position` (1-based ordinal), and
153
+ `sequence_workspaces_remaining` (slots the chain may still open). The controlling
154
+ root seeds them once per continuation workspace from the recorded parent and the
155
+ parent's counter; values only decrease, malformed values fail closed, and a
156
+ workspace without a recorded parent/position is not a sequence member. The
157
+ release milestone additionally carries `sequence_role: release`, which makes
158
+ `check candidate` and `check seal` require its manifest to cover the whole
159
+ recorded chain (built by `state merge-manifest`).
160
+ `observe summary`/`orient` surface them under `sequence`.
161
+
150
162
  <!-- authority:state-tracking:start -->
151
163
  Git-tracked shared state: `.devrites/specs/`. Per-clone runtime state: `.devrites/work/`, `.devrites/archive/`, `.devrites/ACTIVE`.
152
164
  <!-- authority:state-tracking:end -->
package/docs/flow.md CHANGED
@@ -351,6 +351,10 @@ erDiagram
351
351
  string status "running | awaiting_human | blocked | done"
352
352
  string active_slice "N: name"
353
353
  int afk_slices_remaining "root-owned; never negative; one charge per green built slice"
354
+ string sequence_parent "deferred-ship chain: preceding workspace slug"
355
+ int sequence_position "1-based ordinal in the recorded continuation chain"
356
+ int sequence_workspaces_remaining "chain slots still open after this workspace; never negative"
357
+ string sequence_role "release on the release milestone; gates then require the chain union"
354
358
  string return_phase "durable later-phase clarify return"
355
359
  string return_next_action "restored only after fresh CLEAR"
356
360
  block awaiting_human "qid, gate, question, proposed, raised_at (only when paused)"
@@ -127,8 +127,11 @@ conflict, extra paths, moved base, or cleanup failure stops with worktree eviden
127
127
  preserved. No ad hoc copy/cherry-pick/merge occurs from the read-only root.
128
128
 
129
129
  Isolation does not authorize same-worktree throughput. Parallel writers are allowed
130
- **only** under `/rite-build --parallel N` when path-disjoint eligibility, abort-batch,
131
- and a control `parallel-lease.md` apply (see
130
+ **only** under the `/rite-build` batch path when path-disjoint eligibility, abort-batch,
131
+ and a control `parallel-lease.md` apply. `--parallel N` (or the AFK sentinel
132
+ `max_parallel`, default cap 10 under `/rite-autocomplete`) is a **cap**: each round runs
133
+ the largest eligible set, recomputes after every integrate, and repeats until no pending
134
+ slice remains; fewer than two eligible slices fall back to the serial cycle (see
132
135
  [`parallel-batch.md`](../pack/.claude/skills/rite-build/reference/parallel-batch.md)).
133
136
  Same-worktree multi-writer and root-emulated worktrees remain forbidden; default
134
137
  `/rite-build` stays one writer across linked worktrees.
@@ -31,7 +31,7 @@ func rootModeFor(command string, args []string) rootMode {
31
31
  return rootLenient
32
32
  case "state":
33
33
  switch subcommand {
34
- case "resolve", "close":
34
+ case "resolve", "merge-manifest", "close":
35
35
  return rootStrict
36
36
  }
37
37
  return rootUnused
@@ -49,7 +49,7 @@ func rootModeFor(command string, args []string) rootMode {
49
49
  return rootStrictUsage
50
50
  case "observe":
51
51
  switch subcommand {
52
- case "summary":
52
+ case "summary", "slice":
53
53
  return rootStrictUsage
54
54
  }
55
55
  return rootUnused
@@ -118,6 +118,21 @@ func ArchiveDirChecked(root string) (string, error) {
118
118
  return checkedCanonicalDir(root, filepath.Join(root, "archive"), "archive", "")
119
119
  }
120
120
 
121
+ // ExistingArchivedFeatureDirChecked resolves an archived feature directory that
122
+ // must already exist. A live workspace never satisfies this lookup; callers
123
+ // that accept either location try ExistingFeatureDirChecked first.
124
+ func ExistingArchivedFeatureDirChecked(root, slug string) (string, error) {
125
+ if !validSlug(slug) {
126
+ return "", fmt.Errorf("DRV-WORKSPACE-INVALID: %q is not a feature slug", slug)
127
+ }
128
+ candidate := filepath.Join(root, "archive", slug)
129
+ resolved, err := checkedCanonicalDir(root, candidate, filepath.Join("archive", slug), "")
130
+ if err != nil {
131
+ return "", err
132
+ }
133
+ return resolved, nil
134
+ }
135
+
121
136
  func checkedCanonicalDir(root, candidate, parent, slug string) (string, error) {
122
137
  resolvedRoot, err := safepath.ResolveExisting(root)
123
138
  if err != nil {
@@ -51,9 +51,38 @@ func Check(kind Kind, root, slug string) (*Result, error) {
51
51
  if err != nil {
52
52
  return nil, fmt.Errorf("gate %s: %w", kind, err)
53
53
  }
54
+ for _, problem := range unsanctionedRootFiles(observation) {
55
+ result.StateProblems = append(result.StateProblems, "placement: "+problem)
56
+ // Keep a more specific reason (readiness-stale) when the observation
57
+ // already blocked; only an otherwise-passing gate takes the generic one.
58
+ if !result.Blocked {
59
+ result.Blocked = true
60
+ result.ReasonID = ResultReasonID(kind, true)
61
+ }
62
+ }
54
63
  return result, nil
55
64
  }
56
65
 
66
+ // unsanctionedRootFiles blocks a workspace-root file the schema does not place
67
+ // there and is over the packet ceiling. `packets/` owns by-reference dispatch
68
+ // packets and admitted accounts (<= 64 KiB each) and `history/` owns relocated
69
+ // narrative, so a large stray file in the root is misplaced payload — the shape
70
+ // that let a real workspace reach 71 MB, 83% of it reviewer packets and traces
71
+ // (see context-hygiene.md dispatch packets and its failing case).
72
+ func unsanctionedRootFiles(observation *state.WorkspaceObservation) []string {
73
+ var problems []string
74
+ for _, file := range observation.RootFiles() {
75
+ if state.SanctionedRootFile(file.Name) || file.Bytes <= state.PacketMaxBytes {
76
+ continue
77
+ }
78
+ problems = append(problems, fmt.Sprintf(
79
+ "%s is %d bytes in the workspace root; move dispatch packets and accounts to packets/ (<= %d bytes each), closed narrative to history/ via /rite-plan revise, and never persist transcripts anywhere in .devrites/",
80
+ file.Name, file.Bytes, state.PacketMaxBytes,
81
+ ))
82
+ }
83
+ return problems
84
+ }
85
+
57
86
  func checkObservation(kind Kind, observation *state.WorkspaceObservation) (*Result, error) {
58
87
  phase, err := observation.DeclaredPhase()
59
88
  if err != nil {
@@ -109,6 +138,28 @@ func checkObservation(kind Kind, observation *state.WorkspaceObservation) (*Resu
109
138
  blocked = true
110
139
  }
111
140
  }
141
+ if len(missingFiles) == 0 {
142
+ for _, problem := range artifactBudgetProblems(observation, policy) {
143
+ stateProblems = append(stateProblems, "budget: "+problem)
144
+ blocked = true
145
+ }
146
+ }
147
+ // Deliberately not gated on missingFiles: a file over the read cap IS missing,
148
+ // so the budget comparison below can never reach it. Missing already blocks it;
149
+ // name the size remedies too so the signal is actionable rather than a bare cap.
150
+ for _, artifact := range policy.RequiredArtifacts {
151
+ fact, ok := observation.Fact(artifact)
152
+ if !ok {
153
+ continue
154
+ }
155
+ if diagnostic, has := fact.Diagnostic(); has && diagnostic.Code == state.DiagnosticFileTooLarge {
156
+ stateProblems = append(stateProblems, fmt.Sprintf(
157
+ "budget: %s exceeds the %d-byte artifact cap; relocate history (history/<file>-<YYYYMMDD>.md) or split the feature via /rite-plan revise|course-correct",
158
+ artifact, state.MaxArtifactBytes,
159
+ ))
160
+ blocked = true
161
+ }
162
+ }
112
163
  if len(missingFiles) == 0 && phaseRequiresReadinessBinding(policy) {
113
164
  expected, bindingErr := verifyReadinessBinding(observation)
114
165
  if bindingErr != nil {
@@ -142,6 +193,33 @@ func checkObservation(kind Kind, observation *state.WorkspaceObservation) (*Resu
142
193
  return result, nil
143
194
  }
144
195
 
196
+ // artifactBudgetProblems blocks a required artifact only on a material overshoot
197
+ // (>= state.BudgetBlockFactor of a line or byte budget) with no structural
198
+ // `Budget override:` line. Smaller overshoots stay advisory and are reported by
199
+ // `orient`.
200
+ func artifactBudgetProblems(observation *state.WorkspaceObservation, policy state.PhasePolicy) []string {
201
+ var problems []string
202
+ for _, artifact := range policy.RequiredArtifacts {
203
+ fact, ok := observation.Fact(artifact)
204
+ if !ok || fact.State() != state.ArtifactPresent {
205
+ continue
206
+ }
207
+ if !state.ArtifactBudgetGateApplies(string(artifact)) {
208
+ continue
209
+ }
210
+ status, ok := state.ArtifactBudget(string(artifact), fact.Bytes())
211
+ if !ok || !status.Material || status.Override {
212
+ continue
213
+ }
214
+ problems = append(problems, fmt.Sprintf(
215
+ "%s is %d lines/%d bytes, at or above %gx its %d-line/%d-byte budget; relocate history (history/<file>-<YYYYMMDD>.md) or split the feature via /rite-plan revise|course-correct, or record a structural `Budget override: <reason>` line",
216
+ status.File, status.Lines, status.Bytes, state.BudgetBlockFactor,
217
+ status.LineBudget, status.ByteBudget,
218
+ ))
219
+ }
220
+ return problems
221
+ }
222
+
145
223
  func acceptanceMapProblems(observation *state.WorkspaceObservation, policy state.PhasePolicy) []string {
146
224
  requireTasks := phaseRequiresTasks(policy)
147
225
  requireTestPlan := phaseRequiresTestPlan(policy)
@@ -636,3 +636,121 @@ func writeWorkFeature(t *testing.T, root, slug string, files map[string]string)
636
636
  testutil.WriteFile(t, filepath.Join(root, "work", slug, name), content)
637
637
  }
638
638
  }
639
+
640
+ func TestCheckBlocksMaterialBudgetOvershootWithoutOverride(t *testing.T) {
641
+ root := t.TempDir()
642
+ writeCompleteGateFeature(t, root, "oversized", state.PhaseBuild, state.PhaseBuild, "none\n")
643
+ workspace := filepath.Join(root, "work", "oversized")
644
+ oversized := "# Tasks\n\n## SLICE-001 A\nDependencies: none\n\n" + strings.Repeat("long line of planning prose\n", 500)
645
+ testutil.WriteFile(t, filepath.Join(workspace, "tasks.md"), oversized)
646
+ binding := mustReadinessBinding(t, root, "oversized")
647
+ testutil.AppendFile(t, filepath.Join(workspace, "eng-review.md"), "\n"+binding+"\n")
648
+
649
+ res, err := Check(Readiness, root, "oversized")
650
+ if err != nil {
651
+ t.Fatal(err)
652
+ }
653
+ if !res.Blocked {
654
+ t.Fatalf("blocked=false, want true")
655
+ }
656
+ joined := strings.Join(res.StateProblems, "\n")
657
+ if !strings.Contains(joined, "budget: tasks.md is") || !strings.Contains(joined, "Budget override") {
658
+ t.Fatalf("StateProblems=%q", joined)
659
+ }
660
+
661
+ testutil.AppendFile(t, filepath.Join(workspace, "tasks.md"), "\nBudget override: vendored requirement matrix, relocation pending\n")
662
+ res, err = Check(Readiness, root, "oversized")
663
+ if err != nil {
664
+ t.Fatal(err)
665
+ }
666
+ if strings.Contains(strings.Join(res.StateProblems, "\n"), "budget: tasks.md") {
667
+ t.Fatalf("override did not clear the budget problem: %v", res.StateProblems)
668
+ }
669
+ }
670
+
671
+ func TestCheckKeepsNonMaterialOvershootAdvisory(t *testing.T) {
672
+ root := t.TempDir()
673
+ writeCompleteGateFeature(t, root, "slightly-over", state.PhaseBuild, state.PhaseBuild, "none\n")
674
+ workspace := filepath.Join(root, "work", "slightly-over")
675
+ // 300 lines against a 280-line budget: over, but below the material factor.
676
+ testutil.WriteFile(t, filepath.Join(workspace, "tasks.md"), testutil.CanonicalTasksMarkdown+"\n"+strings.Repeat("note\n", 200))
677
+ binding := mustReadinessBinding(t, root, "slightly-over")
678
+ testutil.AppendFile(t, filepath.Join(workspace, "eng-review.md"), "\n"+binding+"\n")
679
+
680
+ res, err := Check(Readiness, root, "slightly-over")
681
+ if err != nil {
682
+ t.Fatal(err)
683
+ }
684
+ if strings.Contains(strings.Join(res.StateProblems, "\n"), "budget:") {
685
+ t.Fatalf("non-material overshoot must stay advisory: %v", res.StateProblems)
686
+ }
687
+ }
688
+
689
+ func TestCheckBlocksOversizedPacketInWorkspaceRoot(t *testing.T) {
690
+ root := t.TempDir()
691
+ writeCompleteGateFeature(t, root, "stray", state.PhaseBuild, state.PhaseBuild, "none\n")
692
+ workspace := filepath.Join(root, "work", "stray")
693
+ binding := mustReadinessBinding(t, root, "stray")
694
+ testutil.AppendFile(t, filepath.Join(workspace, "eng-review.md"), "\n"+binding+"\n")
695
+
696
+ // Sanctioned conditional artifact over the ceiling: placement stays legal.
697
+ testutil.WriteFile(t, filepath.Join(workspace, "references.md"),
698
+ "# refs\n\n"+strings.Repeat("reference line\n", 6000))
699
+ // Unsanctioned root payload over the ceiling: blocked.
700
+ testutil.WriteFile(t, filepath.Join(workspace, "vet-review-input-031.json"),
701
+ strings.Repeat("x", state.PacketMaxBytes+1))
702
+
703
+ res, err := Check(Readiness, root, "stray")
704
+ if err != nil {
705
+ t.Fatal(err)
706
+ }
707
+ joined := strings.Join(res.StateProblems, "\n")
708
+ if !res.Blocked || !strings.Contains(joined, "placement: vet-review-input-031.json") {
709
+ t.Fatalf("blocked=%v StateProblems=%q", res.Blocked, joined)
710
+ }
711
+ if !strings.Contains(joined, "packets/") {
712
+ t.Fatalf("remediation must name packets/: %q", joined)
713
+ }
714
+ if strings.Contains(joined, "references.md") {
715
+ t.Fatalf("sanctioned root artifact must not be treated as misplaced: %q", joined)
716
+ }
717
+ }
718
+
719
+ func TestCheckNamesSizeRemediesForArtifactOverReadCap(t *testing.T) {
720
+ root := t.TempDir()
721
+ writeCompleteGateFeature(t, root, "huge", state.PhaseBuild, state.PhaseBuild, "none\n")
722
+ workspace := filepath.Join(root, "work", "huge")
723
+ // Over the read cap, so the artifact cannot be measured against its line budget.
724
+ // No binding: an over-cap file cannot be hashed into one, and this asserts the
725
+ // size signal alone rather than a passing gate.
726
+ testutil.WriteFile(t, filepath.Join(workspace, "tasks.md"),
727
+ "# Tasks\n\n"+strings.Repeat("n\n", state.MaxArtifactBytes/2+1))
728
+
729
+ res, err := Check(Readiness, root, "huge")
730
+ if err != nil {
731
+ t.Fatal(err)
732
+ }
733
+ joined := strings.Join(res.StateProblems, "\n")
734
+ if !res.Blocked || !strings.Contains(joined, "budget: tasks.md exceeds the") {
735
+ t.Fatalf("blocked=%v StateProblems=%q", res.Blocked, joined)
736
+ }
737
+ if !strings.Contains(joined, "history/") || !strings.Contains(joined, "/rite-plan") {
738
+ t.Fatalf("size remedies must be named: %q", joined)
739
+ }
740
+ }
741
+
742
+ func TestCheckLeavesProofLedgerOvershootAdvisory(t *testing.T) {
743
+ root := t.TempDir()
744
+ writeCompleteGateFeature(t, root, "big-ledger", state.PhaseProve, state.PhaseProve, "none\n")
745
+ workspace := filepath.Join(root, "work", "big-ledger")
746
+ testutil.WriteFile(t, filepath.Join(workspace, "evidence.md"), strings.Repeat("EVID-001 proof line\n", 800))
747
+ testutil.WriteFile(t, filepath.Join(workspace, "touched-files.md"), strings.Repeat("trail line\n", 600))
748
+
749
+ res, err := Check(Readiness, root, "big-ledger")
750
+ if err != nil {
751
+ t.Fatal(err)
752
+ }
753
+ if joined := strings.Join(res.StateProblems, "\n"); strings.Contains(joined, "budget:") {
754
+ t.Fatalf("proof ledgers must stay advisory: %v", res.StateProblems)
755
+ }
756
+ }
@@ -33,6 +33,8 @@ const (
33
33
  type candidateRow struct {
34
34
  state string
35
35
  path string
36
+ slice string
37
+ reason string
36
38
  executable bool
37
39
  size int64
38
40
  info os.FileInfo
@@ -203,10 +205,12 @@ func parseCandidateManifest(raw []byte) ([]candidateRow, error) {
203
205
  if err != nil {
204
206
  return nil, fmt.Errorf("row %d File: %w", i+1, err)
205
207
  }
206
- if strings.TrimSpace(cells[3]) == "" {
208
+ sliceCell := strings.TrimSpace(cells[3])
209
+ if sliceCell == "" {
207
210
  return nil, fmt.Errorf("row %d Slice must be nonempty", i+1)
208
211
  }
209
- if strings.TrimSpace(cells[4]) == "" {
212
+ reasonCell := strings.TrimSpace(cells[4])
213
+ if reasonCell == "" {
210
214
  return nil, fmt.Errorf("row %d Reason must be nonempty", i+1)
211
215
  }
212
216
  if _, ok := seen[normalized]; ok {
@@ -221,7 +225,7 @@ func parseCandidateManifest(raw []byte) ([]candidateRow, error) {
221
225
  }
222
226
  seen[normalized] = struct{}{}
223
227
  seenFolded[folded] = normalized
224
- rows = append(rows, candidateRow{state: state, path: normalized})
228
+ rows = append(rows, candidateRow{state: state, path: normalized, slice: sliceCell, reason: reasonCell})
225
229
  if len(rows) > maxCandidateRows {
226
230
  return nil, errors.New("manifest exceeds 4096 rows")
227
231
  }