# DAG Edge Evaluation Runbook — adjudicating the operator-sweep edge harvest

**Purpose.** A self-contained process for evaluating the **275 candidate DAG subsumption edges**
harvested as a byproduct of the operator-search sweeps (operator 05 generalization + operator 13
cluster-without-parent, 2026-07-03). Each candidate proposes that an existing prime (`child`) is
subsumed by another existing prime (`parent`) via an edge the DAG does not currently contain.
This runbook lets a fresh context window (with the EOA MCP + repo access) adjudicate them to the
project-06 standard and produce a clean, owner-ready draw-list.

**This is a DENSIFICATION task, not a discovery task.** No new primes are created. The corpus is
**frozen at 1,325** (owner decision 2026-07-03). Drawing edges changes only the hierarchy, not
the node set, so this work is fully independent of the pending end-of-search prime curation and
can run in parallel.

---

## 1. Where everything is

- **Input worklist:** `workspace/operator_search/dag_edge_worklist.yaml` — the 275 candidates,
  sorted parent-hubs-first, each with source, hub flag, pre-computed FLAGS, both one-liners, and
  blank `decision` / `qualifier` / `justification` fields to fill.
- **Provenance manifests** (why each edge was proposed): `manifest_op05_framed.yaml`,
  `manifest_op05_rest.yaml` (route `verified_MISSING_EDGE` in the crank files), `manifest_op13.yaml`
  (`byproduct_dag_gap_worklist`).
- **Canonical DAG store:** edges live in each prime's **v2 frontmatter** as a `dag_edges:` block
  (NOT in separate ledger files — those were migrated 2026-05-29). Example, from
  `prime_abstractions/v2/abilene_paradox.md`:
  ```yaml
  dag_edges:
  - parent: private_public_preference_divergence
    type: subsumption
    flavor: ''
    qualifier: strict
    reason_short: child of emergent private_public_preference_divergence
    reason: child of emergent private_public_preference_divergence
  ```
  The block lives on the **CHILD**: an edge "child is-a parent" is recorded in `<child>.md`.
- **Derived artifacts** (regenerated by the owner, NOT by this task): `build_dag.py` →
  `dist/dag.{jsonl,json,manifest.json}`. The current DAG: **665 subsumption + 699 composition +
  192 decompose + 6 mutual edges**. Do not run the build; hand the owner the draw-list.
- **Existing project-06 process doc:** `workspace/06b_prerequisite_edges_plan.md` (the original
  edge-construction method — this runbook inherits its discipline).

## 2. The four edge types (you will mostly confirm or reclassify, not invent)

- **subsumption** — `child` IS-A `parent` (genus/species). The candidates are ALL proposed as
  subsumption; your job is to confirm that, OR reclassify to one of the below, OR drop.
- **composition** — `child` is built-from / has-as-a-part `parent` (or co-occurs as a component).
  **This is the most common correct reclassification** — many proposed "genus" links are really
  part-of links (see §4). The current DAG already has more composition than subsumption edges.
- **decompose** — `parent` breaks down into `child` (the inverse framing of composition; used
  where the parent is the whole).
- **mutual** — genuinely bidirectional/interdependent (rare; 6 total). Use only when neither
  direction dominates.

Subsumption edges carry a **qualifier**: `strict` (every instance of child is an instance of
parent) or `typical` (usually, with exceptions). Current split ≈ 524 strict / 141 typical.

## 3. The three pre-computed FLAGS in the worklist (read these first per candidate)

The harvest checked only *subsumption ancestry*, so two failure modes are pre-flagged:

- **`ALREADY_EXISTS:<type>`** (62 candidates) — an edge between this exact pair already exists,
  but in a different type (usually `composition`). The candidate is proposing subsumption on top.
  → Decide: is the existing composition edge correct (then **DROP** the subsumption proposal), or
  is the relationship really is-a and the existing edge mis-typed (then **RECLASSIFY_EXISTING**)?
  A pair almost never needs both a composition AND a subsumption edge — pick the one true relation.
- **`REVERSE_EDGE_EXISTS`** (18 candidates) — the `parent→child` edge already exists (i.e. the
  DAG already says the *proposed parent* is the child of the *proposed child*). **DIRECTION/CYCLE
  RISK.** → Either the harvest got the direction backwards (**DROP**), or the existing edge is
  wrong. Drawing the candidate as-is would risk a cycle. Handle these with the most care; when in
  doubt, DROP and note for owner.
- **No flag** (196 candidates, "clean-new") — no existing edge either direction. The normal case:
  confirm the is-a, or reclassify to composition, or drop as not-a-real-relation.

## 4. The adjudication test (apply per candidate)

For each edge, using the MCP (`get_prime`, `get_prime_neighborhood`, `search_prime`,
`find_related_primes`) to read both primes' actual content:

