---
name: boundary
description: "Use when a plan or diff might break a cross-cutting contract. Boundary diagnostic: reads the source a plan touches — db schema, wire envelope, auth, events — and reports violations with a pass/block verdict. Read-only; also runs on a diff. Triggers on 'boundary check', 'what could break'."
---

# Boundary Diagnostic

You diagnose whether a plan's changes would break an application boundary.

A boundary is a contract between two pieces of code (or code and infra) that share an assumption with **no static link** between them: the column a raw SQL string names, the JSON envelope a client unwraps, the event string a dispatcher parses, the env var a deploy script writes. Changing one side ships green — compiles, lints, tests pass — and breaks the other at runtime. Find those edges in the plan's path _before_ execution.

**The litmus is "would it ship green?"** An edge the compiler or an existing test already guards is not a boundary — spend your reading on the edges with no static link.

## Contract sources

Three layers tell you what to look for; the code tells you what exists.

- **The mechanisms** — [`references/mechanisms.md`](references/mechanisms.md): the seven failure mechanisms every boundary instantiates (rendezvous-string, serialized-shape, generated-artifact, dual-authority, config-elsewhere, trust-invariant, lifecycle-protocol), each with its trace strategy, universal fix, and severity, plus the two stack-independent domain contracts (entity-model, tenancy). Load it on every check.
- **The technology packs** — [`references/index.md`](references/index.md) routes to the packs under `references/packs/` by the signals in the touched code; each pack carries one technology area's detect patterns, gotchas, and safe-change sequences. Load **only** the packs the touch list exhibits. The packs are a floor, not a fence: a contract no pack covers is still in scope — diagnose it from its mechanism and report it if it passes the litmus.
- **Repo doctrine** — `.claude/rules/`, `docs/architecture/` (including `decisions/`), and any contracts package name the repo's bespoke contracts (a documented response envelope, a schema-parity rule, an entity model). A documented contract is a real side of a boundary: a plan that contradicts one is a finding **even when no code consumer exists yet** — this is how a greenfield plan, with no code to trace, still gets checked.

## Run

**Input:** a plan path (given, or the newest in `docs/history/plans/`) — or a diff or named code area for non-plan work, where the diff's hunks stand in for the plan's steps. Steps 1–5 are identical either way; the report's **Missing plan subsections** and **Docs the plan's ledger missed** sections, and step 6, apply only to a plan.

1. **Build the touch list.** Parse the plan's Proposed Changes: files created or modified, entities or state added or changed, API changes, anything the author flags as a cross-module contract. Note missing subsections.

2. **Identify the contracts.** Read each touched file and its immediate imports. Against the mechanisms, the routed packs, and the repo doctrine, list the contracts this code participates in — the schema it queries, the envelope it emits, the events it publishes or parses, the auth checks it sits behind, the env it reads.

3. **Trace the other side.** The danger lives on the side the plan _doesn't_ mention. For each contract, grep the shared name or shape across the repo — the column name in other SQL strings, the response field in client unwrappers, the event kind in subscribers, the route in fetch calls and scripts, the env key in deploy tooling. Record consumers as `file:line`, doctrine as the doc path. At ≳10 contracts, fan the tracing out to parallel sub-agents — one per pack area, each prompt self-contained with its contracts and grep targets — and judge the returned evidence yourself; a small diff traces inline.

4. **Judge each intersection.** Does the planned change alter a shape a traced consumer depends on, break an invariant the code or doctrine establishes (append-only vocabularies, idempotency keys, fail-closed checks, ordering guarantees), or introduce a new cross-module edge? Grade it:

   | Severity | Meaning |
   | --- | --- |
   | **CRITICAL** | Can corrupt persisted data, or open an auth/money path — trust-invariants and persisted or replayed shapes live here |
   | **HIGH** | Silent cross-module breakage that ships green |
   | **MEDIUM** | Drift-prone coupling not yet broken (string-matched, duplicated constants) |
   | **LOW** | Smell |

   Loud, immediately visible runtime breakage caps at HIGH. Severity is intrinsic to the finding, never curved — three genuine CRITICALs in a small repo is signal, not inflation.

5. **Report in chat:**

   ```
   # Boundary check — {plan}

   **Verdict: PASS | PASS WITH AMENDMENTS | BLOCK**

   Touched files read: {N} · Contracts identified: {N} · Consumers traced: {N}

   ## Violations
   | # | Boundary | Mechanism | Planned change | Other side (file:line or doc) | Severity |

   ## New edges the plan introduces
   | # | Contract | Sides | Hardening to fold into the plan |

   ## Coverage
   | Area touched | Contracts checked | Result |

   ## Suggested plan amendments
   ## Missing plan subsections
   ## Docs the plan's ledger missed
   | Feature doc | Owned path in the touch list | In Doc Obligations? |
   ```

   **Fill the doc cross-check from the touch list you already hold:** resolve its paths against the ownership index and compare the result to the plan's **Doc Obligations** rows. The plan's author wrote that ledger and nobody else checks it — a `None` that contradicts your touch list is the failure this section catches. Report the gap; **never** edit the ledger yourself.

   **BLOCK** = any CRITICAL; a blocked plan folds the amendments and re-runs the check. HIGH findings yield **PASS WITH AMENDMENTS** — the invoking session folds the amendments into the plan in the same pass, before the plan is shown as finished. Order amendments sequencing-first: many violations dissolve by reordering steps (expand-then-contract, migrate-before-code) rather than changing what ships — prefer that fix, drawn from the pack entry's **Safe change** or the mechanism's **Universal fix**.

6. **Record the verdict in the plan's `Gates:` line.** Rewrite only your own segment, to exactly one of:

   | Verdict | Segment |
   | --- | --- |
   | PASS | `Boundary: passed YYYY-MM-DD` |
   | PASS WITH AMENDMENTS | `Boundary: passed YYYY-MM-DD` — written only once the amendments are folded |
   | BLOCK | `Boundary: blocked YYYY-MM-DD` |

   The compliance hook greps exactly this segment and blocks implementation edits inside the plan's scope until it reads `passed` — `pending` and `blocked` wall alike (the other gates are enforced by section presence, not segment text). A plan with no `Gates:` line gets one added; never skip the write-back.

## Rules

- **Read-only, one exception.** You never edit the plan's content, the code, or any doc — the invoking session folds your amendments into the plan; a plan is not finished until its segment reads `passed`. The single write you own is the plan's `Gates:` line (step 6), your segment only.
- **Verify in source.** **Never** flag from plan text alone — read both sides of every finding and cite them: code as `file:line`, doctrine as the doc path.
- **No other side, no violation.** An intersection with no traced consumer and no doctrine behind it is a **new edge**, not a violation: report it in its own section with the hardening its mechanism prescribes (version the cache key now, make the enum append-only now), so the fragile edge is born safe.
- **A clean report is valid.** Zero violations means say so — the coverage table is the evidence it was checked, not skipped. Don't pad findings.
