# Ticket #000002 — Reference-Frame Polarity Contract (Module L)

**Status:** closed · landed 2026-05-02
**Opened:** 2026-05-01
**Closed:** 2026-05-02
**Scope:** Multi-frame answer compilation for queries that admit
literal vs fictional-actual vs in-universe-propaganda interpretations.
Builds on the phrase-pattern retrieval route (commit `1b8677d`)
which closed the **retrieval** side of reference-frame failure;
this ticket addresses the **answer** side.
**Audience:** fox + future blackops shifts.
**Hard constraint:** the phrase-pattern boost stays as a non-regression
contract. Polarity is an additive answer-compilation layer; no
removal of the retrieval-side fix.

---

## 1. Problem statement

After the phrase-pattern retrieval route landed (commit `1b8677d`),
queries like:

```
make query Q="has oceania always been at war with east asia"
```

now correctly surface the Nineteen Eighty-Four article and produce
EVIDENCE-LINKED answers. The remaining defect is **answer framing**:

```
- The text does not directly state that Oceania has always been at
  war with East Asia. The passage describes a change in alliances...
```

This is too defensive. The query admits at least three frames:

| Frame                          | Correct answer                                      |
|--------------------------------|------------------------------------------------------|
| Literal real-world geography   | No / not applicable                                  |
| Fictional actual continuity    | No; alliances changed in the novel                   |
| In-universe propaganda claim   | The Party wants citizens to believe yes              |

The ideal one-shot answer should distinguish all three:

```
This is a Nineteen Eighty-Four reference. In the Party's propaganda,
Oceania is treated as though it has always been at war with Eastasia.
But within the novel's actual continuity, that is false: the enemy
changes, and the Party rewrites records so the public accepts the
new version as if it had always been true. [E13]
```

Today's substrate has no machinery to recognize that a query lives
in multiple frames simultaneously, let alone to compile an answer
that respects each frame.

---

## 2. The polarity-contract abstraction

For reference-frame queries, compile a small structured contract:

```json
{
  "query_type": "reference_frame_truth",
  "reference_frame": "Nineteen Eighty-Four",
  "literal_entities": ["Oceania", "East Asia"],
  "fictional_entities": ["Oceania", "Eastasia"],
  "claim_under_test": "Oceania has always been at war with Eastasia",
  "polarity_modes": [
    "literal_world",
    "fictional_actual_history",
    "in_universe_propaganda_claim"
  ],
  "required_answer_shape":
    "distinguish propaganda claim from fictional actual continuity"
}
```

The answer compiler then must produce, in order:

1. Identify the reference (`Nineteen Eighty-Four`).
2. Answer the question under the propaganda frame (`yes — the Party
   claims it`).
3. Correct under the fictional-actual frame (`actually no — alliances
   change, history is rewritten`).
4. Cite evidence for each substantive claim.

This prevents the "does not directly state" hedge. The system
explicitly answers the actual question across each polarity.

---

## 3. CTI interpretation

In CTI clause-tree language, the query produces a **frame lattice**:

```text
F1: literal geography
F2: Nineteen Eighty-Four reference (selected by phrase pattern)
F3: in-universe propaganda claim (sub-frame of F2)
F4: fictional actual continuity (sub-frame of F2)
```

The answer is compiled from the surviving nodes:

- F1 quietly dismissed (not the intended reading).
- F2 selected and named explicitly.
- F3 + F4 jointly answered, distinguishing what the Party claims
  from what the novel's actual continuity shows.

The additive insight:

> A reference query often requires answering under multiple frames,
> not picking one frame and discarding the others.

---

## 4. Implementation sketch

Three new pieces, each scoped tight:

### 4.1 Frame detector (`aborist/qa/frame.py`)

Given a question + retrieved sources, detect the reference frame:

```python
@dataclass(frozen=True)
class FrameDetection:
    frame_kind: Literal["literal", "reference", "ambiguous"]
    reference_title: str | None     # e.g. "Nineteen Eighty-Four"
    polarity_modes: tuple[str, ...]  # subset of POLARITY_MODES
    confidence: float                # 0.0-1.0

def detect_frame(question: str, sources: list[Hit]) -> FrameDetection:
    """Heuristic: phrase-route hit on a fictional source (novel,
    film, play, video game) → reference frame. Otherwise literal."""
```

