{"path":"research/what-a-link-strength-means.md","content":"# What a link's strength means\n\n**Date**: 2026-09-28 · **Type**: design analysis, measured on the live graph · **State**: RULED 2026-09-28\n(ledger Q31; founder: *\"Yes.\"*), build pending in `TODO.md`\n\n**The question, verbatim** (founder, after the store-the-blank rule was added globally and its one\nlive case turned out to be the 0.7 every hand-made link carries): *\"about the default strength...\nwhat consequences would that blank strength reset have? Wouldn't it make more sense to give it a\nconscious look, to reconsider what the default value SHOULD be, maybe it should be set dynamically\nor smt? Let's look at this carefully and think deeply about it.\"*\n\n---\n\n## 0. The answer in five lines\n\n1. The stored number on a link (`r.strength`) **has no definition anywhere it is written.** The\n   extraction prompt asks for `strength: 0.0-1.0` and nothing else; every other writer is a\n   constant.\n2. It does **four jobs**: it is printed to readers as a percentage, it picks which boxes a map shows,\n   it ranks four feeds and lists, and it gates whether the automatic linker writes a link at all. The\n   one job it does not do is the badge, which reads it and discards it.\n3. **A blank alone would be honest on the pages and would distort the rest**: a missing value sorts\n   as zero, so hand-made and human links would drop behind machine-written ones in every ranking.\n4. **So \"what should the default be?\" dissolves once the number is split by job.** How strongly a\n   link holds up is computed on read from its answered critical questions (already built, and what\n   the badge uses), so it has no default: it starts as *not yet examined* and moves when someone\n   answers. The machine's own rating is kept, named for what it is, given a rubric, and left blank\n   wherever no machine judged the link. Ordering is computed from both, plus structure.\n5. That is the founder's own ruling on horizon kinds (*read, never set*, 2026-09-15) applied to\n   links, and it also answers two open items: whether the bridging feed should read the badge, and\n   the map view's deferred \"order by badge\".\n\n## 1. Who writes the number, and what they are told\n\n| Writer | Value | What the writer was told |\n|---|---|---|\n| Extraction's relationship pass | the model's choice | `strength: 0.0-1.0` (the prompt, `cross_structure.py`); the response model's field has no description |\n| Automatic linker (`auto_connect`) | the model's choice | *\"Strength of the relationship (0 if unrelated)\"* |\n| The keeper of the seven keys | the model's choice | *\"How strong the relation is, 0 to 1\"* |\n| Critical-question scaffolding | 0.5 | a constant |\n| Cross-source premise proposals | 0.5 | a constant |\n| The splitter | 0.8 | a constant |\n| A person decomposing a claim | 0.8 | a constant (`api.py`) |\n| A person clarifying a term | 0.85 | a constant |\n| A person adding evidence or answering a question | 0.7 | the function's default |\n| Hand-made maps (`store_hand_extraction.py`) | 0.7 | the script's fallback |\n\nNone of these says what the number measures: the model's certainty that the link exists, how far\nestablishing one claim would advance the other, or something else. The corpus has been calling it\n*the classifier's extraction-time confidence*; no prompt asks for a confidence. It is the same kind\nof quantity as the self-evaluation score removed on 2026-08-18, a number requested with no rubric, so\nthere was nothing for it to be calibrated against.\n\n## 2. What the live graph holds (measured 2026-09-28, 4,639 live argument links)\n\n| Who wrote it | Links | Values |\n|---|---|---|\n| extraction, scaffolding links | 3,118 | all 0.5 |\n| automatic linker | 709 | 0.7 ×251, 0.6 ×132, 0.8 ×126, 0.9 ×62, 15 distinct values |\n| extraction, substantive links | 630 | 0.7 ×231, 0.8 ×138, 0.9 ×120, 0.85 ×69, 11 distinct values |\n| people | 92 | 0.8 ×33, 0.85 ×23, 0.7 ×22 |\n| cross-source premise proposals | 50 | all 0.5 |\n| splitter | 37 | all 0.8 |\n\nThe model-chosen values cluster on round numbers, which is what an undefined rating looks like. **Seven\nsources carry 0.7 on every substantive link, 174 links in all**, 144 of them one mapped author's file\nand the rest synthetic test material; the community compartments hold more hand-made maps at 0.7.\n\n## 3. What reads it\n\n**Shown to readers.** The claim page and the extraction page print it beside every link as a\npercentage (`70%`). On a hand-made map every link reads 70%, which states a precision nobody measured.\n\n**Chooses what is shown.** The map view keeps a claim's 24 direct neighbours and 4 second-step claims\nper neighbour *strongest first* (`claim_map.assemble`); the claim's graph view takes its top five\nlinks by it (`api.py`); the older graph drawing sets line width from it.\n\n**Ranks.** The *strongest* and *weakest* feeds order by it and label the results *well-scrutinized*\nand *needs scrutiny*, while their docstring says they rank by QBAF badge strength (`feed.py`; the\nbadge is the strength the site computes from answered critical questions). The bridging feed and the\ntruth graph's bridging list multiply disagreement by its average. So *well-scrutinized* currently\nmeans *the model gave these links a high number at extraction*, which no scrutiny ever changes.\n\n**Gates.** The automatic linker writes a link only when the model's own number exceeds 0.3.\n\n**Does not read it: the badge.** `badge_inputs.py` fetches it and discards it (`_strength`); an edge's\nstrength in the badge comes from `compute_edge_strength`, over its answered critical questions, with\n0.5 when none are answered. So the strength layer is clean, and every surface above uses a different\nnumber from the one the badge uses, under the same name.\n\n## 4. What a blank would do, reader by reader\n\n- **Pages**: the percentage disappears (the template shows it only when present). Honest.\n- **Map and top-five**: a missing value sorts as 0.0, so in a mixed neighbourhood every hand-made or\n  human link drops behind every machine-written one. That is a new distortion: a person's link is not\n  weaker for having been written by a person.\n- **Feeds**: ordering by a missing value depends on the database's null ordering, and the bridging\n  average falls back to 0.5. Unpredictable in the first, neutral in the second.\n- **The linker's gate**: unaffected, since it reads the model's own output before storing.\n\nSo blanking the hand-made 0.7 alone trades a visible false precision for a hidden ranking bias.\nChoosing a different constant (0.5, say) keeps the false precision and prints *50%*. Neither\nanswers what the number is for.\n\n## 5. The proposal: one number becomes three, each with one job\n\n**A link's strength, as readers see it, is a reading, never a stored value.** It is computed on read\nby the function the badge already uses, from the link's answered critical questions (and, while it\nstands, the methodology prior that ledger Q8 proposes to retire). It has no default: an unexamined\nlink reads *not yet examined*, never *50%*, and moves when someone answers a question on it. This is\nwhat *set dynamically* means here, and it makes the percentage on the page mean what readers take it\nto mean.\n\n**The machine's own rating is kept, as what it is.** Renamed so it cannot be mistaken for the reading\n(`classifier_confidence` or similar), given a rubric that says what 0.3 and 0.9 mean, and stored only\nwhere a model judged the link. Where a person wrote the link, or a constant did, it is blank, because\nnothing rated it. It keeps two jobs: the linker's write gate, and the trust ladder's triage of machine\nproposals (`earning-the-right-to-write.md`).\n\n**Ordering is computed.** A map or a feed orders by the reading first, then by what hangs on the far\nclaim (the map-view spec's open question, § 8, which the founder answered with *\"aren't these two\nboth important, in their own way?\"*), then by the machine's rating as a tie-break among machine\nlinks only. The *well-scrutinized* feed then shows links that were actually examined, which today is\nfew, and says so.\n\n**Why this and not a better default**:\n\n- *Blank only* hides the false precision and adds a ranking bias against people's links (§ 4).\n- *A different constant* is still a number nobody measured.\n- *A default from the methodology ladder* builds on the input ledger Q8 proposes to retire, and it\n  is a prior, not a measurement.\n- *A model rating every link, people's included* turns a person's assertion into a machine's opinion\n  of it, and a machine judgment on contested ground is a proposal, never a stored fact.\n\n## 6. What it would change, and what it costs\n\n- **Most links would read *not yet examined*.** That is the true state of the graph. It makes the\n  scarcity of examination visible, which the triage feed and *no gap displayed without a move* turn\n  into invitations.\n- **The map's selection needs its second signal.** With most readings equal, *strongest first*\n  degenerates to the tie-break; the structural signal (what hangs on a claim) has to exist first.\n- **Computing a reading per neighbour costs queries.** The map spec deferred ordering by badge for\n  exactly this reason; per-link readings can be cached and refreshed when a question on that link is\n  answered.\n- **The bridging feed re-ranks** (the long-open founder call in `TODO.md`), and so do *strongest*\n  and *weakest*. Nothing in the badge moves.\n- **Migration**: rename the stored field on machine-written links, clear it on constant-written ones,\n  and point every reader in § 3 at the reading or the renamed field. Reversible, since nothing is\n  deleted from the graph's edges except a number with no definition.\n\n## 7. Found on the way\n\n- `feed.py`'s own docs say *strongest* and *weakest* rank by badge strength and the bridging mode by\n  *high QBAF strength*; all three read the stored number. The August correction reached the public\n  docs and missed the code's.\n- A person's term clarification is stored with a fixed claim confidence of 0.65 (`api.py`), the\n  claim-level sibling of this defect.\n- Seven places in six files called the stored number *the classifier's extraction-time confidence*; corrected\n  2026-09-28 to say what it is: an undefined rating.\n\n## Cross-references\n\n`deliberus/graph/qbaf.py` (`compute_edge_strength`, `display_band`) · `deliberus/graph/badge_inputs.py`\n· `deliberus/graph/claim_map.py` · `deliberus/feed.py` · `deliberus/extraction/cross_structure.py` ·\n[strength-layer-audit.md](strength-layer-audit.md) (the badge's own history) ·\n[what-belongs-in-the-ontology.md](what-belongs-in-the-ontology.md) § 6c (*read, never set*) ·\n[earning-the-right-to-write.md](earning-the-right-to-write.md) (the trust ladder) ·\n[session39-what-the-graph-stopped-claiming.md](session39-what-the-graph-stopped-claiming.md) (the rule\nthis applies) · `specs/map-view/design.md` § 3 and § 8\n"}