Trap Catalog Maintenance
Trap Catalog
data/traps.json is the load-bearing artifact for Mobile Surfaces’ agentic-development surface. It enumerates every silent-failure trap, contract invariant, and platform constraint that downstream consumers (the AI assistant guides, future audit CLI, future MCP server, the long-form troubleshooting recipes) read from. Edit the catalog; everything else regenerates.
Pipeline
data/traps.json ──► packages/surface-contracts/src/traps.ts (Zod validation)
├─► AGENTS.md (generated by scripts/build-agents-md.mjs)
└─► CLAUDE.md (identical content; Claude Code reads this directly)
Additional consumers shipped in v7:
npx mobile-surfaces audit [path]: walks the catalog against an existing Expo project, emits a pass/warn/fail report with MS-id chips anddocsUrllinks. Backed by the same script set that runs inpnpm surface:checkfor this repo. Available with thecreate-mobile-surfacesinstall.
All consumers read from this catalog. None are hand-maintained.
Catalog schema
Defined in packages/surface-contracts/src/traps.ts and exported as trapCatalog. The top-level shape:
{
"schemaVersion": "1",
"entries": [ /* TrapEntry[] */ ]
}
Each TrapEntry:
| Field | Type | Required | Notes |
|---|---|---|---|
id | MS\d{3} | yes | Stable across releases. Append new ids; never reuse. |
title | string | yes | Short imperative title. |
severity | error | warning | info | yes | See Severity. |
detection | static | config | runtime | advisory | yes | See Detection. |
tags | TrapTag[] | yes (≥1) | Free-form within a closed enum; see traps.ts. |
summary | string | yes | One-sentence statement of the rule. |
symptom | string | yes | What the user sees when the rule is violated. Live Activity failures are mostly silent, so write the silence: “no error, just X never appears.” |
fix | string | yes | Concrete fix in one or two steps. |
iosMin | string | no | Minimum iOS version where the rule applies, e.g. "17.2". |
enforcement.script | string | no | Repo-relative path to the script that enforces this rule today. The validator confirms the file exists. |
appleDocs | URL[] | no | Pointers into Apple documentation when the failure mode is platform-defined. |
docs | string[] | no | Pointers into local docs/ (path + optional #anchor). |
since | semver | yes | Catalog schema version when the rule was introduced. |
deprecated | boolean | no | Set when the rule has been retired but the id is reserved. |
Severity
| Severity | When to use |
|---|---|
error | Violation breaks a contract, produces a silent failure on real devices, or makes a build unshipable. AI assistants must not bypass error rules. |
warning | Violation degrades reliability or operating cost (e.g. priority budgets, end-of-life token cleanup) but does not break the user experience on the first send. |
info | Awareness-only. Apple bugs, force-quit caveats, cross-platform notes. Detection is advisory. |
Detection
| Detection | Meaning |
|---|---|
static | Repo-local script can verify the rule by reading source files. Most catalog rules are here. |
config | Verifiable from declarative config (app.json, package.json, expo-target.config.js). |
runtime | Only surfaces at send/receive time. APNs reason codes, token environment crossing, payload-size ceilings. |
advisory | No programmatic check. Captured in the catalog so the rule appears in AGENTS.md and the user has runbook coverage. |
Workflow: adding a rule
- Pick the next id. Highest existing
id+ 1, padded to three digits. Reserved ids stay reserved even when retired. - Add the entry to
data/traps.json. Keep entries in numeric order. Multi-line prose is fine; JSON requires\nfor line breaks but most fields read better as a single sentence. - Run
pnpm traps:check. Validates the catalog against the Zod schema and confirms everyenforcement.scriptexists on disk. - Run
pnpm agents:build. RegeneratesAGENTS.mdandCLAUDE.md. - Run
pnpm surface:check. Confirms the umbrella picks up your new rule and nothing is stale. - Commit
data/traps.json,AGENTS.md, andCLAUDE.mdtogether. A drift-free PR is a one-shot review.
If the rule is static or config and you want CI to enforce it, add the script under scripts/ and reference it via enforcement.script. The validator script in scripts/validate-trap-catalog.mjs confirms the path exists; the script itself runs from surface:check. The next milestone (mobile-surfaces check) will route enforced rules through these scripts directly so the catalog and the runner share one definition.
Workflow: editing or deprecating a rule
- Edit: mutate the entry in place. Bump
sinceonly if the change widens the set of inputs that violate the rule (i.e. an existing project may now report a new error). Tightening detection without changing the rule’s meaning does not require asincebump. - Deprecate: keep the entry, set
deprecated: true, optionally add adeprecatedReason-style note insidesummary. Do not delete and do not reuse the id.
Why a catalog instead of hand-written AGENTS.md
AGENTS.md files rot. Project conventions evolve, iOS minor versions shift the deployment floor, Apple closes radars, and @bacons/apple-targets ships features that obsolete entire rules. A hand-maintained AGENTS.md is a rotting prose document by month six.
A structured catalog gives every fact one home. When iOS 27 lands and the deployment floor changes, we update MS012 in data/traps.json, regenerate, commit. The change is a one-line diff plus the regenerated artifacts. Reviewing it is trivial, and every downstream consumer (the AI guide files, the future audit CLI, the long-form docs) picks up the change without manual edits.
See also
AGENTS.mdandCLAUDE.md: generated guides for AI coding assistants.docs/concepts.md: the contract, the surfaces, the adapter boundary.docs/troubleshooting.md: long-form symptom-to-fix recipes; the catalog summarizes whattroubleshooting.mdwalks through.