# Contract ownership `src/contracts` is not a default destination for every shared-looking type. A contract belongs there only when the change authority is genuinely shared across layers, capabilities, build tooling, or runtime composition. ## Decision rule For every proposed contract, ask: 1. Which requirement can cause this type or policy to change? 2. Is there one clear capability or feature owner? 3. Does another runtime/tooling boundary consume the same semantic contract? 4. Is the contract a wire/artifact authority shared by browser runtime and build/release tooling? The placement rule is: - one feature owner -> keep it under that feature, - one reusable capability owner -> keep it under that adapter/capability and export it through the capability public entry point, - multiple independent capability/layer owners -> `src/contracts`, - browser/build/release wire or artifact authority -> `src/contracts` even when the browser source graph alone looks small. Consumer count alone is not sufficient. Scripts, generated artifacts and release gates are semantic consumers too. ## Audit result The September 2026 architecture review triggered an import-graph audit of all 39 contract files. ### Capability-owned contract moved `cursor-pagination.ts` had one production owner: `src/adapters/query-cache/cursor-pagination-runtime.ts`. It moved to: `src/adapters/query-cache/cursor-pagination-contract.ts` and is exported through: `src/adapters/query-cache/index.ts` Tests use that public capability entry point. Pagination vocabulary no longer occupies the global contract bucket merely because it is reusable inside one adapter. ### Contracts intentionally kept global The following examples have multiple semantic owners and remain global: - `errors.ts` — application, presentation and several adapters, - `result.ts` — common success/failure carrier below application, - `boundary-mapper.ts` — HTTP, browser RPC, realtime and feature registries, - `mutation-intent.ts` — application, presentation, HTTP, platform and bootstrap, - `exact-snapshot.ts` — HTTP, query-cache and browser-transfer, - `rest-profiles.ts` — auth, HTTP, bootstrap and feature contract validation, - `query-invalidation.ts` / `query-keys.ts` — query-cache, presentation, bootstrap and features, - `cache-invalidation.ts` — cross-context wire protocol plus query invalidation policy, - `storage-keys.ts` — browser storage and cross-context invalidation, - `telemetry.ts` / `diagnostics.ts` — runtime adapters, application and bootstrap. Some contracts appear to have few browser-source consumers but are still shared authorities: - `env.ts` is consumed by bootstrap, runtime-schema/security tests and registry governance, - `deployment-admission.ts` is shared by runtime-config generation and release admission, - `release-tokens.ts` is shared by runtime coherence tooling and tests, - `service-worker-static-manifest.ts` is a runtime-neutral canonical format shared by build generation, validation and service-worker evidence. Moving those based only on `src/**` import counts would split one semantic authority across processes. ## Feature contracts Feature-specific contracts stay inside the vertical slice: `features//contracts` The reference feature owns routes, schemas, mapper definitions, message catalogs and contribution identities. Central installed files aggregate those contributions; they do not own their semantics. The message catalog is a deliberate special case: the compiled catalog remains total even when a feature is build-time disabled so the typed message lookup does not become partial. The central message file therefore aggregates compiled message keys rather than treating runtime installation as message ownership. ## Review rule for future additions A new file under `src/contracts` should be rejected during review when all of the following are true: - one feature or one capability is the only semantic owner, - no build/release/runtime wire authority needs the same definition, - moving the definition to that owner does not create an inward dependency violation. Do not move a contract merely to reduce the number 39. The goal is explicit ownership, not a smaller directory.