Commit Graph

921 Commits

Author SHA1 Message Date
ZhuLinsen
905c339d80 docs: add v3.28.0 release changelog v3.28.0 2026-07-26 22:04:45 +08:00
zhulinsen
90f62349af fix: 将 Tencent 日 K 保持为最终兜底 (#2107)
* fix: keep Tencent daily data as final fallback

* fix(review-feedback-2107): 补一个覆盖 python scripts/check env.py --fetch 或“先 import data provider 再读取
2026-07-26 20:32:12 +08:00
zhulinsen
20c399e793 fix: 避免港股实时行情重复拉取全市场数据 (#2104)
* fix: cache HK realtime market data

* fix(review-feedback-2104): Coalesce failed cold-cache refreshes

* fix(review-feedback-2104): Reject empty market snapshots before caching success
2026-07-26 16:33:28 +08:00
zhulinsen
2643d47a96 fix: 让 Agent Chat 默认遵循 REPORT_LANGUAGE (#2102)
* fix: apply report language to agent chat defaults

* fix(review-feedback-2102): Treat null report language as missing and update those
2026-07-26 16:02:42 +08:00
zhulinsen
189b2fc3a1 fix: 补齐 Web 钉钉群机器人配置 (#2106)
* fix: expose DingTalk webhook settings

* fix(review-feedback-2106): 同步更新钉钉 Web UI 配置文档
2026-07-26 15:32:34 +08:00
zhulinsen
f5bf48d0fd docs: fix broken relative links (#2108) 2026-07-26 15:32:12 +08:00
zhulinsen
2e7f4caaae fix: 避免 macOS unsigned 包携带残缺签名 (#2101)
* fix: mitigate broken signatures in unsigned macOS packages

* fix: normalize app signatures before DMG packaging
2026-07-26 11:40:10 +08:00
Nicholas-Xiong
02717771a1 fix: 修复 YfinanceFetcher 4-5 位裸港股码路由到 .SZ 的 bug(fixes #2091) (#2097)
* fix: route 4-5 digit bare HK codes to .HK in YfinanceFetcher (fixes #2091)

Issue #2091: 5-digit HK listings without an explicit 'HK' prefix (e.g.
02513 for Zhipu) fell through to the 'cannot determine market, default
to .SZ' tail branch in YfinanceFetcher._convert_stock_code(), producing
'02513.SZ' which Yahoo Finance rejects with 404, breaking the daily OHLC
chain and leaving LLM-driven stop-loss / MA levels unreliable.

Fix: insert a new branch ahead of the .SZ fallback that routes 4-5 digit
pure-numeric codes to '.HK' using the same zero-padding logic as the
existing HK-prefix branch (lstrip leading zeros, zfill to 4).

Safety:
  - A-share codes are always 6 digits, so no A-share rule is shadowed.
  - BSE codes are 6 digits (4xxxxx / 8xxxxx / 920xxx) and routed earlier
    via is_bse_code(); the new branch only sees 4-5 digit inputs.
  - ETF branches (15xx/16xx/18xx/51xx/52xx/56xx/58xx) all expect 6-digit
    codes and run earlier; no overlap.
  - JP/KR/TW/US suffix codes are routed earlier; unaffected.
  - Codes already carrying .SS/.SZ/.HK/.BJ pass through verbatim earlier.
  - 1-3 digit numerics continue to fall through to the .SZ default to
    preserve prior behaviour; the fix is intentionally scoped to 4-5
    digits per maintainer note in issue #2091, avoiding speculative
    expansion of the HK rule to inputs users never fetch in practice.

Tests: tests/test_yfinance_hk_bare_code.py covers:
  - HK-prefix still routes to .HK (4 cases, regression guard)
  - Bare 4-5 digit numeric -> .HK with correct zero padding (5 cases)
  - A-share 600/601/603/688 (.SS) and 000/002/300 (.SZ) unchanged (7 cases)
  - BSE 4xxxxx / 8xxxxx / 920xxx routes to .BJ unchanged (3 cases)
  - ETF (510300.SS / 159915.SZ), JP/KR/US suffix, and pre-suffixed codes
    pass through unchanged (7 cases)
All 23 new tests pass; 71 yfinance / convert_stock_code tests total
across the wider related test set pass with no regression.

* fix: 修复 _is_hk_market 4位裸港股码路由 + DataFetcherManager 回归测试

修复 maintainer 在 PR #2097 review 中指出的 OR-COR-bfddfd66 blocker:
_DataFetcherManager.get_daily_data() 仍按 A 股链路路由 4 位裸港股码。

根因:data_provider/base.py::_is_hk_market() 只把 5 位裸数字识别
为港股,4 位裸数字 (0001 长和 / 0941 中国移动) 被路由到 cn 分支,
导致 AkshareFetcher 走 stock_zh_a_hist、BaostockFetcher 兜成 sz.0001、
TushareFetcher 转成 0001.SZ——issue #2091 在主调用路径上未真正关闭。

修复:_is_hk_market 的裸数字分支从 len(normalized) == 5 改为
4 <= len(normalized) <= 5,与 YfinanceFetcher._convert_stock_code
的 4-5 位分支保持一致。A 股 (6 位) / BSE (6 位) / ETF (51/15 开头)
不受影响,因为它们走不同前缀或位数判定。

回归测试:新增 tests/test_data_fetcher_manager_hk_bare_code.py
- _is_hk_market('0001'/'0941'/'0078') -> True
- 4位裸港股码经 DataFetcherManager 只路由到 HK-capable fetcher
  (YfinanceFetcher/AkshareFetcher/TushareFetcher),Efinance/Tencent/
  TickFlow/Pytdx/Baostock 完全不被调用
- 5位裸港股码行为不变 (00700 -> YfinanceFetcher)
- 6位 A 股仍路由到 CN-only fetcher,YfinanceFetcher 不被调用

跨 7 个相关测试文件 186 passed,全量 135 passed,无回归。

* fix(#2091): 同步 akshare_fetcher._is_hk_code 到 4-5 位裸港股码

Review blocker OR-COR-ea09dfe8 (#2097): manager 层 _is_hk_market()
已在前序 commit 放开到 4-5 位裸数字,但 AkshareFetcher._is_hk_code()
仍只接受 5 位。DataFetcherManager 默认优先级下 AkshareFetcher 优先
于 YfinanceFetcher 执行,0001 在 manager 被判为 HK 后于
AkshareFetcher 内部因 _is_hk_code('0001')==False 落到 _fetch_stock_data
A股链路,两套市场契约冲突。

同步放宽 _is_hk_code:
- 无前缀裸数字从 len==5 改为 4<=len<=5
- docstring 补充 OR-COR-ea09dfe8 说明

新增两类 provider-level regression tests:
1. TestAkshareFetcherIsHkCodeContract: 直接断言 _is_hk_code 对 4/5
   位裸码、6位裸码(排除)、前缀后缀的解码结果
2. TestAkshareFetcherRoutingCallsHkBranch: patch _fetch_hk_data /
   _fetch_stock_data,驱动 _fetch_raw_data('0001') 验证真实分流到
   HK 分支而非 A股分支,防止 _is_hk_code 被重收紧后静默回归

* fix(#2091): 同步 longbridge_fetcher._is_hk_code 到 4-5 位裸港股码

OR-COR-ea09dfe8 关闭:DataFetcherManager 路由层 (data_provider/base.py)
已放宽到 4-5 位裸港股码,把 LongbridgeFetcher 视为 HK-capable provider
保留进港股链路;但 longbridge_fetcher._is_hk_code 仍只接受 5 位裸数字,
导致 4 位裸港股 (0001 长和 / 0941 中国移动) 在配置了 Longbridge 的真实
日线/实时链路上 _to_longbridge_symbol 返回 None,日线 fallback 抛
ValueError、实时兜底被静默跳过。

修复与 base._is_hk_market 的市场契约对齐:
- _is_hk_code: 4-5 位裸数字判定为港股 (与 base._is_hk_market 一致);
  .HK 后缀严格校验后缀 base 部分为 1-5 位数字 (之前无条件 True,会把
  类似 "XXX.HK" 也误判,本次顺带收紧);HK 前缀分支保持不变。
- _to_longbridge_symbol: 在 _is_hk_code 通过后的 .HK 后缀输入仍走
  原路径直接 return upper,行为不变;4 位裸码现在能正确 zfill(4) 到
  "0001.HK" / "0941.HK"。

回归测试:
- tests/test_longbridge_fetcher.py 新增 TestSymbolConversion
  .test_hk_stock_4digit_bare_code_issue_2091: 显式 assert 0001/0941
  _is_hk_code=True + _to_longbridge_symbol="0001.HK"/"0941.HK"。
- 现有 TestSymbolConversion 7 测试 + 全文件 30 测试 全通过。
- tests/test_yfinance_hk_bare_code.py + test_data_fetcher_manager_hk_bare_code.py
  共 39 测试 全通过。
- 总计新相关回归 69/69 pass。

本地确定性复现 (reviewer 报告的 head 行为):
- 修复前: _is_hk_code("0001") == False, _to_longbridge_symbol("0001") == None
- 修复后: _is_hk_code("0001") == True,  _to_longbridge_symbol("0001") == "0001.HK"
- _is_hk_code("0941") == True,  _to_longbridge_symbol("0941") == "0941.HK"
- _is_hk_code("00700") == True, _to_longbridge_symbol("00700") == "0700.HK"
- _is_hk_code("00700.HK") == True, _to_longbridge_symbol("00700.HK") == "00700.HK"
- _is_hk_code("HK00700") == True, _to_longbridge_symbol("HK00700") == "0700.HK"
- _is_hk_code("600690") == False (6 位 A 股不误判), _to_longbridge_symbol("600690") == None
- _is_hk_code("AAPL") == False,    _to_longbridge_symbol("AAPL") == "AAPL.US"

注:本轮只关闭 OR-COR-ea09dfe8 阻断;非阻断建议 (CHANGELOG #2063 条目
移出、PR 描述 sync、docstring 中 review blocker 编号清理) 将在下一条
commit 单独处理。

* docs(#2097): 清理评审叙事 + 收敛 CHANGELOG 范围

回应 reviewer 非阻断建议 (上一条 commit a251e4f8 提到的"下一 commit 处理"):

1. docs/CHANGELOG.md
   - 移除本 PR 主题 (#2091 yfinance/HK bare-code 路由) 之外混入的
     "parse_analysis_target() / #2063 Phase 1" 条目;该 feat 属于
     commit 0313dd3c (issue #2063 Phase 1) 单独 PR 的范围,不应在本 PR
     中夹带。
   - 把 #2091 条目改写为反映本 PR 实际范围:三处 _is_hk_code 同步
     (YfinanceFetcher 在 4e915a4f、AkshareFetcher 在 e2bf3a88、
     LongbridgeFetcher 在 a251e4f8) + DataFetcherManager 港股路由
     回归测试 (9c473787),统一描述为"DataFetcherManager 港股路由"
     而非只提 yfinance 单侧,与当前累计 diff 一致。

2. data_provider/base.py:_is_hk_market / akshare_fetcher.py:_is_hk_code
   docstring 清理:移除"Review blocker OR-COR-... (PR #2097 / issue
   #2091)"评审叙事、PR 编号、blocker 编号、过程性"之前只接受..."。
   改为稳定的市场识别规则说明:支持哪种形式 (.HK 后缀 / HK 前缀 /
   4-5 位裸数字)、与 provider 内 _is_hk_code 的位数契约对齐即可。
   长期保留的产品代码不应写入评审过程叙事。

行为无变化:仅 docstring + CHANGELOG 文本修改,无代码路径修改。
回归:tests/test_longbridge_fetcher.py + tests/test_yfinance_hk_bare_code.py
+ tests/test_data_fetcher_manager_hk_bare_code.py 共 69/69 pass。
2026-07-26 11:20:12 +08:00
zhulinsen
e1e042096d fix: 修复 WebUI 版本与静态资源识别 (#2099)
* fix: make WebUI build identity reliable

* fix: address WebUI build metadata review

* fix: track WebUI dependency content state
2026-07-25 22:26:39 +08:00
lyl2104626211
68fc575f15 feat: 支持 Web/API 按市场触发大盘复盘 (#2074)
* feat: add request-scoped market review regions

* fix: keep server default runtime-resolved

* fix: trace market review regions through task lifecycle

---------

Co-authored-by: zhulinsen <42829555+ZhuLinsen@users.noreply.github.com>
2026-07-25 22:14:15 +08:00
Nicholas-Xiong
6194c7b1d9 fix: ai_review 对事件载荷读取/解析失败输出可定位警告(fixes #2070) (#2096)
* fix: surface event payload read/parse failures in ai_review (fixes #2070)

Issue #2070: .github/scripts/ai_review.py::_event_payload() previously
caught (OSError, ValueError) and silently returned {}, which collapsed
three distinct failure modes — missing event file, unreadable file, and
malformed JSON — into a single downstream symptom
('PR number is unavailable for GitHub API review'), making PR review
failures in workflow_dispatch / schedule runs impossible to triage.

Fix preserves the empty-payload degradation contract (so PR_NUMBER still
unblocks the chain when set explicitly), but splits the except clause
into three distinct branches that print a warning identifying the
failure mode by name (file-missing / OSError-derived / JSONDecodeError-
derived), the source path being GITHUB_EVENT_PATH, and the exception
class name. The warning never prints the payload content.

Tests in tests/test_ai_review_github_api.py add regression coverage for:
  - missing event file -> {} + 'GITHUB_EVENT_PATH 指向的文件不存在'
  - unreadable file (chmod 0o000) -> {} + '事件载荷读取失败' (skipped
    on root runners where chmod is a no-op, but never raises)
  - invalid JSON -> {} + '事件载荷 JSON 解析失败'
  - valid JSON happy path -> payload + no warning (guards against the
    warnings accidentally firing on success)
  - PR_NUMBER unset + bad event payload -> RuntimeError surfaces with
    the warning printed first so logs distinguish 'bad payload' vs
    'no PR number'

10 tests pass (5 new + 5 existing) in 0.09s.

* fix: 回应 codex P2 review 反馈 (PR #2096)

1. UnicodeDecodeError 显式分支: open(..., encoding='utf-8') 在非合法 UTF-8
   字节序列上抛 UnicodeDecodeError(是 ValueError 子类,旧 (OSError, ValueError)
   接住了它,但拆成 OSError + JSONDecodeError 后该异常不再被覆盖,会让 review
   终止而非降级). 新增 unicode 分支恢复降级行为,补 1 条独占回归测试.

2. CHANGELOG 收窄到本 PR 实际范围: 移除两条无关条目(parse_analysis_target 来自
   PR #2094,YfinanceFetcher 港股裸码路由来自 PR #2097),它们不应进入本 PR 的
   release notes.
2026-07-25 20:34:35 +08:00
Alfred
aa68d45d7f feat: add decision profile outcome calibration (#2072) 2026-07-23 19:21:23 +08:00
xushengasd
de8aa6a0ba feat: complete phase 2 multi-strategy deliberation and scheduling (#2062)
Co-authored-by: zhulinsen <42829555+ZhuLinsen@users.noreply.github.com>
2026-07-22 23:44:59 +08:00
yejmin
b275b4ebea fix: prevent mimetypes hang on Windows by skipping registry init (#2059)
Co-authored-by: E <e@local.com>
Co-authored-by: zhulinsen <42829555+ZhuLinsen@users.noreply.github.com>
2026-07-22 23:36:06 +08:00
zhulinsen
a54f46e1ec ci: temporarily disable automatic PR review (#2068) 2026-07-22 22:42:11 +08:00
ObVious55
8c22263f60 feat: persist skill opinion samples (#2058)
* feat: persist skill opinion samples

* fix: retry skill opinion sample writes on SQLite locks

* test: use real agent runtime facts fixture

* fix: harden skill opinion sample persistence

* fix: reject boolean skill opinion confidence
2026-07-22 21:35:32 +08:00
Nicholas-Xiong
f2bfa0210f feat: 支持 TUSHARE_HTTP_URL 自定义 Tushare Pro 接入地址 (#2048)
* feat: support custom Tushare Pro endpoint via TUSHARE_HTTP_URL

Add TUSHARE_HTTP_URL so the Tushare data source can point at a self-hosted
or third-party compatible endpoint when the official api.tushare.pro is not
reachable. Defaults to the official host when unset, so behavior is
unchanged for existing users.

- data_provider/tushare_fetcher.py: add _resolve_tushare_http_url() helper
  (strip + http(s):// schema validation) and forward the resolved URL into
  _TushareHttpClient, with an info log when a custom endpoint is in use
- .env.example + .github/workflows/00-daily-analysis.yml: document and map
  TUSHARE_HTTP_URL so the new option is wired into the daily job without
  leaving a half-configured state
- tests: cover env parsing (empty/whitespace/http/https/missing schema),
  fetcher fall-through to the official host, and end-to-end POST target
- docs/CHANGELOG.md: flat [Unreleased] entries

Fixes #1985

* refactor: drop unnecessary string-literal type hint in _build_api_client

TushareHttpClient is already defined above TushareFetcher in the module
scope, so a string-literal type hint is not needed for forward reference.
Restore the bare type to match the surrounding code style and reduce the
diff against main.

* docs(tushare): 补 TUSHARE_HTTP_URL 在 full-guide 中英版本的用途/默认行为/workflow 映射说明

按 PR #2048 review 反馈补齐:
- 表格内新增 TUSHARE_HTTP_URL 行(中英文版本同步),明确默认 https://api.tushare.pro 与 http(s):// 前缀要求
- 在 GitHub Actions 段落后补充 TUSHARE_HTTP_URL 的 vars/Secrets 优先级与每日 workflow 0映射说明,与现有非敏感配置(TICKFLOW_PRIORITY)一致
- 完整环境变量列表(中英文版本)补 TUSHARE_HTTP_URL 行,默认值列填 https://api.tushare.pro
- 与代码实现一致:00-daily-analysis.yml 已用 vars.TUSHARE_HTTP_URL || secrets.TUSHARE_HTTP_URL 映射

* docs(tushare): align TUSHARE_HTTP_URL default with runtime and clarify vars/secrets precedence

Per review feedback on PR #2048: the per-repo config contract must stay
consistent across runtime, .env.example, workflow priority, tests and
both zh/en guides. Two fixes applied as a single contract update:

1. Default endpoint alignment. data_provider/tushare_fetcher.py:100,
   .env.example, and tests/test_tushare_fetcher_http_client.py all keep
   the existing official endpoint http://api.tushare.pro, but the zh/en
   full-guide rows had drifted to https://api.tushare.pro. Switching the
   documented default to HTTPS would silently change the runtime contract
   that the feat commit explicitly preserved. Revert both zh and en
   guide rows to http://api.tushare.pro so docs match runtime, .env.example
   and the test assertions.

2. vars/secrets precedence wording. The workflow uses
   'vars.TUSHARE_HTTP_URL || secrets.TUSHARE_HTTP_URL', which means a
   non-empty vars entry always wins and Secrets cannot override it. The
   zh/en notes previously suggested 'Secrets as a tamper fallback' which
   is incorrect under this precedence and can mislead users into thinking
   Secrets has override power. Replace with explicit description of the
   real semantics: vars wins when non-empty; Secrets is only selected
   when the Variable is empty; for a tamper-resistant deployment put the
   value only in Secrets and leave Variables empty.

Both zh and en guides are updated together; the same 6 contract surfaces
(runtime / .env.example / workflow priority / tests / zh guide / en guide)
now describe one consistent contract.

* docs(tushare): remove false Secret-as-tamper-guard claim, document real vars/secrets write-permission model
2026-07-22 20:54:40 +08:00
ObVious55
915c400bb3 feat(agent): 增加 Pipeline 最终分歧解释 (#2044)
* feat(agent): add pipeline-final disagreement explanation

* fix(agent): align final explanation with public action

* fix(agent): keep ambiguous actions fail-closed
2026-07-21 23:41:42 +08:00
zhulinsen
16e3421c1b fix: secure fork PR review workflow (#2057) 2026-07-21 22:24:19 +08:00
JaxonHu
d13721e817 feat: 新增富途Futu真实持仓导入支持 (#2042)
* feat: add Futu portfolio import support

* docs: condense Futu changelog entry

* fix: tighten Futu portfolio import contracts
2026-07-20 22:45:45 +08:00
Nicholas-Xiong
2933cdf8c5 fix: 外股代码映射到中文显示名时英文新闻相关性漏判(issue #2026,PR #2047 关闭重做) (#2049)
* fix(search): 外股代码映射到中文显示名时英文新闻相关性漏判 (issue #2026)

问题:STOCK_NAME_MAP 把外股 ticker 映射为中文显示名(AAPL→苹果、00700→腾讯控股、
BABA→阿里巴巴集团)后,search 层在三个维度上误判英文新闻:

1. search_stock_news:prefer_chinese 看见 stock_name 含中文就在 is_foreign
   之前 return True,导致 AAPL 走中文查询「苹果 AAPL 股票 最新消息」,
   英文 provider 收不到 Apple 公司名。
2. search_comprehensive_intel / search_stock_events:英文查询分支直接拼
   stock_name,把「苹果」喂给英文 provider。
3. _score_news_relevance:company_identity_terms 仅来自中文 stock_name,
   英文标题「Apple reports earnings beat」既无中文匹配也无英文 alias 匹配,
   被判 macro_market_news 而非 direct_company_news。

方案 A(替代 PR #2047 的 SearchService 私有 29 项静态表):

1. src/data/stock_mapping.py 新增同源 sibling 英文表 STOCK_ENGLISH_NAME_MAP,
   与 STOCK_NAME_MAP 同文件维护;模块加载时 _assert_foreign_english_map_invariant
   静态校验 keys ⊆ STOCK_NAME_MAP 外股子集、且外股子集 ⊆ keys(双向不漂移)。
2. canonicalize_foreign_stock_code 提供 bare / .US / .N / .O / .A / .HK suffix
   / HK00700 prefix 全形式归一化为 STOCK_ENGLISH_NAME_MAP 的 key 形。
3. foreign_stock_english_aliases 在 stock_name 已含 CJK 时返回 canonical
   英文 alias 元组;已是英文名或非外股则返回 (),调用方各自回退到 stock_name。
4. SearchService._is_foreign_stock / _foreign_english_query_terms /
   search_stock_news / search_comprehensive_intel / search_stock_events /
   _score_news_relevance 全部改为读这一个真源;并修复 prefer_chinese 在
   is_foreign 且有 alias 时强制为 False,让 foreign 分支真正可达。
5. 测试:tests/test_search_news_freshness.py 新增 8 个用例覆盖
   _market_english_aliases 全场景、STOCK_ENGLISH_NAME_MAP ⊆ STOCK_NAME_MAP
   双向 invariant、AAPL/AMZN/MSFT/00700/BABA 五 ticker 在三入口的
   英文查询构建、_score_news_relevance 英文媒体短名标题归类、A 股对照
   不污染。

Fixes #2026.

* fix(search): alias 展开 term 去重 + 死分支清理 + CHANGELOG 标签格式 (PR #2049 review)

ZhuLinsen 在 PR #2049 复核给出 1 个高置信度 blocker、1 个非阻断建议;massif-01
AI bot 给出 1 个非阻断死代码建议。本次提交关闭三处:

1. OR-COR-3ff1e068 [correctness] 高 confidence blocker

   因:STOCK_ENGLISH_NAME_MAP['AAPL'] = ('Apple Inc.', 'Apple'),legal alias
   Apple Inc. 经 _company_identity_terms 展开后即包含 Apple,循环里
   拿 Apple Inc. 命中 snippet Apple 加 16 分;再到第二个 alias
   Apple 又对同一 snippet 同一 Apple 命中再加 16 分;再叠 12 分事件词
   得 44 分越 direct_signal >= 38 阈值,把摘要英文名歧义命中抬升为
   direct_company_news。

   果(修复前 massif-01 复现):

   title='US stocks mixed after Fed comments'
   snippet='Apple reports earnings beat and revenue grows.'
   stock_code='AAPL' stock_name='苹果'
   → relevance_score=44, classification=direct_company_news(错误)

   修:在 _score_news_relevance alias 路径引入 seen_identity_terms 集合,
   按 term 而非 alias 累加,同一 Apple 在任一 alias 展开中已被计分后,
   后续 alias 路径不再重复加分;保留每个 term 在标题/摘要 single-pass 命中
   即 break 的语义不变。

   果(修复后):

   同输入 → relevance_score=28, classification=sector_related_news
   (正确降级为背景新闻,因未命中股票代码或公司全称触发第三条原因
    '未命中股票代码或公司全称,降级为背景新闻')

   锁回归测试 test_score_news_relevance_english_alias_dedup_prevents_double_count
   覆盖:snippet-only + 英文短名歧义命中场景,断言 classification 必为
   sector_related_news、relevance_score < 38、reasons 含且仅含一次摘要命中。

2. ZhuLinsen non-blocking:docs/CHANGELOG.md [Unreleased] 条目未用
   AGENTS.md §1.4 要求的 - [类型] 描述 扁平标签格式。

   修:把 - 修复 #2026 ... 改为 - [修复] #2026 ...,并在描述末尾
   补充去重修复一并告知。

3. massif-01 AI bot non-blocking 死代码:_is_foreign_stock 在
   canonicalize_foreign_stock_code 已统一 HK00700 / 00700.HK 全形到 00700
   之后,原 lower.startswith('hk') 分支不可达。

   修:删除该分支,注释中说明 canonical 之后只剩 5 位纯数字一种 HK 形式。

验证:

\b

\b

\b

\b

无回归:标题命中、港股综合、A 股对照、reasons 解析、各 search 入口查询构建均保持。
2026-07-20 21:55:30 +08:00
zhulinsen
e685751f16 docs: add v3.27.0 release changelog (#2041) 2026-07-19 22:29:13 +08:00
zhulinsen
b36c721415 fix(web): 明确报告输入诊断与资讯数据范围 (#1983)
* fix: clarify report input context details

* fix(review-feedback-1983): 代码结论 :不可。重新基线评审完整 diff 后,确认 2 个当前 blocker。旧 correctness finding

* fix(web): clarify report input diagnostics

* docs: trim unreleased changelog entries
v3.27.0
2026-07-19 21:46:13 +08:00
ObVious55
5af5550718 refactor(agent): 增加决策后 runtime facts (#2030)
* refactor: collect internal agent runtime facts

* fix(agent): preserve loop result compatibility

* fix(agent): canonicalize parsed dashboard content

* fix(agent): align post-risk finalization and timeout facts

* docs: document agent runtime facts boundary

* fix(agent): align risk-adjusted core conclusion

* test: update dashboard finalization calls

---------

Co-authored-by: zhulinsen <42829555+ZhuLinsen@users.noreply.github.com>
Co-authored-by: zhulinsen <zhuls97@163.com>
2026-07-19 19:46:14 +08:00
zhulinsen
5aee85679e fix: handle MiniMax string reasoning wrappers (#2039) 2026-07-19 18:56:08 +08:00
xushengasd
5d98d6d787 feat(phase1): converge multi-strategy evidence contract (#2031)
Introduce the StrategyEngine facade and centralize deterministic opinion partitioning, aggregation, synthesis, and signal normalization.

Keep invalid opinions in diagnostics, protect synthesis ownership across fallback paths, and add localized strategy rendering for notification, history, Markdown, and WeChat outputs.

Harden legacy and malformed strategy_synthesis payload handling through shared renderer helpers, with public-entry regression coverage and an updated Phase 1 contract.

Co-authored-by: zhulinsen <42829555+ZhuLinsen@users.noreply.github.com>
2026-07-19 18:55:42 +08:00
oguz
748dba5074 fix(yfinance): populate pe_ratio/pb_ratio for US realtime quotes (#2023)
get_realtime_quote hardcoded pe_ratio and pb_ratio to None for US stocks,
so the valuation block was always empty and every US quote reported
data_quality="partial" with pe_ratio/pb_ratio in missing_fields.

yfinance already returns both via Ticker.info (trailingPE / priceToBook),
and info is fetched a few lines above for the stock name, so this reads
them from the existing dict with no extra request.

The US index path (_get_us_index_realtime_quote) is intentionally left
alone: indices have no PE/PB.

Verified: AAPL now returns pe_ratio=39.67, pb_ratio=45.08 and
missing_fields shrinks from ['amount','pe_ratio','pb_ratio'] to ['amount'].
2026-07-19 18:01:22 +08:00
oguz
9b1b4bb871 fix(tools): describe get_stock_info as multi-market, not A-share only (#2022)
The stock_code parameter was described to the model as "A-share stock
code, e.g., '600519'". The agent reads that schema literally and does not
call get_stock_info for US/HK tickers, so any skill relying on
fundamentals silently degrades to a price/news-only answer there.

The handler already supports these markets: for AAPL it returns
market="us", status="ok" with valuation, growth (revenue_yoy,
net_profit_yoy, roe, gross_margin) and earnings (revenue,
net_profit_parent, operating_cash_flow) populated via the yfinance
fundamental adapter. Only the description was misleading.

Verified with the growth_quality skill on AAPL: before, the agent called
get_daily_history/analyze_trend/get_chip_distribution/search_stock_news
and never get_stock_info, producing a purely technical summary. After, it
calls get_stock_info and the report cites ROE 141.5% and net profit
+19.4% YoY.
2026-07-19 17:54:20 +08:00
zhulinsen
529f6f2061 fix(issue-2013): [bug]-填写的是minimax-api,分析结果报错 (#2018) 2026-07-19 17:30:29 +08:00
Tom
52e787a736 Update Anspire info (#2033)
* update anspire info

* update anspire for web link

* Update anspire info

---------

Co-authored-by: xiaowei <4775987@qq.com>
2026-07-19 16:32:55 +08:00
Alfred
628c5b6ef7 feat: add Codex App Server agent prototype (#2004) 2026-07-19 16:31:54 +08:00
Alfred
487e49e565 feat: 支持保存决策风格重评估结果 (#2014)
* feat: persist decision profile reassessment signals

* fix: align reassess persistence outcomes and lifecycle
2026-07-16 19:22:14 +08:00
zhulinsen
55946536a9 fix(issue-1996): [bug] (#1998) 2026-07-13 21:54:34 +08:00
zhulinsen
e8a9ca7742 fix: harden release packages and report market context (#1994)
* fix: bundle orjson in release packages

* fix: remove duplicate decision signal excerpts

* feat: add TickFlow sector ranking fallback
v3.26.1
2026-07-12 18:56:21 +08:00
ZhuLinsen
49f46954b3 docs: release v3.26.0 v3.26.0 2026-07-12 16:26:44 +08:00
zhulinsen
5a0552f1f5 fix: 修复通知理由字段被截断 (#1989)
* fix: preserve complete decision signal reasons

* fix(review-feedback-1989): 评审结论 . - 必要性 :通过。PR 针对 1969 中 DecisionSignal 理由被静默截断的问题提供了直接且有用户价值的修复

* fix(review-feedback-1989): 评审结论 - 是否可直接合入 :不可
2026-07-12 16:07:01 +08:00
Kushida
44371c2961 fix: delete all history records by stock code (#1987)
* fix: delete all history records by stock code

* fix: reject blank history stock codes

---------

Co-authored-by: zhulinsen <42829555+ZhuLinsen@users.noreply.github.com>
2026-07-12 15:02:54 +08:00
zhulinsen
6fda28b4be fix: bundle AkShare calendar data in desktop builds (#1990) 2026-07-12 14:38:49 +08:00
zhulinsen
85c02edca9 fix: reuse empty concept rankings within pipeline run (#1988) 2026-07-12 13:09:25 +08:00
zhulinsen
6da1360a0b feat: 重建市场结构上下文 (#1981)
* feat: rebuild market structure context

* fix(review-feedback-1981): apps/dsa-web/src/components/report/MarketStructureCard.tsx 新增用户可见界面,但

* fix(review-feedback-1981): apps/dsa-web/src/components/report/MarketStructureCard.tsx 新增用户可见界面,但

* fix(review-feedback-1981): Scope in-flight ranking keys to each fetcher manager

* fix(review-feedback-1981): 修正无证据情况下的个股层级判定,并按仓库规范补充可访问的 Web 页面截图、更新 PR 描述事实

* fix(review-feedback-1981): apps/dsa-web/src/components/report/MarketStructureCard.tsx 新增用户可见界面,但

* fix(review-feedback-1981): 按 AGENTS.md 为新增市场结构卡片补充可直接查看的截图,并同步 PR 描述中的 diff 与 CI 事实

* fix(review-feedback-1981): apps/dsa-web/src/components/report/MarketStructureCard.tsx 新增用户可见界面,但

* fix(review-feedback-1981): 按仓库规范补充可直接审查的市场结构卡片截图,并同步 PR 描述中的 diff 与 CI 事实

* fix(review-feedback-1981): apps/dsa-web/e2e/market-structure-card-visual.spec.ts:276 在

* fix(review-feedback-1981): apps/dsa-web/e2e/market-structure-card-visual.spec.ts 将本 PR

* fix(review-feedback-1981): 同步当前 Head 的 diff/CI 结论,并按仓库规范在 PR 描述或评论中附可访问的市场结构卡片截图

* fix(review-feedback-1981): apps/dsa-web/e2e/market-structure-card-visual.spec.ts:261 新增 async 空对象解构

* fix(review-feedback-1981): 按仓库规范在 PR 描述或评论中附市场结构卡片的可访问截图,并同步当前 diff 统计和 CI 结果

* fix(review-feedback-1981): 消除当前运行结果对历史持久化成功的依赖,补充对应回归测试,并补齐可访问的 UI 截图及更新失真的 PR 描述

* fix(review-feedback-1981): src/utils/data processing.py 提取榜单时丢弃了上游 boards / concept boards 的

* fix(review-feedback-1981): 修正 PR 描述并补齐可访问的视觉证据

* fix(review-feedback-1981): 关闭市场结构前置数据获取可能阻塞主分析的问题,并同步修正 PR 描述、范围清单和视觉证据

* fix(review-feedback-1981): 将 PR 描述、完整范围、当前 CI 证据、视觉证据及回滚表述同步到最新 Head

* fix(review-feedback-1981): PR 描述与最新 Head 不一致:完整 diff 包含 38 个文件及 src/services/analysis

* fix(review-feedback-1981): 按最新 Head 同步 PR 描述,并补充可访问的市场结构卡片截图证据

* fix(review-feedback-1981): 统一即时响应与历史响应的 details.raw result 契约并补最终 API 回归测试,同时更新 PR 描述和可访问的视觉证据

* fix(review-feedback-1981): 将 PR 描述、完整范围、CI 结果及可访问的 UI 截图同步到最新 Head,消除描述与实际改动的实质性不一致

* fix(review-feedback-1981): 同步 PR 描述与最新 Head,并补充可访问的 Web 页面截图

* fix(review-feedback-1981): 同步 PR 描述并按仓库规范附上可访问的 Web 页面截图

* fix(review-feedback-1981): 代码结论 :不可。已按 origin/main...76b5b596fdff 的完整 38 文件 diff 重新建立基线。上次 6 个

* fix(review-feedback-1981): 代码结论 :不可。最新修复已正确收窄无成分股、无龙头证据的原生榜单路径:该路径现在返回 edge/partial,不再直接输出
2026-07-12 11:30:59 +08:00
zhulinsen
01ebf70a10 feat: add reliable home watchlist workspace (#1984)
* feat: add reliable home watchlist workspace

* fix(review-feedback-1984): Don't trust stale stock-bar rows after refresh failures

* fix(review-feedback-1984): apps/dsa-web/src/stores/stockPoolStore.ts 的 refreshStockBar

* fix(review-feedback-1984): Clear loading when refresh supersedes initial stock-bar load

* fix(review-feedback-1984): Type stock-bar test fixtures as StockBarItem and 跟进结论 - 结论 :不接受;最新

* fix(review-feedback-1984): tying the Today fetch to the same refresh path while this tab is
2026-07-11 21:45:04 +08:00
zhulinsen
093057a11b fix: 统一报告动作展示口径 (#1982)
* fix: unify report action display

* fix(review-feedback-1982): add Korean action labels or fall back before returning display action

* fix(review-feedback-1982): Derive signal metadata from resolved actions

* fix(review-feedback-1982): Derive history signal metadata from resolved actions

* fix(review-feedback-1982): Derive renderer emojis from resolved actions

* fix(review-feedback-1982): src/notification.py:2838:build stock summary 先得到 display

* fix(review-feedback-1982): 将 PR 正文同步到最新 head,确保范围、验证结果与实际 diff 一致

* fix(review-feedback-1982): 将 GitHub PR 正文同步到当前 head,并修正 docs/CHANGELOG.md 中不准确的审查过程记录
2026-07-11 14:04:34 +08:00
ObVious55
d08374898c feat(agent): 在决策合成前增加低敏多 Agent 分歧摘要 (#1973)
* feat(agent): add low-sensitive disagreement summary

* fix(agent): avoid treating risk-clear signals as bullish

* fix(agent): align disagreement summary with runtime contracts
2026-07-10 22:22:35 +08:00
Alfred
7c17a242f0 feat: field decision signal profiles (#1967) 2026-07-10 22:05:10 +08:00
Alfred
aa513135d6 feat: add internal DSA tool surface (#1943) 2026-07-08 22:12:24 +08:00
Gach-Coder
16ff3e743f feat: 子Agent 独立超时配置(#1929) (#1961)
* feat: 子Agent 独立超时配置(#1929)

* fix: 子Agent超时钳位在无Pipeline预算时独立生效(#1929)

* test: 新增子Agent超时钳位回归测试(#1929)
2026-07-08 21:52:48 +08:00
Tom
bfdee03241 update anspire for web link (#1955)
* update anspire info

* update anspire for web link

---------

Co-authored-by: xiaowei <4775987@qq.com>
2026-07-07 21:34:31 +08:00
Sam Smith
a3c039ac13 feat: add feishu file upload support for report delivery (#1932)
* feat: add feishu file upload support for report delivery

- Add FEISHU_SEND_AS_FILE config option to switch from text to file delivery
- Implement FeishuSender.send_feishu_file() with App Bot SDK upload + webhook fallback
- Integrate file upload path into pipeline dashboard notification loop
- Integrate file upload path into NotificationService.send_report()
- Add save_and_send_feishu_file() convenience wrapper
- Add .env.example entry and CHANGELOG.md record

* fix: restrict feishu file mode to report routes and wire into workflow

- Limit FEISHU_SEND_AS_FILE to route_type=None or 'report' in
  _send_to_static_channel, preventing alert/event paths from
  unexpectedly saving alerts as files (Codex review P2).
- Add FEISHU_SEND_AS_FILE env var to .github/workflows/00-daily-analysis.yml
  so the setting is available in scheduled runs (Codex review P2).
- Add 13 tests: 7 FeishuSender unit tests (send_feishu_file webhook/App Bot
  paths), 6 NotificationService integration tests (route_type filtering)

* fix: address round-2 review blockers

Correctness:
- Remove route_type=None file-mode fallback; only explicit
  route_type='report' triggers Feishu file delivery
  (api/v1/endpoints/agent.py calls send() without route_type)

Compatibility:
- Isolate CreateFileRequest/CreateFileRequestBody imports from
  CreateMessageRequest; add FEISHU_FILE_SDK_AVAILABLE flag
  so old lark-oapi without file-upload classes won't break
  existing App Bot text messaging

Test fix:
- Fix webhook test assertion: # Test Report -> **Test Report**
  (format_feishu_markdown converts markdown headings to bold)

Documentation:
- Add FEISHU_SEND_AS_FILE to docs/notifications.md config table
- Add file-send section to docs/bot/feishu-bot-config.md
  (permissions, deps, webhook fallback, route scope, CI mapping)
- Add FEISHU_SEND_AS_FILE to docs/full-guide.md and
  docs/full-guide_EN.md config tables
- Add Feishu file create OpenAPI link to docs/notifications.md

* docs: fix feishu_sender drift and document config entry boundary

- Fix outdated '本轮未改动 feishu_sender.py' line in docs/notifications.md
  (we added send_feishu_file to feishu_sender.py)
- Document FEISHU_SEND_AS_FILE as .env/Actions-only in
  docs/bot/feishu-bot-config.md (not exposed in Web/Desktop settings)

* feat: add FEISHU_SEND_AS_FILE to system_config_service env mapping

- Add FEISHU_SEND_AS_FILE -> feishu_send_as_file (bool) mapping
  alongside FEISHU_MAX_BYTES in the notification env key mapping
- Update docs/bot/feishu-bot-config.md to reflect standard config paths

* test: add non-mock SDK import smoke test for file upload classes
2026-07-06 21:26:19 +08:00
zhulinsen
267c2139ae docs: clarify data source configuration (#1935) 2026-07-05 20:57:42 +08:00
Alfred
36f03c06e2 feat: add decision signal stock context (#1925)
Co-authored-by: zhulinsen <42829555+ZhuLinsen@users.noreply.github.com>
2026-07-05 19:22:23 +08:00