feat: 增加全国气象预警对账补偿 - #144
Conversation
Reviewer's Guide添加一个可选的全国范围“中国天气”对账(reconciliation)流水线:轮询紧凑预警索引,将详细载荷规范化为与 FAN 兼容的天气事件,并在具有稳健去重和安全检查的前提下,将其注入现有的 China Weather 对账轮询与分发的时序图sequenceDiagram
participant Runtime as DisasterServiceRuntimeService
participant Reconciler as ChinaWeatherReconciler
participant HTTP as aiohttp_ClientSession
participant Parser as WeatherAlarmParser
participant Pipeline as DisasterEventPipeline
Runtime->>Runtime: start_scheduled_http_fetch()
Runtime->>Runtime: _run_china_weather_loop(fallback_config)
Runtime->>HTTP: ClientSession(timeout, headers)
loop every poll_interval_seconds while service.running
Runtime->>HTTP: fetch_text(_CHINA_WEATHER_INDEX_URL)
HTTP-->>Runtime: index_script
Runtime->>Reconciler: reconcile(index_script, fetch_detail, _dispatch_china_weather_payload)
Reconciler->>HTTP: fetch_detail(detail_path)
HTTP-->>Reconciler: detail_script
Reconciler->>Reconciler: parse_warning_detail(detail_script, reference)
Reconciler->>Runtime: _dispatch_china_weather_payload(payload)
Runtime->>Parser: parse_event("china_weather_fanstudio", json.dumps(payload))
Parser-->>Runtime: event
Runtime->>Pipeline: _handle_disaster_event(event)
end
File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your Experience访问你的 dashboard 来:
Getting HelpOriginal review guide in EnglishReviewer's GuideAdd an optional nationwide China Weather reconciliation pipeline that polls a compact warning index, normalizes detail payloads into FAN-compatible weather events, and feeds them into the existing china_weather_fanstudio flow with robust deduplication and safety checks. Sequence diagram for China Weather reconciliation polling and dispatchsequenceDiagram
participant Runtime as DisasterServiceRuntimeService
participant Reconciler as ChinaWeatherReconciler
participant HTTP as aiohttp_ClientSession
participant Parser as WeatherAlarmParser
participant Pipeline as DisasterEventPipeline
Runtime->>Runtime: start_scheduled_http_fetch()
Runtime->>Runtime: _run_china_weather_loop(fallback_config)
Runtime->>HTTP: ClientSession(timeout, headers)
loop every poll_interval_seconds while service.running
Runtime->>HTTP: fetch_text(_CHINA_WEATHER_INDEX_URL)
HTTP-->>Runtime: index_script
Runtime->>Reconciler: reconcile(index_script, fetch_detail, _dispatch_china_weather_payload)
Reconciler->>HTTP: fetch_detail(detail_path)
HTTP-->>Reconciler: detail_script
Reconciler->>Reconciler: parse_warning_detail(detail_script, reference)
Reconciler->>Runtime: _dispatch_china_weather_payload(payload)
Runtime->>Parser: parse_event("china_weather_fanstudio", json.dumps(payload))
Parser-->>Runtime: event
Runtime->>Pipeline: _handle_disaster_event(event)
end
File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Code Review
This pull request introduces an optional, low-frequency China Weather national active warning reconciliation fallback (weather_alarm_fallback) to supplement the real-time FAN Studio stream. It adds the configuration schema, implements the core reconciliation and parsing logic with a bounded TTL cache for deduplication, integrates the polling loop into the disaster service runtime, and includes comprehensive unit tests. The review feedback highlights two important optimization opportunities: first, removing the detail semaphore restriction around the downstream dispatch call to prevent performance bottlenecks, and second, optimizing the BoundedTTLSet._purge_expired method to break early from the ordered dictionary traversal once a non-expired entry is encountered.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
Hey - 我发现了 1 个问题,并留下了一些整体性的反馈:
- 在
ChinaWeatherReconciler._process_reference中,同一个detail_semaphore被用来同时保护网络请求和后续的下游分发;如果你的意图只是限制 HTTP 并发数量,建议不要在分发阶段也使用这个信号量包裹,这样就不会不必要地把事件管线串行化。 - 对账测试通过
importlib.util.spec_from_file_location和一些合成包来构建自定义的模块导入图;这相当复杂,而且在未来目录结构变化时可能比较脆弱——建议重构为直接通过公共包 API 进行测试,或者尽可能使用更简单的假对象 / stub。
给 AI Agent 的提示
Please address the comments from this code review:
## Overall Comments
- In `ChinaWeatherReconciler._process_reference`, the same `detail_semaphore` is used to guard both network fetch and downstream dispatch; if the intent is only to cap HTTP concurrency, consider not wrapping the dispatch in the semaphore so you don’t unnecessarily serialize the event pipeline.
- The reconciliation tests build a custom module import graph using `importlib.util.spec_from_file_location` and synthetic packages; this is quite intricate and may be brittle against future layout changes—consider refactoring to exercise the public package API directly or using simpler fakes/stubs where possible.
## Individual Comments
### Comment 1
<location path="tests/test_china_weather_reconciliation.py" line_range="631-271" />
<code_context>
+ async def test_unsafe_detail_paths_are_rejected_before_fetch(self) -> None:
</code_context>
<issue_to_address>
**suggestion (testing):** Add direct unit tests for validate_detail_path to cover all path validation rules.
The async reconciler test verifies that obviously unsafe paths are blocked, but `validate_detail_path` enforces additional rules that aren’t directly tested:
- Rejecting leading/trailing whitespace
- Handling URL-encoded components (e.g. `%2e%2e%2fencoded.html`)
- Empty string and non-string inputs
- Single-dot and double-dot names (`"."`, "..")
Because `validate_detail_path` is exported from `core.services.weather` and acts as a security-critical guard, please add targeted unit tests that call it directly and assert both allowed and rejected cases, so future changes to the path rules are captured explicitly rather than inferred via reconciler behavior.
Suggested implementation:
```python
async def test_unsafe_detail_paths_are_rejected_before_fetch(self) -> None:
def test_validate_detail_path_accepts_safe_paths(self) -> None:
safe_paths = (
"a.html",
"b.json",
"index.html",
)
for path in safe_paths:
# Should not raise for safe, normalized paths
validate_detail_path(path)
def test_validate_detail_path_rejects_unsafe_and_malformed_paths(self) -> None:
unsafe_paths = (
# Existing unsafe patterns
"https://evil.example/a.html",
"//evil.example/a.html",
"/absolute.html",
"../traversal.html",
"nested/a.html",
"nested\\a.html",
"a.html?query=1",
# Leading/trailing whitespace
" leading.html",
"trailing.html ",
"\ta.html",
"\na.html",
# URL-encoded components
"%2e%2e%2fencoded.html", # "../encoded.html"
"%2E%2E%2Fencoded.html",
# Empty and non-path-ish inputs
"",
" ",
# Single-dot and double-dot names
".",
"..",
)
for path in unsafe_paths:
with self.assertRaises(ValueError):
validate_detail_path(path)
```
1. Ensure `validate_detail_path` is imported at the top of `tests/test_china_weather_reconciliation.py`, e.g.:
`from core.services.weather import validate_detail_path`.
2. If `validate_detail_path` signals invalid paths using a different exception type (e.g. `RuntimeError` or a custom exception) or by returning a boolean instead of raising, adjust the `assertRaises(ValueError)` block accordingly:
- If it returns `False` for invalid paths, change the loop to `self.assertFalse(validate_detail_path(path))`.
- If it returns the normalized path for valid inputs, you may want to assert equality for some of the safe cases, e.g. `self.assertEqual(path, validate_detail_path(path))`.
3. If your test class uses any specific mixins or helpers for validation-related tests, you can move these new test methods into that class or adapt naming/structure to match existing conventions.
</issue_to_address>帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续评审。
Original comment in English
Hey - I've found 1 issue, and left some high level feedback:
- In
ChinaWeatherReconciler._process_reference, the samedetail_semaphoreis used to guard both network fetch and downstream dispatch; if the intent is only to cap HTTP concurrency, consider not wrapping the dispatch in the semaphore so you don’t unnecessarily serialize the event pipeline. - The reconciliation tests build a custom module import graph using
importlib.util.spec_from_file_locationand synthetic packages; this is quite intricate and may be brittle against future layout changes—consider refactoring to exercise the public package API directly or using simpler fakes/stubs where possible.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `ChinaWeatherReconciler._process_reference`, the same `detail_semaphore` is used to guard both network fetch and downstream dispatch; if the intent is only to cap HTTP concurrency, consider not wrapping the dispatch in the semaphore so you don’t unnecessarily serialize the event pipeline.
- The reconciliation tests build a custom module import graph using `importlib.util.spec_from_file_location` and synthetic packages; this is quite intricate and may be brittle against future layout changes—consider refactoring to exercise the public package API directly or using simpler fakes/stubs where possible.
## Individual Comments
### Comment 1
<location path="tests/test_china_weather_reconciliation.py" line_range="631-271" />
<code_context>
+ async def test_unsafe_detail_paths_are_rejected_before_fetch(self) -> None:
</code_context>
<issue_to_address>
**suggestion (testing):** Add direct unit tests for validate_detail_path to cover all path validation rules.
The async reconciler test verifies that obviously unsafe paths are blocked, but `validate_detail_path` enforces additional rules that aren’t directly tested:
- Rejecting leading/trailing whitespace
- Handling URL-encoded components (e.g. `%2e%2e%2fencoded.html`)
- Empty string and non-string inputs
- Single-dot and double-dot names (`"."`, "..")
Because `validate_detail_path` is exported from `core.services.weather` and acts as a security-critical guard, please add targeted unit tests that call it directly and assert both allowed and rejected cases, so future changes to the path rules are captured explicitly rather than inferred via reconciler behavior.
Suggested implementation:
```python
async def test_unsafe_detail_paths_are_rejected_before_fetch(self) -> None:
def test_validate_detail_path_accepts_safe_paths(self) -> None:
safe_paths = (
"a.html",
"b.json",
"index.html",
)
for path in safe_paths:
# Should not raise for safe, normalized paths
validate_detail_path(path)
def test_validate_detail_path_rejects_unsafe_and_malformed_paths(self) -> None:
unsafe_paths = (
# Existing unsafe patterns
"https://evil.example/a.html",
"//evil.example/a.html",
"/absolute.html",
"../traversal.html",
"nested/a.html",
"nested\\a.html",
"a.html?query=1",
# Leading/trailing whitespace
" leading.html",
"trailing.html ",
"\ta.html",
"\na.html",
# URL-encoded components
"%2e%2e%2fencoded.html", # "../encoded.html"
"%2E%2E%2Fencoded.html",
# Empty and non-path-ish inputs
"",
" ",
# Single-dot and double-dot names
".",
"..",
)
for path in unsafe_paths:
with self.assertRaises(ValueError):
validate_detail_path(path)
```
1. Ensure `validate_detail_path` is imported at the top of `tests/test_china_weather_reconciliation.py`, e.g.:
`from core.services.weather import validate_detail_path`.
2. If `validate_detail_path` signals invalid paths using a different exception type (e.g. `RuntimeError` or a custom exception) or by returning a boolean instead of raising, adjust the `assertRaises(ValueError)` block accordingly:
- If it returns `False` for invalid paths, change the loop to `self.assertFalse(validate_detail_path(path))`.
- If it returns the normalized path for valid inputs, you may want to assert equality for some of the safe cases, e.g. `self.assertEqual(path, validate_detail_path(path))`.
3. If your test class uses any specific mixins or helpers for validation-related tests, you can move these new test methods into that class or adapt naming/structure to match existing conventions.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
|
已在提交
全量测试从 34 增至 36, 关于测试中的合成包导入:当前仓库模块会经包初始化间接依赖 AstrBot,而独立单测环境没有安装 AstrBot,因此保留最小 stub 以隔离纯逻辑;PR 前已另用真实 AstrBot 环境执行公共包导入烟测,生产导入路径没有被弱化。 |
|
补充修复了实网发现的气象预警图标错配:上游实时流可能把 CMA 紧凑 TYPECODE 放进 11B 前缀中,例如高温事件携带 11B07,而 FAN 图标接口按国家标准将 11B07 解释为沙尘暴。现在解析边界会按已知预警语义规范化为标准 11B 图标码,复合灾种采用最长匹配,未知语义保持原码。新增高温实案、常见 14 类、复合灾种和未知类型回归测试;本分支全量 40/40 通过,Ruff、format、compileall 与 diff-check 均通过。 |
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 247 |
| Duplication | 0 |
AI Reviewer: first review requested successfully. AI can make mistakes. Always validate suggestions.
TIP This summary will be updated as you push new changes.
There was a problem hiding this comment.
Pull Request Overview
The pull request is currently not up to standards according to Codacy analysis. The most significant concern is a potential logic flaw in the weather parser's deduplication mechanism, where a mismatch between internal IDs and payload IDs could cause redundant alerts.
Additionally, several files exhibit high complexity or excessive length, notably in the runtime loop and the weather warning parser. While the feature implementation aligns with the requirement to provide an optional, bounded reconciliation service for China Weather alerts, refactoring is recommended for the main polling loop and the data parsing logic to ensure long-term maintainability.
Test suggestions
- Verify that the first reconciliation cycle establishes a baseline and does not trigger alerts.
- Verify that the BoundedTTLSet correctly expires old entries and respects the entry limit.
- Verify that validate_detail_path rejects absolute paths, directory traversal (../), and URL parameters.
- Verify that normalize_weather_warning_code corrects conflicting codes based on semantic text analysis.
- Verify that the fallback configuration correctly clamps out-of-bounds numeric values for interval, timeout, and concurrency.
- Verify that detail fetch failures are retried in the next cycle while dispatch failures follow 'at-most-once' semantics.
TIP Improve review quality by adding custom instructions
TIP How was this review? Give us feedback
|
✅ Health: 8.1 (unchanged) 📋 At a glance 🚨 Change risk: high (riskier than 99% of this repo's commits)
🔎 More signals (1)🔥 Hotspots touched (2)
👀 Suggested reviewers @DBJD-CR 📊 Full report · ⭐ Star Repowise · 📥 Install bot · Last updated 2026-07-17 11:32 UTC |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (5)
🚧 Files skipped from review as they are similar to previous changes (4)
📜 Recent review details⏰ Context from checks skipped due to timeout. (1)
🔇 Additional comments (1)
📝 WalkthroughWalkthrough新增 China Weather 全国气象预警对账补偿能力,包含配置、索引与详情解析、快照去重、事件分发、运行时轮询、告警编码规范化及相关测试和文档。 Changes气象预警对账补偿
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant RuntimeScheduler
participant ChinaWeatherReconciler
participant ChinaWeather
participant DisasterEventHandler
RuntimeScheduler->>ChinaWeatherReconciler: 启动轮询周期
ChinaWeatherReconciler->>ChinaWeather: 请求活动预警索引
ChinaWeather-->>ChinaWeatherReconciler: 返回新告警引用
ChinaWeatherReconciler->>ChinaWeather: 请求新增告警详情
ChinaWeather-->>ChinaWeatherReconciler: 返回详情载荷
ChinaWeatherReconciler->>DisasterEventHandler: 投递 FAN 兼容事件
Suggested labels: Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@core/parsers/weather_parser.py`:
- Around line 20-40: 更新 _extract_issue_time,使用严格正则从事件 ID 中解析官方下划线格式和 FAN
连字符格式的时间段(如 310000-20260713100000-11B0102)。仅接受完整有效的时间字段,解析失败或格式不匹配时继续返回
effective_time,确保缺失 effective 时仍能使用 ID 中的发布时间。
In `@core/services/weather/china_weather_reconciliation.py`:
- Around line 290-295: 限制新增记录的处理规模,避免在 asyncio.gather 中为 new_references
的每条记录一次性创建任务。更新包含 _process_reference 的处理流程,使用固定数量 worker
或有界队列(或在进入处理前拒绝超过容量的快照),确保并发与待处理任务数量有明确上限,而不要仅依赖 detail_concurrency 或
max_entries。
In `@README.md`:
- Around line 557-564: 将 README.md 中 weather_alarm_fallback 配置示例包装在最外层 JSON
对象的大括号内,使用户复制整个代码块时得到有效 JSON;保留现有配置键和值不变。
In `@tests/test_china_weather_reconciliation.py`:
- Around line 475-482: Update the missing_type_code and unsupported_level_code
payloads in test_parse_warning_detail_rejects_missing_or_unsupported_codes to
include the matching identifier expected by REF_A, while preserving each
payload’s intended invalid condition so the tests reach the missing TYPECODE and
unsupported LEVELCODE branches respectively.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 904c10e3-e307-46b5-99f2-2cef2d18ad76
📒 Files selected for processing (10)
CHANGELOG.mdREADME.md_conf_schema.jsoncore/app/runtime/disaster_service_runtime.pycore/parsers/weather_parser.pycore/services/weather/__init__.pycore/services/weather/china_weather_reconciliation.pycore/services/weather/warning_code_normalization.pytests/test_china_weather_reconciliation.pytests/test_disaster_service_runtime.py
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
- GitHub Check: Codacy Static Code Analysis
🧰 Additional context used
🪛 ast-grep (0.44.1)
core/app/runtime/disaster_service_runtime.py
[warning] 29-29: Do not make http calls without encryption
Context: "http://www.weather.com.cn/alarm/"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.
(requests-http)
[info] 271-271: use jsonify instead of json.dumps for JSON output
Context: json.dumps(payload, ensure_ascii=False)
Note: [CWE-116] Improper Encoding or Escaping of Output.
(use-jsonify)
tests/test_china_weather_reconciliation.py
[info] 136-136: use jsonify instead of json.dumps for JSON output
Context: json.dumps({'count': str(len(rows)), 'data': rows})
Note: [CWE-116] Improper Encoding or Escaping of Output.
(use-jsonify)
[info] 140-149: use jsonify instead of json.dumps for JSON output
Context: json.dumps(
{
"ISSUETIME": "2026-07-13 10:10:00",
"head": reference.title,
"ISSUECONTENT": "Expect severe weather.",
"TYPECODE": "01",
"LEVELCODE": "02",
"identifier": reference.identifier,
}
)
Note: [CWE-116] Improper Encoding or Escaping of Output.
(use-jsonify)
tests/test_disaster_service_runtime.py
[warning] 188-188: Do not make http calls without encryption
Context: "http://www.weather.com.cn/alarm/"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.
(requests-http)
[warning] 276-276: Do not make http calls without encryption
Context: "http://www.weather.com.cn/alarm/"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.
(requests-http)
🪛 GitHub Check: Codacy Static Code Analysis
tests/test_china_weather_reconciliation.py
[warning] 1-1: tests/test_china_weather_reconciliation.py#L1
File tests/test_china_weather_reconciliation.py has 618 non-comment lines of code
[failure] 214-214: tests/test_china_weather_reconciliation.py#L214
resolver is not callable
[failure] 228-228: tests/test_china_weather_reconciliation.py#L228
resolver is not callable
[failure] 238-238: tests/test_china_weather_reconciliation.py#L238
resolver is not callable
[failure] 564-564: tests/test_china_weather_reconciliation.py#L564
reconciler_type is not callable
tests/test_disaster_service_runtime.py
[failure] 169-169: tests/test_disaster_service_runtime.py#L169
resolver is not callable
[failure] 210-210: tests/test_disaster_service_runtime.py#L210
resolver is not callable
🪛 LanguageTool
CHANGELOG.md
[uncategorized] ~12-~12: 您的意思是“"不"齐”?
Context: ...中国天气网全国活动预警对账补偿,可在不替换 FAN Studio 实时流的前提下补齐可能遗漏的中间气象预警。 - 气象预警事件 ID 去重缓存扩展为 24 小时、...
(BU)
🔇 Additional comments (10)
_conf_schema.json (1)
190-235: LGTM!Also applies to: 968-968
core/services/weather/china_weather_reconciliation.py (1)
1-289: LGTM!Also applies to: 296-461
core/services/weather/warning_code_normalization.py (1)
1-116: LGTM!core/services/weather/__init__.py (1)
1-32: LGTM!tests/test_china_weather_reconciliation.py (1)
1-474: LGTM!Also applies to: 483-752
core/parsers/weather_parser.py (1)
15-19: LGTM!Also applies to: 41-52, 92-92, 109-129, 194-196
core/app/runtime/disaster_service_runtime.py (1)
12-31: LGTM!Also applies to: 106-107, 185-276
tests/test_disaster_service_runtime.py (1)
1-326: LGTM!README.md (1)
120-120: LGTM!Also applies to: 422-422, 444-444, 545-556, 565-565
CHANGELOG.md (1)
8-22: LGTM!
|
感觉只拿来做预警对账源的话有点可惜?如果你能从中国天气网上抓取到完整的一个不漏的气象预警信息,其实我更推荐你把它单独做成一个独立的数据源。而且现在Fan的气象预警确实推送频率降低了不少,好像每15/30分钟才推一条。 另外由此可能产生的大量推送,你可以参考一下 #109 中提到的合并转发,设计一个合并转发的机制(暂时可以先只适配该数据源)。如果是其他平台,可能需要设计一些熔断机制,不过问题不大,可以之后再补上。 |
|
哈哈是的,会刷屏的问题存在。我之前<关键词白名单>里填的“上海”,被群友说一直刷太烦,于是改成具体区名了。 独立数据源方向我研究下看看可靠不 |
📝 描述 / Description
FAN Studio 气象 WebSocket 当前只提供单条最新快照;多个地区在同一采集周期内连续发布预警时,中间事件可能在进入 AstrBot 前被覆盖。
本 PR 增加一个默认关闭、全国通用的中国天气网活动预警对账源。它不替换 FAN 实时流,也不针对上海或任何单一地区写特殊规则。
Closes #143
🛠️ 改动点 / Modifications
新增中国天气网紧凑活动预警索引与详情解析,按官方标识、灾种和等级重建 FAN 兼容事件 ID。
首次成功快照仅建立基线;后续只抓取新官方 ID 的详情。
继续复用
china_weather_fanstudio的解析、过滤、展示、统计和发送链。新增 24 小时、最多 4096 条的气象事件 ID 缓存,抑制 FAN 与 HTTP 到达顺序造成的重复推送。
详情校验、下载或解析失败会隔离并在下一轮重试;一旦进入现有发送链,本层按最多一次语义处理,避免部分发送后的重复。
严格限制详情路径,拒绝协议、主机、绝对路径、目录穿越、查询参数、片段和编码路径。
新增默认关闭的
weather_alarm_fallback配置,轮询、超时和并发均有上下界。保留既有 Wolfx 任务和 FAN WebSocket 行为;未启用配置时不创建对账任务。
这不是一个破坏性变更 / This is NOT a breaking change.
📸 运行截图或测试结果 / Screenshots or Test Results
额外验证:
_conf_schema.json可正常解析。✅ 检查清单 / Checklist
aiohttp。Summary by Sourcery
添加一个可选的全国级“中国天气”对账管线,用于补充现有的 CMA 预警,扩展天气 ID 去重能力,并记录新的回退行为和配置。
新特性:
weather_alarm_fallback,为对账循环设置受限的轮询间隔、请求超时和详情并发度。增强:
文档:
测试:
Original summary in English
Summary by Sourcery
Add an optional nationwide China Weather reconciliation pipeline to complement existing CMA alerts, expanding weather ID deduplication and documenting the new fallback behaviour and configuration.
New Features:
weather_alarm_fallbackruntime option, with bounded polling interval, request timeout, and detail concurrency for the reconciliation loop.Enhancements:
Documentation:
Tests:
Summary by CodeRabbit