summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-06-07 14:07:11 +0900
committerAdam Malczewski <[email protected]>2026-06-07 14:07:11 +0900
commitefddee1edd2924725a4dd240894666ede97b67b9 (patch)
tree294bbedb837f6101a2eb9dc9d3fe4ae021d5cd69
parent2eed0f7ea0bf593cb99bc176d1421b09cfb1066f (diff)
downloaddispatch-efddee1edd2924725a4dd240894666ede97b67b9.tar.gz
dispatch-efddee1edd2924725a4dd240894666ede97b67b9.zip
docs(harness): biome-clean rule + parallel-wave orchestration
- add .dispatch/rules/biome-clean.md (0 warnings/0 infos; no `!`/useLiteralKeys), wired into the every-agent scoping map + canonical invocation - package-agent: note biome zero-tolerance; verify line clarifies 0 warnings AND 0 infos - ORCHESTRATOR: document parallel-execution waves (2a) + agent-failure recovery patterns (5a) + concurrency caveats
-rw-r--r--.dispatch/package-agent.md5
-rw-r--r--.dispatch/rules/biome-clean.md12
-rw-r--r--ORCHESTRATOR.md72
3 files changed, 82 insertions, 7 deletions
diff --git a/.dispatch/package-agent.md b/.dispatch/package-agent.md
index 9a769d3..9af0485 100644
--- a/.dispatch/package-agent.md
+++ b/.dispatch/package-agent.md
@@ -55,6 +55,9 @@ The authoritative rules (`.dispatch/rules/*`, inlined into this prompt) govern.
module wired between features. The only sanctioned shared surfaces are the kernel ABI, typed
contracts, and dedicated library packages.
- **Strict TS.** Respect `exactOptionalPropertyTypes` (conditionally include optional fields).
+- **Biome is zero-tolerance** (`.dispatch/rules/biome-clean.md`, inlined). `bunx biome check` must
+ end with ZERO warnings AND ZERO infos — not merely zero errors. Fix the code; never
+ `// biome-ignore` or relax config.
## Verify before finishing — YOUR PACKAGE IN ISOLATION
Other agents may be editing sibling packages in parallel, so never run the whole-graph build.
@@ -63,7 +66,7 @@ Run, and paste the output into your report:
- `bunx vitest run packages/<your-package>/src` → all pass (count must go up)
- If your package uses `bun:sqlite`, use `bun test packages/<your-package>/src` instead
(vitest can't load `bun:sqlite`).
-- `bunx biome check packages/<your-package>` → clean
+- `bunx biome check packages/<your-package>` → clean (0 warnings AND 0 infos)
The orchestrator runs the authoritative full-graph `typecheck` / `test` / `check` itself.
## Report (REQUIRED) → `reports/<your-package>.md`
diff --git a/.dispatch/rules/biome-clean.md b/.dispatch/rules/biome-clean.md
new file mode 100644
index 0000000..4cd5e83
--- /dev/null
+++ b/.dispatch/rules/biome-clean.md
@@ -0,0 +1,12 @@
+# Rule: biome is zero-tolerance (0 warnings, 0 infos)
+
+`bunx biome check` must finish with ZERO warnings AND ZERO infos — not just zero errors.
+"Clean" means there is no "Found N warnings" / "Found N infos" line at all. Fix the code;
+NEVER add a `// biome-ignore` comment and NEVER relax the biome config to silence a finding.
+
+Two findings recur — pre-empt them:
+- **No postfix non-null assertions (`value!`).** Narrow with an explicit guard
+ (`if (x === undefined) throw new Error(...)`) or a tiny `assertDefined` helper — this both
+ proves the intent and narrows the type. (Most common in tests.)
+- **No `useLiteralKeys`.** Use dot access for identifier keys (`obj.foo`); reserve bracket
+ access for genuinely dotted / dynamic keys (`obj["a.b"]`).
diff --git a/ORCHESTRATOR.md b/ORCHESTRATOR.md
index a20dab9..620b983 100644
--- a/ORCHESTRATOR.md
+++ b/ORCHESTRATOR.md
@@ -39,8 +39,9 @@ they justify every rule below.
## 1. The golden workflow (build/modify a feature)
-1. **Plan.** Decide the unit(s). Respect the dependency-topological order. One
- agent owns one unit; it may ONLY edit its assigned files.
+1. **Plan.** Decide the unit(s); split into dependency-topological **waves** of
+ disjoint units, and WIDEN each wave where you can (§2a). One agent owns one unit;
+ it may ONLY edit its assigned files.
2. **Overlap check FIRST (anti-synonym-drift, §5.6).** Before creating anything
new, check `GLOSSARY.md` + existing code. If the request *describes* an
existing concept under a new name, steer to the canonical term (e.g.
@@ -51,8 +52,10 @@ they justify every rule below.
existing one?" — surface it to the user; never decide granularity silently.
4. **Write the prompt** to `prompts/<unit>.md` (gitignored). See §3 for the
prompt recipe.
-5. **Summon the agent** via `opencode run` (see §2). Parallelize disjoint units.
-6. **Verify** the report + independently re-run checks (see §4). Trust nothing
+5. **Summon the wave** via `opencode run` (see §2); disjoint units run in PARALLEL
+ (§2a). RE-READ `.dispatch/rules/` + the §3 scoping map before each wave — assemble
+ from the files, not from memory.
+6. **Verify** the reports + independently re-run checks (see §4). Trust nothing
until you've re-run `typecheck`/`test`/`check` yourself.
7. **Resolve** any contract gaps / errors (see §5).
8. **Commit** the milestone with a clear message + test count. Update `tasks.md`.
@@ -81,7 +84,7 @@ opencode run --dir /home/tradam/projects/dispatch/arch-rewrite \
-m opencode-go/mimo-v2.5-pro \
"$(cat .dispatch/package-agent.md)
$(cat .dispatch/extension-agent.md)
-$(cat .dispatch/rules/one-owner.md .dispatch/rules/isolation-over-dry.md .dispatch/rules/pure-core.md .dispatch/rules/no-internal-mocks.md .dispatch/rules/typed-handles.md)
+$(cat .dispatch/rules/one-owner.md .dispatch/rules/isolation-over-dry.md .dispatch/rules/biome-clean.md .dispatch/rules/pure-core.md .dispatch/rules/no-internal-mocks.md .dispatch/rules/typed-handles.md)
## TASK
$(cat prompts/<unit>.md)" \
@@ -132,6 +135,29 @@ log into context as a hard failure.
---
+## 2a. Parallel execution — WAVES
+
+Throughput comes from running disjoint units at once. Organise it as waves:
+- **A wave = units that (a) touch DISJOINT files and (b) have no compile-time dependency
+ on each other** (each imports only already-built packages + existing contracts). Launch a
+ wave by emitting one summon per unit as CONCURRENT tool calls (§2). Later waves depend on
+ earlier ones; the composition root (`packages/host-bin/`) is almost always the LAST wave.
+- **Pre-author the seam to widen the wave.** Because the orchestrator OWNS contracts (§6),
+ author the shared contract / typed handle in `packages/kernel/src/contracts/*` FIRST, then
+ summon the producer AND the consumer in the SAME wave against that fixed type — neither needs
+ the other's implementation. Authoring the contract up front is what turns a sequential
+ producer→consumer chain into one parallel wave (and `lsp references` on the new symbol gives
+ the exact consumer set to summon).
+- **Also widen by removing edges:** prefer a consumer-defined handle the producer implements,
+ or a generic utility over a feature-specific one, so a dependency disappears entirely.
+- **One writer per file, always** — even across waves. If two units would edit the same file,
+ they are NOT separable; merge them into one unit or sequence them.
+- **After a wave:** read every report, run the §4 checks ONCE for the whole wave, commit the
+ milestone (update `tasks.md`), then start the next wave. Don't open a new wave before the
+ prior one is green.
+
+---
+
## 3. The per-summon `prompts/<unit>.md` is JUST the TASK block
The invariant guardrails — single-writer directory ownership, visibility, coupling, the
@@ -152,7 +178,7 @@ Keep it scoped (P6): state only the project-specific, non-inferable task — the
**`.dispatch/rules/` scoping map** — include ONLY the rows matching the unit (per §0
"scoped rules beat general rules"); do NOT dump every rule on every agent:
-- **Every agent:** `one-owner.md`, `isolation-over-dry.md`.
+- **Every agent:** `one-owner.md`, `isolation-over-dry.md`, `biome-clean.md`.
- **Kernel unit:** `kernel-purity.md` + `pure-core.md` + `no-internal-mocks.md`.
- **Pure-core unit:** `pure-core.md` + `no-internal-mocks.md`.
- **Any extension coupling via hooks/services:** `typed-handles.md`.
@@ -165,6 +191,14 @@ Keep it scoped (P6): state only the project-specific, non-inferable task — the
OWN harness (`package-agent.md` + `frontend-*.md` rules) + ITS OWN scoping map — NOT
these backend rules. See that repo's `ORCHESTRATOR.md`.
+**Tell each agent it has company (parallel waves).** Add to each wave TASK: sibling units are
+being built in OTHER packages right now; `tsc -b`/vitest/biome are whole-PROJECT, so if a check
+reports errors OUTSIDE your package, that's concurrent WIP — ignore it and ensure YOUR files are
+clean. The orchestrator's post-wave run (§4) is the source of truth.
+
+**Make agents IMPLEMENT, not deliberate.** A summoned owner must edit files + run its checks +
+write its report in the one run. If a summon returns only a plan, re-summon (§5a).
+
---
## 4. Verification (the orchestrator's trust protocol)
@@ -200,6 +234,12 @@ git status --short # confirm the agent stayed in its lane (no out-of-scope edit
- Confirm the agent touched ONLY its assigned files (one-owner rule).
- For pure units, confirm tests use NO internal `vi.mock("@dispatch/*")`.
+**Concurrency caveat (parallel waves):** `tsc -b`/vitest/biome are whole-project, so an agent's
+OWN mid-wave check can transiently see a sibling's half-written file. Don't act on a report's
+out-of-package errors; YOUR post-wave run is authoritative. Re-run a suite that depends on shared
+external state before trusting it — and ALWAYS sweep leaked server/collector processes between
+live runs (§8 bracket trick), since a leak silently poisons the next run's counts.
+
---
## 5. Resolving errors & contract changes
@@ -225,6 +265,26 @@ git status --short # confirm the agent stayed in its lane (no out-of-scope edit
---
+## 5a. Agent-failure recovery patterns
+
+- **Plan-only / "shall I proceed?" agent.** A summon sometimes returns a PLAN and STOPS without
+ editing (no diff, no `reports/<unit>.md`). Detect via `git status` + the missing report.
+ Re-summon the SAME TASK prefixed: "IMPLEMENT THIS NOW — make all edits, run the checks, write
+ the report; do not stop to plan or ask." Don't hand-fix its work.
+- **A behaviour change reds a SIBLING's tests (test fan-out).** When a unit's new behaviour
+ invalidates another unit's test ASSERTIONS, those tests belong to that OTHER owner — summon it
+ with a focused "fix these N failing tests to match the new behaviour" TASK (state the
+ behaviour). The orchestrator never edits feature tests itself. (Distinct from an INTEGRATION
+ bug where neither side is wrong — that's the temporary multi-knowledge agent in §5.)
+- **Agent strayed out of its lane.** `git status --short` after every wave; if an agent touched a
+ file outside its package, keep it ONLY if it's legitimately the orchestrator's lane
+ (contracts / build / config / harness, §6) and note it — otherwise revert + re-summon with a
+ tighter scope.
+- **Flaky green.** A wave that passes once but leaked a server/collector or relies on shared
+ external state can pass for the wrong reason; sweep (§8) and re-run before committing.
+
+---
+
## 6. Restrictions & invariants (NEVER violate)
- **Single-writer:** never let two agents edit the same file concurrently.