# Infrastructure work shape

How infrastructure work — new core packages, new external services, new database backends, new build/deploy primitives — flows through the agent-first workflow. For the broader workflow context see [`docs/architecture/agent-first-workflow-and-conformance.md`](../architecture/agent-first-workflow-and-conformance.md).

## When this guide applies

You're proposing or implementing:

- A new optional core package (`core-cache`, `core-email`, `core-feature-flags`, …)
- A new external service or layer (Redis, CDN, alternative CMS, additional message bus, …)
- A change to bootstrap, build, or CI infrastructure
- A swap of an existing infrastructure component

If you're working on backend feature code or frontend, this is not your guide.

## Two categories

| Category | Example | Path |
|---|---|---|
| **A. New optional core package** | `core-cache`, `core-email` | `pnpm turbo gen core-package <name>` |
| **B. New infrastructure layer** | Redis, CDN, deploy target, CI image swap | ADR → integration PRD → epic + stories |

Category A is well-trodden: the generator emits a canonical core-package shape; the conformance system already handles optional cores via `requiredCores` in manifests. No new conformance rules required.

Category B is the one that needs the ADR-first dance described below.

## ADRs precede infrastructure work

ADRs (Architecture Decision Records) live at `docs/adr/NNN-<slug>.md`. The pattern is established in this repo (ADR-018 captured the audit-and-compliance system, for example).

ADRs are to infrastructure what PRDs are to features: decision documents, written first, providing the rationale that downstream PRDs and stories implement. An ADR documents *what was decided and why*; a PRD documents *what to build*.

## ADR authoring flow

```
1. Human runs `pnpm work adr-new "<one-line proposal>"`
2. Dedicated ADR elicitation skill interviews the human:
   - Context (what's the situation today?)
   - Drivers (what's forcing a decision?)
   - Considered options (what alternatives are on the table?)
   - Trade-offs (what does each option cost?)
   - Decision (which option, and why?)
   - Consequences (what changes downstream?)
3. Agent drafts ADR at docs/adr/NNN-<slug>.md with status: proposed
4. Human reviews, edits, flips to status: accepted (or rejected / superseded)
5. Accepted ADR(s) trigger one or more integration PRDs
6. PRDs flow through the normal decompose → dispatch loop
```

The ADR elicitation skill is distinct from the PRD elicitation skill. Same interview shape, different template and pushiness:

- PRD eliciter focuses on **problem framing** and **success criteria**
- ADR eliciter focuses on **alternatives** and **trade-offs** — it actively pushes back if only one option is articulated

## ADR template

```markdown
---
id: NNN
title: <decision title>
status: proposed | accepted | rejected | superseded
date: YYYY-MM-DD
supersedes: []
superseded-by: null
related-prds: []
---

## Context
What's the situation? What's broken or about to break? Who is affected?

## Drivers
What's forcing this decision now?

## Considered options
- Option 1: ...
  - Pros / Cons
- Option 2: ...
  - Pros / Cons
- Option 3: ...
  - Pros / Cons

## Decision
We chose Option X because ...

## Consequences

### Positive
- ...

### Negative / accepted trade-offs
- ...

### Follow-up work
- PRD: ...
- PRD: ...
```

## Path A: new optional core package

When the new infrastructure is *small enough to be a single package* (cache, email, feature flags, etc.):

1. ADR (if the decision is non-trivial — for "add core-cache because we need response caching", a short ADR is still worthwhile)
2. `pnpm turbo gen core-package <name>` — generator emits canonical shape
3. Implement package contents (interface, impls, tests) — flows through normal story-and-task decomposition
4. Add `<name>` to manifests' `requiredCores` in features that adopt it
5. Wire into `BindContext` in `core-shared/di/`
6. Wire into each app's `bindAll()` aggregator
7. Update generator templates if features need to scaffold differently when this core is present (e.g., `core-events` causes `turbo gen feature` to emit event-handler stubs)

The conformance system catches forgotten wiring automatically:

- `required-cores-installed` ESLint rule flags manifests declaring `requiredCores: ["<name>"]` when the package isn't in `pnpm-workspace.yaml`
- Boot assertion `assertConformance(ctx)` fails on missing bind-context entries
- CI's `pnpm conformance` aggregates the cross-feature view

## Path B: new infrastructure layer

When the new infrastructure is bigger than one package — a new external service, a swap of an existing component, a deploy-target change:

1. **ADR** captures the decision and trade-offs
2. **Integration PRD(s)** specify what to build/wire/migrate; one PRD per integration concern is common
3. PRDs decompose into the normal Epic → Story → Task hierarchy
4. Stories typically include: a new core package (if one fits), configuration plumbing, bootstrap wiring, feature adoption, documentation updates, and (often) a deprecation/removal of the prior approach

Examples of category B work:

- "Add Redis for response caching" — ADR + core-cache package + bind-context wiring + adoption stories per feature
- "Replace Payload with Sanity" — ADR + repository implementation swap + migration scripts + docs rewrite
- "Move from Vercel to Cloudflare Workers" — ADR + new deploy target stories per app + CI workflow updates

## Conformance for infrastructure

Two rules extend the conformance system for infra concerns:

| Rule | Layer | What it catches |
|---|---|---|
| `required-cores-in-workspace` | ESLint + CI | manifest declares a core that isn't in `pnpm-workspace.yaml` |
| `core-package-shape-conforms-to-generator` | CI | a core package's structure has drifted from what `pnpm turbo gen core-package <name>` would produce today |

These extend the existing milestone iv work; no new tooling required.

## Common pitfalls

- **Skipping the ADR for "small" infra changes.** A swap of a single dependency is still a decision worth recording. The ADR doesn't have to be long — but it should exist.
- **Implementing before the ADR is accepted.** Don't decompose an integration PRD into stories until the ADR is `accepted`. The work-system orchestrator can refuse to dispatch tasks whose epic's ADR is still `proposed`.
- **Manifest drift after infra adoption.** A new core is added but features that use it don't declare it in `requiredCores`. The ESLint rule catches the inverse (declared-but-not-installed); CI's full conformance run also checks the other direction.
- **Bootstrap wiring forgotten.** A new core package is created but never bound in `apps/*/server/bind-production.ts`. Boot assertion catches this on first `pnpm dev`.
- **Documentation lag.** New infra is shipped but `docs/guides/` and `CLAUDE.md` aren't updated. Make documentation a required story under any integration epic.

## Open items (filled in as we ship)

- ADR elicitation skill — exact prompt shape and heuristics
- ADR ↔ PRD linkage — how an accepted ADR fans out into one or more PRDs (frontmatter `related-prds`?)
- Refusal logic — should the work-system refuse to decompose a PRD whose triggering ADR is still proposed?
