Narrative Handoff Contract
Table of Contents
- Core Principles
- Workflow
- The three fields that carry the weight
- The escalation object
- Guardrails
- Quick Reference
Related skills: Use narrative-evidence-ledger to build the claim set this contract points at, narrative-arc-mapping to fill the slots, and narrative-fidelity-audit to check the prose that comes back.
Core Principles
- A pipeline whose interface is prose has no interface. Two agents that hand each other paragraphs cannot enforce anything. The handoff is a file.
- The evidence array is the validated field, not the value. A slot with a confident sentence and no claim ID fails here rather than reading well downstream.
- ABSENT is a passing state. An architecture with every slot filled is flagged, because real material always has holes.
- Enforce with a cap, not a request. "Never draft prose" decays as context fills. A length limit on scene lines does not.
- The channel runs both ways. Without an escalation object the drafting layer has no way to report a structural defect, so it papers over it with polish.
- Pointers resolve outward. A citation resolving into the pipeline's own earlier output is circular, invisible to reading, and a hard failure.
Workflow
Copy this checklist and track your progress:
Handoff Contract Progress:
- [ ] Step 1: Emit the architecture object
- [ ] Step 2: Validate before handing off
- [ ] Step 3: Write the demand manifest
- [ ] Step 4: Receive and route escalations
Step 1: Emit the architecture object
Step 1.1: Write architecture.json with the fields in resources/schema.md. Start from the worked example there rather than from an empty file.
Step 1.2: Stamp the run header — model, corpus reference, timestamp, and the list of claim IDs actually consulted. A run over a corpus too large to read linearly must record which claims it did not see. Silent partial coverage reported as full coverage defeats every audit downstream.
Step 1.3: Write incrementally. Append each slot as you settle it, so a run that dies partway loses one slot rather than the whole pass.
Step 2: Validate before handing off
Step 2.1: Run the validator. It reports every problem, not just the first:
python3 resources/validate_architecture.py path/to/architecture.json \
--corpus-root path/to/corpus --output-root path/to/pipeline/output
Step 2.2: Fix errors. Read warnings as diagnosis rather than noise — "0 slots ABSENT" usually means slot-filling, not unusually complete material.
Step 2.3: Use --strict in CI, where a warning should stop the build. Leave it off while drafting.
Step 3: Write the demand manifest
Step 3.1: Give the drafting agent absolute paths, an explicit scope in beat IDs, an explicit out-of-scope statement, the style contract, and the required return shape.
Step 3.2: Read it back as a stranger. If it only makes sense to someone who saw the previous conversation, it will fail. The downstream agent inherits nothing else.
Step 4: Receive and route escalations
Step 4.1: An escalation naming layer architecture is a defect in the spine or the slot. An escalation naming layer reporting means the corpus lacks something — route it to research, not to redrafting.
Step 4.2: A spine change is legal but never local. Bump spine_version, invalidate the draft, and re-pass from the scene weave down. Patching one section into a different structure while the rest keeps the old one is what readers register as untrustworthy without being able to say why.
The three fields that carry the weight
| Field | Rule | What it prevents |
|---|---|---|
slots[].evidence[] |
Non-empty for any slot not marked ABSENT | A fluent sentence standing in for a finding |
slots[].status |
ABSENT passes; all-filled warns |
Twenty-two slots producing twenty-two inventions |
scenes[].tagged_line |
Hard character cap | The structural agent quietly drafting, leaving the craft agent editing text instead of executing architecture |
Two more matter almost as much. dead_column[] keeps every killed finding, distinguishing did_not_support from CONTRADICTED — the second always reaches the reader, and its absence is how cherry-picking becomes undetectable. And scenes[].representativeness is assigned upstream against the corpus, never by the drafting agent, because a vivid case in the opener is selected for energy and energy correlates with being atypical.
The escalation object
{
"beat_id": "b14",
"layer": "architecture",
"defect": "No particular exists anywhere in the corpus for this beat; the ladder audit finds an R2 run with no R1 within two paragraphs.",
"what_would_resolve_it": "Either a dated artifact from the 1998 filings, or a redesign that does not require a scene here."
}
layer is architecture when only the spine can resolve it, and reporting when the material itself is missing. Both are successful outputs. Neither is a request for permission to invent.
Guardrails
Requirements:
- Validate before every handoff. An unvalidated contract is a suggestion.
- Absolute paths only. Relative paths across an agent boundary are a documented recurring failure.
- Version the contract. A run that cannot say which contract it was written against cannot be re-derived or diffed.
- Every gap carries exactly one disposition — RESEARCH, REDESIGN, DECLARE or CUT. There is no "draft and flag": flagged prose survives review at high rates because it reads well.
- Zero gaps is a red flag, not a success.
Common pitfalls:
- Treating the markdown companion as the artifact. Generate it from the JSON; never edit it by hand and expect the JSON to follow.
- Letting the drafting agent widen its own scope because "the next section obviously follows."
- Recording coverage as the whole corpus when the agent read the first N chunks.
- Deleting killed findings to tidy the file.
- Escalating by writing a note into the prose instead of emitting the object, where nothing will route it.
Quick Reference
Key resources:
- resources/schema.md: full field list, types, and a worked example for a system protagonist
- resources/validate_architecture.py: the validator; exit 0 pass, 1 violated, 2 unreadable
- resources/evaluators/rubric_narrative_handoff_contract.json: quality scoring
Inputs required:
- A claim set or evidence ledger with stable claim IDs
- A chosen structure and its slots
- The output directory, for the circular-citation check
Outputs produced:
architecture.json, validated- A demand manifest a stranger could execute
- Escalation objects routed by layer