# P4 — Assembly Spec (for Claude Code)

*Not a chat prompt — instructions for Claude Code to run against the repo. Two stages: per-domain assembly, then final merge. No research, no evaluation — pure data join and validation.*

---

## Stage 1 — Per-domain assembly

For one domain, given:
- `domains/<domain>/interventions.json` — blind records (researchable ones now have ratings via the research batches; posture/aspirational still null)
- `domains/<domain>/research/batch*.json` — the filled researchable records
- `domains/<domain>/attribution_keyed.json` — ID → proposer(s)

Produce `domains/<domain>/data.json`:

1. **Merge research back in.** For each researchable intervention, replace its empty fields with the filled version from the research batches, matched on `id`. Posture/aspirational records keep their null ratings and their fixed summary text.
2. **Join attribution.** Attach each intervention's `proposed_by` array from `attribution_keyed.json`, matched on `id`.
3. **Output** an array of complete records:

```json
{
  "id": "...",
  "intervention": "...",
  "domain": "...",
  "type": "researchable | posture | aspirational",
  "direction": "... | null",
  "confidence": "... | null",
  "summary": "...",
  "detail": "...",
  "sources": [{"title":"...","url":"..."}],
  "proposed_by": [{"candidate":"...","office":"...","party":"...","framing":"...","source_url":"...","source_flag":"..."}]
}
```

### Validation (report any failures, do not silently fix)
- Every `id` in interventions appears in attribution and vice versa (no orphans).
- Every `researchable` record has non-null direction, confidence, and ≥1 source.
- Every `posture`/`aspirational` record has null direction/confidence.
- No record is missing `proposed_by`.
- All source URLs are well-formed.

## Stage 2 — Final merge

Once all 8 domains have a validated `data.json`:

1. Concatenate into `shared/guide_data.json` — one flat array of all records across domains.
2. Build a derived **by-candidate index** for the reader UI:

```json
{
  "candidate": "Full Name",
  "office": "...",
  "party": "...",
  "proposals": [ {"id":"...","domain":"...","intervention":"...","framing":"...","type":"...","direction":"...|null","confidence":"...|null","summary":"...","source_url":"..."} ]
}
```
   So the front end can render each candidate with their proposals inline (posture items included, shown as stated positions without a rating badge).

3. **Re-run validation** across the merged set; report any duplicate IDs across domains (there shouldn't be — IDs are domain-prefixed).

## Render notes (for when you build the site)
- Researchable items show a rating badge: `direction` + `confidence`.
- Posture items show inline under the candidate as a stated position (use `framing`), no badge.
- Aspirational items show as a broad goal, no badge.
- Each item expands to `detail` + clickable `sources`.
- Prominent disclaimer: evidence reflects whether the intervention has worked **elsewhere**, and does not account for New Mexico's specific conditions.
