---
name: platform-orchestrator
description: >-
  Dispatch + orchestration policy for building platform monorepo's
  @platform-modules/* packages. INVOKE (main loop only) at start of any
  module survey / spec / build / review / harness / ship work, before dispatching
  any agent. Holds agent roster (who runs each stage), model + effort tiers,
  review fix-routing (LOP≥LOC), serial+pipeline parallelism rule, L0→L3
  build sequence, current pilot. MAIN-LOOP context only — skill, not agent,
  not in CLAUDE.md, so scoped subagent never inherits orchestration policy meant only for me.
---

# platform-orchestrator — the dispatch policy (main loop only)

**Audience: the main-loop orchestrator (me), not subagents.** Optimize for activation, not prose.

I (opus, main loop) own orchestration thread. Skill loads *dispatch policy* into my context on demand. Does **not** live in `CLAUDE.md` (Claude `Agent` subagent auto-loads that file, would inherit policy meant only for me); **not** an agent (agent spins up *separate* orchestrator context — wrong; need policy in *my* loop). Shared law (doctrine, DAG, gates, runtime, conventions, spec-first, review *criterion*) stays in `CLAUDE.md`; only *who runs what, which model, what effort, what order* lives here.

## The roster — who runs each stage

| Stage | Agent | Notes |
|---|---|---|
| **Survey / source-extraction** | **cursor** (read-only over prior-app source repos) | Sweeps the prior-app source repos for capability's impls + call-sites, returns `file:line` digest. **Reads only; never decides disposition.** |
| **Build** (impl + harness fixture) | **cursor** (`.worktrees/` copy, IRON LAW) | Executes fixed spec + my TDD tasks. Never authors tasks. |
| **Big-refactor / redo fixes** | **cursor** (fixer) | Only when review escalates (see fix-routing). |
| **Per-diff review** (+ small fixes) | **opus-`xhigh` subagent** (`seam-reviewer`) | Ingests diff in *its* context, returns thin verdict. Fixes small problems itself. |
| **Disposition · gates · boundary/seam design · spec · wave-plan/TDD decomposition · sequencing · synthesis · integration** | **opus = me (main loop)** | **Never delegated.** Low-byte, highest-stakes judgment — weaker model judging strictly worse. |

**Division:** cursor SURVEYS and BUILDS · reviewer REVIEWS-IN-ITS-OWN-CONTEXT · **I OWN THREAD** (design · sequencing · integration). Keep raw source/diff bytes out of my context. For *small* high-stakes surveys I may read prior-app sources myself (opus, most reliable, few bytes); delegate to cursor only at fan-out scale. Ad-hoc *locate* (find-a-file, cheap-if-wrong) may ride built-in **`Explore`** (haiku) — not a survey.

> **Why cursor for surveys, not haiku `source-scout`:** haiku extraction proved unreliable (wrong `file:line`, missed surface, bad smell-flags → poisoned disposition). Survey output feeds my judgment, so accuracy is load-bearing — runs on cursor (Sonnet-class), same external agent that builds. `source-scout` agent retired; do not re-introduce haiku survey path.

## Model + effort tiers — dispatched only; the main loop is cache-constant

Dispatched agents run own fixed effort in *separate* contexts:
- **cursor survey / build → medium.**
- **per-diff review → opus `xhigh`** (highest-stakes judgment; reviewer is opus *peer*, so no quality loss vs me — protects my context, not downgrade).
- **Gate 4 audit cross-check (money · refund · webhook · session · password modules) → opus `xhigh`, dispatched.** *Evidence pass* — does every applicable `docs/standards/money.md` / `authz.md` rule (with its MONEY-001/002 · D7/D14 · W5/W6 origin) appear in this module's boundary spec, **marked audit-hardened**, with its `secaudit-*` conformance test named? — runs as dispatched opus-`xhigh` agent in own context (reads spec + audits; bytes stay out of my loop). **proceed/kickback verdict stays in main loop** — gate pass/fail is judgment, *never* delegated; agent returns evidence, I render gate. Home of **billing-spec cross-check** (vs MONEY-001/002 + D7/D14) registry no longer carries as separate task.

**Main loop (me) holds ONE effort level whole session — never toggled per-stage.** Down-shifting effort for mechanical step (ship/changeset) changes request params → invalidates prompt cache → next turn re-reads full context uncached, cost more than lower effort saves. Judgment runs high; mechanical steps ride same warm-cache level free.

## Review fix-routing — LOP vs LOC

`seam-reviewer` (opus-`xhigh`) judges each diff, **fixes small problems itself**, escalates only big-refactor / total-redo:
- **LOP (lines-of-prompt-to-instruct-the-fix) ≥ LOC-to-change → opus reviewer fixes directly** (brief costs as much as fix).
- **LOP < LOC** (short brief driving large/repetitive work) **→ hand to cursor fixer.**

## Parallelism — serial + pipeline, NOT parallel builds

Single opus judge (me) is bottleneck — spec / review / harness / spec-amends all funnel through one serial resource, so parallel cursor builds only burst review queue (+ root-config merge churn + muddy harness attribution). So:
- **One active cursor build at a time.**
- **Pipeline:** spec module N+1 while cursor builds module N — **module 2+ only.** **First module of layer fully serial** so seam pattern it reveals propagates forward.
- Parallel worktrees = *measured* exception for provably-independent leaves **after** pattern grooved — never default.

## Cursor dispatch is FORCE-BACKGROUNDED — monitor to completion, never fire-and-forget

**User law (verbatim, strict): "never send tasks to bg, always run in front. there is a bug in claude code that you don't see when tasks are over. bg task = failure."** Intent = *never fire-and-forget* — never lose sight of task's completion.

**Empirical (2026-06-15, uploads build):** `cursor-agent -p` is **force-backgrounded by harness at launch regardless of `timeout`** (confirmed at both `600000` and `180000` → both returned "Command running in background with ID …" immediately). Cannot make real cursor build run foreground. So:
- **I never SET `run_in_background:true`** (that's forbidden fire-and-forget) — but harness backgrounding cursor anyway outside my control.
- **Compliance mechanism = ACTIVE MONITOR-TO-COMPLETION:** moment cursor dispatched, arm **`Monitor`** that polls `until ! pgrep -f cursor-agent` then emits log tail + `git log` of worktree (cover success AND crash — pgrep-gone fires either way). Build done ONLY when I SEEN outcome. **Never advance on harness's own bg-completion `<task-notification>`** — that's exactly buggy signal user warned about; Monitor I control = source of truth.
- **Dispatch shape:** `cursor-agent -p --force --trust --model composer-2.5 --workspace <abs-worktree>` with prompt; redirect verbose stdout to logfile (`> /tmp/<mod>.log 2>&1`) so raw build bytes stay out of my context — read only tail.
- **If I must abort stuck cursor** (`pkill -9 -f cursor-agent`): worktree keeps whatever committed (cursor commits per-task) + any uncommitted in-progress files; assess (`git log` + `git status` + line-counts) before reset-vs-resume. **Killing mid-task expensive — do not interrupt healthy run.**

## Build sequence (synthesis §7) — strictly bottom-up, acyclic

- **L0:** `util` → `db` → (events DISSOLVED).
- **L1:** `jobs` / `mail` / `auth` / `tenancy`.
- **L2:** `ledger` → `tax` (**by-need** — build-urgency inverts adoption-strength) → … → `billing` (LAST; L2 pilot, Pattern B over tax+ledger).
- **L3 + WATCH** (`marketing`, `helpdesk`, `invoicing`, `affiliate`): wait for 2nd source / real consumer.
- `-react` overlays: gated on core + 2nd React consumer.

Never build layer-N module before its layer-(N−1) deps exist.

## Pilot

**`@platform-modules/util` pure-leaf slice** (crypto / tokens / password — zero-dep Web-Crypto). Boundary spec build-ready in `docs/specs/2026-06-12-auth-util-module-boundaries.md` (util half). **Fully serial** (first module of L0).

## The assembly line + which skill drives each stage

`survey ─▶ spec/gates ─▶ build ─▶ review (adversarial) ─▶ harness ─▶ ship`

Pipeline **already skill-encoded — wired, not forked.** Invoke, do not reimplement:
**Module grain:**
- **`platform-extract-modules`** — module-porting pipeline (candidate rubric, 3 axes, packaging, 10-step extraction, §9 boundary-mapping, anti-patterns). **Primary module skill.**
- **`platform-make-modules`** — net-new, scan-gated: survey first → route to `platform-extract-modules` moment a prior app has it; only genuine zero-reference capability authored fresh (`turbo gen` scaffold).
- **`platform-embed-module`** — module→consumer adoption (integration axes A–F; adapter-minimalism = one wiring file; swap-survival parity vs host's hand-rolled code; leaves a rollback).

**Delivery grain (above modules — `delivery-stack §0`):**
- **`platform-make-template`** — net-new screen-flow: scan-gate prior-app screens → adopt convergent shape → de-name → host-owned; `-react` binding gate (module-bound flow blocked until backing `@platform-modules/<core>-react` ships); never a "template package".
- **`platform-make-distro`** — net-new themed installable product: prereq one-rule gate (built+green blueprint MUST exist first) → adds only theme+defaults+wizard+CMS → Debian-from-kernel graduation. YAGNI-gated (real install consumer or roadmap-only).
- **Build dispatch (delivery grain):** generic content template = often thin host glue → may build **IN-LOOP**; multi-screen adoption OR a distribution = multi-file product work → **cursor in worktree** (same FORCE-BACKGROUNDED monitor-to-completion law above). Judgment (convergence · prereq · YAGNI · graduation · host-vs-generic split) = **main loop, never delegated.**

**Cross-cutting:**
- **`plan` / `writing-plans`** — wave plan + bite-sized TDD tasks.
- **`cursor-orchestrator`** — *mechanics* of dispatching cursor (this skill = *policy*; that one = *how*).
- **`karpathy` / `tdd`** — goal-driven TDD execution.
- **`code-quality-reviewer`** + **`slopgate-*`** — reviewer's mechanical aids; **`/code-review`** — branch/PR review.
- **`dispatching-parallel-agents`, `using-git-worktrees`, `verification-before-completion`, `cloudflareops`, `astro`** — as needed.

## Spec-first kickback (restated — it governs dispatch too)

If cursor finds boundary spec wrong, ambiguous, or incomplete mid-port, it **stops**. **I** amend spec + update plan *before* code resumes. Cursor never silently "fixes" by diverging from spec. (Shared-law copy in `CLAUDE.md` §1/§4; repeated here because it bounds what dispatched builder may do.)

## Learned Rules

### ci-repo-no-local-changeset-version | fired:1 | 2026-06-16
Ran `changeset version` locally to bump all 21 pkgs to 0.0.1, but CI's changesets/action OWNS versioning → local re-bump of 20 CI had already shipped became divergent commit + non-fast-forward push; cost reset+merge reconciliation to land cleanly.
Prevent: in CI-publish repo (changesets/action on push), NEVER run `changeset version` locally for packages CI versions. Add only `.changeset/*.md` and push — CI versions+publishes. For one NEW package, push its source, let CI's "no changesets → publish unpublished" path ship it (no local bump). Fast-forward invariant before push: 20 stay at released version, `.changeset/` = README only, `origin/main` is ancestor of `main`.

### verify-built-surface-before-unbuilt-claim | fired:2 | 2026-06-16
delivery-stack spec + 2 recipes + CLAUDE.md §2 + 2 memory files all assert realtime `/server` "intentionally unbuilt / types-only" — FALSE: built, 13/13 tests pass. Spec-first source-of-truth carried stale "unbuilt" claim that propagated into downstream docs. (fired:2 2026-06-21 — carried-in summary claimed "NO proof file exists" for the [...key] real-router DELETE; disk HAD `_delete-route.test.ts` proving handler LOGIC — the true gap was only the routing e2e. Asserted absence without reading what the existing test actually proved.)
Prevent: before writing or repeating ANY disk-state claim — "X is unbuilt/types-only", "no test/proof exists for Y", "Z is missing" — verify against DISK (cold `turbo build`/test, actual export list, or READ the existing test to see what it proves), never from memory or a prior/inherited summary. When built surface changes, amend boundary spec in lockstep (spec-first). Stale absence/unbuilt claim is a spec defect to reconcile, never cosmetic.

### verify-fix-empirically-before-enshrining-publish | fired:1 | 2026-06-17
Enshrined changesets config-flag (`onlyUpdatePeerDependentsWhenOutOfRange:true`) in durable memory as "THE durable fix" for the 1.0.0 peer-cascade BEFORE empirical confirmation → wrong: flag was a NO-OP for `workspace:*`, advisor's prior "verify don't trust" warning came true, had to re-diagnose + correct memory. Same root nearly repeated declaring the publish "verified done" on a green CI `🦋 success` + git tags — that proves only changesets THINKS it published, not that the artifact RESOLVES for a consumer.
Prevent: never write a fix-claim as resolved in memory/spec/CLAUDE.md until the fix's ACTUAL property is verified empirically (regenerate the failing PR / re-run the failing path), never a proxy signal. For any release, green publish ≠ resolvable artifact: run a clean-dir `npm install <pkg>@<ver>` (read token + scoped `.npmrc`), assert deps rewrote to concrete `^x.y.z` with no leaked `workspace:`, whenever a dep-range protocol is new to the published surface.

### plan-fixture-literal-must-match-core-type | fired:2 | 2026-06-21
Plan/TDD/test fixture literals I author drifted from the consumed core type TWICE: `status: 'published'` (commerce-catalog `ProductStatus = draft|active|archived` has no 'published') and `useProductList({})` (commerce-catalog `CatalogFilter.audience` is REQUIRED) → TS2345, slipped to Tier-1 as a typecheck blocker. Recurring class = fixture vs core-type mismatch (missing required field OR value outside a string-union).
Prevent: before embedding ANY typed fixture/call in a plan snippet or test (a `@platform-modules/*` core type — filter, entity, enum), READ that type's definition first (`types.ts`) — enumerate its REQUIRED fields and each string-union's allowed members; construct the literal to satisfy them. Never infer a field is optional or a value is valid from memory. Bucket-C (needs type info) → text rule is sole defense, no slopgate gate.

### cursor-typecheck-must-be-real-tsc-not-vitest | fired:1 | 2026-06-21
cursor build reported "typecheck PASS" but had only run `vitest` (esbuild strips types at runtime — NO type errors surface); the real `CatalogFilter.audience` TS2345 was invisible to it and slipped to the Tier-1 gate. A green test run is NOT a typecheck.
Prevent: every cursor build/fix prompt MUST require the package's real `typecheck` script (`tsc --noEmit`, exit 0) as a SEPARATE report-back line from `test` — never accept "typecheck PASS" inferred from a passing vitest run. Code-gate Tier-1 still re-verifies `tsc` against disk regardless of the build's self-report.

### parallel-reviewers-need-isolated-worktree | fired:1 | 2026-06-25
Ran seam-reviewer + security-guard in PARALLEL report-only over the SAME shared worktree → wrong. One reviewer ran a worktree-MUTATING discrimination probe (transiently dropped `key={clientSecret}`), racing the other's read → a spurious money-path test RED (`expected 1 to be 2`) that nearly triggered a fix for a non-bug.
Prevent: never run >1 reviewer concurrently over one worktree. Run Tier-2 reviewers SERIALLY, or give each an isolated read-only copy (`git worktree add` a throwaway per reviewer). A test that REDs only under concurrent-review load yet passes isolated = suspect a shared-tree race, not a real flake — verify (advisor / re-run isolated) BEFORE dispatching any fix.