# Platform — Agent Operating Manual

Modular boilerplate platform. **Mission, the one line above every disposition: _all the building blocks you need for your project, and for any future project you start._** You (the author) are **adopter #1** — dogfooding across your own future projects what **thousands of unknown third-party adopters** will later install; both are real consumers, and every contract is shaped for the unknown one (north-star below). A pnpm/turbo monorepo of reusable **`@platform-modules/*`** packages, mostly **adapted from prior production apps** into versioned, headless, swappable libraries any app installs à la carte.

> **North star — design every public contract for it:** the end state is a **FOSS, host-agnostic application boilerplate** adopted by **thousands of unknown third-party projects**, each running on **any host** (serverless edge, Node self-host, container, …) with **whatever framework / provider / validator the adopter already chose**. Sourcing from prior apps only *seeds* this — prior apps prove a seam is real; the consumer you design for is an **unknown adopter on an unknown host**, never just today's reference apps. Four standing consequences: (1) treat **every public export as a frozen, semver-grade contract** shaped to the **ecosystem-standard interface** of its capability class, never to one reference app's call site or one host's SDK; (2) **never impose or bundle** a host, framework, provider, or validator — each sits behind a **swappable adapter seam** the adopter chooses; (3) **the adopter is increasingly an AI agent, not only a human — make every seam agent-legible:** fully discoverable and callable from its **types + DTS + machine-readable `exports`/`registry.json` alone**, with typed inputs/outputs and typed errors (no bare throw), **uniform packaging across modules** (an agent that learned one operates all), and a co-located behavioral test per export as the usage example — so an agent wires a seam **without reading the impl**; (4) **device-agnostic by design — binds the presentation axis only** (`ui-*` family + `-react`/framework siblings + templates/distros; headless L0–L3 cores carry no UI surface, exempt): every UI contract is **responsive by design, never desktop-first retrofitted** — MUST render and stay usable phone→tablet→desktop→large-screen with no adopter layout rewrite; primitives adapt to **their container (container queries), never the viewport**, only page shells use viewport breakpoints; a fixed-width layout container or desktop-only grid is a **defect at the seam — same hard-floor weight as a11y (§1)**. Responsiveness is a **typed token contract + enforced rule, never a per-component convention** — the token mechanics (`--breakpoint-*` contract, the shared `--container-*` namespace trap, enforcement) are canonical in `docs/standards/coding-standard.md` §6; point there, never re-copy. Consequence (3) splits into two phases — sequenced in `docs/plans/2026-06-16-agent-experience-roadmap.md` (canonical; don't re-inline): **Phase 1 (now)** = agent-legible seams, **mostly already delivered** by the §4 seam checklist + §6 conventions (name those as *agent affordances*, never weaken them); the only new Phase-1 surface is keeping each package **self-describing**. **Phase 2 (planned, deferred, lower priority)** = an agent-operable MCP/skill control surface — it **is** on the roadmap, but it is **gated per-tool** (Gate-1 delete-test + adapter-minimalism: a thin adapter over an existing operation, never a reimplementation) and built only **after** Phase-1 modules + the publish path are stable. Never build Phase 2 speculatively. This **tightens** the agnosticism + contract-stability + agent-legibility bar; it does **not** loosen **YAGNI-on-surface** (§3) — build only the slice you can prove now, but shape its seam as if public forever.

> **The one principle: be lazy in the implementation, strict at the seam.**
> Climb the §2 ladder inside a function; satisfy every §4 box at an export. A `@platform-modules/*` package *is* its seam — a typed contract that stays stable while the impl underneath is swapped/optimized/re-ported.

