# Boundary Mechanisms

Load when: every boundary check — this is the core reference. The packs under `packs/` instantiate these mechanisms with exact detect signals and gotchas.

Every boundary instantiates one of seven mechanisms. The mechanism tells you what to grep for, what the universal fix is, and how bad a break is — which is how you diagnose a technology no pack covers.

---

## 1 · rendezvous-string

Two sides meet on a literal identifier: a column name in raw SQL, an event/job/topic name, a route path, an env key, a cache key, a channel template, a DI token, a flag key, a metric name, a port number, a binding name. The compiler sees two unrelated literals.

- **Ask:** where else does this exact string (or its template) appear — including config, IaC, CI, dashboards, and other repos?
- **Failure:** the sides silently stop meeting — publishes into the void, reads `undefined`, routes 404, handler never fires, alert goes quiet.
- **Trace:** grep the literal and its prefix/template variants repo-wide; the other side is often not code (a deploy manifest, a saved dashboard query, a provider allowlist).
- **Universal fix:** centralize the identifier in one shared constant or module. On rename, serve both old and new until the old side drains — in-flight jobs, cached entries, sent emails, deployed clients.
- **Severity:** HIGH by default; CRITICAL when the string scopes trust (a tenant segment in a channel name, a redirect-URI allowlist entry).

## 2 · serialized-shape

A payload crosses a gap in space or time — a process boundary, a deploy window, persistence — and the reader is not the writer. Old data and mixed-version peers must still parse. The defining sub-case is the **mixed-version window**: rolling deploys, in-flight queue items, long-lived clients, persisted events, browser storage — the old shape exists somewhere and outlives the change.

- **Ask:** who reads this shape that doesn't build from this commit — old rows, queued messages, deployed clients, replayed histories?
- **Failure:** the reader crashes or misreads with no error at the writer; persisted old shapes fail **forever**, not just during the deploy.
- **Trace:** find every deserializer of the shape (parsers, `JSON.parse` + property reads, ORM rehydration, client unwrappers) and every store where old instances persist.
- **Universal fix:** additive-only changes (add optional fields, never rename/retype/remove); carry an explicit version and read all live versions; readers tolerate unknown fields and ignore unknown discriminators.
- **Severity:** CRITICAL when the shape is persisted or replayed (the break is historical, not just live); HIGH for live-traffic shapes.

## 3 · generated-artifact

A derived artifact must stay in sync with its source: ORM client from schema, types from codegen, lockfile from package.json, bundler aliases from tsconfig, seed SQL from a CSV. The artifact is trusted as if it were the source — when they drift, the artifact **lies** to everything that consumes it.

- **Ask:** what generates this, what does it generate, and would CI notice if they drifted?
- **Failure:** code compiles against stale types and mismatches at runtime; installs resolve a tree nobody tested; hand-edits are clobbered on the next generation.
- **Trace:** find the generator invocation (scripts, `prepack`, CI steps) and every consumer of the output; check whether generation is enforced or manual.
- **Universal fix:** regenerate in the same commit as the source change; CI-gate drift (`git diff --exit-code` after generate); never hand-edit generated output.
- **Severity:** HIGH by default; CRITICAL when the artifact governs installs or schema (lockfile, migrations).

## 4 · dual-authority

Two independent writers own the same state: two migration tools targeting one database, a framework that owns its own tables, an app route table and an ingress rule, hand-written DDL and an ORM mirror. Each authority is internally consistent; the state they share is not.

