| 2 |
2 |
\section{The Project Construct and the Extraction Contract}\label{sec:construct} |
| 3 |
3 |
% ============================================================================ |
| 4 |
4 |
|
| 5 |
|
−\subsection{What counts as a project} |
|
5 |
+\subsection{What counts as a project}\label{sec:construct_def} |
| 6 |
6 |
|
| 7 |
|
−The unit of measurement is a \emph{distinct, identifiable, issuer-associated strategic initiative} involving a planned, announced, ongoing, completed, postponed or cancelled action: a plant expansion, a research program, a technology deployment, an AI initiative, a data-center build, a supply-chain transformation, an acquisition and its integration, a renewable-energy investment, and the other categories of the taxonomy. The database stores two tiers and, in its intended final form, five labels: |
|
7 |
+The unit of measurement is a \emph{distinct, identifiable, issuer-associated strategic initiative} involving a planned, announced, ongoing, completed, postponed or cancelled action: a plant expansion, a research program, a technology deployment, an AI initiative, a data-center build, a supply-chain transformation, an acquisition and its integration, a renewable-energy investment, and the other categories of the taxonomy. The database stores two tiers and, in its intended final form, six labels: |
| 8 |
8 |
|
| 9 |
9 |
\begin{itemize} |
| 10 |
10 |
\item \texttt{project\_mention}: a particular sourced statement about an initiative, in one section of one filing, with the extracted fields and the model's one-sentence description; |
| 11 |
11 |
\item \texttt{project}: a resolved initiative described by one or more mentions, carrying a stable identifier and a timeline; |
| 12 |
12 |
\item \texttt{generic\_strategy}: non-specific aspirations (``we continue to invest in innovation'', ``we may pursue acquisitions'') that the contract instructs the model to exclude and that the resolver never sees unless the model fails to exclude them; |
| 13 |
13 |
\item \texttt{historical\_or\_third\_party\_reference}: initiatives of a competitor, a customer or a former parent, mentioned in the issuer's filing but not attributable to the issuer; |
|
14 |
+\item \texttt{financing\_instrument}: share-repurchase programs, dividends, credit facilities, term loans, note offerings, at-the-market programs and commercial paper, which are corporate actions but not projects in the sense above; the taxonomy has no category for them, the gate word ``program'' admits them, and the prompt's ``any concrete initiative, investment, program'' does not exclude them; |
| 14 |
15 |
\item \texttt{uncertain\_candidate}: a plausible initiative without enough identity evidence (no name, location, counterparty or amount) to be counted. |
| 15 |
16 |
\end{itemize} |
| 16 |
17 |
|
| 17 |
|
−The current build implements the first two tiers directly. The third is enforced only through the prompt and the confidence threshold; the fourth and fifth exist as instructions and as a confidence score, not as stored labels. Promoting them to explicit columns of the mention table, filled by annotators and eventually by a classifier, is the first schema change proposed in \texttt{docs/project\_ontology.md}. |
|
18 |
+The current build implements the first two tiers directly. The third is enforced only through the prompt and the confidence threshold; the fourth, fifth and sixth exist as instructions and as a confidence score, not as stored labels. The financing class was added in this revision after a regular-expression pass over the stored mentions (\texttt{repurchase|buy-?back|dividend|credit facility|revolving|term loan|notes? (due|offering)|at-the-market|senior notes|commercial paper} on the project name and description) matched \SPIDfinMentions\ mentions, \SPIDfinMentionsPct\% of the total, carrying \SPIDfinAmountB~B of the \SPIDfinAmountDenomB~B USD of mention amounts; the match concentrates in Part~II Item~2 of the 10-Q (\SPIDfinUnregPct\% of its mentions, where issuer repurchases are tabled) and in 8-K bodies (\SPIDfinEightKPct\%), and by category in \texttt{capex\_program} (\SPIDfinCapexPct\% of its mentions), \texttt{cost\_reduction} (\SPIDfinCostPct\%) and \texttt{ma\_integration} (\SPIDfinMaPct\%). \Cref{sec:results} reports the category counts with and without this class. Promoting the labels to explicit columns of the mention table, filled by annotators and eventually by a classifier, is the first schema change proposed in \texttt{docs/project\_ontology.md}. |
| 18 |
19 |
|
| 19 |
20 |
\subsection{Taxonomy} |
| 20 |
21 |
|
| 21 |
|
−The SPID taxonomy has 21 categories (Table~\ref{tab:taxonomy} in Appendix~\ref{app:taxonomy}), defined in \texttt{spid/taxonomy.py} with a human-readable label and a set of lexical signals used by the rule-based extractor and by the candidate gate. The LLM extractor receives the 21 labels verbatim in its system prompt and must choose exactly one per project; a label outside the list is mapped back to the closest category by substring matching or, failing that, to \texttt{technology\_deployment}. The categories are not mutually exclusive in substance (an acquired plant is both \texttt{ma\_integration} and \texttt{plant\_construction}; a data center is also \texttt{infrastructure}), and the model's choice in such cases is a classification decision we have not yet audited. We document the taxonomy as it stands rather than redesign it: any extension would be versioned, with a crosswalk from old to new codes, so that counts published under the current version remain reproducible. |
|
22 |
+The SPID taxonomy has \SPIDtaxonomyN\ categories (\Cref{tab:taxonomy} in \Cref{app:taxonomy}), defined in \texttt{spid/taxonomy.py} with a human-readable label and a set of lexical signals used by the rule-based extractor and by the candidate gate. The LLM extractor receives the \SPIDtaxonomyN\ labels verbatim in its system prompt and must choose exactly one per project. A label outside the list is mapped back to a category by substring matching in a fixed order and, failing that, to \texttt{technology\_deployment}; an unrecognized status is mapped to \texttt{mentioned}. Neither fallback is logged, and the raw model output is not stored, so their frequency can only be bounded from the stored fields: \SPIDtechDeployMentionedNoSignal\ of the \SPIDtechDeployMentionedN\ mentions that carry both default values have no lexical signal of any category in their name or description, a lower bound on silently defaulted mentions, and the lexical signal of the assigned category is present in the name or description of \SPIDtypeSignalMaPct\% of \texttt{ma\_integration} mentions but only \SPIDtypeSignalTechDeployPct\% of \texttt{technology\_deployment} mentions (\texttt{results/grounding/fallback\_bounds.json}). The categories are not mutually exclusive in substance (an acquired plant is both \texttt{ma\_integration} and \texttt{plant\_construction}; a data center is also \texttt{infrastructure}), and the model's choice in such cases is a classification decision we have not yet audited against human labels. We document the taxonomy as it stands rather than redesign it: any extension would be versioned, with a crosswalk from old to new codes, so that counts published under the current version remain reproducible. |
| 22 |
23 |
|
| 23 |
|
−\subsection{Candidate gating and focus windows} |
|
24 |
+\subsection{Candidate gating and focus windows}\label{sec:focus} |
| 24 |
25 |
|
| 25 |
|
−A section reaches the model only if it contains at least 30 words and matches a broad lexical gate (project, initiative, program, invest, expan-, construct, build, launch, develop, deploy, implement, acqui-, partner, facilit-, capacity, capital, migrat-, transform, pipeline, plant, data center, automat-, sustainab-, renewable, restructur-; see Appendix~\ref{app:prompt}). The gate is deliberately permissive---it exists to avoid paying for sections that cannot contain a project---and its false-negative rate is unknown; sampling rejected sections to estimate it is part of the validation plan. For sections longer than 9{,}000 characters, the extractor keeps windows of about 600 characters around each gate hit (merged when they overlap) up to a budget of roughly 9{,}000--12{,}600 characters, so that the cost per call is bounded regardless of section length. This ``focus'' step is the main source of \emph{silent truncation} in the pipeline: a project described far from any gate word, or beyond the budget in a very long MD\&A, is never shown to the model. The 10-K MD\&A sections submitted have a median length of 9{,}905 words (roughly 60{,}000 characters), so truncation is the rule rather than the exception for annual reports, and the recall of the pipeline on long sections is an open empirical question. |
|
26 |
+A section is written to the extraction ledger if it contains at least \SPIDminWords\ words; it reaches the model only if it also matches a broad lexical gate (the case-insensitive regular expression reproduced from the code in \Cref{app:prompt}: project, initiative, program, invest, expan-, construct, build, launch, develop, deploy, implement, acqui-, partner, facilit-, capacity, capital, migrat-, transform, pipeline, plant, data center, automat-, sustainab-, renewable, restructur-). The gate is applied inside the extractor, which returns an empty list \emph{before any API call} when it fails, and the pipeline writes that result to the ledger as ``extracted with zero mentions'' exactly as it writes a model abstention. The ledger therefore counts \SPIDledgerTotal\ rows but only \SPIDgatePassTotal\ calls; \SPIDgateRejectedSections\ rows (\SPIDgateRejectedPct\%) were never sent, and no section with a stored mention fails the gate. The gate is deliberately permissive---it exists to avoid paying for sections that cannot contain a project---and its false-negative rate cannot be estimated from the ledger because gate rejections and abstentions are recorded identically; the annotation frame of \Cref{sec:validation} draws gate-rejected sections explicitly for that purpose. |
| 26 |
27 |
|
| 27 |
|
−\subsection{The extraction contract} |
|
28 |
+For sections longer than \SPIDfocusEmitBudget\ characters, the extractor collects windows of \SPIDfocusWindowBefore\ characters before and \SPIDfocusWindowAfter\ characters after each gate hit, in document order, merging overlaps, stops collecting at \SPIDfocusCollectBudget\ characters of source text, emits at most \SPIDfocusEmitBudget\ characters, and cuts the user message at \SPIDuserMessageCap\ characters (a limit never reached: \SPIDmsgTruncatedN\ messages were cut). The function is deterministic, so what the model was shown can be reconstructed for every ledgered section without a model call, and this revision does so (\texttt{results/focus/}). \SPIDfocusOverBudgetSections\ ledgered sections (\SPIDfocusOverBudgetSectionsPct\%) and \SPIDfocusOverBudgetCalls\ of the \SPIDgatePassTotal\ calls (\SPIDfocusOverBudgetCallsPct\%) exceed the budget; for them the mean fraction of the text shown is \SPIDfocusMeanShownOverBudgetPct\%. The submitted 10-K MD\&A sections (\SPIDmdnaN\ of them) have a median length of \SPIDmdnaMedianWords\ words or \SPIDmdnaMedianChars\ characters; the model saw a median \SPIDmdnaShownMedianPct\% of each (tenth percentile \SPIDmdnaShownPTenPct\%, ninetieth \SPIDmdnaShownPNinetyPct\%), the last character shown lies at \SPIDmdnaLastShownMedianPct\% of the text in the median section, \SPIDmdnaShownLtTwentyFivePct\% of these sections were shown for less than a quarter, and the median share of gate hits inside the shown windows is \SPIDmdnaHitsShownMedianPct\%. The medians are \SPIDbusinessShownMedianPct\% for the 10-K business item, \SPIDriskShownMedianPct\% for risk factors, \SPIDtenQmdnaShownMedianPct\% for the 10-Q MD\&A and \SPIDtenQfinShownMedianPct\% for the 10-Q financial-statement notes, whereas \SPIDeightKWholePct\% of 8-K bodies are shown whole. Because the windows are taken in document order and the budget is reached early, the liquidity and capital-resources discussion that closes a long MD\&A is structurally under-represented: only \SPIDcapexVocabShownMdnaPct\% of the occurrences of ``capital expenditure'', ``liquidity and capital resources'' or ``commitment'' in over-budget 10-K MD\&As fall inside a shown window (\SPIDcapexVocabShownBusinessPct\% in the business item, \SPIDcapexVocabShownTenQmdnaPct\% in the 10-Q MD\&A). |
| 28 |
29 |
|
| 29 |
|
−The LLM call is a chat completion with a fixed system prompt, the section name and the focused text as user message, temperature~0, JSON-object output mode and a 2{,}000-token completion limit. The prompt (Appendix~\ref{app:prompt}) instructs the model to act as a financial analyst extracting corporate projects, lists the 21 allowed types, and returns a JSON object with one entry per project and the following fields: \texttt{project\_name}, \texttt{project\_type}, \texttt{description} (one sentence grounded in the text), \texttt{objective}, \texttt{status} (planned, in\_progress, completed, mentioned), \texttt{amount\_usd}, \texttt{locations}, \texttt{technologies}, \texttt{partners}, \texttt{benefits}, \texttt{risks}, \texttt{years} and \texttt{confidence}. Four rules in the prompt define the construct operationally: extract only real initiatives, not boilerplate or hypotheticals; return an empty list when no concrete project is described; do not invent facts---numbers and locations must appear in the text; prefer fewer high-quality projects. Output is post-processed deterministically: amounts are coerced to a float in USD (with the raw string retained in \texttt{amount\_raw}), list fields are truncated to eight items of at most 120 characters, years are parsed as four-digit integers, status is normalized, and mentions with confidence below 0.45 are dropped. The mention identifier is a SHA-1 of the accession number, section identifier, type and project name, so that re-running the extractor on the same section with the same output overwrites rather than duplicates. |
|
30 |
+Two consequences follow. First, \SPIDmentionsFromLtTwentyFive\ of the \SPIDledgerMentionsReturned\ mentions returned by the model (\SPIDmentionsFromLtTwentyFivePct\%) come from sections of which less than a quarter was shown---\SPIDmentionsFromLtTwentyFiveTenK\% of 10-K mentions, \SPIDmentionsFromLtTwentyFiveTenQ\% of 10-Q mentions and \SPIDmentionsFromLtTwentyFiveEightK\% of 8-K mentions---so most of the database rests on partial readings of its sources. Second, the yield is bounded by the budget rather than by the text: the number of mentions per 10-K MD\&A rises with section length from about \SPIDplateauLow\ to \SPIDplateauHigh\ up to roughly \SPIDplateauKchars\ characters and stays between \SPIDplateauRange\ beyond, about \SPIDmentionsPerTenKShownChars\ mentions per ten thousand shown characters regardless of length. A deterministic recall bound makes the same point from the other side: running the rule-based extractor of the code base on the full text and on the focused text of the over-budget sections, the focused text retains \SPIDrulesFocusRecovered\ of \SPIDrulesFocusTotal\ rule-based mentions (\SPIDrulesFocusRecoveredPct\%; \SPIDrulesFocusMdnaPct\% in the 10-K MD\&A, \SPIDrulesFocusBusinessPct\% in the business item, \SPIDrulesFocusTenQmdnaPct\% in the 10-Q MD\&A, \SPIDrulesFocusEightKPct\% in 8-K bodies), an upper bound on what any extractor can see through the windows (\Cref{sec:validation}). A separate concern raised in review---10-K MD\&As incorporated by reference and therefore too short to be submitted---turns out to be small: \SPIDshortMdnaN\ of \SPIDshortMdnaDenom\ parsed 10-K MD\&A sections (\SPIDshortMdnaPct\%) are under \SPIDminWords\ words, and \SPIDshortMdnaIncorporatedN\ are under 300 words with an incorporation-by-reference clause. Storing the focus spans per call is part of the proposed schema. |
| 30 |
31 |
|
| 31 |
|
−What the contract does \emph{not} guarantee should be equally explicit. The ``description'' is a model paraphrase, not a verbatim quote, and the character span of the supporting passage is not stored; grounding is therefore verifiable by a reader who opens the section, but not mechanically checkable. The model may extract a counterparty's initiative as the issuer's (the third-party label above). It may split one initiative into several entries when a section describes phases, or merge phases into one. It receives no information about the issuer other than the text, which protects against hallucinated background knowledge but also prevents it from recognizing a subsidiary name. And the same section is seen once; a project described across two sections of the same filing yields two mentions with distinct identifiers. |
|
32 |
+\subsection{The extraction contract as implemented}\label{sec:contract} |
| 32 |
33 |
|
| 33 |
|
−\subsection{Cost, throughput and the extraction ledger} |
|
34 |
+The LLM call is a chat completion with a fixed system prompt, the section name and the focused text as user message, temperature~0, the JSON-object response format and a \SPIDcompletionTokens-token completion limit. The response format guarantees syntactically valid JSON; it does not enforce a schema. The field list lives in the prompt (\Cref{app:prompt}): the model is instructed to act as a financial analyst extracting corporate projects, is given the \SPIDtaxonomyN\ allowed types, and is asked for a JSON object with one entry per project and the fields \texttt{project\_name}, \texttt{project\_type}, \texttt{description} (one sentence grounded in the text), \texttt{objective}, \texttt{status} (planned, in\_progress, completed, mentioned), \texttt{amount\_usd}, \texttt{locations}, \texttt{technologies}, \texttt{partners}, \texttt{benefits}, \texttt{risks}, \texttt{years} and \texttt{confidence}. Four rules in the prompt define the construct operationally: extract only real initiatives, not boilerplate or hypotheticals; return an empty list when no concrete project is described; do not invent facts---numbers and locations must appear in the text; prefer fewer high-quality projects. The output is then normalized deterministically, and several steps of that normalization were undocumented in the earlier version of this paper: |
| 34 |
35 |
|
| 35 |
|
−The October 2026 run submitted 968{,}134 sections in about twelve hours of effective extraction (48 concurrent calls, 27--36 sections per second), at a cost of roughly 775~USD for the full universe at current \texttt{gpt-4o-mini} prices (about 0.0008~USD per section). Every submitted section is written to an \texttt{extracted\_sections} ledger (section, accession, backend, number of mentions, timestamp), which makes the step resumable and prevents double billing. The ledger also protects against a failure mode encountered during the run: when the API key's credit balance was exhausted, the extractor's retry logic returned empty results that were recorded as ``extracted with zero mentions'' for 149{,}352 sections before the problem was detected. Those rows were removed from the ledger using the timestamp of the first quota error and the sections were re-submitted; the final ledger has no section processed during the outage. The episode is recorded in the research log because it illustrates a general point: a ledger that cannot distinguish ``no project'' from ``call failed'' is not sufficient, and an explicit \texttt{call\_status} column is now part of the proposed schema. |
|
36 |
+\begin{itemize} |
|
37 |
+\item the amount is coerced to a float in USD; \texttt{amount\_raw} is \emph{not} the string from the filing but a re-formatting of that float (``\$1,500,000,000''), left empty when the amount is zero, so currency, scale and original wording are not retained (\SPIDamountRawDeviations\ mentions with a zero amount have an empty \texttt{amount\_raw}; \SPIDamountNegative\ carry a negative amount); |
|
38 |
+\item when the model returns no \texttt{years} or no \texttt{technologies}, both are back-filled by regular expressions applied to the model's own one-sentence description rather than to the source text; the stored lists equal that regex output for \SPIDyearsRegexEqualPct\% of mentions with years and \SPIDtechRegexEqualPct\% of mentions with technologies, upper bounds on the share that was back-filled; |
|
39 |
+\item a missing or non-numeric \texttt{confidence} is set to \SPIDconfDefault, which passes the \SPIDconfThreshold\ threshold; \SPIDconfExactDefault\ stored mentions carry exactly that value (\SPIDconfExactDefaultJune\ from June, \SPIDconfExactDefaultOctober\ from October) and cannot be separated from genuine model confidences of \SPIDconfDefault; |
|
40 |
+\item an out-of-vocabulary type is mapped to \texttt{technology\_deployment} and an unknown status to \texttt{mentioned} (\Cref{sec:construct_def}); |
|
41 |
+\item list fields are truncated to \SPIDlistItemsMax\ items of at most \SPIDlistItemChars\ characters, years are parsed as four-digit integers, and mentions with confidence below \SPIDconfThreshold\ are dropped. |
|
42 |
+\end{itemize} |
|
43 |
+ |
|
44 |
+The mention identifier is a SHA-1 hash of the accession number, the section identifier, the type and the first \SPIDidNameChars\ characters of the project name, and mentions are written with an insert-or-replace statement. Two same-type projects whose names share their first \SPIDidNameChars\ characters in one section therefore overwrite each other after being counted in the ledger, which is why the ledger sum of \SPIDledgerMentionsReturned\ mentions returned by the model exceeds the \SPIDmentions\ stored mentions by \SPIDcollisionMentions\ (\SPIDledgerGapByForm) over \SPIDcollisionSections\ sections (\Cref{tab:sections}). Every count in \Cref{sec:results} uses the stored mentions. An index or the full name in the hash is part of the proposed schema. |
|
45 |
+ |
|
46 |
+What the contract does \emph{not} guarantee should be equally explicit. The ``description'' is a model paraphrase, not a verbatim quote, and the character span of the supporting passage is not stored; whether the description is faithful to the passage can only be judged by a reader who opens the section. The structured fields, by contrast, are literal tokens whose presence in the stored section text is a string search, and the earlier statement that grounding was ``not mechanically checkable'' was wrong: \Cref{sec:validation} reports the containment rate of every year, partner, location, technology tag and amount for all \SPIDmentions\ mentions. The model may extract a counterparty's initiative as the issuer's (the third-party label above). It may split one initiative into several entries when a section describes phases, or merge phases into one. It receives no information about the issuer other than the text, which protects against hallucinated background knowledge but also prevents it from recognizing a subsidiary name. And the same section is seen once; a project described across two sections of the same filing yields two mentions with distinct identifiers. |
|
47 |
+ |
|
48 |
+The instrument is re-runnable and ledgered, not deterministic. The calls used temperature~0 without a \texttt{seed} parameter, the \texttt{system\_fingerprint} returned by the API was not stored, and the provider does not guarantee identical outputs across calls or model builds at temperature~0; a re-run can return different mentions. What is reproducible from the archived materials is the mapping from the stored mentions to every table and number of this paper. The stability of the output under re-submission of the same sections, under a paraphrased prompt and under a substitute model has not been measured: a protocol over a few hundred sections is specified in \Cref{sec:validation} and requires new model calls that were not authorised for this revision. |
|
49 |
+ |
|
50 |
+\subsection{Cost, throughput and the extraction ledger}\label{sec:ledger} |
|
51 |
+ |
|
52 |
+Every ledgered section is written to the \texttt{extracted\_sections} table (section, accession, backend, number of mentions, timestamp), which makes the step resumable and prevents double billing. Restated on calls rather than rows, the October 2026 run wrote \SPIDoctoberRows\ rows of which \SPIDoctoberCalls\ were calls, and the June block \SPIDbackfilledRows\ rows of which \SPIDjuneCalls\ were calls; the model returned at least one project for \SPIDproductiveShareCalls\% of calls (\SPIDproductiveShareLedger\% of rows; \SPIDjuneProductiveShareCalls\% and \SPIDoctoberProductiveShareCalls\% by run), \SPIDmentionsPerCall\ mentions per call (\SPIDmentionsPerLedgerSection\ per row). At the authors' recorded total of about \SPIDtotalCostUsd~USD for the October run at the then-current \texttt{gpt-4o-mini} prices, the cost is about \SPIDusdPerCall~USD per call (\SPIDusdPerOctoberRow~USD per ledger row, the figure the earlier version reported ``per section''). The run was executed with \SPIDworkers\ concurrent workers; the ledger timestamps span \SPIDoctoberWallClockHours\ hours of wall-clock time (\SPIDoctoberFirstFlush\ to \SPIDoctoberLastFlush), of which \SPIDoutageHours\ hours are the largest gap, so the effective throughput over \SPIDoctoberEffectiveHours\ hours was \SPIDoctoberRowsPerSecondEffective\ rows or \SPIDoctoberCallsPerSecondEffective\ calls per second; the ``twelve hours'' and ``27--36 sections per second'' of the earlier version were mutually inconsistent and are withdrawn. |
|
53 |
+ |
|
54 |
+The ledger also records a failure mode encountered during the run, which this revision has reconciled against the run log rather than reported from memory. When the API key's credit balance was exhausted (log window \SPIDoutageWindowStart\ to \SPIDoutageWindowEnd), the extractor's retry logic returned empty results that were recorded as ``extracted with zero mentions'': the log carries \SPIDllmFailedRetryableHttpFourTwoNineFivexx\ retryable HTTP errors and \SPIDllmFailedConnectionError\ connection resets in that window, batches \SPIDoutageZeroBatchRange\ (\SPIDoutageZeroBatchWindow) returned no mention at all, and \SPIDoutageRowsRemoved\ rows were removed from the ledger---a number that reconciles exactly with the log as the sum of sections reported complete (\SPIDlogExtractionCompleteSum) minus the sections pending when the run was restarted (\SPIDlogPendingSecondStart). The final ledger has no row inside the largest gap (\SPIDoutageLargestGapStart\ to \SPIDoutageLargestGapEnd); \SPIDoutageSurvivingRows\ productive rows (\SPIDoutageSurvivingMentions\ mentions) stamped in the first quarter of an hour of the window survived because their calls had succeeded. Two residues remain. First, the extractor also returns an empty list after \SPIDretries\ failed attempts on any other error, and the log shows \SPIDllmFailedJsonDecodeError\ JSON-decode failures outside the outage (\SPIDjsonFailBeforeOutage\ before, \SPIDjsonFailAfterOutage\ after; \SPIDjuneLlmCallFailed\ in the June run), each ledgered as ``no project''; the earlier version reported one. Second, the first batch after the restart (\SPIDresumeBatchWindow; \SPIDresumeBatchSections\ sections of \SPIDresumeBatchCiks\ issuers, \SPIDresumeBatchCalls\ calls) returned \SPIDresumeBatchMentions\ mentions with no logged failure: \SPIDresumeBatchProductive\ productive sections against about \SPIDresumeBatchExpectedProductive\ expected at the form-by-item rates of the rest of the run, with \SPIDresumeBatchZeroSharePct\% zero-mention calls in its last minute. The most likely reading is a block of empty answers returned with a success status while the quota was being restored; those sections are ledgered as ``no project'' and were not re-run. A re-submission of the \SPIDresumeBatchCalls\ gate-passing sections of that batch (about \SPIDresumeBatchCalls\ calls) was requested during the review and is not granted in this revision, so the batch stays flagged as suspect in \Cref{tab:evidence} and the issuer list is published with the audit outputs. The general point stands: a ledger that cannot distinguish ``no project'' from ``call failed'' or ``empty answer'' is not sufficient, and an explicit \texttt{call\_status} column, together with the raw response, is part of the proposed schema. |