This file is **platform-specific doctrine + the agentic wiring**. General operating rules (caveman, auto-commit, never-co-author, verify-don't-ask) are inherited from `~/.claude/CLAUDE.md` — not repeated here. Don't duplicate; point.

---

## 1. The law (canonical docs — read before acting, don't re-inline)

| Doc | Governs | Load when |
|---|---|---|
| `docs/standards/coding-standard.md` | **how code is written** — §2 ladder · R1/R2/R3 porting hazards · §4 seam checklist · §5.1/R4 preserve audit-hardened prior-app code · §6 `-react` overlay | before writing/porting any `@platform-modules/*` code; §4 before declaring an export done; §5.1 before porting any money/auth/webhook path |
| `docs/specs/2026-06-13-monorepo-architecture-synthesis.md` | **what/where** — the layer DAG · governance patterns A/B/C · build sequence (**§6 status table superseded by the registry**) | choosing what to build, where it sits, in what order |
| `docs/plans/module-plan-template.md` | **the build filter** — Gates 0–3; copy per module before any task | spec'ing a module |
| `docs/registry.json` (**machine query surface**) · `docs/specs/2026-06-12-module-registry.md` (**canonical prose source** it mirrors) | **the canonical structure index** — every module/subpath/adapter/dep/layer/status; a **filter, not a backlog** | **grep/`ctx_search` the JSON** for "what's the structure / does X exist / layer-status-deps" — context-cheap, never full-load; read a **scoped MD section** only for the *rationale* behind a disposition. Don't load both — the JSON exists so you don't load the prose. **Before any exploration agent** |
| `docs/standards/money.md` | **money-path invariants M1–M8** — claim→provider→settle phases, atomic claims, idempotency keys, webhook claims, release discipline | before writing/porting ANY code that moves money (charge · refund · payout · PSP webhook) |
| `docs/standards/authz.md` | **authorization invariants A1–A6** — per-branch ownership, IDOR, actor-filtered updates, enumeration surface | before writing/porting any endpoint that reads/mutates a resource the caller might not own (≈ every server export with a request boundary) |
| `docs/standards/ui-api-conventions.md` | **primitive API shape** — the four API families + per-family rules; owns ref/prop-surface decisions | before adding or changing any `ui-primitives` component API |
| `docs/standards/ui-liveness-and-a11y.md` | **`ui-*` liveness contract** — state matrix, token tiering, island/hydration policy, a11y conformance floor | before building/reviewing any `ui-*` family code |
| `docs/standards/mod-design-system.md` | **dogfood visual doctrine** — blueprints + demo previews ONLY; NEVER governs `@platform-modules/*` or adopters | before authoring any dogfood screen/theme (`apps/mod-cms`, `apps/mod-www`, `docs/viz/`) |

**Hard floor — never on the chopping block, any rung:** trust-boundary validation, data-loss handling, security, accessibility. The §2 laziness applies *above* this floor, never through it.

**Robustness default — robust vs hacky is NEVER a question (owner directive 2026-06-19).** When a decision is **one robust/industry-standard option vs one hacky quick-win**, the answer is **ALWAYS robust** — do **NOT** surface it as a choice. You cannot obtain permission to ship the worse option by asking; asking just stalls an autonomous build for an answer the standing `caveman ultra` directive already fixed. A **UX footgun** (e.g. leaving a refresh flow unwired so sessions force re-login) is **not a user decision either** — **you** advise against it and build the robust path. Reserve `AskUserQuestion` for decisions genuinely the owner's (product-scope ambiguity with no robust default, mutually-exclusive *valid* designs, irreversible external ops) — never for "do it properly vs take a shortcut."

**Spec-first — the specs ARE the source of truth.** The `docs/specs/*` boundary specs (detail) + the synthesis doc (sequence/registry) are authoritative; code conforms to them, never the reverse. Any bug fix or behavior change starts at the spec, in this order: **amend the spec → update the module plan → then change code.** Code that diverges from its spec is a defect *even when green* — reconcile by fixing the code, or by a deliberate, dated spec edit, never by silent drift. This rule has teeth at two build stages (§4): **build kicks back** to the spec when the spec is found wrong/incomplete mid-port (stop coding, amend spec, resume), and **review checks the diff against the module's boundary spec**, not just the §4 seam checklist.

---

## 2. The layer DAG (build strictly bottom-up; acyclic)

```
L0 FOUNDATION (zero/near-zero runtime dep)   @platform-modules/util · @platform-modules/db · @platform-modules/i18n   (i18n reclassified —→L0 2026-06-16: zero-dep foundation; events DISSOLVED 2026-06-14 — adoption count ×0; decoupling = jobs/outbox + direct calls)
L1 CORE INFRA (→L0)                          @platform-modules/jobs · @platform-modules/mail · @platform-modules/auth · @platform-modules/tenancy · @platform-modules/cache
L2 DOMAIN PRIMITIVES (→L0/L1, acyclic)       @platform-modules/ledger ★ · @platform-modules/tax · @platform-modules/notifications · @platform-modules/uploads
                                             @platform-modules/search · @platform-modules/seo · @platform-modules/ai · @platform-modules/realtime · @platform-modules/billing(pilot) · @platform-modules/audit
L3 COMPOSITE / BOLT-ON (compose L2)          @platform-modules/marketing · @platform-modules/invoicing · @platform-modules/helpdesk · @platform-modules/affiliate
```

Never build a layer-N module before its layer-(N−1) deps exist. **Shipped:** `@platform-modules/i18n` (L0), `@platform-modules/i18n-react` (framework-axis sibling). `@platform-modules/realtime` shipped — core barrel **types-only** (browser-safe), the Workers-locked `/server` subpath **built** (DO/Queue helpers: broadcast · hibernatable-accept · publish · queue-consumer · timing-safe internal-secret); `@platform-modules/realtime-react` shipped. Full registry + per-module status: **query `docs/registry.json`** (the machine mirror — grep/`ctx_search` it for structure facts; context-cheap, **never full-load**) and read **scoped** sections of **`docs/specs/2026-06-12-module-registry.md`** (the canonical prose source it mirrors, reconciled 2026-06-16) only for the *rationale* behind a disposition. The JSON exists so agents don't load the prose — **don't defeat it by loading both.** The synthesis doc §6 status table is superseded (synthesis §1 layer DAG + §2–§7 sequencing remain authoritative).

---

## 3. Governance (the filters that decide *whether* and *where*)

- **Disposition rule (GENERALIZABILITY test — supersedes the adoption-count floor; owner directive 2026-06-18):** The decision is **"can this be generalized to serve other future projects?"** — **NOT** "how many prior apps already have it." **Default = BUILD.** An owner ask for a real project **IS** the need — it serves this project *and* the many future ones the kit must start in hours — so it is **NEED-IT-NOW, never YAGNI.** Build at **zero prior apps** when the owner needs the building block **AND** it is **generalizable** (one contract serves multiple future app *classes*). **YAGNI now means exactly one thing: nobody asked for it** (no current/near consumer). **Adoption count is a *historical sourcing signal*, no longer a build gate** — the platform is **mostly done adapting from prior apps**; **net-new module-building is now the default mode**, and a **first real use is a valid trigger to author a new module** (when no prior app exists to adapt from). **The ONE override → NOT a module/template/blueprint; stays HOST-OWNED:** the capability is **highly specialized** — it owns logic that *defines what one specific product IS* and **cannot be cleanly abstracted** for other products. Test: *"would any other app want this exact logic?"* — **No → host-owned; Yes → build/share.** This is the **app-specific-vs-abstraction split** (same axis as R5 generic-vs-app-domain): abstract and share the generalizable mechanism; leave the product-defining specialized logic in the host.
  - **Host-owned (specialized — IS the app):** a highly-specialized product feature (e.g. a ticketing app's ticket-selling, a transcription app's transcription) — logic that *defines what one specific product is* and cannot be cleanly abstracted. **Generalizable → build/share even at ×1/×0:** **QR-code validation** (carried by more than one prior app) · **LLM usage** (→ `ai`).
  - **Blueprint granularity corollary:** name the **abstraction**, not the instance — *"FOSS website"* = too narrow; *"project-site"* = abstract enough.
  - **Still binding (these gates did NOT change — they bound *shape*, never *whether-to-build*):** **Gate-1 delete-test** (a real module's complexity *vanishes* on delete, never just relocates — else dissolve to a `@platform-modules/util` subpath/leaf, never a standalone module); **one contract** for the generalization — a *lookalike* need with an **incompatible shape** is two things, not one module (measure the contract against the **ecosystem-standard interface** thousands of unknown adopters expect, never a single reference app's call site — a reference app that diverges is evidence the *reference app* is non-standard, not license to bake its quirk in); and **YAGNI-on-surface** (build the *right-sized* seam the need requires, never a speculative framework — bounds *how much surface*, never *whether to build*).
- **Capability altitude (R5 — thin core, importable growth):** disposition decides *whether a module exists*; R5 decides *how much of a mature capability it carries, and where each piece sits.* The host-vs-module-capability test is **generic-vs-app-domain, not adoption-count**: a generic mature capability is **carried as an importable subpath** (or composed from a sibling module), **never discarded to the host as "app-specific"** — only this app's entities/rules/schema/wiring stay host. **YAGNI bars *inventing* surface; R5 bars *discarding* mature surface** — among already-mature capabilities, default to importable over host-dump. Build the most mature form, layered for opt-in; ship maturity you have, never futures you guess; freeze a ×1 capability's contract only when a **non-reference-app** consumer confirms it. Full ladder + guardrails: `docs/standards/coding-standard.md` §5A. Extends the forward-need rule above to the *capability* grain (not just whole-module).
- **Gate 1 delete-test (keystone):** *delete this module — does complexity vanish, or just relocate into N apps with a new dep added?* Relocates → **not a module** (dissolve to `@platform-modules/util` leaves + a documented pattern, or keep in host). A "no" is a successful outcome. Killed `@platform-modules/cron`, `cache/http`, `@platform-modules/kv-store`.
- **Pre-1.0.0 = ZERO backward-compat tax (owner directive 2026-06-18).** Until the deliberate public `1.0.0` (`@platform-modules/*` stay `0.x` until the final release — any `1.0.0` before it is a defect), there are **no external consumers** — only the owner (adopter #1). So **never** justify keeping anything with *"removing it would break X."* The only question is: **"would removing/changing it make the PRODUCT better?"** If yes → remove/change it freely; a bootstrap shortcut, a transitional shim, a v0.0.x acceptance path are all **deletable on merit, not protected by precedent.** Backward-compat, deprecation cycles, and "don't break the old path" are **post-1.0.0** concerns — applying them now manufactures legacy bloat. (Killed the static `ADMIN_TOKEN` bootstrap in favor of unified `auth`-issued credentials under exactly this rule.) Caveat: this loosens **compat**, never the **Hard floor** (§1) — security/data-loss/a11y/validation still bind.
- **Pattern A — provider-in-charge → config, not a module.** If a provider does X as an intrinsic side-effect of Y it already does, X is config of the Y-adapter (Sumit invoice-on-charge → billing config, not `@platform-modules/invoicing`).
- **Pattern B — a shared primitive lives ABOVE its consumers.** Consumed by ≥2 siblings → standalone, never nested under one (`tax`, `ledger` sit above billing).
- **Pattern C — pricing model (inclusive vs exclusive) is a host-level boundary driver.** Inclusive (IL/EU) → rate resolvable pre-charge → shared primitive; exclusive (US) → at-charge → can hide in billing.
- **Gates 0–3** (module-plan-template): 0 candidate rubric · 1 delete-test · 2 adapter-minimalism (one direct function, no Service/Repo/Controller layers until earned) · 3 consumer-harness fixture in `apps/consumer`.

---

## 4. The agentic framework (assembly line — shape here, dispatch policy in the skill)

**Dispatch policy is MAIN-LOOP-ONLY and lives in the `platform-orchestrator` skill — invoke it before any `@platform-modules/*` build work.** *Who* runs each stage (survey · build · per-diff review), the model/effort tiers, fix-routing (LOP≥LOC), serial+pipeline parallelism, the build sequence, and the pilot load into *my* context only when I invoke that skill. They are deliberately **kept out of this file**: a Claude `Agent` subagent auto-loads `CLAUDE.md`, so dispatch policy here would pollute a scoped subagent's context — that split is the whole point.

The assembly line — **shape only** (policy in the skill): **survey ─▶ spec/gates ─▶ build ─▶ review (adversarial) ─▶ harness ─▶ ship**.

**Lifecycle skills — route by the trigger; the WHEN/WHY/HOW below is the router, the full procedure lives in each skill body + `module-plan-template` (don't re-inline it):**

| Skill | Use WHEN | WHY it exists | HOW to enter |
|---|---|---|---|
| **`platform-extract-modules`** | a capability is duplicated across ≥1 prior app and you want it shared · asking "is X a module candidate?" · designing adapter/capability/domain boundaries | platform code is **mostly adapted from prior apps** — adapting beats reinventing; it is the module-porting assembly line (survey→disposition→call-site audit→classify→seam→scaffold→migrate→harness→publish) carrying the candidate rubric, the 3 axes, and the anti-patterns | `/platform-extract-modules`. The main loop owns disposition/gates/seam (never delegated); gates in `module-plan-template` |
| **`platform-make-modules`** | building a **NET-NEW** module for a capability that exists in **zero** prior apps | its **scan-gate** stops you reinventing existing code — it surveys prior apps first and routes to extract the moment any prior app has it; only a genuine zero-reference capability is authored fresh | `/platform-make-modules`. Holds no code rules of its own → points to `coding-standard.md` + gates, scaffolds via `turbo gen` |
| **`platform-embed-module`** | adopting / installing / wiring a `@platform-modules/*` package **into** a consuming app, or testing that a module swaps in cleanly | embedding differs sharply per **integration axis** (A siblings · B db-migration · C stores · D provider · E endpoint · F react) — it classifies, wires *only* the needed seam (adapter-minimalism = one wiring file), proves **swap-survival parity** vs the host's hand-rolled code, and leaves a rollback | `/platform-embed-module`. Vehicle = local `file:` link (nothing published yet — all modules `0.0.0`) or GHP for adoption; per-module axes in its `references/module-axes.md` |
| **`platform-make-template`** | authoring a **NET-NEW template** — a multi-screen UI flow (screen-set) for a blueprint | its **scan-gate** surveys prior-app *screens* and adopts a convergent screen-shape instead of reinventing; its **binding gate** blocks a module-bound flow until the backing `@platform-modules/<core>-react` sibling ships (delivery-stack §3.1); generic content templates (landing/docs) build now. Enforces *never a "template package"* (copied + host-owned) | `/platform-make-template`. Holds no code rules → points to `delivery-stack` §2/§3.1, `coding-standard.md §6`, `mod-ui-enforcement` |
| **`platform-make-distro`** | authoring a **NET-NEW distribution** — a themed, installable, self-hostable **product** over a blueprint | its **prereq-gate** requires a built+green blueprint first (delivery-stack one-rule), its **YAGNI gate** blocks speculative distros (build only for a real install/self-host consumer), and it carries the **graduation rule** (Debian-from-kernel: own repo on frozen-contracts + proven-publish). Adds only theme+defaults+wizard+CMS — never reusable code | `/platform-make-distro`. Holds no code rules → points to `mod-www` design §0/§9/§10, `delivery-stack §2` |
| **`platform-orchestrator`** | **before any `@platform-modules/*` build/dispatch work** (main-loop only) | it carries the **dispatch policy** (roster · model/effort tiers · fix-routing LOP≥LOC · serial+pipeline · build sequence · pilot), deliberately kept OUT of this file so a subagent's auto-loaded `CLAUDE.md` is not polluted by it (the ¶ above is the why) | invoke it into the main loop; **never inline its policy here**; subagents never invoke it |

**Lifecycle map (two grains, one dispatcher):** **module grain** — **make-modules** (zero-reference, scan-gated) → routes to **extract** (prior app → module) → **embed** (module → consumer); **delivery grain (above modules)** — **make-template** (screens → flow, copied/host-owned) and **make-distro** (blueprint → themed installable product) climb the delivery stack (`delivery-stack §0`). **orchestrator** governs build dispatch across all of them. All six are **project-only** (`.claude/skills/`, `platform-*` prefix) — never global.

**Three rules here ARE shared law — every subagent inherits them, they are not dispatch policy:**
- **Spec-first kickback (§1):** a builder that finds the boundary spec wrong, ambiguous, or incomplete mid-build **stops** — the spec is amended and the plan updated *before* code resumes; never a silent "fix" that diverges from the spec.
- **Review criterion (§1):** a diff is judged against the module's **boundary spec** + the coding-standard **§4 seam checklist** + the R1–R3 porting hazards + the §2 ladder; a green diff that contradicts its spec is **rejected, not merged**.
- **Judgment is never delegated:** disposition, gate pass/fail, boundary/seam design, the spec, the wave-plan/TDD decomposition, sequencing, synthesis, and integration are the main loop's alone — a subagent gathers evidence or executes a fixed task, it never renders the verdict.

---

## 5. Runtime: web-standard core, host primitives behind adapter seams

**Rule: core imports zero host-specific SDK — server code is web-standard `Request`/`Response` only.** One module then runs unchanged on serverless edge, Node self-host, a container, or another host, and under any framework router (Astro endpoint, Hono, Next, a bare `fetch` handler) — never force a consumer to migrate framework or host.

**Stateful/edge primitives are contract seams, not direct dependencies.** A module needing key-value, queue, blob/object, durable-coordination, or SQL declares a **typed interface** and consumes that; each host is an **adapter behind the interface**. Build the adapter the current work needs — the **CF Workers adapter is the first reference adapter, not the lock** — and design the seam so another host's adapter slots in **without touching consumers**. Never bundle a host primitive (Durable Objects, Queues, KV, R2, D1, Hyperdrive, `cloudflare:workers`, or a Vercel/Node equivalent) into a module; it lives in its adapter. (This is the same agnostic-contract-plus-per-adapter shape `@platform-modules/db` already uses for its drivers — apply it to every host primitive.)

**CF Workers is the tightest reference budget, kept as a design floor:** ~1–3 MB compressed bundle and a no-Node-builtins runtime are real constraints — a module that fits the strictest host fits the looser ones. Hold them as a floor, **not** as a target that excludes other hosts. Provider SDKs stay `peerDependencies` behind an adapter, never bundled into L0.

---

## 6. Repo conventions

- **pnpm workspace**; sibling `@platform-modules/*` linked `workspace:^` (see *Dependency classification* below), shared versions via `catalog:`. Dev with workspace links — never edit a module from inside a consuming app.
- **tsdown** build (`@tooling/tsdown-config` → `tsdownBase`), DTS on, `external` everything cross-package (`react`, provider SDKs, **and** sibling `@platform-modules/*` deps). **turbo** `build` `dependsOn: ["^build"]`.
- **TypeScript split (temporary):** lifecycle `tsc` is native TypeScript 7 via `@typescript/native`; the module name `typescript` intentionally resolves to `@typescript/typescript6` for Astro/tsdown and other compiler-API consumers. `tsc6` is the explicit TS6 CLI. Do not collapse the aliases until embedded-language tooling supports the TS7 programmatic API; `scripts/typescript-toolchain.test.mjs` pins this contract.
- **Dependency classification (semver-cascade-safe — apply at every package.json).** Declare sibling `@platform-modules/*` deps as regular `dependencies` (genuinely-optional ones → `optionalDependencies`), pinned `workspace:^` — **never `peerDependencies`.** Reserve optional `peerDependencies` for genuinely **adopter-supplied / host-swapped externals**: framework (`react`/`react-dom`), provider SDKs (`resend`/`postmark`/`@aws-sdk/*`/`stripe`/`better-auth`), `drizzle-orm`, `@cloudflare/workers-types`. **Why:** no module imports a sibling as a shared runtime singleton — siblings are consumed as factories / pure functions / error-classes / types — so peer-dedup buys nothing, while sibling-as-peer (a) **force-majors every dependent in changesets** on any non-patch bump (the spurious `1.0.0` cascade), and (b) publishes an over-rigid exact-version peer pin; `workspace:^` publishes a permissive `^x.y.z` range. **Cross-package error identity must not rely on `instanceof`** (two deduped copies break it) — export/use a structural type-guard. (Reclassified repo-wide 2026-06-17; supersedes the prior "siblings = peerDependencies" convention — older module *plans* still show the prior form.)
- **ESM-only** packages: `"type":"module"`, `exports` with `types`+`import` conditions, `files:["dist"]`, **`sideEffects:false`**. One subpath per *cohesive capability group* (`./rtl`, `./format`); **the framework axis (`-react`, future `-astro`) is a separate flat sibling package, never a `@platform-modules/<core>/react` subpath or `@platform-modules/react` umbrella** (a `./react` subpath poisons the core's zero-dep guarantee; an umbrella is a fan-in hub that breaks swap-survival).
- **vitest** co-located `*.test.ts(x)` (jsdom for `-react`). One behavioral test per export — fallback + edge inputs, not the happy line.
- **changesets** for per-package semver. Breaking a public signature = semver major.
- Single `main` trunk — all work merges into `main` via PR; **never push directly to `main`** (enforced by `lefthook.yml` `block-main-push`). Agents: commit to a feature branch, push, open a PR, merge via `gh pr merge`. (Collapsed from an accidental `master`/`main` split, 2026-06-14.)
- **Explore once, query forever.** When you survey/catalog something not catalogued before (a capability sweep, a UI survey, any "which prior app has X / how do prior apps do Y" answer): (1) **persist** it as a dated artifact under `docs/catalog/` or `docs/specs/` — never leave it only in chat; (2) **SHA-pin** it at the finest grain that matters (**path-scoped** `git -C <repo> log -1 --format=%h -- <path>` where possible). **Before using any catalogued survey, check freshness** (compare its pin to the source's current state); **fresh → use it, do NOT re-explore; stale → re-survey ONLY the changed source at the changed grain** (lazy refresh), bump that pin. Read-only freshness re-check / cheap single-source refresh = `Explore` `model:'haiku'`; a build-feeding content re-survey = non-opus Sonnet-class (cursor). **Read-only exploration is NEVER opus** — opus is judgment-only (see `platform-orchestrator` skill).
- **No ignored signals.** Every error, warning, notice, or hint from a build, test, commit, or write/edit is addressed before moving on — *fixed*, or *explicitly justified as benign* (never silently passed). A pnpm `WARN`, a type hint, a hook notice all count. Green means *clean*, not *passed-with-noise*.
