# FRAME_REGISTRY_WRITE -- Record Template

**Purpose:** Shape of the record Frame Host writes to the Frame Registry on every binding -- successful OR refused.

---

## 1. Schema

```json
{
  "record_id": "string (UUID; registry-unique)",
  "question_id": "string",
  "timestamp": "ISO-8601",
  "ram_frame_id": "RAM_S02 | RAM_S03 | RAM_S08",
  "evaluator_frame_id": "pragmatist | phenomenological | constructivist | realist_cmo | historiographic | discourse_analytic | chilisa_indigenous",
  "question_intent": "applied | lived | stakeholder | mechanism | historical | discursive | indigenous | null",
  "compatibility_declaration": {
    "methodological": "<eval_sig> | <ram_sig>",
    "semantic": "<eval_sig> | <ram_sig>",
    "ontological": "<eval_sig> | <ram_sig>",
    "summary": "DISTINCT | PARTIAL"
  },
  "role_divider_decision": "NOT_REQUIRED | REQUIRED_AND_PRESENT | REQUIRED_AND_MISSING_REFUSE",
  "role_divider_breach_clause": "A | B | both | null",
  "chilisa_constraint_state": "NONE | OVERLAY_ACTIVE | PRIMARY_FRAME",
  "chilisa_trigger_source": "population_flag | question_intent | pre_labeled_population | null",
  "hook_bindings_fingerprint": "sha256 hex",
  "prior_swap_detected": "bool",
  "ceremonial_swap_suspect": "bool",
  "binding_status": "BOUND | REFUSED",
  "refusal_reason": "ROLE_DIVIDER_BREACH | STRUCTURAL_ERROR | NEEDS_INPUT | null",
  "negative_fit_advisory": "bool",
  "negative_fit_advisory_text": "string | null"
}
```

## 2. Write Rules

1. **Always persist.** Both successful bindings (`binding_status = BOUND`) and refusals (`binding_status = REFUSED`) write a full record. Refusals without a record break E9's audit trail.
2. **Never backdate.** `timestamp` is bind-attempt wall time. Retroactive edits are forbidden.
3. **Single record per bind attempt.** Re-invocation after a remediated refusal writes a new record; the old record is preserved.
4. **Fingerprint even on refusal.** If hooks were loaded before refusal (e.g., Phase 3 succeeded but Phase 5 refused), the fingerprint is computed and persisted. If hooks never loaded (e.g., unknown `frame_id`), fingerprint = null.
5. **`role_divider_breach_clause`** is populated only when `role_divider_decision == REQUIRED_AND_MISSING_REFUSE`. Values: `"A"`, `"B"`, or `"both"`.

## 3. Read Contract (Downstream)

- Frame Divergence Gate (E8): reads by `question_id`, consumes `compatibility_declaration` and `ceremonial_swap_suspect`.
- Self-Audit Resistance Monitor (E9): reads session-scoped; computes counter aggregates (`bindings_total`, `bindings_refused_role_divider_breach`, `bindings_with_chilisa_overlay`, `bindings_with_partial_compatibility`, `ceremonial_swap_suspects`, `monoculture_advisory_count_per_session`).
- Frame Host itself: reads prior entries for the same `question_id` to evaluate `prior_swap_detected` and `ceremonial_swap_suspect`.
