@tyroneross/build-loop 0.30.3 → 0.35.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.
Files changed (171) hide show
  1. package/.agents/plugins/marketplace.json +2 -2
  2. package/.claude-plugin/marketplace.json +4 -4
  3. package/.claude-plugin/plugin.json +1 -1
  4. package/.codex-plugin/plugin.json +1 -1
  5. package/AGENTS.md +11 -2
  6. package/README.md +8 -7
  7. package/agents/advisor.md +111 -0
  8. package/agents/alignment-checker.md +11 -0
  9. package/agents/assessment-orchestrator.md +1 -1
  10. package/agents/build-orchestrator.md +28 -33
  11. package/agents/fact-checker.md +1 -1
  12. package/agents/fix-critique.md +1 -1
  13. package/agents/independent-auditor.md +1 -1
  14. package/agents/overfitting-reviewer.md +1 -1
  15. package/agents/plan-critic.md +8 -6
  16. package/agents/promotion-reviewer.md +1 -1
  17. package/agents/retrospective-synthesizer.md +20 -3
  18. package/agents/scope-auditor.md +1 -1
  19. package/agents/security-reviewer.md +1 -1
  20. package/agents/self-improvement-architect.md +1 -1
  21. package/commands/{handoff.md → compose-handoff.md} +4 -4
  22. package/commands/{optimize.md → optimize-run.md} +1 -1
  23. package/commands/{agent-rally-point.md → rally-point.md} +3 -3
  24. package/commands/{research.md → research-run.md} +1 -1
  25. package/commands/setup-memory.md +32 -0
  26. package/commands/{plan-verify.md → verify-plan.md} +1 -1
  27. package/docs/agent-surface-policy.md +38 -20
  28. package/docs/memory-setup.md +19 -14
  29. package/hooks/_resolve_python.sh +28 -0
  30. package/hooks/closeout.sh +58 -0
  31. package/hooks/git/pre-push +69 -6
  32. package/hooks/hooks.json +34 -13
  33. package/hooks/post-push-closeout.sh +73 -0
  34. package/hooks/session-start-closeout.sh +69 -0
  35. package/hooks/session-start-memory.sh +27 -0
  36. package/hooks/session-start-plugin-heal.sh +33 -0
  37. package/hooks/test_closeout.sh +124 -0
  38. package/package.json +7 -4
  39. package/plugin-artifacts/codex/.codex-plugin/plugin.json +41 -0
  40. package/plugin-artifacts/codex/AGENTS.md +507 -0
  41. package/plugin-artifacts/codex/BUILD-ARTIFACT.md +5 -0
  42. package/plugin-artifacts/codex/LICENSE +202 -0
  43. package/plugin-artifacts/codex/README.md +404 -0
  44. package/plugin-artifacts/codex/docs/agent-surface-policy.md +63 -0
  45. package/plugin-artifacts/codex/references/advisor-dispatch-ladder.md +62 -0
  46. package/plugin-artifacts/codex/references/agent-role-taxonomy.md +135 -0
  47. package/plugin-artifacts/codex/references/autonomous-and-per-commit-modes.md +161 -0
  48. package/plugin-artifacts/codex/references/autonomy-config.md +231 -0
  49. package/plugin-artifacts/codex/references/capability-routing.md +182 -0
  50. package/plugin-artifacts/codex/references/codex-subagents.md +106 -0
  51. package/plugin-artifacts/codex/references/coordination-file-template.md +181 -0
  52. package/plugin-artifacts/codex/references/coordination-rules.md +283 -0
  53. package/plugin-artifacts/codex/references/dogfood-reload-checkpoint.md +112 -0
  54. package/plugin-artifacts/codex/references/halt-and-ask-protocol.md +102 -0
  55. package/plugin-artifacts/codex/references/implementer-envelope-schema.md +302 -0
  56. package/plugin-artifacts/codex/references/intent-capability-pack.md +257 -0
  57. package/plugin-artifacts/codex/references/intent-exploration-prompts.md +96 -0
  58. package/plugin-artifacts/codex/references/leadership.md +72 -0
  59. package/plugin-artifacts/codex/references/memory-systems.md +238 -0
  60. package/plugin-artifacts/codex/references/memory.md +299 -0
  61. package/plugin-artifacts/codex/references/model-tier-mapping.md +257 -0
  62. package/plugin-artifacts/codex/references/modular-systems-pack.md +96 -0
  63. package/plugin-artifacts/codex/references/phase-1-assess.md +231 -0
  64. package/plugin-artifacts/codex/references/phase-2-plan.md +78 -0
  65. package/plugin-artifacts/codex/references/phase-3-execute.md +49 -0
  66. package/plugin-artifacts/codex/references/phase-4-review.md +322 -0
  67. package/plugin-artifacts/codex/references/phase-5-iterate.md +71 -0
  68. package/plugin-artifacts/codex/references/phase-6-learn.md +56 -0
  69. package/plugin-artifacts/codex/references/recent-design-structures.md +274 -0
  70. package/plugin-artifacts/codex/references/research-trigger-policy.md +140 -0
  71. package/plugin-artifacts/codex/references/runtime-smoke-triggers.md +42 -0
  72. package/plugin-artifacts/codex/references/self-review.md +234 -0
  73. package/plugin-artifacts/codex/references/single-writer-commit-protocol.md +90 -0
  74. package/plugin-artifacts/codex/references/task-capture-policy.md +68 -0
  75. package/plugin-artifacts/codex/references/ui-io-contract.md +116 -0
  76. package/plugin-artifacts/codex/references/ui-spotcheck-protocol.md +65 -0
  77. package/plugin-artifacts/codex/skills/build-loop/SKILL.md +372 -0
  78. package/plugin-artifacts/codex/skills/build-loop/detect-plugins.mjs +82 -0
  79. package/plugin-artifacts/codex/skills/build-loop/eval-guide.md +65 -0
  80. package/plugin-artifacts/codex/skills/build-loop/fallbacks.md +549 -0
  81. package/plugin-artifacts/codex/skills/build-loop/phases/fact-check.md +42 -0
  82. package/plugin-artifacts/codex/skills/build-loop/phases/ui-validation.md +267 -0
  83. package/plugin-artifacts/codex/skills/build-loop/references/advisor-dispatch-ladder.md +62 -0
  84. package/plugin-artifacts/codex/skills/build-loop/references/apple-native-planning.md +439 -0
  85. package/plugin-artifacts/codex/skills/build-loop/references/autonomous-and-per-commit-modes.md +161 -0
  86. package/plugin-artifacts/codex/skills/build-loop/references/capability-routing.md +182 -0
  87. package/plugin-artifacts/codex/skills/build-loop/references/codex-subagents.md +106 -0
  88. package/plugin-artifacts/codex/skills/build-loop/references/coordination.md +161 -0
  89. package/plugin-artifacts/codex/skills/build-loop/references/correction-aware-capture.md +177 -0
  90. package/plugin-artifacts/codex/skills/build-loop/references/independent-auditor.md +72 -0
  91. package/plugin-artifacts/codex/skills/build-loop/references/intent-capability-pack.md +257 -0
  92. package/plugin-artifacts/codex/skills/build-loop/references/intent-exploration-prompts.md +96 -0
  93. package/plugin-artifacts/codex/skills/build-loop/references/leadership.md +72 -0
  94. package/plugin-artifacts/codex/skills/build-loop/references/memory.md +299 -0
  95. package/plugin-artifacts/codex/skills/build-loop/references/modular-systems-pack.md +96 -0
  96. package/plugin-artifacts/codex/skills/build-loop/references/output-style.md +129 -0
  97. package/plugin-artifacts/codex/skills/build-loop/references/pay-it-forward-arch.md +98 -0
  98. package/plugin-artifacts/codex/skills/build-loop/references/phase-1-assess.md +231 -0
  99. package/plugin-artifacts/codex/skills/build-loop/references/phase-2-plan.md +78 -0
  100. package/plugin-artifacts/codex/skills/build-loop/references/phase-3-execute.md +49 -0
  101. package/plugin-artifacts/codex/skills/build-loop/references/phase-4-review.md +322 -0
  102. package/plugin-artifacts/codex/skills/build-loop/references/phase-5-iterate.md +71 -0
  103. package/plugin-artifacts/codex/skills/build-loop/references/phase-6-learn.md +56 -0
  104. package/plugin-artifacts/codex/skills/build-loop/references/recent-design-structures.md +274 -0
  105. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/ASSESSMENT.md +85 -0
  106. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/STANDALONE_TEST_RUN.md +149 -0
  107. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/01-simple-bugfix.md +32 -0
  108. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/02-ui-build-with-iteration.md +48 -0
  109. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/03-multi-failure-escalation.md +60 -0
  110. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/04-ui-build-ibr-absent.md +51 -0
  111. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/05-refactor-navgator-absent.md +71 -0
  112. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/06-recurring-bug-debugger-absent.md +52 -0
  113. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/trace-comparison.md +202 -0
  114. package/plugin-artifacts/codex/skills/build-loop/references/self-recursive-dev.md +77 -0
  115. package/plugin-artifacts/codex/skills/build-loop/references/self-review.md +234 -0
  116. package/plugin-artifacts/codex/skills/build-loop/references/ui-io-contract.md +116 -0
  117. package/plugin-artifacts/codex/skills/build-loop/scanners/audit-design-rules.mjs +476 -0
  118. package/plugin-artifacts/codex/skills/build-loop/scanners/require-visual-evidence.mjs +239 -0
  119. package/plugin-artifacts/codex/skills/build-loop/templates/backlog-item.md +35 -0
  120. package/plugin-artifacts/codex/skills/build-loop/templates/codex-worker-prompt.md +100 -0
  121. package/plugin-artifacts/codex/skills/build-loop/templates/ui-subagent-prompt.md +179 -0
  122. package/plugin-artifacts/codex/skills/build-loop/templates/ux-fix-plan.md +40 -0
  123. package/scripts/_paths.py +59 -13
  124. package/scripts/build_codex_plugin_artifact.py +314 -0
  125. package/scripts/check_cache_sync.py +1 -1
  126. package/scripts/install_memory.py +11 -3
  127. package/scripts/prune_plugin_cache.py +225 -11
  128. package/scripts/sync_navgator_lessons.py +25 -0
  129. package/scripts/sync_plugin_cache.py +66 -36
  130. package/skills/agent-rally-point/SKILL.md +1 -1
  131. package/skills/agent-rally-watcher/SKILL.md +1 -1
  132. package/skills/build-loop/SKILL.md +11 -155
  133. package/skills/build-loop/references/advisor-dispatch-ladder.md +62 -0
  134. package/skills/build-loop/references/autonomous-and-per-commit-modes.md +161 -0
  135. package/skills/build-loop/references/capability-routing.md +4 -3
  136. package/skills/build-loop/references/codex-subagents.md +8 -0
  137. package/skills/build-loop/references/coordination.md +1 -1
  138. package/skills/build-loop/references/intent-capability-pack.md +88 -1
  139. package/skills/build-loop/references/memory.md +17 -2
  140. package/skills/build-loop/references/phase-1-assess.md +13 -0
  141. package/skills/build-loop/references/phase-2-plan.md +2 -1
  142. package/skills/build-loop/references/phase-3-execute.md +4 -2
  143. package/skills/build-loop/references/phase-4-review.md +12 -0
  144. package/skills/build-loop/references/phase-6-learn.md +1 -1
  145. package/skills/build-loop/references/self-review.md +4 -2
  146. package/skills/build-loop/templates/codex-worker-prompt.md +45 -34
  147. package/skills/handoff/SKILL.md +3 -3
  148. package/skills/loop-builder/SKILL.md +98 -0
  149. package/skills/loop-builder/presets/active-project-evidence.yaml +97 -0
  150. package/skills/loop-builder/presets/generic-artifact-loop.yaml +95 -0
  151. package/skills/loop-builder/presets/presentation-audit.yaml +96 -0
  152. package/skills/loop-builder/presets/research-synthesis.yaml +96 -0
  153. package/skills/loop-builder/presets/source-ingestion-raw-data-audit.yaml +96 -0
  154. package/skills/loop-builder/references/spec-format.md +80 -0
  155. package/skills/loop-builder/scripts/loop_builder.py +346 -0
  156. package/skills/model-tiering/SKILL.md +65 -40
  157. package/skills/optimize/SKILL.md +2 -2
  158. package/skills/plan-verify/SKILL.md +1 -1
  159. package/skills/plugin-builder/references/distribution.md +8 -0
  160. package/skills/research/SKILL.md +33 -6
  161. package/skills/runtime-parity-verification/SKILL.md +51 -0
  162. package/skills/spec-writing/SKILL.md +19 -0
  163. package/templates/memory/README.md +65 -0
  164. package/templates/memory/charter.md.template +46 -0
  165. package/templates/memory/manifest.json +24 -4
  166. package/codex-skills/debug-loop/SKILL.md +0 -18
  167. package/codex-skills/handoff/SKILL.md +0 -22
  168. package/codex-skills/knowledge/SKILL.md +0 -21
  169. package/codex-skills/optimize/SKILL.md +0 -18
  170. package/codex-skills/research/SKILL.md +0 -18
  171. /package/commands/{knowledge-review.md → review-knowledge.md} +0 -0
