devrites 3.2.5 → 3.2.7
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 +13 -0
- package/README.md +1 -1
- package/docs/cli.md +0 -1
- package/docs/command-map.md +1 -1
- package/docs/orchestration.md +1 -2
- package/engine/commands.go +1 -1
- package/engine/hooks_agent_dispatch.go +98 -33
- package/engine/internal/lib/reconcile.go +1 -1
- package/engine/internal/lib/reconcile_test.go +4 -12
- package/engine/internal/lib/util.go +2 -2
- package/engine/main.go +0 -3
- package/engine/root_routing_test.go +0 -1
- package/engine/tests/hook_test.go +235 -0
- package/pack/.claude/skills/rite-build/reference/forge.md +2 -2
- package/pack/.claude/skills/rite-build/reference/phase-contract.md +11 -20
- package/pack/.claude/skills/rite-build/reference/wright-dispatch.md +2 -5
- package/pack/.claude/skills/rite-prove/reference/acceptance-proof.md +0 -1
- package/pack/.claude/skills/rite-seal/reference/final-evidence.md +0 -1
- package/pack/generated/claude/skills/rite-build/reference/forge.md +2 -2
- package/pack/generated/claude/skills/rite-build/reference/phase-contract.md +11 -20
- package/pack/generated/claude/skills/rite-build/reference/wright-dispatch.md +2 -5
- package/pack/generated/claude/skills/rite-prove/reference/acceptance-proof.md +0 -1
- package/pack/generated/claude/skills/rite-seal/reference/final-evidence.md +0 -1
- package/pack/generated/codex/skills/rite-build/reference/forge.md +2 -2
- package/pack/generated/codex/skills/rite-build/reference/phase-contract.md +11 -20
- package/pack/generated/codex/skills/rite-build/reference/wright-dispatch.md +2 -5
- package/pack/generated/codex/skills/rite-prove/reference/acceptance-proof.md +0 -1
- package/pack/generated/codex/skills/rite-seal/reference/final-evidence.md +0 -1
- package/package.json +1 -1
- package/scripts/build-release-tarball.sh +1 -0
- package/scripts/validate.sh +0 -1
- package/engine/internal/lib/packageexistence.go +0 -968
- package/engine/internal/lib/packageexistence_test.go +0 -506
- package/engine/testdata/golden/TestParityPackageExistence/declared.golden +0 -2
- package/engine/testdata/golden/TestParityPackageExistence/default-import-subpath.golden +0 -2
- package/engine/tests/parity_packageexistence_test.go +0 -64
|
@@ -899,6 +899,18 @@ func writeCodexSkillContract(t *testing.T, root, skill, roles string) {
|
|
|
899
899
|
}
|
|
900
900
|
}
|
|
901
901
|
|
|
902
|
+
func writeCodexConditionalSkillContract(t *testing.T, root, skill, role string) {
|
|
903
|
+
t.Helper()
|
|
904
|
+
dir := filepath.Join(filepath.Dir(root), ".agents", "skills", skill)
|
|
905
|
+
if err := os.MkdirAll(dir, 0o755); err != nil {
|
|
906
|
+
t.Fatal(err)
|
|
907
|
+
}
|
|
908
|
+
contract := "---\nname: " + skill + "\ndescription: Test skill.\nrequired-agent-roles: none\n---\n\nConditionally dispatch `" + role + "` when needed.\n"
|
|
909
|
+
if err := os.WriteFile(filepath.Join(dir, "SKILL.md"), []byte(contract), 0o600); err != nil {
|
|
910
|
+
t.Fatal(err)
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
|
|
902
914
|
func writeCodexV2Rollouts(
|
|
903
915
|
t *testing.T,
|
|
904
916
|
codeHome, projectRoot, sessionID, turnID, role, taskName string,
|
|
@@ -1096,6 +1108,156 @@ func TestCodexAgentDispatchArmsInstalledSkillRequirements(t *testing.T) {
|
|
|
1096
1108
|
}
|
|
1097
1109
|
}
|
|
1098
1110
|
|
|
1111
|
+
func TestCodexAgentDispatchPromptGivesExactNamedCallBeforeCompletion(t *testing.T) {
|
|
1112
|
+
root := newWorkspace(t)
|
|
1113
|
+
role := "devrites-plan-drafter"
|
|
1114
|
+
writeCodexAgentContract(t, root, role)
|
|
1115
|
+
writeCodexSkillContract(t, root, "rite-plan", role)
|
|
1116
|
+
|
|
1117
|
+
out, stderr, code := runDevritesIO(t, root, hookPayload(t, map[string]any{
|
|
1118
|
+
"hook_event_name": "UserPromptSubmit",
|
|
1119
|
+
"session_id": "session-plan-drafter-guidance",
|
|
1120
|
+
"turn_id": "turn-plan-drafter-guidance",
|
|
1121
|
+
"prompt": "$rite-plan repair",
|
|
1122
|
+
}), nil, "hook", "agent-dispatch", "--harness=codex")
|
|
1123
|
+
if code != 0 {
|
|
1124
|
+
t.Fatalf("arm exit=%d stderr=%s", code, stderr)
|
|
1125
|
+
}
|
|
1126
|
+
for _, want := range []string{
|
|
1127
|
+
"MANDATORY DISPATCH THIS TURN",
|
|
1128
|
+
"spawn_agent",
|
|
1129
|
+
"agent_type=" + role,
|
|
1130
|
+
"unique task_name",
|
|
1131
|
+
`fork_turns="none"`,
|
|
1132
|
+
".codex/agents/" + role + ".toml",
|
|
1133
|
+
"send agent_type anyway",
|
|
1134
|
+
"Wait for the returned child",
|
|
1135
|
+
} {
|
|
1136
|
+
if !strings.Contains(out, want) {
|
|
1137
|
+
t.Fatalf("initial dispatch guidance omitted %q:\n%s", want, out)
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
func TestCodexConditionalAgentDispatchRejectsDefaultAndArmsNamedRole(t *testing.T) {
|
|
1143
|
+
root := newWorkspace(t)
|
|
1144
|
+
role := "devrites-proof-runner"
|
|
1145
|
+
writeCodexAgentContract(t, root, role)
|
|
1146
|
+
writeCodexConditionalSkillContract(t, root, "rite-polish", role)
|
|
1147
|
+
sessionID, turnID := "session-conditional-role", "turn-conditional-role"
|
|
1148
|
+
|
|
1149
|
+
out, stderr, code := runDevritesIO(t, root, hookPayload(t, map[string]any{
|
|
1150
|
+
"hook_event_name": "UserPromptSubmit",
|
|
1151
|
+
"session_id": sessionID,
|
|
1152
|
+
"turn_id": turnID,
|
|
1153
|
+
"prompt": "$rite-polish",
|
|
1154
|
+
}), nil, "hook", "agent-dispatch", "--harness=codex")
|
|
1155
|
+
if code != 0 {
|
|
1156
|
+
t.Fatalf("arm exit=%d stderr=%s", code, stderr)
|
|
1157
|
+
}
|
|
1158
|
+
for _, want := range []string{
|
|
1159
|
+
"CONDITIONAL DISPATCH RULE",
|
|
1160
|
+
"exact named agent_type=devrites-<role>",
|
|
1161
|
+
`fork_turns="none"`,
|
|
1162
|
+
"send agent_type anyway",
|
|
1163
|
+
"never use a default child",
|
|
1164
|
+
} {
|
|
1165
|
+
if !strings.Contains(out, want) {
|
|
1166
|
+
t.Fatalf("conditional dispatch guidance omitted %q:\n%s", want, out)
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
for _, agentType := range []string{"", "default"} {
|
|
1171
|
+
out, stderr, code = runDevritesIO(t, root, hookPayload(t, map[string]any{
|
|
1172
|
+
"hook_event_name": "PreToolUse",
|
|
1173
|
+
"session_id": sessionID,
|
|
1174
|
+
"turn_id": turnID,
|
|
1175
|
+
"tool_name": "spawn_agent",
|
|
1176
|
+
"tool_use_id": "default-" + agentType,
|
|
1177
|
+
"tool_input": map[string]any{
|
|
1178
|
+
"agent_type": agentType,
|
|
1179
|
+
"task_name": "conditional_default",
|
|
1180
|
+
"fork_turns": "none",
|
|
1181
|
+
"message": "Run the conditional DevRites check.",
|
|
1182
|
+
},
|
|
1183
|
+
}), nil, "hook", "agent-dispatch", "--harness=codex")
|
|
1184
|
+
if code != 0 {
|
|
1185
|
+
t.Fatalf("default spawn exit=%d stderr=%s", code, stderr)
|
|
1186
|
+
}
|
|
1187
|
+
if decision, reason := parsePermissionDecision(t, out); decision != "deny" ||
|
|
1188
|
+
!strings.Contains(reason, "exact named agent_type=devrites-<role>") {
|
|
1189
|
+
t.Fatalf("conditional default child not denied: decision=%q reason=%q out=%s", decision, reason, out)
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
out, stderr, code = runDevritesIO(t, root, hookPayload(t, map[string]any{
|
|
1194
|
+
"hook_event_name": "PreToolUse",
|
|
1195
|
+
"session_id": sessionID,
|
|
1196
|
+
"turn_id": turnID,
|
|
1197
|
+
"tool_name": "spawn_agent",
|
|
1198
|
+
"tool_use_id": "missing-named-type",
|
|
1199
|
+
"tool_input": map[string]any{
|
|
1200
|
+
"task_name": "conditional_missing_type",
|
|
1201
|
+
"fork_turns": "none",
|
|
1202
|
+
"message": "Read .codex/agents/" + role + ".toml and run the check.",
|
|
1203
|
+
},
|
|
1204
|
+
}), nil, "hook", "agent-dispatch", "--harness=codex")
|
|
1205
|
+
if code != 0 {
|
|
1206
|
+
t.Fatalf("missing type spawn exit=%d stderr=%s", code, stderr)
|
|
1207
|
+
}
|
|
1208
|
+
if decision, reason := parsePermissionDecision(t, out); decision != "deny" ||
|
|
1209
|
+
!strings.Contains(reason, "agent_type="+role) ||
|
|
1210
|
+
!strings.Contains(reason, "send agent_type anyway") {
|
|
1211
|
+
t.Fatalf("missing named type did not get exact retry: decision=%q reason=%q out=%s", decision, reason, out)
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
out, stderr, code = runDevritesIO(t, root, hookPayload(t, map[string]any{
|
|
1215
|
+
"hook_event_name": "PreToolUse",
|
|
1216
|
+
"session_id": sessionID,
|
|
1217
|
+
"turn_id": turnID,
|
|
1218
|
+
"tool_name": "spawn_agent",
|
|
1219
|
+
"tool_use_id": "named-conditional",
|
|
1220
|
+
"tool_input": map[string]any{
|
|
1221
|
+
"agent_type": role,
|
|
1222
|
+
"task_name": "conditional_proof",
|
|
1223
|
+
"fork_turns": "none",
|
|
1224
|
+
"message": "Run the conditional DevRites check.",
|
|
1225
|
+
},
|
|
1226
|
+
}), nil, "hook", "agent-dispatch", "--harness=codex")
|
|
1227
|
+
if code != 0 || strings.TrimSpace(out) != "" {
|
|
1228
|
+
t.Fatalf("named conditional spawn rejected: exit=%d out=%s stderr=%s", code, out, stderr)
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
out, stderr, code = runDevritesIO(t, root, hookPayload(t, map[string]any{
|
|
1232
|
+
"hook_event_name": "Stop",
|
|
1233
|
+
"session_id": sessionID,
|
|
1234
|
+
"turn_id": turnID,
|
|
1235
|
+
}), nil, "hook", "agent-dispatch", "--harness=codex")
|
|
1236
|
+
if code != 0 || !strings.Contains(out, "DevRites dispatch for "+role+" is not complete") {
|
|
1237
|
+
t.Fatalf("named conditional spawn was not armed: exit=%d out=%s stderr=%s", code, out, stderr)
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
func TestCodexAgentDispatchAllowsDefaultChildOutsideSkillTurn(t *testing.T) {
|
|
1242
|
+
root := newWorkspace(t)
|
|
1243
|
+
out, stderr, code := runDevritesIO(t, root, hookPayload(t, map[string]any{
|
|
1244
|
+
"hook_event_name": "PreToolUse",
|
|
1245
|
+
"session_id": "session-unrelated-default",
|
|
1246
|
+
"turn_id": "turn-unrelated-default",
|
|
1247
|
+
"tool_name": "spawn_agent",
|
|
1248
|
+
"tool_use_id": "unrelated-default",
|
|
1249
|
+
"tool_input": map[string]any{
|
|
1250
|
+
"agent_type": "default",
|
|
1251
|
+
"task_name": "unrelated",
|
|
1252
|
+
"fork_turns": "all",
|
|
1253
|
+
"message": "Handle an unrelated bounded task.",
|
|
1254
|
+
},
|
|
1255
|
+
}), nil, "hook", "agent-dispatch", "--harness=codex")
|
|
1256
|
+
if code != 0 || strings.TrimSpace(out) != "" {
|
|
1257
|
+
t.Fatalf("unrelated default child was rejected: exit=%d out=%s stderr=%s", code, out, stderr)
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1099
1261
|
func TestCodexAgentDispatchRejectsInvalidInstalledSkillRequirements(t *testing.T) {
|
|
1100
1262
|
root := newWorkspace(t)
|
|
1101
1263
|
writeCodexSkillContract(t, root, "rite-vet", "root-inline-reviewer")
|
|
@@ -1406,6 +1568,79 @@ func TestCodexAgentDispatchConfirmsDurableV2NamedRole(t *testing.T) {
|
|
|
1406
1568
|
}
|
|
1407
1569
|
}
|
|
1408
1570
|
|
|
1571
|
+
func TestCodexAgentDispatchConfirmsConditionalDurableV2NamedRole(t *testing.T) {
|
|
1572
|
+
root := newWorkspace(t)
|
|
1573
|
+
codeHome := t.TempDir()
|
|
1574
|
+
sessionID, turnID := "session-v2-conditional", "turn-v2-conditional"
|
|
1575
|
+
role := "devrites-security-auditor"
|
|
1576
|
+
writeCodexAgentContract(t, root, role)
|
|
1577
|
+
writeCodexConditionalSkillContract(t, root, "devrites-audit", role)
|
|
1578
|
+
|
|
1579
|
+
runDevritesIO(t, root, hookPayload(t, map[string]any{
|
|
1580
|
+
"hook_event_name": "UserPromptSubmit",
|
|
1581
|
+
"session_id": sessionID,
|
|
1582
|
+
"turn_id": turnID,
|
|
1583
|
+
"prompt": "$devrites-audit security",
|
|
1584
|
+
}), nil, "hook", "agent-dispatch", "--harness=codex")
|
|
1585
|
+
|
|
1586
|
+
writeCodexV2Rollouts(
|
|
1587
|
+
t, codeHome, filepath.Dir(root), sessionID, turnID, role,
|
|
1588
|
+
"devrites_security_auditor_conditional", true, true, true,
|
|
1589
|
+
)
|
|
1590
|
+
stop := hookPayload(t, map[string]any{
|
|
1591
|
+
"hook_event_name": "Stop",
|
|
1592
|
+
"session_id": sessionID,
|
|
1593
|
+
"turn_id": turnID,
|
|
1594
|
+
})
|
|
1595
|
+
if out, stderr, code := runDevritesIO(t, root, stop,
|
|
1596
|
+
[]string{"CODEX_HOME=" + codeHome},
|
|
1597
|
+
"hook", "agent-dispatch", "--harness=codex"); code != 0 || strings.TrimSpace(out) != "" {
|
|
1598
|
+
t.Fatalf("conditional durable v2 stop exit=%d out=%s stderr=%s", code, out, stderr)
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
func TestCodexAgentDispatchRejectsConditionalDurableV2DefaultChild(t *testing.T) {
|
|
1603
|
+
root := newWorkspace(t)
|
|
1604
|
+
codeHome := t.TempDir()
|
|
1605
|
+
sessionID, turnID := "session-v2-default", "turn-v2-default"
|
|
1606
|
+
writeCodexConditionalSkillContract(t, root, "devrites-audit", "devrites-security-auditor")
|
|
1607
|
+
|
|
1608
|
+
runDevritesIO(t, root, hookPayload(t, map[string]any{
|
|
1609
|
+
"hook_event_name": "UserPromptSubmit",
|
|
1610
|
+
"session_id": sessionID,
|
|
1611
|
+
"turn_id": turnID,
|
|
1612
|
+
"prompt": "$devrites-audit security",
|
|
1613
|
+
}), nil, "hook", "agent-dispatch", "--harness=codex")
|
|
1614
|
+
|
|
1615
|
+
writeCodexV2Rollouts(
|
|
1616
|
+
t, codeHome, filepath.Dir(root), sessionID, turnID, "default",
|
|
1617
|
+
"default_conditional_child", true, true, true,
|
|
1618
|
+
)
|
|
1619
|
+
stop := hookPayload(t, map[string]any{
|
|
1620
|
+
"hook_event_name": "Stop",
|
|
1621
|
+
"session_id": sessionID,
|
|
1622
|
+
"turn_id": turnID,
|
|
1623
|
+
})
|
|
1624
|
+
out, stderr, code := runDevritesIO(t, root, stop,
|
|
1625
|
+
[]string{"CODEX_HOME=" + codeHome},
|
|
1626
|
+
"hook", "agent-dispatch", "--harness=codex")
|
|
1627
|
+
if code != 0 {
|
|
1628
|
+
t.Fatalf("conditional default stop exit=%d stderr=%s", code, stderr)
|
|
1629
|
+
}
|
|
1630
|
+
var decision struct {
|
|
1631
|
+
Decision string `json:"decision"`
|
|
1632
|
+
Reason string `json:"reason"`
|
|
1633
|
+
}
|
|
1634
|
+
if err := json.Unmarshal([]byte(strings.TrimSpace(out)), &decision); err != nil {
|
|
1635
|
+
t.Fatalf("invalid conditional default response: %v\n%s", err, out)
|
|
1636
|
+
}
|
|
1637
|
+
if decision.Decision != "block" ||
|
|
1638
|
+
!strings.Contains(decision.Reason, "default or non-DevRites child") ||
|
|
1639
|
+
!strings.Contains(decision.Reason, "never use a default child") {
|
|
1640
|
+
t.Fatalf("conditional V2 default child passed: %#v", decision)
|
|
1641
|
+
}
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1409
1644
|
func TestCodexAgentDispatchRejectsIncompleteDurableV2(t *testing.T) {
|
|
1410
1645
|
for _, tc := range []struct {
|
|
1411
1646
|
name string
|
|
@@ -166,8 +166,8 @@ decision.
|
|
|
166
166
|
|
|
167
167
|
Hand the winner's structured artifact to the normal cycle. Run immediate
|
|
168
168
|
reconciliation, doubt every stood decision, and complete test-integrity,
|
|
169
|
-
|
|
170
|
-
|
|
169
|
+
targeted, browser, and other slice proof. Only after every required gate is
|
|
170
|
+
green:
|
|
171
171
|
|
|
172
172
|
```bash
|
|
173
173
|
devrites-engine forge record "$RUN_ID" verification verified \
|
|
@@ -73,14 +73,13 @@ See also [`one-slice-cycle.md`](one-slice-cycle.md).
|
|
|
73
73
|
(reported in its `Principles` field, or that you detect against `.devrites/principles.md`) is
|
|
74
74
|
handled here like an irreversible-risk item: block, route to a human-approved scoped
|
|
75
75
|
exception in the register or stop; never doubt-and-accept a principle violation into the slice.
|
|
76
|
-
5. **Run retained-baseline integrity
|
|
76
|
+
5. **Run the retained-baseline integrity gate, then recover any objective red.**
|
|
77
77
|
```bash
|
|
78
78
|
devrites-engine test-integrity; echo "test-integrity rc=$?"
|
|
79
|
-
devrites-engine package-existence; echo "package-existence rc=$?"
|
|
80
79
|
```
|
|
81
|
-
If the wright's `Gates` were red (targeted tests / types / lint),
|
|
82
|
-
failed, or
|
|
83
|
-
|
|
80
|
+
If the wright's `Gates` were red (targeted tests / types / lint), `test-integrity`
|
|
81
|
+
failed, or proof could not be verified: do **not** mark the slice `built`, and **do not
|
|
82
|
+
fix the code yourself**.
|
|
84
83
|
Classify each causal fingerprint through
|
|
85
84
|
[`cleanup-and-classify.md`](../../devrites-debug-recovery/reference/cleanup-and-classify.md),
|
|
86
85
|
run `devrites-engine recovery route <class>`, and follow the `recovery-route/v1`
|
|
@@ -95,9 +94,9 @@ See also [`one-slice-cycle.md`](one-slice-cycle.md).
|
|
|
95
94
|
`recovery clear --class <class> "<root cause>" <slug>` only after green. Before every
|
|
96
95
|
re-dispatch, update the root-owned allowlist only for an accepted in-slice path and run
|
|
97
96
|
`reconcile snapshot`: after a clean check this refreshes canonical-state scope while
|
|
98
|
-
retaining the original source baseline. Repeat reconcile and
|
|
99
|
-
return. This owns red
|
|
100
|
-
|
|
97
|
+
retaining the original source baseline. Repeat reconcile and the integrity gate on every
|
|
98
|
+
return. This owns red gates, missing coverage, browser/runtime failures, and
|
|
99
|
+
workflow-tool defects.
|
|
101
100
|
After recovery:
|
|
102
101
|
- green → continue to record;
|
|
103
102
|
- product-contract/acceptance ambiguity or irreversible risk → open the genuine human gate
|
|
@@ -106,22 +105,14 @@ See also [`one-slice-cycle.md`](one-slice-cycle.md).
|
|
|
106
105
|
- exhausted objective failure → preserve reproduction/dead ends, set `Status: blocked` and
|
|
107
106
|
`Next step: /rite-plan unblock`, then STOP without a question or `/rite-resolve`.
|
|
108
107
|
6. **Close the retained baseline, then record. You are the canonical writer.**
|
|
109
|
-
Reconciliation ran immediately on return and
|
|
108
|
+
Reconciliation ran immediately on return and `test-integrity` ran in step 5.
|
|
110
109
|
**Exit 3 → hard STOP:** a test was deleted, skipped, or de-asserted since the slice base: the
|
|
111
110
|
slice went green by weakening its tests, a Critical protocol violation. Revert the weakening and
|
|
112
111
|
re-dispatch the wright; do **not** mark the slice `built`.
|
|
113
112
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
`requirements.txt`, `pyproject.toml`, `Pipfile`, `Cargo.toml`): the classic shape of a
|
|
118
|
-
hallucinated or typo-squatted dependency. Confirm the name on the registry and declare it via the
|
|
119
|
-
package manager, or remove the import; do **not** mark the slice `built`. The gate is deterministic
|
|
120
|
-
and fail-open (not a git repo / no manifest / stdlib-only import → rc 0). If the nearest
|
|
121
|
-
manifest declares the package, treat the mismatch as a workflow-tool defect under bounded
|
|
122
|
-
recovery, not a plan repair or retry-authorization question. Once every gate and doubt
|
|
123
|
-
verdict is accepted, a forged slice records successful verification and runs
|
|
124
|
-
manifest-only cleanup per [`forge.md`](forge.md). Then close the private window:
|
|
113
|
+
Once every gate and doubt verdict is accepted, a forged slice records successful
|
|
114
|
+
verification and runs manifest-only cleanup per [`forge.md`](forge.md). Then close the
|
|
115
|
+
private window:
|
|
125
116
|
```bash
|
|
126
117
|
devrites-engine reconcile close
|
|
127
118
|
```
|
|
@@ -66,15 +66,12 @@ and exact changed-file set. Before the root writes any canonical record, run:
|
|
|
66
66
|
```bash
|
|
67
67
|
devrites-engine reconcile check; echo "reconcile rc=$?"
|
|
68
68
|
devrites-engine test-integrity; echo "test-integrity rc=$?"
|
|
69
|
-
devrites-engine package-existence; echo "package-existence rc=$?"
|
|
70
69
|
```
|
|
71
70
|
|
|
72
71
|
- Reconcile `5`: reject the result. Preserve pre-snapshot user work; restore only the
|
|
73
72
|
unauthorized slice delta; never widen scope from the writer's self-report.
|
|
74
73
|
- Test integrity `3`: a test was deleted, muted, focused, or de-asserted. Treat it as a
|
|
75
74
|
Critical protocol failure and correct it through the wright.
|
|
76
|
-
- Package existence `3`: verify the exact package/version and fix the bounded workflow
|
|
77
|
-
or dependency defect through recovery. It is not a reason to ask for retry approval.
|
|
78
75
|
- A setup/corrupt-baseline error blocks acceptance; never fall back silently to `HEAD`.
|
|
79
76
|
|
|
80
77
|
The clean reconcile check records that source has not changed since inspection. The
|
|
@@ -105,13 +102,13 @@ Before every retry:
|
|
|
105
102
|
|
|
106
103
|
That refresh requires the prior clean check, re-fingerprints root-owned state, and keeps
|
|
107
104
|
the original source baseline. Re-dispatch with the exact output, attempt count, and dead
|
|
108
|
-
ends. Then repeat reconcile and
|
|
105
|
+
ends. Then repeat reconcile and `test-integrity` from zero. Clear recovery only after
|
|
109
106
|
green with `recovery clear --class <class> "<root cause>" <slug>`. An exhausted objective
|
|
110
107
|
failure becomes a technical blocker with its reproduction, not a `rite-resolve` question.
|
|
111
108
|
|
|
112
109
|
## Close and record
|
|
113
110
|
|
|
114
|
-
When reconciliation, integrity,
|
|
111
|
+
When reconciliation, integrity, proof, and doubt gates all pass:
|
|
115
112
|
|
|
116
113
|
```bash
|
|
117
114
|
devrites-engine reconcile close
|
|
@@ -53,7 +53,6 @@ gates:
|
|
|
53
53
|
```bash
|
|
54
54
|
devrites-engine test-integrity; echo "test-integrity rc=$?" # exit 3 = a test deleted/skipped/loosened → Critical NO-GO
|
|
55
55
|
devrites-engine mutation-gate # changed-files mutation score — band the verdict; survivors are unproven behaviours
|
|
56
|
-
devrites-engine package-existence; echo "package-existence rc=$?" # exit 3 = a new import isn't declared in any manifest (hallucinated/typo-squatted dep) → Critical NO-GO
|
|
57
56
|
```
|
|
58
57
|
A test weakened since the slice base is a **Critical NO-GO**: the suite went green by lowering the
|
|
59
58
|
bar, not by the code being right. Record the mutation score in `seal.md`; under
|
|
@@ -166,8 +166,8 @@ decision.
|
|
|
166
166
|
|
|
167
167
|
Hand the winner's structured artifact to the normal cycle. Run immediate
|
|
168
168
|
reconciliation, doubt every stood decision, and complete test-integrity,
|
|
169
|
-
|
|
170
|
-
|
|
169
|
+
targeted, browser, and other slice proof. Only after every required gate is
|
|
170
|
+
green:
|
|
171
171
|
|
|
172
172
|
```bash
|
|
173
173
|
devrites-engine forge record "$RUN_ID" verification verified \
|
|
@@ -73,14 +73,13 @@ See also [`one-slice-cycle.md`](one-slice-cycle.md).
|
|
|
73
73
|
(reported in its `Principles` field, or that you detect against `.devrites/principles.md`) is
|
|
74
74
|
handled here like an irreversible-risk item: block, route to a human-approved scoped
|
|
75
75
|
exception in the register or stop; never doubt-and-accept a principle violation into the slice.
|
|
76
|
-
5. **Run retained-baseline integrity
|
|
76
|
+
5. **Run the retained-baseline integrity gate, then recover any objective red.**
|
|
77
77
|
```bash
|
|
78
78
|
devrites-engine test-integrity; echo "test-integrity rc=$?"
|
|
79
|
-
devrites-engine package-existence; echo "package-existence rc=$?"
|
|
80
79
|
```
|
|
81
|
-
If the wright's `Gates` were red (targeted tests / types / lint),
|
|
82
|
-
failed, or
|
|
83
|
-
|
|
80
|
+
If the wright's `Gates` were red (targeted tests / types / lint), `test-integrity`
|
|
81
|
+
failed, or proof could not be verified: do **not** mark the slice `built`, and **do not
|
|
82
|
+
fix the code yourself**.
|
|
84
83
|
Classify each causal fingerprint through
|
|
85
84
|
[`cleanup-and-classify.md`](../../devrites-debug-recovery/reference/cleanup-and-classify.md),
|
|
86
85
|
run `devrites-engine recovery route <class>`, and follow the `recovery-route/v1`
|
|
@@ -95,9 +94,9 @@ See also [`one-slice-cycle.md`](one-slice-cycle.md).
|
|
|
95
94
|
`recovery clear --class <class> "<root cause>" <slug>` only after green. Before every
|
|
96
95
|
re-dispatch, update the root-owned allowlist only for an accepted in-slice path and run
|
|
97
96
|
`reconcile snapshot`: after a clean check this refreshes canonical-state scope while
|
|
98
|
-
retaining the original source baseline. Repeat reconcile and
|
|
99
|
-
return. This owns red
|
|
100
|
-
|
|
97
|
+
retaining the original source baseline. Repeat reconcile and the integrity gate on every
|
|
98
|
+
return. This owns red gates, missing coverage, browser/runtime failures, and
|
|
99
|
+
workflow-tool defects.
|
|
101
100
|
After recovery:
|
|
102
101
|
- green → continue to record;
|
|
103
102
|
- product-contract/acceptance ambiguity or irreversible risk → open the genuine human gate
|
|
@@ -106,22 +105,14 @@ See also [`one-slice-cycle.md`](one-slice-cycle.md).
|
|
|
106
105
|
- exhausted objective failure → preserve reproduction/dead ends, set `Status: blocked` and
|
|
107
106
|
`Next step: /rite-plan unblock`, then STOP without a question or `/rite-resolve`.
|
|
108
107
|
6. **Close the retained baseline, then record. You are the canonical writer.**
|
|
109
|
-
Reconciliation ran immediately on return and
|
|
108
|
+
Reconciliation ran immediately on return and `test-integrity` ran in step 5.
|
|
110
109
|
**Exit 3 → hard STOP:** a test was deleted, skipped, or de-asserted since the slice base: the
|
|
111
110
|
slice went green by weakening its tests, a Critical protocol violation. Revert the weakening and
|
|
112
111
|
re-dispatch the wright; do **not** mark the slice `built`.
|
|
113
112
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
`requirements.txt`, `pyproject.toml`, `Pipfile`, `Cargo.toml`): the classic shape of a
|
|
118
|
-
hallucinated or typo-squatted dependency. Confirm the name on the registry and declare it via the
|
|
119
|
-
package manager, or remove the import; do **not** mark the slice `built`. The gate is deterministic
|
|
120
|
-
and fail-open (not a git repo / no manifest / stdlib-only import → rc 0). If the nearest
|
|
121
|
-
manifest declares the package, treat the mismatch as a workflow-tool defect under bounded
|
|
122
|
-
recovery, not a plan repair or retry-authorization question. Once every gate and doubt
|
|
123
|
-
verdict is accepted, a forged slice records successful verification and runs
|
|
124
|
-
manifest-only cleanup per [`forge.md`](forge.md). Then close the private window:
|
|
113
|
+
Once every gate and doubt verdict is accepted, a forged slice records successful
|
|
114
|
+
verification and runs manifest-only cleanup per [`forge.md`](forge.md). Then close the
|
|
115
|
+
private window:
|
|
125
116
|
```bash
|
|
126
117
|
devrites-engine reconcile close
|
|
127
118
|
```
|
|
@@ -66,15 +66,12 @@ and exact changed-file set. Before the root writes any canonical record, run:
|
|
|
66
66
|
```bash
|
|
67
67
|
devrites-engine reconcile check; echo "reconcile rc=$?"
|
|
68
68
|
devrites-engine test-integrity; echo "test-integrity rc=$?"
|
|
69
|
-
devrites-engine package-existence; echo "package-existence rc=$?"
|
|
70
69
|
```
|
|
71
70
|
|
|
72
71
|
- Reconcile `5`: reject the result. Preserve pre-snapshot user work; restore only the
|
|
73
72
|
unauthorized slice delta; never widen scope from the writer's self-report.
|
|
74
73
|
- Test integrity `3`: a test was deleted, muted, focused, or de-asserted. Treat it as a
|
|
75
74
|
Critical protocol failure and correct it through the wright.
|
|
76
|
-
- Package existence `3`: verify the exact package/version and fix the bounded workflow
|
|
77
|
-
or dependency defect through recovery. It is not a reason to ask for retry approval.
|
|
78
75
|
- A setup/corrupt-baseline error blocks acceptance; never fall back silently to `HEAD`.
|
|
79
76
|
|
|
80
77
|
The clean reconcile check records that source has not changed since inspection. The
|
|
@@ -105,13 +102,13 @@ Before every retry:
|
|
|
105
102
|
|
|
106
103
|
That refresh requires the prior clean check, re-fingerprints root-owned state, and keeps
|
|
107
104
|
the original source baseline. Re-dispatch with the exact output, attempt count, and dead
|
|
108
|
-
ends. Then repeat reconcile and
|
|
105
|
+
ends. Then repeat reconcile and `test-integrity` from zero. Clear recovery only after
|
|
109
106
|
green with `recovery clear --class <class> "<root cause>" <slug>`. An exhausted objective
|
|
110
107
|
failure becomes a technical blocker with its reproduction, not a `rite-resolve` question.
|
|
111
108
|
|
|
112
109
|
## Close and record
|
|
113
110
|
|
|
114
|
-
When reconciliation, integrity,
|
|
111
|
+
When reconciliation, integrity, proof, and doubt gates all pass:
|
|
115
112
|
|
|
116
113
|
```bash
|
|
117
114
|
devrites-engine reconcile close
|
|
@@ -53,7 +53,6 @@ gates:
|
|
|
53
53
|
```bash
|
|
54
54
|
devrites-engine test-integrity; echo "test-integrity rc=$?" # exit 3 = a test deleted/skipped/loosened → Critical NO-GO
|
|
55
55
|
devrites-engine mutation-gate # changed-files mutation score — band the verdict; survivors are unproven behaviours
|
|
56
|
-
devrites-engine package-existence; echo "package-existence rc=$?" # exit 3 = a new import isn't declared in any manifest (hallucinated/typo-squatted dep) → Critical NO-GO
|
|
57
56
|
```
|
|
58
57
|
A test weakened since the slice base is a **Critical NO-GO**: the suite went green by lowering the
|
|
59
58
|
bar, not by the code being right. Record the mutation score in `seal.md`; under
|
|
@@ -166,8 +166,8 @@ decision.
|
|
|
166
166
|
|
|
167
167
|
Hand the winner's structured artifact to the normal cycle. Run immediate
|
|
168
168
|
reconciliation, doubt every stood decision, and complete test-integrity,
|
|
169
|
-
|
|
170
|
-
|
|
169
|
+
targeted, browser, and other slice proof. Only after every required gate is
|
|
170
|
+
green:
|
|
171
171
|
|
|
172
172
|
```bash
|
|
173
173
|
devrites-engine forge record "$RUN_ID" verification verified \
|
|
@@ -73,14 +73,13 @@ See also [`one-slice-cycle.md`](one-slice-cycle.md).
|
|
|
73
73
|
(reported in its `Principles` field, or that you detect against `.devrites/principles.md`) is
|
|
74
74
|
handled here like an irreversible-risk item: block, route to a human-approved scoped
|
|
75
75
|
exception in the register or stop; never doubt-and-accept a principle violation into the slice.
|
|
76
|
-
5. **Run retained-baseline integrity
|
|
76
|
+
5. **Run the retained-baseline integrity gate, then recover any objective red.**
|
|
77
77
|
```bash
|
|
78
78
|
devrites-engine test-integrity; echo "test-integrity rc=$?"
|
|
79
|
-
devrites-engine package-existence; echo "package-existence rc=$?"
|
|
80
79
|
```
|
|
81
|
-
If the wright's `Gates` were red (targeted tests / types / lint),
|
|
82
|
-
failed, or
|
|
83
|
-
|
|
80
|
+
If the wright's `Gates` were red (targeted tests / types / lint), `test-integrity`
|
|
81
|
+
failed, or proof could not be verified: do **not** mark the slice `built`, and **do not
|
|
82
|
+
fix the code yourself**.
|
|
84
83
|
Classify each causal fingerprint through
|
|
85
84
|
[`cleanup-and-classify.md`](../../devrites-debug-recovery/reference/cleanup-and-classify.md),
|
|
86
85
|
run `devrites-engine recovery route <class>`, and follow the `recovery-route/v1`
|
|
@@ -95,9 +94,9 @@ See also [`one-slice-cycle.md`](one-slice-cycle.md).
|
|
|
95
94
|
`recovery clear --class <class> "<root cause>" <slug>` only after green. Before every
|
|
96
95
|
re-dispatch, update the root-owned allowlist only for an accepted in-slice path and run
|
|
97
96
|
`reconcile snapshot`: after a clean check this refreshes canonical-state scope while
|
|
98
|
-
retaining the original source baseline. Repeat reconcile and
|
|
99
|
-
return. This owns red
|
|
100
|
-
|
|
97
|
+
retaining the original source baseline. Repeat reconcile and the integrity gate on every
|
|
98
|
+
return. This owns red gates, missing coverage, browser/runtime failures, and
|
|
99
|
+
workflow-tool defects.
|
|
101
100
|
After recovery:
|
|
102
101
|
- green → continue to record;
|
|
103
102
|
- product-contract/acceptance ambiguity or irreversible risk → open the genuine human gate
|
|
@@ -106,22 +105,14 @@ See also [`one-slice-cycle.md`](one-slice-cycle.md).
|
|
|
106
105
|
- exhausted objective failure → preserve reproduction/dead ends, set `Status: blocked` and
|
|
107
106
|
`Next step: $rite-plan unblock`, then STOP without a question or `$rite-resolve`.
|
|
108
107
|
6. **Close the retained baseline, then record. You are the canonical writer.**
|
|
109
|
-
Reconciliation ran immediately on return and
|
|
108
|
+
Reconciliation ran immediately on return and `test-integrity` ran in step 5.
|
|
110
109
|
**Exit 3 → hard STOP:** a test was deleted, skipped, or de-asserted since the slice base: the
|
|
111
110
|
slice went green by weakening its tests, a Critical protocol violation. Revert the weakening and
|
|
112
111
|
re-dispatch the wright; do **not** mark the slice `built`.
|
|
113
112
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
`requirements.txt`, `pyproject.toml`, `Pipfile`, `Cargo.toml`): the classic shape of a
|
|
118
|
-
hallucinated or typo-squatted dependency. Confirm the name on the registry and declare it via the
|
|
119
|
-
package manager, or remove the import; do **not** mark the slice `built`. The gate is deterministic
|
|
120
|
-
and fail-open (not a git repo / no manifest / stdlib-only import → rc 0). If the nearest
|
|
121
|
-
manifest declares the package, treat the mismatch as a workflow-tool defect under bounded
|
|
122
|
-
recovery, not a plan repair or retry-authorization question. Once every gate and doubt
|
|
123
|
-
verdict is accepted, a forged slice records successful verification and runs
|
|
124
|
-
manifest-only cleanup per [`forge.md`](forge.md). Then close the private window:
|
|
113
|
+
Once every gate and doubt verdict is accepted, a forged slice records successful
|
|
114
|
+
verification and runs manifest-only cleanup per [`forge.md`](forge.md). Then close the
|
|
115
|
+
private window:
|
|
125
116
|
```bash
|
|
126
117
|
devrites-engine reconcile close
|
|
127
118
|
```
|
|
@@ -66,15 +66,12 @@ and exact changed-file set. Before the root writes any canonical record, run:
|
|
|
66
66
|
```bash
|
|
67
67
|
devrites-engine reconcile check; echo "reconcile rc=$?"
|
|
68
68
|
devrites-engine test-integrity; echo "test-integrity rc=$?"
|
|
69
|
-
devrites-engine package-existence; echo "package-existence rc=$?"
|
|
70
69
|
```
|
|
71
70
|
|
|
72
71
|
- Reconcile `5`: reject the result. Preserve pre-snapshot user work; restore only the
|
|
73
72
|
unauthorized slice delta; never widen scope from the writer's self-report.
|
|
74
73
|
- Test integrity `3`: a test was deleted, muted, focused, or de-asserted. Treat it as a
|
|
75
74
|
Critical protocol failure and correct it through the wright.
|
|
76
|
-
- Package existence `3`: verify the exact package/version and fix the bounded workflow
|
|
77
|
-
or dependency defect through recovery. It is not a reason to ask for retry approval.
|
|
78
75
|
- A setup/corrupt-baseline error blocks acceptance; never fall back silently to `HEAD`.
|
|
79
76
|
|
|
80
77
|
The clean reconcile check records that source has not changed since inspection. The
|
|
@@ -105,13 +102,13 @@ Before every retry:
|
|
|
105
102
|
|
|
106
103
|
That refresh requires the prior clean check, re-fingerprints root-owned state, and keeps
|
|
107
104
|
the original source baseline. Re-dispatch with the exact output, attempt count, and dead
|
|
108
|
-
ends. Then repeat reconcile and
|
|
105
|
+
ends. Then repeat reconcile and `test-integrity` from zero. Clear recovery only after
|
|
109
106
|
green with `recovery clear --class <class> "<root cause>" <slug>`. An exhausted objective
|
|
110
107
|
failure becomes a technical blocker with its reproduction, not a `rite-resolve` question.
|
|
111
108
|
|
|
112
109
|
## Close and record
|
|
113
110
|
|
|
114
|
-
When reconciliation, integrity,
|
|
111
|
+
When reconciliation, integrity, proof, and doubt gates all pass:
|
|
115
112
|
|
|
116
113
|
```bash
|
|
117
114
|
devrites-engine reconcile close
|
|
@@ -53,7 +53,6 @@ gates:
|
|
|
53
53
|
```bash
|
|
54
54
|
devrites-engine test-integrity; echo "test-integrity rc=$?" # exit 3 = a test deleted/skipped/loosened → Critical NO-GO
|
|
55
55
|
devrites-engine mutation-gate # changed-files mutation score — band the verdict; survivors are unproven behaviours
|
|
56
|
-
devrites-engine package-existence; echo "package-existence rc=$?" # exit 3 = a new import isn't declared in any manifest (hallucinated/typo-squatted dep) → Critical NO-GO
|
|
57
56
|
```
|
|
58
57
|
A test weakened since the slice base is a **Critical NO-GO**: the suite went green by lowering the
|
|
59
58
|
bar, not by the code being right. Record the mutation score in `seal.md`; under
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "devrites",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.7",
|
|
4
4
|
"description": "DevRites: a disciplined senior-engineer workflow pack for Claude Code and Codex",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"homepage": "https://github.com/ViktorsBaikers/DevRites#readme",
|
|
@@ -59,6 +59,7 @@ for item in "${PAYLOAD[@]}"; do
|
|
|
59
59
|
if [[ -e "$item" ]]; then
|
|
60
60
|
if [[ "$item" == "engine" ]] && git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
61
61
|
while IFS= read -r -d '' path; do
|
|
62
|
+
[[ -e "$path" ]] || continue
|
|
62
63
|
if [[ "$path" == engine/testdata/golden/* ]]; then
|
|
63
64
|
continue
|
|
64
65
|
fi
|