<!-- CURSOR_AGENT_PR_BODY_BEGIN -->
## Summary
Adds drones matrix (AI-268): a 2x3/3x3 implementer(row) × reviewer(col) model-comparison grid over one task, where every cell runs the normal cloud lifecycle (implementer → reviewer → addresser → Mercy) via the unmodified runDrone entrypoint. Ships plan (dry-run), fire, and blinded-judge modes, a matrix-only synthetic identity for receipt attribution, and historical-replay safety.
This PR is the harness only. No real matrix has been fired — every non-dry invocation requires an operator-supplied exact model grid and an explicit confirmation phrase, and CURSOR_API_KEY is not available in the environment this was built in (both by design and by this session's constraints). All behavior is verified with unit tests using injected fakes for the cloud SDK, git/gh, and the judge model.
## Why It's Needed
The standing model question (BACKLOG.md AI-268 entry) needs reproducible, full-lifecycle evidence instead of impressions: measured reviewer cost per run is $1.51 on claude-opus-4-8 vs $4.45 on claude-opus-5 (~2.9x), with no evidence yet that the pricier model reduces escapes. A normal drones run protects one (ticket, work) from duplicate implementer fires; a matrix intentionally needs several independently-attributable cells for the *same* task, so that exception has to be synthetic, explicit, and impossible for a normal fire to invoke by accident.
## Changes
- src/matrix-identity.ts — matrix-only synthetic identity (matrixRunId + cellId), bounded 2x3/3x3 grid-shape constants.
- src/matrix-historical.ts — historical-replay safety: validates the original pre-merge base SHA against an injectable git seam (never guesses/substitutes main), builds the disposable matrix-replay/<runId>/<sha12> base branch, and refuses a production-shaped branch at every call site.
- src/matrix.ts — grid validation, live Cursor Cloud model-registry resolution (AI-199, both at plan and fire time — no static allowlist), the versioned plan/artifact schema, the deterministic --confirm phrase, and atomic JSON+markdown artifact I/O.
- src/matrix-judge.ts — blinded, randomized judge pass against a fixed initial rubric (correctness / scope discipline / test quality / verification quality / maintainability); the unblinding map is assembled only *after* scoring and never appears in the judge prompt; raw reviewer finding counts are surfaced as context, never as an accuracy claim.
- src/matrix-fire.ts — fires a resolved cell (or a whole plan, sequentially) through runDrone, forcing the reviewer to the column model and leaving the addresser override unset so it inherits the row's implementer model via the existing cheap warm-agent-reuse path. Links (never duplicates) the resulting receipt/events into per-cell evidence, honestly labelling anything unresolved.
- src/runner.ts / src/telemetry.ts — purely additive optional matrixCell?: MatrixCellIdentity field on RunDroneInput / DroneRunRecord, threaded through the exact same conditional-spread pattern already used for the existing kind field. drones run / drones dispatch / every other entrypoint never sets it — pinned statically by src/matrix-identity-isolation.test.ts.
- src/cli/matrix.ts — the drones matrix verb: plan (default), --fire --confirm <phrase>, --judge --artifact <path>. Owns the one real git/gh-backed historical-safety implementation and the one real judge cloud-agent call (reusing the same createCloudAgent/sendToAgent chokepoints every other phase uses).
- experiments/matrix-model-comparison.md + two scrubbed example config fixtures — operator runbook and versioned config schema reference.
- Decision log entry, ARCHITECTURE.md / AGENTS.md updates, BACKLOG.md AI-268 status update, .gitignore entry for per-run matrix artifacts.
## Breaking Changes
None. matrixCell is additive and optional everywhere; no existing verb, flag, receipt field, or default model changes behavior when the new field is absent (which it always is outside drones matrix --fire).
## Test Plan
- pnpm typecheck — clean.
- pnpm exec vitest run — 155 files / 4867 tests pass, including 7 new matrix test files covering: dry-run grid-shape acceptance (2x3, 3x3) and rejection (1x3, 3x4); live-model-variant rejection (never silently skipped); confirmation-phrase determinism and refusal (including "omitted" and "near-miss" cases); matrix-only synthetic-identity isolation (static grep pin across every normal fire entrypoint); historical-base safety (SHA-not-found, not-an-ancestor, ancestor-check-throws, production-branch refusal, case-insensitive protected names); blinded/randomized judge mapping (never leaks a real cell id/model into the prompt, unblinding only in the artifact); and artifact reproducibility (atomic write + round-trip read, schema-version rejection).
- node scripts/run-python-tests.mjs — 716 tests, OK (skipped=19), unaffected by this change.
- pnpm build — clean.
- Manual CLI smoke test (see Verification Artifact) confirming the fail-closed preflights, grid-shape validation, and historical-SHA-validation refusal all fire before any network/cloud-agent call.
Not exercised in this session: an actual --fire against a real repo/task (needs CURSOR_API_KEY, which is unavailable here, and an operator-confirmed exact model grid per AGENTS.md's "ask before firing" rule) and an actual --judge invocation. Both paths are unit-tested via injected fakes for runDrone and the judge model call.
## Verification Artifact
$ CURSOR_API_KEY=fake-key pnpm drones matrix --config /tmp/matrix-1row.json[drones] Matrix rows count must be one of {2, 3} (implementer-configuration axis); got 1.
$ CURSOR_API_KEY=fake-key pnpm drones matrix --config experiments/matrix-config-example-historical-3x3.json
[drones] Historical-replay preflight failed:
- originalBaseSha 0000...0000 was not found in https://github.com/AI-Builder-Team/example-repo.git. Fetch it
explicitly (it may be un-reachable from any branch after history rewrites) before retrying — never substitute
a nearby commit.
$ CURSOR_API_KEY=fake-key pnpm drones matrix --config experiments/matrix-config-example-2x3.json
[drones] Live model resolution failed: Invalid User API Key # reaches the real live registry, as designed
$ pnpm exec vitest run
Test Files 155 passed (155)
Tests 4867 passed (4867)
## Impact Estimate
Business value: Replaces ad-hoc model comparisons with reproducible, full-lifecycle evidence while preserving every existing duplicate-fire/claim protection. Actual cost and quality evidence (once fired by an operator with a confirmed model grid) can calibrate the standing DRONES_*_MODEL defaults and future spend policy instead of relying on impressions.
Pre-AI estimate: 5 points (per the task spec) — designing safe multi-fire identities and historical-replay isolation, composing live model validation with full-lifecycle runs, collecting existing cross-phase metrics, building blinded judging/artifacts, and proving normal dispatch safeguards remain intact, matched the estimated scope.
<!-- CURSOR_AGENT_PR_BODY_END -->
<div><a href="https://cursor.com/agents/bc-1ade2c99-2605-4fd9-8a7c-0b79ab3c9844?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a> <a href="https://cursor.com/background-agent?bcId=bc-1ade2c99-2605-4fd9-8a7c-0b79ab3c9844&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a> </div>
<!-- drones:impact-actual:begin -->
Agent time: 1 h 36 m (implementer 0 m · reviewer 1 h 36 m · addresser 0 m)
Summed across phases. The 60 reviewer dimensions ran concurrently, so this exceeds elapsed wall-clock.
Efficiency vs. estimate: ~25.0× (5 points = 40 h of pre-AI effort)
<!-- drones:impact-actual:end -->
<!-- CURSOR_AGENT_PR_BODY_END -->
<div><a href="https://cursor.com/agents/bc-1ade2c99-2605-4fd9-8a7c-0b79ab3c9844?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a> <a href="https://cursor.com/background-agent?bcId=bc-1ade2c99-2605-4fd9-8a7c-0b79ab3c9844&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a> </div>
<!-- drones:impact-actual:begin -->
Agent time: 0 m (excludes reviewer) (implementer 0 m · reviewer not measured · addresser 0 m)
<!-- drones:impact-actual:end -->
## Review Round Completeness
- outcome: complete
- round: 1
- dispatched: 5
- reported: 5
- missing: (none)
- cause: complete
- head: 7aca9636ba8d51f3a71161e8899ff269c4b3b871
- run: fanout-222-2026-08-21T07-19-54-664Z
- review: 4990785701
<!-- drones:round-completeness head=7aca9636ba8d51f3a71161e8899ff269c4b3b871 run=fanout-222-2026-08-21T07-19-54-664Z -->
GitHub review #4990785701 was published and all dispatched review dimensions reported against the stamped head. Thread-count signals (unreplied=0) are meaningful for this head only — a later push invalidates the stamp. This section is a harness-shaped, head-bound self-report (not an authenticated out-of-band attestation).
<!-- CURSOR_AGENT_PR_BODY_END -->
<div><a href="https://cursor.com/agents/bc-1ade2c99-2605-4fd9-8a7c-0b79ab3c9844?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a> <a href="https://cursor.com/background-agent?bcId=bc-1ade2c99-2605-4fd9-8a7c-0b79ab3c9844&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a> </div>