devrites 6.1.0 → 6.1.2

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 (202) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +1 -1
  3. package/docs/architecture.md +3 -1
  4. package/docs/cli.md +4 -1
  5. package/docs/engine/commands.md +4 -4
  6. package/docs/orchestration.md +4 -3
  7. package/docs/usage.md +1 -1
  8. package/engine/internal/lib/claims.go +12 -2
  9. package/engine/internal/lib/claims_holder.go +124 -0
  10. package/engine/internal/lib/cli_observe.go +14 -0
  11. package/engine/internal/lib/taskgraph.go +124 -0
  12. package/engine/internal/parallel/cli.go +111 -9
  13. package/engine/internal/parallel/lease.go +58 -4
  14. package/engine/internal/parallel/ops.go +244 -75
  15. package/engine/internal/parallel/select.go +31 -6
  16. package/pack/.claude/agents/devrites-plan-drafter.md +2 -1
  17. package/pack/.claude/agents/devrites-slice-wright.md +2 -1
  18. package/pack/.claude/skills/devrites-debug-recovery/SKILL.md +5 -4
  19. package/pack/.claude/skills/devrites-lib/reference/parallel-dispatch.md +7 -2
  20. package/pack/.claude/skills/devrites-lib/reference/reply-contract.md +12 -15
  21. package/pack/.claude/skills/devrites-lib/reference/standards/afk-hitl.md +28 -8
  22. package/pack/.claude/skills/devrites-lib/reference/standards/agents.md +6 -2
  23. package/pack/.claude/skills/devrites-lib/reference/standards/core.md +1 -1
  24. package/pack/.claude/skills/devrites-lib/reference/standards/one-shot-actions.md +7 -6
  25. package/pack/.claude/skills/devrites-lib/reference/standards/workflow-artifacts.md +10 -6
  26. package/pack/.claude/skills/devrites-lib/reference/workspace-artifact-schema.md +1 -1
  27. package/pack/.claude/skills/rite-autocomplete/SKILL.md +13 -11
  28. package/pack/.claude/skills/rite-autocomplete/reference/loop.md +8 -6
  29. package/pack/.claude/skills/rite-autocomplete/reference/stop-conditions.md +28 -21
  30. package/pack/.claude/skills/rite-build/SKILL.md +7 -7
  31. package/pack/.claude/skills/rite-build/reference/afk-discipline.md +8 -5
  32. package/pack/.claude/skills/rite-build/reference/checkpoint.md +1 -1
  33. package/pack/.claude/skills/rite-build/reference/one-slice-cycle.md +1 -1
  34. package/pack/.claude/skills/rite-build/reference/parallel-batch.md +33 -26
  35. package/pack/.claude/skills/rite-build/reference/phase-contract.md +10 -1
  36. package/pack/.claude/skills/rite-build/reference/spec-drift-guard.md +3 -2
  37. package/pack/.claude/skills/rite-build/reference/wright-dispatch.md +2 -2
  38. package/pack/.claude/skills/rite-define/SKILL.md +1 -1
  39. package/pack/.claude/skills/rite-handoff/SKILL.md +1 -1
  40. package/pack/.claude/skills/rite-plan/SKILL.md +1 -1
  41. package/pack/.claude/skills/rite-plan/reference/slicing.md +5 -0
  42. package/pack/.claude/skills/rite-prove/SKILL.md +4 -2
  43. package/pack/.claude/skills/rite-prove/reference/failure-triage.md +2 -1
  44. package/pack/.claude/skills/rite-spec/reference/state-workspace.md +2 -2
  45. package/pack/.claude/skills/rite-vet/reference/artifacts.md +8 -0
  46. package/pack/.claude/skills/rite-vet/reference/review-axes.md +1 -1
  47. package/pack/generated/claude/agents/devrites-plan-drafter.md +2 -1
  48. package/pack/generated/claude/agents/devrites-slice-wright.md +2 -1
  49. package/pack/generated/claude/skills/devrites-debug-recovery/SKILL.md +5 -4
  50. package/pack/generated/claude/skills/devrites-lib/reference/parallel-dispatch.md +7 -2
  51. package/pack/generated/claude/skills/devrites-lib/reference/reply-contract.md +12 -15
  52. package/pack/generated/claude/skills/devrites-lib/reference/standards/afk-hitl.md +28 -8
  53. package/pack/generated/claude/skills/devrites-lib/reference/standards/agents.md +6 -2
  54. package/pack/generated/claude/skills/devrites-lib/reference/standards/core.md +1 -1
  55. package/pack/generated/claude/skills/devrites-lib/reference/standards/one-shot-actions.md +7 -6
  56. package/pack/generated/claude/skills/devrites-lib/reference/standards/workflow-artifacts.md +10 -6
  57. package/pack/generated/claude/skills/devrites-lib/reference/workspace-artifact-schema.md +1 -1
  58. package/pack/generated/claude/skills/rite-autocomplete/SKILL.md +13 -11
  59. package/pack/generated/claude/skills/rite-autocomplete/reference/loop.md +8 -6
  60. package/pack/generated/claude/skills/rite-autocomplete/reference/stop-conditions.md +28 -21
  61. package/pack/generated/claude/skills/rite-build/SKILL.md +7 -7
  62. package/pack/generated/claude/skills/rite-build/reference/afk-discipline.md +8 -5
  63. package/pack/generated/claude/skills/rite-build/reference/checkpoint.md +1 -1
  64. package/pack/generated/claude/skills/rite-build/reference/one-slice-cycle.md +1 -1
  65. package/pack/generated/claude/skills/rite-build/reference/parallel-batch.md +33 -26
  66. package/pack/generated/claude/skills/rite-build/reference/phase-contract.md +10 -1
  67. package/pack/generated/claude/skills/rite-build/reference/spec-drift-guard.md +3 -2
  68. package/pack/generated/claude/skills/rite-build/reference/wright-dispatch.md +2 -2
  69. package/pack/generated/claude/skills/rite-define/SKILL.md +1 -1
  70. package/pack/generated/claude/skills/rite-handoff/SKILL.md +1 -1
  71. package/pack/generated/claude/skills/rite-plan/SKILL.md +1 -1
  72. package/pack/generated/claude/skills/rite-plan/reference/slicing.md +5 -0
  73. package/pack/generated/claude/skills/rite-prove/SKILL.md +4 -2
  74. package/pack/generated/claude/skills/rite-prove/reference/failure-triage.md +2 -1
  75. package/pack/generated/claude/skills/rite-spec/reference/state-workspace.md +2 -2
  76. package/pack/generated/claude/skills/rite-vet/reference/artifacts.md +8 -0
  77. package/pack/generated/claude/skills/rite-vet/reference/review-axes.md +1 -1
  78. package/pack/generated/codex/agents/devrites-plan-drafter.toml +2 -1
  79. package/pack/generated/codex/agents/devrites-slice-wright.toml +2 -1
  80. package/pack/generated/codex/skills/devrites-debug-recovery/SKILL.md +5 -4
  81. package/pack/generated/codex/skills/devrites-lib/reference/parallel-dispatch.md +7 -2
  82. package/pack/generated/codex/skills/devrites-lib/reference/reply-contract.md +12 -15
  83. package/pack/generated/codex/skills/devrites-lib/reference/standards/afk-hitl.md +28 -8
  84. package/pack/generated/codex/skills/devrites-lib/reference/standards/agents.md +6 -2
  85. package/pack/generated/codex/skills/devrites-lib/reference/standards/core.md +1 -1
  86. package/pack/generated/codex/skills/devrites-lib/reference/standards/one-shot-actions.md +7 -6
  87. package/pack/generated/codex/skills/devrites-lib/reference/standards/workflow-artifacts.md +10 -6
  88. package/pack/generated/codex/skills/devrites-lib/reference/workspace-artifact-schema.md +1 -1
  89. package/pack/generated/codex/skills/rite-autocomplete/SKILL.md +13 -11
  90. package/pack/generated/codex/skills/rite-autocomplete/reference/loop.md +8 -6
  91. package/pack/generated/codex/skills/rite-autocomplete/reference/stop-conditions.md +28 -21
  92. package/pack/generated/codex/skills/rite-build/SKILL.md +7 -7
  93. package/pack/generated/codex/skills/rite-build/reference/afk-discipline.md +8 -5
  94. package/pack/generated/codex/skills/rite-build/reference/checkpoint.md +1 -1
  95. package/pack/generated/codex/skills/rite-build/reference/one-slice-cycle.md +1 -1
  96. package/pack/generated/codex/skills/rite-build/reference/parallel-batch.md +33 -26
  97. package/pack/generated/codex/skills/rite-build/reference/phase-contract.md +10 -1
  98. package/pack/generated/codex/skills/rite-build/reference/spec-drift-guard.md +3 -2
  99. package/pack/generated/codex/skills/rite-build/reference/wright-dispatch.md +2 -2
  100. package/pack/generated/codex/skills/rite-define/SKILL.md +1 -1
  101. package/pack/generated/codex/skills/rite-handoff/SKILL.md +1 -1
  102. package/pack/generated/codex/skills/rite-plan/SKILL.md +1 -1
  103. package/pack/generated/codex/skills/rite-plan/reference/slicing.md +5 -0
  104. package/pack/generated/codex/skills/rite-prove/SKILL.md +4 -2
  105. package/pack/generated/codex/skills/rite-prove/reference/failure-triage.md +2 -1
  106. package/pack/generated/codex/skills/rite-spec/reference/state-workspace.md +2 -2
  107. package/pack/generated/codex/skills/rite-vet/reference/artifacts.md +8 -0
  108. package/pack/generated/codex/skills/rite-vet/reference/review-axes.md +1 -1
  109. package/pack/generated/devin/agents/devrites-plan-drafter.md +2 -1
  110. package/pack/generated/devin/agents/devrites-slice-wright.md +2 -1
  111. package/pack/generated/devin/skills/devrites-debug-recovery/SKILL.md +5 -4
  112. package/pack/generated/devin/skills/devrites-lib/reference/parallel-dispatch.md +7 -2
  113. package/pack/generated/devin/skills/devrites-lib/reference/reply-contract.md +12 -15
  114. package/pack/generated/devin/skills/devrites-lib/reference/standards/afk-hitl.md +28 -8
  115. package/pack/generated/devin/skills/devrites-lib/reference/standards/agents.md +6 -2
  116. package/pack/generated/devin/skills/devrites-lib/reference/standards/core.md +1 -1
  117. package/pack/generated/devin/skills/devrites-lib/reference/standards/one-shot-actions.md +7 -6
  118. package/pack/generated/devin/skills/devrites-lib/reference/standards/workflow-artifacts.md +10 -6
  119. package/pack/generated/devin/skills/devrites-lib/reference/workspace-artifact-schema.md +1 -1
  120. package/pack/generated/devin/skills/rite-autocomplete/SKILL.md +13 -11
  121. package/pack/generated/devin/skills/rite-autocomplete/reference/loop.md +8 -6
  122. package/pack/generated/devin/skills/rite-autocomplete/reference/stop-conditions.md +28 -21
  123. package/pack/generated/devin/skills/rite-build/SKILL.md +7 -7
  124. package/pack/generated/devin/skills/rite-build/reference/afk-discipline.md +8 -5
  125. package/pack/generated/devin/skills/rite-build/reference/checkpoint.md +1 -1
  126. package/pack/generated/devin/skills/rite-build/reference/one-slice-cycle.md +1 -1
  127. package/pack/generated/devin/skills/rite-build/reference/parallel-batch.md +33 -26
  128. package/pack/generated/devin/skills/rite-build/reference/phase-contract.md +10 -1
  129. package/pack/generated/devin/skills/rite-build/reference/spec-drift-guard.md +3 -2
  130. package/pack/generated/devin/skills/rite-build/reference/wright-dispatch.md +2 -2
  131. package/pack/generated/devin/skills/rite-define/SKILL.md +1 -1
  132. package/pack/generated/devin/skills/rite-handoff/SKILL.md +1 -1
  133. package/pack/generated/devin/skills/rite-plan/SKILL.md +1 -1
  134. package/pack/generated/devin/skills/rite-plan/reference/slicing.md +5 -0
  135. package/pack/generated/devin/skills/rite-prove/SKILL.md +4 -2
  136. package/pack/generated/devin/skills/rite-prove/reference/failure-triage.md +2 -1
  137. package/pack/generated/devin/skills/rite-spec/reference/state-workspace.md +2 -2
  138. package/pack/generated/devin/skills/rite-vet/reference/artifacts.md +8 -0
  139. package/pack/generated/devin/skills/rite-vet/reference/review-axes.md +1 -1
  140. package/pack/generated/omp/agents/devrites-plan-drafter.md +2 -1
  141. package/pack/generated/omp/agents/devrites-slice-wright.md +2 -1
  142. package/pack/generated/omp/skills/devrites-debug-recovery/SKILL.md +5 -4
  143. package/pack/generated/omp/skills/devrites-lib/reference/parallel-dispatch.md +7 -2
  144. package/pack/generated/omp/skills/devrites-lib/reference/reply-contract.md +12 -15
  145. package/pack/generated/omp/skills/devrites-lib/reference/standards/afk-hitl.md +28 -8
  146. package/pack/generated/omp/skills/devrites-lib/reference/standards/agents.md +6 -2
  147. package/pack/generated/omp/skills/devrites-lib/reference/standards/core.md +1 -1
  148. package/pack/generated/omp/skills/devrites-lib/reference/standards/one-shot-actions.md +7 -6
  149. package/pack/generated/omp/skills/devrites-lib/reference/standards/workflow-artifacts.md +10 -6
  150. package/pack/generated/omp/skills/devrites-lib/reference/workspace-artifact-schema.md +1 -1
  151. package/pack/generated/omp/skills/rite-autocomplete/SKILL.md +13 -11
  152. package/pack/generated/omp/skills/rite-autocomplete/reference/loop.md +8 -6
  153. package/pack/generated/omp/skills/rite-autocomplete/reference/stop-conditions.md +28 -21
  154. package/pack/generated/omp/skills/rite-build/SKILL.md +7 -7
  155. package/pack/generated/omp/skills/rite-build/reference/afk-discipline.md +8 -5
  156. package/pack/generated/omp/skills/rite-build/reference/checkpoint.md +1 -1
  157. package/pack/generated/omp/skills/rite-build/reference/one-slice-cycle.md +1 -1
  158. package/pack/generated/omp/skills/rite-build/reference/parallel-batch.md +33 -26
  159. package/pack/generated/omp/skills/rite-build/reference/phase-contract.md +10 -1
  160. package/pack/generated/omp/skills/rite-build/reference/spec-drift-guard.md +3 -2
  161. package/pack/generated/omp/skills/rite-build/reference/wright-dispatch.md +2 -2
  162. package/pack/generated/omp/skills/rite-define/SKILL.md +1 -1
  163. package/pack/generated/omp/skills/rite-handoff/SKILL.md +1 -1
  164. package/pack/generated/omp/skills/rite-plan/SKILL.md +1 -1
  165. package/pack/generated/omp/skills/rite-plan/reference/slicing.md +5 -0
  166. package/pack/generated/omp/skills/rite-prove/SKILL.md +4 -2
  167. package/pack/generated/omp/skills/rite-prove/reference/failure-triage.md +2 -1
  168. package/pack/generated/omp/skills/rite-spec/reference/state-workspace.md +2 -2
  169. package/pack/generated/omp/skills/rite-vet/reference/artifacts.md +8 -0
  170. package/pack/generated/omp/skills/rite-vet/reference/review-axes.md +1 -1
  171. package/pack/generated/pi/agents/devrites-plan-drafter.md +2 -1
  172. package/pack/generated/pi/agents/devrites-slice-wright.md +2 -1
  173. package/pack/generated/pi/skills/devrites-debug-recovery/SKILL.md +5 -4
  174. package/pack/generated/pi/skills/devrites-lib/reference/parallel-dispatch.md +7 -2
  175. package/pack/generated/pi/skills/devrites-lib/reference/reply-contract.md +12 -15
  176. package/pack/generated/pi/skills/devrites-lib/reference/standards/afk-hitl.md +28 -8
  177. package/pack/generated/pi/skills/devrites-lib/reference/standards/agents.md +6 -2
  178. package/pack/generated/pi/skills/devrites-lib/reference/standards/core.md +1 -1
  179. package/pack/generated/pi/skills/devrites-lib/reference/standards/one-shot-actions.md +7 -6
  180. package/pack/generated/pi/skills/devrites-lib/reference/standards/workflow-artifacts.md +10 -6
  181. package/pack/generated/pi/skills/devrites-lib/reference/workspace-artifact-schema.md +1 -1
  182. package/pack/generated/pi/skills/rite-autocomplete/SKILL.md +13 -11
  183. package/pack/generated/pi/skills/rite-autocomplete/reference/loop.md +8 -6
  184. package/pack/generated/pi/skills/rite-autocomplete/reference/stop-conditions.md +28 -21
  185. package/pack/generated/pi/skills/rite-build/SKILL.md +7 -7
  186. package/pack/generated/pi/skills/rite-build/reference/afk-discipline.md +8 -5
  187. package/pack/generated/pi/skills/rite-build/reference/checkpoint.md +1 -1
  188. package/pack/generated/pi/skills/rite-build/reference/one-slice-cycle.md +1 -1
  189. package/pack/generated/pi/skills/rite-build/reference/parallel-batch.md +33 -26
  190. package/pack/generated/pi/skills/rite-build/reference/phase-contract.md +10 -1
  191. package/pack/generated/pi/skills/rite-build/reference/spec-drift-guard.md +3 -2
  192. package/pack/generated/pi/skills/rite-build/reference/wright-dispatch.md +2 -2
  193. package/pack/generated/pi/skills/rite-define/SKILL.md +1 -1
  194. package/pack/generated/pi/skills/rite-handoff/SKILL.md +1 -1
  195. package/pack/generated/pi/skills/rite-plan/SKILL.md +1 -1
  196. package/pack/generated/pi/skills/rite-plan/reference/slicing.md +5 -0
  197. package/pack/generated/pi/skills/rite-prove/SKILL.md +4 -2
  198. package/pack/generated/pi/skills/rite-prove/reference/failure-triage.md +2 -1
  199. package/pack/generated/pi/skills/rite-spec/reference/state-workspace.md +2 -2
  200. package/pack/generated/pi/skills/rite-vet/reference/artifacts.md +8 -0
  201. package/pack/generated/pi/skills/rite-vet/reference/review-axes.md +1 -1
  202. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,18 @@
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
+ ## [6.1.2](https://github.com/ViktorsBaikers/DevRites/compare/v6.1.1...v6.1.2) (2026-10-16)
6
+
7
+ ### Fixed
8
+
9
+ * **devrites:** close autocomplete dead ends and orphaned writer claims ([#108](https://github.com/ViktorsBaikers/DevRites/issues/108)) ([a680203](https://github.com/ViktorsBaikers/DevRites/commit/a680203d226160f9dae3bf5a386914567bd25da5))
10
+
11
+ ## [6.1.1](https://github.com/ViktorsBaikers/DevRites/compare/v6.1.0...v6.1.1) (2026-10-16)
12
+
13
+ ### Fixed
14
+
15
+ * **devrites:** escalate spent recovery strategies instead of dead-ending ([#107](https://github.com/ViktorsBaikers/DevRites/issues/107)) ([bf1c986](https://github.com/ViktorsBaikers/DevRites/commit/bf1c986e28e6ea8fb63aa47a342b036536cb0e38))
16
+
5
17
  ## [6.1.0](https://github.com/ViktorsBaikers/DevRites/compare/v6.0.4...v6.1.0) (2026-10-15)
6
18
 
7
19
  ### Added
package/README.md CHANGED
@@ -31,7 +31,7 @@ history can't lose it. After you clear the conversation, switch hosts, or hand
31
31
  the feature to another engineer, the next session reads the same plan,
32
32
  decisions, and evidence before it continues.
33
33
 
34
- **Status:** [`v6.1.0`](https://github.com/ViktorsBaikers/DevRites/releases/tag/v6.1.0): see [`CHANGELOG.md`](CHANGELOG.md) for release notes.
34
+ **Status:** [`v6.1.2`](https://github.com/ViktorsBaikers/DevRites/releases/tag/v6.1.2): see [`CHANGELOG.md`](CHANGELOG.md) for release notes.
35
35
 
36
36
  This is the latest published release; `main` may contain unreleased work.
37
37
 
@@ -383,7 +383,9 @@ when the answer is required.
383
383
  AFK always pauses for genuine product/scope/policy choices, irreversible risk,
384
384
  and human-only access or actions, regardless of the sentinel. Objective test,
385
385
  type, lint, runtime, and coverage failures stay inside bounded technical
386
- recovery; exhaustion records a blocker without inventing a question. See
386
+ recovery; a spent strategy escalates to a new correction class, and a fully
387
+ escalated fingerprint parks while independent work continues, without inventing a
388
+ question. See
387
389
  [`pack/.claude/skills/devrites-lib/reference/standards/afk-hitl.md`](../pack/.claude/skills/devrites-lib/reference/standards/afk-hitl.md) for the full
388
390
  contract.
389
391
 
package/docs/cli.md CHANGED
@@ -165,7 +165,10 @@ self-contained updater.
165
165
  and exits `3` naming the holder when a live claim by another session covers a
166
166
  path; `release --session <id> --id <claim>` frees it; `list [--all]` shows
167
167
  live (or all) claims; `check [--session <id>] <path>...` is the read-only
168
- preflight. Claims coordinate concurrent same-tree sessions; they never
168
+ preflight. Each claim records its host and the claiming session's long-lived
169
+ processes; when all of them have exited on this host, `list` shows the claim
170
+ `dead` and it no longer conflicts. Other hosts or an unavailable `ps` never
171
+ prove exit. Claims coordinate concurrent same-tree sessions; they never
169
172
  replace the one-writer-per-worktree rule in `standards/agents.md`.
170
173
  - `note <add|list|check|rm>` manages `notes.md` anchored notes: `add <slug>
171
174
  <subject> <quote> <title> [body]` binds a note to a verbatim quote in one
@@ -16,9 +16,9 @@ workflow strategy.
16
16
  | `check readiness --emit-binding <slug>` | Render the exact stable Build-input binding for Vet to record after review. |
17
17
  | `check seal <slug>` | Check files required by target Phase `seal`, open human gates, the `tasks.md` slice graph, canonical `AC-###` presence when `tasks.md`/`test-plan.md` are required, the stable Build-input binding, and exact candidate bindings. |
18
18
  | `check path-disjoint [--root <dir>] [<json-file> | -]` | Verify slice path sets are pairwise disjoint. |
19
- | `parallel select --cap <1-10> [--root <dir>] [<json-file> | -]` | Choose the greedy path-disjoint subset ≤ cap from supplied ready slices. |
20
- | `parallel <create\|integrate\|cleanup\|status\|abort\|lease-read\|lease-write\|lease-clear\|record-green>` | Deterministic parallel worktree leases, integration, and cleanup for parallel writer batches. |
21
- | `check task-graph <slug>` | Validate `tasks.md` slice dependency graph for cycles, unknown deps, malformed tokens, duplicate IDs, missing `Dependencies`, and `depends_on` mismatch. Prints a non-blocking `ADVISORY size:` line (and records a `size-advisory` metric) for each slice with 12+ Writer allowlist files and no `Size rationale:`. A `Dependencies` ID may carry a `(via <interface>)` suffix (empty or unclosed is a malformed token); prints a non-blocking `ADVISORY edge:` line (and records an `edge-advisory` metric) for each edge with no via, or whose via text is not a case-insensitive substring of the dependency's `Consumes / Produces:`. Advisories print only when the graph is valid. |
19
+ | `parallel select --cap <1-10> [--root <dir>] [--slug <slug>] [<json-file> | -]` | Choose the greedy path-disjoint subset ≤ cap from supplied ready slices. With `--slug` and a running lease, the lease's not-yet-landed slices hold cap slots and paths, and only new picks print. |
20
+ | `parallel <create\|add\|integrate\|cleanup\|status\|abort\|lease-read\|lease-write\|lease-clear\|record-green>` | Deterministic parallel worktree leases, integration, and cleanup for parallel writer batches. A lease is a pipeline: `integrate --slice <id> --apply-to-control` lands one green sibling onto control (refusing if anything but this lease moved control), and `add` starts new path-disjoint siblings from the current control tip while others still run. |
21
+ | `check task-graph <slug>` | Validate `tasks.md` slice dependency graph for cycles, unknown deps, malformed tokens, duplicate IDs, missing `Dependencies`, and `depends_on` mismatch. Prints a non-blocking `ADVISORY size:` line (and records a `size-advisory` metric) for each slice with 12+ Writer allowlist files and no `Size rationale:`. A `Dependencies` ID may carry a `(via <interface>)` suffix (empty or unclosed is a malformed token); prints a non-blocking `ADVISORY edge:` line (and records an `edge-advisory` metric) for each edge with no via, or whose via text is not a case-insensitive substring of the dependency's `Consumes / Produces:`. Prints `schedule: <n> slices in <r> build rounds at cap 10` (the `/rite-build` batch selection replayed over each slice's Writer allowlist, else Files likely touched; omitted when a slice has no path) and a non-blocking `ADVISORY hub:` line (top five; records a `hub-advisory` metric) for each path, compared case-folded, that three or more slices without `Serial rationale:` write. Advisories print only when the graph is valid. |
22
22
  | `check regression <slug> [--update]` | Compare the workspace's structural progress facts (phase ordinal, checked ACs, met/abandoned gates, done slices, resolved questions, present artifacts) against the recorded `regression-baseline.json` high-water mark; `--update` ratchets the baseline forward under the feature lock and prints each blessed regression. |
23
23
  | `check drift <slug> [--record]` | Attribute readiness-input changes to the exact artifact. `--record` writes the per-input `readiness-inputs.json` digest baseline under the feature lock; without it the workspace diffs current inputs against that baseline (or falls back to the aggregate binding recorded in `eng-review.md`). Advisory: exit `0` on drift; a corrupt baseline exits `3`. A `test-plan.md` change limited to exact `Workflow Artifact reviewed identity: <64hex>` lines is reported as `reviewed-identity-only` (ADR-0034). |
24
24
  | `check windows <slug> [--worktree\|--staged\|--base <ref>]` | Fail on deferral and bar-lowering markers the change introduces without a waiver row in the workspace's `windows.md`: added TODO/FIXME/XXX/HACK, skipped/focused-test and stub idioms, checker suppressions, one-line empty catch; removed `deleted-test` files and net `removed-assertion` lines in remaining test files. |
@@ -37,7 +37,7 @@ workflow strategy.
37
37
  | `dispatch <slug> <open\|start\|seal\|return\|status\|abandon>` | Launch-wave barrier for parallel dispatch: seal needs a handle per role, return needs seal; start/return auto-record metrics. A build wave with a wright role needs `--slice <SLICE-ID>` per slice, and a slice-bound vet wave takes it too; every 5 rounds of either kind on one slice, `open` exits `3` until `--reslice-review <DRIFT-ID>` names an unused `drift.md` `## <DRIFT-ID>` heading for that slice. `open` also warns when an earlier wave for the same slice never returned. |
38
38
  | `metrics record <slug> --phase <p> --event <e> [--role r] [--bytes n] [--note s]` | Append an event to the workspace's `metrics.jsonl` ledger. |
39
39
  | `metrics summary [slug] [--by-slice]` | Reduce `metrics.jsonl` into a per-phase roll-up. `--by-slice` reads `dispatch.json` instead: per slice, build wright rounds, slice-bound Vet rechecks, and agent-minutes (role start to `returned_at`; abandoned waves excluded). |
40
- | `claim <add\|release\|list\|check>` | Advisory session-scoped file claims in `.devrites/claims.jsonl` (append-only). `add` records intent to write a path set with a TTL (1–240 min, default 30); a live claim by another session exits `3` and names the holder. `release` appends a release event owned by the claiming session. `list` shows live claims (`--all` includes expired/released). `check` is the read-only preflight for a path set. Coordination aid only — never a substitute for one-writer-per-worktree. |
40
+ | `claim <add\|release\|list\|check>` | Advisory session-scoped file claims in `.devrites/claims.jsonl` (append-only). `add` records intent to write a path set with a TTL (1–240 min, default 30); a live claim by another session exits `3` and names the holder. `release` appends a release event owned by the claiming session. `list` shows live claims (`--all` includes expired/released); a claim whose holding session has provably exited on this host shows `dead` and no longer conflicts. `check` is the read-only preflight for a path set. Coordination aid only — never a substitute for one-writer-per-worktree. |
41
41
  | `note <add\|list\|check\|rm> <slug> ...` | Anchored workspace notes in `notes.md`: `add <slug> <subject> <quote> <title> [body]` binds a note to a verbatim quote in one repository file and assigns `NOTE-###`; `list` and `check` regrade each anchor `exact`/`moved`/`stale`/`ambiguous`/`lost` by searching the repo for the quote (dependency and workspace trees excluded); `check --repair` rewrites a `moved` subject to its new file; `rm` deletes by ID. `check seal` refuses a malformed `notes.md` and any non-`exact` anchor. |
42
42
  | `gates <scaffold\|status\|run\|reverify\|lint\|attest\|abandon> <slug>` | Operate the `gates.md` acceptance ledger: seed per-AC gates, execute runnable gates bound to `test-plan.md` preflight rows, attest manual gates, and reduce to `all-met`/`not-met`/`handoff`/`malformed`. |
43
43
  | `state resolve <qid> "<answer>"` | Resolve an open question and update `questions.md` plus `state.md` atomically. |
@@ -138,9 +138,10 @@ and a control `parallel-lease.md` apply. `--parallel N` on `/rite-autocomplete`
138
138
  or `/rite-build` is the batch cap for that run and wins over leftover sentinel
139
139
  `max_parallel`; `/rite-autocomplete --parallel N` also writes or replaces only
140
140
  that field. Absent the flag, the sentinel (default cap 10 under
141
- `/rite-autocomplete`) is a **cap**: each round runs
142
- the largest eligible set, recomputes after every completed round, and repeats until no
143
- pending slice remains; a one-slice round is serial for that round only (see
141
+ `/rite-autocomplete`) is a **cap**: the run fills it
142
+ with the largest eligible set, lands each sibling as soon as its review and proof are
143
+ green, refills the freed slot (`parallel add`), and repeats until no pending slice
144
+ remains; a one-slice round is serial for that round only (see
144
145
  [`parallel-batch.md`](../pack/.claude/skills/rite-build/reference/parallel-batch.md)).
145
146
  Same-worktree multi-writer and root-emulated worktrees remain forbidden; default
146
147
  `/rite-build` stays one writer across linked worktrees.
package/docs/usage.md CHANGED
@@ -71,7 +71,7 @@ Project-root sentinel (outside the workspace):
71
71
  | `.devrites/AFK` | you (presence = AFK mode active) | optional YAML: `max_slices`, `notify`, `allow_gates`. Empty file = AFK with defaults. See [`pack/.claude/skills/devrites-lib/reference/standards/afk-hitl.md`](../pack/.claude/skills/devrites-lib/reference/standards/afk-hitl.md). |
72
72
  | `.devrites/CHECKPOINT` | unused as a gate | reserved path (not a candidate). After Independent Build review and fail-on-red proof are green (not when a wright returns), `/rite-build` / `/rite-prove` / `/rite-polish` / `/rite-review` land a local `WIP(<slug>): <imperative summary>` commit (serial: checkpoint git recipe or no-op if nothing staged; parallel: `devrites-engine parallel integrate`); `/rite-ship` later collapses an eligible WIP run. See [`pack/.claude/skills/rite-build/reference/checkpoint.md`](../pack/.claude/skills/rite-build/reference/checkpoint.md). |
73
73
  | `.devrites/dup-ignore` | you (optional) | One `check dup` cluster hash per line with a `#` reason — the dismissal ledger. Content-derived hashes survive line moves but resurface on structural edits. See [`pack/.claude/skills/devrites-lib/reference/standards/duplicate-code.md`](../pack/.claude/skills/devrites-lib/reference/standards/duplicate-code.md). |
74
- | `.devrites/claims.jsonl` | `devrites-engine claim add` | Append-only advisory file claims: `{id, session, paths, reason, claimed_at, expires_at}` plus release events. Session-scoped and TTL-bounded — per-checkout state, so gitignore it (a committed ledger exports stale claims to every clone). See [`standards/agents.md`](../pack/.claude/skills/devrites-lib/reference/standards/agents.md). |
74
+ | `.devrites/claims.jsonl` | `devrites-engine claim add` | Append-only advisory file claims: `{id, session, paths, reason, claimed_at, expires_at, host, anchors}` plus release events. Session-scoped and TTL-bounded — per-checkout state, so gitignore it (a committed ledger exports stale claims to every clone). See [`standards/agents.md`](../pack/.claude/skills/devrites-lib/reference/standards/agents.md). |
75
75
 
76
76
  The shape of this directory is also documented in
77
77
  [`flow.md` § Workspace state model](flow.md#7-workspace-state-model).
@@ -51,6 +51,10 @@ type claimRecord struct {
51
51
  ClaimedAt string `json:"claimed_at"`
52
52
  ExpiresAt string `json:"expires_at"`
53
53
  Released bool `json:"released,omitempty"`
54
+ // Host and Anchors identify the claiming session's long-lived processes,
55
+ // so a later session can prove that holder exited (see holderProbe).
56
+ Host string `json:"host,omitempty"`
57
+ Anchors []claimProc `json:"anchors,omitempty"`
54
58
  }
55
59
 
56
60
  // RunClaim manages the advisory file-claim ledger.
@@ -299,7 +303,8 @@ func claimAddLocked(path, session, reason string, ttl int, paths []string, stdou
299
303
  return 2
300
304
  }
301
305
  now := time.Now().UTC()
302
- conflicts := claimConflicts(liveClaims(latest, order, now), session, paths)
306
+ probe := newHolderProbe()
307
+ conflicts := claimConflicts(probe.withoutGone(liveClaims(latest, order, now)), session, paths)
303
308
  if len(conflicts) > 0 {
304
309
  printConflicts(stderr, conflicts)
305
310
  return 3
@@ -311,6 +316,8 @@ func claimAddLocked(path, session, reason string, ttl int, paths []string, stdou
311
316
  Reason: reason,
312
317
  ClaimedAt: now.Format(time.RFC3339),
313
318
  ExpiresAt: now.Add(time.Duration(ttl) * time.Minute).Format(time.RFC3339),
319
+ Host: probe.host,
320
+ Anchors: probe.anchors(now),
314
321
  }
315
322
  if err := appendClaim(path, rec); err != nil {
316
323
  fmt.Fprintf(stderr, "claim: %v\n", err)
@@ -389,6 +396,7 @@ func claimList(root string, args []string, stdout, stderr io.Writer) int {
389
396
  return 2
390
397
  }
391
398
  now := time.Now().UTC()
399
+ probe := newHolderProbe()
392
400
  rows := liveClaims(latest, order, now)
393
401
  if all {
394
402
  rows = rows[:0]
@@ -404,6 +412,8 @@ func claimList(root string, args []string, stdout, stderr io.Writer) int {
404
412
  state := "live"
405
413
  if rec.Released {
406
414
  state = "released"
415
+ } else if probe.gone(rec) {
416
+ state = "dead"
407
417
  } else if exp, err := time.Parse(time.RFC3339, rec.ExpiresAt); err != nil || !exp.After(now) {
408
418
  state = "expired"
409
419
  }
@@ -453,7 +463,7 @@ func claimCheck(root string, args []string, stdout, stderr io.Writer) int {
453
463
  fmt.Fprintf(stderr, unparsedLedgerMsg, bad)
454
464
  return 2
455
465
  }
456
- conflicts := claimConflicts(liveClaims(latest, order, time.Now().UTC()), session, paths)
466
+ conflicts := claimConflicts(newHolderProbe().withoutGone(liveClaims(latest, order, time.Now().UTC())), session, paths)
457
467
  if len(conflicts) > 0 {
458
468
  printConflicts(stdout, conflicts)
459
469
  return 3
@@ -0,0 +1,124 @@
1
+ package lib
2
+
3
+ import (
4
+ "os"
5
+ "os/exec"
6
+ "slices"
7
+ "strconv"
8
+ "strings"
9
+ "time"
10
+ )
11
+
12
+ // claimAnchorAge separates a claiming session's long-lived host processes from
13
+ // the per-command shells and launchers that start moments before `claim add`.
14
+ const claimAnchorAge = time.Minute
15
+
16
+ // claimProc names one process by pid and start time, so a reused pid cannot
17
+ // impersonate it.
18
+ type claimProc struct {
19
+ PID int `json:"pid"`
20
+ Start string `json:"start"`
21
+ }
22
+
23
+ type procInfo struct {
24
+ ppid int
25
+ start string
26
+ }
27
+
28
+ // processTable lists running processes keyed by pid, or nil when the host
29
+ // cannot say. Tests replace it.
30
+ var processTable = psProcessTable
31
+
32
+ func psProcessTable() map[int]procInfo {
33
+ cmd := exec.Command("ps", "-A", "-o", "pid=,ppid=,lstart=")
34
+ cmd.Env = append(os.Environ(), "LC_ALL=C")
35
+ out, err := cmd.Output()
36
+ if err != nil {
37
+ return nil
38
+ }
39
+ table := map[int]procInfo{}
40
+ for _, line := range strings.Split(string(out), "\n") {
41
+ f := strings.Fields(line)
42
+ if len(f) != 7 {
43
+ continue
44
+ }
45
+ pid, perr := strconv.Atoi(f[0])
46
+ ppid, pperr := strconv.Atoi(f[1])
47
+ start, serr := time.ParseInLocation("Mon Jan 2 15:04:05 2006", strings.Join(f[2:], " "), time.Local)
48
+ if perr != nil || pperr != nil || serr != nil {
49
+ continue
50
+ }
51
+ table[pid] = procInfo{ppid: ppid, start: start.UTC().Format(time.RFC3339)}
52
+ }
53
+ if len(table) == 0 {
54
+ return nil
55
+ }
56
+ return table
57
+ }
58
+
59
+ // lineage walks from pid up to, but not including, pid 1.
60
+ func lineage(table map[int]procInfo, pid int) []claimProc {
61
+ var out []claimProc
62
+ seen := map[int]bool{}
63
+ for pid > 1 && !seen[pid] {
64
+ seen[pid] = true
65
+ p, ok := table[pid]
66
+ if !ok {
67
+ break
68
+ }
69
+ out = append(out, claimProc{PID: pid, Start: p.start})
70
+ pid = p.ppid
71
+ }
72
+ return out
73
+ }
74
+
75
+ // holderProbe answers whether a claim's holding session has exited. It only
76
+ // ever proves exit on this host; anything it cannot see counts as alive.
77
+ type holderProbe struct {
78
+ table map[int]procInfo
79
+ host string
80
+ self []claimProc
81
+ }
82
+
83
+ func newHolderProbe() holderProbe {
84
+ table := processTable()
85
+ host, _ := os.Hostname()
86
+ return holderProbe{table: table, host: host, self: lineage(table, os.Getppid())}
87
+ }
88
+
89
+ // anchors returns the caller's ancestors that started more than
90
+ // claimAnchorAge before now: the session's host processes.
91
+ func (p holderProbe) anchors(now time.Time) []claimProc {
92
+ var out []claimProc
93
+ for _, proc := range p.self {
94
+ start, err := time.Parse(time.RFC3339, proc.Start)
95
+ if err == nil && now.Sub(start) > claimAnchorAge {
96
+ out = append(out, proc)
97
+ }
98
+ }
99
+ return out
100
+ }
101
+
102
+ // gone reports whether rec's holder is proven exited: the claim was taken on
103
+ // this host and every anchor it does not share with the caller has exited.
104
+ func (p holderProbe) gone(rec *claimRecord) bool {
105
+ if p.table == nil || rec.Host == "" || rec.Host != p.host {
106
+ return false
107
+ }
108
+ unique := 0
109
+ for _, a := range rec.Anchors {
110
+ if slices.Contains(p.self, a) {
111
+ continue
112
+ }
113
+ unique++
114
+ if proc, ok := p.table[a.PID]; ok && proc.start == a.Start {
115
+ return false
116
+ }
117
+ }
118
+ return unique > 0
119
+ }
120
+
121
+ // withoutGone drops claims whose holder session has exited.
122
+ func (p holderProbe) withoutGone(claims []*claimRecord) []*claimRecord {
123
+ return slices.DeleteFunc(claims, p.gone)
124
+ }
@@ -5,6 +5,7 @@ import (
5
5
  "io"
6
6
 
7
7
  "github.com/devrites/devrites/internal/devritespaths"
8
+ "github.com/devrites/devrites/internal/parallel"
8
9
  "github.com/devrites/devrites/internal/state"
9
10
  )
10
11
 
@@ -36,6 +37,19 @@ func RunTaskGraphCheck(root, slug string, stdout, stderr io.Writer) int {
36
37
  if over > 0 {
37
38
  recordMetric(root, slug, "define", "size-advisory", "", int64(over))
38
39
  }
40
+ paths, serial := sliceWritePaths(raw, graph)
41
+ if rounds := scheduleRounds(graph, paths, root); rounds > 0 {
42
+ fmt.Fprintf(stdout, "task-graph: schedule: %d slices in %d build rounds at cap %d\n", len(graph.Slices), rounds, parallel.MaxParallelSlices)
43
+ }
44
+ if hubs := hubAdvisories(graph, paths, serial); len(hubs) > 0 {
45
+ for _, line := range hubs[:min(len(hubs), hubAdvisoryShown)] {
46
+ fmt.Fprintf(stdout, "task-graph: %s\n", line)
47
+ }
48
+ if extra := len(hubs) - hubAdvisoryShown; extra > 0 {
49
+ fmt.Fprintf(stdout, "task-graph: ADVISORY hub: %d more shared paths; fix the ones above first\n", extra)
50
+ }
51
+ recordMetric(root, slug, "define", "hub-advisory", "", int64(len(hubs)))
52
+ }
39
53
  }
40
54
  if edges := edgeAdvisories(graph); len(edges) > 0 {
41
55
  for _, line := range edges {
@@ -2,8 +2,11 @@ package lib
2
2
 
3
3
  import (
4
4
  "fmt"
5
+ "path"
6
+ "sort"
5
7
  "strings"
6
8
 
9
+ "github.com/devrites/devrites/internal/parallel"
7
10
  "github.com/devrites/devrites/internal/state"
8
11
  )
9
12
 
@@ -27,6 +30,127 @@ func CheckTaskGraph(root, slug string) (TaskGraphResult, error) {
27
30
  return ParseTaskGraph(raw), nil
28
31
  }
29
32
 
33
+ // hubAdvisoryMin is how many slices must write one path before it is flagged:
34
+ // slices sharing a write path never share a parallel build round.
35
+ const hubAdvisoryMin = 3
36
+
37
+ // hubAdvisoryShown caps printed hub lines; the metric still counts every hub.
38
+ const hubAdvisoryShown = 5
39
+
40
+ // sliceWritePaths returns each slice's write set (Writer allowlist, else Files
41
+ // likely touched) and whether it records a `Serial rationale:`.
42
+ func sliceWritePaths(tasksMarkdown []byte, graph TaskGraphResult) (map[string][]string, map[string]bool) {
43
+ paths := make(map[string][]string, len(graph.Slices))
44
+ serial := make(map[string]bool)
45
+ for _, s := range graph.Slices {
46
+ block, _ := state.ExtractTaskSlice(tasksMarkdown, s.ID)
47
+ fields := sliceFields(block)
48
+ allow, _ := fieldValue(fields, "writer allowlist")
49
+ paths[s.ID] = pathTokens(allow)
50
+ if len(paths[s.ID]) == 0 {
51
+ touched, _ := fieldValue(fields, "files likely touched")
52
+ paths[s.ID] = pathTokens(touched)
53
+ }
54
+ if v, _ := fieldValue(fields, "serial rationale"); v != "" {
55
+ serial[s.ID] = true
56
+ }
57
+ }
58
+ return paths, serial
59
+ }
60
+
61
+ // pathTokens keeps the list entries that can be paths; prose and Markdown links
62
+ // (anything with whitespace) are not write paths.
63
+ func pathTokens(raw string) []string {
64
+ var out []string
65
+ for _, p := range parsePathList(raw) {
66
+ if !strings.ContainsAny(p, " \t") {
67
+ out = append(out, p)
68
+ }
69
+ }
70
+ return out
71
+ }
72
+
73
+ // scheduleRounds replays /rite-build batch selection at the maximum cap: each
74
+ // round runs the plan-order path-disjoint subset of dependency-ready slices.
75
+ // It returns 0 when a slice has no write paths or parallel select rejects them.
76
+ func scheduleRounds(graph TaskGraphResult, paths map[string][]string, root string) int {
77
+ done := make(map[string]bool, len(graph.Slices))
78
+ rounds := 0
79
+ for len(done) < len(graph.Slices) {
80
+ var ready []parallel.SlicePaths
81
+ for _, s := range graph.Slices {
82
+ if done[s.ID] || !allDone(s.Dependencies, done) {
83
+ continue
84
+ }
85
+ if len(paths[s.ID]) == 0 {
86
+ return 0
87
+ }
88
+ ready = append(ready, parallel.SlicePaths{ID: s.ID, Paths: paths[s.ID]})
89
+ }
90
+ if len(ready) == 0 {
91
+ return 0
92
+ }
93
+ picked, err := parallel.SelectGreedy(parallel.MaxParallelSlices, ready, root)
94
+ if err != nil || len(picked) == 0 {
95
+ return 0
96
+ }
97
+ for _, p := range picked {
98
+ done[p.ID] = true
99
+ }
100
+ rounds++
101
+ }
102
+ return rounds
103
+ }
104
+
105
+ func allDone(ids []string, done map[string]bool) bool {
106
+ for _, id := range ids {
107
+ if !done[id] {
108
+ return false
109
+ }
110
+ }
111
+ return true
112
+ }
113
+
114
+ // hubAdvisories names each path written by hubAdvisoryMin+ slices that carry
115
+ // no `Serial rationale:`, most-shared first.
116
+ func hubAdvisories(graph TaskGraphResult, paths map[string][]string, serial map[string]bool) []string {
117
+ writers := map[string][]string{}
118
+ shown := map[string]string{} // first spelling seen, for display
119
+ for _, s := range graph.Slices {
120
+ if serial[s.ID] {
121
+ continue
122
+ }
123
+ seen := map[string]bool{}
124
+ for _, p := range paths[s.ID] {
125
+ key := strings.ToLower(path.Clean(strings.ReplaceAll(p, `\`, "/")))
126
+ if !seen[key] {
127
+ seen[key] = true
128
+ writers[key] = append(writers[key], s.ID)
129
+ if _, ok := shown[key]; !ok {
130
+ shown[key] = p
131
+ }
132
+ }
133
+ }
134
+ }
135
+ hubs := make([]string, 0, len(writers))
136
+ for p, ids := range writers {
137
+ if len(ids) >= hubAdvisoryMin {
138
+ hubs = append(hubs, p)
139
+ }
140
+ }
141
+ sort.Slice(hubs, func(i, j int) bool {
142
+ if len(writers[hubs[i]]) != len(writers[hubs[j]]) {
143
+ return len(writers[hubs[i]]) > len(writers[hubs[j]])
144
+ }
145
+ return hubs[i] < hubs[j]
146
+ })
147
+ lines := make([]string, len(hubs))
148
+ for i, p := range hubs {
149
+ lines[i] = fmt.Sprintf("ADVISORY hub: %s is written by %d slices (%s), so they build one at a time; move the shared edit into one seam slice they depend on, or record `Serial rationale:`", shown[p], len(writers[p]), strings.Join(writers[p], ", "))
150
+ }
151
+ return lines
152
+ }
153
+
30
154
  // edgeAdvisories names each dependency edge that does not say what crosses it:
31
155
  // no `(via <interface>)`, or a via the dependency's Consumes / Produces lacks.
32
156
  // An edge the dependent reads nothing across only serializes work.