@pipeworx/mcp-edgar 0.3.9 → 0.3.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/package.json +3 -3
- package/server.json +1 -1
- package/src/index.ts +97 -11
- package/src/server.ts +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The Securities and Exchange Commission's filings database. Every public company in the US files here, every filing is timestamped and immutable, and every disclosure (revenue, debt, risk factors, executive compensation, M&A activity, insider trading) is structured for machine retrieval. Free and authoritative.
|
|
4
4
|
|
|
5
|
-
Part of [Pipeworx](https://pipeworx.io) — an MCP gateway connecting AI agents to
|
|
5
|
+
Part of [Pipeworx](https://pipeworx.io) — an MCP gateway connecting AI agents to 1819+ live data sources. This is an independent, unofficial integration — not affiliated with, endorsed by, or published by the upstream provider.
|
|
6
6
|
|
|
7
7
|
## Why this matters for AI agents
|
|
8
8
|
|
|
@@ -106,7 +106,7 @@ directly, instead of just this one's:
|
|
|
106
106
|
}
|
|
107
107
|
```
|
|
108
108
|
|
|
109
|
-
Both URLs reach the same gateway and the same
|
|
109
|
+
Both URLs reach the same gateway and the same 1819+ data sources. The
|
|
110
110
|
only difference is which pack's tools are listed **directly**; `ask_pipeworx`
|
|
111
111
|
reaches all of them from either one.
|
|
112
112
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pipeworx/mcp-edgar",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.11",
|
|
4
4
|
"description": "EDGAR MCP — SEC EDGAR public APIs (free, no auth)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"@cloudflare/workers-types": "^4.20260405.1"
|
|
27
27
|
},
|
|
28
28
|
"pipeworx": {
|
|
29
|
-
"sourceHash": "v1-
|
|
30
|
-
"sourceCommit": "
|
|
29
|
+
"sourceHash": "v1-7ce3b2ab39a6713c682f44a33fe013a7e07b55298b5e01883e16f33b0d1ab1d4",
|
|
30
|
+
"sourceCommit": "a03f96ed672b8c149593c64ecbf30280cabf084c"
|
|
31
31
|
}
|
|
32
32
|
}
|
package/server.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "io.github.pipeworx-io/edgar",
|
|
4
4
|
"title": "Edgar",
|
|
5
5
|
"description": "EDGAR MCP — SEC EDGAR public APIs (free, no auth)",
|
|
6
|
-
"version": "0.3.
|
|
6
|
+
"version": "0.3.11",
|
|
7
7
|
"websiteUrl": "https://pipeworx.io/packs/edgar",
|
|
8
8
|
"repository": {
|
|
9
9
|
"url": "https://github.com/pipeworx-io/mcp-edgar",
|
package/src/index.ts
CHANGED
|
@@ -699,6 +699,16 @@ const normalize = (s: string): string =>
|
|
|
699
699
|
* exact (4) > prefix (3) > whole-word (2) > substring (1). Ties break by shortest
|
|
700
700
|
* name — the primary entity (e.g. "Apple Inc." over "Apple Hospitality REIT").
|
|
701
701
|
* Returns only items that match at all, best first. Pure (no I/O).
|
|
702
|
+
*
|
|
703
|
+
* `prefix` requires a WORD BOUNDARY (`n.startsWith(q + ' ')`), not a bare
|
|
704
|
+
* `startsWith`. A bare `startsWith` let "ZOOM" claim "ZOOMCAR HOLDINGS INC" at
|
|
705
|
+
* the SAME tier as "Apple" claiming "APPLE INC." — "Zoomcar" is a different
|
|
706
|
+
* word that happens to begin with the same letters, not the brand name plus a
|
|
707
|
+
* corporate-form suffix. That conflation is what sent resolve_entity("Zoom")
|
|
708
|
+
* to Zoomcar and resolve_entity("Audi") to AudioEye Inc (fleet #2776's
|
|
709
|
+
* mis-resolution fixture) — both now correctly fall through to the weaker
|
|
710
|
+
* `substring` tier instead of tying with a genuine word-boundary prefix hit
|
|
711
|
+
* like "Palantir" -> "Palantir Technologies Inc." (fleet #3100).
|
|
702
712
|
*/
|
|
703
713
|
function rankMatches<T>(
|
|
704
714
|
query: string,
|
|
@@ -714,7 +724,7 @@ function rankMatches<T>(
|
|
|
714
724
|
let kind: MatchKind | null = null;
|
|
715
725
|
let score = 0;
|
|
716
726
|
if (n === q) { kind = 'exact'; score = 4; }
|
|
717
|
-
else if (n.startsWith(q)) { kind = 'prefix'; score = 3; }
|
|
727
|
+
else if (n.startsWith(`${q} `)) { kind = 'prefix'; score = 3; }
|
|
718
728
|
else if (n.includes(` ${q} `) || n.endsWith(` ${q}`)) { kind = 'word'; score = 2; }
|
|
719
729
|
else if (n.includes(q)) { kind = 'substring'; score = 1; }
|
|
720
730
|
if (kind) scored.push({ item, kind, score, len: name.length });
|
|
@@ -731,7 +741,15 @@ interface SecEntity {
|
|
|
731
741
|
cik_padded: string;
|
|
732
742
|
company_name: string;
|
|
733
743
|
matched_by: 'ticker' | 'company_name';
|
|
734
|
-
|
|
744
|
+
/**
|
|
745
|
+
* The `rankMatches` kind that won, when `matched_by` is `'company_name'`
|
|
746
|
+
* (a ticker hit has no kind — it did not go through ranking at all). Lets a
|
|
747
|
+
* caller tell a word-boundary PREFIX hit ("Palantir" -> "Palantir
|
|
748
|
+
* Technologies Inc.") from a weaker `word`/`substring` guess, which
|
|
749
|
+
* `matched_by: 'company_name'` alone cannot (fleet #3100).
|
|
750
|
+
*/
|
|
751
|
+
matched_kind?: MatchKind;
|
|
752
|
+
alternatives?: { ticker: string; company_name: string; cik: string; kind: MatchKind }[];
|
|
735
753
|
}
|
|
736
754
|
|
|
737
755
|
const SEC_TICKERS_URL = 'https://www.sec.gov/files/company_tickers.json';
|
|
@@ -767,10 +785,12 @@ async function resolveSecEntity(
|
|
|
767
785
|
const ranked = rankMatches(query, rows, (r) => r.title);
|
|
768
786
|
if (ranked.length) {
|
|
769
787
|
const best = toEntity(ranked[0].item, 'company_name');
|
|
788
|
+
best.matched_kind = ranked[0].kind;
|
|
770
789
|
const alts = ranked.slice(1, 4).map((m) => ({
|
|
771
790
|
ticker: m.item.ticker,
|
|
772
791
|
company_name: m.item.title,
|
|
773
792
|
cik: String(m.item.cik_str),
|
|
793
|
+
kind: m.kind,
|
|
774
794
|
}));
|
|
775
795
|
if (alts.length) best.alternatives = alts;
|
|
776
796
|
return best;
|
|
@@ -1238,7 +1258,7 @@ const tools: McpToolExport['tools'] = [
|
|
|
1238
1258
|
concept: {
|
|
1239
1259
|
type: 'string',
|
|
1240
1260
|
description:
|
|
1241
|
-
'REQUIRED (alias `metric`). Metric name. Common: "Revenue" / "Revenues", "NetIncomeLoss", "Cash", "Assets", "Liabilities", "StockholdersEquity", "EarningsPerShareDiluted", "LongTermDebt".',
|
|
1261
|
+
'REQUIRED (alias `metric`). Metric name. Common: "Revenue" / "Revenues", "NetIncomeLoss", "Cash", "Assets", "Liabilities", "StockholdersEquity", "EarningsPerShareDiluted", "LongTermDebt", "SharesOutstanding" (newest cover-page count, dei), "Capex", "OperatingCashFlow", "ResearchAndDevelopment", "SGA", "CostOfRevenue", "DilutedShares", "PublicFloat". Exact us-gaap or dei tag names also work.',
|
|
1242
1262
|
},
|
|
1243
1263
|
period: {
|
|
1244
1264
|
type: 'string',
|
|
@@ -3128,6 +3148,17 @@ async function companyFacts(cikOrTicker: string) {
|
|
|
3128
3148
|
// Anything not in the table still falls through to [concept] (the bare
|
|
3129
3149
|
// literal), so we don't regress for niche concepts not yet observed in
|
|
3130
3150
|
// failures.
|
|
3151
|
+
// Cover-page tags live in the `dei` taxonomy, not us-gaap. Until 2026-10-16
|
|
3152
|
+
// every candidate was fetched under /us-gaap/, so the dei tag listed below for
|
|
3153
|
+
// "shares outstanding" 404'd on every filer and
|
|
3154
|
+
// edgar_company_concept({concept:"EntityCommonStockSharesOutstanding"}) told
|
|
3155
|
+
// callers "this filer reports no XBRL tag matching ..." for Tesla, which has 67
|
|
3156
|
+
// such facts (latest 3,949,547,394 at 2026-07-16). A report built on that
|
|
3157
|
+
// answer took the share count from a stale 10-Q cover instead and was off 5%
|
|
3158
|
+
// on every per-share number. Resolve the namespace per TAG, not per lookup.
|
|
3159
|
+
const DEI_TAGS = new Set(['EntityCommonStockSharesOutstanding', 'EntityPublicFloat']);
|
|
3160
|
+
const namespaceForTag = (defaultNs: string, tag: string): string => (DEI_TAGS.has(tag) ? 'dei' : defaultNs);
|
|
3161
|
+
|
|
3131
3162
|
const CONCEPT_CANDIDATES: Record<string, string[]> = {
|
|
3132
3163
|
// ── friendly names ────────────────────────────────────────────────
|
|
3133
3164
|
revenue: ['RevenueFromContractWithCustomerExcludingAssessedTax', 'Revenues', 'SalesRevenueNet'],
|
|
@@ -3145,6 +3176,31 @@ const CONCEPT_CANDIDATES: Record<string, string[]> = {
|
|
|
3145
3176
|
sharesoutstanding: ['CommonStockSharesOutstanding', 'EntityCommonStockSharesOutstanding', 'CommonStockSharesIssued'],
|
|
3146
3177
|
commonsharesoutstanding: ['CommonStockSharesOutstanding', 'EntityCommonStockSharesOutstanding', 'CommonStockSharesIssued'],
|
|
3147
3178
|
commonstocksharesoutstanding: ['CommonStockSharesOutstanding', 'EntityCommonStockSharesOutstanding'],
|
|
3179
|
+
// The cash-flow and expense lines an equity model needs. Measured 2026-10-16:
|
|
3180
|
+
// a routed "Tesla capex Q2 2026" question reached this tool as
|
|
3181
|
+
// concept:"CapitalExpenditures", which no filer tags, and the answer was
|
|
3182
|
+
// "reports no matching XBRL tag" — a miss on a figure every 10-Q carries as
|
|
3183
|
+
// PaymentsToAcquirePropertyPlantAndEquipment. The report that asked went to a
|
|
3184
|
+
// third-party site for it instead.
|
|
3185
|
+
capex: ['PaymentsToAcquirePropertyPlantAndEquipment', 'PaymentsToAcquireProductiveAssets', 'PaymentsForCapitalImprovements'],
|
|
3186
|
+
capitalexpenditure: ['PaymentsToAcquirePropertyPlantAndEquipment', 'PaymentsToAcquireProductiveAssets', 'PaymentsForCapitalImprovements'],
|
|
3187
|
+
capitalexpenditures: ['PaymentsToAcquirePropertyPlantAndEquipment', 'PaymentsToAcquireProductiveAssets', 'PaymentsForCapitalImprovements'],
|
|
3188
|
+
operatingcashflow: ['NetCashProvidedByUsedInOperatingActivities', 'NetCashProvidedByUsedInOperatingActivitiesContinuingOperations'],
|
|
3189
|
+
cashfromoperations: ['NetCashProvidedByUsedInOperatingActivities', 'NetCashProvidedByUsedInOperatingActivitiesContinuingOperations'],
|
|
3190
|
+
netcashfromoperatingactivities: ['NetCashProvidedByUsedInOperatingActivities', 'NetCashProvidedByUsedInOperatingActivitiesContinuingOperations'],
|
|
3191
|
+
netcashprovidedbyoperatingactivities: ['NetCashProvidedByUsedInOperatingActivities', 'NetCashProvidedByUsedInOperatingActivitiesContinuingOperations'],
|
|
3192
|
+
researchanddevelopment: ['ResearchAndDevelopmentExpense', 'ResearchAndDevelopmentExpenseExcludingAcquiredInProcessCost'],
|
|
3193
|
+
researchanddevelopmentexpense: ['ResearchAndDevelopmentExpense', 'ResearchAndDevelopmentExpenseExcludingAcquiredInProcessCost'],
|
|
3194
|
+
sga: ['SellingGeneralAndAdministrativeExpense'],
|
|
3195
|
+
sellinggeneralandadministrative: ['SellingGeneralAndAdministrativeExpense'],
|
|
3196
|
+
costofrevenue: ['CostOfRevenue', 'CostOfGoodsAndServicesSold', 'CostOfGoodsSold'],
|
|
3197
|
+
costofgoodssold: ['CostOfGoodsAndServicesSold', 'CostOfGoodsSold', 'CostOfRevenue'],
|
|
3198
|
+
cogs: ['CostOfGoodsAndServicesSold', 'CostOfGoodsSold', 'CostOfRevenue'],
|
|
3199
|
+
dilutedshares: ['WeightedAverageNumberOfDilutedSharesOutstanding'],
|
|
3200
|
+
weightedaveragedilutedshares: ['WeightedAverageNumberOfDilutedSharesOutstanding'],
|
|
3201
|
+
basicshares: ['WeightedAverageNumberOfSharesOutstandingBasic'],
|
|
3202
|
+
weightedaveragebasicshares: ['WeightedAverageNumberOfSharesOutstandingBasic'],
|
|
3203
|
+
publicfloat: ['EntityPublicFloat'],
|
|
3148
3204
|
cash: [
|
|
3149
3205
|
'CashAndCashEquivalentsAtCarryingValue',
|
|
3150
3206
|
'Cash',
|
|
@@ -3399,7 +3455,7 @@ async function companyConcept(
|
|
|
3399
3455
|
const tryNamespace = async (ns: string, tags: string[]) => {
|
|
3400
3456
|
for (const candidate of tags) {
|
|
3401
3457
|
const r = await pwFetch(
|
|
3402
|
-
`${DATA_BASE}/api/xbrl/companyconcept/CIK${paddedCik}/${ns}/${encodeURIComponent(candidate)}.json`,
|
|
3458
|
+
`${DATA_BASE}/api/xbrl/companyconcept/CIK${paddedCik}/${namespaceForTag(ns, candidate)}/${encodeURIComponent(candidate)}.json`,
|
|
3403
3459
|
{ headers: SEC_HEADERS },
|
|
3404
3460
|
);
|
|
3405
3461
|
if (!r.ok) { lastStatus = r.status; continue; }
|
|
@@ -3438,12 +3494,18 @@ async function companyConcept(
|
|
|
3438
3494
|
if (!factsRes.ok) {
|
|
3439
3495
|
lastStatus = factsRes.status;
|
|
3440
3496
|
} else if (tokens.length) {
|
|
3441
|
-
|
|
3497
|
+
type FactsNs = Record<string, { label?: string; description?: string; units: Record<string, ConceptDoc['units'][string]> }>;
|
|
3498
|
+
const facts = (await factsRes.json()) as { entityName?: string; facts?: { 'us-gaap'?: FactsNs; dei?: FactsNs } };
|
|
3442
3499
|
resolvedEntityName = facts.entityName ?? '';
|
|
3443
|
-
|
|
3500
|
+
// Scan dei too: cover-page facts (shares outstanding, public float) are
|
|
3501
|
+
// reported there and nowhere in us-gaap for many filers.
|
|
3502
|
+
const scanNamespaces: [string, FactsNs][] = [
|
|
3503
|
+
['us-gaap', facts.facts?.['us-gaap'] ?? {}],
|
|
3504
|
+
['dei', facts.facts?.dei ?? {}],
|
|
3505
|
+
];
|
|
3444
3506
|
const FLOW = /^(ProceedsFrom|RepaymentsOf|PaymentsOf|IncreaseDecrease|AmortizationOf|Gain|Loss)/;
|
|
3445
3507
|
const matches: { isFlow: boolean; latestEnd: string; doc: ConceptDoc }[] = [];
|
|
3446
|
-
for (const [tag, entry] of Object.entries(
|
|
3508
|
+
for (const [scanNs, nsFacts] of scanNamespaces) for (const [tag, entry] of Object.entries(nsFacts)) {
|
|
3447
3509
|
if (!tokens.some((t) => norm(tag).includes(t))) continue;
|
|
3448
3510
|
let latestEnd = '';
|
|
3449
3511
|
for (const [, values] of unitEntries(entry.units)) {
|
|
@@ -3455,7 +3517,7 @@ async function companyConcept(
|
|
|
3455
3517
|
matches.push({
|
|
3456
3518
|
isFlow: FLOW.test(tag),
|
|
3457
3519
|
latestEnd,
|
|
3458
|
-
doc: { cik: Number(cik), entityName: facts.entityName ?? '', tag, taxonomy:
|
|
3520
|
+
doc: { cik: Number(cik), entityName: facts.entityName ?? '', tag, taxonomy: scanNs, label: entry.label ?? tag, description: entry.description ?? '', units: entry.units },
|
|
3459
3521
|
});
|
|
3460
3522
|
}
|
|
3461
3523
|
matches.sort((a, b) => Number(a.isFlow) - Number(b.isFlow) || (b.latestEnd ?? '').localeCompare(a.latestEnd ?? ''));
|
|
@@ -3536,7 +3598,7 @@ async function companyConcept(
|
|
|
3536
3598
|
reported: false,
|
|
3537
3599
|
latest: null,
|
|
3538
3600
|
values: [],
|
|
3539
|
-
note: `This filer reports no XBRL tag matching "${concept}" under any recognized name — checked us-gaap candidates ${JSON.stringify(candidates)}, IFRS, and a full company-facts name scan. This means EITHER the company genuinely has none (common for e.g. long-term debt at equity-funded filers) OR it reports the item under a tag we didn't match (e.g. convertible/other debt lines). value is null, not zero — call edgar_company_facts({cik:"${cikOrTicker}"}) to see the exact tags this filer uses before treating it as absent.`,
|
|
3601
|
+
note: `This filer reports no XBRL tag matching "${concept}" under any recognized name — checked us-gaap/dei candidates ${JSON.stringify(candidates)}, IFRS, and a full company-facts name scan (us-gaap and dei). This means EITHER the company genuinely has none (common for e.g. long-term debt at equity-funded filers) OR it reports the item under a tag we didn't match (e.g. convertible/other debt lines). value is null, not zero — call edgar_company_facts({cik:"${cikOrTicker}"}) to see the exact tags this filer uses before treating it as absent.`,
|
|
3540
3602
|
};
|
|
3541
3603
|
}
|
|
3542
3604
|
found.sort((a, b) => (b.latestEnd ?? '').localeCompare(a.latestEnd ?? ''));
|
|
@@ -3591,6 +3653,17 @@ async function companyConcept(
|
|
|
3591
3653
|
value: entry.val,
|
|
3592
3654
|
form: entry.form, // 10-K / 10-Q / 20-F / 40-F (+ /A amendments)
|
|
3593
3655
|
filed: entry.filed,
|
|
3656
|
+
// Which filing this exact number came out of (fleet #3178). SEC's
|
|
3657
|
+
// companyconcept payload carries `accn` on every fact and we were
|
|
3658
|
+
// dropping it, so a caller holding a value and a period_end had no way
|
|
3659
|
+
// back to the document without a second edgar_company_filings call and
|
|
3660
|
+
// a date match — and a consumer that FANS OUT over this tool
|
|
3661
|
+
// (entity_profile's fundamentals) could not cite its own figures at all.
|
|
3662
|
+
// Reported rows only: a derived Q4/standalone-quarter row below is
|
|
3663
|
+
// arithmetic over several filings, not a fact any one of them states, so
|
|
3664
|
+
// it carries `accession: undefined` rather than the accession of
|
|
3665
|
+
// whichever leg happened to be the minuend.
|
|
3666
|
+
accession: entry.accn as string | undefined,
|
|
3594
3667
|
unit,
|
|
3595
3668
|
derived: false as boolean | undefined,
|
|
3596
3669
|
note: undefined as string | undefined,
|
|
@@ -3640,6 +3713,7 @@ async function companyConcept(
|
|
|
3640
3713
|
value: fyRow.value - qSum,
|
|
3641
3714
|
form: 'derived',
|
|
3642
3715
|
filed: fyRow.filed,
|
|
3716
|
+
accession: undefined, // arithmetic over FY + Q1-Q3, not a fact one filing states
|
|
3643
3717
|
unit: fyRow.unit,
|
|
3644
3718
|
derived: true,
|
|
3645
3719
|
note: 'Computed as FY minus Q1-Q3 — SEC filers do not report a standalone Q4 fact.',
|
|
@@ -3704,6 +3778,7 @@ async function companyConcept(
|
|
|
3704
3778
|
value: q2ytd.value - q1.value,
|
|
3705
3779
|
form: 'derived',
|
|
3706
3780
|
filed: q2ytd.filed,
|
|
3781
|
+
accession: undefined, // YTD(Q2) minus Q1 — spans two filings
|
|
3707
3782
|
unit: q2ytd.unit,
|
|
3708
3783
|
derived: true,
|
|
3709
3784
|
note: `Computed as the YTD figure filed for Q2 (${q2ytd.value}, covering ${q2ytd.period_start}..${q2ytd.period_end}) minus Q1 (${q1.value}) — this filer reports this concept cumulatively in its 10-Q (a cash-flow-statement concept, typically), not quarter-only.`,
|
|
@@ -3723,6 +3798,7 @@ async function companyConcept(
|
|
|
3723
3798
|
value: q3ytd.value - q2ytd.value,
|
|
3724
3799
|
form: 'derived',
|
|
3725
3800
|
filed: q3ytd.filed,
|
|
3801
|
+
accession: undefined, // YTD(Q3) minus YTD(Q2) — spans two filings
|
|
3726
3802
|
unit: q3ytd.unit,
|
|
3727
3803
|
derived: true,
|
|
3728
3804
|
note: `Computed as the YTD figure filed for Q3 (${q3ytd.value}) minus the YTD figure filed for Q2 (${q2ytd.value}) — this filer reports this concept cumulatively in its 10-Q, not quarter-only.`,
|
|
@@ -3823,8 +3899,18 @@ async function companyConcept(
|
|
|
3823
3899
|
// neither the caller nor any automatic check can tell it apart". A
|
|
3824
3900
|
// substituted tag is the same shape, and gets the same treatment.
|
|
3825
3901
|
const requested = concept.trim();
|
|
3826
|
-
|
|
3827
|
-
|
|
3902
|
+
// A friendly name the tool itself documents ("shares outstanding", "revenue")
|
|
3903
|
+
// resolving to one of ITS OWN listed tags is the advertised behaviour, not a
|
|
3904
|
+
// substitution — the warning below is for the fuzzy name-scan path, where a
|
|
3905
|
+
// narrower tag really can stand in for a broader concept. Until 2026-10-16
|
|
3906
|
+
// "shares outstanding" → CommonStockSharesOutstanding carried the full "NOT
|
|
3907
|
+
// interchangeable" warning on a correct answer.
|
|
3908
|
+
const requestedKey = requested.toLowerCase().replace(/[^a-z0-9]/g, '');
|
|
3909
|
+
const aliasServed = (CONCEPT_CANDIDATES[requestedKey] ?? []).some(
|
|
3910
|
+
(t) => t.toLowerCase() === data.tag.toLowerCase(),
|
|
3911
|
+
);
|
|
3912
|
+
const substituted = requested.length > 0 && !aliasServed
|
|
3913
|
+
&& data.tag.toLowerCase().replace(/[^a-z0-9]/g, '') !== requestedKey;
|
|
3828
3914
|
|
|
3829
3915
|
// Coverage-bound disclosure (fleet #693). A returned value can be genuinely
|
|
3830
3916
|
// CURRENT for this exact XBRL tag while a newer periodic filing exists that
|