# DPE Canonical Artifact Migration

Maps DPE-native fields to `abi-control-core` canonical schemas.

## New Artifacts Per Run

| File | Schema | Description |
|------|--------|-------------|
| `plan_graph.json` | `plan-graph/1.0` | DAG of DPE pipeline stages with deps and status |
| `eval_suite.json` | `eval-suite/1.0` | Eval cases: schema validation, golden comparison, PRD rubric |
| `run_manifest.core.json` | `run-manifest/1.0` | Canonical run manifest for downstream consumption |

All three are written to the run directory alongside existing DPE artifacts.
On validation failure, `validation_errors.json` is also written.

## Run ID Mapping

| DPE | Core | Rule |
|-----|------|------|
| 12-char hex (`uuid4().hex[:12]`) | 8-char hex (`^[0-9a-f]{8}$`) | Prefix truncation: `dpe_run_id[:8]` |

The full 12-char DPE run ID is preserved in the core manifest `notes` field.

## PlanGraph Field Mapping

| Core Field | DPE Source |
|------------|-----------|
| `schema_version` | `"plan-graph/1.0"` (const) |
| `run_id` | `dpe_run_id[:8]` |
| `description` | `"DPE dialectical pipeline"` |
| `nodes[].node_id` | `"dpe-{stage.lower()}"` |
| `nodes[].name` | `Stage.value` (e.g. `"INPUT_NORMALIZE"`) |
| `nodes[].status` | From `StageRecord`: completed/skipped/failed/pending |
| `nodes[].depends_on` | DAG edges (see below) |
| `nodes[].agent` | `StageRecord.adapter_used` |
| `nodes[].metadata` | `{dpe_artifact, dpe_role}` |

### Dependency DAG

```
INPUT_NORMALIZE
├── IDEATION_A
│   ├── CROSS_CRITIQUE_A
│   └── CROSS_CRITIQUE_B
├── IDEATION_B
│   ├── CROSS_CRITIQUE_A
│   └── CROSS_CRITIQUE_B
SYNTHESIS ← [IDEATION_A, IDEATION_B, CROSS_CRITIQUE_A, CROSS_CRITIQUE_B]
PRD_V1 ← SYNTHESIS
PRD_CRITIQUE_R1 ← PRD_V1
PRD_REVISION_R1 ← [PRD_V1, PRD_CRITIQUE_R1]
PRD_CRITIQUE_R2 ← PRD_REVISION_R1
PRD_REVISION_R2 ← [PRD_REVISION_R1, PRD_CRITIQUE_R2]
FINALIZE ← last completed revision stage
```

## Core RunManifest Field Mapping

| Core Field | DPE Source |
|------------|-----------|
| `schema_version` | `"run-manifest/1.0"` |
| `run_id` | `dpe_run_id[:8]` |
| `gate` | `"custom"` |
| `mode` | `"dry-run"` if simulation, else `"production"` |
| `trigger` | `"manual"` |
| `started_at` | First `StageRecord.started_at` |
| `completed_at` | Last `StageRecord.finished_at` |
| `intent_gate_hash` | `"sha256:" + sha256(config_hash)` |
| `verdict` | `completed→pass`, `budget_exceeded→warn`, `error:*→fail` |
| `summary.total` | `len(stages)` |
| `summary.passed` | Stages not skipped and not failed |
| `summary.failed` | Stages with error |
| `summary.skipped` | Stages with `skipped=True` |
| `summary.blocker` | `1` if verdict is `fail`, else `0` |
| `notes` | `"dpe_run_id={full}; source=run_manifest.json; {warnings}"` |
| `manifest_hash_jcs_sha256` | `"jcs_sha256:" + canonical_hash(manifest)` |
| `hashing` | `{"jcs": {"status": "ok"}}` |

Omitted optional fields: `token_usage`, `budget_actual` (DPE tracks calls, not tokens).

## EvalSuite Cases

| Sub-suite | Cases | Tags |
|-----------|-------|------|
| Schema validation | 3 (one per canonical artifact) | `schema-validation` |
| Golden comparison | 2–3 (plan_graph, manifest, prd if completed) | `golden` |
| PRD rubric | 7 (completeness, goals, non-goals, user-stories, tech-reqs, metrics, traceability) | `prd-rubric` |

All cases use `comparison: "structural"`. DPE defines suites; execution is MCO's job.

## Integration Point

`Orchestrator._finalize_manifest()` calls `emit_core_artifacts()` after writing native
DPE artifacts. Wrapped in try/except — core bridge failures never break existing DPE behavior.

## Dependencies

```toml
# pyproject.toml
dependencies = [
    "abi-control-core>=0.1.0",
    # ... existing deps
]
```