1. **Reality of the relation.** Is there a genuine hierarchical/compositional relation at all, or
   did the cheap-model NEAREST field just name a semantically-near prime? If no real relation →
   **DROP**.
2. **is-a vs part-of (the core call).** Ask: "Is every `child` necessarily a kind of `parent`?"
   - Yes → **subsumption** (pick qualifier strict/typical).
   - No, but `child` is built out of / centrally involves `parent` as a component → **composition**
     (or **decompose** if `parent` is better read as the whole that contains `child`).
   - The classic trap: a genus that is really a *mechanism the child uses*. E.g. a prime that
     "uses feedback" is composition-with `feedback`, not is-a `feedback`. The op-05 crank
     systematically over-proposed subsumption for these; expect many `feedback`, `modularity`,
     `emergence` hub edges to reclassify to composition.
3. **Direction & acyclicity.** Confirm the arrow points child→parent (more specific → more
   general). Re-check any REVERSE_EDGE_EXISTS flag. Never propose an edge that creates a cycle
   with existing ancestry — if unsure, DROP and flag.
4. **Non-redundancy.** If `parent` is already a *transitive* ancestor of `child` through other
   edges, a direct edge is redundant → DROP (note it as already-covered). (The harvest removed
   direct-subsumption ancestors but NOT multi-hop or other-typed paths.)
5. **Search-justification.** Write a ≤25-word justification naming the structural reason, in the
   forward-looking style of existing `reason_short` fields. This is the project-06 bar: an edge
   without a stated structural justification is not ready to draw.

Bias: **precision over recall.** A wrongly-drawn edge corrupts every downstream view (Ontology,
hierarchy export, sunburst, force-graph, MCP neighborhoods); a dropped-but-real edge can be
recovered later. When genuinely unsure, DROP with a one-line note rather than draw.

## 5. Suggested sequencing (hubs first — highest leverage)

The worklist is pre-sorted parent-hubs-first. Work in this order:

1. **The 18 hub parents (3+ children each):** `feedback`(10), `emergence`(5), `modularity`(5),
   `path_dependence`(5), `homeostasis`(5), `goodharts_law`(4), `concept_drift`(4), `authority`(3),
   `normalization_of_deviance`(3), `decomposition`(3), `fixed_point`(3), … Adjudicate each hub as a
   *set* — deciding "what is the true relation of these N children to this parent" once is faster
   and more consistent than one-at-a-time, and the hubs carry the most navigational value.
2. **The 18 REVERSE_EDGE_EXISTS (cycle-risk):** do these deliberately, second.
3. **The 62 ALREADY_EXISTS (type conflicts):** decide keep-composition vs reclassify per pair.
4. **The remaining clean-new singletons:** fastest pass; many will be composition or drop.

## 6. Output contract

Fill the three blank fields on each worklist entry in place (edit
`dag_edge_worklist.yaml`), OR write a parallel `dag_edge_decisions.yaml` — either is fine, keep
child+parent keys so it joins back. Per entry:

```
decision:     DRAW_SUBSUMPTION | DRAW_COMPOSITION | DRAW_DECOMPOSE | RECLASSIFY_EXISTING | DROP
qualifier:    strict | typical        # only if drawing a subsumption
justification: <=25 words, structural, forward-looking (becomes reason_short)
```

Then produce a short **summary block** at the top: counts by decision, the hub-by-hub verdicts,
any acyclicity concerns surfaced, and any candidate that on inspection suggests a *missing prime*
or a *merge* (route those to the owner's separate curation queue, do not act on them here).

**Do NOT:** create/delete primes, edit any `dag_edges:` block in a prime file, run `build_dag.py`,
or rebuild the site. This task produces a reviewed **draw-list**; the owner draws the edges into
frontmatter and rebuilds, applying the CLAUDE.md `one_liner`-sync rule and the acyclicity check at
incorporation.

## 7. Guardrails & gotchas

- **Corpus frozen (1,325).** If adjudication reveals a needed intermediate abstraction that does
  not exist, do NOT create it — note it as a candidate for the frozen end-of-search prime queue.
- **Existence method (per [[feedback-prime-existence-check]]):** confirm a prime exists via MCP
  `search_prime` or a broad name+slug grep, never exact-slug guessing.
- **The cheap-model provenance is a lead, not a verdict.** Every candidate came from a haiku/sonnet
  NEAREST field. Treat the pairing as "worth checking," and re-derive the relation from the primes'
  actual content, not from the proposed label.
- **YAML brittleness:** some project-06 v1 frontmatters have known YAML fragility (see the
  project-06 memory). If editing frontmatter blocks later, validate parse before/after.
- **Two prior edge harvests exist** inside the manifests (op13's 12, op05-framed's 34) — all are
  already merged into the single worklist; work only from `dag_edge_worklist.yaml`.
