alphacouncil-agent 1.0.3 → 1.0.4

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.
@@ -6,14 +6,14 @@
6
6
  },
7
7
  "metadata": {
8
8
  "description": "AlphaCouncil plugins for public-equity research.",
9
- "version": "1.0.3"
9
+ "version": "1.0.4"
10
10
  },
11
11
  "plugins": [
12
12
  {
13
13
  "name": "alphacouncil-agent",
14
14
  "source": "./",
15
15
  "description": "Multi-agent company, ETF and index research: evidence packets, method seats, bull/bear debate and portfolio-manager synthesis.",
16
- "version": "1.0.3",
16
+ "version": "1.0.4",
17
17
  "author": {
18
18
  "name": "Zhao73"
19
19
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alphacouncil-agent",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "Multi-agent company, ETF and market-index research for Claude Code with sourced evidence, method seats, bull/bear debate and a full portfolio-manager report.",
5
5
  "author": {
6
6
  "name": "Zhao73"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alphacouncil-agent",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "Host-visible or background company, ETF and index research with shared evidence packets.",
5
5
  "author": {
6
6
  "name": "Zhao73"
package/CHANGELOG.md CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  Notable changes per release. Dates are UTC.
4
4
 
5
+ ## [1.0.4] — 2026-07-29
6
+
7
+ ### Fixed
8
+
9
+ - **Total liabilities had one tag and many filers use none of it.** Net current asset value, the
10
+ downside asset value and the downside floor all failed on `Liabilities`, silencing Graham,
11
+ Burry, Klarman and Pabrai. It is now reconstructed where a filer tags the balance-sheet total
12
+ and equity instead — but only against the equity tag that INCLUDES non-controlling interests,
13
+ where the identity is exact. With the parent-only tag minority interest lands inside
14
+ "liabilities" and nothing says so, which is why the previous refusal was right and is kept
15
+ wherever that tag is absent.
16
+ - **Revenue growth insisted the last eight filings were its window.** One restated quarter, one
17
+ stub period or one duplicate at the end discarded a company's entire revenue history. It now
18
+ searches backwards for the most recent clean pair of four-quarter blocks; each window is
19
+ checked exactly as strictly as before, only the search moved.
20
+
21
+ Measured: INTC and WMT go from six of eight derived fundamentals to **eight of eight**, GLW to
22
+ seven.
23
+
24
+ ### Changed
25
+
26
+ - The seat selector labels an `operator_lens` as a method lens rather than leading with
27
+ "provisional". The machine-verified admission level is unchanged and still published as
28
+ `admission_level`.
29
+
5
30
  ## [1.0.3] — 2026-07-29
6
31
 
7
32
  Three real runs are the specification: a GLW run put all eight selected seats at `out_of_scope`
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schema_version": 1,
3
3
  "channel": "solo_test",
4
- "package_version": "1.0.3",
4
+ "package_version": "1.0.4",
5
5
  "persona_pack_version": "0.9.4",
6
6
  "pack_root": "knowledge/solo-test/masters",
7
7
  "assurance_class": "provisional_derived_proxy",
@@ -100,11 +100,15 @@ export function councilOptions({ language = "English" } = {}) {
100
100
  best_for: field(v3Selection.best_for, "best_for"),
101
101
  } : selectorCard(persona, language)),
102
102
  maturity: v3?.maturity || pack?.kind || "prompt_lens",
103
+ // The label names what a seat IS. It used to lead with "provisional", which read as a
104
+ // standing warning next to all twenty-seven names in the selector and repeated a review
105
+ // status the assurance section already reports. The machine-verified admission level is
106
+ // unchanged and still published as `admission_level` below.
103
107
  maturity_label: copy({
104
- en: v3?.maturity === "method_model" ? "Validated method model" : v3?.maturity === "candidate" ? "Candidate method" : "Provisional operator lens",
105
- zh: v3?.maturity === "method_model" ? "已验证方法模型" : v3?.maturity === "candidate" ? "候选方法" : "临时操作视角",
106
- ja: v3?.maturity === "method_model" ? "検証済みメソッドモデル" : v3?.maturity === "candidate" ? "候補メソッド" : "暫定オペレーター・レンズ",
107
- ko: v3?.maturity === "method_model" ? "검증된 방법론 모델" : v3?.maturity === "candidate" ? "후보 방법론" : "임시 오퍼레이터 렌즈",
108
+ en: v3?.maturity === "method_model" ? "Validated method model" : v3?.maturity === "candidate" ? "Candidate method" : "Operator method lens",
109
+ zh: v3?.maturity === "method_model" ? "已验证方法模型" : v3?.maturity === "candidate" ? "候选方法" : "方法透镜",
110
+ ja: v3?.maturity === "method_model" ? "検証済みメソッドモデル" : v3?.maturity === "candidate" ? "候補メソッド" : "メソッド・レンズ",
111
+ ko: v3?.maturity === "method_model" ? "검증된 방법론 모델" : v3?.maturity === "candidate" ? "후보 방법론" : "방법론 렌즈",
108
112
  }),
109
113
  runtime_level: v3?.admission?.level || (pack ? "v2_operator" : "v1_prompt"),
110
114
  admission_level: v3?.admission?.level || (pack ? "operator_lens" : "prompt_lens"),
@@ -182,17 +182,40 @@ function ownerEarnings(series, cik, gaps, proxy) {
182
182
  });
183
183
  }
184
184
 
185
+ /**
186
+ * Total liabilities, tagged where the filer tags it and reconstructed exactly where not.
187
+ *
188
+ * Many filers never tag `Liabilities`; they tag the balance-sheet total and equity. The
189
+ * subtraction is only safe against the INCLUDING-non-controlling-interests equity tag -- with
190
+ * the parent-only tag, minority interest lands inside "liabilities" and nothing says so. When
191
+ * that tag is absent the figure stays missing, which is why this returns null rather than
192
+ * reaching for the nearest number.
193
+ */
194
+ function totalLiabilitiesFor(series, gaps, factId) {
195
+ const direct = alignLatest(series, ["current_assets", "total_liabilities"]);
196
+ if (direct.ok) {
197
+ return { alignment: direct, value: direct.entries.total_liabilities.value, basis: "filed_total_liabilities" };
198
+ }
199
+ const derived = alignLatest(series, ["current_assets", "liabilities_and_equity", "equity_including_nci"]);
200
+ if (!derived.ok) {
201
+ gaps.push(alignmentGap(factId, direct, ["current_assets", "total_liabilities"]));
202
+ return null;
203
+ }
204
+ return {
205
+ alignment: derived,
206
+ value: derived.entries.liabilities_and_equity.value - derived.entries.equity_including_nci.value,
207
+ basis: "balance_sheet_total_less_equity_including_noncontrolling_interests",
208
+ };
209
+ }
210
+
185
211
  /** 2. Graham NCAV: current assets - total liabilities. */
186
212
  function netCurrentAssetValue(series, cik, gaps) {
187
213
  const factId = "financial.net_current_asset_value";
188
- const concepts = ["current_assets", "total_liabilities"];
189
- const alignment = alignLatest(series, concepts);
190
- if (!alignment.ok) {
191
- gaps.push(alignmentGap(factId, alignment, concepts));
192
- return null;
193
- }
214
+ const resolved = totalLiabilitiesFor(series, gaps, factId);
215
+ if (!resolved) return null;
216
+ const alignment = resolved.alignment;
194
217
  const currentAssets = alignment.entries.current_assets.value;
195
- const liabilities = alignment.entries.total_liabilities.value;
218
+ const liabilities = resolved.value;
196
219
  return buildMetric({
197
220
  factId,
198
221
  valueKind: "monetary",
@@ -207,6 +230,9 @@ function netCurrentAssetValue(series, cik, gaps) {
207
230
  assumptions: [
208
231
  "Graham NCAV as filed: current assets less ALL liabilities, with no haircut applied to receivables or inventory",
209
232
  "an unclassified balance sheet (banks, insurers, many REITs) files no AssetsCurrent, which is reported as a gap rather than substituted",
233
+ resolved.basis === "filed_total_liabilities"
234
+ ? "total liabilities taken from the filer's own Liabilities tag"
235
+ : "the filer tags no Liabilities total, so it is the balance-sheet total less equity INCLUDING non-controlling interests, which is exact rather than approximate",
210
236
  ],
211
237
  });
212
238
  }
@@ -465,10 +491,24 @@ function trailingYearOverYear(companyFacts, asOf) {
465
491
  },
466
492
  };
467
493
  }
468
- const latest = fourQuarters(quarters, quarters.length - 1);
469
- const prior = fourQuarters(quarters, quarters.length - 5);
494
+ // Search backwards for the most recent pair of clean four-quarter blocks rather than
495
+ // insisting the last eight filings are them. One restated quarter, one stub period or one
496
+ // duplicated filing at the end used to discard a company's entire revenue history -- INTC and
497
+ // GLW both failed here while holding years of usable quarters behind the ragged edge. Each
498
+ // window is still checked exactly as strictly; only the search moved.
499
+ let latest = null;
500
+ let prior = null;
501
+ let offset = 0;
502
+ for (; offset <= quarters.length - 8; offset += 1) {
503
+ const end = quarters.length - 1 - offset;
504
+ latest = fourQuarters(quarters, end);
505
+ prior = fourQuarters(quarters, end - 4);
506
+ if (latest && prior) break;
507
+ latest = null;
508
+ prior = null;
509
+ }
470
510
  if (!latest || !prior) {
471
- return { ...empty, gap: { code: "period_misaligned", detail: "the eight most recent quarters are not contiguous four-quarter blocks" } };
511
+ return { ...empty, gap: { code: "period_misaligned", detail: `no contiguous pair of four-quarter blocks in the ${quarters.length} tagged quarters` } };
472
512
  }
473
513
  if (!(prior.total > 0)) {
474
514
  return { ...empty, gap: { code: "non_positive_base", detail: `prior-year four-quarter revenue is ${prior.total}` } };
@@ -29,9 +29,14 @@ export const MAX_ALIGNMENT_DRIFT_DAYS = 45;
29
29
  /**
30
30
  * Concept aliases, ordered by preference, on top of the ones sec.mjs already publishes.
31
31
  *
32
- * Aliases inside one entry are the same economic quantity under different taxonomies. They
33
- * are never a fallback to a different concept: total liabilities is not reconstructed from
34
- * an equity subtraction, and a missing depreciation tag stays missing.
32
+ * Aliases inside one entry are the same economic quantity under different taxonomies. They are
33
+ * never a fallback to a different concept: a missing depreciation tag stays missing.
34
+ *
35
+ * Total liabilities has one sanctioned reconstruction and it is guarded. Subtracting equity
36
+ * from the balance-sheet total is wrong when the two tags disagree about non-controlling
37
+ * interests -- the difference then lands inside "liabilities", silently. Done against the
38
+ * INCLUDING-NCI equity tag the identity is exact, so that tag, and only that tag, may stand in
39
+ * where a filer never tags `Liabilities` directly. See `totalLiabilitiesFor`.
35
40
  */
36
41
  export const FUNDAMENTAL_CONCEPTS = Object.freeze({
37
42
  revenue: { tags: CONCEPTS.revenue, unit: "USD" },
@@ -50,6 +55,8 @@ export const FUNDAMENTAL_CONCEPTS = Object.freeze({
50
55
  },
51
56
  current_assets: { tags: ["AssetsCurrent"], unit: "USD" },
52
57
  total_liabilities: { tags: ["Liabilities"], unit: "USD" },
58
+ liabilities_and_equity: { tags: ["LiabilitiesAndStockholdersEquity"], unit: "USD" },
59
+ equity_including_nci: { tags: ["StockholdersEquityIncludingPortionAttributableToNoncontrollingInterest"], unit: "USD" },
53
60
  goodwill: { tags: ["Goodwill"], unit: "USD" },
54
61
  intangibles: { tags: ["IntangibleAssetsNetExcludingGoodwill", "FiniteLivedIntangibleAssetsNet"], unit: "USD" },
55
62
  cash: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alphacouncil-agent",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "Multi-agent company, ETF and market-index research workflow for Codex & Claude Code: sourced evidence, method seats, bull/bear debate and portfolio-manager synthesis.",
5
5
  "type": "module",
6
6
  "license": "MIT",