- **Ask:** who else writes this — and does either writer know the other exists?
- **Failure:** one authority clobbers or drifts from the other; the loser's consumers break with no signal on the winner's side (a schema push drops the auth library's tables; login breaks).
- **Trace:** list every tool/config with write authority over the state (migration runners, CLIs, IaC, admin dashboards) and what each believes the state is.
- **Universal fix:** designate one canonical authority and make the others read-only mirrors reconciled from it — or byte-align them and CI-check the parity.
- **Severity:** CRITICAL when the shared state is persisted data or auth; HIGH otherwise.

## 5 · config-elsewhere

A value is declared in one place and consumed in another — env vars, platform bindings, secret paths, ports, build-time defines. Reader and provider never reference each other statically, and the provider is often per-environment, so the break can exist in exactly one environment.

- **Ask:** for each value this code reads, where is it declared — in **every** environment, not just the one you can see?
- **Failure:** `undefined` at request time, boot failure in one env only, a stale build-time literal where a runtime value was expected, a secret baked into a public artifact.
- **Trace:** map each read (`process.env.X`, `env.BINDING`, `import.meta.env.Y`) to its declaration in every env file, deploy manifest, CI secret store, and dashboard.
- **Universal fix:** validate the full key set at boot and fail fast; keep a tracked example/contract file (`.env.example`); change reader and every provider in one commit.
- **Severity:** HIGH by default; CRITICAL when the flow direction is wrong (a secret reaching a client bundle) — that is also a trust-invariant break.

## 6 · trust-invariant

An auth or isolation guarantee that **fails open**: tenancy scoping, RLS policies, cookie flags, CSRF defenses, redirect-URI allowlists, JWT audience checks, public-env prefixes. Unlike the other mechanisms, breaking it doesn't stop the system — everything keeps working, plus an attacker path or a cross-tenant leak.

- **Ask:** if this check were deleted, would anything visibly fail — or would the system happily serve data it shouldn't?
- **Failure:** silent grant or disclosure. There is no error to observe; tests that only exercise the happy path stay green by construction.
- **Trace:** find every enforcement point of the invariant and every path that bypasses it (new endpoints, new tables, raw queries, `SECURITY DEFINER`-style escape hatches, spoofable inputs like `req.body.tenantId`).
- **Universal fix:** enforce centrally (middleware, policy, schema default) so a new code path inherits the invariant instead of having to remember it; default-deny on any missing input.
- **Severity:** CRITICAL, categorically. Loud auth failures (everyone locked out) cap at HIGH; it's the quiet successes that are CRITICAL.

## 7 · lifecycle-protocol

An ordering or sequencing agreement with a platform or across deploys: expand-then-contract migrations, deploy order between producer and consumer, graceful-shutdown draining, replay determinism, retry/idempotency budgets, timezone/DST assumptions, append-only version tags.

- **Ask:** does correctness depend on *when* or *in what order* this runs — and who else assumes that order?
- **Failure:** correct code applied in the wrong order: a migration that strands a rolling deploy, a retry that double-charges, a rename that orphans live stateful objects, a cron that fires on the wrong day twice a year.
- **Trace:** reconstruct the sequence the change requires (what must exist before what) and compare against how deploys actually roll out — including crash/retry paths.
- **Universal fix:** make each step independently safe (idempotent handlers, additive-first migrations, append-only version markers); many boundary violations dissolve by **reordering the plan**, not changing what ships.
- **Severity:** CRITICAL when a wrong order corrupts persisted state or duplicates money-adjacent side effects; HIGH otherwise.

---

## Domain contracts — stack-independent, always checked

Two contracts come from the product's information architecture, not from any technology, and are checked on every run:

- **entity-model — CRITICAL.** The entity vocabulary and topology (what the entities are, how they relate) that every module, migration, wire type, and doc agrees on. Re-relating or renaming an entity is a change to *every* mechanism at once. Sourced from `docs/architecture/` (domain model, ADRs), a contracts package, and the schema — never from a single module's view of it. Safe change: map every consumer before re-relating; coordinate schema + wire + client in one planned sequence.
- **tenancy — CRITICAL · trust-invariant.** The invariant that every request carries a non-spoofable tenant identity and all data access is scoped by it, at every layer. Its enforcement points are technology-specific (a JWT claim, a channel-name segment, an RLS policy, a scoped query helper) but the invariant is one contract — a single unscoped path anywhere breaks it.

---

## Severity recap

The scale is `SKILL.md` step 4; each mechanism's **Severity** line above places a finding on it.
