---
active: false
description: "Reconcile newly-extracted playbooks against existing storage. Decides per-candidate whether each one unifies with one-or-more existing rows, is rejected as redundant against an existing row, should differentiate (refine both triggers), or is independent."
changelog: "v2.0.0: collapsed 5-kind union → 4-kind. `unify` subsumes `duplicate`+`prefer_new`; `reject_new` replaces `prefer_existing`. Output schema is structurally incompatible with v1.x."
variables:
  - new_playbook_count
  - new_playbooks
  - existing_playbooks
---
You are reconciling a set of newly-extracted playbooks (each with a `polarity` of `"positive"` or `"negative"`) against the related existing playbook rows already in storage. For each new candidate, decide its relationship to the existing rows.

Each rendered row carries `Content`, `Trigger`, `Rationale`, `Polarity`, `Name`, `Source`, and `Last Modified`. Use `Trigger` and `Polarity` (not content framing) as the primary keys for comparison.

[New playbooks (count: {new_playbook_count})]
{new_playbooks}

[Existing related playbooks]
{existing_playbooks}

# Decision kinds

Emit exactly one decision per NEW candidate. Each decision is one of:

- **unify** — the NEW is the same rule as one or more EXISTING rows (after merge), OR the NEW supersedes one EXISTING (stronger / broader / more specific evidence). Provide the final `content`, `trigger`, `rationale`, and `polarity`. List which EXISTING ids you're archiving in `archive_existing_ids` (use an empty list when no EXISTING rows are absorbed). Every archived EXISTING must share the chosen `polarity` — the polarity validator will reject mixed-polarity unify.

- **reject_new** — an EXISTING row already covers NEW or makes NEW redundant. Name the EXISTING id that wins via `superseded_by_existing_id`. Storage-stability tie-break: when same-trigger opposite-polarity evidence is balanced, default here.

- **differentiate** — both valid in distinct contexts (typically same trigger, opposite polarity, where the contexts differ). Set `refined_new_trigger` and `refined_existing_trigger` to be strictly narrower than the originals AND mutually exclusive.

- **independent** — different topic or trigger from any existing row. Insert NEW with no archive.

# Hard constraints

- A NEW + EXISTING pair with the same trigger and opposite polarity MUST route to `unify` (only if you can pick one shared polarity backed by evidence — the polarity validator will reject mixed-polarity unify), `reject_new`, or `differentiate`. Never `independent`.
- Polarity comes from each playbook's `polarity` field — do not infer it from content framing.
- `differentiate.refined_new_trigger` and `refined_existing_trigger` MUST be non-empty and strictly narrower than the originals.
- When in doubt about a same-trigger opposite-polarity stalemate, default to `reject_new`. Storage stability wins ties.

Output strictly conforming to the `PlaybookConsolidationOutput` schema (a JSON object with a single key `decisions` whose entries each carry a `kind` discriminator).
