Skip to content

fix: 修复单股推送模式下通知链路的共享实例并发复用问题 (#876) - #899

Merged
ZhuLinsen merged 11 commits into
mainfrom
autocode/issue-876-bug
Apr 1, 2026
Merged

fix: 修复单股推送模式下通知链路的共享实例并发复用问题 (#876)#899
ZhuLinsen merged 11 commits into
mainfrom
autocode/issue-876-bug

Conversation

@ZhuLinsen

@ZhuLinsen ZhuLinsen commented Mar 27, 2026

Copy link
Copy Markdown
Owner

PR Type

  • fix
  • feat
  • refactor
  • docs
  • chore
  • test

Background And Problem

  • 当前问题:在不改动通知渠道配置、workflow、deploy 或 migration 的前提下,修复单股推送模式下 StockAnalysisPipeline 共享 NotificationService 被并发复用导致的通知不稳定问题。
  • 影响范围:本次改动涉及 4 个文件,Diff 为 +331 / -22
  • 触发来源:Issue 自动执行(Issue [Bug] 修复单股推送模式下通知链路的共享实例并发复用问题 #876)。

Scope Of Change

  • docs/CHANGELOG.md
  • src/core/pipeline.py
  • tests/test_pipeline_single_notify_thread_safety.py
  • tests/test_pipeline_single_stock_notify.py

Documentation And Changelog

  • 已同步更新文档/变更记录:docs/CHANGELOG.md
  • 当前补丁尚未包含 README.md 或专题文档;如用户可见行为发生变化,请补充文档落点。

Issue Link

Closes #876

Verification Commands And Results

./scripts/ci_gate.sh flake8
./scripts/ci_gate.sh offline-tests

关键输出/结论 / Key output & conclusion:

  • lint:PASS, test:TIMEOUT

Compatibility And Risk

  • Medium:涉及 docs/CHANGELOG.md, src/core/pipeline.py, tests/test_pipeline_single_notify_thread_safety.py, tests/test_pipeline_single_stock_notify.py,建议按文件范围复核。
  • 前提假设:
    • 问题主入口是 src/core/pipeline.py 的批量并发路径:run() 用线程池并发调用 process_single_stock(),而 single_stock_notify=true 时多个 worker 会共享同一个 self.notifier
    • 当前 API / TaskQueue 路径通常会为每个任务单独创建 StockAnalysisPipeline,不属于这次缺陷的主要复用点,除非补充排查发现同类共享实例。
    • 最小改动优先方案是在 pipeline 层提取单股通知 helper,并把“报告生成 + notifier.send()”整体放入同一临界区串行执行;若回归测试显示仍有状态污染,再退一步改为每次通知创建独立 NotificationService,但不先扩散修改各 sender。
    • 不新增配置项,不改 sender 协议/重试语义;文档层面仅补 docs/CHANGELOG.md,README 无需变更。

Rollback Plan

  • git revert <merge-commit> 回滚本 PR 提交,重点确认 docs/CHANGELOG.md, src/core/pipeline.py, tests/test_pipeline_single_notify_thread_safety.py, tests/test_pipeline_single_stock_notify.py 恢复正常。

Acceptance Criteria

  • single_stock_notify 开启且 max_workers > 1 时,同一个 pipeline 实例内不会再并发进入单股通知的报告生成与发送逻辑。
  • 非单股推送路径保持现状:汇总推送、邮件分组路由、Markdown 转图片回退、上下文渠道回复等现有行为不回归。
  • 新增回归测试能够覆盖并发单股推送场景,并验证修复后不会同时复用共享通知实例进入关键发送路径。
  • 变更不涉及 secrets、workflow、deploy、migration,并在 docs/CHANGELOG.md 记录该通知稳定性修复。

Implementation

已完成针对 review blocker 的修复:

  1. docs/CHANGELOG.md 已移除 [Unreleased] 内不规范的 ### 修复 分类标题,并清理重复条目,改为单条平铺格式。
  2. docs/CHANGELOG.md[3.11.0] 已不再包含本次单股推送修复条目,避免将未发布变更写入已发布版本。
  3. src/core/pipeline.py 保留 _SINGLE_STOCK_NOTIFY_LOCK_INIT_GUARD,并补充注释说明其仅用于 __new__ 绕过 __init__ 场景(测试用例)下的防御性初始化。
  4. 未触碰 workflow/deploy/migrations/.env 等禁改区域,未做额外功能改动。
  5. 本次为文档合规与评审阻塞项修复,未在本次执行中补跑测试。

Checklist

  • 本 PR 有明确动机和业务价值 / This PR has a clear motivation and value
  • 已提供可复现的验证命令与结果 / Reproducible verification commands and results are included
  • 已评估兼容性与风险 / Compatibility and risk have been assessed
  • 已提供回滚方案 / A rollback plan is provided
  • 文档与 docs/CHANGELOG.md 同步仍需确认;如涉及用户可见变更,请在合并前补充原因与文档落点 / Documentation and docs/CHANGELOG.md sync still needs confirmation before merge when user-visible behavior changes

Copilot AI review requested due to automatic review settings March 27, 2026 16:49
@github-actions github-actions Bot added documentation Improvements or additions to documentation size/L testing labels Mar 27, 2026
@github-actions

github-actions Bot commented Mar 27, 2026

Copy link
Copy Markdown

🤖 自动审查报告

项目 结果
📊 变更文件 4 个
➕ 新增行数 333 行
➖ 删除行数 22 行
🔍 静态检查 ✅ 通过
🧠 AI 审查 ✅ 已完成

📁 修改的文件

  • 📝 docs/CHANGELOG.md (+4/-0)
  • 📝 src/core/pipeline.py (+62/-22)
  • 🆕 tests/test_pipeline_single_notify_thread_safety.py (+120/-0)
  • 🆕 tests/test_pipeline_single_stock_notify.py (+147/-0)

💡 提示: 请确保代码已通过本地测试,并遵循项目代码规范。

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

修复单股推送模式下,同一个 StockAnalysisPipeline 实例并发复用共享 NotificationService 导致通知不稳定的问题;通过将单股通知发送串行化并增加实例级临界区来保证线程安全。

Changes:

  • StockAnalysisPipeline 中引入实例级锁,并抽取 _send_single_stock_notification() 统一封装“生成报告 + send”的临界区逻辑。
  • run() 路径保持个股分析并发,但将 single_stock_notify 的即时通知移动到结果收集侧串行发送,避免线程池内并发复用通知实例。
  • 新增并发回归测试覆盖直接单股入口与批量运行下的单股通知线程安全/串行发送行为,并更新 docs/CHANGELOG.md 记录修复。

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
src/core/pipeline.py 增加单股通知发送的实例级锁与统一发送函数,并将批量通知改为结果收集侧串行发送
tests/test_pipeline_single_notify_thread_safety.py 新增并发回归测试,验证直接单股通知入口不会并发进入生成/发送临界区
tests/test_pipeline_single_stock_notify.py 新增回归测试,验证 run() 模式下单股通知不在 worker 线程发送且串行执行
docs/CHANGELOG.md 记录单股推送模式下通知链路并发复用问题的修复说明

Comment on lines +1 to +5
# -*- coding: utf-8 -*-
"""
Regression tests for single-stock notification behavior in StockAnalysisPipeline.
"""

Copilot AI Mar 27, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR description lists the changed files as only docs/CHANGELOG.md, src/core/pipeline.py, and tests/test_pipeline_single_notify_thread_safety.py, but this PR also adds tests/test_pipeline_single_stock_notify.py. Please update the PR description scope/file list so reviewers and release notes accurately reflect the full change set.

Copilot uses AI. Check for mistakes.
Comment thread src/core/pipeline.py Outdated
Comment on lines +1314 to +1317
notify_lock = self.__dict__.setdefault(
"_single_stock_notify_lock",
threading.Lock(),
)

Copilot AI Mar 27, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_send_single_stock_notification() uses self.__dict__.setdefault(..., threading.Lock()). The threading.Lock() expression is evaluated on every call, so a new (discarded) lock object is created even when _single_stock_notify_lock already exists. Prefer getattr(self, "_single_stock_notify_lock", None) and only create/assign the lock when missing (or store it once in __init__ and rely on that for normal construction).

Suggested change
notify_lock = self.__dict__.setdefault(
"_single_stock_notify_lock",
threading.Lock(),
)
notify_lock = getattr(self, "_single_stock_notify_lock", None)
if notify_lock is None:
notify_lock = threading.Lock()
setattr(self, "_single_stock_notify_lock", notify_lock)

Copilot uses AI. Check for mistakes.
notify_barrier = threading.Barrier(2)

def _analyze(code, report_type, query_id):
notify_barrier.wait(timeout=1)

Copilot AI Mar 27, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

threading.Barrier.wait(timeout=1) can be flaky on slower/loaded CI runners (a 1s scheduling delay can trip the timeout and fail the test for non-functional reasons). Consider removing the timeout or increasing it to a more forgiving value so the regression test remains stable.

Suggested change
notify_barrier.wait(timeout=1)
notify_barrier.wait(timeout=10)

Copilot uses AI. Check for mistakes.

@ZhuLinsen ZhuLinsen left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

评审结论

  • 必要性:通过 + 单股推送模式下共享 NotificationService 的并发复用会直接影响通知稳定性,这个修复目标明确且和当前改动范围一致。
  • 是否有对应 issue:有(Fixes #876
  • PR 类型:fix + 核心改动集中在 src/core/pipeline.py 的并发通知路径修复,并补了对应回归测试与 docs/CHANGELOG.md 记录。
  • description 完整性:不完整 + Scope Of Change / Implementation 仍写 3 个文件、+144 / -17,但本地完整 diff 实际为 4 个文件、+323 / -22,且漏写了 tests/test_pipeline_single_stock_notify.py;同时验证说明里既写了已执行 ./scripts/ci_gate.sh ...,又写了未跑 ./scripts/ci_gate.sh,信息前后不一致。
  • 是否可直接合入:不可 + 当前结构化事实显示该 PR 与目标分支存在冲突,且 PR 描述里的改动范围与验证记录需要先按 AGENTS.md 要求补齐和校正。

主要问题

  1. [Process blocker] 结构化事实已明确“当前 merge 状态:存在冲突,当前不能直接合并”。在这个状态下,即使当前 CI 是 success,也还不能判定可直接合入。
  2. [Process blocker] PR 描述与本地完整改动不一致:实际改动文件包含 tests/test_pipeline_single_stock_notify.py,diff 统计也不是描述里的 +144 / -17。另外验证部分对 ./scripts/ci_gate.sh 是否执行给出了互相矛盾的说法,这不符合仓库 AGENTS.md 对 description 完整性、验证证据和交付一致性的要求。

🤖 此回复由 OpenReview Bot 自动生成,仅供参考。如有疑问请 @维护者。

@ZhuLinsen ZhuLinsen left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

评审结论

  • 必要性:通过 + 单股推送模式下共享 NotificationService 的并发复用会直接影响通知稳定性,本 PR 的修复目标与改动范围一致
  • 是否有对应 issue:有(Fixes #876
  • PR 类型:fix + 核心改动集中在 src/core/pipeline.py 的单股通知并发路径修复,并补了回归测试与 docs/CHANGELOG.md 记录
  • description 完整性:不完整 + Scope Of Change / Implementation / diff 统计仍写 3 个文件、+144 / -17,但实际改动为 4 个文件、+323 / -22;验证部分对 ./scripts/ci_gate.sh 是否实际执行也前后矛盾
  • 是否可直接合入:不可 + 当前分支存在冲突,需先解决冲突;同时 PR 描述需按 AGENTS.md 要求修正为与实际改动范围和验证证据一致。除这两点外,当前 diff 未发现更高优先级的行为/兼容性阻断问题

主要问题

  1. [Process blocker] 结构化事实已明确当前分支“存在冲突,当前不能直接合并”。在冲突未解决前,现有 review 结论无法保证对应最终待合入代码,因此不能直接合入。
  2. [Process blocker] PR 描述与实际改动不一致:完整改动文件列表实际包含 tests/test_pipeline_single_stock_notify.py,本地 diff 统计也是 4 files / 323 insertions(+), 22 deletions(-),但正文多处仍写 3 个文件、+144 / -17;同时前文写已执行 ./scripts/ci_gate.sh flake8./scripts/ci_gate.sh offline-tests,后文又写“未跑 ./scripts/ci_gate.sh”。按仓库 AGENTS.md,交付说明必须准确覆盖改动范围、验证情况、未验证项和回滚方式,当前表述会误导评审和后续变更追踪。

🤖 此回复由 OpenReview Bot 自动生成,仅供参考。如有疑问请 @维护者。

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4ad9687700

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/core/pipeline.py Outdated
Comment on lines +1314 to +1317
notify_lock = getattr(self, "_single_stock_notify_lock", None)
if notify_lock is None:
notify_lock = threading.Lock()
setattr(self, "_single_stock_notify_lock", notify_lock)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Make lazy lock initialization atomic

When _single_stock_notify_lock is missing (e.g., instances created via __new__, which your new tests also do), two threads can both observe None here, each create a different threading.Lock(), and then enter the notifier critical section concurrently. That reintroduces the exact concurrent NotificationService reuse this patch is trying to prevent and can make the new thread-safety path flaky under contention.

Useful? React with 👍 / 👎.

@ZhuLinsen ZhuLinsen left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

评审结论

  • 必要性:通过 + 单股推送模式下共享 NotificationService 被并发复用会直接影响通知稳定性,本 PR 针对 issue #876 的修复目标明确,实际代码和回归测试也围绕这一点展开
  • 是否有对应 issue:有(Fixes #876
  • PR 类型:fix + 核心改动在 src/core/pipeline.py 的单股通知并发路径修复,并补充了 tests/test_pipeline_single_notify_thread_safety.pytests/test_pipeline_single_stock_notify.py 两组回归测试及 docs/CHANGELOG.md 记录
  • description 完整性:不完整 + Scope Of ChangeImplementation、diff 统计和“未跑测试”的说明仍把本 PR 写成仅 docs/CHANGELOG.md 的 docs-only 整理,遗漏了 src/core/pipeline.py 与两个新增测试文件
  • 是否可直接合入:不可 + 当前分支与目标分支存在冲突;同时 PR 描述与实际改动内容实质性不符,按 AGENTS.md 的合入阻断条件需要先解决

主要问题

  1. [Process blocker] PR 描述中的改动范围、实现说明和验证说明与实际 diff 明显矛盾:正文写的是“只改 docs/CHANGELOG.md”“Diff 为 +24 / -2”“未跑测试,因为只是文档侧冲突整理”,但本地完整 diff 实际包含 src/core/pipeline.pytests/test_pipeline_single_notify_thread_safety.pytests/test_pipeline_single_stock_notify.py,总计 4 个文件、346 行新增 / 23 行删除,且结构化事实中的 CI 已成功。这个问题会直接误导 reviewer 对风险面、验证面和发布说明的判断;按仓库 AGENTS.md,“PR 描述与实际改动内容实质性矛盾”属于合入阻断项。
  2. src/core/pipeline.py_send_single_stock_notification()_single_stock_notify_lock 的惰性初始化不是原子的:先 getattr(..., None),再新建 threading.Lock(),最后 setattr(...)。当前生产实例通常会在 __init__ 里先建好这个锁,但这次新增的直接路径回归测试刻意通过 __new__ 绕过了 __init__,因此这里仍然存在两个线程各自创建不同锁、重新并发进入通知临界区的窗口,回归保护有概率失真。置信度:中
  3. 结构化事实已经明确标记“存在冲突,当前不能直接合并”。即使当前 CI 全绿,这个 head 也不能判定为可直接合入,需要先解决冲突后再确认最终代码和测试结论是否保持一致

🤖 此回复由 OpenReview Bot 自动生成,仅供参考。如有疑问请 @维护者。

@ZhuLinsen ZhuLinsen left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

评审结论

  • 必要性:通过 + 单股推送模式下共享 NotificationService 的并发复用会直接影响通知稳定性,本 PR 的修复目标和改动范围一致
  • 是否有对应 issue:有(Fixes #876
  • PR 类型:fix + 核心改动集中在 src/core/pipeline.py 的单股通知并发路径修复,并补充了两组回归测试与 docs/CHANGELOG.md 记录
  • description 完整性:不完整 + 已补齐 4 个改动文件、验证命令和回滚方案,但未按 AGENTS.md / PR 模板说明未更新 README.md 的原因;文档落点只写到了 docs/CHANGELOG.md
  • 是否可直接合入:不可 + 当前 head 存在明确合并冲突;另外 _send_single_stock_notification() 的懒初始化锁仍有竞态,建议先处理后再合入

主要问题

  1. src/core/pipeline.py_send_single_stock_notification()_single_stock_notify_lock 缺失时采用 getattr(...) -> threading.Lock() -> setattr(...) 的懒初始化,这不是原子操作。当前 PR 新增的 tests/test_pipeline_single_notify_thread_safety.pytests/test_pipeline_single_stock_notify.py 都通过 StockAnalysisPipeline.__new__ 构造未执行 __init__ 的实例;在这种场景下,两个线程仍可能各自创建不同的锁并同时进入“生成报告 + send”临界区,和本 PR 想保证的直接调用路径线程安全目标相冲突。置信度:中。
  2. PR description / 文档说明:仓库里已有 README.mddocs/FAQ.mddocs/full-guide.mdSINGLE_STOCK_NOTIFY 的通用说明,但本次新增了“并发分析、结果收集侧串行发送”的语义,描述里没有按 AGENTS.md 说明为何无需同步这些已有说明文档,只把信息落在了 docs/CHANGELOG.md。这项不影响代码正确性,但当前 description 仍不完整。

🤖 此回复由 OpenReview Bot 自动生成,仅供参考。如有疑问请 @维护者。

@ZhuLinsen ZhuLinsen left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

评审结论

  • 必要性:通过 + 单股推送模式下共享 NotificationService 被并发复用会直接影响通知稳定性,本次修复目标明确且与 issue #876 直接对应
  • 是否有对应 issue:有(Fixes #876
  • PR 类型:fix + 核心改动集中在 src/core/pipeline.py 的单股通知并发路径修复,并补了两组回归测试与 docs/CHANGELOG.md 记录
  • description 完整性:不完整 + Scope Of Change / diff 统计 / Implementation 仍按“1 个文件、+7 / -2、主要只改 src/core/pipeline.py”描述,和本地完整 diff 的 4 个文件、353/23 不一致;同时未按 AGENTS.md 说明未更新 README.md 的原因与文档落点
  • 是否可直接合入:不可 + 当前 head 与 main 存在明确冲突,且 PR 描述与实际改动范围实质性矛盾;需先解决冲突并同步描述后再合入

主要问题

  1. [Process blocker] 结构化事实已明确当前 merge 状态为“存在冲突,当前不能直接合并”。即使当前 CI 为 success,这个 PR 也不能按现状直接合入。
  2. [Process blocker] PR 描述与实际改动不一致:描述仍写“仅 1 个文件、+7 / -2”,但本地 merge-base diff 实际包含 docs/CHANGELOG.mdsrc/core/pipeline.pytests/test_pipeline_single_notify_thread_safety.pytests/test_pipeline_single_stock_notify.py 共 4 个文件、353/23。按 AGENTS.md 的交付要求,这会直接影响变更范围判断、验证证据理解和回滚评估。

🤖 此回复由 OpenReview Bot 自动生成,仅供参考。如有疑问请 @维护者。

@ZhuLinsen ZhuLinsen left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

评审结论

  • 必要性:通过 + 单股推送模式下共享 NotificationService 被并发复用会直接影响通知稳定性,本 PR 的代码改动和两组回归测试都与 issue #876 的修复目标直接对应。
  • 是否有对应 issue:有(Fixes #876
  • PR 类型:fix + 核心改动在 src/core/pipeline.py 的单股通知并发路径修复,并补充了 tests/test_pipeline_single_stock_notify.pytests/test_pipeline_single_notify_thread_safety.py 回归测试,同时更新了 docs/CHANGELOG.md
  • description 完整性:不完整 + Scope Of Change、影响范围、diff 统计和 Implementation 仍按“仅 docs/CHANGELOG.md、1 个文件、+1/-1”描述,但本地 merge-base diff 实际是 4 个文件、+353/-23;另外未按 AGENTS.md 说明未更新 README.md 的原因。
  • 是否可直接合入:不可 + 当前存在明确合并冲突,且 PR 描述仍未与实际 diff 对齐;基于当前代码本身我未再看到新的正确性阻断,但合入前至少需要先解决这两个阻断点。

主要问题

  1. [Process blocker] 结构化事实已明确显示当前分支“存在冲突,当前不能直接合并”。CI 虽然已通过,但在冲突未解前,我不能给出“可直接合入”的结论。置信度:高
  2. [Process blocker] PR 描述仍与实际改动范围明显不一致:当前 diff 实际修改了 src/core/pipeline.pytests/test_pipeline_single_stock_notify.pytests/test_pipeline_single_notify_thread_safety.pydocs/CHANGELOG.md,不是描述里的“仅 1 个文件”。这会直接误导评审边界、验证覆盖判断和回滚说明;按 AGENTS.md,还需要补齐未更新 README.md 的原因及文档落点说明。置信度:高

🤖 此回复由 OpenReview Bot 自动生成,仅供参考。如有疑问请 @维护者。

@ZhuLinsen ZhuLinsen left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

评审结论

  • 必要性:通过 + 单股推送模式下共享 NotificationService 被并发复用会直接影响通知稳定性,本次在 src/core/pipeline.py 的修复目标明确,且补了对应回归测试。
  • 是否有对应 issue:有(Fixes #876
  • PR 类型:fix + 核心改动是修复 src/core/pipeline.py 的单股通知并发路径,并新增 tests/test_pipeline_single_stock_notify.pytests/test_pipeline_single_notify_thread_safety.py 回归覆盖。
  • description 完整性:不完整 + Scope Of Change、影响范围/Diff 统计、ImplementationRollback Plan 仍按“仅修改 docs/CHANGELOG.md+1 / -0、未做其他改动、只回滚 changelog”描述,与实际 4 个改动文件和代码/测试修复内容实质不符。
  • 是否可直接合入:不可 + 当前分支存在明确合并冲突;同时 PR 描述与实际改动内容实质性矛盾,按 AGENTS.md 属于阻断项。

主要问题

  1. [Process blocker] PR 描述与实际 diff 明显不一致:当前实际改动包含 src/core/pipeline.pytests/test_pipeline_single_stock_notify.pytests/test_pipeline_single_notify_thread_safety.pydocs/CHANGELOG.md 共 4 个文件,且本地 diff 统计为 354 insertions / 23 deletions;但描述中的影响范围、Scope Of ChangeImplementation 和回滚方案仍按“仅 docs 改动”填写。这会直接误导评审范围、验证证据和回滚判断,不符合仓库 AGENTS.md 对 PR 描述完整性和 fix 类 PR 交付信息的要求。
  2. [Process blocker] 结构化事实显示当前分支与目标分支存在合并冲突,现阶段不能直接合并;需要先解决冲突,再基于最新 head 复核最终 diff。

🤖 此回复由 OpenReview Bot 自动生成,仅供参考。如有疑问请 @维护者。

@ZhuLinsen ZhuLinsen left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

评审结论

  • 必要性:通过 + 单股推送模式下共享 NotificationService 被并发复用会直接影响通知稳定性,本 PR 在 src/core/pipeline.py 中把批量路径改为结果收集侧串行发送,并补了两组回归测试,修复目标明确。
  • 是否有对应 issue:有(Fixes #876
  • PR 类型:fix + 核心改动是修复 src/core/pipeline.py 的单股通知并发路径,并新增 tests/test_pipeline_single_stock_notify.pytests/test_pipeline_single_notify_thread_safety.py 回归覆盖。
  • description 完整性:不完整 + 顶部 Background And Problem / Scope Of Change 仍写“1 个文件、+1 / -1、仅 docs/CHANGELOG.md”,与本地完整 diff 的 4 个文件、354 insertions / 23 deletions 明显不一致;虽然后文 Implementation 已补充,但整份描述仍存在实质性矛盾。
  • 是否可直接合入:不可 + 当前代码层面未见新的阻断性正确性问题,但结构化事实显示当前分支存在冲突,且 PR 描述与实际改动内容仍实质性矛盾;按 AGENTS.md,这两点都需要先处理。

主要问题

  1. [Process blocker] PR description 里的 Background And ProblemScope Of Change 与实际改动不一致:实际变更包含 src/core/pipeline.pytests/test_pipeline_single_stock_notify.pytests/test_pipeline_single_notify_thread_safety.pydocs/CHANGELOG.md 共 4 个文件,而不是“仅 docs/CHANGELOG.md / +1 / -1”。这会直接误导评审、验证范围和回滚边界;按 AGENTS.md,“PR 描述与实际改动内容实质性矛盾”属于合入阻断项。置信度:高
  2. [Process blocker] 结构化事实明确显示当前分支“存在冲突,当前不能直接合并”。在冲突未解决前,最终合入代码态仍可能变化,现有评审结论不能直接覆盖最终 merge 结果。置信度:高

🤖 此回复由 OpenReview Bot 自动生成,仅供参考。如有疑问请 @维护者。

@ZhuLinsen
ZhuLinsen force-pushed the autocode/issue-876-bug branch from 67bd5aa to a76767d Compare March 31, 2026 02:13

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a76767d7e6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/CHANGELOG.md Outdated

- [修复] 🐳 **Docker WebUI 运行时优先复用预构建静态资源** — `prepare_webui_frontend_assets()` 现在会先检查镜像内已有的 `static/index.html` 是否可直接复用;当容器运行时不包含 `apps/dsa-web` 源码目录且未安装 `npm` 时,也不会误报“未找到前端项目,无法自动构建”,从而恢复 Docker 部署后的 WebUI 打开能力。
- [修复] 市场复盘生成链路将 LLM `max_tokens` 从 `2048` 提升到 `8192`,降低长复盘输出因 `MAX_TOKENS` 提前截断导致内容未完成的概率。
### 修复

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Remove section headers from [Unreleased]

This adds a ### 修复 heading inside [Unreleased], but the repo rule in AGENTS.md requires that section to stay in flat - [类型] 描述 lines with no category headers; keeping the heading here reintroduces the merge-conflict pattern this policy is meant to avoid and makes the changelog format inconsistent for subsequent PRs.

Useful? React with 👍 / 👎.

@ZhuLinsen ZhuLinsen left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

评审结论

  • 必要性:通过 + 单股推送模式下共享 NotificationService 被并发复用会直接影响通知稳定性,本 PR 的修复目标与 issue #876 直接对应。
  • 是否有对应 issue:有(Closes #876
  • PR 类型:fix + 核心改动在 src/core/pipeline.py 的单股通知并发路径修复,并新增两组回归测试覆盖批量入口与直接单股入口。
  • description 完整性:不完整 + 已补充 issue、验证命令、风险和回滚方案,但描述里的 diff 统计与当前结构化事实不一致,且 Implementation 段仍混入一次中途修文过程,不是最终 PR 说明。
  • 是否可直接合入:不可 + 需要先修正文档变更中的历史版本重复记录问题;代码层面未看到新的阻断性正确性风险,但当前 docs/CHANGELOG.md 仍有必须收口的发布说明问题。

主要问题

  1. [Process blocker] docs/CHANGELOG.md:本次修复已经按仓库规范追加到 [Unreleased],但同一修复又被追加到了已发布的 ## [3.11.0] - 2026-03-27### 修复 段里,而且是两条近似重复描述。按 AGENTS.md,当前变更应记录在 [Unreleased] 的扁平条目中;把未发布修复写回已发布版本会污染历史 release note,重复条目也会扩大这种偏差。建议只保留 [Unreleased] 中的一条最终表述,删除 3.11.0 下这两条新增记录。置信度:高。

🤖 此回复由 OpenReview Bot 自动生成,仅供参考。如有疑问请 @维护者。

@ZhuLinsen
ZhuLinsen force-pushed the autocode/issue-876-bug branch from 4aeef71 to ed64b06 Compare March 31, 2026 07:05

@ZhuLinsen ZhuLinsen left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

评审结论

  • 必要性:通过 — 单股推送模式下 NotificationService 被并发复用是真实并发 bug,修复目标明确、改动范围合理。
  • 是否有对应 issue:有(Closes #876
  • PR 类型:fix — 核心改动为 src/core/pipeline.py 并发路径修复 + 两组回归测试。
  • description 完整性:不完整 — PR 描述的 Implementation 段混入了 CHANGELOG 编辑操作的调试轨迹(Read/Edit/Verify/shell 命令),不属于 PR 模板要求的实现说明;diff 统计 +335 / -22 与描述顶部的 +335 / -22 一致,但 Implementation 段仍提及"1 个文件、15 lines read"等残留。
  • 是否可直接合入:不可 — 存在以下阻断问题需修复后再合入。

主要问题

  1. [Correctness blocker] docs/CHANGELOG.md 违反 AGENTS.md 规范:[Unreleased] 段内新增了 ### 修复 分类标题(第 20 行)。仓库规范明确禁止在 [Unreleased] 内添加 ### 类目标题。此外该标题下方有一条重复的 Docker WebUI 修复条目(第 22 行,与第 15 行完全重复),以及单股推送修复条目出现两条几乎相同的记录(第 23、24 行),均需清理。同一修复还被写入了 [3.11.0]### 修复 段(第 57、58 行),但本 PR 功能尚未发版,不应出现在已发布版本段中。置信度:高。
  2. [Correctness blocker] [3.11.0] 已发布段被追加了本 PR 的修复条目(第 57–58 行)[3.11.0] - 2026-03-27 是已发布版本,本次修复应只出现在 [Unreleased] 段。在已发布版本段追加条目会误导用户和发布流程。置信度:高。
  3. [Nice to have] 模块级 _SINGLE_STOCK_NOTIFY_LOCK_INIT_GUARD(第 49 行)实际上不必要__init__ 已经在实例初始化时赋值 self._single_stock_notify_lock = threading.Lock()(第 94 行),_send_single_stock_notification 中的 getattr + double-check 逻辑(第 1316–1322 行)只会在通过 __new__ 绕过 __init__ 构造的实例上触发。正常生产路径不存在这种情况,该 guard 属于防御性代码但增加了理解成本。两组测试文件均使用 __new__ 跳过 __init__ 构建 pipeline,但这只是测试便利手段。不构成阻断,但建议在代码注释中说明此 guard 的存在理由。
  4. [Nice to have] PR 描述 Implementation 段包含调试轨迹Read CHANGELOG.mdEdit CHANGELOG.mdCheck exact whitespaceVerify no ### in Unreleased 等步骤是自动化工具的执行日志,不是实现说明,建议清理后再合入。

🤖 此回复由 OpenReview Bot 自动生成,仅供参考。如有疑问请 @维护者。

@ZhuLinsen
ZhuLinsen force-pushed the autocode/issue-876-bug branch from 1c4b4bb to 2a2f929 Compare March 31, 2026 14:03

@ZhuLinsen ZhuLinsen left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

评审结论

  • 必要性:通过 + 单股推送下共享 NotificationService 在并发 worker 中复用,确实会导致发送乱序/状态污染,修复动机与问题来源(Issue #876)对应且清晰。
  • 是否有对应 issue:有(#876
  • PR 类型:fix + 主要修改集中在 src/core/pipeline.py 的单股推送并发路径,并补充两组回归测试。
  • description 完整性:不完整 + PR 说明未明确确认 docs/CHANGELOG.md 当前已存在 AGENTS 约束冲突风险(Unreleased 仍含分类标题),且本地验证命令给出 test:TIMEOUT,缺少明确的本地重放结果。
  • 是否可直接合入:可 + 仅有非阻断性整理项需要在合并前补齐(文档格式合规与验证重跑),无明确阻断性运行期缺陷证据。

主要问题

  1. [Nice to have] docs/CHANGELOG.md 未严格满足仓库约束。证据来自结构化 diff:[Unreleased] 段内仍出现 ### 修复 分类标题,并出现同类“单股推送模式不再并发复用共享通知实例”条目重复(结合 AGENTS.md 明确要求 Unreleased 采用平铺行、禁止分类标题)。风险:引发 PR 合规性与协作风格退化,增加合并冲突概率。置信度:高。
  2. [Nice to have] 验证链不闭环。PR 描述列出的 ./scripts/ci_gate.sh offline-tests 输出为 test:TIMEOUT,当前本地仅有 CI 成功记录,未给出该 PR 新增测试(如 tests/test_pipeline_single_stock_notify.pytests/test_pipeline_single_notify_thread_safety.py)的明确本地通过证据。风险:回归保障不够完整,建议补充可复现的本地重跑说明。置信度:高。

🤖 此回复由 OpenReview Bot 自动生成,仅供参考。如有疑问请 @维护者。

@ZhuLinsen
ZhuLinsen force-pushed the autocode/issue-876-bug branch from 2a2f929 to 63b15fb Compare March 31, 2026 15:01

@ZhuLinsen ZhuLinsen left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

评审结论

  • 必要性:通过 + 单股推送模式下共享 NotificationService 在并发 worker 中进入同一发送链路,存在真实的竞态风险,PR 明确对应 Issue #876 且改动集中在该修复点。
  • 是否有对应 issue:有(#876
  • PR 类型:fix + 变更聚焦于 src/core/pipeline.py 的单股通知并发行为修复,并补充两类回归测试。
  • description 完整性:不完整 + 已声明了主要动机、范围、issue、验证命令,但在文档合规与验证闭环有缺口:docs/CHANGELOG.md[Unreleased] 仍出现不合规结构;新增测试结果仅有 test:TIMEOUT,无法确认新并发测试实际通过。
  • 是否可直接合入:可 + 当前没有发现明确阻断性行为风险,但建议在合并前补齐以下两项非阻断修补项。

主要问题

  1. [Nice to have] docs/CHANGELOG.md:本次 patch 在 [Unreleased] 中新增了 ### 修复 分类标题并出现单股修复条目重复/冗余表述(置信度:高)。该仓库 AGENTS 明确要求 Unreleased 使用平铺条目格式,当前形式会增加维护与合并冲突风险。
  2. 建议:移除 ### 分类标题;保持单条规范格式 - [修复] ...,并合并重复表述。
  3. [Nice to have] 验证闭环:Verification Commands And Results 显示测试阶段为 TIMEOUT,而实现中新增了并发安全回归测试(tests/test_pipeline_single_stock_notify.pytests/test_pipeline_single_notify_thread_safety.py)但未给出稳定通过证据(置信度:高)。
  4. 建议:在本地或 CI 运行 pytest 覆盖上述新增并发用例并补充执行结果,降低并发修复回归风险。

🤖 此回复由 OpenReview Bot 自动生成,仅供参考。如有疑问请 @维护者。

@ZhuLinsen
ZhuLinsen merged commit 4c3a48f into main Apr 1, 2026
7 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 02c2ee45ef

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/core/pipeline.py
Comment on lines +1257 to +1261
if single_stock_notify and send_notification and not dry_run:
self._send_single_stock_notification(
result,
report_type=report_type,
fallback_code=code,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep single-stock notifications out of delay-gated loop

This notification call now runs inside the same as_completed loop that applies analysis_delay, so when ANALYSIS_DELAY > 0 the second and later completed stocks can be held back by one delay interval each even if their analysis already finished. In single_stock_notify mode this regresses the prior “notify as soon as a stock finishes” behavior and can introduce substantial user-visible lag on larger stock lists.

Useful? React with 👍 / 👎.

Wanan-AN0 pushed a commit to Wanan-AN0/daily_stock_analysis that referenced this pull request Apr 1, 2026
主要更新内容:
- feat: AI预测 vs 实际走势对比视图 (ZhuLinsen#913)
- feat: 隐藏 LiteLLM 实现细节,简化模型接入 (ZhuLinsen#925)
- fix: Docker WebUI 系统设置保存问题 (ZhuLinsen#911)
- fix: A股/中文场景相关资讯恢复中文优先 (ZhuLinsen#916)
- fix: 启动早期失败时日志缺失问题 (ZhuLinsen#932)
- fix: Discord Webhook 签名验证 (ZhuLinsen#934)
- feat: Windows 安装包可选目标目录 (ZhuLinsen#918)
- fix: 断点续传逻辑 (ZhuLinsen#900)
- fix: 单股推送模式并发复用问题 (ZhuLinsen#899)
- feat: SerpAPI 正文抓取优化 (ZhuLinsen#898)
- fix: 实时行情误报问题 (ZhuLinsen#905)
- fix: 并发执行共享状态加锁 (ZhuLinsen#928)
- fix: WebUI SCHEDULE_TIME 修改不生效 (ZhuLinsen#914)
- feat: Windows 客户端支持 minimax 模型 (ZhuLinsen#917)
- feat: 版本查询功能 (ZhuLinsen#907)
- fix: 市场复盘 max_tokens 提升到 8192 (ZhuLinsen#923)

冲突解决:
- src/market_analyzer.py: 保留 report_language 参数支持中文输出
yangshiyan pushed a commit to yangshiyan/daily_stock_analysis that referenced this pull request Apr 20, 2026
* fix(issue-876): [bug]-修复单股推送模式下通知链路的共享实例并发复用问题
huangzhe1925 pushed a commit to huangzhe1925/daily_stock_analysis that referenced this pull request Apr 23, 2026
* fix(issue-876): [bug]-修复单股推送模式下通知链路的共享实例并发复用问题
EchoingFootsteps pushed a commit to EchoingFootsteps/daily_stock_analysis that referenced this pull request Jul 4, 2026
* fix(issue-876): [bug]-修复单股推送模式下通知链路的共享实例并发复用问题
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/L testing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] 修复单股推送模式下通知链路的共享实例并发复用问题

2 participants