@tyroneross/build-loop 0.36.0 → 0.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/plugins/marketplace.json +2 -2
- package/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.cursor/rules/build-loop-surface.mdc +12 -11
- package/.cursor/rules/skill-index.mdc +33 -0
- package/AGENTS.md +213 -34
- package/README.md +99 -31
- package/agents/advisor.md +4 -4
- package/agents/alignment-checker.md +2 -2
- package/agents/architecture-scout.md +4 -4
- package/agents/build-orchestrator.md +38 -36
- package/agents/database-assessor.md +11 -5
- package/agents/design-contract-specialist.md +8 -8
- package/agents/fact-checker.md +13 -3
- package/agents/fix-critique.md +2 -2
- package/agents/independent-auditor.md +60 -7
- package/agents/leak-scanner.md +82 -0
- package/agents/overfitting-reviewer.md +2 -2
- package/agents/plan-critic.md +1 -1
- package/agents/promotion-reviewer.md +5 -5
- package/agents/retrospective-synthesizer.md +138 -35
- package/agents/scope-auditor.md +82 -11
- package/agents/security-reviewer.md +56 -2
- package/agents/self-improvement-architect.md +17 -3
- package/agents/transcript-pattern-miner.md +5 -5
- package/agents/ui-validator.md +1 -1
- package/bin/build-loop-debugger.js +143 -0
- package/bin/build-loop-install.js +1 -4
- package/bin/build-loop-load-probe.js +345 -0
- package/codex-skills/build-loop/SKILL.md +28 -6
- package/commands/feedback.md +37 -0
- package/dist/src/interactive-verifier.d.ts +1 -14
- package/dist/src/interactive-verifier.d.ts.map +1 -1
- package/dist/src/interactive-verifier.js +6 -113
- package/dist/src/interactive-verifier.js.map +1 -1
- package/dist/src/quality.d.ts +5 -0
- package/dist/src/quality.d.ts.map +1 -0
- package/dist/src/quality.js +81 -0
- package/dist/src/quality.js.map +1 -0
- package/dist/src/storage.d.ts.map +1 -1
- package/dist/src/storage.js +37 -3
- package/dist/src/storage.js.map +1 -1
- package/docs/agent-surface-policy.md +35 -31
- package/docs/memory-setup.md +19 -0
- package/hooks/git/pre-push +65 -4
- package/hooks/hooks.json +95 -38
- package/hooks/pre-commit +20 -1
- package/hooks/pre-edit-rally-point.sh +10 -3
- package/hooks/session-start-codex-hook-trust.sh +30 -0
- package/hooks/session-start-git-hooks.sh +3 -1
- package/hooks/session-start-rally-point.sh +52 -4
- package/hooks/session-start-worktree-gc.sh +47 -94
- package/hooks/stop-transcript-sweep.sh +173 -0
- package/hooks/test_closeout.sh +14 -2
- package/package.json +8 -7
- package/scripts/README.md +1 -1
- package/scripts/_paths.py +65 -0
- package/scripts/groundwork_exchange.py +1012 -0
- package/scripts/install_memory.py +33 -1
- package/scripts/lessons_index/ingest.py +13 -2
- package/scripts/lessons_index/query.py +36 -13
- package/scripts/memory_context/__init__.py +108 -14
- package/scripts/memory_graph/__init__.py +5 -1
- package/scripts/project_resolver.py +42 -36
- package/scripts/sync_plugin_cache.py +37 -2
- package/skills/agent-rally-point/SKILL.md +46 -0
- package/skills/api-registry-bridge/SKILL.md +1 -1
- package/skills/architecture/dead/SKILL.md +1 -1
- package/skills/architecture/impact/SKILL.md +1 -1
- package/skills/architecture/review/SKILL.md +1 -1
- package/skills/architecture/rules/SKILL.md +3 -3
- package/skills/architecture/scan/SKILL.md +1 -1
- package/skills/architecture/trace/SKILL.md +1 -1
- package/skills/attribution-standard/SKILL.md +6 -6
- package/skills/auto-decision-capture/SKILL.md +31 -2
- package/skills/auto-finding-capture/SKILL.md +28 -1
- package/skills/build-loop/SKILL.md +131 -23
- package/skills/build-loop/fallbacks.md +16 -21
- package/skills/build-loop/phases/ui-validation.md +2 -2
- package/skills/build-loop/references/advisor-dispatch-ladder.md +1 -1
- package/skills/build-loop/references/apple-native-planning.md +1 -1
- package/skills/build-loop/references/autonomous-and-per-commit-modes.md +11 -5
- package/skills/build-loop/references/autonomy-dashboard.md +115 -0
- package/skills/build-loop/references/capability-routing.md +24 -2
- package/skills/build-loop/references/coordination.md +24 -6
- package/skills/build-loop/references/experiment-results-template.md +15 -3
- package/skills/build-loop/references/leadership.md +1 -1
- package/skills/build-loop/references/memory.md +14 -3
- package/skills/build-loop/references/modular-systems-pack.md +8 -0
- package/skills/build-loop/references/output-style.md +86 -0
- package/skills/build-loop/references/phase-1-assess.md +102 -2
- package/skills/build-loop/references/phase-2-plan.md +9 -1
- package/skills/build-loop/references/phase-3-execute.md +5 -2
- package/skills/build-loop/references/phase-4-review.md +85 -8
- package/skills/build-loop/references/phase-5-iterate.md +76 -8
- package/skills/build-loop/references/phase-6-learn.md +10 -17
- package/skills/build-loop/references/privileged-request-broker.md +254 -0
- package/skills/build-loop/references/resource-aware-execution.md +183 -0
- package/skills/build-loop/references/self-recursive-dev.md +2 -2
- package/skills/build-loop/references/status-output-format.md +207 -0
- package/skills/build-loop/references/verify-dispatch.md +56 -2
- package/skills/building-with-deepagents/SKILL.md +1 -1
- package/skills/claim-scope/SKILL.md +185 -0
- package/skills/color-engine/SKILL.md +103 -0
- package/skills/color-engine/_core.py +464 -0
- package/skills/color-engine/color_engine.py +175 -0
- package/skills/cost-rca/SKILL.md +61 -0
- package/skills/data-plane-worktrees/SKILL.md +139 -0
- package/skills/data-plane-worktrees/agents/openai.yaml +4 -0
- package/skills/database-practice/SKILL.md +200 -0
- package/skills/database-practice/references/diagnostic-queries.sql +126 -0
- package/skills/database-practice/references/vector-and-graph-tuning.md +208 -0
- package/skills/database-practice/scripts/db_table_map.py +1244 -0
- package/skills/database-practice/scripts/test_db_table_map.py +514 -0
- package/skills/debug-loop/SKILL.md +36 -6
- package/skills/debugging-memory/SKILL.md +32 -430
- package/skills/debugging-memory/references/pattern-extraction.md +4 -4
- package/skills/debugging-memory/references/search.md +32 -120
- package/skills/debugging-memory/references/store.md +32 -126
- package/skills/debugging-memory/references/subagent-integration.md +1 -1
- package/skills/decision-queue/SKILL.md +251 -0
- package/skills/decision-queue/assets/template.html +1242 -0
- package/skills/decision-queue/references/example-large-queue-batching.md +164 -0
- package/skills/decision-queue/scripts/regen_template_constants.py +160 -0
- package/skills/defenseclaw-bridge/SKILL.md +2 -2
- package/skills/defenseclaw-bridge/references/dc-config-mapping.md +2 -9
- package/skills/drain-proposals/SKILL.md +53 -0
- package/skills/focused-loop-builder/SKILL.md +31 -0
- package/skills/focused-loop-builder/references/spec-format.md +27 -0
- package/skills/handoff/SKILL.md +169 -8
- package/skills/ibr-bridge/SKILL.md +4 -1
- package/skills/knowledge/SKILL.md +26 -14
- package/skills/knowledge/references/review-mode.md +2 -3
- package/skills/knowledge/templates/madr-minimal.md +1 -1
- package/skills/mcp-builder/SKILL.md +1 -1
- package/skills/model-bakeoff/SKILL.md +48 -10
- package/skills/model-tiering/SKILL.md +92 -31
- package/skills/native-ax-driver/SKILL.md +38 -5
- package/skills/native-ax-driver/scripts/native_driver.py +278 -22
- package/skills/native-ax-driver/scripts/test_native_driver.py +227 -0
- package/skills/optimize/SKILL.md +1 -1
- package/skills/plugin-builder/SKILL.md +48 -1
- package/skills/plugin-builder/references/build-loop-phase-guidance.md +3 -4
- package/skills/plugin-builder/references/distribution.md +13 -2
- package/skills/plugin-builder/references/plugin-hygiene-lessons.md +2 -2
- package/skills/plugin-tests/SKILL.md +2 -2
- package/skills/recursive-retrospective/SKILL.md +1 -1
- package/skills/repo-closeout/SKILL.md +17 -0
- package/skills/repo-closeout/agents/openai.yaml +4 -0
- package/skills/repo-maintenance/SKILL.md +179 -0
- package/skills/repo-maintenance/agents/openai.yaml +4 -0
- package/skills/repo-maintenance/references/pre-public-hygiene.md +134 -0
- package/skills/repo-maintenance/references/repository-taxonomy.md +161 -0
- package/skills/repo-maintenance/references/safety-protocol.md +106 -0
- package/skills/repo-maintenance/references/stack-profiles.md +138 -0
- package/skills/repo-maintenance/scripts/audit_repo_maintenance.py +1198 -0
- package/skills/repo-maintenance/scripts/test_audit_repo_maintenance.py +506 -0
- package/skills/repository-intelligence/SKILL.md +189 -0
- package/skills/repository-intelligence/agents/openai.yaml +4 -0
- package/skills/repository-intelligence/references/assessment-rubric.md +88 -0
- package/skills/repository-intelligence/scripts/repository_inventory.py +347 -0
- package/skills/research/SKILL.md +12 -2
- package/skills/root-cause-analysis/SKILL.md +1 -1
- package/skills/runtime-parity-verification/SKILL.md +36 -1
- package/skills/security-methodology/SKILL.md +23 -10
- package/skills/security-methodology/references/agentic-handoff-templates.md +220 -0
- package/skills/security-methodology/references/cross-source-matrix.md +1 -1
- package/skills/security-methodology/references/owasp-agentic-top-10.md +1 -1
- package/skills/security-scan/SKILL.md +55 -15
- package/skills/self-improve/SKILL.md +70 -50
- package/skills/silent-assumptions/SKILL.md +341 -0
- package/skills/silent-assumptions/references/elicitation-detectors.md +342 -0
- package/skills/spec-writing/SKILL.md +128 -24
- package/skills/spec-writing/scripts/check_checklist.py +114 -15
- package/skills/ui-design/SKILL.md +6 -4
- package/skills/ui-design/references/color-engine.md +132 -0
- package/skills/ui-design/references/design-preferences-from-owned-apps.md +8 -8
- package/skills/ui-design/references/ui-guidance-sources.md +1 -1
- package/skills/ui-design/references/universal-design-principles.alt.md +2 -2
- package/plugin-artifacts/codex/.codex-plugin/plugin.json +0 -41
- package/plugin-artifacts/codex/AGENTS.md +0 -560
- package/plugin-artifacts/codex/BUILD-ARTIFACT.md +0 -5
- package/plugin-artifacts/codex/LICENSE +0 -202
- package/plugin-artifacts/codex/README.md +0 -313
- package/plugin-artifacts/codex/assets/build-loop-plugin-icon.png +0 -0
- package/plugin-artifacts/codex/docs/agent-surface-policy.md +0 -63
- package/plugin-artifacts/codex/references/advisor-dispatch-ladder.md +0 -62
- package/plugin-artifacts/codex/references/agent-role-taxonomy.md +0 -135
- package/plugin-artifacts/codex/references/autonomous-and-per-commit-modes.md +0 -161
- package/plugin-artifacts/codex/references/autonomy-config.md +0 -231
- package/plugin-artifacts/codex/references/backlog-system.md +0 -285
- package/plugin-artifacts/codex/references/capability-routing.md +0 -231
- package/plugin-artifacts/codex/references/codex-subagents.md +0 -106
- package/plugin-artifacts/codex/references/coordination-file-template.md +0 -181
- package/plugin-artifacts/codex/references/coordination-rules.md +0 -552
- package/plugin-artifacts/codex/references/dogfood-reload-checkpoint.md +0 -112
- package/plugin-artifacts/codex/references/halt-and-ask-protocol.md +0 -102
- package/plugin-artifacts/codex/references/implementer-envelope-schema.md +0 -302
- package/plugin-artifacts/codex/references/intent-capability-pack.md +0 -257
- package/plugin-artifacts/codex/references/intent-exploration-prompts.md +0 -96
- package/plugin-artifacts/codex/references/leadership.md +0 -72
- package/plugin-artifacts/codex/references/memory-systems.md +0 -261
- package/plugin-artifacts/codex/references/memory.md +0 -313
- package/plugin-artifacts/codex/references/model-tier-mapping.md +0 -296
- package/plugin-artifacts/codex/references/modular-systems-pack.md +0 -96
- package/plugin-artifacts/codex/references/phase-1-assess.md +0 -249
- package/plugin-artifacts/codex/references/phase-2-plan.md +0 -86
- package/plugin-artifacts/codex/references/phase-3-execute.md +0 -49
- package/plugin-artifacts/codex/references/phase-4-review.md +0 -341
- package/plugin-artifacts/codex/references/phase-5-iterate.md +0 -72
- package/plugin-artifacts/codex/references/phase-6-learn.md +0 -58
- package/plugin-artifacts/codex/references/recent-design-structures.md +0 -274
- package/plugin-artifacts/codex/references/research-trigger-policy.md +0 -140
- package/plugin-artifacts/codex/references/runtime-smoke-triggers.md +0 -42
- package/plugin-artifacts/codex/references/self-review.md +0 -234
- package/plugin-artifacts/codex/references/single-writer-commit-protocol.md +0 -90
- package/plugin-artifacts/codex/references/task-capture-policy.md +0 -68
- package/plugin-artifacts/codex/references/ui-io-contract.md +0 -116
- package/plugin-artifacts/codex/references/ui-spotcheck-protocol.md +0 -65
- package/plugin-artifacts/codex/references/verify-dispatch.md +0 -85
- package/plugin-artifacts/codex/skills/build-loop/SKILL.md +0 -381
- package/plugin-artifacts/codex/skills/build-loop/detect-plugins.mjs +0 -82
- package/plugin-artifacts/codex/skills/build-loop/eval-guide.md +0 -65
- package/plugin-artifacts/codex/skills/build-loop/fallbacks.md +0 -549
- package/plugin-artifacts/codex/skills/build-loop/phases/fact-check.md +0 -42
- package/plugin-artifacts/codex/skills/build-loop/phases/ui-validation.md +0 -267
- package/plugin-artifacts/codex/skills/build-loop/references/advisor-dispatch-ladder.md +0 -62
- package/plugin-artifacts/codex/skills/build-loop/references/apple-native-planning.md +0 -439
- package/plugin-artifacts/codex/skills/build-loop/references/autonomous-and-per-commit-modes.md +0 -161
- package/plugin-artifacts/codex/skills/build-loop/references/capability-routing.md +0 -231
- package/plugin-artifacts/codex/skills/build-loop/references/codex-subagents.md +0 -106
- package/plugin-artifacts/codex/skills/build-loop/references/coordination.md +0 -161
- package/plugin-artifacts/codex/skills/build-loop/references/correction-aware-capture.md +0 -177
- package/plugin-artifacts/codex/skills/build-loop/references/experiment-results-template.md +0 -101
- package/plugin-artifacts/codex/skills/build-loop/references/independent-auditor.md +0 -72
- package/plugin-artifacts/codex/skills/build-loop/references/intent-capability-pack.md +0 -257
- package/plugin-artifacts/codex/skills/build-loop/references/intent-exploration-prompts.md +0 -96
- package/plugin-artifacts/codex/skills/build-loop/references/leadership.md +0 -72
- package/plugin-artifacts/codex/skills/build-loop/references/memory.md +0 -313
- package/plugin-artifacts/codex/skills/build-loop/references/modular-systems-pack.md +0 -96
- package/plugin-artifacts/codex/skills/build-loop/references/output-style.md +0 -222
- package/plugin-artifacts/codex/skills/build-loop/references/pay-it-forward-arch.md +0 -98
- package/plugin-artifacts/codex/skills/build-loop/references/phase-1-assess.md +0 -249
- package/plugin-artifacts/codex/skills/build-loop/references/phase-2-plan.md +0 -86
- package/plugin-artifacts/codex/skills/build-loop/references/phase-3-execute.md +0 -49
- package/plugin-artifacts/codex/skills/build-loop/references/phase-4-review.md +0 -341
- package/plugin-artifacts/codex/skills/build-loop/references/phase-5-iterate.md +0 -72
- package/plugin-artifacts/codex/skills/build-loop/references/phase-6-learn.md +0 -58
- package/plugin-artifacts/codex/skills/build-loop/references/recent-design-structures.md +0 -274
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/ASSESSMENT.md +0 -85
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/STANDALONE_TEST_RUN.md +0 -149
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/01-simple-bugfix.md +0 -32
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/02-ui-build-with-iteration.md +0 -48
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/03-multi-failure-escalation.md +0 -60
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/04-ui-build-ibr-absent.md +0 -51
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/05-refactor-navgator-absent.md +0 -71
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/06-recurring-bug-debugger-absent.md +0 -52
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/trace-comparison.md +0 -202
- package/plugin-artifacts/codex/skills/build-loop/references/self-recursive-dev.md +0 -77
- package/plugin-artifacts/codex/skills/build-loop/references/self-review.md +0 -234
- package/plugin-artifacts/codex/skills/build-loop/references/ui-io-contract.md +0 -116
- package/plugin-artifacts/codex/skills/build-loop/references/verify-dispatch.md +0 -85
- package/plugin-artifacts/codex/skills/build-loop/scanners/audit-design-rules.mjs +0 -476
- package/plugin-artifacts/codex/skills/build-loop/scanners/require-visual-evidence.mjs +0 -239
- package/plugin-artifacts/codex/skills/build-loop/templates/backlog-item.md +0 -35
- package/plugin-artifacts/codex/skills/build-loop/templates/codex-worker-prompt.md +0 -100
- package/plugin-artifacts/codex/skills/build-loop/templates/ui-subagent-prompt.md +0 -179
- package/plugin-artifacts/codex/skills/build-loop/templates/ux-fix-plan.md +0 -40
- package/scripts/build_codex_plugin_artifact.py +0 -321
|
@@ -1,552 +0,0 @@
|
|
|
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
|
-
**Rally's REAL CLI surface (the only commands build-loop shells out to).** Rally exposes `enter`, `say <kind>`, `whoami`, `room`, `next`, `recent`, `stop <session|name|tool>`, `sessions [--reap]`, `migrate-legacy`, `mission`, `version`, and `check`. It has NO `setup`, NO `post`, NO `start`, and NO `replay` — those were anticipated but never shipped, and a discovery tier that gated on them was dead code (removed). A write goes out as `rally say <kind> --json …` (build-loop's `post()` helper translates to this); identity/channel info comes from `rally whoami --json` (`repo_root`/`repo_id`/`worktree`/`build_id`/`cwd`), NOT a `setup` probe. The surface-acceptance check (`discovery_bridge._rally_binary_supports_required_surface`) is pinned to a real rally binary's `--help` by `scripts/test_discovery_bridge.py::RequiredSurfacePinnedToRealRallyTests`, so it can never silently drift back to a phantom surface. When adding a rally call, read the binary's real `--help` first; do not assume a command exists.
|
|
55
|
-
|
|
56
|
-
**Anti-pattern (silent no-op):**
|
|
57
|
-
|
|
58
|
-
```python
|
|
59
|
-
# Never do this — readers' checkpoint_read returns changed: false
|
|
60
|
-
from scripts.rally_point.changes import append_change
|
|
61
|
-
append_change(channel_dir, record) # forgot bump_revision; record invisible
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
Memory citation: `feedback_post_helper_prevents_revision_bump_bug`.
|
|
65
|
-
|
|
66
|
-
---
|
|
67
|
-
|
|
68
|
-
## Trust model (unauthenticated channel; advisory leadership lease)
|
|
69
|
-
|
|
70
|
-
**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.
|
|
71
|
-
|
|
72
|
-
What this means in practice:
|
|
73
|
-
|
|
74
|
-
- **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.
|
|
75
|
-
|
|
76
|
-
- **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.
|
|
77
|
-
|
|
78
|
-
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.
|
|
79
|
-
|
|
80
|
-
---
|
|
81
|
-
|
|
82
|
-
## Evidence boundary (Rally is not a verifier)
|
|
83
|
-
|
|
84
|
-
Rally records are peer-authored coordination metadata. They can tell an agent
|
|
85
|
-
what another agent claimed, handed off, reviewed, blocked, or released, and they
|
|
86
|
-
can point to artifacts worth inspecting. They do not prove the artifact, code,
|
|
87
|
-
package, tag, release, or remote state is correct.
|
|
88
|
-
|
|
89
|
-
Before making a factual claim about repo or release state, check the authoritative
|
|
90
|
-
surface directly:
|
|
91
|
-
|
|
92
|
-
- Code and docs: working tree, `git diff`, file contents, and tests.
|
|
93
|
-
- Package/version surface: manifests, package tests, dry-run pack/publish output,
|
|
94
|
-
and release-surface verifier scripts.
|
|
95
|
-
- Remote release state: GitHub/npm/GitHub Packages API or public pages, not a
|
|
96
|
-
Rally `release` or `artifact` record.
|
|
97
|
-
|
|
98
|
-
A Rally `artifact`, `release`, `resolve`, `review_artifact`, or `next` record is
|
|
99
|
-
a routing signal. It may identify what to inspect; it is never the inspection.
|
|
100
|
-
|
|
101
|
-
---
|
|
102
|
-
|
|
103
|
-
## Cheap detection at step boundaries
|
|
104
|
-
|
|
105
|
-
**Poll `coordination_status.py` BEFORE any step-boundary decision.** Costs ~100 tokens; prevents stale-state recommendations that cost full plan rewrites (~5K tokens).
|
|
106
|
-
|
|
107
|
-
```bash
|
|
108
|
-
python3 scripts/coordination_status.py \
|
|
109
|
-
--workdir . \
|
|
110
|
-
--session-id <my-session-id> \
|
|
111
|
-
--owned-file <path>... \
|
|
112
|
-
--coordination-file .build-loop/coordination/<active-coord-file>.md \
|
|
113
|
-
--json
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
**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.
|
|
117
|
-
|
|
118
|
-
**Step-boundary triggers (poll BEFORE each):**
|
|
119
|
-
|
|
120
|
-
1. Recommending next steps to the user.
|
|
121
|
-
2. Dispatching a subagent.
|
|
122
|
-
3. Committing (any commit).
|
|
123
|
-
4. Bumping plugin version.
|
|
124
|
-
5. Archiving / deleting files.
|
|
125
|
-
6. Editing a shared / no-touch-zone file.
|
|
126
|
-
7. Transitioning a step from `verification-pending` to `done`.
|
|
127
|
-
8. Declaring a self-recursive runtime-changing stage ready for the next stage
|
|
128
|
-
after a dogfood reload checkpoint.
|
|
129
|
-
|
|
130
|
-
Between triggers, no polling is needed only when there is no active peer, no
|
|
131
|
-
active coord file, and no tool inbox message. When a host is waiting on an
|
|
132
|
-
async peer response, has an active peer, or has an inbox message, keep a cheap
|
|
133
|
-
watcher running:
|
|
134
|
-
|
|
135
|
-
```bash
|
|
136
|
-
python3 scripts/coordination_watch.py --workdir "$PWD" --session-id "$SESSION_ID" --tool "$TOOL_NAME" --interval 5 --jsonl --baseline-current
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
For long-running task ownership, write a task heartbeat at task start and at
|
|
140
|
-
least every 10 minutes:
|
|
141
|
-
|
|
142
|
-
```bash
|
|
143
|
-
python3 scripts/agent_rally.py heartbeat --workdir "$PWD" --session-id "$SESSION_ID" --tool "$TOOL_NAME" --task-ref "$TASK_REF" --progress "still on task" --json
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
Then pass `--task-ref "$TASK_REF"` to `status` or `watch`. Presence only says
|
|
147
|
-
the session is live; task heartbeat says whether it is still on the claimed
|
|
148
|
-
task and when the next check-in is due.
|
|
149
|
-
|
|
150
|
-
For self-recursive runtime-changing stages, use
|
|
151
|
-
`scripts/dogfood_reload_checkpoint.py` and
|
|
152
|
-
`references/dogfood-reload-checkpoint.md`. A Rally handoff or inject is not reload proof.
|
|
153
|
-
Each participating terminal must ACK runtime root + commit, or
|
|
154
|
-
the live agent must record a fallback (`reassign`, `defer`, or
|
|
155
|
-
`continue_solo`) before continuing.
|
|
156
|
-
|
|
157
|
-
Use stable tool ids (`claude_code`, `codex`, `cursor`, etc.) so targeted
|
|
158
|
-
`inbox/<tool>.jsonl` messages route cleanly. Broadcast messages live in
|
|
159
|
-
`inbox/all.jsonl`; every tool's read path includes that file in addition to
|
|
160
|
-
its direct inbox. Unread counts are session-ack aware: after reading and acting
|
|
161
|
-
on current inbox payloads, run `agent_rally.py ack-inbox --session-id <id>
|
|
162
|
-
--tool <tool>` so resolved notes stop appearing as new doorbells. Status
|
|
163
|
-
`clear` → proceed; status `warn` → review peer
|
|
164
|
-
overlap + dirty files; status `blocked` → resolve unresolved verdicts before
|
|
165
|
-
any of the above. Memory citation:
|
|
166
|
-
`feedback_poll_channel_at_step_boundaries`, `feedback_script_first_coordination_checks`.
|
|
167
|
-
|
|
168
|
-
## Peer liveness & orphaned lanes (never wait on an idle peer)
|
|
169
|
-
|
|
170
|
-
**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.
|
|
171
|
-
|
|
172
|
-
**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.
|
|
173
|
-
|
|
174
|
-
**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.
|
|
175
|
-
|
|
176
|
-
## Recency decay & size-scaled lead/ownership auto-reclaim
|
|
177
|
-
|
|
178
|
-
A single coordination policy governs message aging and stale-claim reclaim,
|
|
179
|
-
mirrored from the canonical Rust implementation (agent-rally-point). Tunables
|
|
180
|
-
live under `coordinationPolicy` in `.build-loop/config.json` (defaults shown):
|
|
181
|
-
|
|
182
|
-
```json
|
|
183
|
-
{
|
|
184
|
-
"coordinationPolicy": {
|
|
185
|
-
"half_life_hours": 48,
|
|
186
|
-
"archive_floor_weight": 0.05,
|
|
187
|
-
"reclaim_small_minutes": 30,
|
|
188
|
-
"reclaim_large_minutes": 120
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
- **Recency decay (listing order + archive).** Every coordination change gets a
|
|
194
|
-
weight `0.5 ** (age_hours / half_life_hours)` (default half-life 48h). The
|
|
195
|
-
status / recent-changes listing orders fresh-first by weight and EXCLUDES any
|
|
196
|
-
change whose weight has fallen below the archive floor (default `0.05`, ≈14d).
|
|
197
|
-
Archived changes are losslessly retrievable with `--include-archived`
|
|
198
|
-
(`coordination_status.py --include-archived`), which also folds back any
|
|
199
|
-
physically-rotated `changes.jsonl.<date>` logs. Decay applies only to the
|
|
200
|
-
historical change stream — never to the live direct-message inbox or to active
|
|
201
|
-
state. Fails OPEN: a change with a malformed `ts` is treated as fresh.
|
|
202
|
-
- **Size-scaled lead/ownership auto-reclaim.** A lead lease (`rally/lead.json`)
|
|
203
|
-
whose `lease_until` has passed is auto-reclaimable by the next `claim_lead`.
|
|
204
|
-
The lease WINDOW scales with the claimed work size: a small (single-file /
|
|
205
|
-
effort XS·S) claim expires after `reclaim_small_minutes` (default 30m); a
|
|
206
|
-
large (multi-file / coarse / effort M·L·XL) claim after `reclaim_large_minutes`
|
|
207
|
-
(default 2h). Pass `work_size`/`effort`/`owns` to `claim_lead`; with NO size
|
|
208
|
-
signal the lease window stays the historical `renew_every_minutes` cadence
|
|
209
|
-
(backward-compatible). An auto-reclaim posts a durable `lead-reclaim` record
|
|
210
|
-
naming who reclaimed, the prior owner, and the reason (`stale-by-timeout`).
|
|
211
|
-
- **Preserved invariants.** Reclaim stays race-safe (the `rally/lead.lock`
|
|
212
|
-
fcntl lock is untouched) and FAIL-CLOSED: a present incumbent lease whose
|
|
213
|
-
`lease_until` is unparseable is NEVER auto-reclaimed (we refuse rather than
|
|
214
|
-
reclaim on a timestamp we cannot trust). An empty seat is still freely
|
|
215
|
-
claimable.
|
|
216
|
-
- **Policy is Rust-only; the Python math is an in-process helper.** Reclaim and
|
|
217
|
-
reap DECISIONS are made by the Rust binary (facade in `reaper.py` /
|
|
218
|
-
`leadership.py`, fail-loud below full capability). `decay.py` survives only as
|
|
219
|
-
pure in-process math the lead-lease window sizing needs (`recency_weight`,
|
|
220
|
-
`reclaim_timeout_seconds`, `classify_work_size`); it is NOT a behavioral mirror
|
|
221
|
-
of `decay.rs` and is no longer double-pinned against a cross-repo golden
|
|
222
|
-
fixture. The status/recent-changes LISTING still applies the decay weight in
|
|
223
|
-
Python over build-loop's own change-log so an old on-PATH binary cannot
|
|
224
|
-
un-decay the listing (pinned by `scripts/test_coordination_decay_invariant.py`);
|
|
225
|
-
that is a presentation concern, distinct from the now-Rust-only reclaim/reap
|
|
226
|
-
actuation.
|
|
227
|
-
|
|
228
|
-
This complements (does not replace) the >10-minute idle absorption rule above:
|
|
229
|
-
idle-absorption handles local reversible lanes a quiet peer left open; the lease
|
|
230
|
-
timeout governs the formal lead/ownership role handover.
|
|
231
|
-
|
|
232
|
-
## In-room stale-state reaper (actuator) — RUST-ONLY via a fail-loud facade
|
|
233
|
-
|
|
234
|
-
The sections above define WHEN records become stale. Physically removing them
|
|
235
|
-
(reaping) is **Rust-only**. There is no Python reaper sweep — the prior Python
|
|
236
|
-
parity mirror (presence/claim-index/lead deletion, double-pinned against golden
|
|
237
|
-
fixtures) was RETIRED in the Rust-rally facade migration. A Python process
|
|
238
|
-
deleting coordination records the Rust binary owns is the exact shadow
|
|
239
|
-
implementation that is worse than no coordination.
|
|
240
|
-
|
|
241
|
-
**Canonical actuator (Rust):** the `rally` binary's reaper (`rally sessions
|
|
242
|
-
--reap`, or `rally doctor --reap-stale` on newer builds). Dry-run by default;
|
|
243
|
-
`--reap`/`--apply` physically removes over-TTL presence, claims, and leads.
|
|
244
|
-
|
|
245
|
-
**Facade (`scripts/rally_point/reaper.py`).** `reap_channel(channel, workdir,
|
|
246
|
-
apply=…)` resolves coordination capability via `discovery_bridge` and then:
|
|
247
|
-
- **full capability** (a real binary owns the channel — `repo-local-rally-cli`
|
|
248
|
-
/ `fetched-binary` / env-override / path-binary / python-import) → shells
|
|
249
|
-
`rally sessions --reap` and surfaces the result (`capability_level: full`,
|
|
250
|
-
`deferred_to_rust: false`).
|
|
251
|
-
- **below full** (degraded-breadcrumb or unavailable) → REFUSES. It reaps
|
|
252
|
-
nothing and returns a capability-marked report (`deferred_to_rust: true`,
|
|
253
|
-
`coordination_unavailable: <reason>`). A degraded session must never reap a
|
|
254
|
-
peer it cannot prove is dead.
|
|
255
|
-
|
|
256
|
-
CLI: `python3 scripts/rally_point/reaper.py --workdir <path> [--apply] [--json]`.
|
|
257
|
-
|
|
258
|
-
**Capability field on every coordination envelope.** Every facade return and
|
|
259
|
-
`DiscoveryEnvelope` carries `capability_level` (`full` / `degraded-breadcrumb` /
|
|
260
|
-
`unavailable`) + a `coordination_unavailable` reason. The single source of truth
|
|
261
|
-
is `scripts/rally_point/capability.py`; `FULL_ONLY_OPERATIONS`
|
|
262
|
-
(claim/release/reclaim/lead/reap/liveness/before_write/checkpoint) are permitted
|
|
263
|
-
only at full capability.
|
|
264
|
-
|
|
265
|
-
**Degraded breadcrumb path (the ONLY thing a sub-full session may write).** When
|
|
266
|
-
no binary is available but the host is supported, a session may write
|
|
267
|
-
capability-marked presence/handoff *breadcrumb* facts so a later full-capability
|
|
268
|
-
peer (or a human) sees it existed. It must NOT — and structurally cannot — claim
|
|
269
|
-
ownership, reclaim, infer liveness, reap, or imply before-write protection.
|
|
270
|
-
|
|
271
|
-
**Unsupported-host = loud no-coordination.** A host with no fetchable pinned-
|
|
272
|
-
binary asset (Intel macOS, musl/Alpine, exotic arch) resolves to
|
|
273
|
-
`capability_level: unavailable` (`coordination_unavailable: unsupported_host`).
|
|
274
|
-
The facade is a loud no-op there — NEVER a policy mirror.
|
|
275
|
-
|
|
276
|
-
**Remaining Python guards** (the destructive paths that survive as in-process
|
|
277
|
-
guards, all FAIL-CLOSED): `presence.reap_stale` physically unlinks only at full
|
|
278
|
-
capability; `leadership` reclaim (taking a peer's lease) is full-only, while
|
|
279
|
-
seeding an EMPTY lead seat and self-relinquishing one's OWN seat stay breadcrumb-
|
|
280
|
-
class. The in-process `decay.py` / `liveness.py` are now pure window/weight math
|
|
281
|
-
helpers (lead-lease sizing, adaptive presence window), not behavioral mirrors.
|
|
282
|
-
|
|
283
|
-
**Codex parity.** A codex session emits the same presence record claude does, via
|
|
284
|
-
the `.codex/hooks.json` `SessionStart` hook that calls `session_probe.py --tool
|
|
285
|
-
codex`, so it ages and decays identically — now enforced by the single Rust
|
|
286
|
-
reaper both tools share, not by a cross-language golden fixture.
|
|
287
|
-
|
|
288
|
-
**Session-end self-release (primary).** Both tool hooks release the agent's Rally
|
|
289
|
-
file-claims at turn completion (`Stop` event) so peers immediately see the agent's
|
|
290
|
-
absence and the claims do not leak past Stop. The two hosts reach this differently
|
|
291
|
-
because their session models differ:
|
|
292
|
-
|
|
293
|
-
- **Codex** emits `rally stop codex` (`.codex/hooks.json` Stop). `codex` resolves to
|
|
294
|
-
Codex's managed `rally-*` tmux session, so that one call both self-kills the
|
|
295
|
-
session (it can never become a detached orphan) AND releases the session's claims.
|
|
296
|
-
- **Claude Code** is normally NOT a `rally run`-managed session, so `rally stop
|
|
297
|
-
claude_code` fails (`unknown managed session`). The Claude Stop hook therefore
|
|
298
|
-
releases claims via the portable primitive instead: `scripts/stop_closeout.py`
|
|
299
|
-
(`release_my_claims`, called from `hooks/closeout.sh stop`) enumerates this tool's
|
|
300
|
-
open claims with `rally room --tool claude_code --json` and releases each by event
|
|
301
|
-
id with `rally say release --tool claude_code --ref <event-id>`. It fires on EVERY
|
|
302
|
-
Stop (a stopped session is no longer editing), is advisory + fail-open (`command -v
|
|
303
|
-
rally` guarded; swallows all errors; exit 0 always), and is capped per Stop so a
|
|
304
|
-
backlog can't make the hook run long. History: before this, the Claude hook
|
|
305
|
-
released only the run IDENTITY, never the file claims, so `claude_code` auto-claims
|
|
306
|
-
accreted unbounded (112→127 observed). Added 2026-06-29.
|
|
307
|
-
|
|
308
|
-
**Reaper = backstop, not primary (NON-DEFAULT).** The reaper that expires abandoned
|
|
309
|
-
claims/presence (`rally sessions --reap`, faced by `scripts/rally_point/reaper.py`)
|
|
310
|
-
is Rust-only and dry-run/manual by default — it is NOT turned on. Self-release above
|
|
311
|
-
is the primary mechanism. The reaper exists ONLY to catch the dead: sessions that
|
|
312
|
-
crash (SIGKILL / 529 / network drop) before their Stop hook fires, so self-release
|
|
313
|
-
never ran. Do not enable it as a default-on sweep; run it deliberately as the
|
|
314
|
-
explicit backstop for crash-orphaned claims.
|
|
315
|
-
|
|
316
|
-
## Adaptive multi-signal liveness (squad-projection decay + tmux orphan reaper)
|
|
317
|
-
|
|
318
|
-
Fixed staleness cutoffs are replaced by liveness that ADAPTS to each session's
|
|
319
|
-
planned heartbeat cadence and weighs four signals. The liveness DECISION (reap /
|
|
320
|
-
self-exit) is Rust-only via the facade; `scripts/rally_point/liveness.py` retains
|
|
321
|
-
only the in-process window/verdict MATH the presence squad-projection uses,
|
|
322
|
-
verified by its own inline unit tests (`test_liveness.py`). The cross-repo golden
|
|
323
|
-
fixture `liveness_vectors.json` and its `_provenance.json` drift entry were
|
|
324
|
-
RETIRED in the Rust-rally migration — there is no longer a byte-identical parity
|
|
325
|
-
contract to maintain across the two codebases.
|
|
326
|
-
|
|
327
|
-
**Adaptive cadence.** A session declares its beat via `planned_heartbeat_secs`
|
|
328
|
-
(presence record) or `renew_every_minutes` (lead.json); undeclared → the default
|
|
329
|
-
cadence. Staleness is RELATIVE: `window = planned_interval * MISS_MULTIPLIER + GRACE`.
|
|
330
|
-
Defaults `DEFAULT_CADENCE_SECS=300`, `MISS_MULTIPLIER=6`, `GRACE_SECS=60` →
|
|
331
|
-
a 5-min cadence is stale at ~31 min (≈6 missed beats); a 5-hour cadence not until
|
|
332
|
-
~30 h. Tunable via `.rally/config.json` `coordination{}` (Rust) /
|
|
333
|
-
`.build-loop/config.json` `coordinationPolicy{}` (Python):
|
|
334
|
-
`default_cadence_secs`, `miss_multiplier`, `grace_secs` (+ `RALLY_*` env in Rust).
|
|
335
|
-
Legacy `heartbeat_minutes` is honored as a cadence source for backward compat.
|
|
336
|
-
|
|
337
|
-
**Four signals — LIVE if ANY is fresh within the adaptive window:**
|
|
338
|
-
(a) heartbeat/presence `last_seen`; (b) inject/ack (a `receipt`/`wake`/`handoff`
|
|
339
|
-
naming the session); (c) forward code progress (the session's worktree branch HEAD
|
|
340
|
-
MOVED since the last poll — Rust compares the two newest presence facts' shas, the
|
|
341
|
-
Python reaper compares a cached `branch_head_sha`); (d) declared active work (a
|
|
342
|
-
live claim or authored mission/handoff).
|
|
343
|
-
|
|
344
|
-
**Two fail-directions, each on the safe side:**
|
|
345
|
-
- **Squad VISIBILITY projection** (Rust `snapshot_from_facts_with_policy`) is
|
|
346
|
-
FAIL-OPEN. A squad whose four signals are ALL provably stale is DROPPED from the
|
|
347
|
-
default `rally room` view; `--include-archived` restores it (mirrors the message
|
|
348
|
-
archive model). A `Live` OR `Unknown` (any absent/unparseable signal) verdict
|
|
349
|
-
KEEPS the squad visible — hiding a still-alive peer could cause the very
|
|
350
|
-
write-collision this system prevents.
|
|
351
|
-
- **Reaper REMOVAL** (presence-file unlink, claim/lead) stays FAIL-CLOSED — never
|
|
352
|
-
remove on a signal it cannot trust.
|
|
353
|
-
|
|
354
|
-
**tmux orphan reaper.** `rally sessions --reap` also detects DETACHED `rally-*`
|
|
355
|
-
tmux sessions whose last activity is past the adaptive window and which are not
|
|
356
|
-
tracked as managed sessions, kills them, and tombstones the reap (closing the gap
|
|
357
|
-
where `--reap` saw 0 of the real detached orphans). Attached sessions (a human is
|
|
358
|
-
looking) are never killed.
|
|
359
|
-
|
|
360
|
-
## Zombie-tmux prevention — three layers over ONE liveness model
|
|
361
|
-
|
|
362
|
-
Root cause of accreted zombie tmux sessions: rally `exec`s the agent, so a session
|
|
363
|
-
auto-closes when its agent EXITS, but agents that never exit (a disabled autonomy
|
|
364
|
-
poller, idle detached panes) leave the session forever — tmux has no native
|
|
365
|
-
idle/lifetime timeout. The fix is three layers, all reusing the single
|
|
366
|
-
`liveness::is_live` 4-signal model and the adaptive window above. NONE adds a
|
|
367
|
-
fixed/brute-force idle clock; lifetime follows real liveness/ownership.
|
|
368
|
-
|
|
369
|
-
**Layer 1 — completion-scoped self-exit (prevent at source).** `rally
|
|
370
|
-
self-exit-check --tool <self>` is a stateless re-check: a task-scoped session that
|
|
371
|
-
holds NO active claims AND for which `rally next` is non-actionable for a SUSTAINED
|
|
372
|
-
streak self-kills its own `rally-*` tmux session, so `exec` auto-closes it. The
|
|
373
|
-
streak (default 2 consecutive empty re-checks, `liveness::DEFAULT_SELF_EXIT_STREAK`)
|
|
374
|
-
is persisted in the session's OWN tmux env (`RALLY_SELFEXIT_STREAK`, dies with the
|
|
375
|
-
session — no new filesystem surface) so a brief lull between claims never exits
|
|
376
|
-
mid-task. **Opt-out:** `--persistent` short-circuits to "never self-exit" for a
|
|
377
|
-
deliberately-long-lived session. The existing `rally stop` self-kill remains the
|
|
378
|
-
explicit-completion path; Layer 1 adds the implicit "work done" path. Decision is
|
|
379
|
-
the shared `liveness::completion_self_exit_eligible(work_resolved,
|
|
380
|
-
next_empty_streak, required_streak, persistent_optout)`.
|
|
381
|
-
|
|
382
|
-
**Layer 2 — event-driven liveness-lease safety net.** `rally enter` (a new agent
|
|
383
|
-
joining) opportunistically sweeps detached `rally-*` orphan tmux sessions via the
|
|
384
|
-
SAME reaper Layer-3 logic, in addition to `rally sessions --reap`. Best-effort and
|
|
385
|
-
fail-open: it runs AFTER presence (so the entering agent's own session is in the
|
|
386
|
-
guard set), never blocks the enter path, and never raises. A live / parent-alive
|
|
387
|
-
session is never reaped. No daemon/cron (those would themselves need worktree
|
|
388
|
-
isolation). Both the enter sweep and `sessions --reap` call ONE shared actuator
|
|
389
|
-
(`sweep_orphan_tmux`).
|
|
390
|
-
|
|
391
|
-
**Layer 3 — parent-lifecycle binding.** At launch (`tmux_start_command`) the new
|
|
392
|
-
session's env is stamped with `RALLY_PARENT_PID=<launcher pid>` in the SAME atomic
|
|
393
|
-
`tmux new-session -e` call. The reaper reads it back (`show-environment`), probes
|
|
394
|
-
`kill -0 <pid>` (no new crate dependency — the repo keeps a zero-extra-dep
|
|
395
|
-
contract), and feeds the result to the shared `liveness::reapable(liveness,
|
|
396
|
-
parent_alive)`. This targets the exact failure mode here (autonomy poller died →
|
|
397
|
-
its child sessions orphaned).
|
|
398
|
-
|
|
399
|
-
**The single reaper-eligibility authority** is `liveness::reapable` (mirrored
|
|
400
|
-
Rust↔Python, asserted by the byte-identical `liveness_vectors.json` `reapable_cases`):
|
|
401
|
-
|
|
402
|
-
| liveness | parent_alive | reapable | rationale |
|
|
403
|
-
|----------|--------------|----------|-----------|
|
|
404
|
-
| Live | any | NO | any of 4 signals fresh → independently live |
|
|
405
|
-
| Unknown | any | NO | fail-closed: untrustworthy signals |
|
|
406
|
-
| Stale | alive | NO | stale by signals but a live parent may re-drive it (conservative) |
|
|
407
|
-
| Stale | dead | YES | the Layer-3 orphan target |
|
|
408
|
-
| Stale | none (no info)| YES | window criterion ALONE — fail-safe degradation |
|
|
409
|
-
|
|
410
|
-
**Fail-safe directions (binding):**
|
|
411
|
-
- A session making code progress / heartbeating on cadence / recently injected /
|
|
412
|
-
holding a live plan is NEVER reaped — that's `Live` → not reapable, regardless of
|
|
413
|
-
parent state.
|
|
414
|
-
- The control NEVER reaps on the parent criterion ALONE: parent-dead reaps only a
|
|
415
|
-
session that is ALSO `Stale` by the 4-signal liveness.
|
|
416
|
-
- Missing/unparseable parent info (`parent_alive = None`) degrades to the
|
|
417
|
-
liveness-window criterion alone (`Stale → reap`), preserving the pre-Layer-3
|
|
418
|
-
orphan-window behavior exactly — never reaped *because* the parent is unknown.
|
|
419
|
-
- `kill -0` failing for any reason other than "no such process" (e.g. EPERM) reads
|
|
420
|
-
ALIVE (a live-but-unsignalable process is never treated as dead).
|
|
421
|
-
|
|
422
|
-
## Idle-agent self-selection (rally facilitates, the agent decides)
|
|
423
|
-
|
|
424
|
-
**Rally is a facilitator, not an orchestrator or verifier.** It exposes room state (`rally room` / `rally next`), file-level deconfliction (`rally check before-write --path P`), and claims/handoffs. It does **not** assign work, pick work, or verify code/release truth. A waiting agent runs this decision tree itself and chooses — the agent's LLM reasons over Rally's surfaced coordination records. This keeps coordination decentralized: no single point that hands out tasks (which would be a failure site and a bottleneck).
|
|
425
|
-
|
|
426
|
-
When an agent is idle and `rally next` returns no actionable item, walk the tree top-down, stop at the first match:
|
|
427
|
-
|
|
428
|
-
1. **Pending handoff/inject addressed to me** (by session, name, or tool) → handle it, record the response, then run `ack-inbox`.
|
|
429
|
-
2. **An open blocker I can resolve** → resolve it; post the resolution.
|
|
430
|
-
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.
|
|
431
|
-
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).
|
|
432
|
-
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.
|
|
433
|
-
|
|
434
|
-
The tree is the guideline; Rally supplies coordination records (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.
|
|
435
|
-
|
|
436
|
-
## Coordination reliability (verify the room before trusting it)
|
|
437
|
-
|
|
438
|
-
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:
|
|
439
|
-
|
|
440
|
-
- **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.
|
|
441
|
-
- **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.
|
|
442
|
-
- **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.
|
|
443
|
-
- **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.
|
|
444
|
-
|
|
445
|
-
## Room-policy reconciliation (mission / envelopes vs dispatch brief)
|
|
446
|
-
|
|
447
|
-
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.
|
|
448
|
-
|
|
449
|
-
- **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).
|
|
450
|
-
- **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.
|
|
451
|
-
- **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.
|
|
452
|
-
- **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.
|
|
453
|
-
|
|
454
|
-
---
|
|
455
|
-
|
|
456
|
-
## MECE Packets (briefs require all seven; rally packets six + optional 7th)
|
|
457
|
-
|
|
458
|
-
**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.
|
|
459
|
-
|
|
460
|
-
| Element | What it answers | Example |
|
|
461
|
-
|---|---|---|
|
|
462
|
-
| **Owns** | Which files/scopes may the peer write? | `scripts/coordination_status.py`, `scripts/test_coordination_status.py` |
|
|
463
|
-
| **Does not own** | Which files/scopes must the peer NOT touch? | any agent body; any coord-file content |
|
|
464
|
-
| **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 |
|
|
465
|
-
| **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 |
|
|
466
|
-
| **Allowed tools** | Which tools may the peer use? (empty list = no restriction) | `["Bash", "Read", "Edit"]` or `[]` |
|
|
467
|
-
| **Denied tools** | Which tools must the peer NOT use? (empty list = no restriction) | `["WebSearch"]` or `[]` |
|
|
468
|
-
|
|
469
|
-
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).
|
|
470
|
-
|
|
471
|
-
**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.
|
|
472
|
-
|
|
473
|
-
**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`.
|
|
474
|
-
|
|
475
|
-
---
|
|
476
|
-
|
|
477
|
-
## Verification of release surface
|
|
478
|
-
|
|
479
|
-
**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:
|
|
480
|
-
|
|
481
|
-
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.
|
|
482
|
-
2. **Manifest test exits 0** — `python3 scripts/test_plugin_manifest.py` (or the plugin's equivalent).
|
|
483
|
-
3. **Local commit log matches expected pattern** — `git log --oneline -1` shows the expected commit message shape and SHA.
|
|
484
|
-
4. **Local tag exists** — `git tag --list <tag>` returns the tag.
|
|
485
|
-
5. **Branch HEAD SHA matches commit SHA** — `git rev-parse <branch>` == commit SHA.
|
|
486
|
-
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).
|
|
487
|
-
7. **(Optional) Fresh-session load test** — `claude plugin refresh` + cache diff vs canonical returns empty.
|
|
488
|
-
|
|
489
|
-
**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`.
|
|
490
|
-
|
|
491
|
-
### Three-file lockstep (plugin manifest)
|
|
492
|
-
|
|
493
|
-
Plugin version bumps in the RossLabs ecosystem update **three** files in lockstep, not two:
|
|
494
|
-
|
|
495
|
-
1. `.claude-plugin/plugin.json` — `version` field.
|
|
496
|
-
2. `.codex-plugin/plugin.json` — `version` field.
|
|
497
|
-
3. `.claude-plugin/marketplace.json` — BOTH `metadata.version` AND `plugins[name=<plugin>].version`.
|
|
498
|
-
|
|
499
|
-
`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.
|
|
500
|
-
|
|
501
|
-
**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".
|
|
502
|
-
|
|
503
|
-
---
|
|
504
|
-
|
|
505
|
-
## Closeout hygiene
|
|
506
|
-
|
|
507
|
-
**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.
|
|
508
|
-
|
|
509
|
-
**Phase D closeout protocol (orchestrator runs by default at end of every run):**
|
|
510
|
-
|
|
511
|
-
1. **Reap this run's session presence:** `scripts/rally_point/lifecycle.reap_my_sessions(channel_dir, my_session_id)`.
|
|
512
|
-
2. **Stop watchers:** SIGTERM any `coordination_watch.py --interval N` processes started during the run.
|
|
513
|
-
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.
|
|
514
|
-
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.
|
|
515
|
-
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.
|
|
516
|
-
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.
|
|
517
|
-
7. **Track in state:** `state.json.runs[N].closeout_status`.
|
|
518
|
-
|
|
519
|
-
The protocol is automated, not operator-discipline-dependent. Memory citation: `feedback_close_out_stops_the_watcher`.
|
|
520
|
-
|
|
521
|
-
---
|
|
522
|
-
|
|
523
|
-
## C-FLOW rules
|
|
524
|
-
|
|
525
|
-
**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.
|
|
526
|
-
|
|
527
|
-
**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`.
|
|
528
|
-
|
|
529
|
-
**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.
|
|
530
|
-
|
|
531
|
-
**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".
|
|
532
|
-
|
|
533
|
-
---
|
|
534
|
-
|
|
535
|
-
## Quick-reference cross-index
|
|
536
|
-
|
|
537
|
-
| Rule | Canonical implementation |
|
|
538
|
-
|---|---|
|
|
539
|
-
| Operating rule (verdicts gating) | `scripts/coordination_status.py` `BLOCKING_VERDICTS` constant; coord file Operating Rule section |
|
|
540
|
-
| `post()` mandatory | `scripts/rally_point/post.py` (the helper itself) |
|
|
541
|
-
| Cheap detection at step boundaries | `scripts/coordination_status.py` + `scripts/coordination_watch.py` |
|
|
542
|
-
| MECE packets enforcement | `scripts/brief_mece_validator.py` + `agents/build-orchestrator.md` dispatch wrappers |
|
|
543
|
-
| Release-surface verification | `scripts/verify_release_surface.py` |
|
|
544
|
-
| Three-file lockstep enforcement | `scripts/test_plugin_manifest.py` `VersionShapeTests` |
|
|
545
|
-
| Closeout hygiene | `scripts/rally_point/lifecycle.py` + `scripts/collapse_run.py` + `agents/build-orchestrator.md` Phase D |
|
|
546
|
-
| Coord-file shape | `references/coordination-file-template.md` |
|
|
547
|
-
|
|
548
|
-
---
|
|
549
|
-
|
|
550
|
-
## When to update this file
|
|
551
|
-
|
|
552
|
-
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.
|