Methodology and limitations: use cases 1-3
*Version m8-1, 2026-09-30 (use-case plan milestone M8). Every page and export of use cases 1-3 links here. The figures below are as of 2026-09-30; a later release restates them in its own manifest. Plan: docs/PLAN_USE_CASES_1_2_3_2026-09-29.md.*
What the pages say, and what they do not
The pages say who is connected, with a receipt per relationship: a company named in a covered filer's annual report, the quote that names it, and the filing it came from.
They do not say how much an event carries. No page states sizes, severity bands, tested directions or forecasts, and no page gives one figure for a whole book (plan §1.1 C-3; docs/MODEL_PLAN_2026-09-27.md ruling 3; the RATES-1 and POLICY-1 results). The one piece of book arithmetic is the book-weight share of use case 3, titled "book weight, not a loss or exposure estimate".
A page that finds nothing does not call the result clear. It says "no disclosed relationship among N covered filers read through <date>", with the coverage panel beside it (plan §1.7).
Every page and export is the same for every viewer. The session page matches a pasted list inside the viewer's browser; the list is not sent anywhere, stored, or written into the page's address (founder ruling of 2026-09-29, D4 option a). Whether this arrangement meets any legal standard has not been reviewed by counsel.
What is covered
- Covered filers: 189 companies that file annual reports with the SEC (10-K, and 20-F for foreign private issuers). Their annual reports were read for named customers, suppliers, foundries, assembly and test providers, contract manufacturers, distributors, licensors and licensees, deals and joint ventures.
- Filings read: 2,642 annual filings in the read ledger (
graph/read_ledger_v2.json), dated 2012-01-26 through 2026-09-10. - The dated table: 43,482 rows over 11,536 relationships (
graph/edge_state_v2.jsonl). Each row holds the quote, the accession and the date it became known (known_from). - Not covered:
- companies that do not file with the SEC, except where a covered filer names them;
- quarterly reports, current reports (8-K) and press releases, which are not read for relationships;
- relationships a filer describes without naming the other company. The accounting rules (ASC 280) make a filer disclose that a customer is 10% of revenue, not its name.
The dated State of a relationship
A relationship is one filer naming one counterparty in one kind of relation. Its State on a date comes from eval/state/state.py State.at(edge, date), reading only filings dated before that date:
| State | Meaning |
|---|---|
| current | the filer's latest read annual filing before the date names it |
| unobserved | the filer's latest read filing is more than 455 days old (its next annual filing has not been read), and less than 548 days |
| anonymised | the filer stopped naming the company and reports an unnamed counterparty with the same relation and a compatible stated share |
| stale | two or more of the filer's read annual filings after its last naming do not name it |
| ended | the filer's own filing says the relationship ended |
| lapsed | the filer's latest read filing is more than 548 days old |
| not yet disclosed | first named on or after the date |
A relationship not yet disclosed on a date never appears in a view of that date (plan C-2). Stale, ended and lapsed relationships are shown, with their last-named date, because a stopped naming is information too.
Receipts
Each row shows its receipt (plan C-1): the quote, the form, the filing date, the accession with its EDGAR link, the character offsets where the quote was re-found in the cached filing text, the heading above it, the fiscal period, the filer's name as it filed, and a context window (up to about 600 characters before and 400 after, widened to a sentence or a blank line). The CSV exports carry the same receipt in their own columns (quote, quote_status, accession, filed, form, filer_name, period, url, char_start, char_end, item_heading_above, context, and whether a display shows an ellipsis at either end of the window), beside the naming filer (named_by). A legibility page's parent view shows each ownership claim it rests on with that claim's receipts, each located in the cached text the same way and dated by its own filing; a receipt filed on or after the date is left out, and a claim left with no receipt is not shown. The claims it rests on are those whose object is a company in the book's view; the same group's claims about companies no holding names are counted on the line, not listed, so no receipt puts a company on the page that is not in the book.
The evidence index re-found all 43,482 row quotes in the cached filing text on 2026-09-30 (39,744 exactly, 3,657 with whitespace differences, 79 after normalising characters); 2 are marked "span too long to be a quote". A quote that cannot be re-found reads "quote not re-found" and is counted.
Identity
Companies are joined through an identity view (graph/identity_view_v1.jsonl, milestone M3):
- a key becomes an identity by identifier, then exact normalised name, then alias;
- a parent is a group, never a merge (Huawei Investment & Holding is a group key; Huawei Technologies is a member);
- names that may be one company, but are not proven so, are shown as "possible same entity" and never counted together;
- a company is never listed as its own counterparty (the self-match rule), while its own filings still count.
Known limits: the view holds ASML.AS ("ASM Lithography", ASML's former name) apart from ASML. Book intake reads the listing ASML.AS as ASML through its table of home-market listings, and the separate key is an open identity item. The view shows 4063.T (Shin-Etsu Chemical's code) under the name of its subsidiary Shin-Etsu Handotai; that is an open identity item too.
Use case 1: events
- Hop 1, both directions. A holding is reached when either its own filing or the locus's filing names the relationship; each line says "named by <filer>".
- Second hop. Hidden until the second-hop test (H2) passes. Its rules are fixed (
pipeline/evidence/reach.py,m16-hop2-v2; its own stop reasonsstops-hop2-v2): a second hop continues only through a covered filer whose first hop is current on the date, through the dated table and through the graph store's foundry, outsourced manufacturing and assembly-and-test claims. A graph-store line carries its receipts dated by their own filing (the evidence index's date for the accession; a claim's own date when the index does not hold the filing), only receipts filed before the date are carried, matched or counted, and the unit of disclosure is one claim in one receipt filing. A graph-store series is judged current, stale, lapsed or unobserved against the filer's read filings in which the store holds a claim of the same relationship, never against the whole read ledger, and its sentence names that set and says that the filer's filings were not searched. - Places. A place event is shown as a base-rate sentence ("N of M covered filers state a site in P"), not as a list of holdings, until the place-channel test (R5) passes. Revenue by geography is always labelled revenue.
- Where the evidence stopped. Every result carries a stop ledger from a frozen list of reasons (
pipeline/evidence/stops.py, stops-v1): the locus not a covered filer, a counterparty not read, a counterparty unresolved, a relationship stale, ended, lapsed or anonymised, a filer's latest filing not read, a covered filer never asked about the locus, a filer not read before the date, the depth limit, a self match left out, and place evidence stated only at country level. - Silent and never asked are kept apart. "Never asked" means the filer's filings were read by the extraction but not searched for the locus. "Searched and silent" needs a search receipt, a receipt kind that does not exist yet (plan M22), so no page says a filer is silent.
Use case 2: notices and lists
Sources and their start dates:
- Federal Register documents of the Bureau of Industry and Security (Entity List, Unverified List, Military End-User List, the Affiliates rule): the document catalogue from 2016-09-01 through 2026-09-30. The notice records read the second parse (
graph/screen/entries_v2.jsonl: 214 BIS documents, 136 with entries, 4,659 entries), the file the removal check below was run on, and each record pins it by its sha256. The first parse (entries_v1.jsonl: 174 BIS documents, 125 of them with list entries, 4,194 entries) is kept as written and no record reads it. - eCFR point-in-time copies of the lists (an editorial compilation, not the official legal edition):
- Entity List (Supplement No. 4 to Part 744): copies from 2017-01-03 through 2026-08-24;
- Unverified List (Supplement No. 6): from 2017-01-03 through 2025-04-25;
- Military End-User List (Supplement No. 7): from 2020-12-23 through 2025-11-12.
- Consolidated Screening List (trade.gov; includes OFAC's SDN list and the NS-CMIC list): one snapshot, downloaded 2026-09-30. It is a current-only layer: it says what the file listed on that day, and it has not been tested on history. Its direct check (plan D5;
pipeline/screen/holding_check.py, rulesm25-holding-2, recordsm25-record-2) is issued as an append-only record, and the session page carries that record's book-independent layer (schemauc2-csl-universe-2) with the record's pins. A holding, or a company the graph store's subsidiary claims (wholly owns, directly controls, wholly owned subsidiary, significant subsidiary, subsidiary of; filed before the download date, with the filing named) or the identity view's dated tables place in its group, is matched by a list row under the matching rules below; a legal entity number lifts only a decision held back for want of corroboration, never one for a covered filer or a company in a covered filer's group. The codes a row states (ISIN, CUSIP, listing code) are compared with the codes written on a book line: an ISIN or CUSIP confirms the security, and a listing code is a possible match, since a code can pass from one company to another. Each book line gets one of six labels: match confirmed, match possible, ended row only, no entry matched, code only and no entry, not checked; and a company the file does not match is not said to be unlisted.
Tiers of a notice record:
- Tier A: a covered filer's filing states a relationship with the listed party (the dated State table).
- Tier B: a covered filer's filing names the party, and the relation is not classified.
- Tier C: a listed party's parent or arm through an ownership claim filed before the notice date. Not built yet; the store's ownership claims were filed almost entirely in 2025-26, so tier C is not testable before 2025.
Matching rules: an alias confirms a match only with address or country corroboration; an alias that equals or contains the name of a different known company never confirms by rule; a one-word name needs corroboration; city and province prefixes fold (?zhejiang dahua is Dahua). Anything else is a "possible match", shown as possible and not counted as reached until a person confirms the identity with one answer: same entity, different entity, or cannot tell. A record exports only with the confirmer's name and a UTC time.
Listed as of a date: every Federal Register document the Federal Register's catalogue lists as amending 15 CFR part 744, published 2016-09-01 through 2026-09-30, was fetched and read into the second parse, and the removal record it gives was compared with each eCFR copy in that window, entry by entry, in both directions (the parser's check S3 (c), in-sample: the parser was built and reconciled on these same notices; the held-out S3 is the same measure on notices first fetched after the freeze, reported apart). Inside that check's window (the Entity List and the Unverified List from 2017-01-03, the Military End-User List from 2020-12-23), a record whose entry matches by name reads "Listed as of <date> on the <list>: <how it came to be listed>; every Federal Register document amending 15 CFR part 744 through <date> was read, and none read removes it". The date is the notice date, never the check's later window end. An alias match says the same without the opening words. An entry the check names as an exception carries the reason instead. Outside the window a record reads "added on <date> by <document>; removal status not checked", or the removal record read so far, stated only through the notice date.
The notice date is the earlier of the effective date and the publication date. Nothing filed on or after it is used; what later notices did to an entry sits in a separate, labelled panel that the as-of view never reads. A development notice's page keeps that panel closed; the pages of a session's scored items carry none.
Use case 3: shared counterparties
- Counted: a relationship that is current by State, confirmed by the identity view, and in one of six families (foundry, assembly and test, contract manufacturing, named customer or supplier, distribution, licence). The family treatment is a frozen file (
eval/usecases/legibility/family_treatment_v1.json), pinned by its sha256. - Folded into one counted line: smelters, banks, universal licensors, and list sentences (a relationship kept current only by receipts that name nine or more companies).
- Unranked. The list is ordered by how many holdings of the book name each counterparty, then by name. A ranking by specificity is a labelled hypothesis, withheld until its test (L1) passes. Each counterparty shows its document frequency: how many covered filers name it.
- Parent view: ownership claims filed before the date group companies as a view; each company keeps its own line. Only the claims about companies in the book's view are printed; the group's other claims are counted.
- Sole and dual sourcing: only where the filing's own words say so, with the quote, until the sole-source audit (L3) passes.
- Book-weight shares: for each shared counterparty, the share of the book's gross, long and short weight held in holdings with a current disclosed relationship with it. Long and short are never netted. This is book weight, not a loss or exposure estimate.
Book intake
Every line of a pasted list or CSV gets one label, and no line is dropped (plan C-4, L7): covered, not covered, could not read, fund (not looked through), cash (not a company), or not a holding line (blank, comment, header, total). Each unmatched line says why.
- Identifiers: tickers (US, class shares such as BRK.B, exchange-suffixed codes such as 2330.TW, 005930.KS, 0981.HK, 8035.T, and Bloomberg-style codes such as "2330 TT"), ISINs (with their check digit; US and CA ISINs hold a CUSIP, TW and KR ISINs hold the local code), CUSIPs (with their check digit), and CIKs.
- Home-market listings of covered filers are read through a frozen table: 2330.TW is TSM, 3711.TW is ASX, ASML.AS is ASML, 6758.T is SONY.
- US and OTC lines of companies held under a home-market code (ADRs and foreign ordinaries such as IFNNY for Infineon, IFX.DE) are read through a second frozen table,
m8-adr-1(23 lines). It was built from exact name equality between SEC's company-list titles and the identity view's names, widened to every line of the same CIK, and each pair was read by hand. Intake itself never matches a name. - Other lines of the same SEC registrant: an OTC foreign line (four letters and F or Y, such as TSMWF) or a class share (BRK-A) whose CIK is the CIK of a held identity is read as that identity, and the line says so. A preferred share or a note of the same registrant is not: it reads "not matched to an identity the view holds under this ticker".
- CIKs: a covered filer's CIK comes from
graph/filers.json, from the identity view where one identity holds it, and otherwise from SEC's company list under the filer's own ticker (43 of the 189 covered filers on 2026-10-01, Alphabet's CIK, which two share classes hold, among them). A line entered by a covered filer's CIK reads covered. A CIK another identity already holds is never taken over. - CUSIPs: looked up in the release's CUSIP table (CUSIP to the key intake reads), which
eval/usecases/books13f.pybuilds from SEC's Official List of Section 13(f) Securities and the resolver (plan M19) and which intake reads fromgraph/cusip13f_table.jsonwhen that file is in the release. A release built before the table exists holds none, and a CUSIP line then reads "could not read" with that reason; a CUSIP the table does not hold reads "could not read" too. The line stays in the book either way. The list does not say which of its rows are funds:books13f.pytypes a row a fund when its issuer name or description holds one of the fund words intake reads in a name column, or the issuer name starts with one of a few fund sponsors' trust names (rulem19-fund-1, not checked row by row). Those rows are never mapped to a ticker (one trust's CIK names many funds); the table lists their CUSIPs apart, so a fund entered by its CUSIP alone, or by a US or CA ISIN that holds that CUSIP, reads "fund" and is not looked through. - Funds: a frozen list of widely held exchange-traded funds, SEC company-list titles that name a fund, the CUSIPs the CUSIP table lists as funds, and CSV type or name columns. Funds are left out of the shared counterparties and of the book-weight shares.
- Names are used only to recognise funds and cash, never to match a company. In a file with no ticker, ISIN, CUSIP or CIK column, a name-column cell that is one identifier and nothing else ("MU", "2330.TW", "2330 TT Equity") is read as that identifier, as the same text on a pasted line is; a cell with other words is a name.
- Words that are also tickers: "PCT" alone is PureCycle's ticker, not a header. "CASH" in capitals is both a cash line and Pathward Financial's ticker, so it reads "could not read" with both readings stated (its weight stays in the book); "Cash" reads as cash, "CASH US" as the company.
- Characters: digits are the ASCII digits 0 to 9 (a full-width or Arabic-Indic digit is not read as a weight); spaces include the no-break and ideographic spaces; a leading byte-order mark is dropped. The browser and Python read every line the same way, and a test checks both on hundreds of random books.
Exports and printing
- Every CSV row carries a methodology column: this page's file name in the release, the release date, and the sha256 of this page's source, so a saved file still names the exact text it was built under. It becomes an address when the release is published (plan M28).
- Every CSV row of the session page carries its licence words: the event's relationship or place wording, "screening aid, not a determination" for notices and the screening list, "unranked" for shared counterparties.
- A notice record exports only with the confirmer's name and a UTC time, in the release's CSV files and in the session page's CSV text alike; until then the session page's CSV text holds one row saying the record is not exported.
- Printed pages carry every receipt's context window and every stop entry. The panel of what later notices did prints its label only; its text is after the notice date and stays closed. The session page prints the sections that are open.
- The session page holds this page's text inside the file, so its link works wherever the file is saved.
What each result is licensed to say
| Statement | Licensed by | Status on 2026-09-30 | Wording used until then |
|---|---|---|---|
| Reached through a disclosed relationship | R1, R2 (UC1); S1, S2 (UC2) | not tested | "Relationship mentions, completeness untested" |
| Connected through two disclosed hops | H2 | not tested | second-hop block hidden |
| Reached through a site, a counterparty or revenue in a place | R5 per channel | not tested | a base-rate sentence; revenue labelled revenue |
| Export rule with no named entity | E1 | not tested | "Sector membership, not relationship reach" |
| A screen of filers with a relationship with a listed party | S1-S3 | not tested | "Research aid, not a screen" |
| Listed as of a date | S3 (c), removals read | in use inside the check's window, in-sample (M5b); held-out not measured | "Added on <date>; removal status not checked" (outside the window) |
| No disclosed relationship among covered filers | always, with the coverage panel | in use | never clear |
| Ranked shared counterparties | L1 | not tested | unranked, with document frequency |
| Sole source | L3 | not tested | explicit wording only, with the quote |
| Silent on a question | L4 | not built | not shown |
Measured rates
| Rate | Measured | Source |
|---|---|---|
| Row quotes re-found in the filing text | 43,482 of 43,482 (2026-09-30) | the evidence index evidence_94056e2c5484 |
| History-edge receipts that support the row | 83.0% supported, 1.7% wrong (an audit of a sample) | docs/HISTORY_EDGES_2026-09-24.md |
| Relationship recall (R1), precision (R2), stop correctness (R4) | not measured yet | acceptance runs, plan M26 |
| Second hop (H2), place channels (R5), export-rule channel (E1) | not measured yet | plan M16, M20, M23 |
| Notice recall (S1), identity precision (S2), parser (S3 (a), (b), and (c) held out) | not measured yet | plan M18, M26 |
| Removal record against eCFR's copies (S3 (c), in-sample) | compared at each copy date: 131 (Entity List), 24 (Unverified List), 14 (Military End-User List); the 23 runs of copy rows the lookup misses are named, and reported from the copy | graph/screen/listed_asof_check_v2.json |
| Universal nodes in the top five (L1), sole-source audit (L3), silent cells (L4) | not measured yet | plan M21, M22, M24 |
| Rows supported as shown, by two readers (C-6) | not measured yet | plan M21 |
Known misses, from the plan's checks: only 11 of the 22 filers that named Huawei in the two years before its 2019 listing appear in the dated table; a relationship a filer states without the counterparty's name cannot be reached.
Versions
Wording lint uc123-lint-2 (pipeline/lint.py); book intake m8-book-5 with the ADR table m8-adr-1 (pipeline/evidence/book.py); reports m8-report-4 (pipeline/evidence/report.py); session page m8-session-6; notice records m6-record-5 (pipeline/screen/record.py); stop list stops-v1; family treatment v1; evidence index m2-4; second hop m16-hop2-v2 with its stop reasons stops-hop2-v2 (pipeline/evidence/reach.py, stops.py); screening-list parser csl-2 and layer csl-layer-3 (pipeline/screen/csl.py), its direct check m25-holding-2 and records m25-record-2 (pipeline/screen/holding_check.py). Each release's manifest (release.json) pins the sha256 of every input and file, and a release is not built while this page names another version or entries file than the release's code and records (methodology_problems in pipeline/evidence/report.py).
The wording lint checks our own words on every page, export and the release data inside the session page. Some words are never used (for example clear, will, safe, arrows, valuation words); others appear only where a negator governs them in the same clause or heads a closed list ("no sizes, severities, forecasts or directions").