devrites 3.0.0 → 3.0.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.
- package/CHANGELOG.md +12 -0
- package/README.md +1 -1
- package/docs/engine/commands.md +1 -1
- package/engine/hooks_events_test.go +15 -0
- package/engine/hooks_workspace.go +8 -31
- package/engine/internal/gate/gate.go +4 -9
- package/engine/internal/gate/gate_test.go +16 -0
- package/engine/internal/lib/analyze.go +9 -10
- package/engine/internal/lib/buildreadiness.go +10 -16
- package/engine/internal/lib/checkacceptance.go +9 -9
- package/engine/internal/lib/coverage.go +13 -15
- package/engine/internal/lib/cursor_compat_test.go +91 -0
- package/engine/internal/lib/lanes.go +1 -1
- package/engine/internal/lib/progress.go +25 -24
- package/engine/internal/lib/resolve.go +9 -14
- package/engine/internal/lib/tickafk.go +11 -28
- package/engine/internal/migrate/migrate.go +28 -16
- package/engine/internal/migrate/migrate_test.go +5 -3
- package/engine/internal/state/cursor.go +84 -0
- package/engine/internal/state/cursor_test.go +58 -0
- package/engine/internal/state/feature.go +34 -31
- package/engine/internal/state/schema.go +30 -18
- package/engine/internal/state/snapshot.go +13 -2
- package/engine/internal/state/state_test.go +48 -3
- package/engine/internal/workflow/commands.go +25 -8
- package/engine/internal/workflow/commands_test.go +35 -0
- package/engine/testdata/golden/TestParityAnalyze/slug=noac.golden +1 -1
- package/engine/testdata/golden/TestParityCheckAcceptance/arg=flat-ok.golden +1 -1
- package/engine/tests/adr_0004_required_by_phase_test.go +7 -1
- package/engine/tests/canonical_ac_ids_test.go +44 -0
- package/engine/tests/gate_test.go +22 -0
- package/engine/tests/migrate_cli_test.go +3 -3
- package/pack/.claude/skills/rite-define/SKILL.md +6 -0
- package/pack/.claude/skills/rite-spec/SKILL.md +2 -0
- package/pack/.claude/skills/rite-vet/SKILL.md +6 -1
- package/pack/generated/claude/skills/rite-define/SKILL.md +6 -0
- package/pack/generated/claude/skills/rite-spec/SKILL.md +2 -0
- package/pack/generated/claude/skills/rite-vet/SKILL.md +6 -1
- package/pack/generated/codex/skills/rite-define/SKILL.md +6 -0
- package/pack/generated/codex/skills/rite-spec/SKILL.md +2 -0
- package/pack/generated/codex/skills/rite-vet/SKILL.md +6 -1
- package/package.json +1 -1
|
@@ -13,14 +13,19 @@ type Command struct {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
var phaseToVerb = map[string]string{
|
|
16
|
-
"frame":
|
|
17
|
-
"spec":
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"vet":
|
|
22
|
-
"
|
|
23
|
-
"
|
|
16
|
+
"frame": "frame",
|
|
17
|
+
"spec": "spec",
|
|
18
|
+
"temper": "temper",
|
|
19
|
+
"define": "define",
|
|
20
|
+
"plan": "define", // plan is the artifact state produced by rite-define.
|
|
21
|
+
"vet": "vet",
|
|
22
|
+
"build": "build",
|
|
23
|
+
"converge": "converge",
|
|
24
|
+
"prove": "prove",
|
|
25
|
+
"polish": "polish",
|
|
26
|
+
"review": "review",
|
|
27
|
+
"seal": "seal",
|
|
28
|
+
"ship": "ship",
|
|
24
29
|
}
|
|
25
30
|
|
|
26
31
|
// ForVerb returns the Claude and Codex forms for a public rite verb. The empty
|
|
@@ -35,6 +40,18 @@ func ForVerb(verb string) Command {
|
|
|
35
40
|
return Command{Verb: verb, Claude: "/" + name, Codex: "$" + name}
|
|
36
41
|
}
|
|
37
42
|
|
|
43
|
+
// ForAction extracts the first explicit rite invocation from a cursor action.
|
|
44
|
+
// Cursor values may append a short reason after the command.
|
|
45
|
+
func ForAction(action string) Command {
|
|
46
|
+
for _, field := range strings.Fields(action) {
|
|
47
|
+
field = strings.Trim(field, "`'\"()[]{}<>,.;:")
|
|
48
|
+
if strings.HasPrefix(field, "/rite-") || strings.HasPrefix(field, "$rite-") {
|
|
49
|
+
return ForVerb(field)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return Command{}
|
|
53
|
+
}
|
|
54
|
+
|
|
38
55
|
// ForPhase returns the next public command for a workflow phase.
|
|
39
56
|
func ForPhase(phase string) Command {
|
|
40
57
|
verb := phaseToVerb[strings.TrimSpace(strings.ToLower(phase))]
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
package workflow
|
|
2
|
+
|
|
3
|
+
import "testing"
|
|
4
|
+
|
|
5
|
+
func TestForActionExtractsCanonicalInvocation(t *testing.T) {
|
|
6
|
+
for _, tc := range []struct {
|
|
7
|
+
action string
|
|
8
|
+
verb string
|
|
9
|
+
}{
|
|
10
|
+
{action: "/rite-define after readiness passes", verb: "define"},
|
|
11
|
+
{action: "resume with $rite-build", verb: "build"},
|
|
12
|
+
{action: "none"},
|
|
13
|
+
} {
|
|
14
|
+
if got := ForAction(tc.action); got.Verb != tc.verb {
|
|
15
|
+
t.Fatalf("ForAction(%q).Verb=%q, want %q", tc.action, got.Verb, tc.verb)
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
func TestForPhaseCoversCurrentLifecycle(t *testing.T) {
|
|
21
|
+
for _, phase := range []string{
|
|
22
|
+
"frame", "spec", "temper", "define", "vet", "build", "converge",
|
|
23
|
+
"prove", "polish", "review", "seal", "ship",
|
|
24
|
+
} {
|
|
25
|
+
if got := ForPhase(phase).Verb; got != phase {
|
|
26
|
+
t.Fatalf("ForPhase(%q).Verb=%q, want %q", phase, got, phase)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if got := ForPhase("plan").Verb; got != "define" {
|
|
30
|
+
t.Fatalf("ForPhase(plan).Verb=%q, want define compatibility route", got)
|
|
31
|
+
}
|
|
32
|
+
if got := ForPhase("done").Verb; got != "" {
|
|
33
|
+
t.Fatalf("ForPhase(done).Verb=%q, want empty", got)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -2,7 +2,7 @@ exit 0
|
|
|
2
2
|
# Cross-artifact analysis: noac
|
|
3
3
|
|
|
4
4
|
## Coverage
|
|
5
|
-
- [warn] spec.md — no
|
|
5
|
+
- [warn] spec.md — no AC-### acceptance ids found; tag criteria for a machine-checkable gate.
|
|
6
6
|
|
|
7
7
|
## Consistency
|
|
8
8
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
exit 0
|
|
2
|
-
check-acceptance: OK — 2 acceptance items all checked in seal.md (no ids; add
|
|
2
|
+
check-acceptance: OK — 2 acceptance items all checked in seal.md (no ids; add AC-### for id-level grading)
|
|
@@ -16,12 +16,18 @@ import (
|
|
|
16
16
|
var phaseArc = []state.Phase{
|
|
17
17
|
state.PhaseFrame,
|
|
18
18
|
state.PhaseSpec,
|
|
19
|
+
state.PhaseTemper,
|
|
20
|
+
state.PhaseDefine,
|
|
19
21
|
state.PhasePlan,
|
|
22
|
+
state.PhaseVet,
|
|
20
23
|
state.PhaseBuild,
|
|
24
|
+
state.PhaseConverge,
|
|
21
25
|
state.PhaseProve,
|
|
22
|
-
state.
|
|
26
|
+
state.PhasePolish,
|
|
27
|
+
state.PhaseReview,
|
|
23
28
|
state.PhaseSeal,
|
|
24
29
|
state.PhaseShip,
|
|
30
|
+
state.PhaseDone,
|
|
25
31
|
}
|
|
26
32
|
|
|
27
33
|
func TestADR0004RequiredSectionsAreAdditiveDownTheArc(t *testing.T) {
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
package main_test
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"strings"
|
|
5
|
+
"testing"
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
func TestCanonicalAcceptanceIDsAcrossGates(t *testing.T) {
|
|
9
|
+
work := t.TempDir()
|
|
10
|
+
writeFeatureFile(t, work, "canonical", "spec.md",
|
|
11
|
+
"## Acceptance criteria\n- [ ] AC-001: alpha\n- [ ] AC-002: beta\n")
|
|
12
|
+
writeFeatureFile(t, work, "canonical", "tasks.md",
|
|
13
|
+
"## SLICE-001 alpha\nSatisfies: AC-001\n## SLICE-002 beta\nSatisfies: AC-002\n## SLICE-003 orphan\n")
|
|
14
|
+
writeFeatureFile(t, work, "canonical", "seal.md",
|
|
15
|
+
"## Acceptance Criteria\n- [x] AC-001: alpha — evidence: t1\n- [x] AC-002: beta — evidence: t2\n")
|
|
16
|
+
|
|
17
|
+
t.Run("analyze", func(t *testing.T) {
|
|
18
|
+
stdout, stderr, code := runGo(t, work, "analyze", "canonical")
|
|
19
|
+
if code != 0 || !strings.Contains(stdout, "AC-001 — covered") || !strings.Contains(stdout, "slice 'SLICE-003 orphan'") {
|
|
20
|
+
t.Fatalf("exit=%d stdout=%q stderr=%q", code, stdout, stderr)
|
|
21
|
+
}
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
t.Run("coverage", func(t *testing.T) {
|
|
25
|
+
stdout, stderr, code := runGo(t, work, "coverage", "canonical")
|
|
26
|
+
if code != 0 || !strings.Contains(stdout, "| AC-001 | SLICE-001 alpha | yes |") {
|
|
27
|
+
t.Fatalf("exit=%d stdout=%q stderr=%q", code, stdout, stderr)
|
|
28
|
+
}
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
t.Run("check-acceptance", func(t *testing.T) {
|
|
32
|
+
stdout, stderr, code := runGo(t, work, "check-acceptance", ".devrites/features/canonical")
|
|
33
|
+
if code != 0 || !strings.Contains(stdout, "AC-001 AC-002") {
|
|
34
|
+
t.Fatalf("exit=%d stdout=%q stderr=%q", code, stdout, stderr)
|
|
35
|
+
}
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
t.Run("lanes", func(t *testing.T) {
|
|
39
|
+
stdout, stderr, code := runGo(t, work, "lanes", "plan", "canonical")
|
|
40
|
+
if code != 0 || !strings.Contains(stdout, "- SLICE-001 alpha:") {
|
|
41
|
+
t.Fatalf("exit=%d stdout=%q stderr=%q", code, stdout, stderr)
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
}
|
|
@@ -85,6 +85,28 @@ func TestReadinessPassesCompletePhase(t *testing.T) {
|
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
func TestReadinessAcceptsCanonicalTemperCursor(t *testing.T) {
|
|
89
|
+
root := filepath.Join(t.TempDir(), ".devrites")
|
|
90
|
+
testutil.WriteFile(t, filepath.Join(root, "work", "tempered", "state.md"), `# State
|
|
91
|
+
|
|
92
|
+
## Cursor
|
|
93
|
+
| Key | Value |
|
|
94
|
+
| --- | --- |
|
|
95
|
+
| phase | temper |
|
|
96
|
+
| status | running |
|
|
97
|
+
| next_action | /rite-define |
|
|
98
|
+
`)
|
|
99
|
+
testutil.WriteFile(t, filepath.Join(root, "work", "tempered", "spec.md"), "# Spec\n\nReady.\n")
|
|
100
|
+
|
|
101
|
+
out, errOut, code := runDevrites(t, root, "readiness", "tempered")
|
|
102
|
+
if code != 0 {
|
|
103
|
+
t.Fatalf("exit = %d, want 0; stderr:\n%s", code, errOut)
|
|
104
|
+
}
|
|
105
|
+
if !strings.Contains(out, "phase: temper") || !strings.Contains(out, "result: pass") {
|
|
106
|
+
t.Fatalf("unexpected readiness output:\n%s", out)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
88
110
|
func TestSealBlocksWhenSealSectionsMissing(t *testing.T) {
|
|
89
111
|
root := newWorkspace(t)
|
|
90
112
|
out, _, code := runDevrites(t, root, "seal", "auth-tokens")
|
|
@@ -20,7 +20,7 @@ func workWorkspace(t *testing.T) (root, slug string) {
|
|
|
20
20
|
t.Fatal(err)
|
|
21
21
|
}
|
|
22
22
|
files := map[string]string{
|
|
23
|
-
"state.md": "# State\n\
|
|
23
|
+
"state.md": "# State\n\n| Key | Value |\n| --- | --- |\n| phase | temper |\n| status | running |\n",
|
|
24
24
|
"spec.md": "# Spec\n\nRotate tokens.\n",
|
|
25
25
|
"plan.md": "# Plan\n\nStep 1, step 2.\n",
|
|
26
26
|
"tasks.md": "# Tasks\n\n- [x] one\n",
|
|
@@ -68,7 +68,7 @@ func TestMigrateNormalizesCanonicalWorkSchema(t *testing.T) {
|
|
|
68
68
|
if err != nil {
|
|
69
69
|
t.Fatal(err)
|
|
70
70
|
}
|
|
71
|
-
if !strings.Contains(string(fm), "phase:
|
|
71
|
+
if !strings.Contains(string(fm), "phase: temper") {
|
|
72
72
|
t.Errorf("feature.md phase not derived from state.md\n%s", fm)
|
|
73
73
|
}
|
|
74
74
|
if !strings.Contains(string(fm), "schemaVersion: 1") {
|
|
@@ -94,7 +94,7 @@ func TestMigratePostStatusWorks(t *testing.T) {
|
|
|
94
94
|
if code != 0 {
|
|
95
95
|
t.Fatalf("status after migrate exit = %d (stderr: %s)", code, errOut)
|
|
96
96
|
}
|
|
97
|
-
if !strings.Contains(out, "phase:
|
|
97
|
+
if !strings.Contains(out, "phase: temper") {
|
|
98
98
|
t.Errorf("migrated feature status is wrong\n%s", out)
|
|
99
99
|
}
|
|
100
100
|
}
|
|
@@ -119,6 +119,12 @@ Pull these via `Read` when shaping the plan:
|
|
|
119
119
|
as a blocking gate at `/rite-vet`; no file → none declared → nothing to check.)
|
|
120
120
|
6. **Write** `architecture.md`, `plan.md`, `tasks.md`, and `traceability.md`; update
|
|
121
121
|
`state.md` (phase: plan → next `/rite-vet`).
|
|
122
|
+
6a. **Cross-artifact gate — now that `tasks.md` exists.** Run the deterministic
|
|
123
|
+
spec↔tasks coverage/consistency check; any non-zero result blocks plan readiness:
|
|
124
|
+
```bash
|
|
125
|
+
S="$(cat .devrites/ACTIVE 2>/dev/null)"
|
|
126
|
+
devrites-engine analyze "$S"
|
|
127
|
+
```
|
|
122
128
|
7. **Readiness gate** (bottom of plan-template): every acceptance criterion covered by a
|
|
123
129
|
slice, dependency order acyclic + risk-first, no unjustified deviation, rollback for
|
|
124
130
|
every destructive/migration step. **Stop and confirm** before code. Render the review-before-code
|
|
@@ -185,6 +185,8 @@ stay flat `AC-###` bullets; the grammar is opt-in by rigor, never forced.
|
|
|
185
185
|
devrites-engine spec-skeleton ".devrites/work/<slug>"
|
|
186
186
|
devrites-engine spec-validate ".devrites/work/<slug>" --against .devrites/specs
|
|
187
187
|
```
|
|
188
|
+
**Do not run `devrites-engine analyze` in this phase:** `tasks.md` deliberately does not
|
|
189
|
+
exist yet. `/rite-define` owns the first analyze pass after it writes the slices.
|
|
188
190
|
Treat edge/prohibition findings as blocking just like grammar findings. When it passes, write `Spec gate: passed <iso>` to `state.md`.
|
|
189
191
|
6a. **Review-before-code digest.** Before handing off to planning, render the cheap human review:
|
|
190
192
|
`Intent` (one sentence), `Done means` (top acceptance/scenario IDs), `Scope/risk` (what is in/out
|
|
@@ -140,7 +140,12 @@ Audit for a plan resting on unstated beliefs).
|
|
|
140
140
|
(`/rite-build` and `/rite-prove` read it). Harden `plan.md` / `tasks.md` directly for
|
|
141
141
|
behavior-preserving refinements; route every acceptance/behavior-changing delta through the
|
|
142
142
|
**Spec Drift Guard** (`drift.md` + recorded decision + `/rite-plan repair`). Append
|
|
143
|
-
`decisions.md` (one ADR per material call) and `assumptions.md`.
|
|
143
|
+
`decisions.md` (one ADR per material call) and `assumptions.md`. Re-run the gate after
|
|
144
|
+
every fold-back so a task edit cannot invalidate the earlier pass:
|
|
145
|
+
```bash
|
|
146
|
+
devrites-engine analyze; echo "final analyze rc=$?"
|
|
147
|
+
```
|
|
148
|
+
Any non-zero result blocks the handoff. Then update `state.md`:
|
|
144
149
|
`Phase: vet`, `Next step: /rite-build`; on a blocking pause write the `Awaiting human` block +
|
|
145
150
|
`Status: awaiting_human` before stopping.
|
|
146
151
|
6. **Adversarial verification loop.** Apply the light/full branching contract in
|
|
@@ -119,6 +119,12 @@ Pull these via `Read` when shaping the plan:
|
|
|
119
119
|
as a blocking gate at `/rite-vet`; no file → none declared → nothing to check.)
|
|
120
120
|
6. **Write** `architecture.md`, `plan.md`, `tasks.md`, and `traceability.md`; update
|
|
121
121
|
`state.md` (phase: plan → next `/rite-vet`).
|
|
122
|
+
6a. **Cross-artifact gate — now that `tasks.md` exists.** Run the deterministic
|
|
123
|
+
spec↔tasks coverage/consistency check; any non-zero result blocks plan readiness:
|
|
124
|
+
```bash
|
|
125
|
+
S="$(cat .devrites/ACTIVE 2>/dev/null)"
|
|
126
|
+
devrites-engine analyze "$S"
|
|
127
|
+
```
|
|
122
128
|
7. **Readiness gate** (bottom of plan-template): every acceptance criterion covered by a
|
|
123
129
|
slice, dependency order acyclic + risk-first, no unjustified deviation, rollback for
|
|
124
130
|
every destructive/migration step. **Stop and confirm** before code. Render the review-before-code
|
|
@@ -185,6 +185,8 @@ stay flat `AC-###` bullets; the grammar is opt-in by rigor, never forced.
|
|
|
185
185
|
devrites-engine spec-skeleton ".devrites/work/<slug>"
|
|
186
186
|
devrites-engine spec-validate ".devrites/work/<slug>" --against .devrites/specs
|
|
187
187
|
```
|
|
188
|
+
**Do not run `devrites-engine analyze` in this phase:** `tasks.md` deliberately does not
|
|
189
|
+
exist yet. `/rite-define` owns the first analyze pass after it writes the slices.
|
|
188
190
|
Treat edge/prohibition findings as blocking just like grammar findings. When it passes, write `Spec gate: passed <iso>` to `state.md`.
|
|
189
191
|
6a. **Review-before-code digest.** Before handing off to planning, render the cheap human review:
|
|
190
192
|
`Intent` (one sentence), `Done means` (top acceptance/scenario IDs), `Scope/risk` (what is in/out
|
|
@@ -140,7 +140,12 @@ Audit for a plan resting on unstated beliefs).
|
|
|
140
140
|
(`/rite-build` and `/rite-prove` read it). Harden `plan.md` / `tasks.md` directly for
|
|
141
141
|
behavior-preserving refinements; route every acceptance/behavior-changing delta through the
|
|
142
142
|
**Spec Drift Guard** (`drift.md` + recorded decision + `/rite-plan repair`). Append
|
|
143
|
-
`decisions.md` (one ADR per material call) and `assumptions.md`.
|
|
143
|
+
`decisions.md` (one ADR per material call) and `assumptions.md`. Re-run the gate after
|
|
144
|
+
every fold-back so a task edit cannot invalidate the earlier pass:
|
|
145
|
+
```bash
|
|
146
|
+
devrites-engine analyze; echo "final analyze rc=$?"
|
|
147
|
+
```
|
|
148
|
+
Any non-zero result blocks the handoff. Then update `state.md`:
|
|
144
149
|
`Phase: vet`, `Next step: /rite-build`; on a blocking pause write the `Awaiting human` block +
|
|
145
150
|
`Status: awaiting_human` before stopping.
|
|
146
151
|
6. **Adversarial verification loop.** Apply the light/full branching contract in
|
|
@@ -131,6 +131,12 @@ Pull these via `Read` when shaping the plan:
|
|
|
131
131
|
as a blocking gate at `$rite-vet`; no file → none declared → nothing to check.)
|
|
132
132
|
6. **Write** `architecture.md`, `plan.md`, `tasks.md`, and `traceability.md`; update
|
|
133
133
|
`state.md` (phase: plan → next `$rite-vet`).
|
|
134
|
+
6a. **Cross-artifact gate — now that `tasks.md` exists.** Run the deterministic
|
|
135
|
+
spec↔tasks coverage/consistency check; any non-zero result blocks plan readiness:
|
|
136
|
+
```bash
|
|
137
|
+
S="$(cat .devrites/ACTIVE 2>/dev/null)"
|
|
138
|
+
devrites-engine analyze "$S"
|
|
139
|
+
```
|
|
134
140
|
7. **Readiness gate** (bottom of plan-template): every acceptance criterion covered by a
|
|
135
141
|
slice, dependency order acyclic + risk-first, no unjustified deviation, rollback for
|
|
136
142
|
every destructive/migration step. **Stop and confirm** before code. Render the review-before-code
|
|
@@ -197,6 +197,8 @@ stay flat `AC-###` bullets; the grammar is opt-in by rigor, never forced.
|
|
|
197
197
|
devrites-engine spec-skeleton ".devrites/work/<slug>"
|
|
198
198
|
devrites-engine spec-validate ".devrites/work/<slug>" --against .devrites/specs
|
|
199
199
|
```
|
|
200
|
+
**Do not run `devrites-engine analyze` in this phase:** `tasks.md` deliberately does not
|
|
201
|
+
exist yet. `$rite-define` owns the first analyze pass after it writes the slices.
|
|
200
202
|
Treat edge/prohibition findings as blocking just like grammar findings. When it passes, write `Spec gate: passed <iso>` to `state.md`.
|
|
201
203
|
6a. **Review-before-code digest.** Before handing off to planning, render the cheap human review:
|
|
202
204
|
`Intent` (one sentence), `Done means` (top acceptance/scenario IDs), `Scope/risk` (what is in/out
|
|
@@ -152,7 +152,12 @@ Audit for a plan resting on unstated beliefs).
|
|
|
152
152
|
(`$rite-build` and `$rite-prove` read it). Harden `plan.md` / `tasks.md` directly for
|
|
153
153
|
behavior-preserving refinements; route every acceptance/behavior-changing delta through the
|
|
154
154
|
**Spec Drift Guard** (`drift.md` + recorded decision + `$rite-plan repair`). Append
|
|
155
|
-
`decisions.md` (one ADR per material call) and `assumptions.md`.
|
|
155
|
+
`decisions.md` (one ADR per material call) and `assumptions.md`. Re-run the gate after
|
|
156
|
+
every fold-back so a task edit cannot invalidate the earlier pass:
|
|
157
|
+
```bash
|
|
158
|
+
devrites-engine analyze; echo "final analyze rc=$?"
|
|
159
|
+
```
|
|
160
|
+
Any non-zero result blocks the handoff. Then update `state.md`:
|
|
156
161
|
`Phase: vet`, `Next step: $rite-build`; on a blocking pause write the `Awaiting human` block +
|
|
157
162
|
`Status: awaiting_human` before stopping.
|
|
158
163
|
6. **Adversarial verification loop.** Apply the light/full branching contract in
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "devrites",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.2",
|
|
4
4
|
"description": "DevRites — disciplined senior-engineer workflow skills pack for Claude Code and Codex",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"homepage": "https://github.com/ViktorsBaikers/DevRites#readme",
|