Skip to content

fix(RichMan): handle sold-out medal shop items gracefully - #1799

Merged
runhey merged 3 commits into
runhey:devfrom
m123711:fix/medal-soldout
Sep 15, 2026
Merged

runhey merged 3 commits into
runhey:devfrom
m123711:fix/medal-soldout

Conversation

@m123711

@m123711 m123711 commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Problem

When items in the medal shop are sold out, their card templates no longer match (sold-out labels / greyed out), so all configured items fail detection. The script then blindly clicks the back button from the main screen and triggers GameStuckError -> game restart. Reproduced twice with identical stack (RichMan medal shop).

Root cause: no sold-out recognition; sold out (normal state) is treated as not found (abnormal), then wrong exit flow is taken.

Fix

  • Buy an item only when its card template is detected; otherwise record it as not-detected.
  • After processing, OCR-count the sold-out labels in the shop area and verify the not-detected items are all sold out: sold_out_count >= not_found_count -> skip normally; sold_out_count < not_found_count -> warn page may be abnormal.
  • Add timeout guard (15s) to _enter_medal and back_mall to avoid infinite click loops when the UI does not respond.

Verification

  • OCR count verified against real screenshots: 6 sold out -> count 6; 1 sold out -> count 1; bottom-nav excluded correctly.
  • py_compile and module import passed.

Sourcery 总结

妥善处理奖牌商店中已售罄的商品,并在界面无响应时保护商店导航流程。

错误修复:

  • 处理已售罄的奖牌商店商品,不将其误判为缺少页面错误,也不会触发不必要的游戏重启。
  • 当无法检测到的已配置商品数量与页面上已售罄标签的数量无法对应时发出警告。

功能增强:

  • 添加基于 OCR 的已售罄商品计数,以验证奖牌商店商品检测结果。
  • 进入奖牌商店和返回商城时添加 15 秒超时,防止 UI 交互循环无限期卡住。
Original summary in English

Sourcery 摘要

优雅地处理奖牌商店中的售罄商品,防止商店导航无响应而陷入无限交互循环。

错误修复:

  • 处理售罄的奖牌商店商品,不将其视为缺失页面,也不会触发不必要的游戏重启。
  • 当无法检测到的已配置商品与页面上售罄标签的数量无法对应时发出警告。

功能增强:

  • 为无法检测到的奖牌商店商品添加基于 OCR 的验证,并为商店导航操作设置 15 秒超时保护。
Original summary in English

Sourcery 总结

妥善处理奖牌商店中已售罄的商品,防止无响应的商店导航无限期停滞。

错误修复:

  • 处理已售罄的奖牌商店商品,避免将其误判为缺失页面或触发不必要的游戏重启。
  • 当无法将未检测到的已配置商品与商店的售罄标签对应时发出警告。

功能增强:

  • 为未检测到的奖牌商店商品添加基于 OCR 的验证,并通过超时机制保护商店导航。
Original summary in English

Summary by Sourcery

Handle sold-out medal shop items gracefully and prevent unresponsive shop navigation from stalling indefinitely.

Bug Fixes:

  • Handle sold-out medal shop items without treating them as missing pages or triggering unnecessary game restarts.
  • Warn when undetected configured items cannot be reconciled with the shop's sold-out labels.

Enhancements:

  • Add OCR-based validation for undetected medal shop items and protect shop navigation with timeouts.

- add sold-out OCR detection to count 'sold out' labels in medal shop page
- buy item only when its card template is detected; record undetected items
- after processing, verify undetected items are all sold out via OCR count,
  so a fully/partially sold-out shop finishes normally instead of hitting
  GameStuckError from blindly clicking back button
- add timeout guard to enter-medal click and back_mall to avoid infinite loops

@sourcery-ai sourcery-ai 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.

您好——我发现了 1 个问题

给 AI Agent 的提示
请处理本次代码审查中的评论:

## 单条评论

