Conversation
35af225 to
f45c2b3
Compare
There was a problem hiding this comment.
Hey - 我在这里给出一些整体性的反馈:
- 在
SelectItemAction.Run中,你再次调用了resolveGoodsRegion,但识别阶段其实已经完成了区域解析;可以考虑将解析好的区域(以及可能的锚点)放进RecognitionData中,这样可以避免重复解析,也能防止在识别和选择之间锚点变化导致的不一致。 - 在
routeSkipWithAbortReason和stopTaskWithFocus中使用带内联 HTML 的fmt.Printf,与其他聚焦/日志流程(使用的是maafocus和结构化日志)不一致;建议将所有面向用户的通知集中到一个统一机制中,避免混用不同的输出渠道和格式。 - 在
resolveQuantityUpperBound中,当reserveStockBill <= 0时,你返回MaxBuy: 0和CappedQuantity: quotaCurrent,这样会让MaxBuy作为上限的语义变得不清晰;你可能希望将MaxBuy设置为quotaCurrent或者一个有文档说明的哨兵值(例如math.MaxInt32),以便下游的日志和“最大可购买数量”的推理保持一致。
给 AI Agent 的提示
请根据这次代码审查中的评论进行修改:
## 总体评论
- 在 `SelectItemAction.Run` 中,你再次调用了 `resolveGoodsRegion`,但识别阶段其实已经完成了区域解析;可以考虑将解析好的区域(以及可能的锚点)放进 `RecognitionData` 中,这样可以避免重复解析,也能防止在识别和选择之间锚点变化导致的不一致。
- 在 `routeSkipWithAbortReason` 和 `stopTaskWithFocus` 中使用带内联 HTML 的 `fmt.Printf`,与其他聚焦/日志流程(使用的是 `maafocus` 和结构化日志)不一致;建议将所有面向用户的通知集中到一个统一机制中,避免混用不同的输出渠道和格式。
- 在 `resolveQuantityUpperBound` 中,当 `reserveStockBill <= 0` 时,你返回 `MaxBuy: 0` 和 `CappedQuantity: quotaCurrent`,这样会让 `MaxBuy` 作为上限的语义变得不清晰;你可能希望将 `MaxBuy` 设置为 `quotaCurrent` 或者一个有文档说明的哨兵值(例如 `math.MaxInt32`),以便下游的日志和“最大可购买数量”的推理保持一致。帮我变得更有用!请对每条评论点选 👍 或 👎,我会根据你的反馈改进今后的代码审查。
Original comment in English
Hey - I've left some high level feedback:
- In
SelectItemAction.Runyou re-callresolveGoodsRegioneven though the recognition phase has already resolved region; consider carrying the resolved region (and possibly anchor) inRecognitionDatato avoid duplicate resolution and potential inconsistencies if the anchor changes between recognition and selection. - The use of
fmt.Printfwith inline HTML inrouteSkipWithAbortReasonandstopTaskWithFocusis inconsistent with the rest of the focus/logging flow (which usesmaafocusand structured logs); consider centralizing user-facing notifications through a single mechanism to avoid mixing output channels and formats. - In
resolveQuantityUpperBound, whenreserveStockBill <= 0you returnMaxBuy: 0andCappedQuantity: quotaCurrent, which makesMaxBuymisleading as an upper bound; you may want to setMaxBuytoquotaCurrentor a documented sentinel (e.g.,math.MaxInt32) so downstream logging and reasoning about max purchasable quantity remain consistent.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `SelectItemAction.Run` you re-call `resolveGoodsRegion` even though the recognition phase has already resolved region; consider carrying the resolved region (and possibly anchor) in `RecognitionData` to avoid duplicate resolution and potential inconsistencies if the anchor changes between recognition and selection.
- The use of `fmt.Printf` with inline HTML in `routeSkipWithAbortReason` and `stopTaskWithFocus` is inconsistent with the rest of the focus/logging flow (which uses `maafocus` and structured logs); consider centralizing user-facing notifications through a single mechanism to avoid mixing output channels and formats.
- In `resolveQuantityUpperBound`, when `reserveStockBill <= 0` you return `MaxBuy: 0` and `CappedQuantity: quotaCurrent`, which makes `MaxBuy` misleading as an upper bound; you may want to set `MaxBuy` to `quotaCurrent` or a documented sentinel (e.g., `math.MaxInt32`) so downstream logging and reasoning about max purchasable quantity remain consistent.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
Pull request overview
本 PR 为 AutoStockpile 增加“保留调度券”能力,并将识别/中止结果契约重构为“可跳过告警 vs 致命错误”,配套更新 Pipeline、任务选项与多语言文案,以实现更清晰可控的跳过/停止行为。
Changes:
- 新增调度券 OCR(Helper 节点 + Go 侧解析/限购上限计算),并在任务配置中加入按地区的“保留调度券”开关与数量输入。
- 重构识别结果结构与中止原因(AbortReason),在识别与选择阶段统一走 Skip 分支或致命停止分支。
- 更新 AutoStockpile Pipeline(统一 Skip 节点、替换模板图资源)、维护文档与 locales 文案。
Reviewed changes
Copilot reviewed 22 out of 24 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| docs/zh_cn/developers/auto-stockpile-maintain.md | 更新维护指南:阈值解析、保留调度券说明、地区/档位自检清单等 |
| docs/en_us/developers/auto-stockpile-maintain.md | 同步英文维护指南,补充阈值与保留调度券说明 |
| assets/tasks/AutoStockpile.json | 增加按地区保留调度券选项;收紧价格阈值输入校验 |
| assets/resource/pipeline/AutoStockpile/Task.json | 更新模板图引用;用统一的 AutoStockpileSkip 取代旧兜底节点;加入 dev 跳过节点 |
| assets/resource/pipeline/AutoStockpile/Main.json | 调整 SubTask custom_action_param 配置(移除 continue) |
| assets/resource/pipeline/AutoStockpile/Helper.json | 移除溢出 ColorMatch 节点;新增调度券 OCR 节点 AutoStockpileGetStockBill |
| assets/resource/image/AutoStockpile/StockRedistributionKettle.png | 新增/替换模板图资源 |
| assets/resource/image/AutoStockpile/RegionalDevelopmentFunctionLocked.png | 新增/替换模板图资源 |
| assets/misc/locales/zh_tw.json | 增加保留调度券相关文案 |
| assets/misc/locales/zh_cn.json | 增加保留调度券相关文案 |
| assets/misc/locales/ko_kr.json | 增加保留调度券相关文案 |
| assets/misc/locales/ja_jp.json | 增加保留调度券相关文案 |
| assets/misc/locales/en_us.json | 增加保留调度券相关文案 |
| agent/go-service/autostockpile/types.go | 引入 AbortReason 契约、RecognitionResult/Data 拆分、阈值严格解析错误类型等 |
| agent/go-service/autostockpile/thresholds.go | 阈值覆盖解析改为严格正数解析 |
| agent/go-service/autostockpile/stockbill.go | 新增调度券 OCR 解析与“可购买数量上限”计算 |
| agent/go-service/autostockpile/server_time.go | 引入服务器时区与 04:00 日界线的周日判定 |
| agent/go-service/autostockpile/selector.go | 统一 Skip 分支路由;按 AbortReason 决定跳过/停止;加入数量决策与更丰富日志 |
| agent/go-service/autostockpile/register.go | 注册阶段初始化 AbortReason 文案表 |
| agent/go-service/autostockpile/recognition.go | 识别阶段:地区解析失败致命;支持调度券 OCR;识别结果按新契约输出;新增档位合法性校验 |
| agent/go-service/autostockpile/quantity.go | 新增购买数量决策与对应 Pipeline override 生成 |
| agent/go-service/autostockpile/options.go | 选项解析返回 AbortReason;按地区提取 reserve_stock_bill 并换算“万”单位 |
| agent/go-service/autostockpile/abort_reason.json | 新增 AbortReason -> 文案映射(embedded) |
| agent/go-service/autostockpile/abort_reason.go | 新增 embedded 文案表加载/校验与查询 API |
- 移除不稳定的溢出颜色兜底分支 - 溢出详情缺失时仅记录告警 - 删除旧识别节点并新增调度券 OCR 节点
- 新增调度券 OCR、保留额度配置与多语言文案 - 额度不足或无可用购买额度时在识别阶段提前结束 - 根据剩余调度券自动限制购买数量并兼容防溢出/周日逻辑
- 区域、购买配置、阈值和商品档位异常改为致命错误并直接停任务 - 调度券与商品 OCR 不可用时提前跳过本轮购买 - 识别结果新增调度券可用性状态,并统一焦点提示与中止分支
- 将 NoCandidate 分支重命名为 Skip,并同步调整数量决策与 Pipeline 路由 - 对 OCR 异常和致命错误区分提示方式,识别阶段可直接跳过或停止任务 - 将价格阈值与保留调度券输入限制为非空正整数
- 补充阈值回退、保留调度券与运行时覆盖行为 - 更正新增档位与地区时的维护入口和默认值位置 - 同步收敛中英文文档结构与常见坑说明
f45c2b3 to
3d07c5a
Compare
| val, err := strconv.ParseFloat(match[1], 64) | ||
| if err != nil { | ||
| continue | ||
| } | ||
| beforeSlash := strings.SplitN(match[0], "/", 2)[0] | ||
| if strings.Contains(beforeSlash, "万") { | ||
| return int(val * 10000), true | ||
| } | ||
| return int(val), true |
There was a problem hiding this comment.
parseStockBillAmount 把 OCR 提取到的浮点数直接 int(val*10000)/int(val) 截断成整数,存在浮点精度导致的误差/截断问题(例如 0.6 万可能因为二进制表示被截成 5999)。建议改为使用 math.Round(或在可能的情况下直接按字符串/整数解析)并同时考虑上限校验,避免异常大值导致溢出。
| // 使用 parsePriceLimitValue 解析 int 或 string 格式 | ||
| parsedValue, err := parsePriceLimitValue(rawValue) | ||
| if err != nil { | ||
| return 0, true, fmt.Errorf("%s: %w", key, err) |
There was a problem hiding this comment.
collectRegionReserveStockBill 对 reserve_stock_bill_{Region} 的解析错误目前会走 SelectionConfigInvalidFatal(因为这里没有包一层 thresholdConfigError),导致用户看到的中止原因与“阈值配置无效”不一致。建议这里复用 parsePositiveThresholdValue/newThresholdConfigError 来包装错误,让上层能稳定映射到 AbortReasonThresholdConfigInvalidFatal。
| return 0, true, fmt.Errorf("%s: %w", key, err) | |
| return 0, true, newThresholdConfigError(key, err) |
| } | ||
|
|
||
| // 将用户输入("万"单位)转换为实际数值,乘以 10000 | ||
| return parsedValue * 10000, true, nil | ||
| } |
There was a problem hiding this comment.
这里将用户输入值 parsedValue 直接乘以 10000(万单位转换)存在 int 溢出风险:当输入过大时会发生回绕,导致后续比较/限购逻辑异常。建议在乘法前做上限检查(例如 parsedValue > math.MaxInt/10000 时返回错误或饱和到最大可表示值)。
|
|
||
| overflowDetected := false | ||
| overflowAmount := 0 | ||
| overflowCurrent := 0 |
There was a problem hiding this comment.
当 runOverflowDetailOCR 失败时,overflowCurrent 会保持默认值 0 并继续流程,最终写入 RecognitionData.Quota.Current=0。这会把“额度未知”伪装成“额度为 0”,在后续数量决策(尤其是启用保留调度券时的上限计算)中可能导致误判为不可购买/过度限购。建议显式携带“额度识别是否可用”的标记(或用 -1 之类的哨兵值)并在下游逻辑中按“未知”分支处理;或者在需要额度的场景下将其作为可跳过告警直接走 Skip。
| overflowCurrent := 0 | |
| overflowCurrent := -1 |
| if _, err := priceLimitTierIDFromAttachKey(key); err != nil { | ||
| return 0, err | ||
| } | ||
|
|
||
| var stringValue string | ||
| if err := json.Unmarshal(data, &stringValue); err == nil { | ||
| if strings.TrimSpace(stringValue) == "" { | ||
| return requireDefaultPriceLimitForTier(tierID) | ||
| } | ||
| } | ||
|
|
||
| threshold, err := parsePriceLimitValue(data) | ||
| if err != nil { | ||
| return 0, err | ||
| } | ||
|
|
||
| return normalizePriceLimitThreshold(tierID, threshold), nil | ||
| return parsePositiveThresholdValue(key, data) |
There was a problem hiding this comment.
parsePriceLimitOverrideValue 这里把完整 attach key 作为 parsePositiveThresholdValue 的 field 传入;而上游收集阈值时又会再用 key 做一次 fmt.Errorf("%s: %w", key, err) 包装,容易产生重复前缀(形如 price_limits_xxx: price_limits_xxx: ...)的错误文本。建议仅在一处添加字段前缀:要么这里传更短的 field(例如仅 tier/子字段名),要么保证调用方不再重复包一层 key。
Summary by Sourcery
为 AutoStockpile 的识别与选择流程新增存货账单预留(stock bill reserve)支持,并优化中止处理逻辑,同时相应更新流水线、配置和文档。
新功能:
增强:
文档:
Original summary in English
Summary by Sourcery
Add stock bill reserve support and refined abort handling to AutoStockpile recognition and selection flows, updating pipelines, configuration, and docs accordingly.
New Features:
Enhancements:
Documentation: