# INTERFACE CONTRACTS -- RAM Router

**Scope:** Per-edge input schema / output schema / write rules for every dependency edge in the RAM dependency graph. Plus the orchestrator-level write discipline for the two cross-cutting artifacts (Surprise Register, RAM Search Ledger).

**Zero-overlap posture:** all contracts listed here are RAM-side only. The single cross-silo edge (RAM S4 -> Evaluator intake) is an artifact-drop contract, not a shared-state contract.

**Double hyphens only (`--`).**

---

## 0. Dependency graph (from Phase 5, restated)

```
S5 Claim-Typing (KEYSTONE)
  -> S1 Retrieval Router
  -> S7 Fitness Adjudicator
S1 + S7 -> S2 Source Integrity Screen
S5 + S2 + S7 -> S3 Multi-Method Orchestrator
S3 -> S8 Adversarial Pass Engine (parallel overlap; see PARALLEL_DISPATCH_RULES)
S3 + S8 -> S6 Warrant & Saturation Governor
S6 + S3 + S8 + S7 + S2 + S1 -> S4 Epistemic Output Layer
S4 -> bridge/ram-to-evaluator-handoff/
bridge/evaluator-to-ram-reopen/ -> router -> affected component (re-entry)

Cross-cutting:
  Surprise Register: owner S5; writers {S3, S5, S7, S8}; reader S6; renderer S4.
  RAM Search Ledger: owner S4; writers {S1, S2, S3, S7, S8, ram-router}; reader S6; renderer S4.
```

---

## 1. Edge: Router -> S5 (Claim-Typing Engine)

### 1.1 Input to S5

```yaml
question: string           # natural-language research question (required)
domain_hint: string | null # optional monoculture-trigger tiebreaker input
inquiry_id: uuid           # freshly minted by router
prior_run_state: object | null  # only on reopen re-entry
reopen_defect: string | null    # on reopen; e.g., "TYPING", specific claim_id
```

### 1.2 Output from S5

Claim Decomposition Artifact (`ram/templates/CLAIM_DECOMPOSITION_ARTIFACT.md` schema):

```yaml
run_id: string
question_original: string
verb_inventory: [string]          # every verb tokenized
claims:
  - claim_id: uuid
    claim_type: descriptive | causal | predictive | normative | interpretive | UNTYPABLE
    claim_text: string            # per-verb decomposition
    source_verbs: [string]        # subset of verb_inventory
    rationale: string
    fitness_requirements:
      load_bearing_properties: [string]
      disqualifiers: [string]
      weight_overrides: object
      fragility_flag: none | fragile-normative | fragile-predictive
    monoculture_flags:
      domain_sensitivity: bool
      geographic_locus: bool
      practitioner_domain: bool
      claim_type_flag: bool
    typing_confidence: HIGH | MEDIUM | LOW
surprise_register_handle:
  register_id: uuid
  write_token: string             # required by S3 / S7 / S8 for writes
typing_version: int               # increments on reopen re-entry
```

### 1.3 Router invariant checks

- `|verb_inventory| == sum over claims of |source_verbs|`
- Every verb appears in exactly one claim's `source_verbs`.
- No claim's `source_verbs` span two different `claim_type`s.
- If any assertion fails: halt; reopen to S5; do NOT dispatch further.

### 1.4 Write rules

- S5 writes the `decomposition_event` entry to the RAM Search Ledger (writer = `S5`, entry-type = `decomposition`).
- S5 writes the Surprise Register manifest at `state/ram/surprise-register/<run-id>/manifest.json`.

---

## 2. Edge: Router -> S1 (Multi-Corpus Retrieval Router)

### 2.1 Input to S1

Per claim:

```yaml
inquiry_id: uuid
claim_id: uuid
claim_type: string
claim_text: string
decomposition: [string]
fitness_requirements: object      # from S5
monoculture_flags: object         # from S5
discipline_tags: [string]         # disciplines S3 will likely invoke (informational, not authoritative)
ledger_handle:
  ledger_path: string
  write_token: string             # published by S4 at run_open
```

### 2.2 Output from S1

```yaml
records:
  - source_id: uuid
    source_metadata: object       # title, authors, date, venue, DOI, URL, etc.
    corpus_surface: english-peer | non-english | practitioner | indigenous
    query_used: string
    language_detected: string
    fidelity_tag: fidelity_high | fidelity_machine | fidelity_review_required
    human_review_flag: bool
    care_gate_status: not_applicable | passed | refused
    monoculture_trigger_record: object
    retrieval_provenance: object
architectural_limit_disclosure: object | null  # when Indigenous-source unreachable
dispatch_count: int               # must reconcile with Ledger entries
```

### 2.3 Write rules

- S1 writes four record kinds to the Search Ledger: `every-query`, `every-accepted`, `every-rejected`, `every-skipped`.
- S1 reconciles dispatch count vs Ledger entries before handoff. Mismatch -> halt.
- S1 NEVER writes to the Surprise Register. Monoculture-trigger records are a retrieval tag; they are not anomalies.

### 2.4 Router invariant checks

- Every record carries a non-null `corpus_surface`.
- CARE-gate refusals are logged as ledger entries AND surfaced in `architectural_limit_disclosure`.
- No record bypasses S2 on its way to S7.

---

## 3. Edge: S1 -> S2 (Source Integrity Screen)

### 3.1 Input to S2

```yaml
records: [S1.records]  # full record set from S1
```

### 3.2 Output from S2

Per source (per `ram/skills/source-integrity-screen/templates/INTEGRITY_VERDICT_SCHEMA.md`):

```yaml
source_id: uuid
retraction:
  status: retraction | expression-of-concern | withdrawal | clean | unverifiable | deferred
  reason: string | null
  pubpeer_concerns_count: int | null
ai_screen:
  status: clean-tier0 | flagged-tier1 | quarantined-tier2 | blocked-tier3 | skipped-short-text | skipped-language-uncalibrated | deferred-detector-failure
  tier_signals: object
pub_bias:
  status: small-study-effect-absent | small-study-effect-present | small-study-effect-inconclusive | not-applicable | dissemination-risk-baseline | dissemination-risk-elevated | dissemination-risk-unverifiable
  rationale: string
auto_block: bool                  # true only on confirmed retraction OR Tier 3
```

### 3.3 Write rules

- S2 writes per-source Ledger entries with phase tags: `intake`, `retraction`, `ai`, `pub-bias`, `verdict`.
- S2 NEVER writes to the Surprise Register.
- Tier 2 sources are enqueued to a human-review queue with a back-reference to the Ledger entry.

### 3.4 Router invariant checks

- Every S1 record has a matching S2 verdict (no silent filtering).
- `auto_block` sources are excluded from the S7 input set; non-auto-blocked but flagged sources are admitted with flags intact.
- S06 citation verification queue: if S2 produces rationale text citing Sadasivan / Liang / Kirchenbauer / Mitchell, the router confirms the S06 queue is clear before any user-facing render. If not clear -> halt with `s06_citation_unverified` error.

---

## 4. Edge: S2 + S1 + S5 -> S7 (Fitness Adjudicator)

### 4.1 Input to S7

Per (claim, source) pair:

```yaml
claim_record: {claim_id, claim_text, claim_type, decomposition, discipline_tags, stacked_intent_parents}
source_record:
  source_id
  source_metadata
  integrity_flags: S2.integrity_verdict   # full verdict object
  admiralty_reliability_A_to_F: string
  admiralty_credibility_1_to_6: string
  lineage_metrics: object                 # R7.3 metrics from S1
  content_excerpt: string
  retrieval_provenance: object
surprise_register_handle: {register_id, write_token}
ledger_handle: {ledger_path, write_token}
```

### 4.2 Output from S7

Per (claim, source) pair (per `ram/skills/fitness-adjudicator/templates/FITNESS_OUTPUT.md`):

```yaml
claim_id: uuid
source_id: uuid
dimension_scores:
  - dimension_id: D1 | D2 | D3 | D4 | D5
    score: 0-5
    evidence_excerpt: string
    rationale_one_line: string
parameterized_weights: {w_D1, w_D2, w_D3, w_D4, w_D5}   # sums to 1 after modifiers
load_bearing_dimensions: [string]
fragile_rubric: bool
fitness_headline: float           # composite documented
composite_function: string        # explicit; never hidden
disqualified: bool
disqualifier_hits: [string]
tier_bias_suspected: bool
craap_reduction_suspected: bool
admiralty_collapse_suspected: bool
reviewer_flag_required: bool
rationale: string
lineage_collapsed: bool           # set in Step 8 batch reconciliation
```

### 4.3 Write rules

- S7 writes every fitness decision to the Search Ledger (including BLOCKED on missing input).
- S7 writes to the Surprise Register ONLY when:
  - high-Admiralty source disqualifies,
  - lineage-independence dimension scored 0 across the admitted set for this claim (Greenberg cascade),
  - fragile-rubric flag fires on keystone source AND `reviewer_flag_required = true`,
  - anti-collapse flag fires.

### 4.4 Router invariant checks

- Every admissible (claim, source) pair has a fitness record.
- No S7 record has fewer than 5 dimension scores.
- No S7 record has a rationale that could be applied unchanged across claim types.
- Step 8 batch reconciliation re-ran D3 at set level before handoff to S3.

---

## 5. Edge: S5 + S2 + S7 -> S3 (Multi-Method Orchestrator)

### 5.1 Input to S3

```yaml
inquiry_id: uuid
claims:
  - claim_id
    claim_type
    claim_text
    decomposition
    fitness_requirements            # from S5
    verified_source_set:            # from S2 + S7
      - source_id, fitness_record, integrity_verdict
capacity_ceiling:
  K_disciplines: int                # default 6
  K_claims: int                     # default 4
prior_surprise_register_state: object | null  # when reopening a sub-inquiry
run_context:
  charter_hash: string
  monoculture_risk: nontrivial | trivial | none
surprise_register_handle: {register_id, write_token}
ledger_handle: {ledger_path, write_token}
```

### 5.2 Output from S3

Per claim (per `ram/skills/multi-method-orchestrator/templates/CLAIM_TRIANGULATION_RECORD.md`):

```yaml
claim_id: uuid
claim_text
claim_type
selected_disciplines: [string]       # size >= 2 unless SINGLE_METHOD_EXCEPTION
deferred_disciplines: [string]       # capacity-bound
single_method_exception:
  filed: bool
  trigger: string | null             # from closed allowed-list; else null
per_discipline_findings:
  - discipline: string
    finding_text: string
    confidence_on_own_axis: string
    sources_cited: [source_id]
    anomalies: [object]
    method_internal_flags: object
convergence_class: CONVERGENT | PARTIAL_AGREEMENT | CONTRADICTORY | UNDER_DETERMINED | NULL
contradictions:
  - pair: [discipline_a, discipline_b]
    axis: string
    surprise_register_entry_id: uuid
synthesized_finding: string | CONTESTED    # CONTESTED when convergence_class == CONTRADICTORY
partial_discipline_coverage: bool
ledger_reference_range: object
claim_type_revision_candidate:
  fired: bool
  suggested_type: string | null      # when fired, route back to S5
```

### 5.3 Write rules

- S3 writes to the Search Ledger continuously (per invocation, per return, per register write -- never batched).
- S3 writes to the Surprise Register on:
  - every CONTRADICTORY claim,
  - every PARTIAL_AGREEMENT above material-difference threshold,
  - every CLAIM_TYPE_REVISION candidate,
  - every CAPACITY_BOUND claim with PARTIAL_DISCIPLINE_COVERAGE.
- S3 NEVER mutates S5-owned fields of the Surprise Register (the ownership-controlled fields enumerated in `SURPRISE_REGISTER_WRITE_CONTRACT.md`).

### 5.4 Router invariant checks

- Every selected_disciplines set has size >= 2 OR a filed SINGLE_METHOD_EXCEPTION with a closed-list trigger.
- Research Auditor is in every selected_disciplines set.
- No claim is synthesized into a single-trust-score.
- Every contradiction has a Surprise Register entry.
- If any `claim_type_revision_candidate.fired`, route affected claim(s) back to S5 immediately; halt downstream for those claims.

---

## 6. Edge: S3 + S5 -> S8 (Adversarial Pass Engine)

### 6.1 Input to S8

Per claim:

```yaml
inquiry_id
claim_id
claim_text
claim_type
decomposition
discipline: string                 # from S5 / S3 context
confirmatory_findings: S3.per_discipline_findings
fitness_verified_source_set: [source_id]
surprise_register_handle: {register_id, write_token}
ledger_handle: {ledger_path, write_token}
recursion_parent_claim_id: uuid | null    # set for sub-inquiry re-entry
```

### 6.2 Output from S8

Per claim:

