The web-session loop hardcodes max_iterations=50 with no config surface;
heavy multi-step pipelines (a four-layer concept-scoring sweep measured at
52 iterations of real progress) exceed it and die with 'reached max
iterations'. Default stays 50; the cap is read through the config accessor
like every other tuning knob.
Same transport fix as the loader's (review of #1474): the query-string
token leaks into request-exception logs; the endpoint accepts
Authorization: Bearer, so the URL now carries only the format flag.
The EDB rows carry their measurement as a string ("value": "5.4"), so the
grounding evidence extractor — which indexes numeric leaves only — never
saw it while the same row's numeric indicatorcode did. Coercing the
measurement gives the verifier the true values; whether percent claims
verify against generic-tool leaves at all is a wider upstream grounding
question (metric pool admits analysis metrics only), noted separately.
get_cn_macro_series (MacroIndustryData: China macro/regional/industry EDB
— FRED only covered US/global until now), get_cn_announcements
(AnnouncementData: A-share/HK/fund filings with highlighted excerpts —
get_sec_filings covers SEC only) and search_broker_reports
(FinancialResearchReport: the Juyuan report library, coexisting with the
eastmoney-backed get_research_reports). One thin shared client
(gildata_srv.py: JSON-RPC POST + format=json, own throttle bucket, dual
Accept header), routed api_names echoed so a mis-routed NL question is
visible to the agent, rows capped via limit, key-gated on GILDATA_TOKEN
with an optional GILDATA_SRV_TOOL_URL override. News/screening/FinQuery
deliberately left to the existing tools. MCP surface 75 -> 78.
A fund's NAV is its dated price observation, but the generic leaf aliases
only knew close/price-style names — every unit_nav figure in a get_fund_nav
answer was 'no matching tool evidence', the answer gate rejected the run
twice, and the final answer shipped degraded with the NAV figures redacted
(measured live). Adds unit_nav/accumulated_nav/adjusted_nav (plus the
Chinese spellings) to the price aliases, pinned by a verifier-level test.
codes/symbols/tickers are the grounding gate's _SYMBOL_ARGUMENT_KEYS: a tool
carrying them demands a search_symbol identity lock from a previous batch,
and the resolver cannot resolve off-exchange fund codes (eastmoney/yahoo
know no 110022.OF) — measured live, the agent loop bounced between
identity_required and identity_conflict forever. The tool self-resolves
identities deterministically (exact ref_code match against the vendor) and
echoes fund_name in every result, so the gate added no safety. Renamed to
'funds' with a regression test pinning the parameter set against the gate's
key set.
Off-exchange funds publish daily NAV, not OHLCV, so this lands as an
agent tool instead of stretching the loader contract: NetFundUnitValueReport
behind the same ParamCandidateRecall + disk-cache machinery (new otc_fund
wiring). Serves unit/accumulated/adjusted NAV and daily growth, ascending,
most-recent limit, per-fund errors never abort the batch; exchange-listed
codes are rejected with a pointer to get_market_data. Key-gated on
GILDATA_TOKEN; exposed as MCP tool #75 (manifest + six-README lists).
HKStockDailyQuotes for 00700.HK-style symbols (raw bars, volume already in
shares, stamped raw as a per-market exception after measuring 00700.HK) and
IndexDailyQuote for exchange-specific CN index codes (000xxx.SH / 399xxx.SZ,
so 000001.SZ stays Ping An Bank). Both tools need a Juyuan internal code:
ParamCandidateRecall with an exact ref_code match, cached to
~/.vibe-trading/cache/gildata-codes.json so a symbol costs one round-trip
per machine. Joins the hk_equity chain tail. US equities excluded — this
token's US history is sparse before ~2022 (12 rows in 2020, 134 in 2021),
which would silently corrupt backtests.
Review of #1474: request exceptions (DNS failure, timeout) embed the full
URL in their message, so a query-string token leaks into error logs. The
endpoint accepts Authorization: Bearer (measured against the live service:
full payload with the header, 1001 without any credential) — the token now
rides the header and the URL carries only the format flag.
The raw-api endpoint answers 400 unless Accept names both JSON and
text/event-stream — caught live after the first deploy, pinned with a
header assertion in the fetch test.
Mirrors the tushare token plumbing end to end: configured/hint fields on
the GET response, token/clear on the PUT, dotenv persistence with env
sync and hot config reset, desktop secure-credential ownership, and the
password input with clear checkbox in all eight locales.
Token-gated source talking to api.gildata.com with JSON-RPC POSTs:
StockDailyQuote with restorationStatus=1 serves forward split-and-dividend
adjusted dailies (caliber split_dividend, measured against a live payload),
volume converted from wan-shares to shares, avgprice/prevclose ignored
(different adjustment basis), silent rows:[] treated as no-data so the
fallback chain keeps walking. Joins the a_share chain tail; unavailable
without GILDATA_TOKEN so existing users see no behavior change.
Address PR review feedback (#1231): reordering a market's chain is now
user-facing, but sources differ in adjustment basis (yahoo/yfinance serve
raw OHLC while tencent/eastmoney/tushare serve adjusted prices), so a
reordered chain can silently change backtest numbers. Document the caveat
next to the setting (card + .env.example) in all seven locales; the
provenance stamp itself stays with the #1207 items 6/7 fix.
Co-Authored-By: Claude <noreply@anthropic.com>
ci_grep_gates gate (e) rejects raw os.getenv outside src/config/ — the
gate run after the feature caught it. Switch the refresh snapshot to
get_env_value (an un-cached pass-through, so hot-apply semantics are
unchanged), imported inside the function like the sibling loaders'
accessor usage.
Co-Authored-By: Claude <noreply@anthropic.com>
New SourcePrioritySettings card below the data-source form: pick a market,
reorder its fallback chain with up/down buttons (boundary-disabled), reset
to default, or leave it Default-badged. Saving sends every market in one
PUT — a non-default draft persists its order, a default-equal draft sends
null to clear residue in ~/.vibe-trading/.env — and the backend hot-applies
it. Invalid persisted overrides surface an inline warning naming the env
var. Copy added for all 7 locales (parity test enforced); api.ts gains
SourceOrderEntry/SourceOrderUpdate types on the existing data-source
endpoints.
Co-Authored-By: Claude <noreply@anthropic.com>
FALLBACK_CHAINS order was hardcoded; users with paid feeds (e.g. Tushare)
could not prioritize them without editing code. Add one env var per market
(MARKET_DATA_ORDER_<MARKET>, e.g. tushare-first for A-shares) whose value
must be a permutation of the market's default chain — invalid values warn
and keep the default, so a typo can never strip a market of sources.
- registry: snapshot default chains; refresh_source_order_overrides()
reassigns chains in place (dict identity preserved for by-name importers)
and is snapshot-gated, so override-free environments never touch
FALLBACK_CHAINS. Hooked at import, _ensure_registered() and fetch start.
- market_data: auto-detected groups start at the override's head; explicit
source requests, local:/qveris/tickerall codes and the
fallback_chain_provider test hook keep their existing semantics.
- settings API: GET /settings/data-sources returns per-market
default/effective/override state; PUT validates permutations (400 before
persisting), writes ~/.vibe-trading/.env and hot-applies in-process.
- env_schema: declare the 12 vars on DataConfig for visibility.
- tests: registry machinery, market_data routing guards, settings API
round-trip/reset/validation, env defaults, conftest shell scrub.
Default chains are byte-for-byte unchanged.
Co-Authored-By: Claude <noreply@anthropic.com>
The fundamental factor zoo (zoo/fundamental/, 4 PIT-safe alphas) shipped
in v0.1.11 and has a frontend card in AlphaZoo, but the API whitelist was
never updated — GET /alpha/list?zoo=fundamental and POST /alpha/bench both
reject it with 400 "unknown zoo 'fundamental'".
Add "fundamental" to _VALID_ZOOS so both endpoints accept it.
Co-Authored-By: Claude <noreply@anthropic.com>
kimi-k3 rejects any temperature other than 1 ("invalid temperature:
only 1 is allowed for this model"), same as kimi-k2, but the forcing
guard only matched the kimi-k2 prefix — so a default
LANGCHAIN_TEMPERATURE=0.0 config fails on every request with kimi-k3.
Replace the hardcoded prefix tuple with a K-family regex
(kimi-k<digits> + kimi-for-coding) so kimi-k3 and future K-series
reasoning models are covered without another whack-a-mole patch.
Verified against the Kimi for Coding endpoint: both kimi-k3 and its
k3 alias return the temperature error; moonshot-v1-* models are
unaffected. Note: bare aliases like "k3" are intentionally out of
scope for the name-based guard.
Co-Authored-By: Claude <noreply@anthropic.com>
Responding to upstream review feedback:
1. All skill bodies converted to English (matching bundled skills like
akshare). Some Chinese wording was ambiguous in an international project.
2. Added macro constraints (demographic clock / consumption trend /
generational shift) per reviewer's point that a consumer-name pick
should weigh long-term macro headwinds:
- thesis-tracker: new red line on macro-trend reversal for
consumer/property/education names.
- value_investing_committee Li Lu agent: mandatory demographic-clock +
consumption-trend + generational-shift section for consumer-dependent
names; a consumer name cannot score high 10-year certainty without
addressing demographics.
No structural changes; counts unchanged (85 skills, 70 tools, 30 presets).
Co-Authored-By: Claude <noreply@anthropic.com>
An 8-part publication-grade deep-dive on a single company (~120k words):
cognitive reset / moat / profit engine / hidden assets / era variable /
financials / management / valuation+redlines. The core IP is the strict
fact-check checklist (5 pseudo-precision traps + 7 revision checks) and
the cross-article consistency scan.
Adapted from ai-berkshire's deep-company-series.md. Cross-article scan
reuses report_audit (extract numbers across 8 articles) + financial_rigor
cross_validate (flag >1% deviations) — closes the loop with P1's tools.
Co-Authored-By: Claude <noreply@anthropic.com>
P3 of the ai-berkshire fusion — small, broad-impact methodology additions:
- data-routing: add a 'Data Verification Discipline' section — cross-check
material figures across >=2 sources, flag >1% deviations as caliber
mismatches, use financial_rigor's cross_validate for exact comparison,
mark unverified numbers. Pairs with the cross_validate tool added in P1.
- research-discipline (new skill, analysis): a 60-second self-bias checklist
run at the start of any research task — leader-bias, English-bias,
narrative-bias, confirmation-bias, recency-bias, with concrete corrections.
Covers the reasoning layer (vs cross_validate=numbers, report_audit=output).
No code changes, no new deps. Existing data-routing tests still pass (4/4).
Co-Authored-By: Claude <noreply@anthropic.com>
The preset YAML was on disk and loadable (inspect_preset valid=True), but
run_swarm refused preset_name='value_investing_committee' as 'Unknown preset'
because _PRESET_NAMES is derived from _PRESET_KEYWORDS, which the new preset
was not added to. The LLM then fuzzy-matched to the similarly-named built-in
investment_committee and ran the wrong team.
Register value_investing_committee in _PRESET_KEYWORDS (value-investing /
Buffett / Munger / Duan Yongping / Li Lu keywords) and add its
{company}/{market} variables to _build_variables.
Co-Authored-By: Claude <noreply@anthropic.com>
LLMs routinely pass '15%' as 15 instead of 0.15, which made
three_scenario_valuation compound at 1500% and return absurd target prices
(23.5 x 16^3 = 96256 instead of 35.74). The math was correct for the input
given, but the tool silently accepted an unreasonable growth rate.
Now |growth| > 1 is treated as a percent and divided by 100, with a
growth_normalized_from_percent flag and note in the result. Description
also clarified ('0.15 for 15%').
Co-Authored-By: Claude <noreply@anthropic.com>
loop.py dedups non-repeatable tools by name (a tool already in _called_ok
is refused on a second call). Both tools are read-only and idempotent but
were left at the default repeatable=False, so calling financial_rigor
twice in one session (e.g. verify_valuation then three_scenario) hit a
'cached result, cannot re-invoke' refusal. Set repeatable=True on both.
Co-Authored-By: Claude <noreply@anthropic.com>
Ports the ai-berkshire value-investing methodology into first-class
Vibe-Trading tools / skills / swarm preset, rewritten for the BaseTool +
SKILL.md + swarm model (no Claude Code slash-commands or TeamCreate).
Tools (auto-discovered BaseTool subclasses, pure stdlib):
- financial_rigor: exact-decimal verification — verify_market_cap,
verify_valuation, cross_validate, benford, calc, three_scenario. The calc
evaluator walks an AST in the Decimal domain (0.1 + 0.2 == 0.3 exactly),
so there is no eval and no IEEE-754 drift.
- report_audit: markdown data-point extraction -> random sample -> PASS/FAIL
verdict gate. A single-source failure now correctly FAILs the report
(the source logic silently WARNed instead).
Skills (markdown methodology):
- bottleneck-hunter: supply-chain bottleneck arbitrage — decompose a
super-trend to Layer 2/3 choke points with mandatory valuation gates.
- thesis-tracker: post-buy discipline — 5-sentence thesis, falsifiable
assumptions, red lines, 1-10 health score.
- management-deep-dive: management integrity / ability / capital-allocation
/ governance with Duan Yongping's 3-question verdict.
- private-company-research: 6-lens pre-IPO framework (business / financial /
competitive / risk / tech / alternative-data) with confidence labeling
and signal-consistency cross-validation.
Swarm preset:
- value_investing_committee: four adversarial master perspectives
(Buffett / Munger / Duan Yongping / Li Lu) plus a chair synthesizing
consensus and contradictions into a verdict.
63 new tests; EXPECTED_PRESET_COUNT bumped 29 -> 30.
Inspired by https://github.com/xbtlin/ai-berkshire.
Co-Authored-By: Claude <noreply@anthropic.com>