devrites 2.2.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/README.md +30 -17
- package/docs/architecture.md +30 -24
- package/docs/command-map.md +15 -6
- package/docs/flow.md +19 -5
- package/docs/orchestration.md +17 -7
- package/docs/skills.md +32 -8
- package/pack/.claude/agents/devrites-code-reviewer.md +6 -1
- package/pack/.claude/agents/devrites-devex-reviewer.md +94 -0
- package/pack/.claude/agents/devrites-forge-judge.md +92 -0
- package/pack/.claude/agents/devrites-frontend-reviewer.md +8 -0
- package/pack/.claude/agents/devrites-retrospector.md +91 -0
- package/pack/.claude/agents/devrites-slice-wright.md +18 -5
- package/pack/.claude/rules/README.md +5 -2
- package/pack/.claude/rules/agents.md +30 -2
- package/pack/.claude/rules/anti-patterns.md +11 -0
- package/pack/.claude/rules/code-review.md +16 -6
- package/pack/.claude/rules/core.md +13 -4
- package/pack/.claude/rules/developer-experience.md +119 -0
- package/pack/.claude/rules/principles.md +158 -0
- package/pack/.claude/rules/spec-grammar.md +106 -0
- package/pack/.claude/skills/devrites-browser-proof/SKILL.md +42 -3
- package/pack/.claude/skills/devrites-doubt/SKILL.md +1 -1
- package/pack/.claude/skills/devrites-lib/SKILL.md +9 -2
- package/pack/.claude/skills/devrites-lib/scripts/devrites.sh +8 -0
- package/pack/.claude/skills/devrites-lib/scripts/doubt-coverage.sh +39 -0
- package/pack/.claude/skills/devrites-lib/scripts/spec-validate.sh +130 -0
- package/pack/.claude/skills/rite-adopt/SKILL.md +13 -1
- package/pack/.claude/skills/rite-autocomplete/SKILL.md +3 -1
- package/pack/.claude/skills/rite-build/SKILL.md +51 -2
- package/pack/.claude/skills/rite-build/reference/anti-patterns.md +12 -0
- package/pack/.claude/skills/rite-build/reference/forge.md +171 -0
- package/pack/.claude/skills/rite-build/reference/one-slice-cycle.md +2 -0
- package/pack/.claude/skills/rite-build/reference/wright-dispatch.md +22 -2
- package/pack/.claude/skills/rite-define/SKILL.md +14 -1
- package/pack/.claude/skills/rite-frame/SKILL.md +7 -2
- package/pack/.claude/skills/rite-learn/SKILL.md +17 -4
- package/pack/.claude/skills/rite-polish/SKILL.md +3 -1
- package/pack/.claude/skills/rite-prove/SKILL.md +30 -1
- package/pack/.claude/skills/rite-quick/SKILL.md +9 -4
- package/pack/.claude/skills/rite-review/SKILL.md +5 -2
- package/pack/.claude/skills/rite-seal/SKILL.md +39 -4
- package/pack/.claude/skills/rite-seal/reference/anti-patterns.md +2 -0
- package/pack/.claude/skills/rite-ship/SKILL.md +21 -0
- package/pack/.claude/skills/rite-spec/SKILL.md +29 -5
- package/pack/.claude/skills/rite-spec/reference/spec-template.md +11 -1
- package/pack/.claude/skills/rite-status/SKILL.md +3 -1
- package/pack/.claude/skills/rite-vet/SKILL.md +46 -14
- package/package.json +1 -1
- package/scripts/check-cross-refs.py +4 -0
- package/scripts/run-behavioral-evals.sh +170 -0
- package/scripts/run-evals.sh +3 -0
- package/scripts/validate.sh +1 -1
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Spec-grammar validator — deterministic, zero-token lint of the structured
|
|
3
|
+
# Requirement/Scenario acceptance grammar (rules/spec-grammar.md) in a spec.md.
|
|
4
|
+
# Turns "are the behavioral requirements well-formed?" into an exit code instead
|
|
5
|
+
# of prose the model walks by hand — the spec-side mirror of check-acceptance.sh
|
|
6
|
+
# (which grades the SAME [ACn] ids against seal.md at the end of the lifecycle).
|
|
7
|
+
#
|
|
8
|
+
# Grammar checked (only when the spec opts into the structured form):
|
|
9
|
+
# ### Requirement: <name> — must carry a SHALL/MUST statement (header or body)
|
|
10
|
+
# — must own >=1 #### Scenario; header names unique
|
|
11
|
+
# #### Scenario: <name> — must carry both a WHEN and a THEN line
|
|
12
|
+
# A spec with ZERO `### Requirement:` headers uses the simple flat-bullet form
|
|
13
|
+
# (- [ ] [AC1] ...) — valid, and this validator no-ops (exit 0). Absence is never
|
|
14
|
+
# a failure, the same discipline as the principles gate. The grammar is opt-in and
|
|
15
|
+
# recommended for behavioral / high-risk requirements (progressive rigor).
|
|
16
|
+
#
|
|
17
|
+
# Usage: spec-validate.sh <workspace-dir | spec.md path>
|
|
18
|
+
# Exit: 0 valid (or no structured requirements — nothing to lint) ·
|
|
19
|
+
# 1 grammar violation(s) · 2 usage · 5 missing spec.md
|
|
20
|
+
#
|
|
21
|
+
# [ACn] compatibility: tag each scenario's checkable line with an [ACn] id so the
|
|
22
|
+
# same criterion is graded at seal by check-acceptance.sh. This validator checks
|
|
23
|
+
# SHAPE, not proof; the two compose, they don't overlap.
|
|
24
|
+
|
|
25
|
+
set -euo pipefail
|
|
26
|
+
|
|
27
|
+
arg="${1:-}"
|
|
28
|
+
if [ -z "$arg" ]; then
|
|
29
|
+
printf 'usage: spec-validate.sh <workspace-dir | spec.md path>\n' >&2
|
|
30
|
+
exit 2
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
if [ -d "$arg" ]; then
|
|
34
|
+
spec="$arg/spec.md"
|
|
35
|
+
elif [ -f "$arg" ]; then
|
|
36
|
+
spec="$arg"
|
|
37
|
+
else
|
|
38
|
+
printf 'spec-validate: no such workspace or file: %s\n' "$arg" >&2
|
|
39
|
+
exit 2
|
|
40
|
+
fi
|
|
41
|
+
[ -f "$spec" ] || { printf 'spec-validate: no spec.md at %s\n' "$spec" >&2; exit 5; }
|
|
42
|
+
|
|
43
|
+
# Parse the structured grammar in one awk pass. Emits ERROR:/WARN: finding lines
|
|
44
|
+
# and a trailing "__SUMMARY__ <requirements> <scenarios>" line. BSD/GNU awk safe:
|
|
45
|
+
# tolower() is POSIX; no IGNORECASE, no gensub. Keyword matches are case-sensitive
|
|
46
|
+
# on purpose — the grammar mandates uppercase SHALL / MUST / WHEN / THEN.
|
|
47
|
+
findings="$(awk -v FILE="$spec" '
|
|
48
|
+
function close_scenario() {
|
|
49
|
+
if (inScenario) {
|
|
50
|
+
if (!scenWhen) { print "ERROR:" FILE ": Requirement \"" curReq "\" > Scenario \"" scenName "\" (line " scenLine ") has no WHEN line"; }
|
|
51
|
+
if (!scenThen) { print "ERROR:" FILE ": Requirement \"" curReq "\" > Scenario \"" scenName "\" (line " scenLine ") has no THEN line"; }
|
|
52
|
+
inScenario = 0
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function close_requirement() {
|
|
56
|
+
close_scenario()
|
|
57
|
+
if (curReq != "") {
|
|
58
|
+
if (!sawShall) { print "ERROR:" FILE ": Requirement \"" curReq "\" (line " reqLine ") has no SHALL/MUST statement"; }
|
|
59
|
+
if (scenInReq == 0) {
|
|
60
|
+
if (looseWhenThen) { print "ERROR:" FILE ": Requirement \"" curReq "\" (line " reqLine ") has WHEN/THEN lines but no \"#### Scenario:\" header — wrap them in a scenario"; }
|
|
61
|
+
else { print "ERROR:" FILE ": Requirement \"" curReq "\" (line " reqLine ") has no \"#### Scenario:\" block"; }
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/^[[:space:]]*###[[:space:]]+[Rr]equirement:/ {
|
|
66
|
+
close_requirement()
|
|
67
|
+
reqCount++
|
|
68
|
+
name = $0
|
|
69
|
+
sub(/^[[:space:]]*###[[:space:]]+[Rr]equirement:[[:space:]]*/, "", name)
|
|
70
|
+
sub(/[[:space:]]+$/, "", name)
|
|
71
|
+
curReq = name; reqLine = NR
|
|
72
|
+
sawShall = ($0 ~ /(^|[^A-Za-z])(SHALL|MUST)([^A-Za-z]|$)/) ? 1 : 0
|
|
73
|
+
scenInReq = 0; looseWhenThen = 0
|
|
74
|
+
key = tolower(name)
|
|
75
|
+
if (key in seen) { print "ERROR:" FILE ": duplicate Requirement header \"" name "\" (lines " seen[key] " and " NR ") — headers must be unique"; }
|
|
76
|
+
else { seen[key] = NR }
|
|
77
|
+
next
|
|
78
|
+
}
|
|
79
|
+
/^[[:space:]]*####[[:space:]]+[Ss]cenario:/ {
|
|
80
|
+
close_scenario()
|
|
81
|
+
if (curReq == "") { print "ERROR:" FILE ": Scenario at line " NR " is not under any \"### Requirement:\""; }
|
|
82
|
+
sName = $0
|
|
83
|
+
sub(/^[[:space:]]*####[[:space:]]+[Ss]cenario:[[:space:]]*/, "", sName)
|
|
84
|
+
sub(/[[:space:]]+$/, "", sName)
|
|
85
|
+
inScenario = 1; scenCount++; scenInReq++
|
|
86
|
+
scenName = sName; scenLine = NR; scenWhen = 0; scenThen = 0
|
|
87
|
+
next
|
|
88
|
+
}
|
|
89
|
+
{
|
|
90
|
+
if (curReq != "") {
|
|
91
|
+
if ($0 ~ /(^|[^A-Za-z])(SHALL|MUST)([^A-Za-z]|$)/) { sawShall = 1 }
|
|
92
|
+
hasWhen = ($0 ~ /(^|[^A-Za-z])WHEN([^A-Za-z]|$)/)
|
|
93
|
+
hasThen = ($0 ~ /(^|[^A-Za-z])THEN([^A-Za-z]|$)/)
|
|
94
|
+
if (inScenario) {
|
|
95
|
+
if (hasWhen) { scenWhen = 1 }
|
|
96
|
+
if (hasThen) { scenThen = 1 }
|
|
97
|
+
} else if (hasWhen || hasThen) {
|
|
98
|
+
looseWhenThen = 1
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
END { close_requirement(); print "__SUMMARY__ " reqCount+0 " " scenCount+0 }
|
|
103
|
+
' "$spec")"
|
|
104
|
+
|
|
105
|
+
summary="$(printf '%s\n' "$findings" | grep '^__SUMMARY__' || true)"
|
|
106
|
+
reqs="$(printf '%s' "$summary" | awk '{print $2+0}')"
|
|
107
|
+
scens="$(printf '%s' "$summary" | awk '{print $3+0}')"
|
|
108
|
+
problems="$(printf '%s\n' "$findings" | grep -E '^(ERROR|WARN):' || true)"
|
|
109
|
+
errs="$(printf '%s\n' "$findings" | grep -c '^ERROR:' || true)"
|
|
110
|
+
|
|
111
|
+
rel="${spec#"$PWD"/}"
|
|
112
|
+
|
|
113
|
+
if [ "$reqs" -eq 0 ]; then
|
|
114
|
+
printf 'spec-validate: %s uses the simple acceptance form (no "### Requirement:" blocks) — nothing to lint\n' "$rel"
|
|
115
|
+
exit 0
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
if [ -n "$problems" ]; then
|
|
119
|
+
printf '%s\n' "$problems" >&2
|
|
120
|
+
fi
|
|
121
|
+
|
|
122
|
+
if [ "$errs" -gt 0 ]; then
|
|
123
|
+
printf 'spec-validate: %s — %d requirement(s) / %d scenario(s); %d grammar error(s) (see rules/spec-grammar.md)\n' \
|
|
124
|
+
"$rel" "$reqs" "$scens" "$errs" >&2
|
|
125
|
+
exit 1
|
|
126
|
+
fi
|
|
127
|
+
|
|
128
|
+
printf 'spec-validate: OK — %s: %d requirement(s) / %d scenario(s) well-formed (SHALL + WHEN/THEN, unique headers)\n' \
|
|
129
|
+
"$rel" "$reqs" "$scens"
|
|
130
|
+
exit 0
|
|
@@ -22,7 +22,8 @@ lifecycle (`/rite-temper` → `/rite-define` → `/rite-build` …) takes over.
|
|
|
22
22
|
|
|
23
23
|
## Rules consulted (read on demand from `.claude/rules/`)
|
|
24
24
|
**Step 0:** Read `.claude/rules/core.md` first. Pull `documentation.md` when recording
|
|
25
|
-
the adoption decisions (why-not-what) in `decisions.md
|
|
25
|
+
the adoption decisions (why-not-what) in `decisions.md`; pull `principles.md` when the code
|
|
26
|
+
upholds invariants worth proposing as project principles (step 4a).
|
|
26
27
|
|
|
27
28
|
## Operating rules (DevRites core)
|
|
28
29
|
- No silent assumptions · prefer the project's existing conventions (you are *documenting*
|
|
@@ -61,6 +62,16 @@ the adoption decisions (why-not-what) in `decisions.md`.
|
|
|
61
62
|
evidence-gated promotion: the seeds start at the base band and are provenance-tagged as
|
|
62
63
|
onboarding observations, not sealed-slice proofs, so real slices later corroborate or
|
|
63
64
|
(fresh-wins) contradict them.
|
|
65
|
+
4a. **Propose candidate principles** (human-ratified; optional). Where the investigation found an
|
|
66
|
+
invariant the code *consistently and deliberately* upholds — money always in integer cents, PII
|
|
67
|
+
always redacted from logs, every v1 endpoint preserved — surface it as a **candidate
|
|
68
|
+
principle**, not a seeded convention. Principles are prescriptive and gating, so they are
|
|
69
|
+
**ratified by the human, never auto-seeded** the way conventions are: present the candidates via
|
|
70
|
+
`AskUserQuestion` with the evidence (where the code upholds it), and write the ones the human
|
|
71
|
+
ratifies to `.devrites/principles.md` with a dated Governance entry
|
|
72
|
+
([`principles.md`](../../rules/principles.md)). Propose, don't impose — an unratified candidate
|
|
73
|
+
stays a convention, not a gate. Skip cleanly when nothing rises to an invariant (common — a
|
|
74
|
+
fresh adopt may declare zero principles, and that's valid).
|
|
64
75
|
5. **Hand off.** The project is now in the lifecycle with a spec and a head-start ledger.
|
|
65
76
|
Point the user at `/rite-temper` (big/risky) or `/rite-define` (straightforward) — do not
|
|
66
77
|
plan or build here.
|
|
@@ -78,6 +89,7 @@ Adopted: <slug>
|
|
|
78
89
|
Baseline: <one-line summary of current behavior> Placement: <where it lives>
|
|
79
90
|
Next objective: <what we'll build on top>
|
|
80
91
|
Conventions seeded: <n> (commands · idioms · placement · gotchas)
|
|
92
|
+
Principles proposed: <n ratified → .devrites/principles.md | none rose to an invariant>
|
|
81
93
|
Next: big / risky? → /rite-temper · straightforward? → /rite-define
|
|
82
94
|
↻ Hygiene: /clear before the next phase (spec.md + decisions.md + the seeded ledger captured). See rules/context-hygiene.md.
|
|
83
95
|
```
|
|
@@ -22,7 +22,9 @@ blocking / escalating gates, and any NO-GO still pause.
|
|
|
22
22
|
- **Safety gates are not bypassable.** AFK never auto-passes destructive migration /
|
|
23
23
|
auth-authz change / public-API break / external-contract change / red tests; blocking
|
|
24
24
|
and escalating gates and any open `gate: validating` always pause. `--ship` auto-confirms
|
|
25
|
-
the **final** type-GO only — nothing else.
|
|
25
|
+
the **final** type-GO only — nothing else. A change that violates a declared project
|
|
26
|
+
principle (`.devrites/principles.md`) with no recorded exception pauses too — autocomplete
|
|
27
|
+
never grants a principle exception on its own (`principles.md`: that's a human decision).
|
|
26
28
|
- **Loop budget = the plan's own slice count, not a fixed number.** After `/rite-vet`
|
|
27
29
|
(not `/rite-define` — vet may split or add slices, so the count isn't final until then),
|
|
28
30
|
set the AFK budget to however many slices the plan has, so the loop builds exactly the
|
|
@@ -24,6 +24,7 @@ writes; read them yourself for the doubt/record gates or in the inline fallback:
|
|
|
24
24
|
- `error-handling.md` — fail fast, no silent catches, fail closed.
|
|
25
25
|
- `testing.md` — pyramid, behaviour over implementation, see-it-fail-first.
|
|
26
26
|
- `patterns.md` — composition over inheritance, avoid premature abstraction.
|
|
27
|
+
- `principles.md` — the project invariants (`.devrites/principles.md`) the slice must honor; the wright reads them as **binding**, not priors.
|
|
27
28
|
- `security.md` — when the slice touches user input, auth, data, or external integrations.
|
|
28
29
|
|
|
29
30
|
## Operating rules
|
|
@@ -40,11 +41,23 @@ writes; read them yourself for the doubt/record gates or in the inline fallback:
|
|
|
40
41
|
The **prose you write yourself** — `evidence.md`, `decisions.md`, the slice report — follows
|
|
41
42
|
the human-voice charter (`.claude/rules/prose-style.md`; depth in `devrites-prose-craft`): no
|
|
42
43
|
filler openers, no marketing adjectives, exact commands and identifiers kept verbatim.
|
|
44
|
+
- **Honor declared project principles.** The wright reads `.devrites/principles.md` and treats
|
|
45
|
+
each invariant as **binding** (not a prior to weigh like a convention) — a slice it cannot build
|
|
46
|
+
without breaking one is an **Escalation**, not a silent violation. On return **you verify no
|
|
47
|
+
principle was broken**; a fresh violation is handled like any irreversible-risk item — a
|
|
48
|
+
human-approved, scoped exception in the register or a stop, never folded into the slice. No
|
|
49
|
+
`.devrites/principles.md` → none declared → nothing to honor.
|
|
43
50
|
- **You never edit source — the wright is the only writer of code + tests.** You write only
|
|
44
51
|
`.devrites/` bookkeeping. On any red gate, doubt finding, or coverage gap your only remedies
|
|
45
52
|
are **continue the same wright once** (it fixes in its own context) or **stop + escalate** —
|
|
46
53
|
never patch the code yourself. The `reconcile.sh` gate (step 6) enforces this by exit code:
|
|
47
54
|
any source file changed outside the wright's claimed set is a hard STOP.
|
|
55
|
+
- **A `Forge: yes` slice competes candidates — one author still lands.** When `/rite-vet`
|
|
56
|
+
flagged the slice a genuine architecture fork, step 3 runs K=2–3 candidate wrights in
|
|
57
|
+
**isolated worktrees** and lands exactly one winner's diff; the single-writer invariant holds
|
|
58
|
+
because no tree ever has two authors and only the winner reaches the working tree. You still
|
|
59
|
+
never edit source, and reconcile runs against the winner's claimed set. The default slice is
|
|
60
|
+
single-path — forge is the rare exception ([`reference/forge.md`](reference/forge.md)).
|
|
48
61
|
|
|
49
62
|
## Workflow ([one-slice-cycle](reference/one-slice-cycle.md))
|
|
50
63
|
0. **Rules + AFK + readiness check.** Read `.claude/rules/core.md` first. Then **run the
|
|
@@ -111,10 +124,25 @@ writes; read them yourself for the doubt/record gates or in the inline fallback:
|
|
|
111
124
|
[ -f "$ST" ] || ST=pack/.claude/skills/devrites-lib/scripts/stuck.sh
|
|
112
125
|
[ -f "$ST" ] && bash "$ST" log "$(cat .devrites/ACTIVE 2>/dev/null)" dispatch "<slice id>" || true
|
|
113
126
|
```
|
|
127
|
+
**Forge branch — only if the selected slice is `Forge: yes`.** Instead of the single dispatch
|
|
128
|
+
below, run the competitive build per [`reference/forge.md`](reference/forge.md): K=2–3 candidate
|
|
129
|
+
wrights, each in an **isolated git worktree** on the distinct strategy `/rite-vet` named, then a
|
|
130
|
+
fresh-context [`devrites-forge-judge`](../../agents/devrites-forge-judge.md) scores them against
|
|
131
|
+
acceptance + `test-plan.md` + `.devrites/principles.md` + the anti-slop charter, and you land
|
|
132
|
+
exactly **one** winner's diff in the working tree, graft any cheap runner-up improvement by
|
|
133
|
+
continuing the winning wright once, and write `forge-report.md`. Forge returns the **same shape**
|
|
134
|
+
a single wright does (one structured artifact, for the winner), so steps 4–7 (doubt, fail-on-red,
|
|
135
|
+
reconcile against the winner's claimed set, record, stop) run **unchanged**. If you cannot give
|
|
136
|
+
the judge an objective scorecard (the slice lacks acceptance / `test-plan.md` coverage) or cannot
|
|
137
|
+
name two genuinely different strategies, the flag is stale — clear it and build single-path. The
|
|
138
|
+
single-writer invariant is intact: each candidate owns its own tree, exactly one author's diff
|
|
139
|
+
lands. Then **stop** here for this slice; the steps below are the default single-path dispatch.
|
|
140
|
+
|
|
114
141
|
Then assemble the slice contract and send it per
|
|
115
142
|
[`reference/wright-dispatch.md`](reference/wright-dispatch.md): the slice goal, acceptance
|
|
116
143
|
criteria, and **scope boundary**; the paths it may touch (`touched-files.md`); the context
|
|
117
|
-
paths to read (`spec.md`, `plan.md`, `decisions.md`, `assumptions.md`,
|
|
144
|
+
paths to read (`spec.md`, `plan.md`, `decisions.md`, `assumptions.md`, `.devrites/principles.md`
|
|
145
|
+
when present — the binding invariants the slice must honor — plus `test-plan.md`
|
|
118
146
|
when present — its per-gap test requirements + regression-criticals for this slice are the
|
|
119
147
|
coverage the wright must write — and `design-brief.md`
|
|
120
148
|
when the slice touches UI per [frontend-trigger](reference/frontend-trigger.md)); and the
|
|
@@ -136,7 +164,21 @@ writes; read them yourself for the doubt/record gates or in the inline fallback:
|
|
|
136
164
|
4. **Doubt the decisions it stood up.** For each entry in the wright's `Decisions stood`
|
|
137
165
|
(branching, boundary crossing, data model, auth, public API, migration, user-flow change,
|
|
138
166
|
"this is safe/scales") apply `devrites-doubt` **before accepting the slice** — the writer
|
|
139
|
-
doesn't grade its own decisions.
|
|
167
|
+
doesn't grade its own decisions. Each `devrites-doubt` invocation **dispatches the
|
|
168
|
+
`devrites-doubt-reviewer` subagent** (doing the adversarial pass inline is the writer grading
|
|
169
|
+
itself — the thing this step exists to forbid). **Completion criterion (checkable):** step 4
|
|
170
|
+
is done only when **every** `Decisions stood` entry carries a recorded `devrites-doubt`
|
|
171
|
+
verdict — `accept`, or `reject` + the required changes — in `decisions.md` (accepted
|
|
172
|
+
trade-offs) / `questions.md` (open gates). A `Decisions stood` entry with **no verdict on
|
|
173
|
+
record** means doubt did not run for it: **do not enter step 5 and do not mark the slice
|
|
174
|
+
`built`.** Log each dispatch so the seal can prove doubt ran (the footprint already counts a
|
|
175
|
+
`doubt` kind):
|
|
176
|
+
```bash
|
|
177
|
+
FP=.claude/skills/devrites-lib/scripts/footprint.sh
|
|
178
|
+
[ -f "$FP" ] || FP="${CLAUDE_SKILL_DIR:-}/../devrites-lib/scripts/footprint.sh"
|
|
179
|
+
[ -f "$FP" ] || FP=pack/.claude/skills/devrites-lib/scripts/footprint.sh
|
|
180
|
+
[ -f "$FP" ] && bash "$FP" log <slug> doubt "<decision id>" || true
|
|
181
|
+
``` The doubt loop honours `.devrites/AFK` (see its AFK
|
|
140
182
|
exception): findings below the slice's gate ceiling become advisory entries in `questions.md`;
|
|
141
183
|
destructive / auth / public-API concerns always pause regardless. A non-empty `Escalation` in
|
|
142
184
|
the artifact is handled here too: irreversible-risk / blockers → blocking question + set
|
|
@@ -146,6 +188,10 @@ writes; read them yourself for the doubt/record gates or in the inline fallback:
|
|
|
146
188
|
blocking protocol violation — pause and re-dispatch with the item flagged out-of-bounds, do
|
|
147
189
|
**not** doubt-and-accept it. (The wright's return is the not-yet-load-bearing moment — the
|
|
148
190
|
slice isn't `built` or merged yet — so this post-return doubt is still pre-commit.)
|
|
191
|
+
**Principle check (same standing):** a wright return that breaks a declared principle
|
|
192
|
+
(reported in its `Principles` field, or that you detect against `.devrites/principles.md`) is
|
|
193
|
+
handled here like an irreversible-risk item — block, route to a human-approved scoped
|
|
194
|
+
exception in the register or stop; never doubt-and-accept a principle violation into the slice.
|
|
149
195
|
5. **Fail-on-red.** If the wright's `Gates` were red (targeted tests / types / lint) or it
|
|
150
196
|
couldn't verify: do **not** mark the slice `built`, and **do not fix the code yourself**.
|
|
151
197
|
First remedy — **continue the same wright once** (`SendMessage` to it, carrying the failing
|
|
@@ -258,4 +304,7 @@ Next ▸ /rite-prove (prove the completed feature)
|
|
|
258
304
|
Keep fact lines terse — one `key value` per fact, `·` between, no prose. The meter, the
|
|
259
305
|
`✅ ALL BUILT` marker, and the ribbon carry the progress; don't restate them in words.
|
|
260
306
|
|
|
307
|
+
For a **forged slice**, the `Built` line names the competition and points at the record, e.g.
|
|
308
|
+
`Built slice 3 — csv-streaming (forged: 3 candidates → winner B; forge-report.md)`.
|
|
309
|
+
|
|
261
310
|
**DO NOT continue to the next slice automatically** — even at `✅ ALL BUILT`, `/rite-prove` is the user's call.
|
|
@@ -15,6 +15,16 @@ generic AI naming, drive-by refactors): see
|
|
|
15
15
|
| "Slices 1 and 2 are related; let me do both." | One slice, then stop. Full stop. The user asks for the next. |
|
|
16
16
|
| "It's faster to skip `devrites-doubt` for this small change." | Doubt is cheapest *before* the decision is standing. After is debugging. |
|
|
17
17
|
|
|
18
|
+
## Forge ([forge.md](forge.md))
|
|
19
|
+
|
|
20
|
+
| Excuse | Rebuttal |
|
|
21
|
+
|---|---|
|
|
22
|
+
| "This slice is hard — I'll forge it." | Hard ≠ forkable. Forge competes ≥2 *genuinely-different* approaches with no clear winner. One hard approach is single-path; building it K times wastes K× for one answer. |
|
|
23
|
+
| "I'm not sure which approach is right, so let me compete them and decide." | Forge is for a real fork the plan couldn't settle, not for dodging a decision you can make now. Decide from the code/docs first; forge only when the alternatives are genuinely undecidable on paper. |
|
|
24
|
+
| "Candidate A's data layer plus B's UI would be the best of both." | Don't hand-merge candidates — two authors in one tree is the incoherence the single-writer rule exists to prevent. Land one winner whole; graft a *specific* runner-up idea only by continuing the winning wright once. |
|
|
25
|
+
| "The judge already scored these, so I can skip the post-return doubt." | The judge picks *between* candidates; it doesn't replace doubting the winner's standing decisions. Steps 4–7 run on the winner unchanged. |
|
|
26
|
+
| "A fourth candidate might be even better." | K is capped at 3. A fourth rarely moves the winner and multiplies cost; if none of three is right, the plan is wrong — `/rite-plan repair`, don't add candidates. |
|
|
27
|
+
|
|
18
28
|
## Red Flags
|
|
19
29
|
|
|
20
30
|
- About to start slice N+1 without the user asking.
|
|
@@ -23,3 +33,5 @@ generic AI naming, drive-by refactors): see
|
|
|
23
33
|
- Writing a `try/catch` block wider than what you actually handle.
|
|
24
34
|
- A comment that restates what the next line does.
|
|
25
35
|
- Touching files that aren't in `touched-files.md` for "tidiness".
|
|
36
|
+
- Forging a slice with no acceptance / `test-plan.md` coverage for the judge to score against.
|
|
37
|
+
- Landing more than one candidate's code, or keeping a losing worktree/branch around after F7.
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# Forge — competing candidate builds for one slice
|
|
2
|
+
|
|
3
|
+
How `/rite-build` builds a slice that `/rite-vet` flagged `Forge: yes`: instead of one wright,
|
|
4
|
+
**K = 2–3 candidate wrights** each build the slice a genuinely different way in **isolation**, a
|
|
5
|
+
read-only judge scores them, and exactly **one** winner's diff lands in the working tree. Loaded
|
|
6
|
+
on demand by `/rite-build` step 3; the sibling of single-path
|
|
7
|
+
[`wright-dispatch.md`](wright-dispatch.md).
|
|
8
|
+
|
|
9
|
+
Forge is the **rare** path. Most slices are single-path (cheaper, and the default). A slice
|
|
10
|
+
forges only when the work is a genuine architecture fork — two or three approaches that actually
|
|
11
|
+
differ, no clear winner on paper, at high enough stakes that building the wrong one costs more
|
|
12
|
+
than building all of them. That judgment is made at `/rite-vet` and recorded as the slice's
|
|
13
|
+
`Forge:` field; build acts on the flag, it does not invent it.
|
|
14
|
+
|
|
15
|
+
## Why this doesn't break the single-writer invariant
|
|
16
|
+
|
|
17
|
+
DevRites forbids a parallel fan-out of writers **sharing one tree** — concurrent writers on one
|
|
18
|
+
working tree make conflicting implicit decisions and produce incoherent code
|
|
19
|
+
([`wright-dispatch.md`](wright-dispatch.md)). Forge keeps that invariant intact by **isolation**:
|
|
20
|
+
every candidate writes in its own worktree (or its own throwaway branch), never touching another
|
|
21
|
+
candidate's tree, and the orchestrator lands exactly one. No tree ever has two authors; exactly
|
|
22
|
+
one author's work ships. "N isolated complete attempts, winner-takes-all" is not "N writers on
|
|
23
|
+
one slice."
|
|
24
|
+
|
|
25
|
+
## Trust the flag, but clear a stale one
|
|
26
|
+
|
|
27
|
+
Before competing anything, confirm the flag still earns its cost — `/rite-vet` set it, but the
|
|
28
|
+
plan may have moved:
|
|
29
|
+
|
|
30
|
+
- **No objective scorecard** — the slice has no acceptance criteria and no `test-plan.md`
|
|
31
|
+
coverage the judge can score against → clear `Forge` to `no`, build single-path. A competition
|
|
32
|
+
with no rubric is a coin toss with K× the cost.
|
|
33
|
+
- **Can't name two genuinely different strategies** — if the candidates would be variations of
|
|
34
|
+
one approach, there is nothing to compete → single-path.
|
|
35
|
+
- **Slice shrank below the bar** (now Complexity ≤3, or a dependency landed that picks the
|
|
36
|
+
approach) → single-path.
|
|
37
|
+
|
|
38
|
+
A cleared flag is recorded in `decisions.md` (one line: why forge was dropped). Never forge a
|
|
39
|
+
slice you can't score, and never forge to avoid making a decision the plan already made.
|
|
40
|
+
|
|
41
|
+
## Mechanics
|
|
42
|
+
|
|
43
|
+
The orchestrator runs F1–F7. Steps 4–7 of the [one-slice-cycle](one-slice-cycle.md) (doubt,
|
|
44
|
+
fail-on-red, reconcile, record, stop) then run **unchanged** on the winner.
|
|
45
|
+
|
|
46
|
+
### F1 — Confirm the K strategies
|
|
47
|
+
Take the 2–3 candidate strategies `/rite-vet` named (in the slice brief). Each must be a
|
|
48
|
+
**distinct, complete approach** to the same slice contract — a different seam, data shape,
|
|
49
|
+
reuse-vs-build call, or algorithm — not a tweak of one. Name them `A`, `B`, (`C`) with a
|
|
50
|
+
one-line description each. K is capped at 3: a fourth candidate rarely changes the winner and
|
|
51
|
+
multiplies cost.
|
|
52
|
+
|
|
53
|
+
### F2 — Snapshot, then isolate each candidate
|
|
54
|
+
Snapshot the working tree first (the winner's landing is reconciled against it later), then give
|
|
55
|
+
each candidate its own isolated tree. **Prefer parallel isolated worktrees** when the harness can
|
|
56
|
+
dispatch a sub-agent with worktree isolation; the **always-available** path is one throwaway git
|
|
57
|
+
branch per candidate, built sequentially (slower, universally works — the
|
|
58
|
+
[`tooling.md`](../../../rules/tooling.md) "fallback is first-class" discipline):
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
SLUG="$(cat .devrites/ACTIVE 2>/dev/null)"
|
|
62
|
+
git rev-parse --is-inside-work-tree >/dev/null 2>&1 || echo "(not a git repo — forge needs git for isolation; degrade to single-path)"
|
|
63
|
+
BASE="$(git rev-parse --abbrev-ref HEAD)"
|
|
64
|
+
# one isolated worktree per candidate (parallel-capable); falls back to branches if worktrees are unavailable
|
|
65
|
+
for C in A B; do
|
|
66
|
+
git worktree add ".devrites/work/$SLUG/forge/cand-$C" -b "forge/$SLUG/cand-$C" 2>/dev/null \
|
|
67
|
+
|| git branch "forge/$SLUG/cand-$C" "$BASE"
|
|
68
|
+
done
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### F3 — Dispatch K candidate wrights
|
|
72
|
+
Send **each** candidate the identical single-path slice contract from
|
|
73
|
+
[`wright-dispatch.md`](wright-dispatch.md), with **one** line added naming its assigned strategy
|
|
74
|
+
and its isolated tree:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
Forge candidate <A|B|C> of <K>. Build this slice using ONLY this approach:
|
|
78
|
+
Strategy: <the distinct approach, one or two sentences — the seam / data shape / reuse call>
|
|
79
|
+
Work in your isolated tree: <worktree path | branch name>. Do not consult or merge another
|
|
80
|
+
candidate's work. Same discipline as always — orient → RED → implement smallest complete →
|
|
81
|
+
verify → return your structured artifact. Code + tests only.
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Each is still **one wright, one tree** — the invariant holds per candidate. Parallel where the
|
|
85
|
+
harness isolates them; otherwise build candidate A to green, capture its diff, reset to `BASE`,
|
|
86
|
+
then candidate B. A candidate that hits an irreversible-risk item escalates exactly as a
|
|
87
|
+
single-path wright does — **forge never bypasses a gate** (see AFK below).
|
|
88
|
+
|
|
89
|
+
### F4 — Judge (read-only, fresh context)
|
|
90
|
+
Dispatch [`devrites-forge-judge`](../../../agents/devrites-forge-judge.md) with the K finished
|
|
91
|
+
candidate diffs and the scorecard inputs (slice acceptance, `test-plan.md`, `.devrites/principles.md`,
|
|
92
|
+
the anti-slop charter). It scores each candidate, ranks them, names the **winner** and the
|
|
93
|
+
specific runner-up ideas worth grafting, and returns the structured verdict. The judge **never
|
|
94
|
+
writes code** — it reads the diffs and returns findings, like every reviewer agent. If sub-agent
|
|
95
|
+
dispatch is unavailable, do the judge's rubric pass yourself in a fresh read, discarding your
|
|
96
|
+
authoring reasoning (a flagged fallback, not an independent judgment).
|
|
97
|
+
|
|
98
|
+
### F5 — Land the winner, graft sparingly
|
|
99
|
+
Apply **only** the winner's diff to the working tree (merge its worktree / cherry-pick its
|
|
100
|
+
branch). If the judge named a cheap, specific improvement in a runner-up, graft it by
|
|
101
|
+
**continuing the winning wright once** with that instruction — never hand-merge two candidates'
|
|
102
|
+
code (that re-creates the incoherent-tree failure the invariant exists to prevent). The landed
|
|
103
|
+
tree has exactly one author: the winner (plus its own grafted follow-up).
|
|
104
|
+
|
|
105
|
+
### F6 — Write `forge-report.md`
|
|
106
|
+
The durable record of the competition (template below). One per forged slice; archived with the
|
|
107
|
+
feature.
|
|
108
|
+
|
|
109
|
+
### F7 — Clean up, then return to the cycle
|
|
110
|
+
Remove the losing worktrees / delete the candidate branches:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
SLUG="$(cat .devrites/ACTIVE 2>/dev/null)"
|
|
114
|
+
for C in A B; do
|
|
115
|
+
git worktree remove ".devrites/work/$SLUG/forge/cand-$C" --force 2>/dev/null || true
|
|
116
|
+
git branch -D "forge/$SLUG/cand-$C" 2>/dev/null || true
|
|
117
|
+
done
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Then hand the **winner's** structured artifact to [one-slice-cycle](one-slice-cycle.md) step 4 as
|
|
121
|
+
if a single wright produced it. Doubt, fail-on-red, reconcile (against the F2 snapshot, claimed =
|
|
122
|
+
the winner's files), record, and stop all run unchanged.
|
|
123
|
+
|
|
124
|
+
## `forge-report.md` template
|
|
125
|
+
|
|
126
|
+
```markdown
|
|
127
|
+
# Forge report: <slice id — name>
|
|
128
|
+
Forged on <iso>. Reason: <the architecture fork /rite-vet flagged>.
|
|
129
|
+
|
|
130
|
+
## Candidates
|
|
131
|
+
| # | Strategy | Gates | Score | Notes |
|
|
132
|
+
|---|---|---|---|---|
|
|
133
|
+
| A | <approach> | green/red | <judge score> | <one line> |
|
|
134
|
+
| B | <approach> | green/red | <judge score> | <one line> |
|
|
135
|
+
|
|
136
|
+
## Verdict
|
|
137
|
+
Winner: <A|B|C> — <why it won, in the judge's terms: acceptance coverage, simplicity, principle
|
|
138
|
+
fit, anti-slop, reuse>.
|
|
139
|
+
Grafted from runner-up: <specific idea + which candidate | none>.
|
|
140
|
+
Discarded: <the losing approaches + the one-line reason each lost — load-bearing for a later
|
|
141
|
+
slice that might be tempted to retry one>.
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
The **Discarded** section matters: it is a dead-end record at the slice level, the same role
|
|
145
|
+
`decisions.md` "Dead ends" plays for the feature — a later slice shouldn't re-litigate an
|
|
146
|
+
approach forge already rejected.
|
|
147
|
+
|
|
148
|
+
## AFK & budget
|
|
149
|
+
|
|
150
|
+
- **Cost.** Forge multiplies the build by K. Under `.devrites/AFK`, each candidate counts against
|
|
151
|
+
the slice budget (`tick-afk.sh` once per candidate dispatched), so a forge slice can exhaust the
|
|
152
|
+
cap faster — that is intended back-pressure, not a bug.
|
|
153
|
+
- **Gates are unchanged.** Forge changes *how many candidates build*, never *what pauses*. An
|
|
154
|
+
irreversible-risk item, a blocking/escalating gate, or a red-on-completion in **any** candidate
|
|
155
|
+
pauses per [`afk-hitl.md`](../../../rules/afk-hitl.md) exactly as single-path. AFK widens what is
|
|
156
|
+
automatic, never what is irreversible — forge included.
|
|
157
|
+
- **Stuck loop still applies.** Re-dispatching the same candidate without progress trips
|
|
158
|
+
`stuck.sh` the same as a single wright.
|
|
159
|
+
|
|
160
|
+
## When isolation is impossible
|
|
161
|
+
|
|
162
|
+
No git, or neither worktrees nor throwaway branches are usable → **degrade to single-path** and
|
|
163
|
+
say so. Forge is an accelerator for choosing between real alternatives; it is never a requirement
|
|
164
|
+
for building the slice. A slice always has a single-path build available — the competition is the
|
|
165
|
+
optional part.
|
|
166
|
+
|
|
167
|
+
## Anti-patterns
|
|
168
|
+
|
|
169
|
+
See [`anti-patterns.md`](anti-patterns.md) § Forge — the short version: don't forge a decided or
|
|
170
|
+
trivial slice, don't forge to dodge a decision, don't hand-merge candidates, don't exceed K=3,
|
|
171
|
+
and don't let a forged slice skip the post-return doubt because "the judge already looked."
|
|
@@ -9,6 +9,8 @@ The orchestrator (`/rite-build`) gates and records; the **wright** writes. See
|
|
|
9
9
|
```
|
|
10
10
|
SELECT → orchestrator: restate slice goal + acceptance + scope boundary; HITL gate (pause pre-code)
|
|
11
11
|
(SHAPE) → orchestrator: if UI and no design-brief.md, shape it (devrites-ux-shape) before dispatch
|
|
12
|
+
(FORGE) → orchestrator: if slice is Forge: yes, compete K=2–3 isolated candidate wrights →
|
|
13
|
+
devrites-forge-judge → land one winner → forge-report.md, then continue at DOUBT (forge.md)
|
|
12
14
|
DISPATCH → hand the slice contract to devrites-slice-wright (fresh context). Inside the wright:
|
|
13
15
|
ORIENT → load only the files this slice touches; learn the project's idiom; reuse-first
|
|
14
16
|
(RED) → if behavior change: write the failing test first
|
|
@@ -16,8 +16,11 @@ The orchestrator's window is full of spec investigation, planning, prior slices,
|
|
|
16
16
|
output — the exact "lost-in-the-middle" load that degrades instruction-following and pulls the
|
|
17
17
|
model toward generic code. The wright starts clean and sees only the contract, so it holds the
|
|
18
18
|
slice boundary strictly and writes to the *project's* idiom instead of drifting. Single-threaded
|
|
19
|
-
by design: **one** wright per slice, never a parallel fan-out of writers
|
|
20
|
-
make conflicting implicit decisions and produce incoherent
|
|
19
|
+
by design: **one** wright per slice, never a parallel fan-out of writers *sharing a tree* —
|
|
20
|
+
concurrent writers on one working tree make conflicting implicit decisions and produce incoherent
|
|
21
|
+
code. The one sanctioned exception is a **forge** slice, which competes K candidates in *isolated*
|
|
22
|
+
worktrees and lands exactly one — no tree ever has two authors, so the invariant holds (see
|
|
23
|
+
[Forge](#forge--competing-candidates-the-deliberate-exception)).
|
|
21
24
|
|
|
22
25
|
## The contract `/rite-build` sends
|
|
23
26
|
One `Task` call to `devrites-slice-wright` carrying everything the writer needs and nothing it
|
|
@@ -91,6 +94,23 @@ set.
|
|
|
91
94
|
[`evidence-standard.md`](evidence-standard.md). Evidence is the wright's real command output,
|
|
92
95
|
not its say-so. Then tick AFK if `.devrites/AFK` is present (`tick-afk.sh`; exit 3 → STOP).
|
|
93
96
|
|
|
97
|
+
## Forge — competing candidates (the deliberate exception)
|
|
98
|
+
|
|
99
|
+
The single-writer rule forbids parallel writers **sharing one tree**. A `Forge: yes` slice
|
|
100
|
+
(flagged by `/rite-vet` as a genuine architecture fork at Complexity ≥4) is the one sanctioned
|
|
101
|
+
fan-out, and it keeps the rule intact by **isolation**: each candidate wright works in its own
|
|
102
|
+
`git worktree`, sees the identical slice contract plus one **distinct strategy**, and never
|
|
103
|
+
touches another candidate's tree. A read-only [`devrites-forge-judge`](../../../agents/devrites-forge-judge.md)
|
|
104
|
+
then scores the finished candidates against acceptance + `test-plan.md` + `.devrites/principles.md`
|
|
105
|
+
+ the anti-slop charter, and the orchestrator lands **exactly one** winner's diff in the working
|
|
106
|
+
tree. No tree ever has two authors; exactly one author's work ships. Everything downstream (doubt,
|
|
107
|
+
fail-on-red, reconcile against the winner's claimed set, record) runs on the winner as if a single
|
|
108
|
+
wright had built it.
|
|
109
|
+
|
|
110
|
+
Full mechanics — strategy derivation, worktree setup, the judge contract, landing + grafting the
|
|
111
|
+
winner, `forge-report.md`, AFK budgeting, and the worktree-unavailable fallback — live in
|
|
112
|
+
[`forge.md`](forge.md).
|
|
113
|
+
|
|
94
114
|
## Fallback
|
|
95
115
|
If the `Task` tool / sub-agent dispatch is unavailable, `/rite-build` runs the wright's
|
|
96
116
|
discipline **inline** in its own context and flags it as a fallback (no clean-context benefit).
|
|
@@ -17,6 +17,7 @@ nothing gets missed in one batch. **No code here.**
|
|
|
17
17
|
as their first step; the other rule files load on demand. Pull these via `Read` when shaping
|
|
18
18
|
the plan:
|
|
19
19
|
- `development-workflow.md` — small batches, trunk-always-green, definition of done.
|
|
20
|
+
- `principles.md` — the project invariants (`.devrites/principles.md`) the chosen approach must conform to.
|
|
20
21
|
- `documentation.md` — record plan-time decisions and rationale.
|
|
21
22
|
|
|
22
23
|
## Operating rules
|
|
@@ -90,6 +91,12 @@ the plan:
|
|
|
90
91
|
```
|
|
91
92
|
5. **Complexity & deviations gate** — justify anything off DevRites defaults (new dep,
|
|
92
93
|
extra abstraction, second design system) in the plan; if you can't justify it, simplify.
|
|
94
|
+
**Principles conformance:** read `.devrites/principles.md` (if present) and confirm the
|
|
95
|
+
approach honors every declared invariant. A plan that conflicts with one is not "a deviation
|
|
96
|
+
to justify away" — either reshape the approach to conform, or, when the conflict is genuine and
|
|
97
|
+
intended, route it through the Spec Drift Guard plus a recorded decision and a scoped principle
|
|
98
|
+
exception a human approves. Never ready a plan that silently violates an invariant. (Re-scored
|
|
99
|
+
as a blocking gate at `/rite-vet`; no file → none declared → nothing to check.)
|
|
93
100
|
6. **Write** `plan.md` + `tasks.md`; update `state.md` (phase: plan → next `/rite-build`).
|
|
94
101
|
7. **Readiness gate** (bottom of plan-template): every acceptance criterion covered by a
|
|
95
102
|
slice, dependency order acyclic + risk-first, no unjustified deviation, rollback for
|
|
@@ -105,6 +112,9 @@ Goal:
|
|
|
105
112
|
Satisfies: AC-n[, AC-m] # reverse traceability — which spec acceptance criteria this slice satisfies
|
|
106
113
|
Acceptance criteria: # which spec FR/criteria this satisfies
|
|
107
114
|
Complexity: N/5 — <reason> # 1=trivial … 5=hairy; >3 triggers a reslice unless the reason justifies it
|
|
115
|
+
Forge: no | yes — <reason> # default no. Propose yes ONLY when Complexity ≥4 AND the slice has ≥2 genuinely-viable
|
|
116
|
+
# approaches with no clear winner (an architecture fork, not just "hard"). /rite-vet confirms
|
|
117
|
+
# or clears it; /rite-build then competes K isolated candidates and keeps one. See rite-build/reference/forge.md.
|
|
108
118
|
Mode: AFK | HITL # AFK = implementable + mergeable without human gating;
|
|
109
119
|
# HITL = needs a human decision mid-slice (design call,
|
|
110
120
|
# architectural choice, destructive migration sign-off).
|
|
@@ -139,7 +149,10 @@ Evidence required:
|
|
|
139
149
|
> coverage. Keep `Blocked by` cycle-free. `depends_on` is the machine-readable mirror tools read
|
|
140
150
|
> to pick the next *buildable* slice; `Complexity` (>3 → reslice) sizes it; `Satisfies` +
|
|
141
151
|
> `Consumes/Produces` + `Known-Gotchas` + `Validation commands` make each slice a self-contained,
|
|
142
|
-
> one-pass-implementable brief (the PRP target `/rite-vet` checks).
|
|
152
|
+
> one-pass-implementable brief (the PRP target `/rite-vet` checks). `Forge` flags the rare slice
|
|
153
|
+
> worth *competing* — a genuine architecture fork at high complexity, not a slice that is merely
|
|
154
|
+
> hard. Define only proposes it; `/rite-vet` confirms or clears it and `/rite-build` acts on it.
|
|
155
|
+
> The bulk of slices stay `no` (single-path is cheaper and the default).
|
|
143
156
|
|
|
144
157
|
> **Mid-flight discipline.** When tempted to skip vertical slicing, coverage mapping, or dependency-order discipline — see [`anti-patterns`](reference/anti-patterns.md) (Common Rationalizations + Red Flags). Load it the moment you reach for the excuse.
|
|
145
158
|
|
|
@@ -77,6 +77,9 @@ map + worked examples: [`reference/failure-modes.md`](reference/failure-modes.md
|
|
|
77
77
|
- [ ] **4 · Unverifiable goal** — is there a command that proves this, run, with output? Or am
|
|
78
78
|
I asserting "it works"? Tautological test that can't fail? → run the FRAME verify command;
|
|
79
79
|
record command + output (`testing.md`, evidence-over-confidence).
|
|
80
|
+
- [ ] **Principle check** — if `.devrites/principles.md` exists, does the change break a declared
|
|
81
|
+
invariant? A violation with no recorded, human-approved exception is a **Critical** — the
|
|
82
|
+
express lane is not a way around a project gate; escalate it, don't ship it (`principles.md`).
|
|
80
83
|
|
|
81
84
|
The test for each changed line: **it traces directly to the criterion, and the criterion can
|
|
82
85
|
be proven false.** A line that fails either is a finding.
|
|
@@ -85,8 +88,10 @@ be proven false.** A line that fails either is a finding.
|
|
|
85
88
|
|
|
86
89
|
If FRAME can't produce a falsifiable criterion, or AUDIT surfaces a mode-1 / mode-3 issue that
|
|
87
90
|
is actually a hidden design decision (new dependency, data model, second design system, an
|
|
88
|
-
auth/migration/public-API touch)
|
|
89
|
-
|
|
91
|
+
auth/migration/public-API touch), or a **declared-principle violation** with no recorded
|
|
92
|
+
exception → **STOP and route to `/rite-spec`** (a needed exception is a human-approved decision,
|
|
93
|
+
not an inline call). Same drift guard the express lane enforces — don't quietly grow an unframed
|
|
94
|
+
ask into unreviewed work.
|
|
90
95
|
|
|
91
96
|
## Rules
|
|
92
97
|
- Self-applied and inline. No subagent, no `.devrites/` workspace required. For an adversarial
|