How this was built
Pipeline
Raw text → segmentation → named-entity detection → entity normalization → coreference → relation/event extraction → confidence scoring → human correction → network construction → analysis. Every stage is versioned and every release records the exact versions used, so a network can always be traced back to the code and data that produced it. This release of Njáls saga was built with:
| Graph release | njala-2026-09-07-46b49883 |
| Source text SHA-256 | 6d1fc58dfb48447c29f7a6804a92d9d60a1e6bd14fd17267a9a72b3e51c0def1 |
| Segmentation | seg-v1 |
| Mention resolution | mention-v1 |
| Coreference | coref-v1 |
| Relation rules | rel-rules-v2 |
| spaCy model | en_core_web_sm-3.8.16 |
| Entity table | njala-entities-v6 |
| Annotation revisions | annot-v0 |
| Gold standard | gold-v1 |
| LLM extraction | Yuu no Sekai · relation_extraction_v1@9439178a1fc0 · scope: gold-chapters |
Entity resolution
Njáls saga uses a hand-curated 116-entity canonical table (data/entities/njala.yaml): stable ids, canonical names, alias lists, patronymic/epithet fields, known parent links, and a curated chapter-window prior for disambiguating a bare given name shared by multiple entities. The other three sagas use a mechanically bootstrapped table (sagagraph.bootstrap_entities) seeded from the same frequency/patronymic/epithet discovery statistics, marked status: auto-bootstrap and not yet gold-checked — see Extraction for exactly which numbers rest on which table.
A bare given name shared by multiple entities resolves through a four-rung ladder, in order: (1) the surface form itself is qualified (patronymic/epithet) — confidence 1.0; (2) a qualified mention of exactly one candidate occurred in the previous 60 sentences — 0.85; (3) exactly one candidate's curated active-chapter window contains the current chapter — 0.7; (4) otherwise, the candidate with the most recent qualified mention or nearest window boundary, flagged low-confidence for review. Nothing is ever silently merged: every non-1.0 resolution is visible in the annotation review queue.
The full annotation toolkit spans two places. The review queue surfaces low-confidence mention resolutions and relations for verify / reject / retype / flag actions. A character’s own Curate this entitypanel (on every character profile page) handles the entity-level actions — confirming an alias, merging a duplicate into an existing entity, or splitting a bundled entity's mentions into a new one. Every action from either surface writes the same append-only revision record to data/annotations/<saga>/revisions.jsonl, applied on the next pipeline run; nothing is ever deleted, including a rejected relation, which stays in the release with status: rejected rather than disappearing.
Gold annotation
Ten chapters of Njáls saga were hand-annotated by the project author against a written guideline (mentions, a documented pronoun sample, and every kinship/marriage/friendship/conversation/conflict/killing/support relation, tagged explicit or implicit). This is a single-annotator gold set with no independent inter-annotator agreement measurement — see the paper's Limitations section for what that does and does not license.
What the network metrics mean (and don't)
A word of caution before the list: this site uses “edges” in two related but different senses, and both are visible on purpose. The saga browser and cross-saga comparison report a collapsed pair count (how many distinct pairs of characters share any semantic tie — 381 for Njáls saga) because that is what the network-metric algorithms below actually operate on. The interactive graph additionally reports typed edge records (one per (pair, relation type) — e.g. a pair linked by both kinship and conflict counts as two records but one collapsed edge), because the viewer draws one colored line per relation type between a pair. Neither number ever includes the sentence co-occurrence baseline layer.
- Degree / weighted degree — how many distinct characters (or weighted by evidence count) a character is linked to. The most literal, least interpretively loaded metric here.
- Betweenness centrality — how often a character sits on the shortest path between two others, computed on a distance-weighted graph (stronger ties = shorter paths). Read as "structural bridge," not "most important" in any narrative sense on its own.
- Closeness centrality — inverse average distance to everyone else. Sensitive to disconnected components; interpret cautiously for sagas whose graph has more than one component (Laxdæla, Egils saga, Grettis saga all have four).
- PageRank / eigenvector centrality — importance propagated from the importance of one's neighbors. Two different assumptions about "important connections matter more"; they rank characters similarly here but are not the same computation and can diverge.
- Louvain communities — a specific, randomized, resolution-dependent community-detection algorithm, not a ground truth about factions. See the error-propagation results: community assignment is the least robust metric this project reports to plausible extraction error.
- Structural balance — computed only over the signed subgraph of kinship/marriage/friendship/support (positive) and conflict/killing/feud (negative) edges; conversation and co-presence are unsigned and excluded entirely.
All metrics were cross-checked against hand-derived values on synthetic graphs with known answers (star graphs, path graphs, the Zachary karate club's published betweenness values, disjoint cliques for community detection) before being trusted on saga data — see tests/test_metrics.py.
Cross-saga entity resolution
The Icelandic family sagas share a common "saga world": a handful of historical/narrative figures recur across multiple sagas.data/entities/cross_saga.yaml records a short, hand-verified list of such links — currently four persons: Hoskuld Dala-Koll’s son and his half-brother Hrut (linked between Njáls saga and Laxdæla saga, on matching genealogy independently narrated in both texts), Snorri the Priest/Godi (linked across all three sagas that mention him, on a distinctive epithet and consistent chronological placement), and Gudmund the Mighty (linked between Njáls saga and Grettis saga).
Every link was checked against the actual downloaded corpus texts, not asserted from outside knowledge of saga genealogy — each entry in the register quotes the specific passages compared. Building this register also caught a real entity-resolution bug: the bootstrapped Grettis saga table had merged the unrelated minor figure "Gudmund the son of Solmund" together with "Gudmund the Mighty" under one bare-name entity, discovered only when trying to verify the cross-saga link. That entity has since been split and both halves promoted to status: curated.
A cross-saga link never merges the underlying entities: each saga keeps its own separate mentions, edges, and centrality scores for "its" copy of the person. The link only records that two (or three) saga-scoped ids are believed to name the same person, with a confidence level (high / medium) and, where relevant, a caveat about what the link does notestablish. See a linked character’s profile page for the “Also appears in” section, or tests/test_cross_saga.py for the consistency checks the register is held to.
Feud-chain detection (a documented under-count)
A killing is flagged as retaliation for an earlier killing when its victim is the earlier killer (or their kin/declared ally) and its killer is kin/declared ally of the earlier victim. This structurally cannot detect feud propagation carried out throughemployment or fosterage loyalty rather than kinship or an explicitly stated alliance — which Njáls saga uses repeatedly (household servants killing on their employers' behalf). See the paper's Case Studies section for a worked example (chapters 35–45) where this causes a real, acknowledged miss.
Exports
Every saga release ships CSV (nodes/edges), JSON, GraphML, and a citation/provenance text file under its release's export/ directory.