spb/firc0001_uqo
Public
1% ============================================================================2\begin{appendices}3% ============================================================================45\section{Taxonomy}\label{app:taxonomy}67\begin{table}[H]8\centering\small9\caption{The \SPIDtaxonomyN-category SPID project taxonomy}\label{tab:taxonomy}10\begin{threeparttable}11\input{tables/tab_taxonomy}12\begin{tablenotes}\footnotesize13\item Codes and labels are read with \texttt{ast} from \texttt{spid/taxonomy.py} in the hash-verified snapshot of revision \texttt{2324b58} (\texttt{code/audit/spid\_snapshot/}); the module's modification time predates the June 2026 run and no earlier revision exists, so the taxonomy is the same for both runs as far as the file system can show (\Cref{sec:versioning}). The taxonomy has no category for financing instruments (\Cref{sec:construct_def}); an out-of-vocabulary label returned by the model is mapped by substring matching and, failing that, to \texttt{technology\_deployment}.14\end{tablenotes}15\end{threeparttable}16\end{table}1718\section{Extraction contract}\label{app:prompt}1920The system prompt below is reproduced from \texttt{spid/extract/llm.py} with the \SPIDtaxonomyN\ taxonomy codes and labels substituted exactly as the code does (generated by \texttt{code/make\_tables.py}; never retyped). The user message is the string ``\texttt{SECTION: <section\_name>}'' followed by the focused section text (\Cref{sec:focus}), cut at \SPIDuserMessageCap\ characters. Decoding parameters: temperature 0, JSON-object response format (valid JSON is guaranteed; the field list is not enforced by a schema), \SPIDcompletionTokens\ completion tokens, \SPIDretries\ attempts before an empty list is returned, \SPIDtimeoutSeconds-second timeout, no \texttt{seed}. The model identifier is not recorded in the ledger or the logs (\Cref{sec:versioning}). Straight quotes are rendered as sent.2122{\footnotesize\input{tables/prompt_verbatim}}2324\noindent The candidate gate is the case-insensitive regular expression below, reproduced from \texttt{spid/extract/rules.py} (\SPIDgateRegexAlternatives\ alternatives, \SPIDgateRegexLength\ characters, compiled with \texttt{\SPIDgateRegexFlags}); line breaks are inserted for display only. Sections without a match, or with fewer than \SPIDminWords\ words, are not submitted; sections with fewer than \SPIDminWords\ words are not ledgered either, except the \SPIDbackfilledUnderThirtyWords\ June rows backfilled without the filter.2526{\footnotesize\input{tables/gate_regex}}2728\section{Data dictionary and data-model audit}\label{app:dictionary}2930\Cref{tab:datamodel} lists the tables required by the research-design specification against the current implementation (generated from \texttt{data/datamodel\_audit.csv}). The full field-level dictionary of the current tables is maintained in \texttt{docs/data\_dictionary.md} of the working-paper folder and in the repository documentation; \texttt{amount\_raw} is documented there as a formatted copy of \texttt{amount\_usd}, not as a source string.3132{\footnotesize\input{tables/tab_datamodel}}3334\section{Evidence register}\label{app:evidence}3536\begin{table}[H]37\centering\footnotesize38\caption{Evidence register: status of the main claims of this paper at revision \texttt{2324b58} after the Stage D audits}\label{tab:evidence}39\begin{threeparttable}40\begin{tabularx}{\textwidth}{@{}>{\raggedright\arraybackslash}X>{\raggedright\arraybackslash}p{5.9cm}@{}}41\toprule42Claim & Status \\43\midrule44Universe of \SPIDuniverseN\ issuers built from the IWV holdings file (\SPIDiwvHoldingsDate) and the S\&P~500 cache (\SPIDspWikipediaDate); covers \SPIDrussellProxyCoveragePct\% of the index constituent count & Implemented; derived artefacts verified and hashed; source holdings and ticker files not archived; index count read from the factsheet \\45\SPIDfilingsTotal\ primary documents of Forms 10-K/10-Q/8-K since 2010 downloaded; \SPIDfilingsNotParsed\ not parsed (\SPIDfilingsMissingOnDisk\ missing on disk) & Implemented, verified (database counts; accession list published) \\46Acquisition respected the SEC rate limit (aggregate token bucket; no 403 recorded) & Implemented; documented from run notes; orchestrator logs not archived \\47\SPIDsectionsTotal\ sections, \SPIDchunks\ chunks and embeddings; factor panels for \SPIDannualPanelFirms\ issuers & Implemented, verified (database counts) \\48\SPIDledgerTotal\ sections ledgered; \SPIDgatePassTotal\ calls; outage rows removed reconcile with the log & Implemented, verified (gate recomputed; log reconciled) \\49Ledger free of failed-call artefacts & Not verified: \SPIDllmFailedJsonDecodeError\ silent failures outside the outage; first post-outage batch (\SPIDresumeBatchSections\ sections) suspect; re-submission not authorised \\50Two runs under one prompt text & File-system evidence only (modification times, two-line diff between October revisions); no June revision, no model identifier or prompt hash in the ledger \\51\SPIDmentions\ stored mentions (\SPIDledgerMentionsReturned\ returned; \SPIDcollisionMentions\ lost to identifier collisions), \SPIDprojectCountCurrentKey\ projects under the current key, graph of \SPIDkgNodes\ nodes & Implemented, verified; project count depends on the key (\SPIDprojectsKeyTypeDropped--\SPIDprojectsKeyStrict); representative fields depend on tie order \\52Structured fields of each mention grounded in its source section & Measured for all mentions: \SPIDgroundAllPct\% fully grounded (years \SPIDgroundYearsPct\%, partners \SPIDgroundPartnersPct\%, amounts \SPIDgroundAmountNumberPct\%, locations \SPIDgroundLocationsPct\%, technologies \SPIDgroundTechPct\%); transcription, not correctness \\53Description grounded in the passage & Documented (prompt rule); not mechanically checkable (no span stored) \\54What the model was shown & Measured for every ledgered section (median \SPIDmdnaShownMedianPct\% of a 10-K MD\&A; \SPIDmentionsFromLtTwentyFivePct\% of mentions from sections shown $<$ 25\%); recall bound \SPIDrulesFocusRecoveredPct\% \\55Category consistent with an external classification & Measured for 8-Ks as a consistency proxy (Item~2.01 $\to$ \texttt{ma\_integration} \SPIDbenchMaGivenTwoOhOne; Item~2.05 $\to$ \texttt{cost\_reduction} \SPIDbenchCostGivenTwoOhFive); not precision or recall \\56Agreement with a rule-based baseline & Measured on a weighted sample of \SPIDrulesSampleProductive\ + \SPIDrulesSampleZero\ sections (rules flag \SPIDrulesGivenLlmPct\% of model-productive sections); neither is a ground truth \\57Financing instruments and Item~2 swaps as false-positive classes & Measured by pattern (\SPIDfinMentionsPct\% of mentions; \SPIDswapCandidates\ swap candidates); not annotated \\58Extraction precision/recall, category accuracy, field accuracy, calibration & Not measured; frame drawn and weighted ($n = \SPIDannNProductive + \SPIDannNZero$), protocol published, labels pending (author task) \\59Linkage precision/recall of the resolution key & Not measured; over-merge indicators measured (\Cref{sec:resolution_rule}); audit protocol specified \\60Stability under re-submission, prompt paraphrase and model substitution & Not measured; protocol specified; requires model calls not authorised \\61Amounts typed and separated from realized expenditure & Not implemented (proposed); \texttt{amount\_raw} is a formatted float; tail audited (\SPIDamountGeFiftyBMentions\ mentions $\geq$ 50 B USD) \\62Dated project events and point-in-time revision flags & Not implemented (mention-level timeline only) \\63Release of the derived tables; licence & Author decisions pending \\64Author order, affiliations and CRediT contributions & Pending confirmation by the three coauthors \\65\bottomrule66\end{tabularx}67\begin{tablenotes}\footnotesize68\item ``Measured'' entries refer to the read-only audits of \texttt{code/audit/} whose outputs are in \texttt{results/} with a manifest (script hash, database sizes and modification times, row counts); none involved a model call. ``Verified'' means recomputed from the exported data or the databases; ``documented'' means stated by the code or the run notes without an independent check.69\end{tablenotes}70\end{threeparttable}71\end{table}7273\section{The two extraction runs}\label{app:runs}7475\paragraph{Git and file-system evidence.} The repository holds \SPIDrepoCommits\ commits, all dated October~27--28, 2026 (\texttt{results/runs/git\_evidence.md}); \texttt{project-db/} enters at the first commit. The extractor modules carry modification times of \SPIDextractorMtimeDate\ and SHA-256 hashes recorded in \texttt{code/audit/spid\_snapshot/SHA256SUMS}; the driver files were edited on October~27, 2026 before the first commit. The diff between the revision the earlier version called ``the June revision'' (\texttt{df7905d}, dated October~27) and the build revision \texttt{2324b58} on the extractor, parser and driver files is the following change to \texttt{store.py}:7677{\scriptsize\verbatiminput{../results/runs/git_diff_df7905d_2324b58.patch}}7879\noindent The diff from the first commit (\texttt{0304133}) to \texttt{2324b58} on the same files is the following change to the corpus-layer \texttt{filing\_parser.py}:8081{\scriptsize\verbatiminput{../results/runs/git_diff_0304133_2324b58.patch}}8283\paragraph{Mentions and projects by cohort, run and form.} \Cref{tab:june_october} reconciles the mentions of the S\&P~500 cohort (\texttt{in\_sp500} true) and of the Russell-only cohort by run and form; the June block is identified by the backfill timestamp. The S\&P~500 cohort's 10-Q mentions come from both runs for the same issuers, which permits a within-issuer comparison: on the \SPIDpairedIssuers\ issuers with 10-Qs in both runs, the productive share is \SPIDwithinProductiveJune\% in June and \SPIDwithinProductiveOctober\% in October (paired difference \SPIDpairedDeltaPp\ percentage points, standard error \SPIDpairedSePp), mentions per row \SPIDwithinMentionsPerRowJune\ and \SPIDwithinMentionsPerRowOctober, mean confidence \SPIDwithinConfJune\ and \SPIDwithinConfOctober, and the M\&A share \SPIDwithinMaShareJune\% and \SPIDwithinMaShareOctober\% (\texttt{results/runs/within\_sp500\_*.csv}). For 10-Qs, whose text went through the same parser in both runs, the two runs therefore behave alike; the cohort difference of \Cref{sec:time} comes from the volume of sections and from the 10-K segmenter, not from the extractor.8485\begin{table}[H]86\centering\scriptsize87\caption{Mentions, projects touched, filings and issuers by cohort, extraction run and form}\label{tab:june_october}88\begin{threeparttable}89\adjustbox{max width=\textwidth}{\input{tables/tab_june_october}}90\begin{tablenotes}\footnotesize91\item Source: \texttt{results/resolver/june\_october\_reconciliation.csv} (\texttt{code/audit/a03\_resolver\_speccurve.py}). \texttt{in\_sp500} is the cohort flag of the universe; \texttt{run} is ``backfilled\_june'' for rows stamped at the backfill timestamp and ``october'' otherwise; ``projects touched'' counts the projects of the current key that have at least one mention in the cell, so a project can be touched by both runs. The issuer-level regression of the project count on the cohort flag is in \texttt{results/runs/table6\_cohort\_regression.json} and summarized in \Cref{sec:time}.92\end{tablenotes}93\end{threeparttable}94\end{table}9596\paragraph{Fiscal year.} \texttt{fiscal\_year} is empty for \SPIDfiscalYearNullMentions\ mentions because the corresponding \SPIDfiscalYearNullFilings\ filings carry no fiscal year in the corpus layer; a derived fill from the report or filing date is exported for \SPIDfiscalYearFillAccessions\ accessions (\texttt{results/runs/fiscal\_year\_fill\_by\_accession.csv}) and is not stored in the database.9798\section{Additional tables}\label{app:tables}99100\begin{table}[H]101\centering\footnotesize102\caption{Coverage by filing year}\label{tab:coverage_year}103\begin{threeparttable}104\adjustbox{max width=\textwidth}{\input{tables/tab_coverage_year}}105\begin{tablenotes}\footnotesize106\item Source: \texttt{data/issuers\_by\_year.csv}, \texttt{data/filings\_by\_year\_form.csv}, \texttt{data/mentions\_by\_year.csv}, \texttt{data/projects\_by\_first\_seen\_year.csv}. ``Issuers'' counts issuers with at least one filing in the year; ``Projects first seen'' counts projects of the current key whose earliest mention is filed in the year, so 2010 is left-censored and 2026 (to \SPIDfilingDateLast) is partial. The fixed-cohort and windowed-key series are in \texttt{results/timeseries/first\_seen\_fixed\_cohort.csv} and \Cref{tab:timeseries_cohort}.107\end{tablenotes}108\end{threeparttable}109\end{table}110111\begin{table}[H]112\centering\scriptsize113\caption{First-seen projects and mentions per issuer, all issuers and the fixed 2010 cohort, under the current key and under windowed keys}\label{tab:timeseries_cohort}114\begin{threeparttable}115\adjustbox{max width=\textwidth, max totalheight=0.82\textheight}{\input{tables/tab_timeseries_cohort}}116\begin{tablenotes}\footnotesize117\item Source: \texttt{results/timeseries/first\_seen\_fixed\_cohort.csv} (\texttt{code/audit/a09\_timeseries\_cohort.py}). ``fixed\_2010\_cohort'' restricts every series to the \SPIDfixedCohortIssuers\ issuers that file in every year from 2010 to 2025. ``first\_seen\_k3'' and ``first\_seen\_k5'' open a new episode when a project key is silent for more than three or five years (\SPIDepisodesKthree\ and \SPIDepisodesKfive\ episodes in total against \SPIDprojectCountCurrentKey\ projects). 2010 is left-censored and 2026 partial.118\end{tablenotes}119\end{threeparttable}120\end{table}121122\begin{table}[H]123\centering\small124\caption{Issuers with the most resolved projects}\label{tab:top_issuers}125\begin{threeparttable}126\input{tables/tab_top_issuers}127\begin{tablenotes}\footnotesize128\item Source: \texttt{data/top\_issuers.csv}. Counts are projects of the current key; rows with equal counts are ordered by ticker. The list is consistent with issuers whose business consists of enumerable sites, routes or wells; whether it also reflects over-splitting by the key has not been measured (\Cref{sec:resolution_rule}).129\end{tablenotes}130\end{threeparttable}131\end{table}132133\begin{table}[H]134\centering\small135\caption{Self-reported confidence of mentions}\label{tab:confidence}136\begin{threeparttable}137\input{tables/tab_confidence}138\begin{tablenotes}\footnotesize139\item Source: \texttt{data/confidence\_dist.csv}; confidence rounded to one decimal over the \SPIDmentions\ stored mentions. Mentions below \SPIDconfThreshold\ are not stored. The 0.6 bin includes \SPIDconfExactDefault\ mentions whose confidence was defaulted by the post-processing because the model returned none (\Cref{sec:contract}); the minimum stored value in both runs is 0.5. No calibration has been measured.140\end{tablenotes}141\end{threeparttable}142\end{table}143144\begin{table}[H]145\centering\small146\caption{Knowledge graph composition}\label{tab:graph}147\begin{threeparttable}148\input{tables/tab_graph}149\begin{tablenotes}\footnotesize150\item Source: \texttt{data/kg.csv}. Nodes are projected from the \texttt{projects} table of the current key (\texttt{owns}: company to project; \texttt{located\_in}: project to canonical location; \texttt{uses}: project to technology tag). Partner nodes are created without edges. Technology tags are free text and up to \SPIDtechRegexEqualPct\% of tag lists may have been back-filled from the model's description (\Cref{sec:contract}).151\end{tablenotes}152\end{threeparttable}153\end{table}154155\begin{table}[H]156\centering\scriptsize157\caption{Most frequent name tokens of the resolution key among location-less mentions}\label{tab:top_name_tokens}158\begin{threeparttable}159\input{tables/tab_top_name_tokens}160\begin{tablenotes}\footnotesize161\item Source: \texttt{results/resolver/top\_name\_tokens.csv} (\texttt{code/audit/a03\_resolver\_speccurve.py}), first twenty tokens. The token is the first word of at least four letters in the normalized project name of a mention without an extracted location (\Cref{sec:resolution_rule}); ``pct of token-keyed'' shares are over the \SPIDmentionsKeyedNameToken\ mentions and \SPIDprojectsKeyedNameToken\ projects keyed on a token.162\end{tablenotes}163\end{threeparttable}164\end{table}165166\begin{table}[H]167\centering\scriptsize168\caption{Over-merge indicators of the resolution key, by category}\label{tab:overmerge}169\begin{threeparttable}170\adjustbox{max width=\textwidth}{\input{tables/tab_overmerge}}171\begin{tablenotes}\footnotesize172\item Source: \texttt{results/resolver/overmerge\_by\_type.csv}. ``pct\_ge3\_names'' (``pct\_ge2\_names'') is the share of projects of the category whose mentions carry three (two) or more distinct project names; ``pct\_ge3\_partners\_among\_with\_partner'' is the share, among projects with at least one partner, whose mentions name three or more distinct first partners; ``pct\_multi\_all\_names\_distinct'' is the share of multi-mention projects in which every mention carries a different name. Three or more distinct partners in one M\&A project is an over-merge by construction; distinct names may be renamings of one initiative or distinct initiatives, which only annotation can separate.173\end{tablenotes}174\end{threeparttable}175\end{table}176177\begin{table}[H]178\centering\scriptsize179\caption{Field-level grounding of the structured fields in the source section, by form, item and field}\label{tab:grounding}180\begin{threeparttable}181\adjustbox{max width=\textwidth, max totalheight=0.84\textheight}{\input{tables/tab_grounding}}182\begin{tablenotes}\footnotesize183\item Source: \texttt{results/grounding/grounding\_by\_field\_form\_item.csv} (\texttt{code/audit/a02\_grounding.py}, all \SPIDmentions\ mentions joined to their stored section text; \SPIDgroundBootstrapReps\ bootstrap replicates clustered by section). A mention is ``grounded'' on a field when every element of the field is found in the section text after case folding (years as four-digit strings; locations, partners and technologies as literal strings; amounts in the usual renderings, e.g.\ ``1.5 billion'', ``1,500 million'', ``\$1.5B'', with one to three significant digits). Grounding measures transcription, not the correctness of the mention; the lower rates for locations and technologies reflect normalization by the model as well as invention; and for years and technologies the stored list may have been back-filled from the model's description (\Cref{sec:contract}).184\end{tablenotes}185\end{threeparttable}186\end{table}187188\section{Replication}\label{app:replication}189190\begin{enumerate}191\item Clone the repository at revision \texttt{2324b58} and create the Python environment from the lock files shipped with the paper (\texttt{.python-version} = \SPIDpythonVersion; \texttt{requirements.lock}, \SPIDrequirementsLockPackages\ packages from the master node, including DuckDB \SPIDduckdbVersion, pyarrow, lxml and sentence-transformers; \texttt{environment.md} records the hardware). The exhibit environment of the paper is pinned separately in \texttt{reproducibility/environment/}.192\item \texttt{python scripts/build\_universe.py} rebuilds \texttt{data/metadata/universe.json} from a \emph{current} download of the holdings and ticker files, which will not reproduce the October 2026 snapshot; the frozen artefacts used here are kept with the paper (\texttt{data/metadata/}, SHA-256 in \texttt{SHA256SUMS}) and must be used instead.193\item \texttt{python scripts/download\_filings.py --universe --rate 9} downloads the corpus (idempotent; about \SPIDrawGb~GB; \SPIDacqHours\ hours at two IP addresses in October 2026). The cluster orchestration used for the October 2026 build is in \texttt{scripts/cluster/}.194\item \texttt{python scripts/build\_database.py}, \texttt{parse\_filings.py}, \texttt{build\_embeddings.py}, \texttt{build\_factors.py} build the corpus layer; \texttt{export\_shard.py}/\texttt{merge\_shards.py} are needed only for a distributed build. The S\&P~500 10-K items of the June 2026 block cannot be rebuilt by this path (\Cref{sec:segmenters}).195\item In \texttt{project-db/}: \texttt{python -m spid pending} reports the sections to be extracted and the estimated cost; \texttt{python run\_full\_extract.py --workers \SPIDworkers} runs the extraction against the ledger (a re-run is not expected to return identical mentions; \Cref{sec:contract}); \texttt{python -m spid resolve graph embed analytics} builds the project layer (representative fields depend on tie order; \Cref{sec:resolution_rule}).196\item In the working-paper folder: \texttt{./run\_all.sh} regenerates every table, figure and inline number from \texttt{data/} and \texttt{results/} and runs the \SPIDtestsN\ checks of \texttt{tests/}; \texttt{./run\_all.sh --with-node} first re-runs \texttt{code/export\_stats.py} read-only on the master node, and \texttt{--with-audit} re-runs the Stage D audits of \texttt{code/audit/} (read-only connections, temporary tables only, seed \SPIDannSeed). \texttt{latexmk} in \texttt{paper/} compiles the manuscript.197\end{enumerate}198199\end{appendices}200