### 评论 1
<location path="tasks/RichMan/mall/medal.py" line_range="100-101" />
<code_context>
+        # 注意:页面上的售罄标签可能包含未配置购买的商品,因此用 >= 而非 ==,避免误报。
+        if not_found:
+            self.screenshot()
+            soldout_count = self.count_soldout()
+            if soldout_count >= len(not_found):
+                logger.info(f'Medal: {len(not_found)} item(s) not detected, sold out count is {soldout_count}, '\
+                            f'the not-detected items are sold out, skip normally')
</code_context>
<issue_to_address>
**issue (bug_risk):** 聚合 OCR 计数无法验证具体未检测到的已配置商品是否确实已售罄。如果页面异常导致某个模板识别失败,但另一个未配置的商品已售罄,或者本次运行中较早购买的商品在最终计数前变为售罄,那么 `soldout_count >= len(not_found)` 就会错误地将缺失的已配置商品判定为正常,并跳过异常页面处理。

**触发条件:** 至少有一个已配置商品未被检测到,且商店中存在另一个售罄标签,包括本次运行中成功购买后产生的标签。

**建议修复:** 将 OCR 识别出的售罄标签与对应的商品卡片区域关联起来,或者在购买前获取售罄状态快照,并将每个未检测到的商品与其自身区域进行比较。
</issue_to_address>

Sourcery 评估

等待批准。 请先处理 1 个发现的问题。

阻塞性发现:tasks/RichMan/mall/medal.py:101


Sourcery 对开源项目免费——如果您喜欢我们的审查结果,欢迎考虑分享 ✨
Original comment in English

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="tasks/RichMan/mall/medal.py" line_range="100-101" />
<code_context>
+        # 注意:页面上的售罄标签可能包含未配置购买的商品,因此用 >= 而非 ==,避免误报。
+        if not_found:
+            self.screenshot()
+            soldout_count = self.count_soldout()
+            if soldout_count >= len(not_found):
+                logger.info(f'Medal: {len(not_found)} item(s) not detected, sold out count is {soldout_count}, '
+                            f'the not-detected items are sold out, skip normally')
</code_context>
<issue_to_address>
**issue (bug_risk):** The aggregate OCR count does not verify that the specific not-detected configured items are sold out. A template can fail for an abnormal page while another unconfigured item is sold out, or an item bought earlier in the same run can become sold out before this final count; `soldout_count >= len(not_found)` then incorrectly classifies the missing configured item(s) as normal and skips abnormal-page handling.

**Triggers:** When at least one configured item is not detected and the shop contains another sold-out label, including a label created by a successful purchase earlier in this run.

**Suggested fix:** Associate OCR sold-out labels with the corresponding item card regions, or take the sold-out snapshot before purchases and compare each not-detected item against its own region.
</issue_to_address>

Sourcery assessment

Approval pending. 1 finding to address first.

Blocking findings: tasks/RichMan/mall/medal.py:101


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread tasks/RichMan/mall/medal.py
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Findings

  • C5 [风险]
    位置:tasks/RichMan/assets.py:RichManAssets.O_SOLD_OUT
    原因:新增 RuleOcr 资源声明,但 PR 未同步对应的 OCR 元数据文件;按清单属于资源半同步,可能导致运行时资源配置未生效。
    修改:补充并提交对应的 tasks/RichMan/ocr.json(或项目实际生成的 OCR 元数据),确认资源名、区域和关键词与 O_SOLD_OUT 一致。

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • ab.chatgpt.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "ab.chatgpt.com"

See Network Configuration for more information.

Generated by PR Review Checklist for #1799 · codex · gpt56 · 17.3 AIC · ⌖ 2.58 AIC · ⊞ 12.2K ·

@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Change Summary

  • 在勋章商店逐项购买前先做模板识别,识别不到的配置商品记录为 not_found,避免直接进入购买循环。
  • 新增全商店 OCR 的“售”字计数,以售罄数量与 not_found 数量比较后记录正常或异常日志。
  • 为进入勋章页、返回商城的 ui_click 增加 15 秒超时。

