devrites 3.2.14 → 3.2.16

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 CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  All notable changes to DevRites are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and DevRites adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Releases are generated automatically by [semantic-release](https://semantic-release.gitbook.io/) from Conventional Commits on `main`.
4
4
 
5
+ ## [3.2.16](https://github.com/ViktorsBaikers/DevRites/compare/v3.2.15...v3.2.16) (2026-07-27)
6
+
7
+ ### Fixed
8
+
9
+ * **rite:** run root-owned artifact gates ([7614022](https://github.com/ViktorsBaikers/DevRites/commit/7614022b36cf8c887f148e4d12777e20ee2ea3d4))
10
+
11
+ ## [3.2.15](https://github.com/ViktorsBaikers/DevRites/compare/v3.2.14...v3.2.15) (2026-07-27)
12
+
13
+ ### Fixed
14
+
15
+ * **agents:** verify hidden V2 child roles ([e80b62b](https://github.com/ViktorsBaikers/DevRites/commit/e80b62bf53cec440cfad54a3d23d8d3cf5b120f3))
16
+
5
17
  ## [3.2.14](https://github.com/ViktorsBaikers/DevRites/compare/v3.2.13...v3.2.14) (2026-07-26)
6
18
 
7
19
  ### Fixed
package/README.md CHANGED
@@ -25,7 +25,7 @@ final commit, push, and tag, and it requires a typed `GO` confirmation.
25
25
  Unattended runs may create local WIP checkpoint commits along the way, but only
26
26
  Ship collapses and pushes them.
27
27
 
28
- **Status:** [`v3.2.14`](https://github.com/ViktorsBaikers/DevRites/releases/tag/v3.2.14): see [`CHANGELOG.md`](CHANGELOG.md) for release notes.
28
+ **Status:** [`v3.2.16`](https://github.com/ViktorsBaikers/DevRites/releases/tag/v3.2.16): see [`CHANGELOG.md`](CHANGELOG.md) for release notes.
29
29
 
30
30
  ## Quick start
31
31
 
@@ -495,39 +495,54 @@ func durableCodexV2DispatchAttempts(
495
495
  }
496
496
  var attempts []*agentDispatchAttempt
497
497
  for _, spawn := range spawns {
498
- if !devritesAgentNameRe.MatchString(spawn.Role) || spawn.Role == agentDispatchSkillGuard {
498
+ role := spawn.Role
499
+ var childPath string
500
+ var childMeta codexRolloutRecord
501
+ if strings.TrimSpace(spawn.Result) != "" {
502
+ childPath, childMeta, err = findCodexV2ChildRollout(
503
+ sessionsDir, parentPath, projectRoot, sessionID, spawn.AgentPath,
504
+ )
505
+ if err != nil {
506
+ return nil, err
507
+ }
508
+ if childPath != "" {
509
+ role = childMeta.Payload.AgentRole
510
+ }
511
+ }
512
+ if !devritesAgentNameRe.MatchString(role) || role == agentDispatchSkillGuard {
499
513
  if strings.TrimSpace(spawn.Result) != "" {
500
514
  return nil, fmt.Errorf("codex V2 completed a default or non-DevRites child during a DevRites skill turn; %s", conditionalDispatchInstruction())
501
515
  }
502
516
  continue
503
517
  }
504
- armed[spawn.Role] = struct{}{}
518
+ armed[role] = struct{}{}
505
519
  attempt := &agentDispatchAttempt{
506
- Role: spawn.Role,
507
- AgentType: spawn.Role,
520
+ Role: role,
521
+ AgentType: role,
508
522
  Started: true,
509
523
  }
510
524
  attempts = append(attempts, attempt)
511
525
  if strings.TrimSpace(spawn.Result) == "" || !lineBetween(waitLines, spawn.SpawnLine, spawn.ResultLine) {
512
526
  continue
513
527
  }
514
- instructions, err := agentRoleDeveloperInstructions(root, spawn.Role)
528
+ if childPath == "" || childMeta.Payload.AgentRole != role {
529
+ continue
530
+ }
531
+ instructions, err := agentRoleDeveloperInstructions(root, role)
515
532
  if err != nil {
516
- return nil, fmt.Errorf("named role %s is not loadable: %w", spawn.Role, err)
533
+ return nil, fmt.Errorf("named role %s is not loadable: %w", role, err)
517
534
  }
518
- childID, childResult, err := findCodexV2ChildResult(
519
- sessionsDir, parentPath, projectRoot, sessionID, spawn.AgentPath, spawn.Role, instructions,
520
- )
535
+ childResult, err := codexChildResult(childPath, instructions)
521
536
  if err != nil {
522
537
  return nil, err
523
538
  }
524
- if childID == "" || strings.TrimSpace(childResult) == "" {
539
+ if childMeta.Payload.ID == "" || strings.TrimSpace(childResult) == "" {
525
540
  continue
526
541
  }
527
- attempt.AgentID = childID
542
+ attempt.AgentID = childMeta.Payload.ID
528
543
  attempt.Stopped = true
529
544
  attempt.Waited = true
530
- if spawn.Role == "devrites-slice-wright" {
545
+ if role == "devrites-slice-wright" {
531
546
  attempt.WindowID = currentReconcileWindowID()
532
547
  if attempt.WindowID == "" || !reconcileWindowPredates(spawn.SpawnedAt) {
533
548
  continue
@@ -654,10 +669,11 @@ func readCodexV2ParentRollout(
654
669
  return spawns, waitLines, nil
655
670
  }
656
671
 
657
- func findCodexV2ChildResult(
658
- sessionsDir, parentPath, projectRoot, sessionID, agentPath, role, instructions string,
659
- ) (string, string, error) {
660
- var childID, result string
672
+ func findCodexV2ChildRollout(
673
+ sessionsDir, parentPath, projectRoot, sessionID, agentPath string,
674
+ ) (string, codexRolloutRecord, error) {
675
+ var childPath string
676
+ var childMeta codexRolloutRecord
661
677
  err := filepath.WalkDir(sessionsDir, func(path string, entry fs.DirEntry, walkErr error) error {
662
678
  if walkErr != nil {
663
679
  if os.IsNotExist(walkErr) {
@@ -675,18 +691,17 @@ func findCodexV2ChildResult(
675
691
  if record.Type != "session_meta" ||
676
692
  record.Payload.ParentThreadID != sessionID ||
677
693
  record.Payload.AgentPath != agentPath ||
678
- record.Payload.AgentRole != role ||
679
694
  !sameResolvedPath(record.Payload.CWD, projectRoot) {
680
695
  return nil
681
696
  }
682
- if childID != "" {
697
+ if childPath != "" {
683
698
  return fmt.Errorf("multiple Codex child rollouts match %s", agentPath)
684
699
  }
685
- childID = record.Payload.ID
686
- result, err = codexChildResult(path, instructions)
687
- return err
700
+ childPath = path
701
+ childMeta = record
702
+ return nil
688
703
  })
689
- return childID, result, err
704
+ return childPath, childMeta, err
690
705
  }
691
706
 
692
707
  func firstCodexRolloutRecord(path string) (codexRolloutRecord, bool, error) {
@@ -7,6 +7,7 @@ package main_test
7
7
  import (
8
8
  "bytes"
9
9
  "encoding/json"
10
+ "fmt"
10
11
  "os"
11
12
  "path/filepath"
12
13
  "strconv"
@@ -379,6 +380,40 @@ func TestCodexGenericCompatibilityDoesNotShadowRoot(t *testing.T) {
379
380
  }
380
381
  }
381
382
 
383
+ func TestCodexRootRunsArtifactGatesInsideActiveWindow(t *testing.T) {
384
+ root := newWorkspace(t)
385
+ writeActive(t, root, "auth-tokens")
386
+ workspace := filepath.Join(root, "features", "auth-tokens")
387
+ if err := os.WriteFile(filepath.Join(workspace, ".reconcile-base"), []byte("snapshot\n"), 0o600); err != nil {
388
+ t.Fatal(err)
389
+ }
390
+ env := []string{
391
+ "DEVRITES_CODEX_GENERIC_AGENT_COMPAT=1",
392
+ "DEVRITES_HOOK_PROFILE=strict",
393
+ }
394
+ for _, command := range []string{
395
+ "npm run build",
396
+ "npm run test:e2e -- tests/admin-locations.e2e.spec.ts",
397
+ } {
398
+ in := fmt.Sprintf(`{"tool_name":"Bash","tool_input":{"command":%q}}`, command)
399
+ out, errOut, code := runDevritesIO(t, root, in, env,
400
+ "hook", "wright-scope", "--harness=codex")
401
+ if code != 0 || strings.TrimSpace(out) != "" {
402
+ t.Fatalf("%q should be root-owned: exit=%d out=%q stderr=%q", command, code, out, errOut)
403
+ }
404
+ }
405
+
406
+ in := `{"tool_name":"Bash","tool_input":{"command":"printf x > src/app.go"}}`
407
+ out, errOut, code := runDevritesIO(t, root, in, env,
408
+ "hook", "wright-scope", "--harness=codex")
409
+ if code != 0 {
410
+ t.Fatalf("source write guard exit=%d stderr=%q", code, errOut)
411
+ }
412
+ if decision, _ := parsePermissionDecision(t, out); decision != "deny" {
413
+ t.Fatalf("root source mutation was not denied: %q", out)
414
+ }
415
+ }
416
+
382
417
  func TestHookReviewerReadonlyActiveLeafDeniesEveryMutationSurface(t *testing.T) {
383
418
  root := newWorkspace(t)
384
419
  env := []string{
@@ -1667,6 +1702,50 @@ func TestCodexAgentDispatchConfirmsDurableV2NamedRole(t *testing.T) {
1667
1702
  }
1668
1703
  }
1669
1704
 
1705
+ func TestCodexAgentDispatchConfirmsDurableV2ChildRoleWhenParentOmitsAgentType(t *testing.T) {
1706
+ root := newWorkspace(t)
1707
+ codeHome := t.TempDir()
1708
+ sessionID, turnID := "session-v2-hidden-role", "turn-v2-hidden-role"
1709
+ role := "devrites-plan-drafter"
1710
+ writeCodexAgentContract(t, root, role)
1711
+ writeCodexSkillContract(t, root, "rite-plan", role)
1712
+
1713
+ runDevritesIO(t, root, hookPayload(t, map[string]any{
1714
+ "hook_event_name": "UserPromptSubmit",
1715
+ "session_id": sessionID,
1716
+ "turn_id": turnID,
1717
+ "prompt": "$rite-plan unblock",
1718
+ }), nil, "hook", "agent-dispatch", "--harness=codex")
1719
+
1720
+ taskName := "devrites_plan_drafter_hidden_role"
1721
+ writeCodexV2Rollouts(
1722
+ t, codeHome, filepath.Dir(root), sessionID, turnID, role,
1723
+ taskName, true, true, true,
1724
+ )
1725
+ parentPath := filepath.Join(codeHome, "sessions", "2026", "07", "25", "rollout-parent-"+sessionID+".jsonl")
1726
+ parent, err := os.ReadFile(parentPath)
1727
+ if err != nil {
1728
+ t.Fatal(err)
1729
+ }
1730
+ hiddenParentRole := bytes.ReplaceAll(parent, []byte(`\"agent_type\":\"`+role+`\"`), []byte(`\"agent_type\":\"\"`))
1731
+ if bytes.Equal(parent, hiddenParentRole) {
1732
+ t.Fatal("fixture did not hide the parent agent_type")
1733
+ }
1734
+ if err := os.WriteFile(parentPath, hiddenParentRole, 0o600); err != nil {
1735
+ t.Fatal(err)
1736
+ }
1737
+ stop := hookPayload(t, map[string]any{
1738
+ "hook_event_name": "Stop",
1739
+ "session_id": sessionID,
1740
+ "turn_id": turnID,
1741
+ })
1742
+ if out, stderr, code := runDevritesIO(t, root, stop,
1743
+ []string{"CODEX_HOME=" + codeHome},
1744
+ "hook", "agent-dispatch", "--harness=codex"); code != 0 || strings.TrimSpace(out) != "" {
1745
+ t.Fatalf("hidden parent role stop exit=%d out=%s stderr=%s", code, out, stderr)
1746
+ }
1747
+ }
1748
+
1670
1749
  func TestCodexAgentDispatchConfirmsConditionalDurableV2NamedRole(t *testing.T) {
1671
1750
  root := newWorkspace(t)
1672
1751
  codeHome := t.TempDir()
@@ -105,9 +105,9 @@ an escalation and do not proceed.**
105
105
  `$devrites-source-driven` on Codex. Verify the fact in installed source,
106
106
  official documentation, or context7 for current upstream behavior, then include
107
107
  that source in the result. Never invent an API.
108
- 4. **VERIFY (fail-on-red).** Run the slice's targeted tests and the project's type
109
- check, lint, and build where applicable. Capture the exact command and its real
110
- output. If a gate is red, fix the root cause in your code. **Never weaken a test
108
+ 4. **VERIFY (fail-on-red).** Run writer-safe tests/types/lint. Report required
109
+ build/browser/E2E as `not-run`: `root-owned artifact-producing gate`; root
110
+ runs them after reconciliation. Fix red gates in your code. **Never weaken a test
111
111
  to go green** by deleting it, skipping it with `skip`, `xfail`, or `.only`, or
112
112
  loosening an assertion. A test that genuinely must change is an **Escalation**,
113
113
  not a quiet edit. The orchestrator runs `devrites-engine test-integrity` on the
@@ -117,8 +117,7 @@ an escalation and do not proceed.**
117
117
  `devrites-engine recovery` **three-attempt budget per root cause**. At the limit,
118
118
  return the failed gate and reproduction. Reserve `Escalation` for a
119
119
  product-contract or irreversible-risk choice, or a user-only credential or
120
- action. A technical failure is a blocker for the orchestrator, not a permission
121
- question.
120
+ action. Technical failure is a blocker, not a permission question.
122
121
  5. **RETURN** the structured artifact (below) and stop. Do not start the next slice.
123
122
 
124
123
  ## Code quality: consume the rules, don't reinvent them
@@ -15,9 +15,9 @@ DISPATCH → hand the slice contract to devrites-slice-wright (fresh context).
15
15
  ORIENT → load only the files this slice touches; learn the project's idiom; reuse-first
16
16
  (RED) → if behavior change: write the failing test first
17
17
  IMPLEMENT → smallest complete version; match conventions; devrites-frontend-craft for UI
18
- VERIFY → targeted tests (+ types/lint/build); fail-on-red; return artifact — code + tests only
18
+ VERIFY → writer-safe tests/types/lint; return code + tests
19
19
  (DOUBT) → orchestrator, on return: devrites-doubt each non-trivial decision the wright stood up
20
- PROVE → orchestrator: fail-on-red check on the wright's gates; browser proof for UI
20
+ PROVE → root: exact required production build/browser/E2E, then final reconcile; fail-on-red
21
21
  RECORD → orchestrator: after green verification, Forge cleanup/report if used; then
22
22
  state.md, evidence.md, touched-files.md (the canonical writer)
23
23
  (CHECKPOINT) → orchestrator: if .devrites/CHECKPOINT is set, commit the proven slice
@@ -73,13 +73,22 @@ 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 the retained-baseline integrity gate, then recover any objective red.**
76
+ 5. **Run retained-baseline integrity and every root-owned proof gate, then recover
77
+ any objective red.**
77
78
  ```bash
78
79
  devrites-engine test-integrity; echo "test-integrity rc=$?"
79
80
  ```
81
+ Run every exact command reported as `not-run`: `root-owned artifact-producing gate`
82
+ in the wright result. These are root proof commands, not source-edit authority.
83
+ Do not omit, rewrite, or substitute them; a missing command is unverifiable proof.
84
+ After they pass, run `devrites-engine reconcile check` again after the root-owned gates
85
+ and before close, proving their child processes did not change tracked source:
86
+ ```bash
87
+ devrites-engine reconcile check; echo "reconcile rc=$?"
88
+ ```
80
89
  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**.
90
+ failed, a root-owned gate failed, the final reconcile failed, or proof could not be
91
+ verified: do **not** mark the slice `built`, and **do not fix the code yourself**.
83
92
  Classify each causal fingerprint through
84
93
  [`cleanup-and-classify.md`](../../devrites-debug-recovery/reference/cleanup-and-classify.md),
85
94
  run `devrites-engine recovery route <class>`, and follow the `recovery-route/v1`
@@ -105,7 +114,8 @@ See also [`one-slice-cycle.md`](one-slice-cycle.md).
105
114
  - exhausted objective failure → preserve reproduction/dead ends, set `Status: blocked` and
106
115
  `Next step: /rite-plan unblock`, then STOP without a question or `/rite-resolve`.
107
116
  6. **Close the retained baseline, then record. You are the canonical writer.**
108
- Reconciliation ran immediately on return and `test-integrity` ran in step 5.
117
+ Reconciliation ran immediately on return; step 5 ran integrity, root-owned proof,
118
+ and a final clean reconciliation.
109
119
  **Exit 3 → hard STOP:** a test was deleted, skipped, or de-asserted since the slice base: the
110
120
  slice went green by weakening its tests, a Critical protocol violation. Revert the weakening and
111
121
  re-dispatch the wright; do **not** mark the slice `built`.
@@ -1,9 +1,9 @@
1
1
  # Slice-wright dispatch
2
2
 
3
- `/rite-build` delegates one settled slice or correction set to
4
- `devrites-slice-wright`. The root orchestrator owns scope, human questions,
5
- `.devrites/**`, gates, reconciliation, and routing. The wright is the only source/test
6
- writer and never invokes another agent.
3
+ `/rite-build` delegates one slice or correction to `devrites-slice-wright`.
4
+ The root owns scope, questions, `.devrites/**`, reconciliation, and routing.
5
+ Production builds and browser/E2E runs are root-owned gates.
6
+ The wright only writes source/tests, runs writer-safe proof, and never invokes agents.
7
7
 
8
8
  The universal packet, result, budget, await, retry, and host fallback contract is
9
9
  [`standards/agents.md`](../../devrites-lib/reference/standards/agents.md). This file adds
@@ -108,7 +108,7 @@ failure becomes a technical blocker with its reproduction, not a `rite-resolve`
108
108
 
109
109
  ## Close and record
110
110
 
111
- When reconciliation, integrity, proof, and doubt gates all pass:
111
+ Run the root gates and final reconciliation from `phase-contract.md` step 5. Then:
112
112
 
113
113
  ```bash
114
114
  devrites-engine reconcile close
@@ -105,9 +105,9 @@ an escalation and do not proceed.**
105
105
  `$devrites-source-driven` on Codex. Verify the fact in installed source,
106
106
  official documentation, or context7 for current upstream behavior, then include
107
107
  that source in the result. Never invent an API.
108
- 4. **VERIFY (fail-on-red).** Run the slice's targeted tests and the project's type
109
- check, lint, and build where applicable. Capture the exact command and its real
110
- output. If a gate is red, fix the root cause in your code. **Never weaken a test
108
+ 4. **VERIFY (fail-on-red).** Run writer-safe tests/types/lint. Report required
109
+ build/browser/E2E as `not-run`: `root-owned artifact-producing gate`; root
110
+ runs them after reconciliation. Fix red gates in your code. **Never weaken a test
111
111
  to go green** by deleting it, skipping it with `skip`, `xfail`, or `.only`, or
112
112
  loosening an assertion. A test that genuinely must change is an **Escalation**,
113
113
  not a quiet edit. The orchestrator runs `devrites-engine test-integrity` on the
@@ -117,8 +117,7 @@ an escalation and do not proceed.**
117
117
  `devrites-engine recovery` **three-attempt budget per root cause**. At the limit,
118
118
  return the failed gate and reproduction. Reserve `Escalation` for a
119
119
  product-contract or irreversible-risk choice, or a user-only credential or
120
- action. A technical failure is a blocker for the orchestrator, not a permission
121
- question.
120
+ action. Technical failure is a blocker, not a permission question.
122
121
  5. **RETURN** the structured artifact (below) and stop. Do not start the next slice.
123
122
 
124
123
  ## Code quality: consume the rules, don't reinvent them
@@ -15,9 +15,9 @@ DISPATCH → hand the slice contract to devrites-slice-wright (fresh context).
15
15
  ORIENT → load only the files this slice touches; learn the project's idiom; reuse-first
16
16
  (RED) → if behavior change: write the failing test first
17
17
  IMPLEMENT → smallest complete version; match conventions; devrites-frontend-craft for UI
18
- VERIFY → targeted tests (+ types/lint/build); fail-on-red; return artifact — code + tests only
18
+ VERIFY → writer-safe tests/types/lint; return code + tests
19
19
  (DOUBT) → orchestrator, on return: devrites-doubt each non-trivial decision the wright stood up
20
- PROVE → orchestrator: fail-on-red check on the wright's gates; browser proof for UI
20
+ PROVE → root: exact required production build/browser/E2E, then final reconcile; fail-on-red
21
21
  RECORD → orchestrator: after green verification, Forge cleanup/report if used; then
22
22
  state.md, evidence.md, touched-files.md (the canonical writer)
23
23
  (CHECKPOINT) → orchestrator: if .devrites/CHECKPOINT is set, commit the proven slice
@@ -73,13 +73,22 @@ 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 the retained-baseline integrity gate, then recover any objective red.**
76
+ 5. **Run retained-baseline integrity and every root-owned proof gate, then recover
77
+ any objective red.**
77
78
  ```bash
78
79
  devrites-engine test-integrity; echo "test-integrity rc=$?"
79
80
  ```
81
+ Run every exact command reported as `not-run`: `root-owned artifact-producing gate`
82
+ in the wright result. These are root proof commands, not source-edit authority.
83
+ Do not omit, rewrite, or substitute them; a missing command is unverifiable proof.
84
+ After they pass, run `devrites-engine reconcile check` again after the root-owned gates
85
+ and before close, proving their child processes did not change tracked source:
86
+ ```bash
87
+ devrites-engine reconcile check; echo "reconcile rc=$?"
88
+ ```
80
89
  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**.
90
+ failed, a root-owned gate failed, the final reconcile failed, or proof could not be
91
+ verified: do **not** mark the slice `built`, and **do not fix the code yourself**.
83
92
  Classify each causal fingerprint through
84
93
  [`cleanup-and-classify.md`](../../devrites-debug-recovery/reference/cleanup-and-classify.md),
85
94
  run `devrites-engine recovery route <class>`, and follow the `recovery-route/v1`
@@ -105,7 +114,8 @@ See also [`one-slice-cycle.md`](one-slice-cycle.md).
105
114
  - exhausted objective failure → preserve reproduction/dead ends, set `Status: blocked` and
106
115
  `Next step: /rite-plan unblock`, then STOP without a question or `/rite-resolve`.
107
116
  6. **Close the retained baseline, then record. You are the canonical writer.**
108
- Reconciliation ran immediately on return and `test-integrity` ran in step 5.
117
+ Reconciliation ran immediately on return; step 5 ran integrity, root-owned proof,
118
+ and a final clean reconciliation.
109
119
  **Exit 3 → hard STOP:** a test was deleted, skipped, or de-asserted since the slice base: the
110
120
  slice went green by weakening its tests, a Critical protocol violation. Revert the weakening and
111
121
  re-dispatch the wright; do **not** mark the slice `built`.
@@ -1,9 +1,9 @@
1
1
  # Slice-wright dispatch
2
2
 
3
- `/rite-build` delegates one settled slice or correction set to
4
- `devrites-slice-wright`. The root orchestrator owns scope, human questions,
5
- `.devrites/**`, gates, reconciliation, and routing. The wright is the only source/test
6
- writer and never invokes another agent.
3
+ `/rite-build` delegates one slice or correction to `devrites-slice-wright`.
4
+ The root owns scope, questions, `.devrites/**`, reconciliation, and routing.
5
+ Production builds and browser/E2E runs are root-owned gates.
6
+ The wright only writes source/tests, runs writer-safe proof, and never invokes agents.
7
7
 
8
8
  The universal packet, result, budget, await, retry, and host fallback contract is
9
9
  [`standards/agents.md`](../../devrites-lib/reference/standards/agents.md). This file adds
@@ -108,7 +108,7 @@ failure becomes a technical blocker with its reproduction, not a `rite-resolve`
108
108
 
109
109
  ## Close and record
110
110
 
111
- When reconciliation, integrity, proof, and doubt gates all pass:
111
+ Run the root gates and final reconciliation from `phase-contract.md` step 5. Then:
112
112
 
113
113
  ```bash
114
114
  devrites-engine reconcile close
@@ -100,9 +100,9 @@ an escalation and do not proceed.**
100
100
  `$devrites-source-driven` on Codex. Verify the fact in installed source,
101
101
  official documentation, or context7 for current upstream behavior, then include
102
102
  that source in the result. Never invent an API.
103
- 4. **VERIFY (fail-on-red).** Run the slice's targeted tests and the project's type
104
- check, lint, and build where applicable. Capture the exact command and its real
105
- output. If a gate is red, fix the root cause in your code. **Never weaken a test
103
+ 4. **VERIFY (fail-on-red).** Run writer-safe tests/types/lint. Report required
104
+ build/browser/E2E as `not-run`: `root-owned artifact-producing gate`; root
105
+ runs them after reconciliation. Fix red gates in your code. **Never weaken a test
106
106
  to go green** by deleting it, skipping it with `skip`, `xfail`, or `.only`, or
107
107
  loosening an assertion. A test that genuinely must change is an **Escalation**,
108
108
  not a quiet edit. The orchestrator runs `devrites-engine test-integrity` on the
@@ -112,8 +112,7 @@ an escalation and do not proceed.**
112
112
  `devrites-engine recovery` **three-attempt budget per root cause**. At the limit,
113
113
  return the failed gate and reproduction. Reserve `Escalation` for a
114
114
  product-contract or irreversible-risk choice, or a user-only credential or
115
- action. A technical failure is a blocker for the orchestrator, not a permission
116
- question.
115
+ action. Technical failure is a blocker, not a permission question.
117
116
  5. **RETURN** the structured artifact (below) and stop. Do not start the next slice.
118
117
 
119
118
  ## Code quality: consume the rules, don't reinvent them
@@ -15,9 +15,9 @@ DISPATCH → hand the slice contract to devrites-slice-wright (fresh context).
15
15
  ORIENT → load only the files this slice touches; learn the project's idiom; reuse-first
16
16
  (RED) → if behavior change: write the failing test first
17
17
  IMPLEMENT → smallest complete version; match conventions; devrites-frontend-craft for UI
18
- VERIFY → targeted tests (+ types/lint/build); fail-on-red; return artifact — code + tests only
18
+ VERIFY → writer-safe tests/types/lint; return code + tests
19
19
  (DOUBT) → orchestrator, on return: devrites-doubt each non-trivial decision the wright stood up
20
- PROVE → orchestrator: fail-on-red check on the wright's gates; browser proof for UI
20
+ PROVE → root: exact required production build/browser/E2E, then final reconcile; fail-on-red
21
21
  RECORD → orchestrator: after green verification, Forge cleanup/report if used; then
22
22
  state.md, evidence.md, touched-files.md (the canonical writer)
23
23
  (CHECKPOINT) → orchestrator: if .devrites/CHECKPOINT is set, commit the proven slice
@@ -73,13 +73,22 @@ 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 the retained-baseline integrity gate, then recover any objective red.**
76
+ 5. **Run retained-baseline integrity and every root-owned proof gate, then recover
77
+ any objective red.**
77
78
  ```bash
78
79
  devrites-engine test-integrity; echo "test-integrity rc=$?"
79
80
  ```
81
+ Run every exact command reported as `not-run`: `root-owned artifact-producing gate`
82
+ in the wright result. These are root proof commands, not source-edit authority.
83
+ Do not omit, rewrite, or substitute them; a missing command is unverifiable proof.
84
+ After they pass, run `devrites-engine reconcile check` again after the root-owned gates
85
+ and before close, proving their child processes did not change tracked source:
86
+ ```bash
87
+ devrites-engine reconcile check; echo "reconcile rc=$?"
88
+ ```
80
89
  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**.
90
+ failed, a root-owned gate failed, the final reconcile failed, or proof could not be
91
+ verified: do **not** mark the slice `built`, and **do not fix the code yourself**.
83
92
  Classify each causal fingerprint through
84
93
  [`cleanup-and-classify.md`](../../devrites-debug-recovery/reference/cleanup-and-classify.md),
85
94
  run `devrites-engine recovery route <class>`, and follow the `recovery-route/v1`
@@ -105,7 +114,8 @@ See also [`one-slice-cycle.md`](one-slice-cycle.md).
105
114
  - exhausted objective failure → preserve reproduction/dead ends, set `Status: blocked` and
106
115
  `Next step: $rite-plan unblock`, then STOP without a question or `$rite-resolve`.
107
116
  6. **Close the retained baseline, then record. You are the canonical writer.**
108
- Reconciliation ran immediately on return and `test-integrity` ran in step 5.
117
+ Reconciliation ran immediately on return; step 5 ran integrity, root-owned proof,
118
+ and a final clean reconciliation.
109
119
  **Exit 3 → hard STOP:** a test was deleted, skipped, or de-asserted since the slice base: the
110
120
  slice went green by weakening its tests, a Critical protocol violation. Revert the weakening and
111
121
  re-dispatch the wright; do **not** mark the slice `built`.
@@ -1,9 +1,9 @@
1
1
  # Slice-wright dispatch
2
2
 
3
- `$rite-build` delegates one settled slice or correction set to
4
- `devrites-slice-wright`. The root orchestrator owns scope, human questions,
5
- `.devrites/**`, gates, reconciliation, and routing. The wright is the only source/test
6
- writer and never invokes another agent.
3
+ `$rite-build` delegates one slice or correction to `devrites-slice-wright`.
4
+ The root owns scope, questions, `.devrites/**`, reconciliation, and routing.
5
+ Production builds and browser/E2E runs are root-owned gates.
6
+ The wright only writes source/tests, runs writer-safe proof, and never invokes agents.
7
7
 
8
8
  The universal packet, result, budget, await, retry, and host fallback contract is
9
9
  [`standards/agents.md`](../../devrites-lib/reference/standards/agents.md). This file adds
@@ -108,7 +108,7 @@ failure becomes a technical blocker with its reproduction, not a `rite-resolve`
108
108
 
109
109
  ## Close and record
110
110
 
111
- When reconciliation, integrity, proof, and doubt gates all pass:
111
+ Run the root gates and final reconciliation from `phase-contract.md` step 5. Then:
112
112
 
113
113
  ```bash
114
114
  devrites-engine reconcile close
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devrites",
3
- "version": "3.2.14",
3
+ "version": "3.2.16",
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",