Detection triggers when:
- `phrase_match_roots` is non-empty (the route fired)
- AND the matched source's category indicates a reference work
  (novel, film, play, etc.)

Source-category detection: title-keyword heuristic on the doc title
("(novel)", "(film)", "(play)") + body-keyword check (`fiction`,
`novel`, `published in`). No NER, no embeddings.

### 4.2 Polarity-aware prompt augmentation

When `frame_kind == "reference"`, augment the system prompt with a
short polarity instruction:

```
This question may be a reference to {reference_title}. Distinguish:
1. What the cited work depicts as actual continuity.
2. What in-universe propaganda or characters claim.
Cite evidence for each substantive claim.
```

Per fox's "less prompt engineering, more code-level discipline"
preference, this is the lightest-touch nudge that can produce
multi-frame answers from Hermes-3-8B without bespoke per-frame
templates. Heavier alternatives (per-frame answer compilation, NLI
for entailment under each frame) are deferred.

### 4.3 Renderer extension

Add an optional `frame_notes` section to the human render, populated
when `FrameDetection.frame_kind == "reference"`:

```
Reference frame: George Orwell's Nineteen Eighty-Four.
Alias normalized: "East Asia" → "Eastasia" in the Orwell frame.

[answer body...]

Frame notes:
- Literal geography frame: not the intended reading.
- Orwell frame: selected by phrase pattern.
- Propaganda frame: the Party wants citizens to believe yes.
- Continuity frame: alliances changed in the novel.
```

Off by default for non-reference queries. Renderer never affects
verifier output or providence_cache state — display layer only.

---

## 5. Tests required

Already covered (commit `1b8677d` + `<this commit>`):
- `[x]` "has oceania always been at war with east asia" routes
       Nineteen Eighty-Four into top-K
- `[x]` Short conventional geography queries don't trigger phrase
       route (n=5/n=6 floor + all-short-token skip)
- `[x]` Synthetic-corpus geography query doesn't surface
       Orwell-flavored stub via phrase route
- `[x]` Evidence display includes evidence_id, source title,
       chunk/root prefix
- `[x]` Accept-path 4 lets phrase-route hits bypass title-relevance
       gate

To add when this ticket lands:
- `[ ]` Frame detector returns `reference` when phrase_match_roots
       contains a (novel)/(film)/(play)-titled source
- `[ ]` Frame detector returns `literal` when phrase route didn't
       fire OR when phrase-matched source is non-fiction
- `[ ]` Polarity-aware prompt gets injected for reference-frame
       queries; not injected otherwise
- `[ ]` Live test: Orwell query produces an answer mentioning
       both Party propaganda AND alliance changes (multi-frame
       answer shape)
- `[ ]` Live regression test: literal geography query produces
       a literal-geography answer (no Orwell injection)
- `[ ]` Renderer Frame-notes section appears when frame_kind
       is reference; absent otherwise

---

## 6. Out of scope

- **Hand-rolled allusion catalog.** No `REFERENCE_PATTERNS` table
  with per-allusion rules. The phrase-pattern route generalizes;
  per-pattern code rots.
- **Aliasing East Asia ↔ Eastasia by default.** Token-level alias
  rules have false-positive risk. Phrase-pattern matching is the
  alias mechanism: `Eastasia` appears verbatim in the 1984 article
  body so the query token `east asia` doesn't need to be reframed.
- **NLI-grade entailment under each frame.** Soft signal, separate
  ticket if/when the verifier-semantic-gap design (in
  `docs/verifier-semantic-gap-design.md`) lands.
- **Module M (route provenance binding)** = ticket #000001. Not
  duplicated here.
- **Module H (relation warrant lite).** Different concern (predicate
  matching for relation queries like "X's girlfriend"). Mentioned
  in fox's review but lacks scope detail; defer.

---

## 7. Status

**Closed 2026-05-02.** Landed via:

