alphacouncil-agent 0.9.2 → 1.0.0
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/.claude/commands/alpha.md +22 -3
- package/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +2 -2
- package/.codex-plugin/plugin.json +4 -4
- package/.grok/commands/alpha.md +22 -3
- package/.opencode/command/alpha.md +22 -3
- package/AGENTS.md +42 -4
- package/CHANGELOG.md +164 -0
- package/CLAUDE.md +59 -7
- package/README.ja.md +25 -11
- package/README.md +44 -12
- package/README.zh-CN.md +37 -12
- package/commands/alpha.md +22 -3
- package/data/authored/core-seats.mjs +808 -0
- package/data/authored/growth-seats.mjs +581 -0
- package/data/authored/index.mjs +114 -0
- package/data/authored/quant-seats.mjs +564 -0
- package/data/authored/value-seats.mjs +663 -0
- package/data/build-profile.v1.json +2 -1
- package/data/council-evaluation-protocol.v1.json +7 -4
- package/data/master-selector-method-locales.v1.mjs +296 -0
- package/data/persona-v3-ai-assisted-solo-profile.v1.json +2 -2
- package/data/persona-v3-build-specs.v1.mjs +60 -3
- package/docs/INSTALL.md +43 -6
- package/docs/personas.md +2 -1
- package/docs/plans/v1.0-roadmap.md +487 -0
- package/docs/releases/v0.9.3.md +86 -0
- package/docs/releases/v0.9.4.md +79 -0
- package/docs/releases/v0.9.5.md +96 -0
- package/docs/releases/v1.0.0.md +164 -0
- package/docs/report-contract.md +75 -2
- package/knowledge/ai-assisted-solo/experiments/runs/a.json +13 -13
- package/knowledge/ai-assisted-solo/experiments/runs/b.json +2 -2
- package/knowledge/ai-assisted-solo/experiments/runs/c.json +2 -2
- package/knowledge/ai-assisted-solo/experiments/runs/d13.json +126 -126
- package/knowledge/ai-assisted-solo/experiments/runs/d26.json +274 -254
- package/knowledge/ai-assisted-solo/experiments/runs/e-d13.json +129 -129
- package/knowledge/ai-assisted-solo/experiments/runs/e-d26.json +277 -257
- package/knowledge/ai-assisted-solo/experiments/runs/h_ai_reference.json +278 -258
- package/knowledge/ai-assisted-solo/experiments/simulation-input.json +7278 -556
- package/knowledge/ai-assisted-solo/experiments/simulation-manifest.json +22 -22
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_ackman/reviews/{change_value_bridge.ai-review.json → market_capitalisation.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_ackman/reviews/{power_map.ai-review.json → owner_earnings_yield.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_aschenbrenner/reviews/{compute_power_bridge.ai-review.json → market_capitalisation.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_aschenbrenner/reviews/{timeline_reverse_valuation.ai-review.json → price_implied_cash_yield.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_asness/reviews/{crowding_cost_stress.ai-review.json → nominal_earnings_yield_gap.ai-review.json} +49 -49
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_asness/reviews/{factor_decomposer.ai-review.json → real_earnings_yield_gap.ai-review.json} +49 -49
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_bogle/reviews/expected_return_over_long_bond.ai-review.json +277 -0
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_bogle/reviews/fundamental_expected_return.ai-review.json +277 -0
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_buffett/reviews/{incremental_returns.ai-review.json → market_capitalisation.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_buffett/reviews/{owner_earnings_rebuilder.ai-review.json → owner_earnings_yield.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_burry/reviews/{mispricing_carry.ai-review.json → net_current_asset_surplus_per_share.ai-review.json} +49 -49
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_burry/reviews/{capital_structure_reader.ai-review.json → net_current_asset_value_per_share.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_cathie_wood/reviews/{cost_adoption_curve.ai-review.json → current_cash_yield.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_cathie_wood/reviews/{capture_valuation_bridge.ai-review.json → market_capitalisation.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_dalio/reviews/{debt_driver_stress.ai-review.json → policy_real_rate.ai-review.json} +49 -49
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_dalio/reviews/{regime_classifier.ai-review.json → real_curve_slope.ai-review.json} +49 -49
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_damodaran/reviews/{reverse_valuation.ai-review.json → implied_equity_risk_premium.ai-review.json} +49 -49
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_damodaran/reviews/{story_dcf.ai-review.json → premium_versus_long_run_average.ai-review.json} +49 -49
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_druckenmiller/reviews/{liquidity_revision_map.ai-review.json → liquidity_curve_impulse.ai-review.json} +49 -49
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_druckenmiller/reviews/{inflection_payoff.ai-review.json → policy_real_rate.ai-review.json} +49 -49
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_duan_yongping/reviews/{opportunity_cost.ai-review.json → five_year_opportunity_cost.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_duan_yongping/reviews/{user_value_evidence.ai-review.json → margin_retention.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_fisher/reviews/{research_productivity.ai-review.json → margin_retention.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_fisher/reviews/{scuttlebutt_graph.ai-review.json → reinvestment_spread.ai-review.json} +49 -49
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_forensic_short/reviews/{borrow_catalyst.ai-review.json → cash_conversion_gap.ai-review.json} +49 -49
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_forensic_short/reviews/{accounting_rebuilder.ai-review.json → cash_cover_of_leverage.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_graham/reviews/{asset_floor.ai-review.json → defensive_hurdle_base.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_graham/reviews/{normalized_earnings.ai-review.json → half_normalised_earnings_yield.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_jhunjhunwala/reviews/{penetration_liquidity.ai-review.json → cash_quality_gap.ai-review.json} +49 -49
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_jhunjhunwala/reviews/{promoter_governance.ai-review.json → real_structural_growth.ai-review.json} +49 -49
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_klarman/reviews/{recovery_waterfall.ai-review.json → downside_asset_coverage.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_klarman/reviews/{cash_catalyst_compare.ai-review.json → market_capitalisation.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_li_lu/reviews/{promise_integrity_ledger.ai-review.json → cash_backed_decade_return.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_li_lu/reviews/{ten_year_return_bridge.ai-review.json → decade_return_over_long_bond.ai-review.json} +49 -49
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_lynch/reviews/{story_numbers_check.ai-review.json → growth_justified_capitalisation.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_lynch/reviews/{category_classifier.ai-review.json → market_capitalisation.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_marks/reviews/{cycle_temperature.ai-review.json → credit_cycle_position.ai-review.json} +49 -49
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_marks/reviews/{implied_expectations.ai-review.json → equity_over_corporate_debt.ai-review.json} +49 -49
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_munger/reviews/{failure_path_graph.ai-review.json → debt_service_cushion.ai-review.json} +49 -49
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_munger/reviews/{incentive_map.ai-review.json → reported_earnings_cash_gap.ai-review.json} +49 -49
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_natenberg/reviews/{surface_builder.ai-review.json → normalised_skew.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_natenberg/reviews/{greeks_payoff.ai-review.json → round_trip_cost.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_pabrai/reviews/{downside_floor.ai-review.json → downside_floor_coverage.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_pabrai/reviews/{discrete_payoff.ai-review.json → market_capitalisation.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_simons/reviews/{oos_cost_test.ai-review.json → absolute_session_move.ai-review.json} +42 -42
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_simons/reviews/{leakage_audit.ai-review.json → session_move_over_implied.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_sinclair/reviews/{realized_vol_forecast.ai-review.json → round_trip_cost.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_sinclair/reviews/{net_edge_sizer.ai-review.json → volatility_per_unit_of_width.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_soros/reviews/{reversal_monitor.ai-review.json → credit_cycle_position.ai-review.json} +49 -49
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_soros/reviews/{reflexivity_graph.ai-review.json → financing_burden.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_taleb/reviews/{tail_friction.ai-review.json → debt_service_cushion.ai-review.json} +49 -49
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_taleb/reviews/{payoff_ruin.ai-review.json → normalised_skew.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_thorp/reviews/{edge_recalculator.ai-review.json → edge_per_unit_of_volatility.ai-review.json} +46 -46
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/master_thorp/reviews/{fractional_kelly.ai-review.json → net_edge.ai-review.json} +49 -49
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-formula-reviews/review-manifest.json +288 -270
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-semantic-adjudications/index.json +2 -2
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-semantic-extractions/index.json +2 -2
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-semantic-skeptic-reviews/index.json +2 -2
- package/knowledge/ai-assisted-solo/reviews/persona-v3-ai-source-prereviews/index.json +6 -2
- package/knowledge/solo-test/masters/master_ackman/decision_policy.json +122 -11
- package/knowledge/solo-test/masters/master_ackman/doctrine.jsonl +2 -2
- package/knowledge/solo-test/masters/master_ackman/manifest.json +27 -10
- package/knowledge/solo-test/masters/master_ackman/provisional-index.json +3 -3
- package/knowledge/solo-test/masters/master_ackman/sources.jsonl +1 -1
- package/knowledge/solo-test/masters/master_ackman/tools.json +56 -30
- package/knowledge/solo-test/masters/master_aschenbrenner/decision_policy.json +101 -10
- package/knowledge/solo-test/masters/master_aschenbrenner/doctrine.jsonl +2 -2
- package/knowledge/solo-test/masters/master_aschenbrenner/manifest.json +26 -8
- package/knowledge/solo-test/masters/master_aschenbrenner/provisional-index.json +3 -3
- package/knowledge/solo-test/masters/master_aschenbrenner/sources.jsonl +1 -1
- package/knowledge/solo-test/masters/master_aschenbrenner/tools.json +56 -30
- package/knowledge/solo-test/masters/master_asness/decision_policy.json +89 -10
- package/knowledge/solo-test/masters/master_asness/doctrine.jsonl +2 -2
- package/knowledge/solo-test/masters/master_asness/manifest.json +25 -8
- package/knowledge/solo-test/masters/master_asness/provisional-index.json +3 -3
- package/knowledge/solo-test/masters/master_asness/sources.jsonl +1 -1
- package/knowledge/solo-test/masters/master_asness/tools.json +56 -30
- package/knowledge/solo-test/masters/master_bogle/counterfactuals.jsonl +0 -0
- package/knowledge/solo-test/masters/master_bogle/decision_cases.jsonl +0 -0
- package/knowledge/solo-test/masters/master_bogle/decision_policy.json +170 -0
- package/knowledge/solo-test/masters/master_bogle/doctrine.jsonl +14 -0
- package/knowledge/solo-test/masters/master_bogle/evaluation/calibration_cases.jsonl +0 -0
- package/knowledge/solo-test/masters/master_bogle/evaluation/experiments.json +5 -0
- package/knowledge/solo-test/masters/master_bogle/evaluation/golden_cases.jsonl +0 -0
- package/knowledge/solo-test/masters/master_bogle/evaluation/pairwise_cases.jsonl +0 -0
- package/knowledge/solo-test/masters/master_bogle/failures.jsonl +0 -0
- package/knowledge/solo-test/masters/master_bogle/manifest.json +141 -0
- package/knowledge/solo-test/masters/master_bogle/memory_policy.json +5 -0
- package/knowledge/solo-test/masters/master_bogle/provisional-index.json +41 -0
- package/knowledge/solo-test/masters/master_bogle/research_policy.json +11 -0
- package/knowledge/solo-test/masters/master_bogle/sources.jsonl +1 -0
- package/knowledge/solo-test/masters/master_bogle/tools.json +120 -0
- package/knowledge/solo-test/masters/master_bogle/voice.en.md +7 -0
- package/knowledge/solo-test/masters/master_bogle/voice.zh.md +7 -0
- package/knowledge/solo-test/masters/master_buffett/decision_policy.json +102 -11
- package/knowledge/solo-test/masters/master_buffett/doctrine.jsonl +2 -2
- package/knowledge/solo-test/masters/master_buffett/manifest.json +24 -8
- package/knowledge/solo-test/masters/master_buffett/provisional-index.json +3 -3
- package/knowledge/solo-test/masters/master_buffett/sources.jsonl +1 -1
- package/knowledge/solo-test/masters/master_buffett/tools.json +55 -29
- package/knowledge/solo-test/masters/master_burry/decision_policy.json +102 -12
- package/knowledge/solo-test/masters/master_burry/doctrine.jsonl +2 -2
- package/knowledge/solo-test/masters/master_burry/manifest.json +26 -10
- package/knowledge/solo-test/masters/master_burry/provisional-index.json +3 -3
- package/knowledge/solo-test/masters/master_burry/sources.jsonl +1 -1
- package/knowledge/solo-test/masters/master_burry/tools.json +56 -30
- package/knowledge/solo-test/masters/master_cathie_wood/decision_policy.json +74 -12
- package/knowledge/solo-test/masters/master_cathie_wood/doctrine.jsonl +2 -2
- package/knowledge/solo-test/masters/master_cathie_wood/manifest.json +26 -10
- package/knowledge/solo-test/masters/master_cathie_wood/provisional-index.json +3 -3
- package/knowledge/solo-test/masters/master_cathie_wood/sources.jsonl +1 -1
- package/knowledge/solo-test/masters/master_cathie_wood/tools.json +56 -30
- package/knowledge/solo-test/masters/master_dalio/decision_policy.json +123 -16
- package/knowledge/solo-test/masters/master_dalio/doctrine.jsonl +2 -2
- package/knowledge/solo-test/masters/master_dalio/manifest.json +24 -8
- package/knowledge/solo-test/masters/master_dalio/provisional-index.json +3 -3
- package/knowledge/solo-test/masters/master_dalio/sources.jsonl +1 -1
- package/knowledge/solo-test/masters/master_dalio/tools.json +56 -30
- package/knowledge/solo-test/masters/master_damodaran/decision_policy.json +58 -10
- package/knowledge/solo-test/masters/master_damodaran/doctrine.jsonl +2 -2
- package/knowledge/solo-test/masters/master_damodaran/manifest.json +23 -8
- package/knowledge/solo-test/masters/master_damodaran/provisional-index.json +3 -3
- package/knowledge/solo-test/masters/master_damodaran/sources.jsonl +1 -1
- package/knowledge/solo-test/masters/master_damodaran/tools.json +54 -28
- package/knowledge/solo-test/masters/master_druckenmiller/decision_policy.json +89 -10
- package/knowledge/solo-test/masters/master_druckenmiller/doctrine.jsonl +2 -2
- package/knowledge/solo-test/masters/master_druckenmiller/manifest.json +25 -8
- package/knowledge/solo-test/masters/master_druckenmiller/provisional-index.json +3 -3
- package/knowledge/solo-test/masters/master_druckenmiller/sources.jsonl +1 -1
- package/knowledge/solo-test/masters/master_druckenmiller/tools.json +55 -29
- package/knowledge/solo-test/masters/master_duan_yongping/decision_policy.json +138 -13
- package/knowledge/solo-test/masters/master_duan_yongping/doctrine.jsonl +2 -2
- package/knowledge/solo-test/masters/master_duan_yongping/manifest.json +31 -11
- package/knowledge/solo-test/masters/master_duan_yongping/provisional-index.json +3 -3
- package/knowledge/solo-test/masters/master_duan_yongping/sources.jsonl +1 -1
- package/knowledge/solo-test/masters/master_duan_yongping/tools.json +82 -30
- package/knowledge/solo-test/masters/master_fisher/decision_policy.json +102 -11
- package/knowledge/solo-test/masters/master_fisher/doctrine.jsonl +2 -2
- package/knowledge/solo-test/masters/master_fisher/manifest.json +27 -10
- package/knowledge/solo-test/masters/master_fisher/provisional-index.json +3 -3
- package/knowledge/solo-test/masters/master_fisher/sources.jsonl +1 -1
- package/knowledge/solo-test/masters/master_fisher/tools.json +58 -32
- package/knowledge/solo-test/masters/master_forensic_short/decision_policy.json +93 -14
- package/knowledge/solo-test/masters/master_forensic_short/doctrine.jsonl +2 -2
- package/knowledge/solo-test/masters/master_forensic_short/manifest.json +20 -8
- package/knowledge/solo-test/masters/master_forensic_short/provisional-index.json +3 -3
- package/knowledge/solo-test/masters/master_forensic_short/sources.jsonl +1 -1
- package/knowledge/solo-test/masters/master_forensic_short/tools.json +53 -27
- package/knowledge/solo-test/masters/master_graham/decision_policy.json +103 -12
- package/knowledge/solo-test/masters/master_graham/doctrine.jsonl +2 -2
- package/knowledge/solo-test/masters/master_graham/manifest.json +26 -8
- package/knowledge/solo-test/masters/master_graham/provisional-index.json +3 -3
- package/knowledge/solo-test/masters/master_graham/sources.jsonl +1 -1
- package/knowledge/solo-test/masters/master_graham/tools.json +67 -28
- package/knowledge/solo-test/masters/master_jhunjhunwala/decision_policy.json +77 -12
- package/knowledge/solo-test/masters/master_jhunjhunwala/doctrine.jsonl +2 -2
- package/knowledge/solo-test/masters/master_jhunjhunwala/manifest.json +25 -10
- package/knowledge/solo-test/masters/master_jhunjhunwala/provisional-index.json +3 -3
- package/knowledge/solo-test/masters/master_jhunjhunwala/sources.jsonl +1 -1
- package/knowledge/solo-test/masters/master_jhunjhunwala/tools.json +54 -28
- package/knowledge/solo-test/masters/master_klarman/decision_policy.json +105 -14
- package/knowledge/solo-test/masters/master_klarman/doctrine.jsonl +2 -2
- package/knowledge/solo-test/masters/master_klarman/manifest.json +22 -6
- package/knowledge/solo-test/masters/master_klarman/provisional-index.json +3 -3
- package/knowledge/solo-test/masters/master_klarman/sources.jsonl +1 -1
- package/knowledge/solo-test/masters/master_klarman/tools.json +55 -29
- package/knowledge/solo-test/masters/master_li_lu/decision_policy.json +101 -10
- package/knowledge/solo-test/masters/master_li_lu/doctrine.jsonl +2 -2
- package/knowledge/solo-test/masters/master_li_lu/manifest.json +27 -10
- package/knowledge/solo-test/masters/master_li_lu/provisional-index.json +3 -3
- package/knowledge/solo-test/masters/master_li_lu/sources.jsonl +1 -1
- package/knowledge/solo-test/masters/master_li_lu/tools.json +58 -32
- package/knowledge/solo-test/masters/master_lynch/decision_policy.json +127 -16
- package/knowledge/solo-test/masters/master_lynch/doctrine.jsonl +2 -2
- package/knowledge/solo-test/masters/master_lynch/manifest.json +28 -10
- package/knowledge/solo-test/masters/master_lynch/provisional-index.json +3 -3
- package/knowledge/solo-test/masters/master_lynch/sources.jsonl +1 -1
- package/knowledge/solo-test/masters/master_lynch/tools.json +67 -28
- package/knowledge/solo-test/masters/master_marks/decision_policy.json +71 -9
- package/knowledge/solo-test/masters/master_marks/doctrine.jsonl +2 -2
- package/knowledge/solo-test/masters/master_marks/manifest.json +25 -10
- package/knowledge/solo-test/masters/master_marks/provisional-index.json +3 -3
- package/knowledge/solo-test/masters/master_marks/sources.jsonl +1 -1
- package/knowledge/solo-test/masters/master_marks/tools.json +54 -28
- package/knowledge/solo-test/masters/master_munger/decision_policy.json +141 -16
- package/knowledge/solo-test/masters/master_munger/doctrine.jsonl +2 -2
- package/knowledge/solo-test/masters/master_munger/manifest.json +24 -10
- package/knowledge/solo-test/masters/master_munger/provisional-index.json +3 -3
- package/knowledge/solo-test/masters/master_munger/sources.jsonl +1 -1
- package/knowledge/solo-test/masters/master_munger/tools.json +52 -26
- package/knowledge/solo-test/masters/master_natenberg/decision_policy.json +59 -11
- package/knowledge/solo-test/masters/master_natenberg/doctrine.jsonl +2 -2
- package/knowledge/solo-test/masters/master_natenberg/manifest.json +23 -10
- package/knowledge/solo-test/masters/master_natenberg/provisional-index.json +3 -3
- package/knowledge/solo-test/masters/master_natenberg/sources.jsonl +1 -1
- package/knowledge/solo-test/masters/master_natenberg/tools.json +50 -24
- package/knowledge/solo-test/masters/master_pabrai/decision_policy.json +125 -14
- package/knowledge/solo-test/masters/master_pabrai/doctrine.jsonl +2 -2
- package/knowledge/solo-test/masters/master_pabrai/manifest.json +22 -6
- package/knowledge/solo-test/masters/master_pabrai/provisional-index.json +3 -3
- package/knowledge/solo-test/masters/master_pabrai/sources.jsonl +1 -1
- package/knowledge/solo-test/masters/master_pabrai/tools.json +55 -29
- package/knowledge/solo-test/masters/master_simons/decision_policy.json +59 -11
- package/knowledge/solo-test/masters/master_simons/doctrine.jsonl +2 -2
- package/knowledge/solo-test/masters/master_simons/manifest.json +22 -8
- package/knowledge/solo-test/masters/master_simons/provisional-index.json +3 -3
- package/knowledge/solo-test/masters/master_simons/sources.jsonl +1 -1
- package/knowledge/solo-test/masters/master_simons/tools.json +43 -30
- package/knowledge/solo-test/masters/master_sinclair/decision_policy.json +59 -11
- package/knowledge/solo-test/masters/master_sinclair/doctrine.jsonl +2 -2
- package/knowledge/solo-test/masters/master_sinclair/manifest.json +22 -10
- package/knowledge/solo-test/masters/master_sinclair/provisional-index.json +3 -3
- package/knowledge/solo-test/masters/master_sinclair/sources.jsonl +1 -1
- package/knowledge/solo-test/masters/master_sinclair/tools.json +54 -28
- package/knowledge/solo-test/masters/master_soros/decision_policy.json +98 -10
- package/knowledge/solo-test/masters/master_soros/doctrine.jsonl +2 -2
- package/knowledge/solo-test/masters/master_soros/manifest.json +24 -11
- package/knowledge/solo-test/masters/master_soros/provisional-index.json +3 -3
- package/knowledge/solo-test/masters/master_soros/sources.jsonl +1 -1
- package/knowledge/solo-test/masters/master_soros/tools.json +54 -28
- package/knowledge/solo-test/masters/master_taleb/decision_policy.json +124 -13
- package/knowledge/solo-test/masters/master_taleb/doctrine.jsonl +2 -2
- package/knowledge/solo-test/masters/master_taleb/manifest.json +23 -9
- package/knowledge/solo-test/masters/master_taleb/provisional-index.json +3 -3
- package/knowledge/solo-test/masters/master_taleb/sources.jsonl +1 -1
- package/knowledge/solo-test/masters/master_taleb/tools.json +50 -24
- package/knowledge/solo-test/masters/master_thorp/decision_policy.json +61 -13
- package/knowledge/solo-test/masters/master_thorp/doctrine.jsonl +2 -2
- package/knowledge/solo-test/masters/master_thorp/manifest.json +25 -10
- package/knowledge/solo-test/masters/master_thorp/provisional-index.json +3 -3
- package/knowledge/solo-test/masters/master_thorp/sources.jsonl +1 -1
- package/knowledge/solo-test/masters/master_thorp/tools.json +56 -30
- package/knowledge/solo-test/persona-v3-solo-test-formulas/compilation-manifest.json +290 -264
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_ackman/components/tools.json +58 -32
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_ackman/provisional-derivations/market_capitalisation.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_ackman/provisional-derivations/owner_earnings_yield.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_aschenbrenner/components/tools.json +58 -32
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_aschenbrenner/provisional-derivations/market_capitalisation.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_aschenbrenner/provisional-derivations/price_implied_cash_yield.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_asness/components/tools.json +58 -32
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_asness/provisional-derivations/nominal_earnings_yield_gap.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_asness/provisional-derivations/real_earnings_yield_gap.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_bogle/components/tools.json +120 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_bogle/provisional-derivations/expected_return_over_long_bond.derived-proxy-evidence.json +77 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_bogle/provisional-derivations/fundamental_expected_return.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_buffett/components/tools.json +57 -31
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_buffett/provisional-derivations/market_capitalisation.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_buffett/provisional-derivations/owner_earnings_yield.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_burry/components/tools.json +58 -32
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_burry/provisional-derivations/net_current_asset_surplus_per_share.derived-proxy-evidence.json +77 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_burry/provisional-derivations/net_current_asset_value_per_share.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_cathie_wood/components/tools.json +58 -32
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_cathie_wood/provisional-derivations/current_cash_yield.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_cathie_wood/provisional-derivations/market_capitalisation.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_dalio/components/tools.json +58 -32
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_dalio/provisional-derivations/policy_real_rate.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_dalio/provisional-derivations/real_curve_slope.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_damodaran/components/tools.json +56 -30
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_damodaran/provisional-derivations/implied_equity_risk_premium.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_damodaran/provisional-derivations/{reverse_valuation.derived-proxy-evidence.json → premium_versus_long_run_average.derived-proxy-evidence.json} +29 -16
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_druckenmiller/components/tools.json +57 -31
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_druckenmiller/provisional-derivations/liquidity_curve_impulse.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_druckenmiller/provisional-derivations/policy_real_rate.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_duan_yongping/components/tools.json +84 -32
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_duan_yongping/provisional-derivations/five_year_opportunity_cost.derived-proxy-evidence.json +102 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_duan_yongping/provisional-derivations/margin_retention.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_fisher/components/tools.json +60 -34
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_fisher/provisional-derivations/margin_retention.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_fisher/provisional-derivations/reinvestment_spread.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_forensic_short/components/tools.json +55 -29
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_forensic_short/provisional-derivations/{accounting_rebuilder.derived-proxy-evidence.json → cash_conversion_gap.derived-proxy-evidence.json} +28 -15
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_forensic_short/provisional-derivations/cash_cover_of_leverage.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_graham/components/tools.json +69 -30
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_graham/provisional-derivations/defensive_hurdle_base.derived-proxy-evidence.json +89 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_graham/provisional-derivations/half_normalised_earnings_yield.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_jhunjhunwala/components/tools.json +56 -30
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_jhunjhunwala/provisional-derivations/cash_quality_gap.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_jhunjhunwala/provisional-derivations/real_structural_growth.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_klarman/components/tools.json +57 -31
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_klarman/provisional-derivations/downside_asset_coverage.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_klarman/provisional-derivations/market_capitalisation.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_li_lu/components/tools.json +60 -34
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_li_lu/provisional-derivations/cash_backed_decade_return.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_li_lu/provisional-derivations/decade_return_over_long_bond.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_lynch/components/tools.json +69 -30
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_lynch/provisional-derivations/growth_justified_capitalisation.derived-proxy-evidence.json +89 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_lynch/provisional-derivations/market_capitalisation.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_marks/components/tools.json +56 -30
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_marks/provisional-derivations/credit_cycle_position.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_marks/provisional-derivations/equity_over_corporate_debt.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_munger/components/tools.json +54 -28
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_munger/provisional-derivations/debt_service_cushion.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_munger/provisional-derivations/reported_earnings_cash_gap.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_natenberg/components/tools.json +52 -26
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_natenberg/provisional-derivations/{surface_builder.derived-proxy-evidence.json → normalised_skew.derived-proxy-evidence.json} +27 -14
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_natenberg/provisional-derivations/round_trip_cost.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_pabrai/components/tools.json +57 -31
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_pabrai/provisional-derivations/downside_floor_coverage.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_pabrai/provisional-derivations/market_capitalisation.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_simons/components/tools.json +45 -32
- package/knowledge/solo-test/persona-v3-solo-test-formulas/{master_natenberg/provisional-derivations/greeks_payoff.derived-proxy-evidence.json → master_simons/provisional-derivations/absolute_session_move.derived-proxy-evidence.json} +17 -17
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_simons/provisional-derivations/session_move_over_implied.derived-proxy-evidence.json +77 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_sinclair/components/tools.json +56 -30
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_sinclair/provisional-derivations/round_trip_cost.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_sinclair/provisional-derivations/volatility_per_unit_of_width.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_soros/components/tools.json +56 -30
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_soros/provisional-derivations/credit_cycle_position.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_soros/provisional-derivations/financing_burden.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_taleb/components/tools.json +52 -26
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_taleb/provisional-derivations/debt_service_cushion.derived-proxy-evidence.json +76 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_taleb/provisional-derivations/{tail_friction.derived-proxy-evidence.json → normalised_skew.derived-proxy-evidence.json} +27 -14
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_thorp/components/tools.json +58 -32
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_thorp/provisional-derivations/edge_per_unit_of_volatility.derived-proxy-evidence.json +77 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_thorp/provisional-derivations/net_edge.derived-proxy-evidence.json +76 -0
- package/mcp/lib/breadth.mjs +122 -0
- package/mcp/lib/codex.mjs +3 -3
- package/mcp/lib/constants.mjs +76 -25
- package/mcp/lib/council-options.mjs +95 -40
- package/mcp/lib/council-selection.mjs +95 -9
- package/mcp/lib/damodaran.mjs +119 -0
- package/mcp/lib/fred.mjs +246 -0
- package/mcp/lib/fund-holdings-parsers.mjs +297 -0
- package/mcp/lib/fundamentals.mjs +801 -0
- package/mcp/lib/funds.mjs +750 -0
- package/mcp/lib/gates.mjs +149 -15
- package/mcp/lib/grounding.mjs +188 -36
- package/mcp/lib/index-aggregate.mjs +718 -0
- package/mcp/lib/insider-ownership.mjs +149 -0
- package/mcp/lib/instrument-facts.mjs +557 -0
- package/mcp/lib/instruments.mjs +191 -0
- package/mcp/lib/lang.mjs +109 -2
- package/mcp/lib/markdown.mjs +620 -138
- package/mcp/lib/master-catalog.mjs +32 -3
- package/mcp/lib/orchestrator.mjs +1121 -290
- package/mcp/lib/packets.mjs +227 -21
- package/mcp/lib/personas/engine.mjs +44 -31
- package/mcp/lib/personas-v3/compiler.mjs +2 -0
- package/mcp/lib/personas-v3/deterministic-executor.mjs +13 -2
- package/mcp/lib/personas-v3/ga-external-evidence.mjs +3 -2
- package/mcp/lib/personas-v3/ga-gate.mjs +2 -1
- package/mcp/lib/personas-v3/ga-package-evidence.mjs +5 -4
- package/mcp/lib/personas-v3/grounding-adapter.mjs +309 -2
- package/mcp/lib/personas-v3/loader.mjs +10 -7
- package/mcp/lib/personas-v3/production-root.mjs +5 -4
- package/mcp/lib/personas-v3/release-formula-evidence.mjs +14 -7
- package/mcp/lib/personas-v3/release-source-evidence.mjs +2 -1
- package/mcp/lib/personas-v3/releases.mjs +5 -4
- package/mcp/lib/personas-v3/runtime-release-integrity.mjs +6 -5
- package/mcp/lib/personas-v3/semantic-source-adjudication.mjs +2 -1
- package/mcp/lib/personas-v3/semantic-source-extraction.mjs +2 -1
- package/mcp/lib/personas-v3/semantic-source-skeptic-review.mjs +2 -1
- package/mcp/lib/personas-v3/source-acquisition.mjs +10 -3
- package/mcp/lib/personas-v3/source-review-operations.mjs +3 -2
- package/mcp/lib/personas-v3/staging.mjs +22 -3
- package/mcp/lib/prompts.mjs +119 -2
- package/mcp/lib/quotes.mjs +5 -0
- package/mcp/lib/rpc.mjs +101 -42
- package/mcp/lib/run-store.mjs +28 -3
- package/mcp/lib/sec.mjs +32 -0
- package/mcp/lib/tables.mjs +11 -0
- package/mcp/lib/voice.mjs +122 -0
- package/mcp/lib/xbrl-aggregates.mjs +153 -0
- package/mcp/lib/xbrl-series.mjs +339 -0
- package/mcp/lib/xlsx.mjs +155 -0
- package/package.json +5 -5
- package/personas/masters/masters-value/bogle.md +145 -0
- package/schemas/council-evaluation-protocol-v1.schema.json +2 -2
- package/schemas/persona-v3-ai-assisted-solo-profile-v1.schema.json +2 -2
- package/schemas/persona-v3-ai-machine-simulation-v1.schema.json +1 -1
- package/schemas/persona-v3-build-spec-v1.schema.json +3 -3
- package/schemas/persona-v3-release-formula-review-evidence-v1.schema.json +3 -3
- package/schemas/persona-v3-release-manifest-v1.schema.json +6 -6
- package/schemas/persona-v3-release-source-review-evidence-v1.schema.json +3 -3
- package/schemas/persona-v3-tool-graph-v1.schema.json +1 -1
- package/schemas/persona-v3.schema.json +37 -2
- package/schemas/source-review-batch-v1.schema.json +9 -9
- package/scripts/assemble-persona-v3-release.mjs +3 -2
- package/scripts/build-persona-v3-solo-test-packs.mjs +6 -8
- package/scripts/check-persona-v3-ga.mjs +1 -1
- package/scripts/check-persona-v3-production-candidates.mjs +1 -1
- package/scripts/compile-persona-v3-formulas.mjs +19 -18
- package/scripts/doctor.mjs +11 -9
- package/scripts/export-persona-source-review-batch.mjs +1 -1
- package/scripts/generate-persona-v3-drafts.mjs +2 -2
- package/scripts/lib/build-profile.mjs +24 -0
- package/scripts/lib/council-evaluation-protocol.mjs +7 -6
- package/scripts/lib/host-capabilities.mjs +2 -1
- package/scripts/lib/packaged-host-parity.mjs +63 -8
- package/scripts/lib/persona-v3-ai-assisted-solo-status.mjs +6 -4
- package/scripts/lib/persona-v3-ai-formula-review.mjs +6 -5
- package/scripts/lib/persona-v3-ai-machine-simulations.mjs +32 -4
- package/scripts/lib/persona-v3-build-specs.mjs +3 -2
- package/scripts/lib/persona-v3-draft-packs.mjs +2 -2
- package/scripts/lib/persona-v3-formula-pipeline.mjs +11 -10
- package/scripts/lib/persona-v3-production-candidates.mjs +10 -9
- package/scripts/lib/persona-v3-solo-formula-pipeline.mjs +182 -16
- package/scripts/lib/persona-v3-solo-test-packs.mjs +143 -16
- package/scripts/package-smoke.mjs +32 -12
- package/scripts/report-persona-corpus-gaps.mjs +4 -1
- package/scripts/review-persona-v3-solo-formulas.mjs +12 -8
- package/scripts/run-tests.mjs +23 -2
- package/scripts/scaffold-persona-v3-staging.mjs +1 -1
- package/skills/agent-skills-governance/SKILL.md +8 -2
- package/skills/alphacouncil-agent/SKILL.md +60 -9
- package/skills/public-equity-investing/SKILL.md +17 -0
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_ackman/provisional-derivations/change_value_bridge.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_ackman/provisional-derivations/power_map.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_aschenbrenner/provisional-derivations/compute_power_bridge.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_aschenbrenner/provisional-derivations/timeline_reverse_valuation.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_asness/provisional-derivations/crowding_cost_stress.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_asness/provisional-derivations/factor_decomposer.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_buffett/provisional-derivations/incremental_returns.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_buffett/provisional-derivations/owner_earnings_rebuilder.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_burry/provisional-derivations/capital_structure_reader.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_burry/provisional-derivations/mispricing_carry.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_cathie_wood/provisional-derivations/capture_valuation_bridge.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_cathie_wood/provisional-derivations/cost_adoption_curve.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_dalio/provisional-derivations/debt_driver_stress.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_dalio/provisional-derivations/regime_classifier.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_damodaran/provisional-derivations/story_dcf.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_druckenmiller/provisional-derivations/inflection_payoff.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_druckenmiller/provisional-derivations/liquidity_revision_map.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_duan_yongping/provisional-derivations/opportunity_cost.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_duan_yongping/provisional-derivations/user_value_evidence.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_fisher/provisional-derivations/research_productivity.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_fisher/provisional-derivations/scuttlebutt_graph.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_forensic_short/provisional-derivations/borrow_catalyst.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_graham/provisional-derivations/asset_floor.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_graham/provisional-derivations/normalized_earnings.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_jhunjhunwala/provisional-derivations/penetration_liquidity.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_jhunjhunwala/provisional-derivations/promoter_governance.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_klarman/provisional-derivations/cash_catalyst_compare.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_klarman/provisional-derivations/recovery_waterfall.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_li_lu/provisional-derivations/promise_integrity_ledger.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_li_lu/provisional-derivations/ten_year_return_bridge.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_lynch/provisional-derivations/category_classifier.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_lynch/provisional-derivations/story_numbers_check.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_marks/provisional-derivations/cycle_temperature.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_marks/provisional-derivations/implied_expectations.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_munger/provisional-derivations/failure_path_graph.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_munger/provisional-derivations/incentive_map.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_pabrai/provisional-derivations/discrete_payoff.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_pabrai/provisional-derivations/downside_floor.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_simons/provisional-derivations/leakage_audit.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_simons/provisional-derivations/oos_cost_test.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_sinclair/provisional-derivations/net_edge_sizer.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_sinclair/provisional-derivations/realized_vol_forecast.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_soros/provisional-derivations/reflexivity_graph.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_soros/provisional-derivations/reversal_monitor.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_taleb/provisional-derivations/payoff_ruin.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_thorp/provisional-derivations/edge_recalculator.derived-proxy-evidence.json +0 -64
- package/knowledge/solo-test/persona-v3-solo-test-formulas/master_thorp/provisional-derivations/fractional_kelly.derived-proxy-evidence.json +0 -64
|
@@ -0,0 +1,557 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turn a fund or index into typed-fact candidates, including look-through.
|
|
3
|
+
*
|
|
4
|
+
* A basket has no income statement, which is why twenty-five method seats used to abstain on
|
|
5
|
+
* QQQ. But Buffett defined look-through earnings in the 1990 shareholder letter for exactly
|
|
6
|
+
* this situation -- owning pieces of many businesses -- so aggregating the constituents'
|
|
7
|
+
* ratios by weight is the method's own answer, not a workaround bolted onto it.
|
|
8
|
+
*
|
|
9
|
+
* The aggregation itself lives in `funds.mjs`, which refuses to express an absolute-currency
|
|
10
|
+
* sum at all. This module's job is orchestration and honesty about coverage: every
|
|
11
|
+
* look-through fact carries the weight it was computed over, because a portfolio ratio
|
|
12
|
+
* measured across 8% of the basket is a different claim from one measured across 95%.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { LIMITS } from "./constants.mjs";
|
|
16
|
+
import { fetchFundHoldings, fetchFundMetadata, lookThroughAggregate, topHoldingsCoverage } from "./funds.mjs";
|
|
17
|
+
import { fetchIndexAggregate, INDEX_PROXIES, normalizeIndexSymbol } from "./index-aggregate.mjs";
|
|
18
|
+
import { fetchImpliedErp } from "./damodaran.mjs";
|
|
19
|
+
import { fetchBasketBreadth } from "./breadth.mjs";
|
|
20
|
+
import { fetchFundamentals } from "./fundamentals.mjs";
|
|
21
|
+
import { fetchUniverse } from "./sec.mjs";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* How many constituents may be resolved for a look-through pass.
|
|
25
|
+
*
|
|
26
|
+
* Every constituent costs one filing fetch, and weights decay fast enough that the tail buys
|
|
27
|
+
* coverage very slowly: on a cap-weighted basket the top forty names usually clear 60%.
|
|
28
|
+
* ponytail: fixed cap, revisit if a genuinely equal-weighted basket needs the tail.
|
|
29
|
+
*/
|
|
30
|
+
export const LOOK_THROUGH_MAX_CONSTITUENTS = 40;
|
|
31
|
+
export const LOOK_THROUGH_TARGET_COVERAGE = 0.6;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The operating-company facts a basket can supply by aggregating its constituents.
|
|
35
|
+
*
|
|
36
|
+
* Only ratios appear here. An absolute-currency look-through would be "ETF revenue", which is
|
|
37
|
+
* a category error `funds.mjs` refuses to express at all.
|
|
38
|
+
*/
|
|
39
|
+
/**
|
|
40
|
+
* Pack fact id -> the aggregation rule that governs it in `funds.mjs`.
|
|
41
|
+
*
|
|
42
|
+
* The two vocabularies differ on purpose: the aggregator is named for the SHAPE of a metric
|
|
43
|
+
* (a price multiple aggregates harmonically, a margin arithmetically), while a pack asks for
|
|
44
|
+
* the fact it reasons about. Keeping the translation explicit here means neither side has to
|
|
45
|
+
* rename anything, and an unmapped fact simply produces no look-through value rather than a
|
|
46
|
+
* silently mis-aggregated one.
|
|
47
|
+
*
|
|
48
|
+
* Only ratios appear. An absolute-currency look-through would be "ETF revenue", which is a
|
|
49
|
+
* category error `funds.mjs` refuses to express at all.
|
|
50
|
+
*/
|
|
51
|
+
export const LOOK_THROUGH_FACT_RULES = Object.freeze({
|
|
52
|
+
"financial.leverage": "leverage.debt_to_equity",
|
|
53
|
+
"valuation.revenue_growth": "growth.revenue_growth",
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Facts a constituent publishes that are NOT aggregable, and why.
|
|
58
|
+
*
|
|
59
|
+
* Owner earnings, NCAV and the downside values are absolute currency amounts. Summing them
|
|
60
|
+
* across a basket produces "the ETF's owner earnings", which is the exact category error the
|
|
61
|
+
* whole look-through discipline exists to prevent. Turning them into a portfolio number needs
|
|
62
|
+
* a per-constituent denominator -- market capitalisation -- so they become yields first. That
|
|
63
|
+
* is real and worth doing; it is simply not this pass, and pretending otherwise by summing is
|
|
64
|
+
* the failure mode, not the shortcut.
|
|
65
|
+
*/
|
|
66
|
+
export const LOOK_THROUGH_BLOCKED = Object.freeze({
|
|
67
|
+
"financial.owner_earnings": "absolute currency; needs a per-constituent market capitalisation to become a yield",
|
|
68
|
+
"financial.net_current_asset_value": "absolute currency; needs a per-constituent market capitalisation to become a ratio",
|
|
69
|
+
"valuation.downside_asset_value": "absolute currency; needs a per-constituent market capitalisation to become a ratio",
|
|
70
|
+
"valuation.downside_floor": "absolute currency; needs a per-constituent market capitalisation to become a ratio",
|
|
71
|
+
"capital_allocation.share_count": "a count, not a rate; it has no portfolio-level meaning",
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
export const LOOK_THROUGH_FACT_IDS = Object.freeze(Object.keys(LOOK_THROUGH_FACT_RULES));
|
|
75
|
+
|
|
76
|
+
const finite = (value) => typeof value === "number" && Number.isFinite(value);
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* The index whose published valuation describes a fund's portfolio.
|
|
80
|
+
*
|
|
81
|
+
* A cap-weighted tracker holds the index, so the index's aggregate P/E is the honest
|
|
82
|
+
* valuation of the fund's book -- and it is the only same-basis aggregate available for free.
|
|
83
|
+
* Derived by inverting the proxy map so the two directions cannot drift apart: whichever ETF
|
|
84
|
+
* stands in for an index is also the ETF that borrows that index's valuation.
|
|
85
|
+
*/
|
|
86
|
+
const VALUATION_INDEX_BY_FUND = Object.freeze(Object.fromEntries(
|
|
87
|
+
Object.entries(INDEX_PROXIES).flatMap(([index, proxy]) => (
|
|
88
|
+
[proxy.etf, ...(proxy.alternates || [])].map((etf) => [etf, index])
|
|
89
|
+
)),
|
|
90
|
+
));
|
|
91
|
+
|
|
92
|
+
export function valuationIndexFor(symbol) {
|
|
93
|
+
return VALUATION_INDEX_BY_FUND[String(symbol || "").trim().toUpperCase()] || null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Facts an index publishes about itself. Each carries its basis, because index P/E is quoted
|
|
98
|
+
* on incompatible bases and a fact that does not name its own is unusable.
|
|
99
|
+
*/
|
|
100
|
+
function valuationFacts(aggregate) {
|
|
101
|
+
const valuation = aggregate?.valuation;
|
|
102
|
+
if (!valuation || !finite(valuation.pe_trailing)) return [];
|
|
103
|
+
const facts = [];
|
|
104
|
+
const shared = {
|
|
105
|
+
source_kind: "market_snapshot",
|
|
106
|
+
source_url: valuation.source_url,
|
|
107
|
+
public_at: valuation.public_at,
|
|
108
|
+
observation_date: valuation.trade_date,
|
|
109
|
+
basis: valuation.basis,
|
|
110
|
+
title: `${valuation.name} valuation (${valuation.basis})`,
|
|
111
|
+
confidence: 0.8,
|
|
112
|
+
};
|
|
113
|
+
facts.push({
|
|
114
|
+
...shared,
|
|
115
|
+
fact_id: "index.aggregate_pe_ttm",
|
|
116
|
+
value: valuation.pe_trailing,
|
|
117
|
+
value_kind: "ratio",
|
|
118
|
+
unit: "multiple",
|
|
119
|
+
ratio_denominator: "trailing_twelve_month_earnings",
|
|
120
|
+
method: valuation.basis,
|
|
121
|
+
});
|
|
122
|
+
// The reciprocal is what a valuation method actually compares against a bond yield, so it
|
|
123
|
+
// is published as its own fact rather than left for each seat to recompute differently.
|
|
124
|
+
facts.push({
|
|
125
|
+
...shared,
|
|
126
|
+
fact_id: "index.aggregate_earnings_yield",
|
|
127
|
+
value: Number((1 / valuation.pe_trailing).toFixed(6)),
|
|
128
|
+
value_kind: "ratio",
|
|
129
|
+
unit: "decimal",
|
|
130
|
+
ratio_denominator: "price",
|
|
131
|
+
method: `reciprocal_of_${valuation.basis}_trailing_pe`,
|
|
132
|
+
});
|
|
133
|
+
if (finite(valuation.pe_forward)) {
|
|
134
|
+
facts.push({
|
|
135
|
+
...shared,
|
|
136
|
+
fact_id: "index.aggregate_pe_forward",
|
|
137
|
+
value: valuation.pe_forward,
|
|
138
|
+
value_kind: "ratio",
|
|
139
|
+
unit: "multiple",
|
|
140
|
+
ratio_denominator: "forward_twelve_month_earnings",
|
|
141
|
+
method: `${valuation.basis}_forward`,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
if (finite(valuation.dividend_yield)) {
|
|
145
|
+
facts.push({
|
|
146
|
+
...shared,
|
|
147
|
+
fact_id: "index.dividend_yield",
|
|
148
|
+
// Declared as percent by the source; the typed-fact contract is decimal.
|
|
149
|
+
value: valuation.dividend_yield / 100,
|
|
150
|
+
value_kind: "ratio",
|
|
151
|
+
unit: "decimal",
|
|
152
|
+
ratio_denominator: "price",
|
|
153
|
+
method: valuation.basis,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
return facts;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** Concentration and cost, which are properties of the wrapper rather than of the businesses. */
|
|
160
|
+
function structureFacts(holdings, metadata) {
|
|
161
|
+
const facts = [];
|
|
162
|
+
if (!holdings?.holdings?.length) return facts;
|
|
163
|
+
const shared = {
|
|
164
|
+
source_kind: "issuer_disclosure",
|
|
165
|
+
source_url: holdings.source_url,
|
|
166
|
+
public_at: holdings.public_at,
|
|
167
|
+
observation_date: holdings.as_of,
|
|
168
|
+
confidence: 0.9,
|
|
169
|
+
derivation: "rederived",
|
|
170
|
+
};
|
|
171
|
+
const sorted = [...holdings.holdings].sort((left, right) => (right.weight || 0) - (left.weight || 0));
|
|
172
|
+
const topTen = sorted.slice(0, 10).reduce((sum, row) => sum + (row.weight || 0), 0);
|
|
173
|
+
facts.push({
|
|
174
|
+
...shared,
|
|
175
|
+
fact_id: "fund.top_ten_weight",
|
|
176
|
+
value: Number(topTen.toFixed(6)),
|
|
177
|
+
value_kind: "ratio",
|
|
178
|
+
unit: "decimal",
|
|
179
|
+
ratio_denominator: "portfolio_weight",
|
|
180
|
+
method: "sum_of_ten_largest_published_weights",
|
|
181
|
+
title: `${holdings.symbol} top-ten concentration`,
|
|
182
|
+
});
|
|
183
|
+
// Herfindahl over published weights: one number that separates "a basket" from "three
|
|
184
|
+
// positions and some rounding".
|
|
185
|
+
const hhi = sorted.reduce((sum, row) => sum + ((row.weight || 0) ** 2), 0);
|
|
186
|
+
facts.push({
|
|
187
|
+
...shared,
|
|
188
|
+
fact_id: "fund.concentration_hhi",
|
|
189
|
+
value: Number(hhi.toFixed(6)),
|
|
190
|
+
value_kind: "ratio",
|
|
191
|
+
unit: "decimal",
|
|
192
|
+
ratio_denominator: "sum_of_squared_weights",
|
|
193
|
+
method: "herfindahl_over_published_weights",
|
|
194
|
+
title: `${holdings.symbol} concentration index`,
|
|
195
|
+
});
|
|
196
|
+
if (finite(metadata?.expense_ratio)) {
|
|
197
|
+
// Issuers publish the fee as a percent; the typed-fact contract is a decimal fraction.
|
|
198
|
+
// Passing it through unconverted is a hundredfold error that looks entirely plausible.
|
|
199
|
+
const asDecimal = metadata.expense_ratio_unit === "percent"
|
|
200
|
+
? metadata.expense_ratio / 100
|
|
201
|
+
: metadata.expense_ratio;
|
|
202
|
+
facts.push({
|
|
203
|
+
...shared,
|
|
204
|
+
fact_id: "fund.expense_ratio",
|
|
205
|
+
value: Number(asDecimal.toFixed(6)),
|
|
206
|
+
value_kind: "ratio",
|
|
207
|
+
unit: "decimal",
|
|
208
|
+
ratio_denominator: "net_assets",
|
|
209
|
+
derivation: "reported",
|
|
210
|
+
source_url: metadata.source_url || holdings.source_url,
|
|
211
|
+
public_at: metadata.public_at || holdings.public_at,
|
|
212
|
+
method: "issuer_published",
|
|
213
|
+
title: `${holdings.symbol} expense ratio`,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
return facts;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Resolve constituent fundamentals for a look-through pass.
|
|
221
|
+
*
|
|
222
|
+
* One filing fetch per constituent, bounded twice over: by `LOOK_THROUGH_MAX_CONSTITUENTS`
|
|
223
|
+
* and by stopping as soon as the target coverage weight is reached. A constituent that cannot
|
|
224
|
+
* be resolved -- a foreign filer, a share class the ticker map does not carry -- is skipped
|
|
225
|
+
* rather than substituted, and its weight simply does not count toward coverage. That keeps
|
|
226
|
+
* the coverage number honest, which is the only thing that makes the aggregate meaningful.
|
|
227
|
+
*/
|
|
228
|
+
/**
|
|
229
|
+
* True when a diagnostic names a fact the pack ended up producing anyway. Matching is by the
|
|
230
|
+
* fact id appearing in the note, so a note that names no fact is always kept.
|
|
231
|
+
*/
|
|
232
|
+
function factsProducedFor(note, facts) {
|
|
233
|
+
const produced = new Set(facts.map((fact) => fact.fact_id));
|
|
234
|
+
return [...produced].some((factId) => String(note).includes(factId))
|
|
235
|
+
|| (/implied equity risk premium/iu.test(note) && produced.has("valuation.implied_erp"))
|
|
236
|
+
|| (/valuation percentile/iu.test(note) && produced.has("cycle.valuation_percentile"));
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export async function resolveConstituentFacts(holdings, { signal, asOf = null, concurrency = 6 } = {}) {
|
|
240
|
+
const perHolding = new Map();
|
|
241
|
+
// The aggregate inherits whatever span its inputs covered; without carrying it the basket
|
|
242
|
+
// fact arrives as a bare number that no duration contract can accept.
|
|
243
|
+
const perHoldingPeriods = new Map();
|
|
244
|
+
const unavailable = [];
|
|
245
|
+
const ranked = [...holdings]
|
|
246
|
+
.sort((left, right) => (right.weight || 0) - (left.weight || 0))
|
|
247
|
+
.slice(0, LOOK_THROUGH_MAX_CONSTITUENTS);
|
|
248
|
+
if (!ranked.length) return { perHolding, perHoldingPeriods, unavailable, attempted: 0 };
|
|
249
|
+
|
|
250
|
+
let universe = null;
|
|
251
|
+
try {
|
|
252
|
+
universe = new Map((await fetchUniverse({ signal }))
|
|
253
|
+
.map((row) => [String(row.ticker).toUpperCase(), row.cik]));
|
|
254
|
+
} catch (error) {
|
|
255
|
+
return {
|
|
256
|
+
perHolding,
|
|
257
|
+
perHoldingPeriods,
|
|
258
|
+
unavailable: [`look-through: SEC ticker universe unavailable (${String(error?.message || error)})`],
|
|
259
|
+
attempted: 0,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const queue = [...ranked];
|
|
264
|
+
const worker = async () => {
|
|
265
|
+
for (let next = queue.shift(); next; next = queue.shift()) {
|
|
266
|
+
const ticker = String(next.ticker || "").toUpperCase();
|
|
267
|
+
const cik = universe.get(ticker);
|
|
268
|
+
if (!cik) { unavailable.push(`look-through ${ticker}: no SEC registrant for this ticker`); continue; }
|
|
269
|
+
try {
|
|
270
|
+
const derived = await fetchFundamentals({ cik, ticker, asOf, signal });
|
|
271
|
+
const facts = {};
|
|
272
|
+
const periods = {};
|
|
273
|
+
for (const [factId, metric] of Object.entries(derived.metrics || {})) {
|
|
274
|
+
if (!metric || !Number.isFinite(metric.value)) continue;
|
|
275
|
+
facts[factId] = metric.value;
|
|
276
|
+
if (metric.period_start && metric.period_end) {
|
|
277
|
+
periods[factId] = { start: metric.period_start, end: metric.period_end };
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
if (Object.keys(facts).length) perHolding.set(ticker, facts);
|
|
281
|
+
if (Object.keys(periods).length) perHoldingPeriods.set(ticker, periods);
|
|
282
|
+
} catch (error) {
|
|
283
|
+
unavailable.push(`look-through ${ticker}: ${String(error?.message || error)}`);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
await Promise.all(Array.from({ length: Math.min(concurrency, ranked.length) }, worker));
|
|
288
|
+
return { perHolding, perHoldingPeriods, unavailable, attempted: ranked.length };
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Aggregate constituent ratios into portfolio-level operating-company facts.
|
|
293
|
+
*
|
|
294
|
+
* `perHoldingFacts` is supplied by the caller rather than fetched here: resolving it means one
|
|
295
|
+
* filing per constituent, and the caller owns the budget for that. Passing an empty map is a
|
|
296
|
+
* valid, cheap run -- it yields no look-through facts and one explicit gap, which is the
|
|
297
|
+
* correct outcome and not a failure.
|
|
298
|
+
*/
|
|
299
|
+
/**
|
|
300
|
+
* The interval a basket-level aggregate covers: the widest span its contributing constituents
|
|
301
|
+
* reported. Stating a narrower one would claim coverage the inputs do not have, and stating
|
|
302
|
+
* none at all leaves the fact unusable by any duration contract.
|
|
303
|
+
*/
|
|
304
|
+
function aggregatePeriod(perHoldingPeriods, factId, tickers) {
|
|
305
|
+
let start = null;
|
|
306
|
+
let end = null;
|
|
307
|
+
for (const ticker of tickers) {
|
|
308
|
+
const span = perHoldingPeriods?.get(ticker)?.[factId];
|
|
309
|
+
if (!span?.start || !span?.end) continue;
|
|
310
|
+
if (!start || span.start < start) start = span.start;
|
|
311
|
+
if (!end || span.end > end) end = span.end;
|
|
312
|
+
}
|
|
313
|
+
return start && end ? { period_start: start, period_end: end } : {};
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
export function lookThroughFacts({ holdings, perHoldingFacts, perHoldingPeriods, factIds, holdingsMeta }) {
|
|
317
|
+
const facts = [];
|
|
318
|
+
const unavailable = [];
|
|
319
|
+
if (!holdings?.length) return { facts, unavailable };
|
|
320
|
+
const coverage = topHoldingsCoverage(holdings, { minWeight: LOOK_THROUGH_TARGET_COVERAGE });
|
|
321
|
+
for (const factId of factIds) {
|
|
322
|
+
const rule = LOOK_THROUGH_FACT_RULES[factId];
|
|
323
|
+
if (!rule) {
|
|
324
|
+
unavailable.push(`look-through ${factId}: ${LOOK_THROUGH_BLOCKED[factId] || "no aggregation rule is defined for this fact"}`);
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
// The aggregator reads one number per ticker; the rule name selects how it is combined.
|
|
328
|
+
const byTicker = new Map([...perHoldingFacts]
|
|
329
|
+
.filter(([, facts]) => Number.isFinite(facts?.[factId]))
|
|
330
|
+
.map(([ticker, facts]) => [ticker, facts[factId]]));
|
|
331
|
+
const aggregate = lookThroughAggregate({
|
|
332
|
+
holdings: coverage.holdings,
|
|
333
|
+
perHoldingFacts: byTicker,
|
|
334
|
+
factId: rule,
|
|
335
|
+
coverageWeight: coverage.coverage_weight,
|
|
336
|
+
});
|
|
337
|
+
if (!aggregate || !finite(aggregate.value)) {
|
|
338
|
+
unavailable.push(`look-through ${factId}: ${aggregate?.unavailable?.join("; ") || "no constituent supplied this fact"}`);
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
facts.push({
|
|
342
|
+
fact_id: factId,
|
|
343
|
+
value: aggregate.value,
|
|
344
|
+
value_kind: "ratio",
|
|
345
|
+
unit: "decimal",
|
|
346
|
+
ratio_denominator: `weight_${aggregate.method}`,
|
|
347
|
+
source_kind: "issuer_disclosure",
|
|
348
|
+
source_url: holdingsMeta?.source_url,
|
|
349
|
+
public_at: holdingsMeta?.public_at,
|
|
350
|
+
observation_date: holdingsMeta?.as_of,
|
|
351
|
+
...aggregatePeriod(perHoldingPeriods, factId, [...byTicker.keys()]),
|
|
352
|
+
confidence: 0.7,
|
|
353
|
+
derivation: "rederived",
|
|
354
|
+
method: aggregate.method,
|
|
355
|
+
coverage_weight: aggregate.coverage_weight,
|
|
356
|
+
title: `look-through ${factId} over ${aggregate.constituent_count} constituents`,
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
return { facts, unavailable };
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Compose everything a fund or index instrument can contribute.
|
|
364
|
+
*
|
|
365
|
+
* An index has no issuer to publish holdings, so it borrows its tracking ETF's -- labelled a
|
|
366
|
+
* proxy in the returned provenance, because the constituents themselves are a licensed asset
|
|
367
|
+
* and presenting borrowed weights as the index would be both a licensing and an accuracy
|
|
368
|
+
* claim this project has no basis for.
|
|
369
|
+
*/
|
|
370
|
+
export async function gatherInstrumentFacts({
|
|
371
|
+
symbol,
|
|
372
|
+
instrument,
|
|
373
|
+
perHoldingFacts = null,
|
|
374
|
+
lookThroughFactIds = [],
|
|
375
|
+
signal,
|
|
376
|
+
asOf = null,
|
|
377
|
+
} = {}) {
|
|
378
|
+
const facts = [];
|
|
379
|
+
const unavailable = [];
|
|
380
|
+
const provenance = {};
|
|
381
|
+
const normalized = normalizeIndexSymbol(symbol);
|
|
382
|
+
const proxy = INDEX_PROXIES[normalized];
|
|
383
|
+
const holdingsSymbol = instrument?.index_like ? proxy?.etf : symbol;
|
|
384
|
+
// A tracker has no valuation of its own to publish, so it reads the index it holds. Without
|
|
385
|
+
// this a fund run reported "WSJ publishes only three indices" as a gap while the very index
|
|
386
|
+
// it tracks was one of the three.
|
|
387
|
+
const valuationSymbol = instrument?.index_like ? normalized : (valuationIndexFor(symbol) || normalized);
|
|
388
|
+
if (!instrument?.index_like && valuationSymbol !== normalized) {
|
|
389
|
+
provenance.valuation_source = {
|
|
390
|
+
kind: "tracked_index_valuation",
|
|
391
|
+
index: valuationSymbol,
|
|
392
|
+
why: "a cap-weighted tracker holds the index, so the index aggregate describes the fund's book on the same basis",
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
if (instrument?.index_like) {
|
|
397
|
+
provenance.constituent_source = proxy
|
|
398
|
+
? { kind: "tracking_etf_proxy", etf: proxy.etf, licensor: proxy.licensor, why: proxy.why }
|
|
399
|
+
: { kind: "unavailable", why: "no tracking-ETF proxy is registered for this index" };
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Fee and size come from the issuer, not from the index: an index has no expense ratio.
|
|
403
|
+
// This was previously read off the index aggregate, which never carries one, so the fee
|
|
404
|
+
// fact was unreachable code that silently produced nothing.
|
|
405
|
+
const [aggregate, holdings, metadata, erp] = await Promise.all([
|
|
406
|
+
fetchIndexAggregate({ symbol: valuationSymbol, signal, asOf })
|
|
407
|
+
.catch((error) => ({ unavailable: [`index aggregate: ${String(error?.message || error)}`] })),
|
|
408
|
+
holdingsSymbol
|
|
409
|
+
? fetchFundHoldings(holdingsSymbol, { signal })
|
|
410
|
+
.catch((error) => ({ unavailable: [`fund holdings: ${String(error?.message || error)}`] }))
|
|
411
|
+
: Promise.resolve(null),
|
|
412
|
+
holdingsSymbol
|
|
413
|
+
? fetchFundMetadata(holdingsSymbol, { signal })
|
|
414
|
+
.catch((error) => ({ unavailable: [`fund metadata: ${String(error?.message || error)}`] }))
|
|
415
|
+
: Promise.resolve(null),
|
|
416
|
+
fetchImpliedErp({ signal, asOf })
|
|
417
|
+
.catch((error) => ({ unavailable: [`implied equity risk premium: ${String(error?.message || error)}`] })),
|
|
418
|
+
]);
|
|
419
|
+
|
|
420
|
+
facts.push(...valuationFacts(aggregate));
|
|
421
|
+
if (erp && finite(erp.latest)) {
|
|
422
|
+
// The premium the market is actually pricing, with where it sits in its own history. A
|
|
423
|
+
// level alone cannot say whether the market is paying up; the percentile is the claim.
|
|
424
|
+
facts.push({
|
|
425
|
+
fact_id: "valuation.implied_erp",
|
|
426
|
+
value: erp.latest,
|
|
427
|
+
value_kind: "ratio",
|
|
428
|
+
unit: "decimal",
|
|
429
|
+
ratio_denominator: "equity_over_riskfree",
|
|
430
|
+
source_kind: "published_dataset",
|
|
431
|
+
source_url: erp.source_url,
|
|
432
|
+
public_at: erp.public_at,
|
|
433
|
+
observation_date: erp.observation_date,
|
|
434
|
+
confidence: 0.85,
|
|
435
|
+
derivation: "reported",
|
|
436
|
+
method: erp.basis,
|
|
437
|
+
title: "Damodaran implied equity risk premium",
|
|
438
|
+
});
|
|
439
|
+
if (erp.percentile) {
|
|
440
|
+
facts.push({
|
|
441
|
+
fact_id: "cycle.valuation_percentile",
|
|
442
|
+
value: erp.percentile.percentile,
|
|
443
|
+
value_kind: "ratio",
|
|
444
|
+
unit: "decimal",
|
|
445
|
+
ratio_denominator: `rank_within_${erp.percentile.sample_size}_published_months`,
|
|
446
|
+
source_kind: "published_dataset",
|
|
447
|
+
source_url: erp.source_url,
|
|
448
|
+
public_at: erp.public_at,
|
|
449
|
+
observation_date: erp.observation_date,
|
|
450
|
+
confidence: 0.8,
|
|
451
|
+
derivation: "rederived",
|
|
452
|
+
method: `percentile_of_${erp.basis}_since_${erp.percentile.sample_start}`,
|
|
453
|
+
title: "implied equity risk premium percentile",
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
unavailable.push(...(erp?.unavailable || []));
|
|
458
|
+
unavailable.push(...(aggregate?.unavailable || []));
|
|
459
|
+
if (holdings?.holdings?.length) {
|
|
460
|
+
facts.push(...structureFacts(holdings, metadata));
|
|
461
|
+
// Breadth is computed from the basket rather than bought: every free screener that
|
|
462
|
+
// publishes it forbids the query, and the holdings are already in hand.
|
|
463
|
+
const breadth = await fetchBasketBreadth(holdings.holdings, { signal })
|
|
464
|
+
.catch((error) => ({ available: false, unavailable: [`breadth: ${String(error?.message || error)}`] }));
|
|
465
|
+
unavailable.push(...(breadth.unavailable || []));
|
|
466
|
+
if (breadth.available) {
|
|
467
|
+
const shared = {
|
|
468
|
+
source_kind: "market_snapshot",
|
|
469
|
+
source_url: holdings.source_url,
|
|
470
|
+
public_at: holdings.public_at,
|
|
471
|
+
observation_date: holdings.as_of,
|
|
472
|
+
value_kind: "ratio",
|
|
473
|
+
unit: "decimal",
|
|
474
|
+
derivation: "rederived",
|
|
475
|
+
confidence: 0.8,
|
|
476
|
+
coverage_weight: breadth.coverage_weight,
|
|
477
|
+
method: breadth.method,
|
|
478
|
+
};
|
|
479
|
+
facts.push({
|
|
480
|
+
...shared,
|
|
481
|
+
fact_id: "index.breadth_above_200dma",
|
|
482
|
+
value: breadth.weighted_above,
|
|
483
|
+
ratio_denominator: "measured_basket_weight",
|
|
484
|
+
title: "share of basket weight above its 200-day average",
|
|
485
|
+
});
|
|
486
|
+
if (finite(breadth.net_assets) && !finite(metadata?.aum)) {
|
|
487
|
+
facts.push({
|
|
488
|
+
...shared,
|
|
489
|
+
fact_id: "fund.aum",
|
|
490
|
+
value: breadth.net_assets,
|
|
491
|
+
value_kind: "monetary",
|
|
492
|
+
unit: "currency_units",
|
|
493
|
+
currency: "USD",
|
|
494
|
+
scale: 1,
|
|
495
|
+
ratio_denominator: undefined,
|
|
496
|
+
method: "sum_of_disclosed_units_at_last_close",
|
|
497
|
+
title: `${holdings.symbol} assets from disclosed positions`,
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
// The gap between weighted and counted breadth IS the concentration story: a
|
|
501
|
+
// cap-weighted basket can be above its average on weight while most members are below.
|
|
502
|
+
facts.push({
|
|
503
|
+
...shared,
|
|
504
|
+
fact_id: "index.breadth_counted_above_200dma",
|
|
505
|
+
value: breadth.counted_above,
|
|
506
|
+
ratio_denominator: "measured_constituent_count",
|
|
507
|
+
title: "share of measured constituents above their 200-day average",
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
provenance.holdings_as_of = holdings.as_of;
|
|
511
|
+
provenance.holdings_count = holdings.holdings.length;
|
|
512
|
+
}
|
|
513
|
+
unavailable.push(...(holdings?.unavailable || []));
|
|
514
|
+
unavailable.push(...(metadata?.unavailable || []));
|
|
515
|
+
|
|
516
|
+
if (holdings?.holdings?.length && lookThroughFactIds.length) {
|
|
517
|
+
let resolved = perHoldingFacts;
|
|
518
|
+
let resolvedPeriods = null;
|
|
519
|
+
if (!resolved) {
|
|
520
|
+
const constituents = await resolveConstituentFacts(holdings.holdings, { signal, asOf });
|
|
521
|
+
resolved = constituents.perHolding;
|
|
522
|
+
resolvedPeriods = constituents.perHoldingPeriods;
|
|
523
|
+
unavailable.push(...constituents.unavailable);
|
|
524
|
+
provenance.look_through = {
|
|
525
|
+
constituents_attempted: constituents.attempted,
|
|
526
|
+
constituents_resolved: resolved.size,
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
const through = lookThroughFacts({
|
|
530
|
+
holdings: holdings.holdings,
|
|
531
|
+
perHoldingFacts: resolved,
|
|
532
|
+
perHoldingPeriods: resolvedPeriods,
|
|
533
|
+
factIds: lookThroughFactIds,
|
|
534
|
+
holdingsMeta: holdings,
|
|
535
|
+
});
|
|
536
|
+
facts.push(...through.facts);
|
|
537
|
+
unavailable.push(...through.unavailable);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
return {
|
|
541
|
+
symbol,
|
|
542
|
+
research_model: instrument?.research_model || "market_instrument",
|
|
543
|
+
provenance,
|
|
544
|
+
facts,
|
|
545
|
+
// Several facts have more than one route -- the implied ERP and the valuation percentile
|
|
546
|
+
// are computed from the published workbook when the index feed cannot supply them -- and
|
|
547
|
+
// each route reports its own failure. Keeping a note about a fact the pack actually
|
|
548
|
+
// produced reads as a gap that is filled, which is worse than saying nothing: it invites
|
|
549
|
+
// a reader to go and solve a problem that is already solved.
|
|
550
|
+
unavailable: unavailable.filter((note) => !factsProducedFor(note, facts)),
|
|
551
|
+
limits: {
|
|
552
|
+
max_constituents: LOOK_THROUGH_MAX_CONSTITUENTS,
|
|
553
|
+
target_coverage: LOOK_THROUGH_TARGET_COVERAGE,
|
|
554
|
+
fetch_timeout_ms: LIMITS.QUOTE_FETCH_MS,
|
|
555
|
+
},
|
|
556
|
+
};
|
|
557
|
+
}
|