@@ -0,0 +1,283 @@
1
+ <!-- SPDX-FileCopyrightText: 2025-2026 Tyrone Ross, Jr <46267523+tyroneross@users.noreply.github.com> | SPDX-License-Identifier: Apache-2.0 -->
2
+
3
+ # Coordination Rules (Binding Constitution)
4
+
5
+ **Audience:** Any agent participating in a multi-session build-loop run — Claude Code orchestrator, Codex verifier, peer Claude session, CI, headless host.
6
+
7
+ **Status:** Binding. Every rule below was codified from a concrete prior-run failure; cross-reference cited next to each rule.
8
+
9
+ This file is the durable source of truth for **how peers coordinate**. It replaces tone-suggesting "should" framings with operational rules that have automated enforcement where possible. New coordination files (`.build-loop/coordination/<topic>.md`) start from `references/coordination-file-template.md` and inherit this constitution by reference; per-run files MUST NOT contradict it.
10
+
11
+ ---
12
+
13
+ ## Operating Rule (verdicts are gating, not advisory)
14
+
15
+ **Claude does not proceed past a step marked `verification-pending` until the latest verifier feedback entry for that step is one of:**
16
+
17
+ - `PASS` — acceptance criteria verified end-to-end.
18
+ - `VARIANCE` that has been resolved (Claude fixed the variance, documented non-acceptance with rationale, OR escalated to the user with explicit decision).
19
+ - Explicit user override (recorded in the coord file under "Codex feedback log" or in `state.json.userOverrides[]`).
20
+
21
+ A `VARIANCE` left unresolved blocks the next step. A `BLOCKED` entry (verifier could not verify because evidence is missing) requires the producing peer to supply the missing evidence before the next step dispatches.
22
+
23
+ **Why binding (not advisory):** the 2026-05-20 audit-execution run found that even when a fresh verifier session reads the coord file, the default reading of "verifier" leans advisory. The operating rule must be stated up-front in the coord file and re-stated in the brief sent to the verifier. Memory citation: `feedback_codex_pass_is_gate_not_comment`.
24
+
25
+ **Detection:** `python3 scripts/coordination_status.py --workdir . --session-id <id> --coordination-file <path> --json` — `unresolved: []` means safe to advance; non-empty array means hold and resolve. See [Cheap detection](#cheap-detection-at-step-boundaries) below.
26
+
27
+ ---
28
+
29
+ ## Channel & Rally Point
30
+
31
+ **Every cross-session signal goes through Rally Point using the canonical `scripts/rally_point/post.py` `post()` helper.** Raw `append_change(...)` without a subsequent `bump_revision(...)` is a silent-no-op for consumers — the record lands on disk but no peer's `checkpoint_read(...)` ever surfaces it because their cursor still matches the unchanged revision.
32
+
33
+ ```python
34
+ from scripts.rally_point.post import post
35
+ from scripts.rally_point.discovery_bridge import resolve
36
+ from pathlib import Path
37
+ envelope = resolve(Path.cwd())
38
+ channel = Path(envelope.channel_dir)
39
+ post(
40
+ channel_dir=channel,
41
+ kind="feedback", # or "phase", "commit", "dep-change", "handoff", "arch-scan-complete"
42
+ tool="codex", # or "claude_code", "gemini_cli", etc.
43
+ model="gpt-5",
44
+ run_id="<run-id>",
45
+ app_slug=envelope.app_slug,
46
+ payload={"step": "<id>", "verdict": "PASS", "evidence": {...}, "impact": "...", "requested_action": "..."},
47
+ )
48
+ ```
49
+
50
+ `post()` bumps the revision FIRST, then appends the record. That ordering guarantees readers who see the new revision can always find the corresponding record (no race where revision is ahead of the log).
51
+
52
+ **Channel scope (worktree- and clone-independent):** resolve the channel through `scripts/rally_point/discovery_bridge.resolve(workdir)`. Native `agent-rally-point` discovery returns the canonical shared channel (currently `~/.agent-rally-point/apps/<repo-id>/`). The embedded build-loop fallback also defaults to `~/.agent-rally-point/apps/<slug>/`, where `slug` comes from `git rev-parse --git-common-dir` via `scripts/rally_point/channel_paths.app_slug(cwd)`. The main checkout, every worktree, and every clone of the same canonical repo share ONE channel. Different canonical repos get different channel directories (cross-repo isolation).
53
+
54
+ **Anti-pattern (silent no-op):**
55
+
56
+ ```python
57
+ # Never do this — readers' checkpoint_read returns changed: false
58
+ from scripts.rally_point.changes import append_change
59
+ append_change(channel_dir, record) # forgot bump_revision; record invisible
60
+ ```
61
+
62
+ Memory citation: `feedback_post_helper_prevents_revision_bump_bug`.
63
+
64
+ ---
65
+
66
+ ## Trust model (unauthenticated channel; advisory leadership lease)
67
+
68
+ **The coordination channel is unauthenticated and trusted-local-peers-only.** `changes.jsonl`, `presence/`, `rally/lead.json`, and the coordination markdown all live under the channel returned by `discovery_bridge.resolve(workdir)` with ordinary user-account file permissions. Any process running as the same local user can append a change record, write a presence file, or claim/transfer the leadership lease. There is no signing, no authentication, and no identity verification — and there should not be: build-loop is a local single-user developer tool, so a cryptographic trust layer would be disproportionate to the threat.
69
+
70
+ What this means in practice:
71
+
72
+ - **Change-record payloads are untrusted free text.** A buggy or hostile channel writer can put arbitrary text — including prompt-injection content — into a `payload` field. Records flow into orchestrator LLM context via `checkpoint_read` `new_changes[]` and `coordination_status` `new_changes` / `open_escalations`. **Mitigation (SEC-002):** the consume boundary sanitizes every record before surfacing — `scripts/rally_point/checkpoint.sanitize_change_for_surface()` keeps only known structured metadata keys and length-caps every free-text string. The raw `changes.jsonl` log stays immutable and untouched; only the *surfaced projection* is sanitized. Reactions (`dep-change`, `arch-scan-complete`, `soft-claim`) are derived from raw records first, because they read only the structured `kind` field.
73
+
74
+ - **The leadership lease is advisory coordination, not access control (SEC-003).** Every mutating call in `scripts/rally_point/leadership.py` (`claim_lead`, `renew_lease`, `transfer_lead`, `relinquish_lead`) trusts a caller-supplied `session_id`. `claim_lead` succeeds for anyone whenever the lease is absent or expired; `renew`/`transfer`/`relinquish` "authorize" only by string-matching `session_id` against the world-readable `lead.json`. Any local process that reads `lead.json` learns the incumbent's `session_id` and can forge a renew, transfer, or relinquish. **The orchestrator MUST NOT gate an irreversible action on a lead claim** — a lead claim answers "who is coordinating" for cooperating peers, not "who is authorized". The proportionate control is observability: every `claim_lead` / `transfer_lead` / `relinquish_lead` emits a stderr audit line (`[rally-point audit] ...`) recording the requesting tool and `run_id`, in addition to the durable `lead-*` record in `changes.jsonl`, so an unexpected lease mutation is visible after the fact.
75
+
76
+ Threats this model does NOT cover (out of scope by design): a hostile process running as the same user, a compromised local account, or a multi-tenant host. Those are the operating system's responsibility, not the coordination channel's.
77
+
78
+ ---
79
+
80
+ ## Cheap detection at step boundaries
81
+
82
+ **Poll `coordination_status.py` BEFORE any step-boundary decision.** Costs ~100 tokens; prevents stale-state recommendations that cost full plan rewrites (~5K tokens).
83
+
84
+ ```bash
85
+ python3 scripts/coordination_status.py \
86
+ --workdir . \
87
+ --session-id <my-session-id> \
88
+ --owned-file <path>... \
89
+ --coordination-file .build-loop/coordination/<active-coord-file>.md \
90
+ --json
91
+ ```
92
+
93
+ **Always pass `--coordination-file` explicitly.** The default-pick heuristic resolves to safe candidates (active.json pointer → oldest `audit-execution-*.md` → oldest direct markdown), but explicit beats implicit. Fresh handoff stubs are often newer than the run ledger they point at; relying on default-pick has misfired before.
94
+
95
+ **Step-boundary triggers (poll BEFORE each):**
96
+
97
+ 1. Recommending next steps to the user.
98
+ 2. Dispatching a subagent.
99
+ 3. Committing (any commit).
100
+ 4. Bumping plugin version.
101
+ 5. Archiving / deleting files.
102
+ 6. Editing a shared / no-touch-zone file.
103
+ 7. Transitioning a step from `verification-pending` to `done`.
104
+ 8. Declaring a self-recursive runtime-changing stage ready for the next stage
105
+ after a dogfood reload checkpoint.
106
+
107
+ Between triggers, no polling is needed only when there is no active peer, no
108
+ active coord file, and no tool inbox message. When a host is waiting on an
109
+ async peer response, has an active peer, or has an inbox message, keep a cheap
110
+ watcher running:
111
+
112
+ ```bash
113
+ python3 scripts/coordination_watch.py --workdir "$PWD" --session-id "$SESSION_ID" --tool "$TOOL_NAME" --interval 5 --jsonl --baseline-current
114
+ ```
115
+
116
+ For long-running task ownership, write a task heartbeat at task start and at
117
+ least every 10 minutes:
118
+
119
+ ```bash
120
+ python3 scripts/agent_rally.py heartbeat --workdir "$PWD" --session-id "$SESSION_ID" --tool "$TOOL_NAME" --task-ref "$TASK_REF" --progress "still on task" --json
121
+ ```
122
+
123
+ Then pass `--task-ref "$TASK_REF"` to `status` or `watch`. Presence only says
124
+ the session is live; task heartbeat says whether it is still on the claimed
125
+ task and when the next check-in is due.
126
+
127
+ For self-recursive runtime-changing stages, use
128
+ `scripts/dogfood_reload_checkpoint.py` and
129
+ `references/dogfood-reload-checkpoint.md`. A Rally handoff or inject is not reload proof.
130
+ Each participating terminal must ACK runtime root + commit, or
131
+ the live agent must record a fallback (`reassign`, `defer`, or
132
+ `continue_solo`) before continuing.
133
+
134
+ Use stable tool ids (`claude_code`, `codex`, `cursor`, etc.) so targeted
135
+ `inbox/<tool>.jsonl` messages route cleanly. Broadcast messages live in
136
+ `inbox/all.jsonl`; every tool's read path includes that file in addition to
137
+ its direct inbox. Unread counts are session-ack aware: after reading and acting
138
+ on current inbox payloads, run `agent_rally.py ack-inbox --session-id <id>
139
+ --tool <tool>` so resolved notes stop appearing as new doorbells. Status
140
+ `clear` → proceed; status `warn` → review peer
141
+ overlap + dirty files; status `blocked` → resolve unresolved verdicts before
142
+ any of the above. Memory citation:
143
+ `feedback_poll_channel_at_step_boundaries`, `feedback_script_first_coordination_checks`.
144
+
145
+ ## Peer liveness & orphaned lanes (never wait on an idle peer)
146
+
147
+ **An interactive CLI peer (Codex, Cursor, a peer Claude terminal) is NOT a daemon.** It acts only within a turn its user prompts, then idles awaiting the next input — it does **not** autonomously poll this channel and resume. A handoff to such a peer therefore executes only when its user next drives that terminal; it may sit unread indefinitely. Do not model a CLI peer as a continuously-running worker.
148
+
149
+ **Liveness rule:** treat a peer with no channel activity for **>10 minutes while it owns an open handoff lane** as *idle* (silent ≠ dead, but ≠ progressing). Detect via the peer's last `recorded_at` in `changes.jsonl` vs now; a clean `stop`/`relinquish` also means idle.
150
+
151
+ **Orphaned-lane absorption:** when a lane assigned to an idle peer is **local and reversible** (commits, doc/agent edits, dead-code or dead-key trims, version bumps, test updates), the live agent **absorbs it** — does the work itself, then records in the report `absorbed <peer>'s idle lane: <what> [<evidence>]`. Do **not** block a release, a finish, or "done" on an idle peer's local lane — that is the same manufactured wait as a turn-length stop (see `skills/build-loop/SKILL.md` §"Keep going until done"). Only surface/hold a lane that is genuinely **peer-exclusive**: needs the other vendor's model (true cross-vendor review), the peer's environment/credentials, or an irreversible action only that peer is authorized to take. Coordination is cooperative, not a dependency that can deadlock the live agent.
152
+
153
+ ## Idle-agent self-selection (rally facilitates, the agent decides)
154
+
155
+ **Rally is a facilitator, not an orchestrator.** It exposes room state (`rally room` / `rally next`), file-level deconfliction (`rally check before-write --path P`), and claims/handoffs. It does **not** assign or pick work. A waiting agent runs this decision tree itself and chooses — the agent's LLM reasons over rally's surfaced state. This keeps coordination decentralized: no single point that hands out tasks (which would be a failure site and a bottleneck).
156
+
157
+ When an agent is idle and `rally next` returns no actionable item, walk the tree top-down, stop at the first match:
158
+
159
+ 1. **Pending handoff/inject addressed to me** (by session, name, or tool) → handle it, record the response, then run `ack-inbox`.
160
+ 2. **An open blocker I can resolve** → resolve it; post the resolution.
161
+ 3. **A no-regret item is free** → pick from the project's no-regret backlog (`.build-loop/followup/`, deferred-but-safe items, the run's recorded follow-ups). For its files, run `rally check before-write --path <each>`; if clear, `claim` them, `say` what you're starting, then do it. Reversible + behavior-preserving + tests-pass only.
162
+ 4. **All coding candidates are claimed or conflicted** → do read-only research or assessment that helps and has zero file conflict (simplification scans of untouched areas, duplication/test-gap audits, docs the room needs).
163
+ 5. **Nothing fits, or the only work left is risky/deferred/peer-exclusive** → stay idle and say so; do not start risky/deferred work, do not touch another session's claimed paths.
164
+
165
+ The tree is the guideline; rally supplies the facts (claims, collisions, pending items) each branch needs. Two same-tool agents running it independently land on different work because claim-first + `check before-write` makes the first claimant win and the second re-select — no central referee required.
166
+
167
+ ## Coordination reliability (verify the room before trusting it)
168
+
169
+ Room resolution can shift under you — a binary update, a repo-keying change, or a worktree path can move which channel you resolve to. Before concluding "no peers" or "empty room", verify it:
170
+
171
+ - **Check which channel you actually resolved.** If `rally enter` / `rally room` returns a null or empty channel, your *read* is suspect, not the room. A peer you "can't see" is often in a **different room** (different repo slug, or pre/post a keying change), not absent. Confirm the channel's `repo_root` (in `rally.channel.json`) matches the repo you mean.
172
+ - **One repo = one room** (keyed off the canonical repo root, shared by all worktrees); **different repos = different rooms**, correctly. Before declaring a peer missing, confirm you are both keyed to the same repo root — two agents in sibling repos (e.g. `build-loop` vs the spun-out `agent-rally-point`) are *supposed* to be in separate rooms.
173
+ - **A lead that posted then went quiet is idle** (same as any interactive CLI peer — see §Peer liveness). Do not block on it; absorb local lanes, leave a relay for its return.
174
+ - **Never hand-append the hash-chain channel files** (`changes.jsonl`) to "reach" a peer — corruption risk. If the CLI cannot post, relay out-of-band; do not edit the chain.
175
+
176
+ ## Room-policy reconciliation (mission / envelopes vs dispatch brief)
177
+
178
+ Named failure (2026-06-09, agent-rally-point): two orchestrator runs hit the same in-room mission guardrail ("No push to origin without Tyrone go") and split — one pushed past it without addressing it; the other held a finished build at push time even though the line was stale (superseded in practice by five operator-approved pushes). The rule below makes the reconciliation explicit and early.
179
+
180
+ - **Read room policy at entry.** After `rally enter`/`ack`, read the room mission and this agent's autonomy envelope (`rally mission --json`) and reconcile them against the dispatch brief's authorizations for gated actions (push, deploy, destructive).
181
+ - **Surface conflicts at Phase 1, not at push time.** A mission/brief conflict on a gated action is posted on-channel as a decision-needed fact AND returned to the dispatcher immediately — never first discovered after the work is done.
182
+ - **Precedence when reconciling:** newer ledger decision facts supersede older mission text; a per-agent autonomy envelope `may` grant covers its named action; an operator-attributed decision fact satisfies a "without <operator> go" guardrail. Operator-attributed means posted by the operator or from an operator-present interactive session — a subagent cannot mint its own go signal by posting a decision fact mid-run.
183
+ - **Genuine conflict after checking all three → hold the gated action and surface.** Holding is the correct terminal behavior; the failure mode this rule removes is holding late.
184
+
185
+ ---
186
+
187
+ ## MECE Packets (briefs require all seven; rally packets six + optional 7th)
188
+
189
+ **Every implementation handoff to a peer MUST spell out seven elements: `owns / does-not-own / interface-contract / integration-checkpoint / allowed-tools / denied-tools / acceptance-criteria`. The hard seven-field lint applies to dispatch BRIEFS (`brief_mece_validator.py`); rally `kind=handoff` ownership packets require the six structural fields (`mece_gate.py`) and validate `acceptance_criteria` when present — bootstrap/presence posts are not delegations and may omit it.** Anything less is "informational handoff" — produces drift, two writers on the same file, ambiguous "done" definitions.
190
+
191
+ | Element | What it answers | Example |
192
+ |---|---|---|
193
+ | **Owns** | Which files/scopes may the peer write? | `scripts/coordination_status.py`, `scripts/test_coordination_status.py` |
194
+ | **Does not own** | Which files/scopes must the peer NOT touch? | any agent body; any coord-file content |
195
+ | **Interface contract** | What shape does the deliverable take? (schema, format, exit code, location) | CLI `--json` returns `{status, latest_verdicts, ...}`; exit 0 clear / 1 warn / 2 blocked |
196
+ | **Integration checkpoint** | How does Claude verify the handoff landed and how does it plug back in? | regression test passes; orchestrator parses returned JSON; entry appears in coord file |
197
+ | **Allowed tools** | Which tools may the peer use? (empty list = no restriction) | `["Bash", "Read", "Edit"]` or `[]` |
198
+ | **Denied tools** | Which tools must the peer NOT use? (empty list = no restriction) | `["WebSearch"]` or `[]` |
199
+
200
+ Both `allowed-tools` and `denied-tools` MUST be present on every `kind=handoff` post; either MAY be an empty list. An empty `allowed_tools` is a valid explicit "no lateral limits" declaration — only a missing or non-list field is rejected by `mece_gate.validate_handoff`. These fields are the G2 lateral-limits feature (`feat(rally): tool-level lateral limits on handoff packets`, 2026-05-22).
201
+
202
+ **Enforcement:** `python3 scripts/brief_mece_validator.py --brief-file <path> --json`. Exit 0 → all seven present (briefs). Exit 1 → at least one missing; orchestrator surfaces a `[warn]` and may still dispatch (C-FLOW pattern — non-blocking lint). The orchestrator wires this lint into every `Agent(subagent_type=..., ...)` dispatch site for peer-handoff briefs.
203
+
204
+ **Carve-out:** pure-read handoffs ("go look at this and tell me what you find") skip MECE. All write-handoffs need all seven. Memory citation: `feedback_handoffs_require_mece_packets`.
205
+
206
+ ---
207
+
208
+ ## Verification of release surface
209
+
210
+ **Verifying a release means checking the release surface end-to-end, not just local files.** Manifest edited locally + test passing locally proves nothing about what shipped. The release surface includes seven checks:
211
+
212
+ 1. **Manifests show target version** — every file the manifest test enforces (`.claude-plugin/plugin.json`, `.codex-plugin/plugin.json`, `.claude-plugin/marketplace.json` `metadata.version` + `plugins[name=<plugin>].version` for RossLabs-ecosystem plugins). See [Three-file lockstep](#three-file-lockstep-plugin-manifest) below.
213
+ 2. **Manifest test exits 0** — `python3 scripts/test_plugin_manifest.py` (or the plugin's equivalent).
214
+ 3. **Local commit log matches expected pattern** — `git log --oneline -1` shows the expected commit message shape and SHA.
215
+ 4. **Local tag exists** — `git tag --list <tag>` returns the tag.
216
+ 5. **Branch HEAD SHA matches commit SHA** — `git rev-parse <branch>` == commit SHA.
217
+ 6. **Remote refs at same SHA** (load-bearing) — `git ls-remote origin <branch> <tag>` shows BOTH refs at the same SHA. Without this, a passing local verification can ship nothing (silent push failure, wrong remote, branch protection block).
218
+ 7. **(Optional) Fresh-session load test** — `claude plugin refresh` + cache diff vs canonical returns empty.
219
+
220
+ **Enforcement:** `python3 scripts/verify_release_surface.py --version <vN.N.N> --branch <name> --remote origin --json`. Returns structured JSON with per-check pass/fail + evidence; exit 0 if all pass, 1 if any fail. Verifier (Codex, CI, second Claude session) calls this instead of running the seven commands manually. Memory citation: `feedback_verification_checks_release_surface`.
221
+
222
+ ### Three-file lockstep (plugin manifest)
223
+
224
+ Plugin version bumps in the RossLabs ecosystem update **three** files in lockstep, not two:
225
+
226
+ 1. `.claude-plugin/plugin.json` — `version` field.
227
+ 2. `.codex-plugin/plugin.json` — `version` field.
228
+ 3. `.claude-plugin/marketplace.json` — BOTH `metadata.version` AND `plugins[name=<plugin>].version`.
229
+
230
+ `scripts/test_plugin_manifest.py` enforces all three via `VersionShapeTests.test_codex_manifest_matches_plugin_name_and_version` and `test_marketplace_versions_match_plugin`. Two-file bumps fail the marketplace test.
231
+
232
+ **The test is the source of truth, not the prose.** Before drafting ANY version-bump brief, run `python3 scripts/test_plugin_manifest.py` first. Read failure messages to enumerate every enforced manifest. Build the file list from the test output, not from a docs paragraph that may undercount. Memory citation: `feedback_three_file_lockstep_plugin_manifest`. See also `skills/plugin-builder/SKILL.md` §"Dual-Host: Shipping to Claude Code AND Codex".
233
+
234
+ ---
235
+
236
+ ## Closeout hygiene
237
+
238
+ **A coordination run is not complete until all live processes, presence records, worktrees, and active coord files are explicitly cleaned up.** Stale heartbeats in the resolved Rally Point channel's `sessions/` directory and locked worktrees under `.build-loop/worktrees/` mislead the next run's peer-detection — Rally Point may report "active peer" for a dead process; `git worktree list` may show locked entries that block branch operations.
239
+
240
+ **Phase D closeout protocol (orchestrator runs by default at end of every run):**
241
+
242
+ 1. **Reap this run's session presence:** `scripts/rally_point/lifecycle.reap_my_sessions(channel_dir, my_session_id)`.
243
+ 2. **Stop watchers:** SIGTERM any `coordination_watch.py --interval N` processes started during the run.
244
+ 3. **Collapse branches and worktrees:** merge the winning/validated line(s) to `main` first (solo-on-main runs skip this — work is already on main), then call `scripts/collapse_run.py` as described in `agents/build-orchestrator.md` §"Phase D: Closeout" step 4. That step is the single source of truth for the collapse invocation, ordering, JSON-to-report wiring, and `createdRefs[]` lifecycle status updates.
245
+ 4. **Archive the coord file:** `mv .build-loop/coordination/<this-coord-file>.md .build-loop/coordination/archived/`. Not deletion — preserves the durable record while clearing the active queue.
246
+ 5. **Optional changes.jsonl rotation:** `scripts/rally_point/lifecycle.rotate_changes_log(channel_dir, max_mb=1, max_entries=500)` rotates when either threshold is exceeded.
247
+ 6. **Final post:** `post(kind="phase", payload={"phase": "run-closeout", ...})` signals to channel that this run is done; future readers know to skip its presence/changes when scoping.
248
+ 7. **Track in state:** `state.json.runs[N].closeout_status`.
249
+
250
+ The protocol is automated, not operator-discipline-dependent. Memory citation: `feedback_close_out_stops_the_watcher`.
251
+
252
+ ---
253
+
254
+ ## C-FLOW rules
255
+
256
+ **C-FLOW/no_ask_to_commit** — Completed, validated, build-loop-authorized work commits automatically; pausing to ask the user whether to commit is a workflow violation. Only push/deploy verdicts of `confirm` or `block` from `autonomy_gate.py` / `deployment_policy.py` stop the loop; routine commit advancement does not require confirmation.
257
+
258
+ **C-FLOW/no_ask_at_chunk_boundary** — The phrasing "want me to keep going?" / "should I continue with X next?" at a chunk boundary is a workflow violation when the items are same-shape and same-intent. Referenced from `skills/build-loop/SKILL.md`.
259
+
260
+ **C-HEAL/self_heal_safe_issues** — Self-heal is **both reactive and proactive**. **Reactive arm:** when build-loop encounters an error or crash from its own tooling, a hook, a script, a Bash command, or a build/test/lint failure; OR a quality or performance issue surfaced by any Review sub-step, self-review, fact-check, simplify, or efficiency scan — ROOT-CAUSE and FIX it, then continue. Classify via `scripts/classify_action.py`: SAFE → apply, verify (re-run failed action and relevant tests), commit, continue; RISKY → isolate to worktree-branch + log + continue main + surface in report; DECISION/PRODUCTION → surface/escalate. **Proactive arm:** during deep self-review (and any self-recursive build), the self-review/self-heal loop ALSO proactively simplifies build-loop's own code — reducing complexity, splitting oversized files, removing dead/duplicated logic, adding missing tests — driven by `self_review.py`'s `self_simplification[]` findings. The loop MAY author new skills and new scripts (new scripts require a colocated `test_<name>.py`). **MANDATORY SAFETY GATE for self-modifications:** any change to build-loop's own plugin repo or the `build-loop-memory` durable repo MUST pass `python3 scripts/self_mod_verify.py --scope auto --auto-revert` (`verdict: pass`) before commit; on `verdict: fail` the gate auto-reverts and the change is not committed. **Self-modifications execute — they do not stop the loop.** A self-modification that is part of the accepted plan (including edits to the gate, tests, or the self-improvement loop) executes behind the test-suite gate. Build-loop never halts a planned self-modification for human approval. Oversight is post-hoc: (a) self-modifying runs trigger an ADDITIONAL adversarial review (independent-auditor at build scope; the periodic deep self-review re-audits recent self-modifications) — non-blocking; (b) the end-of-run readback reports every self-modification and the additional-review findings. The loop stays on task and reports once, at the end. Structural/architectural self-modifications (new phase, changed contract, agent-role change) surface as DECISION, never auto-apply. Full gate protocol: `skills/build-loop/references/self-review.md` §"Self-modification of the restricted repo". Banned anti-pattern: bypassing a fixable error — `--no-verify`, xfail-ing a test, commenting out failing code, `|| true` on a real failure — when a SAFE root-cause fix exists. Workarounds allowed only when the fix classifies RISKY/DECISION/PRODUCTION or is genuinely infeasible; record both the workaround and the issue.
261
+
262
+ **C-RCA/root_cause_before_done** — Before any "done"/completion claim, investigate EVERY open issue — failed tests, loose ends, errors, warnings, minor issues — to ROOT CAUSE; none are left unaddressed. A surface/symptom patch is a violation. Use the debugging skills (`build-loop:debug-loop` / `root-cause-investigator` / `systematic-debugging`) and/or a **5-whys / causal-tree** analysis to determine the true cause AND how far it spans (same root cause affecting other sites → fix all of them). The fix MUST be **verified by another, independent subagent** (confirms root cause correctly identified, fix resolves it, no regression introduced) before "done." Both the investigation-before-done and the second-subagent verification are mandatory; the specific technique is the operator's choice. The second-subagent check reuses existing surfaces (`independent-auditor`, `fix-critique`, or a dispatched verifier) — no new agent. C-RCA pairs with C-HEAL: C-HEAL governs what to do when a SAFE error surfaces (reactive fix + proactive simplification); C-RCA mandates that the root cause is understood, the fix is durable, and a peer has confirmed both before the run closes. It also operationalizes the standing "attack over defense / always the durable fix / fix everything" preferences as a completion gate. The investigation-before-done and second-subagent verification are non-negotiable; the specific technique is the operator's choice. Referenced from `agents/build-orchestrator.md` §"Root cause before done" and `skills/build-loop/SKILL.md` §"Root cause before done".
263
+
264
+ ---
265
+
266
+ ## Quick-reference cross-index
267
+
268
+ | Rule | Canonical implementation |
269
+ |---|---|
270
+ | Operating rule (verdicts gating) | `scripts/coordination_status.py` `BLOCKING_VERDICTS` constant; coord file Operating Rule section |
271
+ | `post()` mandatory | `scripts/rally_point/post.py` (the helper itself) |
272
+ | Cheap detection at step boundaries | `scripts/coordination_status.py` + `scripts/coordination_watch.py` |
273
+ | MECE packets enforcement | `scripts/brief_mece_validator.py` + `agents/build-orchestrator.md` dispatch wrappers |
274
+ | Release-surface verification | `scripts/verify_release_surface.py` |
275
+ | Three-file lockstep enforcement | `scripts/test_plugin_manifest.py` `VersionShapeTests` |
276
+ | Closeout hygiene | `scripts/rally_point/lifecycle.py` + `scripts/collapse_run.py` + `agents/build-orchestrator.md` Phase D |
277
+ | Coord-file shape | `references/coordination-file-template.md` |
278
+
279
+ ---
280
+
281
+ ## When to update this file
282
+
283
+ This is a constitution, not a changelog. Edit only when a coordination rule itself changes — new operating rule, new enforcement script, retired pattern. Single-run details and step status belong in the per-run coordination file under `.build-loop/coordination/<topic>.md`, not here.
@@ -0,0 +1,112 @@
1
+ <!-- SPDX-FileCopyrightText: 2025-2026 Tyrone Ross, Jr <46267523+tyroneross@users.noreply.github.com> | SPDX-License-Identifier: Apache-2.0 -->
2
+
3
+ # Dogfood Reload Checkpoint
4
+
5
+ Use a reload checkpoint whenever build-loop changes the runtime that active
6
+ agents are using. The checkpoint makes the run stop at a safe boundary, reload
7
+ or restart onto the validated build, prove runtime identity, then continue from
8
+ Rally.
9
+
10
+ ## Trigger
11
+
12
+ Run the checkpoint after a validated stage touches any runtime surface:
13
+
14
+ - `skills/*/SKILL.md`, `agents/*.md`, `commands/*.md`, hooks, plugin manifests,
15
+ MCP config, or plugin install/cache/version behavior.
16
+ - Rally Point integration, watcher/status/heartbeat code, leadership, inbox, or
17
+ room resolution behavior.
18
+ - Memory ingestion/recall/bootstrap/research-trigger paths.
19
+ - Self-recursive detector, per-commit mode, or self-modification safety gates.
20
+
21
+ Do not force a reload checkpoint for ordinary app code or docs that do not
22
+ change the running build-loop runtime.
23
+
24
+ Detect the surface first:
25
+
26
+ ```bash
27
+ python3 scripts/dogfood_reload_checkpoint.py detect \
28
+ --changed-file skills/build-loop/SKILL.md \
29
+ --changed-file scripts/rally_point/task_heartbeat.py
30
+ ```
31
+
32
+ ## Protocol
33
+
34
+ 1. Finish and validate the current stage.
35
+ 2. Create the checkpoint:
36
+
37
+ ```bash
38
+ python3 scripts/dogfood_reload_checkpoint.py create \
39
+ --workdir "$PWD" \
40
+ --checkpoint-id "reload-<commit>" \
41
+ --commit "<commit>" \
42
+ --branch "$(git rev-parse --abbrev-ref HEAD)" \
43
+ --changed-file "<runtime-file>" \
44
+ --expect-tool claude_code \
45
+ --expect-tool codex \
46
+ --instructions "Claude Code: restart with claude --plugin-dir <path-to>/build-loop; Codex: use source scripts from this checkout; run rally next/status after reload."
47
+ ```
48
+
49
+ 3. Post the checkpoint path and instructions to Rally using
50
+ `scripts/agent_rally.py handoff` or the native Rally CLI.
51
+ 4. Every participating terminal stops at the boundary, reloads/restarts, and
52
+ ACKs:
53
+
54
+ ```bash
55
+ python3 scripts/dogfood_reload_checkpoint.py ack \
56
+ --workdir "$PWD" \
57
+ --checkpoint-id "reload-<commit>" \
58
+ --tool codex \
59
+ --session-id "$SESSION_ID" \
60
+ --runtime-root "$PWD" \
61
+ --runtime-commit "$(git rev-parse --short HEAD)" \
62
+ --reload-method "source-checkout" \
63
+ --rally-next-status "proceed_solo"
64
+ ```
65
+
66
+ 5. Continue only when `status.ready == true`:
67
+
68
+ ```bash
69
+ python3 scripts/dogfood_reload_checkpoint.py status \
70
+ --workdir "$PWD" \
71
+ --checkpoint-id "reload-<commit>"
72
+ ```
73
+
74
+ If a terminal is unmanaged, stale, or cannot ACK, record the fallback instead
75
+ of waiting silently:
76
+
77
+ ```bash
78
+ python3 scripts/dogfood_reload_checkpoint.py fallback \
79
+ --workdir "$PWD" \
80
+ --checkpoint-id "reload-<commit>" \
81
+ --tool claude_code \
82
+ --decision continue_solo \
83
+ --reason "lead lease expired; no active peer in Rally status"
84
+ ```
85
+
86
+ Fallback decisions are limited to `reassign`, `defer`, or `continue_solo`.
87
+
88
+ ## Host Reload Boundaries
89
+
90
+ Claude Code:
91
+
92
+ - Working-tree dogfood path: `claude --plugin-dir <path-to>/build-loop`.
93
+ - `SKILL.md` edits may hot-reload with `/reload-plugins`.
94
+ - Hook, agent, command, MCP, and manifest changes require `/reload-plugins` or a
95
+ fresh session. Prefer a fresh session for self-recursive stage boundaries.
96
+
97
+ Codex / Rally:
98
+
99
+ - Use scripts from the source checkout when validating source-built behavior.
100
+ - Do not assume a globally installed `rally` or plugin cache is current.
101
+ - ACK with the source path, commit hash, and the result of the current
102
+ `agent_rally.py status` or `rally next --tool <tool> --json` check.
103
+
104
+ ## Report Requirement
105
+
106
+ Every self-recursive stage that changes runtime behavior states one of:
107
+
108
+ - `reload_checkpoint: ready` with checkpoint id, ACKed tools, runtime roots, and
109
+ commit.
110
+ - `reload_checkpoint: fallback` with the missing tool and fallback decision.
111
+ - `reload_checkpoint: not_required` with the detector output proving no runtime
112
+ surface changed.
@@ -0,0 +1,102 @@
1
+ <!-- SPDX-FileCopyrightText: 2025-2026 Tyrone Ross, Jr <46267523+tyroneross@users.noreply.github.com> | SPDX-License-Identifier: Apache-2.0 -->
2
+
3
+ # Halt-and-Ask Protocol (mode-aware decision handler)
4
+
5
+ _Linked from `agents/build-orchestrator.md` §Phase 3 Execute._
6
+
7
+ C3's `attestation_lint.py` and C4's `synthesis-critic` cover most synthesis-class drift. **Architectural-class decisions** (where a phase lives, defensive contract shape, error-propagation policy, persistence boundary, hard-fail/retry counters, etc.) fall outside both — the lint has nothing to grep for, and the critic only fires on UI files. This protocol catches those via mode-aware routing: implementers return `status: "blocked"` with `novel_decisions[]` populated, and the orchestrator either auto-picks (long-mode) or surfaces the trade-off table (normal-mode) — escalating to the operator only when the implementer signals low confidence.
8
+
9
+ This branch fires at envelope-receive time, **before** the commit step (`references/single-writer-commit-protocol.md`). If `status: "blocked"`, you do NOT enter the commit step at all on this iteration — there's nothing to commit yet.
10
+
11
+ **Trigger**: implementer envelope arrives with `status: "blocked"` AND `novel_decisions[]` non-empty (or any envelope with `novel_decisions[]` non-empty, when the do/branch/surface policy is active).
12
+
13
+ ## Mode resolution
14
+
15
+ Before processing the decision, the orchestrator resolves the current run's mode from `state.execution.budget`:
16
+
17
+ | Mode | Trigger | Effect |
18
+ |---|---|---|
19
+ | **long** | `--long` flag, `--budget >= 4h`, or `overnight` keyword in goal | Auto-pick `recommended_default`; log to `autonomousDefaults[]`; continue |
20
+ | **normal** | Default (2h budget, no long-mode trigger) | Surface trade-off table to operator; wait |
21
+ | **forced-escalate** | `novel_decisions[i].confidence == "low"` | Surface trade-off table even in long-mode |
22
+
23
+ The mode resolution is deterministic; the implementer's `confidence` field is the only thing that can override long-mode → normal-mode behavior.
24
+
25
+ ## Procedure (per blocked envelope)
26
+
27
+ 1. **Validate the envelope schema.** Every `novel_decisions[i]` MUST have `decision_id`, `options` (non-empty), `recommended_default` (matching one of `options[].id`), `confidence` (`high|med|low`), and per-option `user_impact`/`performance`/`speed`/`cost` (non-empty, not `"n/a"`). Schema violations route to Iterate with the implementer asked to fill in the trade-off fields; do NOT enter the resolution loop with a malformed envelope.
28
+
29
+ 2. **Classify via `scripts/classify_action.py`** with the envelope passed in. The classifier returns `DECISION` plus a `decision_state` of `pickable`, `low_confidence`, or `malformed`. Branch on state:
30
+ - `pickable` → proceed to step 3 (mode-aware routing)
31
+ - `low_confidence` → force-escalate (step 4) regardless of mode
32
+ - `malformed` → route to Iterate (step 1 caught most cases; this is the belt-and-braces)
33
+
34
+ 3. **Mode-aware routing for `pickable` decisions.**
35
+
36
+ **Long-mode (`state.execution.budget.mode in {long, custom, overnight}`):**
37
+ - For each `novel_decisions[i]`, take `recommended_default` as `chosen`.
38
+ - Append to `state.json.runs[].autonomousDefaults[]` via `scripts/log_decision.py --kind autonomous_default`.
39
+ - Emit terminal log: `[auto-pick] decision=<id> chose=<chosen> confidence=<level> rationale="<one-line>"`.
40
+ - Re-dispatch the implementer with `resolved_decisions:` containing each pick (same shape as the legacy path).
41
+ - **Do not** dispatch a Thinking-tier resolver. The implementer already articulated the trade-offs; auto-pick honors that.
42
+
43
+ **Normal-mode:**
44
+ - Surface the trade-off table to the operator via `AskUserQuestion` with one row per option showing `user_impact`, `performance`, `speed`, `cost`.
45
+ - The operator's pick is logged to `autonomousDefaults[].escalated: true` so the audit trail captures human-in-the-loop decisions identically.
46
+ - Re-dispatch with the operator's pick as the resolution.
47
+
48
+ 4. **Force-escalate for `low_confidence`.** Even in long-mode, surface the trade-off table to the operator. The implementer is signaling "I cannot pick well" — that's a real ask, not a procedural pause. Logged with `escalated: true` and `reason: "low_confidence"`.
49
+
50
+ 5. **Hard-fail counter (N=3) — preserved for backwards compatibility.** If the same `decision_id` returns as `novel_decisions[]` three times in a row (auto-pick or operator-pick didn't resolve it), surface as `❓ Unfixed` in Review-G with the unresolved decisions logged to `state.json.novelDecisionUnresolved[]`. The counter is per-chunk per-decision; reaching it indicates either the implementer's recommended_default is genuinely wrong or the plan needs revision.
51
+
52
+ 6. **Persist resolutions.** Continue to write `state.json.novelDecisionResolutions[]` for forensic compatibility:
53
+ ```json
54
+ {
55
+ "chunk_id": "<from plan>",
56
+ "decision_id": "<from envelope>",
57
+ "attempt": <1|2|3>,
58
+ "decision": "<verbatim from novel_decisions[]>",
59
+ "implementer_reasoning": "<verbatim>",
60
+ "resolution": "<chosen option id + summary>",
61
+ "rationale": "<from implementer.recommended_default reasoning OR operator pick>",
62
+ "resolved_by": "auto_pick | operator | tier:thinking_fallback",
63
+ "resolved_at": "<iso8601>"
64
+ }
65
+ ```
66
+
67
+ 7. **Re-dispatch the implementer** with the **same brief** plus an appended `resolved_decisions:` block containing every resolution generated for this chunk. The implementer applies the resolutions as if they had been part of the plan's `synthesis_dimensions` from the start, and attests against them in the next envelope's `synthesis_attestation`.
68
+
69
+ 8. **Loop**. The next envelope can return:
70
+ - `status: "completed"` / `"fixed"` / `"partial"` → proceed to the commit step (`references/single-writer-commit-protocol.md`).
71
+ - `status: "blocked"` again with **new** `novel_decisions[]` → repeat from step 1. Per-decision counter increments. At N=3, surface as ❓ Unfixed.
72
+ - Any other failure status → route per the standard commit step's failure handling.
73
+
74
+ ## Legacy Thinking-tier resolver fallback
75
+
76
+ The pre-mode-aware version of this protocol dispatched a Thinking-tier resolver via `Agent(subagent_type: "build-loop:build-orchestrator", ...)` for every novel decision. That path remains as a **fallback** when:
77
+ - The implementer cannot articulate a `recommended_default` (malformed envelope, attempt 1 only; orchestrator re-dispatches asking for the missing field).
78
+ - An operator escalation in normal-mode is interrupted before the operator responds (resume contract).
79
+
80
+ When the fallback fires, `resolved_by: "tier:thinking_fallback"` and the resolver returns the same `{"resolution", "rationale", "alternatives_rejected"}` shape as before. Model routing is unchanged from the legacy doc (see "Routing is `tier: thinking`" below).
81
+
82
+ ## No new dependencies
83
+
84
+ This is a status-branch addition to the existing await-implementer dispatch, not a new runtime. The orchestrator already awaits implementer envelopes; `blocked` is just one more value to switch on. Do NOT introduce LangGraph, a state machine library, or any new event loop. The existing `Agent(...)` dispatch + envelope parsing is the substrate.
85
+
86
+ ## State writes touched by this branch
87
+
88
+ - `state.json.runs[].autonomousDefaults[]` — per-decision auto-picks with full trade-off context (NEW; written by `scripts/log_decision.py`)
89
+ - `state.json.novelDecisionAttempts[<chunk_id>:<decision_id>]` — per-decision counter (≤3 attempts before ❓ Unfixed)
90
+ - `state.json.novelDecisionResolutions[]` — durable resolution log (preserved for backward compat)
91
+ - `state.json.novelDecisionUnresolved[]` — entries that exhausted N=3
92
+
93
+ ## Telemetry
94
+
95
+ Per auto-pick: `[auto-pick] decision=<id> chose=<chosen> confidence=<level> mode=<long|normal> rationale="<short>"`.
96
+ Per operator escalation: `[escalate] decision=<id> reason=<low_confidence|normal_mode> options=<count>`.
97
+ Per re-dispatch: `[redispatch] chunk=<id> decision=<id> attempt=<n>/3 resolution="<short>"`.
98
+ On hard-fail: `[hard-fail] ❌ chunk=<id> decision=<id> exhausted 3 attempts — routing to ❓ Unfixed`.
99
+
100
+ ## Phase 3 UI spot-check (between chunks)
101
+
102
+ Extracted to `references/ui-spotcheck-protocol.md` for MECE separation — that file covers the `uiTouched` signal, dispatch shape, routing on return, iteration budget, skip conditions, and render-path fallback. UI spot-check and the C5 halt-and-ask branch share Phase 3 timing but no machinery — UI spot-check fires after successful commits on `uiTouched: true`, while halt-and-ask fires before commit on `status: blocked`.