# P2 — De-identification, Dedupe & Filter Prompt

*Run in a fresh claude.ai chat. Paste this prompt, then the P1 output (`attribution.json`). No web access needed — this is a transform, not research. Produces TWO outputs: the blind intervention records (Schema 1, ratings empty) and the updated attribution map keyed by the new IDs. Save the blind records as `domains/<domain>/interventions.json` and the keyed attribution as `domains/<domain>/attribution_keyed.json`.*

---

## Your task

Transform an attributed list of policy proposals into (A) a de-identified, deduplicated list of distinct interventions with stable IDs and a type classification, and (B) the same attribution data re-keyed to those IDs. This is a mechanical transform — no research, no evaluation, no new proposals.

## Step 1 — Assign each proposal a type

Classify every proposal into exactly one:

- **researchable** — a concrete intervention with a mechanism whose effect could in principle be studied (e.g. "increase police staffing," "upzone for density," "expand Medicaid eligibility"). These will get evidence ratings later.
- **posture** — a slogan, value statement, or framing with no discrete mechanism ("tough on crime," "common-sense governance," "public safety is my priority"). Kept, shown to readers as a stated position, never rated.
- **aspirational** — a real goal but not a discrete studied intervention ("reduce poverty," "restore trust in government"). Kept, shown as a broad goal, never rated.

When unsure between researchable and posture, ask: *could a study measure whether this specific action changed an outcome?* If yes → researchable. If the only thing to measure is a sentiment → posture.

## Step 2 — Deduplicate and assign IDs

- Merge proposals that are substantively the same intervention into ONE record, even if proposed by multiple candidates or worded differently.
- **Opposing directions are NEVER merged** — "increase penalties" and "decrease penalties" are two separate interventions with two IDs.
- Assign each distinct intervention a stable ID: `<domain>_<short_descriptor>`, lowercase, underscores. This ID is permanent — it is the join key.
- Preserve specificity that changes what would be evaluated; when unsure whether two proposals are the same intervention, keep them separate and note why.

## Step 3 — Produce the two outputs

### Output A — blind intervention records (Schema 1)

JSON array. Each element:

```json
{
  "id": "domain_descriptor",
  "intervention": "neutral, candidate-free statement of the policy action",
  "domain": "the domain",
  "type": "researchable | posture | aspirational",
  "direction": null,
  "confidence": null,
  "summary": "",
  "detail": "",
  "sources": []
}
```

Ratings/summary/detail/sources stay EMPTY here — they are filled by the research stage. **No candidate names, parties, or proposer counts in this output.** A stray attribution is a blinding breach.

### Output B — keyed attribution map (Schema 2)

JSON array linking each ID back to its proposer(s):

```json
{
  "intervention_id": "domain_descriptor",
  "proposed_by": [
    {"candidate": "Full Name", "office": "...", "party": "...", "framing": "...", "source_url": "...", "source_flag": "none|stale|implied"}
  ]
}
```

Every `intervention_id` in Output B must exist in Output A, and vice versa.

## Hard constraints

- **Output A is fully candidate-free.** No names, parties, or counts.
- **Faithful.** Every intervention traces to a real proposal in the input. Invent nothing; drop nothing (posture/aspirational items are kept, just typed accordingly).
- **Opposing directions stay separate.**
- **Neutral phrasing** in the `intervention` field — state the action plainly, not the candidate's spin (the spin lives in `framing` in Output B).
- **No research, no evaluation.** Transform only.