```yaml
claim_id
adversarial_state: defensibly-closed | contradictions-outstanding | meta-anomaly
defensible_nothing_found_record: object | null    # when defensibly-closed; four requirements met
contradiction_bundle:                              # when contradictions-outstanding
  - counter_source_provenance
    inversion_class: IC-1 | IC-2 | IC-3 | IC-4
    contradiction_summary
    sub_inquiry_prompt
    skeptic_frame_origin
    warrant_signal: contradictions-outstanding
inversion_class_coverage:
  IC-1: exercised | non-applicable-with-rationale
  IC-2: exercised | non-applicable-with-rationale
  IC-3: exercised | non-applicable-with-rationale
  IC-4: exercised | non-applicable-with-rationale
saturation_evidence:
  per_class: {K, consecutive_null_or_known_category}
```

### 6.3 Write rules

- S8 writes to the Search Ledger with `pass=adversarial` + inversion_class + skeptic_frame_ref + query_rationale + disconfirmation_category_assigned + saturation_state_after.
- S8 writes to the Surprise Register for every contradiction (as sub-inquiry prompt) and for every meta-anomaly (unchallengeable claim).
- S8 NEVER writes a `confidence` field to the Surprise Register entry (absence is structural).

### 6.4 Router invariant checks

- Every claim has an S8 state emission.
- No S8 output cites a stopping rule based on query count / time / tokens.
- No contradiction appears in the ledger without a matching Surprise Register entry.
- No defensible-nothing-found record is emitted without all four requirements satisfied.

---

## 7. Edge: S3 + S8 -> S6 (Warrant & Saturation Governor)

### 7.1 Input to S6

```yaml
inquiry_id
charter: object                   # full Charter from S5
yield_trace:                      # built from Search Ledger per-claim over time
  - claim_id
    batches:
      - batch_id, novel_claims_count, timestamp
adversarial_verdicts:
  - claim_id, state (from S8.adversarial_state)
surprise_register_snapshot: full register state
ledger_snapshot: full ledger state
operator_pressure: bool           # true on /ram-stop
```

### 7.2 Output from S6

Stopping Warrant (per `ram/skills/warrant-saturation-governor/templates/stopping_warrant.json`):

```yaml
warrant_id: uuid
inquiry_id: uuid
parent_warrant_id: uuid | null
produced_at: ISO-8601
verdict: STOP | CONTINUE
gates:
  yield: {closed: bool, evidence: {per_claim_posteriors}}
  scope: {closed: bool, evidence: {pending_amendments, drift_events_this_invocation, drifting_claims, drift_dimensions, drift_classification}}
  contradiction: {closed: bool, evidence: {sub_inquiries, unprocessed_adversarial_verdicts}}
recall_miss_posterior: {per claim float}
charter_alpha: float
default_alpha_used: bool
pragmatic_proxy: bool             # ALWAYS present
proxy_rationale: string | null    # required if pragmatic_proxy
proxy_method: string | null       # permissible: "no_novel_claims_for_K_batches"
proxy_K: int | null
open_reasons: [object]            # required if verdict == CONTINUE
```

### 7.3 Write rules

- S6 writes the warrant to the Search Ledger via S4's ledger-write interface.
- S6 writes `CHARTER_AMENDMENT_REQUEST` to the Surprise Register when drift is detected.
- S6 writes `sub_inquiry_open` to the Surprise Register for new contradictions.
- S6 writes continuation directives to the router (not to the ledger directly).

### 7.4 Router invariant checks

- `pragmatic_proxy` field is always present and boolean.
- If `verdict: STOP`, all three gates are CLOSED with evidence.
- If `verdict: CONTINUE`, at least one gate is OPEN and `open_reasons` populated.
- No warrant rationale matches the Section 4.3 anti-examples (volume-floor regex).
- Sub-inquiry counts in the register match contradicted/qualified verdict counts in the ledger.

---

## 8. Edge: All upstream -> S4 (Epistemic Output Layer)

### 8.1 Input to S4

```yaml
claims: [S3.triangulation_records]
warrant: S6.stopping_warrant
surprise_register: full register state
search_ledger: full ledger state
decision_context_descriptor: object | null    # from /ram-research --context
invoked_discipline: [S3.selected_disciplines per claim]
role_divider_required_candidate: bool          # router-set flag
```

### 8.2 Output from S4

Evaluator-ready artifact (per `ram/skills/epistemic-output-layer/templates/EVALUATOR_READY_ARTIFACT.md`):

```yaml
inquiry_id
artifact_tag: evaluator-ready=true
per_claim:
  - claim_id
    claim_type
    evidence_axis: {strength_band, supporting_source_count, independent_method_count, contradiction_record, fitness_distribution}
    transportability_axis: {feature_slot, primitive, sub_scores, caveat}   # OR axis_not_computable
    decision_axis: {band, dominant_constraint, rationale, action_caveats, register_bindings}
    fragility_caveats: [string]
surprise_register_section: full render (top-level; never footnoted)
search_ledger_section: full render (every entry; never summarized away)
methodology_trace:
  - discipline
    corpora
    methods
    warrant_rationale
    role_divider_required_candidate_flag: bool
defect_section: [string] | null
```

### 8.3 Write rules

- S4 is the RENDER authority for both cross-cutting artifacts. Others WRITE, S4 RENDERS.
- S4 writes `run_close` to the ledger.
- S4 drops the artifact to `bridge/ram-to-evaluator-handoff/<inquiry_id>/evaluator-ready.json`.

### 8.4 Router invariant checks

- Three axes per claim (or `axis-not-computable` with reason).
- No `overall` / single-trust-score field anywhere.
- Surprise Register rendered as top-level section.
- Search Ledger rendered fully (no summarization).
- Type-coded caveats inline for normative / interpretive claims.
- Role-divider flag propagated in methodology trace.

---

## 9. Edge: S4 -> bridge/ram-to-evaluator-handoff/

### 9.1 Contract

- **Artifact drop, not shared state.** S4 writes a read-only artifact to the bridge path. Evaluator reads the artifact; does NOT mutate any RAM state.
- **Path:** `bridge/ram-to-evaluator-handoff/<inquiry_id>/evaluator-ready.json` + `evaluator-ready.meta.json` (artifact hash, version, produced_at).
- **Degraded mode:** if the bridge is unreachable, the router halts, writes `bridge_unavailable` to the ledger, escalates to the operator. The router does NOT cache-and-retry silently; the operator must be aware that the Evaluator path is degraded.

### 9.2 Invariants

- RAM never reads under `bridge/evaluator-to-ram-reopen/` during a render phase; that path is read only at reopen intake.
- Evaluator never reads under `state/ram/`; all RAM context enters the Evaluator via this bridge artifact.
- Zero-overlap verified per Phase 5 `ZERO_OVERLAP_VERIFICATION.md`.

---

## 10. Edge: bridge/evaluator-to-ram-reopen/ -> Router -> affected component

### 10.1 Contract

Reopen verdict payload (grammar from Evaluator E7 `VERDICT_TOKEN_GRAMMAR.md`):

```yaml
verdict_token: REOPEN | PASS | PASS-DEFERRED | ESCALATED
inquiry_id: uuid
defect_class: TYPING | FITNESS | ORCHESTRATION | ADVERSARIAL_THEATER | ADVERSARIAL_LAZY_CLOSE | WARRANT_MIS_CONSTRUCTED | OUTPUT_COLLAPSE | CEREMONIAL_TRANSPORTABILITY | REGISTER_AS_FOOTNOTE | UNKNOWN
affected_claim_ids: [uuid]
composite_trigger_fired: [P1..P5]
dwell_time_ms: int
rationale: string
```

### 10.2 Router routing

| defect_class | Routes to | Phase re-entry |
|---|---|---|
| TYPING | S5 | Phase 8 re-entry, affected claims only |
| FITNESS | S7 | Per-affected-(claim, source) re-score |
| ORCHESTRATION | S3 | Per-affected-claim re-entry |
| ADVERSARIAL_THEATER | S8 | Per-affected-claim re-entry; Anti-Theater Check tightened |
| ADVERSARIAL_LAZY_CLOSE | S8 | Per-affected-claim re-entry; defensibility rechecked |
| WARRANT_MIS_CONSTRUCTED | S6 | Full warrant re-evaluation |
| OUTPUT_COLLAPSE | S4 | Per-affected-claim re-render |
| CEREMONIAL_TRANSPORTABILITY | S4 | Axis 2 re-computation with proper substitution |
| REGISTER_AS_FOOTNOTE | S4 | Surprise Register re-rendered as top-level section |
| UNKNOWN | (operator) | Escalate; do NOT guess |

