{"path":"research/the-remaining-case-for-the-stance-guard.md","content":"# The remaining case for the stance guard — measured, and mostly dissolved\n\n**Date**: 2026-09-13 · **Asked, verbatim**: *\"Explore and think deeply about the remaining case for such a guard, please. Keep an open mind about whether it's needed.\"* · **Status**: analysis on live data; three build proposals, all three RULED 2026-09-13 — the supersession policy first, then the stance field and the demotion (*\"Guess the two smaller proposals make sense too.\"*).\n\n## 0. The answer in five lines\n\n1. As built — a human-facing list of agreement edges between opponents — the guard is not needed. Read pair by pair today, 84 candidates split into 5 it was built for, 14 that are a *different* bug, and about 65 healthy shared ground.\n2. The 5 it was built for are all reported speech: one author cites the other side's position in order to reject it. Always-mint already gives those a home; what is missing is one field, the reporter's **stance** toward what they report. No module stores it.\n3. The 14 are false `SUPPORTS` edges written by auto-connect between claims with mirrored vocabulary about **different referents** (the UK's current regime vs. jurisdictions with legal assisted suicide), at strength 0.7–0.8. That is a precision failure of the relationship classifier, not stance loss, and it wants an entailment re-check, not a stance guard.\n4. What survives of the guard is its **trigger**: an agreement edge between documented opponents is a cheap, well-placed prompt for an automated re-read of both authors' stance, with the source spans in hand. Under the housekeeping ruling of the same day (*confident, safe housekeeping is the machine's job*) that re-read is automated and writes the stance, never queued for a person.\n5. So: add the stance field at extraction, demote `stance.py` from an endpoint for humans to a batch consistency check that feeds the re-read, and run an entailment re-check over cross-source agreement edges. Three proposals, his call.\n\n## 1. What the guard was built for\n\nRun 6 (2026-08-13, [dogfood-run-6-israel-palestine-cross-domain.md](dogfood-run-6-israel-palestine-cross-domain.md) § J8) found that the relationship classifier, asked how Tsagourias's rendering of the 2004 Wall holding relates to Erakat's, answers `SUPPORTS 1.00` — correct about the sentences, wrong about the authors, since he cites the holding as *\"the contrary position\"* and she rests her case on it. The instrument built the next day (`deliberus/stance.py`, `GET /graph/stance-conflicts`) finds source pairs that attack each other, lists every agreement edge spanning such a pair, and ranks by cosine. Propose-only, no model call, and honest about its own noise: *\"80 of the 84 candidates are probably healthy common ground.\"*\n\n## 2. What the 84 candidates actually are\n\nRead one by one from the live graph on 2026-09-13, with each edge's provenance (`auto_connect`, trust tier medium, `confirmed: false` on 48 of the 50 resolvable):\n\n| Class | Count | Example | Whose job |\n|---|---|---|---|\n| **Reported speech with the reporter's stance lost** — the guard's target | 5 | *\"Opponents of minimum wage legislation argue that a wage floor will harm low-wage workers\"* (reported, to be rebutted) linked as agreeing with Econlib's own assertion of the same; the Wall pair; *\"Proponents of capital punishment commonly argue that execution deters\"* beside van den Haag asserting it | always-mint + a stance field (§ 3a) |\n| **Mirrored vocabulary, different referents** — a false `SUPPORTS` | 14 | *\"There is no active monitoring or enforcement system to detect instances where the legal requirements for assisted suicide are not followed\"* (about legal regimes abroad) written as supporting *\"The current legal status quo regarding end-of-life choices in the United Kingdom lacks formal state oversight\"* (about a country with no assisted dying) | an entailment re-check on cross-source agreement edges (§ 3d) |\n| **Shared ground** — both assert, same direction, used for different conclusions | ~65 | ACLU and van den Haag both asserting the victim-race disparity in death sentencing; two AI-economics sources both asserting mass displacement | nothing; this is what a healthy debate looks like |\n\nThe 12 are verified against the classifier's own stored reasoning, which conflates the referents outright: *\"Claim A makes a general assertion about the lack of formal state oversight in the UK regarding end-of-life choices. Claim B provides a specific detail regarding the lack of monitoring and enforcement for legal requirements. Therefore, B serves as a premise or evidence that supports the broader conclusion stated in A.\"* Claim B is about jurisdictions that *have* assisted suicide. Fourteen edges of this shape sat in one debate, at 0.6–0.8 strength, feeding badges — **retired 2026-09-13** on the founder's word (*\"Fix the wrong support links.\"*) by `scripts/retire_false_support_edges.py` (dry run by default; `--apply` wrote `superseded_by = retired:operator-review-2026-09-13` with the reason on each; every strength reader filters superseded edges, display keeps them, `restore_edge` reverses). An earlier count of 12 missed two; the selection was re-derived by rule.\n\nCaveat that must travel: the three-way sort is one model's reading of 84 pairs, and the 12 are the checkable part — the texts are quoted above and the referent mismatch is visible on the page.\n\n## 3. The failure, decomposed by source\n\nThe guard was built for one symptom, *an agreement edge between opponents*. That symptom has four sources with four different fixes.\n\n**(a) Reported content extracted with the reporter's stance lost.** The root case. Always-mint ([self-similar-decomposition-and-claim-ontology.md](self-similar-decomposition-and-claim-ontology.md) § RATIFIED) mints the reported content once, attributed to the reported party, with the reporter as provenance — so the Wall holding becomes one claim attributed to the Court, and the two renderings are a sameness-merge question rather than an agreement edge. What is missing is the reporter's **stance**: `ReportedSplit` carries `is_reported_speech`, `reported_party`, `report_text`, `content_text`, `confidence` and no stance; the `REPORTS` edge stores no property at all; `attribution.py` has roles `self / third_party / unknown`, and its own first run already found that *third_party bundles citing a supporting authority with reporting an opponent — only the second carries stance signal, so it wants splitting.* Three modules circle the same missing field. Add it once (asserts · rejects · reports without taking a position), on the claim at extraction and on the `REPORTS` edge, and case (a) has no need of a guard.\n\n**(b) Both authors assert the same proposition in their own voice and use it for opposite conclusions.** Not a flattening. After the sameness merge there is one claim with two asserters, and the disagreement lives exactly where it should: in the divergent inferences drawn from it downstream. The guard's own docstring says so (*\"opposed authors agree about background facts constantly, and that is healthy\"*). Flagging these is pure noise, and they are roughly 67 of the 84.\n\n**(c) Detector misses.** *\"Took the contrary position\"* matched no reported-speech pattern in August; irony, scare quotes and a bare restatement of the opponent's premise before rebutting it are the same shape. Here always-mint cannot mint what it did not detect, and a stance field cannot be filled by a pass that did not fire. **This is the only residual case**, and the adversarial-agreement trigger is a good place to catch it after the fact: an author \"agreeing\" with their opponent on a contested point is exactly the pattern a detector miss produces. But the response should be automated — send both claims with their source spans to a stance re-read, and if it returns *rejects* or *reports*, convert the edge (`REPORTS` plus stance) and supersede the agreement edge. Ruled 2026-09-13: *\"Any regular housekeeping should be done that could be done with high confidence in safety/accuracy and could spare human users from having to later clean up and organize the graph manually.\"* A human glance at 84 rows, 67 of them healthy, is the opposite of that.\n\n**(d) Mirrored vocabulary, different referents.** The 14 assisted-dying edges. Two opponents describe the same *kind* of deficiency in two different regimes, the decontextualised texts name their referents plainly, and the classifier links them anyway. Not a stance problem in any sense; the authors both assert. The fix is an entailment check on the edge — *does A actually support B?* — which the sameness programme's pairwise classifier already has to answer (its *same / contains / unrelated* keys), applied to cross-source `auto_connect` agreement edges. The guard's trigger surfaces these only by accident, because opponents mirror each other's vocabulary; it is a useful prior for where to run the check first, not the check.\n\n## 4. What survives, concretely\n\n1. **A stance field** — one enum on the extracted claim (*asserts · rejects · reports*), the same on the `REPORTS` edge, and the `third_party` attribution role split accordingly. Small: the reported-speech pass already reads the sentence with a model; it is one more field in the same call. This is the root fix for (a) and most of (c).\n2. **`stance.py` demoted** from a reader-facing endpoint to a batch consistency check: its adversarial-pair trigger feeds an automated stance re-read with source spans; confident findings write the stance and supersede the wrong edge (originals never destroyed — edge supersession exists for exactly this). The near-identical threshold question logged in run 6 dissolves with the human list.\n3. **An entailment re-check on cross-source agreement edges** written by auto-connect, starting with adversarial pairs. Fourteen known wrong edges are the first fixture (retired by hand 2026-09-13; the re-check must find them again on a restored copy, or on the next such pair). **RULED 2026-09-13** — founder: *\"Yes, replace by itself, keep the old link visible.\"* So: when the re-check is confident *and* the edge is machine-written and unconfirmed, the machine supersedes it by itself, and the superseded link stays visible; a proposal only when either condition fails.\n\nWhat is retired: the guard as an instrument a person reads, and J8's line *\"no instrument covers this\"* — once the stance field exists the mechanism is covered at the root rather than watched at the symptom. Stance flattening keeps its place among the named flattening mechanisms; the instrument for it changes shape.\n\n## 5. What this does not settle\n\n- Whether the stance field is worth its prompt cost on the Claude backend (every extracted claim, one more enum; likely negligible, unmeasured).\n- How the entailment re-check scores against the 14 known-wrong edges — the first thing to measure, since a re-check that passes them is inert.\n- ~~The tension in § 4.3~~ ruled the same day (*\"Yes, replace by itself, keep the old link visible.\"*); what remains open is the measurement in the line above.\n"}