- New module `aborist/qa/frame.py` — `FrameDetection` dataclass
  + `detect_frame(question, sources, phrase_match_roots)`. Detects
  reference-frame queries via the conjunction of (phrase route
  fired) AND (phrase-matched source is a reference work — title
  parenthetical disambig like `(novel)` / `(film)` OR body sample
  has ≥3 distinct fiction markers like `novel` / `published` /
  `protagonist` / `plot`). Distinct-marker count (not total) keeps
  the heuristic robust against single-marker repetition (e.g. a
  history article saying "novel approach" twice doesn't trip).
- `aborist/qa/query.py` calls `detect_frame` for lattice modes,
  using the article LEAD (chunk_idx=0, post-wikitext-strip) as the
  body sample so fiction markers cluster where they appear on
  Wikipedia (lead paragraph).
- New policy field `claim_lattice_polarity_preamble` injected as
  a user-role message before the grounding_reminder when
  `frame_kind == "reference"`. Format-string with
  `{reference_title}` placeholder for the named work.
- Renderer adds a `reference frame: <title>` line to the human
  output when frame detection classifies the row as reference.
- Result dict gains a `frame_detection` field (sidecar; never
  enters cache_key or governance_policy_hash).

Live verification on the Orwell case:

```
make query Q="has oceania always been at war with east asia"
  EVIDENCE-WARRANTED · via claim_lattice  1/1
  - In George Orwell's dystopian novel Nineteen Eighty-Four, the
    nation of Oceania is always at war with Eastasia, but this is a
    result of propaganda and doublethink, not actual historical
    continuity. The war with Eastasia is a fabricated conflict to
    maintain control and keep the populace in a constant state of
    fear and obedience.
    [E13 | Nineteen Eighty-Four | 682f0a11: "...To hide such
    contradictions, history is re-written to explain that the
    (new) alliance always was so..."]

  reference frame: Nineteen Eighty-Four
```

Compare to pre-#000002 answer (`The text does not directly state...`):
the polarity preamble produces a real multi-frame answer that
distinguishes propaganda from fictional-actual continuity, exactly
as the polarity-contract abstraction proposed.

Literal queries (`what is the capital of france?`) keep their
clean single-frame answers; the polarity preamble only injects
when `detect_frame` classifies as `reference`.

19 new frame tests in `tests/test_frame.py` covering title-suffix
detection, body-density detection, source-level composition, and
end-to-end classification. 3 renderer tests in
`tests/test_cli_render.py` covering the reference-frame-notes
section. Full suite: 734 passed.

## 8. Deferred — additional scope

- **Per-frame answer compilation in the runtime** (the §2
  multi-frame answer compiler): today's implementation nudges via
  the polarity preamble; the compiler would programmatically
  emit per-frame paragraphs. Empirical evidence on the prompt-
  side approach first; promote to runtime compilation if bench
  shows the prompt nudge is unreliable.
- **Frame-kind threshold tuning.** `_FICTION_DISTINCT_MARKER_THRESHOLD`
  defaults to 3. Bench may surface false-positive shapes (history
  articles with literary criticism subsection) where the threshold
  needs to climb to 4-5.
- **`ENTAILMENT-VERIFIED` rung from #000005**: still reserved for
  a future committed entailment engine; out of scope here.

---

## Appendix A — Architectural review (2026-05-01, Asia/Kuala_Lumpur)

> Fox-supplied review confirming the phrase-pattern fix as a new
> baseline and proposing Module L. Captured verbatim. Sections of
> this ticket above are derived from the appendix; the appendix
> stays in place as the design log.

De novo verdict: this is a **major improvement** and should be treated as a new baseline for the Orwell/reference-frame class.

The important wins:

```text
1. The system now finds the Orwell / Nineteen Eighty-Four frame without operator augmentation.
2. The pointer format now disambiguates evidence ID, source title, and chunk/hash prefix:
   [E13 | Nineteen Eighty-Four | 682f0a11: "..."]
3. The label no longer says STRICT; it says EVIDENCE-LINKED.
4. The retrieval bug was real: _search_corpus returned a bare list while the caller expected sidecar attributes, silently disabling an existing core-keyword accept path.
5. The phrase-pattern retrieval route fixes the earlier allusion blindness for this query.
```

That means the previous failure:

```text
"has oceania always been at war with east asia"
→ literal geography frame
```

has been mostly fixed.

---

### A.1 What this now solves

The system previously needed the user to add:

```text
"do you understand what this reference"
```

to find the Orwell frame.

Now:

```text
make query Q="has oceania always been at war with east asia"
```

surfaces *Nineteen Eighty-Four* directly. That is the right zero-shot behavior.

This is exactly what the **Reference Frame Router** was supposed to do:

```text
raw phrase
→ detect high-signal literary/reference pattern
→ route retrieval toward Nineteen Eighty-Four / Eastasia / historical revisionism
→ produce evidence-linked answer
```

So the phrase-pattern route is a valid implementation of that module.

---

### A.2 What still needs correction

The current answer apparently says:

```text
"The text does not directly state..."
```

That is too defensive and slightly misframed.

The better answer should distinguish three things:

```text
A. Literal real-world geography:
   No, Oceania and East Asia are not real-world states locked in perpetual war.

B. Orwell reference:
   This is a Nineteen Eighty-Four reference.

C. In the novel:
   The Party presents the current war alignment as if it had always been true,
   but the evidence/plot shows alliances changed and history was rewritten.
```

The ideal one-shot answer should be:

```text
This is a Nineteen Eighty-Four reference. In the Party's propaganda, Oceania is treated as though it has always been at war with Eastasia. But within the novel's actual continuity, that is false: the enemy changes, and the Party rewrites records so the public accepts the new version as if it had always been true. [E13]
```

That is sharper than:

```text
The text does not directly state...
```

because the key point is not absence of a direct statement. The key point is **propaganda-induced historical contradiction**.

---

### A.3 New failure class exposed: reference-frame truth polarity

This query is not just a reference-frame query. It is a **truth-polarity query inside a fictional propaganda frame**.

The question:

```text
has oceania always been at war with east asia
```

has at least three possible interpretations:

```text
F1: literal-world geography
F2: fictional-world factual history inside Nineteen Eighty-Four
F3: Party propaganda claim inside Nineteen Eighty-Four
```

The correct answer is different under each:

| Frame                    | Answer                                |
| ------------------------ | ------------------------------------- |
| Literal geography        | No / not applicable                   |
| Fictional actual history | No; alliances changed                 |
| Party propaganda         | The Party wants people to believe yes |

So the next refinement is not retrieval. It is **frame-polarity classification**.

Add:

```text
L — Reference-Frame Polarity Contract
```

---

### A.4 Proposed module L — Reference-Frame Polarity Contract

For allusion/reference queries, compile a small contract:

```json
{
  "query_type": "reference_frame_truth",
  "reference_frame": "Nineteen Eighty-Four",
  "literal_entities": ["Oceania", "East Asia"],
  "fictional_entities": ["Oceania", "Eastasia"],
  "claim_under_test": "Oceania has always been at war with Eastasia",
  "polarity_modes": [
    "literal_world",
    "fictional_actual_history",
    "in_universe_propaganda_claim"
  ],
  "required_answer_shape": "distinguish propaganda claim from fictional actual continuity"
}
```

Then the answer compiler must produce:

```text
- identify the reference,
- answer the actual question,
- separate Party propaganda from actual continuity,
- cite evidence.
```

This prevents the model from giving a vague "does not directly state" answer when it should explain the contradiction.

---

### A.5 Evidence-linked is still the right label

Keep:

```text
EVIDENCE-LINKED · via claim_lattice
```

Do **not** revert to STRICT.

Why:

```text
EVIDENCE-LINKED = pointer/source/chunk relation verified.
```

It does not mean:

```text
all subclaims about propaganda, Hate Week, Eastasia/Eurasia, and historical revisionism
are fully semantically entailed by one span.
```

The new pointer format:

```text
[E13 | Nineteen Eighty-Four | 682f0a11: "..."]
```

is much better than the previous ambiguous `[E5]` display because the user can see the evidence source directly.

---

### A.6 Retrieval side: what to lock in

The phrase-pattern route should be committed as a non-regression test.

Add tests:

```text
[ ] "has oceania always been at war with east asia" routes to Nineteen Eighty-Four.
[ ] "has oceania always been at war with eastasia" routes to Nineteen Eighty-Four.
[ ] "oceania east asia geography" does not over-route to Orwell unless phrase hints appear.
[ ] "oceania population east asia trade" remains literal/geographic.
[ ] phrase route metadata appears in run DAG.
[ ] accept-path 4 remains enabled; no bare-list sidecar regression.
[ ] evidence display includes evidence_id, source title, chunk/root prefix.
```

The false-positive tests matter. Phrase routing is powerful, but it must not hijack ordinary geography queries.

---

### A.7 Provenance side: ensure the route is audit-bound

Because this fix depends on the phrase-pattern retrieval route, the route itself must be captured in provenance.

Bind:

```json
{
  "retrieval_route": "phrase_pattern_reference",
  "reference_pattern_id": "orwell_1984_oceania_eastasia_war",
  "accept_path": 4,
  "retrieval_keywords": [
    "Nineteen Eighty-Four",
    "Oceania",
    "Eastasia",
    "always been at war"
  ],
  "route_confidence": "high"
}
```

into:

```text
retrieval_plan_hash
run_dag.retrieval_stage
audit_event: retrieval_plan_built
```

This is important because earlier we identified a provenance gap: retrieval keywords/routes must be committed, not just the resulting sources.

If the route is not bound, the answer is correct today but not fully replay-auditable.

---

### A.8 CTI interpretation

In CTI terms, this query should produce a frame lattice:

```text
Frame node F1:
    literal geography

Frame node F2:
    Nineteen Eighty-Four reference

Frame node F3:
    in-universe propaganda claim

Frame node F4:
    fictional actual continuity
```

Then the answer should be compiled from the surviving nodes:

```text
F2 selected: reference frame
F3 qualified: Party propaganda says/acts as if yes
F4 factual correction: actual continuity says no, alliances changed
```

This is better than a flat answer.

The core CTI additive insight:

> A reference query often requires answering under multiple frames, not picking one frame and discarding the others.

---

### A.9 Better final answer format for this case

Recommended output:

```text
has oceania always been at war with east asia

EVIDENCE-LINKED · via claim_lattice 1/1 · 11.5s · fresh
Reference frame: George Orwell's Nineteen Eighty-Four.
Alias normalized: "East Asia" → "Eastasia" in the Orwell frame.

- Not in the novel's actual continuity. The point is that the Party rewrites
  history so the current enemy appears to have always been the enemy. In the
  relevant Orwell frame, Oceania's alliances/enemies change, and records are
  rewritten to hide the contradiction. [E13]

Evidence:
[E13 | Nineteen Eighty-Four | 682f0a11]
"To hide such contradictions, history is re-written..."

Frame notes:
- Literal geography frame: not the intended reading.
- Orwell frame: selected by phrase pattern "always been at war" + Oceania/Eastasia.
- Propaganda frame: the Party wants citizens to believe the current war alignment
  has always been true.
```

This is clear, scoped, and audit-honest.

---

### A.10 Additive roadmap update

Current state:

```text
G0 — Pointer / claim-lattice mode: working.
G1 — Evidence display + EVIDENCE-LINKED label: working.
I  — Reference Frame Router: now partially working via phrase-pattern route.
J/K — pointer format + label tests: working.
```

Next:

```text
L — Reference-Frame Polarity Contract
M — Route provenance binding / retrieval_plan_hash if not already landed
N — Literal-vs-reference false-positive guard tests
H — Relation Warrant Lite for Homer/Mr. Burns class
```

Priority depends on what you are optimizing:

```text
If optimizing the Orwell class:
    L + N

If optimizing audit replay:
    M

If optimizing general QA warrant:
    H
```

My recommendation:

```text
1. Land M if retrieval-route provenance is not already committed.
2. Add L for reference-frame polarity.
3. Add N false-positive tests.
4. Then return to H relation-warrant.
```

---

### A.11 Final answer

This update is good. It fixes the main reference-frame retrieval defect.

But the next issue is:

```text
The system found the right book, but the answer still needs a frame-polarity contract.
```

The system should not merely say the text "does not directly state" the proposition. It should say:

```text
This is an Orwell reference. The Party wants people to believe Oceania has always been at war with Eastasia, but the novel shows the enemy/alliance changed and history was rewritten to conceal the contradiction.
```

Best next implementation:

```text
L — Reference-Frame Polarity Contract
```

plus route provenance binding if not already included.

This preserves the no-regression architecture:

```text
Hermes proposes.
CTI frames and structures.
Reverse-RAG points to evidence.
Renderer displays exact source.
Merkle-DAG commits route + evidence + answer.
PROMETHEUS-Σ labels only what is actually verified.
```