### 10.3 Invariants

- Router NEVER second-guesses a reopen verdict.
- Surprise Register persists across reopens.
- Ledger appends new events on reopen (never rewritten).
- Warrant version increments on S6 re-entry; original warrant preserved in history.

---

## 11. Cross-cutting artifact: Surprise Register -- ORCHESTRATOR WRITE DISCIPLINE

**Owner:** S5. **Writers:** {S3, S5, S7, S8, ram-router (for meta-anomalies only)}. **Reader:** S6. **Renderer:** S4.

### 11.1 Writer-side discipline

Every writer:
1. Obtains write token from S5-published handle (bound at `run_open`).
2. Writes atomic append-line to `state/ram/surprise-register/<run-id>/register.jsonl`.
3. Uses `SURPRISE_REGISTER_WRITE_CONTRACT.md` schema. Required fields: `entry_id, run_id, register_id, claim_id, entry_kind, writer_component, write_timestamp_utc, source_refs, description, provenance, expansion_directive, downstream_effect, rendered_in_output=false`.
4. `entry_kind` NEVER includes `tiebreaker-vote` or `confidence-delta`. Expansion-only.

### 11.2 Router-side discipline

- Router writes ONLY `meta-anomaly` entries (e.g., `governance_disagreement` when Evaluator reopens a stopped run; `claim_type_revision_reroute` for cross-component bookkeeping; `capacity_bound_deferral` summary per phase boundary).
- Router NEVER writes claim-bound anomalies (those belong to S3/S7/S8).
- Router writes `claim_id: null` on meta-anomalies.

### 11.3 Degraded mode

- Register unreachable at S4 render -> S4 emits `register-unavailable` stamp; run flagged degraded.
- Writer cannot acquire token -> halt the writer; escalate to router; NO silent drop.

---

## 12. Cross-cutting artifact: RAM Search Ledger -- ORCHESTRATOR WRITE DISCIPLINE

**Owner:** S4. **Writers:** {S1, S2, S3, S7, S8, ram-router}. **Reader:** S6. **Renderer:** S4.

### 12.1 Writer-side discipline

Every writer writes one of four record kinds:
- `every-query` (issued queries -- confirmatory or adversarial-tagged)
- `every-accepted` (sources admitted)
- `every-rejected` (sources rejected with reason)
- `every-skipped` (avenues skipped with reason)

Every write is atomic; no batching at end of run.

### 12.2 Router-side discipline

Router writes these events to the ledger:
- `run_open` (inquiry_id, charter_hash, mode, produced_at).
- `phase_boundary` (phase transitions with timestamp + summary stats).
- `run_close` (verdict, produced_at).
- `reopen_received` (verdict_token, defect_class, routed-to-component).
- `capacity_bound_deferral` (deferred discipline list, reason).
- `claim_type_revision_reroute` (affected claim IDs, revision candidate).
- `governance_disagreement` (S6 verdict vs Evaluator verdict).
- `operator_halt_request` (per /ram-stop).
- `bridge_unavailable` (on bridge failure).

Writer tag: `ram-router` (distinct from component writers).

### 12.3 Degraded mode

- Ledger unavailable at write -> calling skill HALTS. There is no silent ledger miss.
- Ledger available but write fails -> classified refusal; incident written to orchestrator alarm channel.

---

## 13. Invariant Summary (checked at every phase boundary)

1. Verb-inventory equals claim-decomposition-verb-count (Phase 1 exit).
2. Every retrieved record passes through S2 (Phase 2 exit).
3. Every (claim, source) admissible pair has a fitness record (Phase 2 exit).
4. Every claim has a discipline subset of size >= 2 or filed SINGLE_METHOD_EXCEPTION (Phase 3 exit).
5. Every claim has an S8 state emission (Phase 4 exit).
6. `pragmatic_proxy` boolean present on every warrant (Phase 5 exit).
7. If STOP: all three gates CLOSED (Phase 5 exit).
8. Three axes per claim (or axis-not-computable with reason) on the Evaluator-ready artifact (Phase 6 exit).
9. No single trust score anywhere on the artifact (Phase 6 exit).
10. Surprise Register rendered top-level, Search Ledger rendered fully (Phase 6 exit).
11. No cross-silo read or write (every phase).

End of INTERFACE_CONTRACTS.md.
