devrites 5.14.0 → 5.14.1
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/CHANGELOG.md +11 -0
- package/README.md +6 -3
- package/docs/adr/0033-rite-fast-own-agents.md +45 -0
- package/docs/adr/README.md +2 -1
- package/docs/architecture.md +6 -4
- package/docs/command-map.md +2 -1
- package/docs/flow.md +3 -2
- package/docs/orchestration.md +3 -0
- package/docs/quick-reference.md +2 -1
- package/docs/skills.md +13 -8
- package/docs/usage.md +2 -2
- package/engine/internal/install/apply.go +5 -3
- package/engine/internal/install/binary.go +3 -1
- package/engine/internal/install/install.go +0 -25
- package/engine/internal/lib/claims.go +15 -0
- package/engine/internal/lib/claims_test.go +28 -0
- package/engine/internal/lib/context_next_test.go +53 -0
- package/engine/internal/lib/dispatch.go +28 -7
- package/engine/internal/lib/manifest_union.go +14 -0
- package/engine/internal/overhaul/admit/admit_test.go +9 -0
- package/engine/internal/overhaul/admit/run.go +9 -0
- package/engine/internal/overhaul/bench/run.go +327 -38
- package/engine/internal/overhaul/bench/run_test.go +131 -0
- package/engine/internal/overhaul/bench/stats.go +154 -0
- package/engine/internal/overhaul/ovio/ovio.go +4 -0
- package/engine/internal/overhaul/records/check.go +3 -0
- package/engine/internal/overhaul/records/consistency.go +217 -0
- package/engine/internal/overhaul/records/records_test.go +81 -0
- package/engine/internal/overhaul/records/run.go +1 -1
- package/engine/internal/overhaul/render/run.go +2 -0
- package/engine/internal/overhaul/render/run_test.go +5 -1
- package/engine/internal/overhaul/score/run.go +58 -9
- package/engine/internal/overhaul/score/run_test.go +84 -8
- package/engine/internal/parallel/ops.go +5 -0
- package/engine/internal/state/write.go +8 -2
- package/engine/internal/version/version_test.go +27 -0
- package/engine/main.go +2 -2
- package/pack/.claude/agents/fast-builder.md +90 -0
- package/pack/.claude/agents/fast-checker.md +60 -0
- package/pack/.claude/agents/fast-critic.md +70 -0
- package/pack/.claude/agents/fast-planner.md +95 -0
- package/pack/.claude/agents/overhaul-backend-engineer.md +5 -4
- package/pack/.claude/agents/overhaul-boundary.md +2 -2
- package/pack/.claude/agents/overhaul-craft.md +1 -1
- package/pack/.claude/agents/overhaul-frontend-engineer.md +5 -3
- package/pack/.claude/agents/overhaul-implementer.md +9 -5
- package/pack/.claude/agents/overhaul-specialist.md +6 -3
- package/pack/.claude/agents/overhaul-verifier.md +3 -3
- package/pack/.claude/settings.json +1 -1
- package/pack/.claude/skills/devrites-lib/reference/intent-map.md +2 -0
- package/pack/.claude/skills/overhaul/SKILL.md +2 -1
- package/pack/.claude/skills/overhaul/references/audit-domains.md +139 -12
- package/pack/.claude/skills/overhaul/references/lifecycle.md +2 -0
- package/pack/.claude/skills/overhaul/references/orchestration.md +13 -5
- package/pack/.claude/skills/overhaul/references/records.md +12 -3
- package/pack/.claude/skills/overhaul/references/repair-and-measurement.md +108 -5
- package/pack/.claude/skills/overhaul/references/scope-and-safety.md +17 -2
- package/pack/.claude/skills/overhaul/references/scoring.md +36 -7
- package/pack/.claude/skills/overhaul/references/stack-profiles.md +52 -0
- package/pack/.claude/skills/rite/SKILL.md +4 -1
- package/pack/.claude/skills/rite-doctor/SKILL.md +2 -0
- package/pack/.claude/skills/rite-fast/SKILL.md +183 -0
- package/pack/.claude/skills/rite-fast/reference/artifacts.md +107 -0
- package/pack/.claude/skills/rite-fast/reference/check-and-triage.md +51 -0
- package/pack/.claude/skills/rite-quick/SKILL.md +2 -0
- package/pack/generated/claude/agents/fast-builder.md +90 -0
- package/pack/generated/claude/agents/fast-checker.md +60 -0
- package/pack/generated/claude/agents/fast-critic.md +70 -0
- package/pack/generated/claude/agents/fast-planner.md +95 -0
- package/pack/generated/claude/agents/overhaul-backend-engineer.md +5 -4
- package/pack/generated/claude/agents/overhaul-boundary.md +2 -2
- package/pack/generated/claude/agents/overhaul-craft.md +1 -1
- package/pack/generated/claude/agents/overhaul-frontend-engineer.md +5 -3
- package/pack/generated/claude/agents/overhaul-implementer.md +9 -5
- package/pack/generated/claude/agents/overhaul-specialist.md +6 -3
- package/pack/generated/claude/agents/overhaul-verifier.md +3 -3
- package/pack/generated/claude/settings.json +1 -1
- package/pack/generated/claude/skills/devrites-lib/reference/intent-map.md +2 -0
- package/pack/generated/claude/skills/overhaul/SKILL.md +2 -1
- package/pack/generated/claude/skills/overhaul/references/audit-domains.md +139 -12
- package/pack/generated/claude/skills/overhaul/references/lifecycle.md +2 -0
- package/pack/generated/claude/skills/overhaul/references/orchestration.md +13 -5
- package/pack/generated/claude/skills/overhaul/references/records.md +12 -3
- package/pack/generated/claude/skills/overhaul/references/repair-and-measurement.md +108 -5
- package/pack/generated/claude/skills/overhaul/references/scope-and-safety.md +17 -2
- package/pack/generated/claude/skills/overhaul/references/scoring.md +36 -7
- package/pack/generated/claude/skills/overhaul/references/stack-profiles.md +52 -0
- package/pack/generated/claude/skills/rite/SKILL.md +4 -1
- package/pack/generated/claude/skills/rite-doctor/SKILL.md +2 -0
- package/pack/generated/claude/skills/rite-fast/SKILL.md +183 -0
- package/pack/generated/claude/skills/rite-fast/reference/artifacts.md +107 -0
- package/pack/generated/claude/skills/rite-fast/reference/check-and-triage.md +51 -0
- package/pack/generated/claude/skills/rite-quick/SKILL.md +2 -0
- package/pack/generated/codex/AGENTS.md +1 -0
- package/pack/generated/codex/agents/fast-builder.toml +90 -0
- package/pack/generated/codex/agents/fast-checker.toml +60 -0
- package/pack/generated/codex/agents/fast-critic.toml +70 -0
- package/pack/generated/codex/agents/fast-planner.toml +95 -0
- package/pack/generated/codex/agents/overhaul-backend-engineer.toml +5 -4
- package/pack/generated/codex/agents/overhaul-boundary.toml +2 -2
- package/pack/generated/codex/agents/overhaul-craft.toml +1 -1
- package/pack/generated/codex/agents/overhaul-frontend-engineer.toml +5 -3
- package/pack/generated/codex/agents/overhaul-implementer.toml +9 -5
- package/pack/generated/codex/agents/overhaul-specialist.toml +6 -3
- package/pack/generated/codex/agents/overhaul-verifier.toml +3 -3
- package/pack/generated/codex/skills/devrites-lib/reference/intent-map.md +2 -0
- package/pack/generated/codex/skills/overhaul/SKILL.md +2 -1
- package/pack/generated/codex/skills/overhaul/references/audit-domains.md +139 -12
- package/pack/generated/codex/skills/overhaul/references/lifecycle.md +2 -0
- package/pack/generated/codex/skills/overhaul/references/orchestration.md +13 -5
- package/pack/generated/codex/skills/overhaul/references/records.md +12 -3
- package/pack/generated/codex/skills/overhaul/references/repair-and-measurement.md +108 -5
- package/pack/generated/codex/skills/overhaul/references/scope-and-safety.md +17 -2
- package/pack/generated/codex/skills/overhaul/references/scoring.md +36 -7
- package/pack/generated/codex/skills/overhaul/references/stack-profiles.md +52 -0
- package/pack/generated/codex/skills/rite/SKILL.md +4 -1
- package/pack/generated/codex/skills/rite-doctor/SKILL.md +2 -0
- package/pack/generated/codex/skills/rite-fast/SKILL.md +183 -0
- package/pack/generated/codex/skills/rite-fast/agents/openai.yaml +2 -0
- package/pack/generated/codex/skills/rite-fast/reference/artifacts.md +107 -0
- package/pack/generated/codex/skills/rite-fast/reference/check-and-triage.md +51 -0
- package/pack/generated/codex/skills/rite-quick/SKILL.md +2 -0
- package/pack/generated/devin/AGENTS.md +1 -0
- package/pack/generated/devin/agents/fast-builder.md +96 -0
- package/pack/generated/devin/agents/fast-checker.md +63 -0
- package/pack/generated/devin/agents/fast-critic.md +73 -0
- package/pack/generated/devin/agents/fast-planner.md +98 -0
- package/pack/generated/devin/agents/overhaul-backend-engineer.md +5 -4
- package/pack/generated/devin/agents/overhaul-boundary.md +2 -2
- package/pack/generated/devin/agents/overhaul-craft.md +1 -1
- package/pack/generated/devin/agents/overhaul-frontend-engineer.md +5 -3
- package/pack/generated/devin/agents/overhaul-implementer.md +9 -5
- package/pack/generated/devin/agents/overhaul-specialist.md +6 -3
- package/pack/generated/devin/agents/overhaul-verifier.md +3 -3
- package/pack/generated/devin/skills/devrites-lib/reference/intent-map.md +2 -0
- package/pack/generated/devin/skills/overhaul/SKILL.md +2 -1
- package/pack/generated/devin/skills/overhaul/references/audit-domains.md +139 -12
- package/pack/generated/devin/skills/overhaul/references/lifecycle.md +2 -0
- package/pack/generated/devin/skills/overhaul/references/orchestration.md +13 -5
- package/pack/generated/devin/skills/overhaul/references/records.md +12 -3
- package/pack/generated/devin/skills/overhaul/references/repair-and-measurement.md +108 -5
- package/pack/generated/devin/skills/overhaul/references/scope-and-safety.md +17 -2
- package/pack/generated/devin/skills/overhaul/references/scoring.md +36 -7
- package/pack/generated/devin/skills/overhaul/references/stack-profiles.md +52 -0
- package/pack/generated/devin/skills/rite/SKILL.md +4 -1
- package/pack/generated/devin/skills/rite-doctor/SKILL.md +2 -0
- package/pack/generated/devin/skills/rite-fast/SKILL.md +183 -0
- package/pack/generated/devin/skills/rite-fast/reference/artifacts.md +107 -0
- package/pack/generated/devin/skills/rite-fast/reference/check-and-triage.md +51 -0
- package/pack/generated/devin/skills/rite-quick/SKILL.md +2 -0
- package/pack/generated/omp/agents/fast-builder.md +89 -0
- package/pack/generated/omp/agents/fast-checker.md +59 -0
- package/pack/generated/omp/agents/fast-critic.md +69 -0
- package/pack/generated/omp/agents/fast-planner.md +94 -0
- package/pack/generated/omp/agents/overhaul-backend-engineer.md +5 -4
- package/pack/generated/omp/agents/overhaul-boundary.md +2 -2
- package/pack/generated/omp/agents/overhaul-craft.md +1 -1
- package/pack/generated/omp/agents/overhaul-frontend-engineer.md +5 -3
- package/pack/generated/omp/agents/overhaul-implementer.md +9 -5
- package/pack/generated/omp/agents/overhaul-specialist.md +6 -3
- package/pack/generated/omp/agents/overhaul-verifier.md +3 -3
- package/pack/generated/omp/commands/rite-fast.md +5 -0
- package/pack/generated/omp/skills/devrites-lib/reference/intent-map.md +2 -0
- package/pack/generated/omp/skills/overhaul/SKILL.md +2 -1
- package/pack/generated/omp/skills/overhaul/references/audit-domains.md +139 -12
- package/pack/generated/omp/skills/overhaul/references/lifecycle.md +2 -0
- package/pack/generated/omp/skills/overhaul/references/orchestration.md +13 -5
- package/pack/generated/omp/skills/overhaul/references/records.md +12 -3
- package/pack/generated/omp/skills/overhaul/references/repair-and-measurement.md +108 -5
- package/pack/generated/omp/skills/overhaul/references/scope-and-safety.md +17 -2
- package/pack/generated/omp/skills/overhaul/references/scoring.md +36 -7
- package/pack/generated/omp/skills/overhaul/references/stack-profiles.md +52 -0
- package/pack/generated/omp/skills/rite/SKILL.md +4 -1
- package/pack/generated/omp/skills/rite-doctor/SKILL.md +2 -0
- package/pack/generated/omp/skills/rite-fast/SKILL.md +183 -0
- package/pack/generated/omp/skills/rite-fast/reference/artifacts.md +107 -0
- package/pack/generated/omp/skills/rite-fast/reference/check-and-triage.md +51 -0
- package/pack/generated/omp/skills/rite-quick/SKILL.md +2 -0
- package/pack/generated/pi/AGENTS.md +1 -0
- package/pack/generated/pi/agents/fast-builder.md +90 -0
- package/pack/generated/pi/agents/fast-checker.md +60 -0
- package/pack/generated/pi/agents/fast-critic.md +70 -0
- package/pack/generated/pi/agents/fast-planner.md +95 -0
- package/pack/generated/pi/agents/overhaul-backend-engineer.md +5 -4
- package/pack/generated/pi/agents/overhaul-boundary.md +2 -2
- package/pack/generated/pi/agents/overhaul-craft.md +1 -1
- package/pack/generated/pi/agents/overhaul-frontend-engineer.md +5 -3
- package/pack/generated/pi/agents/overhaul-implementer.md +9 -5
- package/pack/generated/pi/agents/overhaul-specialist.md +6 -3
- package/pack/generated/pi/agents/overhaul-verifier.md +3 -3
- package/pack/generated/pi/prompts/rite-fast.md +5 -0
- package/pack/generated/pi/skills/devrites-lib/reference/intent-map.md +2 -0
- package/pack/generated/pi/skills/overhaul/SKILL.md +2 -1
- package/pack/generated/pi/skills/overhaul/references/audit-domains.md +139 -12
- package/pack/generated/pi/skills/overhaul/references/lifecycle.md +2 -0
- package/pack/generated/pi/skills/overhaul/references/orchestration.md +13 -5
- package/pack/generated/pi/skills/overhaul/references/records.md +12 -3
- package/pack/generated/pi/skills/overhaul/references/repair-and-measurement.md +108 -5
- package/pack/generated/pi/skills/overhaul/references/scope-and-safety.md +17 -2
- package/pack/generated/pi/skills/overhaul/references/scoring.md +36 -7
- package/pack/generated/pi/skills/overhaul/references/stack-profiles.md +52 -0
- package/pack/generated/pi/skills/rite/SKILL.md +4 -1
- package/pack/generated/pi/skills/rite-doctor/SKILL.md +2 -0
- package/pack/generated/pi/skills/rite-fast/SKILL.md +183 -0
- package/pack/generated/pi/skills/rite-fast/reference/artifacts.md +107 -0
- package/pack/generated/pi/skills/rite-fast/reference/check-and-triage.md +51 -0
- package/pack/generated/pi/skills/rite-quick/SKILL.md +2 -0
- package/package.json +1 -1
- package/scripts/codex-generate.sh +2 -1
- package/scripts/devin-generate.sh +4 -3
- package/scripts/omp-generate.sh +3 -3
- package/scripts/pi-generate.sh +4 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
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.14.1](https://github.com/ViktorsBaikers/DevRites/compare/v5.14.0...v5.14.1) (2026-09-29)
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
* **no-release:** add /rite-fast lane for mid-size work ([#89](https://github.com/ViktorsBaikers/DevRites/issues/89)) ([7b71593](https://github.com/ViktorsBaikers/DevRites/commit/7b7159377a88002d33b19277f3b365cd9be89520))
|
|
10
|
+
* **no-release:** close /overhaul audit and repair coverage gaps ([f7c4e6a](https://github.com/ViktorsBaikers/DevRites/commit/f7c4e6a0e27b83e7fa65befdee44df2efebbccca))
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
* **repo:** close engine, script, and doc quality gaps ([#90](https://github.com/ViktorsBaikers/DevRites/issues/90)) ([61572e2](https://github.com/ViktorsBaikers/DevRites/commit/61572e2bccae418aa47c7852807d2551f7f0bda1))
|
|
15
|
+
|
|
5
16
|
## [5.14.0](https://github.com/ViktorsBaikers/DevRites/compare/v5.13.1...v5.14.0) (2026-09-25)
|
|
6
17
|
|
|
7
18
|
### 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:** [`v5.14.
|
|
34
|
+
**Status:** [`v5.14.1`](https://github.com/ViktorsBaikers/DevRites/releases/tag/v5.14.1): 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
|
|
|
@@ -147,6 +147,7 @@ equivalent.
|
|
|
147
147
|
| --- | --- |
|
|
148
148
|
| [`/rite`](pack/.claude/skills/rite/SKILL.md) | Show the command menu, or route a verb. |
|
|
149
149
|
| [`/rite-quick`](pack/.claude/skills/rite-quick/SKILL.md) | Ship a small, reversible change with a compact contract, focused proof, and scope review. Escalates to `/rite-spec` when the work stops being small. |
|
|
150
|
+
| [`/rite-fast`](pack/.claude/skills/rite-fast/SKILL.md) | Take mid-size work through one spec-and-plan step with your answers, up to ten slices, one completeness check, review, polish, and proof. No gate after each slice; explicit invocation only. |
|
|
150
151
|
| [`/rite-autocomplete`](pack/.claude/skills/rite-autocomplete/SKILL.md) | Run the reversible lifecycle unattended and stop at Seal `GO`. With `--ship`, continue through Ship preflight and wait for your literal `GO`. |
|
|
151
152
|
| [`/rite-adopt`](pack/.claude/skills/rite-adopt/SKILL.md) | Reverse-engineer current behavior of an existing codebase into a baseline workspace. |
|
|
152
153
|
| [`/rite-upgrade [slug]`](pack/.claude/skills/rite-upgrade/SKILL.md) | Reconcile an older active workspace with current contracts. Routes only evidence-backed defects to their phase owners. |
|
|
@@ -423,8 +424,8 @@ through Claude Code or Codex plugin stores.
|
|
|
423
424
|
|
|
424
425
|
## Skills and agents
|
|
425
426
|
|
|
426
|
-
The pack ships
|
|
427
|
-
contains the `rite` menu,
|
|
427
|
+
The pack ships 46 skills: 35 public and 11 internal. The public surface
|
|
428
|
+
contains the `rite` menu, 33 `rite-*` workflows and utilities, and the
|
|
428
429
|
standalone, explicit-only `/overhaul`. Ten `devrites-*` specialists load when a
|
|
429
430
|
matching task needs them; `devrites-lib` carries the shared contracts and
|
|
430
431
|
engineering standards.
|
|
@@ -434,6 +435,8 @@ roles plus `devrites-slice-wright`, the sole source and test writer. Codex,
|
|
|
434
435
|
omp, pi, and Devin generate the same one-writer, sixteen-reader split.
|
|
435
436
|
`/overhaul` adds eight `overhaul-*` agents that only it dispatches; they keep
|
|
436
437
|
every tool ([ADR-0031](docs/adr/0031-overhaul-agents-keep-every-tool.md)).
|
|
438
|
+
`/rite-fast` adds four `fast-*` agents that only it dispatches: three read-only
|
|
439
|
+
roles and `fast-builder`, its own writer ([ADR-0033](docs/adr/0033-rite-fast-own-agents.md)).
|
|
437
440
|
|
|
438
441
|
The [skills catalogue](docs/skills.md) lists every skill and agent. The
|
|
439
442
|
[flow diagrams](docs/flow.md) show routing, reviewer fan-out, and namespace
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# ADR-0033: `/rite-fast` ships its own agents and its own writer
|
|
2
|
+
|
|
3
|
+
- **Status:** Accepted
|
|
4
|
+
- **Date:** 2026-09-26
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
|
|
8
|
+
Mid-size work had two routes. `/rite-quick` covers one small reversible change. The
|
|
9
|
+
full lifecycle adds strategy review, a vetted plan, and review plus proof after every
|
|
10
|
+
slice. Users asked for a lane in between: one spec-and-plan step with clarifying
|
|
11
|
+
questions, up to ten slices built with no gate between them, one completeness check
|
|
12
|
+
with gap fixes, then review, polish, and proof.
|
|
13
|
+
|
|
14
|
+
The lifecycle agents are shaped for per-slice gates and engine workspace artifacts
|
|
15
|
+
(`state.md`, `tasks.md`, `touched-files.md`, readiness bindings). `devrites-slice-wright`
|
|
16
|
+
runs writer-safe proof on every slice, which is the step the fast lane removes.
|
|
17
|
+
ADR-0010, ADR-0015, ADR-0017, ADR-0018 and ADR-0019 keep one writer among `devrites-*`
|
|
18
|
+
specialists; ADR-0031 already scoped that rule for `/overhaul`.
|
|
19
|
+
|
|
20
|
+
## Decision
|
|
21
|
+
|
|
22
|
+
- `/rite-fast` is an explicit-only skill (`disable-model-invocation: true`). It stands
|
|
23
|
+
outside the engine lifecycle: its record is `spec.md`, `plan.md`, and `evidence.md`
|
|
24
|
+
under `.devrites/work/<slug>/`, with no `state.md`, no `.devrites/ACTIVE`, and no
|
|
25
|
+
seal. No engine change is needed.
|
|
26
|
+
- The pack ships four agents that only `/rite-fast` dispatches: `fast-planner`,
|
|
27
|
+
`fast-checker`, and `fast-critic` (read-only, `permissionMode: plan`), and
|
|
28
|
+
`fast-builder` (write-capable in the exact paths of its contract,
|
|
29
|
+
`permissionMode: acceptEdits`). `fast-builder` runs no test suite; the skill runs one
|
|
30
|
+
check after all slices and proof last.
|
|
31
|
+
- `validate-agent-composition.py` accepts `fast-builder` as write-capable when it states
|
|
32
|
+
that mode. Codex gives it `default_permissions = ":workspace"`; omp, pi, and Devin give
|
|
33
|
+
it the write tool set. The other `fast-*` agents stay read-only on every host.
|
|
34
|
+
|
|
35
|
+
## Consequences
|
|
36
|
+
|
|
37
|
+
- The one-writer clauses of the lifecycle ADRs govern `devrites-*` specialists only;
|
|
38
|
+
`/overhaul` (ADR-0031) and `/rite-fast` each own one more writer.
|
|
39
|
+
- A `/rite-fast` run is not visible to `/rite-status`, `orient`, `next`, or `handoff`.
|
|
40
|
+
It resumes from its own `plan.md` ledger.
|
|
41
|
+
- Four more agents are installed, updated, and removed with the pack. `/rite-fast`
|
|
42
|
+
stops when they are missing and no fresh context is available.
|
|
43
|
+
|
|
44
|
+
Verified by `scripts/validate-agent-composition.py`, `tests/rite-fast-contract-test.sh`,
|
|
45
|
+
and the host generators' `fast-builder` branches.
|
package/docs/adr/README.md
CHANGED
|
@@ -47,7 +47,7 @@ architecture; per-feature `decisions.md` files stay scoped to that feature.
|
|
|
47
47
|
| ADR | Title | Status | Guard test |
|
|
48
48
|
|-----|-------|--------|-----------|
|
|
49
49
|
| [0001](0001-go-engine-as-control-plane.md) | Go engine as deterministic control plane | Accepted in part; all-state-transition/derivation scope superseded by 0024 | none |
|
|
50
|
-
| [0002](0002-dual-host-harness.md) | Dual-host harness (Claude + Codex) | Accepted | `tests/parity_*_test.go` |
|
|
50
|
+
| [0002](0002-dual-host-harness.md) | Dual-host harness (Claude + Codex) | Accepted | `engine/tests/parity_*_test.go` |
|
|
51
51
|
| [0003](0003-gate-model-hitl-pause.md) | Gates block as HITL pause, never crash | Accepted | `engine/tests/adr_0003_gate_exit_code_test.go` |
|
|
52
52
|
| [0004](0004-state-schema-phases-sections.md) | Phase-relative section completeness | Accepted | `engine/tests/adr_0004_required_by_phase_test.go`, `engine/internal/state/state_test.go` |
|
|
53
53
|
| [0005](0005-hooks-as-engine-subcommands.md) | Hooks are engine subcommands, not shell scripts | Accepted; active hook clause superseded by 0018 | historical |
|
|
@@ -77,3 +77,4 @@ architecture; per-feature `decisions.md` files stay scoped to that feature.
|
|
|
77
77
|
| [0029](0029-v5-workspace-schema-and-native-migration.md) | v5 workspace schema and native migration | Accepted | `engine/internal/state/workspaceschema_test.go`, `engine/tests/parity_resolve_test.go`, `engine/tests/parity_closeout_test.go` |
|
|
78
78
|
| [0031](0031-overhaul-agents-keep-every-tool.md) | `/overhaul` ships its own agents that keep every tool | Accepted; scopes the one-writer clauses of 0010/0015/0017/0018/0019 to `devrites-*` specialists | `scripts/validate-agent-composition.py`, `tests/codex-agent-generation-test.sh` |
|
|
79
79
|
| [0032](0032-single-lint-gate-and-cached-pr-tests.md) | One engine lint gate, and PR tests that reuse main's results | Accepted | `tests/validation-governance-test.sh` |
|
|
80
|
+
| [0033](0033-rite-fast-own-agents.md) | `/rite-fast` ships its own agents and its own writer | Accepted; adds `fast-builder` as a writer outside the `devrites-*` one-writer rule | `scripts/validate-agent-composition.py`, `tests/rite-fast-contract-test.sh` |
|
package/docs/architecture.md
CHANGED
|
@@ -30,7 +30,7 @@ cursor readers, traceability rules, and phase-relative completeness model, see
|
|
|
30
30
|
irreversible git ladder and **closes** the task by archiving the workspace
|
|
31
31
|
and clearing `ACTIVE`. Separate steps let users audit the release decision
|
|
32
32
|
before any irreversible action.
|
|
33
|
-
2. **Public utility and on-ramp skills**: `rite-adopt`, `rite-quick`,
|
|
33
|
+
2. **Public utility and on-ramp skills**: `rite-adopt`, `rite-quick`, `rite-fast`,
|
|
34
34
|
`rite-frame`, `rite-status`, `rite-doctor`, `rite-upgrade`, `rite-learn`, `rite-explain`,
|
|
35
35
|
`rite-customize`, `rite-zoom-out`, `rite-prototype`, `rite-handoff`,
|
|
36
36
|
`rite-pressure-test`, `rite-pov`, `rite-dogfood`, `rite-pr-feedback`,
|
|
@@ -389,8 +389,8 @@ contract.
|
|
|
389
389
|
|
|
390
390
|
## Design choices at a glance
|
|
391
391
|
|
|
392
|
-
- **Surface**:
|
|
393
|
-
menu and the standalone `overhaul` skill:
|
|
392
|
+
- **Surface**: 33 public `rite-*` skills (46 total), plus the thin `/rite`
|
|
393
|
+
menu and the standalone `overhaul` skill: 35 public and 11 internal. The lifecycle
|
|
394
394
|
includes mandatory adaptive Clarify, optional Temper, mandatory Vet, and
|
|
395
395
|
Converge recovery; Seal **decides** and Ship **executes + closes**. Ten
|
|
396
396
|
`devrites-*` specialist skills are model-invoked; `devrites-lib` is the
|
|
@@ -413,7 +413,9 @@ contract.
|
|
|
413
413
|
- **Agents**: 17 fresh-context roles at flat depth one: 16 read-only leaves and
|
|
414
414
|
one wright. Dispatch uses the exact named project role; if it cannot spawn,
|
|
415
415
|
the workflow stops for HITL. `/overhaul` adds eight `overhaul-*` agents
|
|
416
|
-
that only it dispatches and that keep every tool (ADR-0031).
|
|
416
|
+
that only it dispatches and that keep every tool (ADR-0031). `/rite-fast`
|
|
417
|
+
adds four `fast-*` agents: three read-only roles and `fast-builder`, its own
|
|
418
|
+
writer (ADR-0033).
|
|
417
419
|
- **Review**: **feature-scoped** multi-axis review with severity labels and
|
|
418
420
|
fresh-context agents at the seal.
|
|
419
421
|
- **Scope**: clarify → seal (decide) → ship (read-only preflight → type-GO →
|
package/docs/command-map.md
CHANGED
|
@@ -16,7 +16,7 @@ installer; DevRites is not distributed as a Claude or Codex plugin.
|
|
|
16
16
|
The `devrites-` prefix avoids collisions with bundled Claude Code skill names
|
|
17
17
|
such as `prototype`, `handoff`, `triage`, and `diagnose`. The prefix does not
|
|
18
18
|
mean that a skill is internal; each `SKILL.md` uses `user-invocable:` to set
|
|
19
|
-
visibility. Public utilities use the `rite-*` prefix: `rite-quick`,
|
|
19
|
+
visibility. Public utilities use the `rite-*` prefix: `rite-quick`, `rite-fast`,
|
|
20
20
|
`rite-frame`, `rite-adopt`, `rite-learn`, `rite-doctor`, `rite-customize`,
|
|
21
21
|
`rite-zoom-out`, `rite-prototype`, `rite-handoff`, `rite-pressure-test`,
|
|
22
22
|
`rite-autocomplete`, `rite-explain`, `rite-pov`, `rite-dogfood`,
|
|
@@ -106,6 +106,7 @@ See [`cli.md`](cli.md).
|
|
|
106
106
|
| [`/rite-ship`](../pack/.claude/skills/rite-ship/SKILL.md) | ship | `[slug]` | Starts with a read-only Seal/candidate check and exact plan disclosure, then requires fresh literal `GO`. Only then may it collapse checkpoints, stage exact candidate paths, validate staged scope/bytes/bindings/secrets, commit and reverify, perform optional separately approved push/tag/PR actions, and archive/close. | `seal.md` + candidate + Git index | `ship.md`, `state.md`, archive |
|
|
107
107
|
| [`/rite-autocomplete`](../pack/.claude/skills/rite-autocomplete/SKILL.md) | (orchestrator) | `[idea] [--ship\|--yolo] [--max-slices N] [--full] [--cross-model]` | Full lifecycle (spec → clarify → … → seal → ship). Spec + clarify form the one interactive window; AFK/checkpoint mode arms only after decision coverage is CLEAR. Pauses for irreversible risk, escalating, unanswered blocking with no recommended option, human-only access, or remaining NO-GO — not recommended-option blocking questions, temper expand, validating gates, `--max-slices`, or default resource caps. Objective red checks use bounded technical recovery. Default stops at Seal GO; `--ship` (`--yolo`) reaches Ship preflight but still requires fresh literal `GO` and native approval; `--full` selects the Full profile and `--cross-model` arms Vet's second opinion. | idea + workspace | whole workspace (drives every phase) |
|
|
108
108
|
| [`/rite-quick`](../pack/.claude/skills/rite-quick/SKILL.md) | (express) | `<change>` | Express lane for a **small, reversible, unambiguous** change: one-line contract → TDD build → scoped prove → review-lite → ship, no full artifact tree. **Significance gate first**: auth / migration / public-API / destructive / multi-slice / ambiguous → escalates to `/rite-spec`. Triggers: "quick fix", "small change", "tiny tweak", "just do X". | the change + codebase | code + commit (optional `brief.md` / `evidence.md`) |
|
|
109
|
+
| [`/rite-fast`](../pack/.claude/skills/rite-fast/SKILL.md) | (fast lane) | `<task \| slug>` | **Explicit-only** shortened lane for mid-size work: one SHAPE step (`fast-planner` drafts spec + ≤10 slices, root asks ≤5 ranked questions, 10 when risk is flagged, user approves) → BUILD with `fast-builder` and **no per-slice gate** → one CHECK (`fast-checker` completeness pass, ≤2 gap-fix rounds) → REFINE (`fast-critic` review + polish) → PROVE on the final tree. Outside the engine lifecycle: no `state.md`, no `ACTIVE`, no seal; commits only on confirmation. | the task + codebase | `spec.md`, `plan.md`, `evidence.md` under `.devrites/work/<slug>/` + code |
|
|
109
110
|
| [`/rite-frame`](../pack/.claude/skills/rite-frame/SKILL.md) | lens | `[ask \| diff]` | Pre-flight + self-audit lens for ad-hoc work the lifecycle gates never see: **FRAME** turns an imperative ask into a falsifiable success criterion + verify command before code; **AUDIT** checks a raw diff against the four LLM coding failure modes (silent assumption / overcomplication / out-of-scope edit / unverifiable goal). Top of `/rite-quick` or before a plain "just do X". | the ask / a raw diff | success criterion + verify command (inline) |
|
|
110
111
|
| [`/rite-adopt`](../pack/.claude/skills/rite-adopt/SKILL.md) | onboard | `[path or area to adopt] [+ what you want to build next]` | Reverse-derive the existing baseline and next objective; propose any durable project guidance in the nearest native instruction file. | codebase + project instructions | workspace spec/state artifacts + optional guidance proposal |
|
|
111
112
|
| [`/rite-status`](../pack/.claude/skills/rite-status/SKILL.md) | status | `[slug]` | Active feature: phase, run mode, status, persisted next action, evidence, questions, drift, risks, and handoff readiness. | direct workspace ledger/artifacts | none |
|
package/docs/flow.md
CHANGED
|
@@ -381,7 +381,7 @@ separately by `disable-model-invocation`.
|
|
|
381
381
|
|
|
382
382
|
```mermaid
|
|
383
383
|
flowchart TB
|
|
384
|
-
subgraph Public["Public (user-invocable: true):
|
|
384
|
+
subgraph Public["Public (user-invocable: true): 35 skills"]
|
|
385
385
|
direction TB
|
|
386
386
|
R1[/rite/]
|
|
387
387
|
R2[/rite-spec/]
|
|
@@ -401,6 +401,7 @@ flowchart TB
|
|
|
401
401
|
R10[/rite-status/]
|
|
402
402
|
R11[/rite-resolve/]
|
|
403
403
|
RQ[/rite-quick/]
|
|
404
|
+
RFA[/rite-fast/]
|
|
404
405
|
RF[/rite-frame/]
|
|
405
406
|
RA[/rite-adopt/]
|
|
406
407
|
RL[/rite-learn/]
|
|
@@ -435,7 +436,7 @@ flowchart TB
|
|
|
435
436
|
|
|
436
437
|
classDef pub fill:#064e3b,stroke:#34d399,color:#ecfdf5
|
|
437
438
|
classDef int fill:#1f2937,stroke:#9ca3af,color:#f9fafb
|
|
438
|
-
class R1,R2,RCL,RT,R3,RV,R4,R5,RC,R6,R7,R8,R9,R12,R13,R10,R11,RQ,RF,RA,RL,RD,RU,RE,RCU,RDO,RPOV,RPF,IPT,D1,D2,D3 pub
|
|
439
|
+
class R1,R2,RCL,RT,R3,RV,R4,R5,RC,R6,R7,R8,R9,R12,R13,R10,R11,RQ,RFA,RF,RA,RL,RD,RU,RE,RCU,RDO,RPOV,RPF,IPT,D1,D2,D3 pub
|
|
439
440
|
class I1,I2,I3,I4,I5,I6,I7,I8,I9,I10,I11 int
|
|
440
441
|
```
|
|
441
442
|
|
package/docs/orchestration.md
CHANGED
|
@@ -52,6 +52,9 @@ slice-wright uses `default_permissions = ":workspace"` and the other 16
|
|
|
52
52
|
specialists use `default_permissions = ":read-only"`. The eight `overhaul-*` agents of the
|
|
53
53
|
explicit `/overhaul` skill sit outside this split: Claude gives them every tool and
|
|
54
54
|
Codex gives them `:workspace` ([ADR-0031](adr/0031-overhaul-agents-keep-every-tool.md)).
|
|
55
|
+
The four `fast-*` agents of `/rite-fast` also sit outside it: `fast-builder` uses
|
|
56
|
+
`acceptEdits` on Claude and `:workspace` on Codex, and the other three are
|
|
57
|
+
read-only ([ADR-0033](adr/0033-rite-fast-own-agents.md)).
|
|
55
58
|
|
|
56
59
|
If the exact role is unavailable, the root stops instead of substituting a
|
|
57
60
|
generic agent or doing specialist/writer work inline.
|
package/docs/quick-reference.md
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
Executive fast path: **Spec → Build → Prove**. `/rite-spec` writes the
|
|
4
4
|
contract, `/rite-build` implements one slice, `/rite-prove` binds evidence.
|
|
5
5
|
Adaptive Clarify/Vet still run; they ask nothing when the contract is already
|
|
6
|
-
complete. Use `/rite-quick` for a small reversible change
|
|
6
|
+
complete. Use `/rite-quick` for a small reversible change and `/rite-fast` for
|
|
7
|
+
mid-size work that does not need a gate after every slice.
|
|
7
8
|
|
|
8
9
|
Install DevRites with `npx devrites ...`. Normal installs from package and
|
|
9
10
|
release candidates consume pre-generated project-local Claude Code and Codex
|
package/docs/skills.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# All
|
|
1
|
+
# All 46 skills
|
|
2
2
|
|
|
3
|
-
The pack contains
|
|
3
|
+
The pack contains 46 skills: the `rite` menu, 33 user-invocable `rite-*`
|
|
4
4
|
workflow and utility skills, the standalone `overhaul` skill,
|
|
5
5
|
10 model-invoked `devrites-*` specialists, and the internal `devrites-lib` library. `devrites-lib` is not a command. It holds shared
|
|
6
6
|
references and the few explicit script exceptions.
|
|
@@ -19,8 +19,9 @@ guidance block in `AGENTS.md`.
|
|
|
19
19
|
The root and reviewers never write source. Claude enforces the root boundary in
|
|
20
20
|
plan mode. Codex uses a workspace-capable root so its sole write-capable
|
|
21
21
|
slice-wright can execute, while all other specialists remain read-only. On
|
|
22
|
-
Devin, `allowed-tools` gives
|
|
23
|
-
`
|
|
22
|
+
Devin, `allowed-tools` gives `edit`, `write`, and `exec` only to
|
|
23
|
+
`devrites-slice-wright` among lifecycle roles (plus `fast-builder` for
|
|
24
|
+
`/rite-fast`); a missing required profile stops for HITL instead of substituting a
|
|
24
25
|
generic profile. The
|
|
25
26
|
installed `devrites-engine` owns strict candidate identity, deterministic checks,
|
|
26
27
|
exact proof/review/seal bindings,
|
|
@@ -42,7 +43,7 @@ contract when a rite names parallel reviewers.
|
|
|
42
43
|
## Naming convention
|
|
43
44
|
|
|
44
45
|
`rite-*` is the namespace for lifecycle and utility commands. Its utilities are
|
|
45
|
-
`rite-quick`, `rite-frame`, `rite-adopt`, `rite-learn`, `rite-customize`,
|
|
46
|
+
`rite-quick`, `rite-fast`, `rite-frame`, `rite-adopt`, `rite-learn`, `rite-customize`,
|
|
46
47
|
`rite-explain`, `rite-pov`, `rite-dogfood`, `rite-pr-feedback`, `rite-watch-pr`, `rite-doctor`,
|
|
47
48
|
`rite-upgrade`, `rite-prototype`, `rite-handoff`, `rite-zoom-out`, and
|
|
48
49
|
`rite-pressure-test`.
|
|
@@ -145,6 +146,7 @@ and `Shipped`. Utility commands keep the same compact labels and one-next-action
|
|
|
145
146
|
| Skill | What It Does | Use When |
|
|
146
147
|
|---|---|---|
|
|
147
148
|
| [`rite-quick`](../pack/.claude/skills/rite-quick/SKILL.md) | Express lane for a **small, reversible, unambiguous** change: one-line contract → TDD build → scoped prove → review-lite → ship, collapsing the full lifecycle into one pass. Significance gate first: auth / migration / public-API / destructive / multi-slice / ambiguous **escalates to `/rite-spec`**. | "quick fix", "small change", "tiny tweak", "just do X" on a low-risk change. |
|
|
149
|
+
| [`rite-fast`](../pack/.claude/skills/rite-fast/SKILL.md) | Shortened lane: one spec-and-plan step with ranked clarifying questions (more when risk is flagged), up to ten vertical slices built by `fast-builder` without per-slice gates, one `fast-checker` completeness pass with gap fixes, one `fast-critic` review and polish pass, then proof on the final tree. Own `fast-*` agents; outside the engine lifecycle. | Explicit-only: `/rite-fast <task>` for mid-size work that does not need a gate after every slice. |
|
|
148
150
|
| [`rite-frame`](../pack/.claude/skills/rite-frame/SKILL.md) | Pre-flight + self-audit lens for ad-hoc work the lifecycle gates never see: FRAME converts an imperative ask into a falsifiable success criterion + verify command before code; AUDIT checks a raw diff against the four LLM coding failure modes (silent assumption / overcomplication / out-of-scope edit / unverifiable goal). | Top of `/rite-quick`, before a plain "just do X" edit, or to self-review a raw diff. |
|
|
149
151
|
| [`rite-adopt`](../pack/.claude/skills/rite-adopt/SKILL.md) | Bring an EXISTING codebase under DevRites: reverse-derive a baseline `spec.md` of current behavior, placement, and architecture; optionally propose one reviewed scoped-instruction update; then hand off to the lifecycle. | "adopt this project", "onboard this codebase", "we already have code", "reverse-engineer a spec from the existing app". |
|
|
150
152
|
|
|
@@ -261,8 +263,10 @@ and `Shipped`. Utility commands keep the same compact labels and one-next-action
|
|
|
261
263
|
DevRites ships 17 role profiles at depth one. Both hosts have 16 read-only
|
|
262
264
|
leaves and one source/test writer role. The explicit `/overhaul` skill ships eight
|
|
263
265
|
more agents, `overhaul-*`, that only it dispatches and that keep every tool
|
|
264
|
-
([ADR-0031](adr/0031-overhaul-agents-keep-every-tool.md))
|
|
265
|
-
|
|
266
|
+
([ADR-0031](adr/0031-overhaul-agents-keep-every-tool.md)). `/rite-fast` adds four
|
|
267
|
+
`fast-*` agents that only it dispatches: three read-only roles and `fast-builder`,
|
|
268
|
+
its own writer ([ADR-0033](adr/0033-rite-fast-own-agents.md)). The counts here cover
|
|
269
|
+
the lifecycle roles. Four read-only work roles handle
|
|
266
270
|
bounded evidence, planning, proof, and compatibility while the root keeps
|
|
267
271
|
authority:
|
|
268
272
|
|
|
@@ -302,7 +306,8 @@ Seal fan-out diagram: [`flow.md` § /rite-seal fan-out](flow.md#4-rite-seal-fan-
|
|
|
302
306
|
|
|
303
307
|
## Executor agent: fresh-context writer
|
|
304
308
|
|
|
305
|
-
The catalog has one writer role
|
|
309
|
+
The lifecycle catalog has one writer role (`/rite-fast` keeps its own
|
|
310
|
+
`fast-builder`, ADR-0033). Claude and Codex run it with one exact
|
|
306
311
|
path-bounded slice or accepted correction; every other agent remains read-only.
|
|
307
312
|
|
|
308
313
|
| Agent | Purpose |
|
package/docs/usage.md
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
These examples cover the common DevRites workflows. Start a new feature with
|
|
4
4
|
`/rite-spec` and bring an existing codebase in with `/rite-adopt`.
|
|
5
|
-
`/rite-quick
|
|
6
|
-
lifecycle. Workspace phases first read the active workspace from
|
|
5
|
+
`/rite-quick`, `/rite-fast`, and `/rite-frame` handle bounded work outside the full
|
|
6
|
+
feature lifecycle. Workspace phases first read the active workspace from
|
|
7
7
|
`.devrites/ACTIVE` and `.devrites/work/<slug>/`. If none exists, they report the
|
|
8
8
|
command that can create or select one. `/rite-upgrade [slug]` is the
|
|
9
9
|
compatibility audit for an older active workspace that cannot resume.
|
|
@@ -274,9 +274,11 @@ func (r *runner) pruneDropped() error {
|
|
|
274
274
|
return fmt.Errorf("strip hooks from %s: %w", merge.TargetRel, err)
|
|
275
275
|
}
|
|
276
276
|
} else if merge.TargetRel == hostpack.ClaudeSettingsMerge.TargetRel {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
277
|
+
if err := r.stripClaudeSettings(filepath.Join(r.target, filepath.FromSlash(merge.TargetRel)), true); err != nil {
|
|
278
|
+
return fmt.Errorf("strip DevRites settings from %s: %w", merge.TargetRel, err)
|
|
279
|
+
}
|
|
280
|
+
} else if err := stripMarkerPath(filepath.Join(r.target, filepath.FromSlash(merge.TargetRel)), merge.Begin, merge.End); err != nil {
|
|
281
|
+
return fmt.Errorf("strip marker block from %s: %w", merge.TargetRel, err)
|
|
280
282
|
}
|
|
281
283
|
}
|
|
282
284
|
if err := os.Remove(dead); err != nil && !os.IsNotExist(err) {
|
|
@@ -13,6 +13,7 @@ import (
|
|
|
13
13
|
"time"
|
|
14
14
|
|
|
15
15
|
"github.com/devrites/devrites/internal/fsutil"
|
|
16
|
+
"github.com/devrites/devrites/internal/version"
|
|
16
17
|
)
|
|
17
18
|
|
|
18
19
|
func (r *runner) installBinary() error {
|
|
@@ -28,7 +29,8 @@ func (r *runner) installBinary() error {
|
|
|
28
29
|
incoming := strings.TrimPrefix(tag, "v")
|
|
29
30
|
dest := binaryDest()
|
|
30
31
|
if exists(dest) {
|
|
31
|
-
|
|
32
|
+
ev := engineVersion(dest)
|
|
33
|
+
if c, ok := version.Compare(ev, incoming); ok && c > 0 {
|
|
32
34
|
fmt.Fprintf(r.opts.Stderr, "warning: engine binary: installed %s is newer than %s - refusing to downgrade (kept).\n", ev, tag)
|
|
33
35
|
return nil
|
|
34
36
|
}
|
|
@@ -405,28 +405,3 @@ func semverLike(v string) bool {
|
|
|
405
405
|
v = strings.TrimPrefix(v, "v")
|
|
406
406
|
return len(v) > 0 && v[0] >= '0' && v[0] <= '9'
|
|
407
407
|
}
|
|
408
|
-
|
|
409
|
-
func verGT(a, b string) bool {
|
|
410
|
-
a = strings.TrimPrefix(a, "v")
|
|
411
|
-
b = strings.TrimPrefix(b, "v")
|
|
412
|
-
as := strings.Split(strings.Split(a, "-")[0], ".")
|
|
413
|
-
bs := strings.Split(strings.Split(b, "-")[0], ".")
|
|
414
|
-
for len(as) < 3 {
|
|
415
|
-
as = append(as, "0")
|
|
416
|
-
}
|
|
417
|
-
for len(bs) < 3 {
|
|
418
|
-
bs = append(bs, "0")
|
|
419
|
-
}
|
|
420
|
-
for i := 0; i < 3; i++ {
|
|
421
|
-
var ai, bi int
|
|
422
|
-
_, _ = fmt.Sscanf(as[i], "%d", &ai)
|
|
423
|
-
_, _ = fmt.Sscanf(bs[i], "%d", &bi)
|
|
424
|
-
if ai > bi {
|
|
425
|
-
return true
|
|
426
|
-
}
|
|
427
|
-
if ai < bi {
|
|
428
|
-
return false
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
return false
|
|
432
|
-
}
|
|
@@ -15,6 +15,7 @@ import (
|
|
|
15
15
|
"time"
|
|
16
16
|
|
|
17
17
|
"github.com/devrites/devrites/internal/parallel"
|
|
18
|
+
"github.com/devrites/devrites/internal/state"
|
|
18
19
|
)
|
|
19
20
|
|
|
20
21
|
// ClaimsFile is the repo-level append-only claim ledger under .devrites.
|
|
@@ -249,6 +250,20 @@ func claimAdd(root string, args []string, stdout, stderr io.Writer) int {
|
|
|
249
250
|
return 2
|
|
250
251
|
}
|
|
251
252
|
path := claimsPath(root)
|
|
253
|
+
// Hold the ledger lock across read, conflict check, and append so two
|
|
254
|
+
// sessions cannot both pass the check and claim the same path.
|
|
255
|
+
code := 0
|
|
256
|
+
if err := state.WithLock(path+".lock", func() error {
|
|
257
|
+
code = claimAddLocked(path, session, reason, ttl, paths, stdout, stderr)
|
|
258
|
+
return nil
|
|
259
|
+
}); err != nil {
|
|
260
|
+
fmt.Fprintf(stderr, "claim: %v\n", err)
|
|
261
|
+
return 2
|
|
262
|
+
}
|
|
263
|
+
return code
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
func claimAddLocked(path, session, reason string, ttl int, paths []string, stdout, stderr io.Writer) int {
|
|
252
267
|
latest, order, _, err := readClaims(path)
|
|
253
268
|
if err != nil {
|
|
254
269
|
fmt.Fprintf(stderr, "claim: %v\n", err)
|
|
@@ -3,9 +3,11 @@ package lib
|
|
|
3
3
|
import (
|
|
4
4
|
"bytes"
|
|
5
5
|
"encoding/json"
|
|
6
|
+
"fmt"
|
|
6
7
|
"os"
|
|
7
8
|
"path/filepath"
|
|
8
9
|
"strings"
|
|
10
|
+
"sync"
|
|
9
11
|
"testing"
|
|
10
12
|
"time"
|
|
11
13
|
)
|
|
@@ -180,3 +182,29 @@ func TestClaimLedgerToleratesMalformedLines(t *testing.T) {
|
|
|
180
182
|
t.Fatalf("malformed ledger: %d %q", code, out)
|
|
181
183
|
}
|
|
182
184
|
}
|
|
185
|
+
|
|
186
|
+
func TestClaimAddConcurrentOverlapOneWins(t *testing.T) {
|
|
187
|
+
root := claimTestRoot(t)
|
|
188
|
+
const n = 8
|
|
189
|
+
codes := make(chan int, n)
|
|
190
|
+
var wg sync.WaitGroup
|
|
191
|
+
for i := range n {
|
|
192
|
+
wg.Add(1)
|
|
193
|
+
go func() {
|
|
194
|
+
defer wg.Done()
|
|
195
|
+
var out, errOut bytes.Buffer
|
|
196
|
+
codes <- RunClaim(root, []string{"add", "--session", fmt.Sprintf("s%d", i), "pkg/a.go"}, &out, &errOut)
|
|
197
|
+
}()
|
|
198
|
+
}
|
|
199
|
+
wg.Wait()
|
|
200
|
+
close(codes)
|
|
201
|
+
wins := 0
|
|
202
|
+
for c := range codes {
|
|
203
|
+
if c == 0 {
|
|
204
|
+
wins++
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if wins != 1 {
|
|
208
|
+
t.Fatalf("overlapping concurrent claims: %d succeeded, want exactly 1", wins)
|
|
209
|
+
}
|
|
210
|
+
}
|
|
@@ -5,6 +5,7 @@ import (
|
|
|
5
5
|
"os"
|
|
6
6
|
"path/filepath"
|
|
7
7
|
"strings"
|
|
8
|
+
"sync"
|
|
8
9
|
"testing"
|
|
9
10
|
)
|
|
10
11
|
|
|
@@ -519,3 +520,55 @@ func TestDiffScopeAllowlist(t *testing.T) {
|
|
|
519
520
|
t.Fatalf("code=%d\n%s", code, stdout.String())
|
|
520
521
|
}
|
|
521
522
|
}
|
|
523
|
+
|
|
524
|
+
func TestDispatchConcurrentReturnsCompleteWave(t *testing.T) {
|
|
525
|
+
root, featureDir := newWorkspace(t, "build")
|
|
526
|
+
run := func(args ...string) int {
|
|
527
|
+
out, err := &bytes.Buffer{}, &bytes.Buffer{}
|
|
528
|
+
return RunDispatch(root, args, out, err)
|
|
529
|
+
}
|
|
530
|
+
roles := []string{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7"}
|
|
531
|
+
open := []string{"feat", "open", "--phase", "review", "--wave", "w"}
|
|
532
|
+
for _, r := range roles {
|
|
533
|
+
open = append(open, "--role", r)
|
|
534
|
+
}
|
|
535
|
+
if c := run(open...); c != 0 {
|
|
536
|
+
t.Fatal("open failed")
|
|
537
|
+
}
|
|
538
|
+
for _, r := range roles {
|
|
539
|
+
if c := run("feat", "start", "--wave", "w", "--role", r, "--handle", "h-"+r); c != 0 {
|
|
540
|
+
t.Fatalf("start %s failed", r)
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
if c := run("feat", "seal", "--wave", "w"); c != 0 {
|
|
544
|
+
t.Fatal("seal failed")
|
|
545
|
+
}
|
|
546
|
+
var wg sync.WaitGroup
|
|
547
|
+
for _, r := range roles {
|
|
548
|
+
wg.Add(1)
|
|
549
|
+
go func() {
|
|
550
|
+
defer wg.Done()
|
|
551
|
+
if c := run("feat", "return", "--wave", "w", "--role", r); c != 0 {
|
|
552
|
+
t.Errorf("return %s failed: %d", r, c)
|
|
553
|
+
}
|
|
554
|
+
}()
|
|
555
|
+
}
|
|
556
|
+
wg.Wait()
|
|
557
|
+
if c := run("feat", "status", "--wave", "w"); c != 0 {
|
|
558
|
+
data, _ := os.ReadFile(filepath.Join(featureDir, "dispatch.json"))
|
|
559
|
+
t.Fatalf("concurrent returns lost an update; wave not complete:\n%s", data)
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
func TestDispatchAbandonRecordsReason(t *testing.T) {
|
|
564
|
+
root, featureDir := newWorkspace(t, "build")
|
|
565
|
+
out, errOut := &bytes.Buffer{}, &bytes.Buffer{}
|
|
566
|
+
if c := RunDispatch(root, []string{"feat", "open", "--phase", "build", "--wave", "w", "--role", "x"}, out, errOut); c != 0 {
|
|
567
|
+
t.Fatal("open failed")
|
|
568
|
+
}
|
|
569
|
+
RunDispatch(root, []string{"feat", "abandon", "--wave", "w", "--reason", "host limit"}, out, errOut)
|
|
570
|
+
data, err := os.ReadFile(filepath.Join(featureDir, "dispatch.json"))
|
|
571
|
+
if err != nil || !strings.Contains(string(data), `"reason": "host limit"`) {
|
|
572
|
+
t.Fatalf("abandon reason not persisted: %v\n%s", err, data)
|
|
573
|
+
}
|
|
574
|
+
}
|
|
@@ -6,10 +6,12 @@ import (
|
|
|
6
6
|
"io"
|
|
7
7
|
"os"
|
|
8
8
|
"path/filepath"
|
|
9
|
+
"sort"
|
|
9
10
|
"strings"
|
|
10
11
|
"time"
|
|
11
12
|
|
|
12
13
|
"github.com/devrites/devrites/internal/devritespaths"
|
|
14
|
+
"github.com/devrites/devrites/internal/state"
|
|
13
15
|
)
|
|
14
16
|
|
|
15
17
|
// dispatch.go: launch-wave barrier for host-native agent dispatch. Hosts own
|
|
@@ -31,9 +33,10 @@ type dispatchFile struct {
|
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
type dispatchWave struct {
|
|
34
|
-
Phase
|
|
35
|
-
State
|
|
36
|
-
|
|
36
|
+
Phase string `json:"phase"`
|
|
37
|
+
State string `json:"state"` // open, sealed, abandoned, complete
|
|
38
|
+
Reason string `json:"reason,omitempty"`
|
|
39
|
+
Roles map[string]*dispatchRole `json:"roles"`
|
|
37
40
|
}
|
|
38
41
|
|
|
39
42
|
type dispatchRole struct {
|
|
@@ -79,7 +82,7 @@ func saveDispatch(path string, f *dispatchFile) error {
|
|
|
79
82
|
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
|
80
83
|
return err
|
|
81
84
|
}
|
|
82
|
-
return
|
|
85
|
+
return state.AtomicWrite(path, data, 0o600)
|
|
83
86
|
}
|
|
84
87
|
|
|
85
88
|
func nowStamp() string { return time.Now().UTC().Format(time.RFC3339) }
|
|
@@ -122,6 +125,20 @@ func RunDispatch(root string, args []string, stdout, stderr io.Writer) int {
|
|
|
122
125
|
fmt.Fprintf(stderr, "dispatch: %v\n", err)
|
|
123
126
|
return 2
|
|
124
127
|
}
|
|
128
|
+
// Serialize load-modify-save so concurrent start/return calls never lose
|
|
129
|
+
// an update and strand the wave short of complete.
|
|
130
|
+
code := 0
|
|
131
|
+
if err := state.WithFeatureLock(root, slug, func() error {
|
|
132
|
+
code = dispatchLocked(root, slug, sub, phase, wave, role, handle, reason, roles, stdout, stderr)
|
|
133
|
+
return nil
|
|
134
|
+
}); err != nil {
|
|
135
|
+
fmt.Fprintf(stderr, "dispatch: %v\n", err)
|
|
136
|
+
return 3
|
|
137
|
+
}
|
|
138
|
+
return code
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
func dispatchLocked(root, slug, sub, phase, wave, role, handle, reason string, roles []string, stdout, stderr io.Writer) int {
|
|
125
142
|
f, path, err := loadDispatch(root, slug)
|
|
126
143
|
if err != nil {
|
|
127
144
|
fmt.Fprintf(stderr, "dispatch: %v\n", err)
|
|
@@ -204,6 +221,7 @@ func RunDispatch(root string, args []string, stdout, stderr io.Writer) int {
|
|
|
204
221
|
}
|
|
205
222
|
}
|
|
206
223
|
if len(missing) > 0 {
|
|
224
|
+
sort.Strings(missing)
|
|
207
225
|
return fail("wave %q cannot seal: no start handle for %s", wave, strings.Join(missing, ","))
|
|
208
226
|
}
|
|
209
227
|
w.State = "sealed"
|
|
@@ -244,7 +262,8 @@ func RunDispatch(root string, args []string, stdout, stderr io.Writer) int {
|
|
|
244
262
|
|
|
245
263
|
case "status":
|
|
246
264
|
if wave == "" {
|
|
247
|
-
for
|
|
265
|
+
for _, name := range sortedKeys(f.Waves) {
|
|
266
|
+
w := f.Waves[name]
|
|
248
267
|
fmt.Fprintf(stdout, "dispatch: wave %s state=%s roles=%d\n", name, w.State, len(w.Roles))
|
|
249
268
|
}
|
|
250
269
|
if len(f.Waves) == 0 {
|
|
@@ -257,7 +276,8 @@ func RunDispatch(root string, args []string, stdout, stderr io.Writer) int {
|
|
|
257
276
|
return fail("no wave %q", wave)
|
|
258
277
|
}
|
|
259
278
|
var pending []string
|
|
260
|
-
for
|
|
279
|
+
for _, name := range sortedKeys(w.Roles) {
|
|
280
|
+
r := w.Roles[name]
|
|
261
281
|
mark := "declared"
|
|
262
282
|
if r.Handle != "" {
|
|
263
283
|
mark = "started"
|
|
@@ -281,9 +301,10 @@ func RunDispatch(root string, args []string, stdout, stderr io.Writer) int {
|
|
|
281
301
|
return fail("no wave %q", wave)
|
|
282
302
|
}
|
|
283
303
|
if strings.TrimSpace(reason) == "" {
|
|
284
|
-
return fail("--reason is required (non-empty,
|
|
304
|
+
return fail("--reason is required (non-empty, recorded in dispatch.json)")
|
|
285
305
|
}
|
|
286
306
|
w.State = "abandoned"
|
|
307
|
+
w.Reason = reason
|
|
287
308
|
if err := saveDispatch(path, f); err != nil {
|
|
288
309
|
return fail("%v", err)
|
|
289
310
|
}
|
|
@@ -48,6 +48,20 @@ func RunMergeManifest(root string, args []string, stdout, stderr io.Writer) int
|
|
|
48
48
|
fmt.Fprintf(stderr, "merge-manifest: BLOCKED: %v\n", err)
|
|
49
49
|
return 3
|
|
50
50
|
}
|
|
51
|
+
code := 0
|
|
52
|
+
if err := state.WithFeatureLock(root, slug, func() error {
|
|
53
|
+
code = mergeManifestLocked(root, slug, workspace, args, stdout, stderr)
|
|
54
|
+
return nil
|
|
55
|
+
}); err != nil {
|
|
56
|
+
fmt.Fprintf(stderr, "merge-manifest: %v\n", err)
|
|
57
|
+
return 1
|
|
58
|
+
}
|
|
59
|
+
return code
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// mergeManifestLocked reads, unions, and rewrites touched-files.md under the
|
|
63
|
+
// feature lock so a concurrent writer cannot interleave with the rewrite.
|
|
64
|
+
func mergeManifestLocked(root, slug, workspace string, args []string, stdout, stderr io.Writer) int {
|
|
51
65
|
manifestPath := filepath.Join(workspace, "touched-files.md")
|
|
52
66
|
releaseRaw, err := readBoundedRegularFile(manifestPath, maxCandidateManifestBytes)
|
|
53
67
|
if err != nil {
|
|
@@ -80,8 +80,16 @@ func TestReceipt(t *testing.T) {
|
|
|
80
80
|
r["task_id"], r["role"], r["lane"], r["outcome"] = "R-1", "reviewer", "security", "no-findings"
|
|
81
81
|
delete(r, "changed_paths")
|
|
82
82
|
}, "-", 1, "no-findings without inspected ranges is malformed"},
|
|
83
|
+
{"reviewer no-findings without domains", func(r J) {
|
|
84
|
+
r["task_id"], r["role"], r["lane"], r["outcome"], r["inspected"] = "R-1", "reviewer", "security", "no-findings", L{"src/a.py:1-9"}
|
|
85
|
+
}, "-", 1, "no-findings must name its domains_checked"},
|
|
86
|
+
{"reviewer unknown domain", func(r J) {
|
|
87
|
+
r["task_id"], r["role"], r["lane"], r["outcome"], r["inspected"] = "R-1", "reviewer", "security", "no-findings", L{"src/a.py:1-9"}
|
|
88
|
+
r["domains_checked"] = L{"style"}
|
|
89
|
+
}, "-", 1, "domains_checked has unknown domain 'style'"},
|
|
83
90
|
{"reviewer admissible", func(r J) {
|
|
84
91
|
r["task_id"], r["role"], r["lane"], r["outcome"], r["inspected"] = "R-1", "reviewer", "security", "no-findings", L{"src/a.py:1-9"}
|
|
92
|
+
r["domains_checked"] = L{"security"}
|
|
85
93
|
}, "-", 0, "ADMISSIBLE"},
|
|
86
94
|
}
|
|
87
95
|
for _, c := range cases {
|
|
@@ -114,6 +122,7 @@ func TestReceiptAgainstOpenStage(t *testing.T) {
|
|
|
114
122
|
}})
|
|
115
123
|
rc := writerReceipt()
|
|
116
124
|
rc["task_id"], rc["role"], rc["lane"], rc["outcome"], rc["inspected"] = "R-2", "reviewer", "security", "no-findings", L{"src/a.py:1-9"}
|
|
125
|
+
rc["domains_checked"] = L{"security"}
|
|
117
126
|
delete(rc, "changed_paths")
|
|
118
127
|
p := write(t, filepath.Join(dir, "receipts/r2.json"), rc)
|
|
119
128
|
if code, out, errs := run("receipt", dir, p); code != 0 || !strings.Contains(out, "ADMISSIBLE") {
|