Reconstructed Intent

点击此处展开 - 这次改动最可能是为了把“商品已售罄导致模板消失”从页面异常处理为可接受的正常分支,避免继续错误导航并触发游戏重启。 - 同时希望在页面确实异常或 UI 无响应时,避免无限点击循环。

Observed Constraints

点击此处展开 - 每个配置商品的模板识别失败只能说明“未识别到”,不能单独证明“该商品售罄”。 - `O_SOLD_OUT` 覆盖的是整个商品区域,最终只比较总数;它没有把 OCR 结果绑定到具体商品卡片。 - 购买流程会按配置顺序执行,成功购买的商品可能在最终 OCR 前改变页面状态,因此最终计数并非购买前的状态快照。 - `_enter_medal()` 与 `back_mall()` 的超时返回值在调用方没有被检查;超时后流程仍会继续执行后续购买或整体退出流程。

Intent Alignment

  • 只部分覆盖。逐项识别与售罄兼容的主意图基本一致,但聚合计数不能确认具体未检测商品确实售罄;同时导航超时只增加了时间上限,没有定义超时后的安全出口。

Release Risk

  • 风险等级:中
  • 页面异常时,其他未配置商品的售罄标签,或本轮已购买商品新产生的售罄标签,可能使 soldout_count >= len(not_found) 错误判定为正常并跳过异常处理。
  • 进入/返回超时后仍继续使用当前画面,可能在错误页面上执行购买或后续商城导航;这会把“无限卡住”变成“有限时间内的错误操作”。
  • 变更覆盖勋章购买主流程,配置多个商品或页面识别不稳定时影响更明显。

Validation Gaps

点击此处展开 - 未看到针对“具体卡片售罄 vs 其他卡片售罄”的隔离验证;至少应覆盖未配置商品售罄、已购买商品变售罄、模板异常缺失三种组合。 - 未看到 `_enter_medal` / `back_mall` 超时返回 `False` 后的流程验证,需明确是否应中止当前商城任务并回退/报错。 - PR 描述提到 py_compile、导入和 OCR 截图验证,但未看到自动化测试或导航异常场景的可重复验证记录。

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • ab.chatgpt.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "ab.chatgpt.com"

See Network Configuration for more information.

Generated by PR Review Intent for #1799 · codex · gpt56 · 29.8 AIC · ⌖ 2.63 AIC · ⊞ 12.4K ·

@m123711

m123711 commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

关于 C5(O_SOLD_OUT 未同步 ocr.json):这条是误报,无需修改。

核实依据:

  1. ocr.json 不是运行时配置:项目代码中没有任何位置读取 ocr.json(全仓库仅一处注释提到该文件名)。RuleOcr 是纯 Python 类(module/atom/ocr.py),在 assets.py 中定义即生效,运行时直接构造,不依赖任何元数据文件。
  2. 已实测验证:O_SOLD_OUT 导入正常,使用真实勋章商店截图 OCR 统计售罄数量准确(6 个售罄 → 6,1 个售罄 → 1),且按 ROI(y 100-500)正确排除了底部导航"寄售屋"的"售"字干扰。

结论:O_SOLD_OUT 不需要在 ocr.json 中注册,当前 PR 无需为此修改。另补充说明合并策略:本 PR base 为 dev 分支,建议先在 dev 长期测试、确认稳定后再合入 master。

@runhey

runhey commented Sep 10, 2026

Copy link
Copy Markdown
Owner

“# 售罄 OCR:统计勋章商店页面中"售"字(售罄标签)数量,用于核对识别失败的商品是否均为售罄
O_SOLD_OUT = RuleOcr(roi=(0,100,1280,500), area=(0,100,1280,500), mode="Full", method="Default", keyword="售", name="medal_sold_out")”

这条是你自己加的对吧,项目里面都是用工具给转成python代码的,下次刷一下就没了

@runhey
runhey merged commit 82528d0 into runhey:dev Sep 15, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants