Skip to content

对弈竞猜更新 - #1848

Merged
runhey merged 2 commits into
runhey:devfrom
xylolit-mu:pr
Sep 30, 2026
Merged

runhey merged 2 commits into
runhey:devfrom
xylolit-mu:pr

Conversation

@xylolit-mu

@xylolit-mu xylolit-mu commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

更新十周年对弈竞猜资源

Sourcery 摘要

更新 FrogBoss 对周年庆资源的下注支持,并引入持久化的 Oas 预测策略。

新功能:

  • 添加 Oas 策略,将精选预测和群体情绪结合起来,并通过基于结果的持久化可靠性评分进行评估。
  • 使用阵容指纹和 JSONL 历史记录,跨回合记录并验证下注决策和结果。
  • 从已配置的外部来源获取并筛选与时间相关的预测,用于 Oas 下注决策。

错误修复:

  • 更新 FrogBoss 检测区域和 OCR 坐标,以适配更新后的周年庆下注资源。
  • 防止对过时或已更改的阵容下注;当下注页面或控件不可用时,将活动报告为卡住。

增强功能:

  • 更新 FrogBoss 图像资源,并添加对更新后下注主页的检测。
  • 让 Oas 策略共享现有的 Dashen 预测源列表。

测试:

  • 增加对 Oas 持久化、可靠性更新、去重、回退行为、模糊预测和阵容匹配的测试覆盖。

杂项:

  • 更新忽略规则,以排除新生成的本地数据。
Original summary in English

Summary by Sourcery

Update FrogBoss betting support for the anniversary resources and introduce the persistent Oas prediction strategy.

New Features:

  • Add the Oas strategy, which combines curated predictions and crowd sentiment with persistent outcome-based reliability scoring.
  • Record and verify betting decisions and results across rounds using lineup fingerprints and JSONL history.
  • Fetch and filter time-relevant predictions from configured external sources for Oas betting decisions.

Bug Fixes:

  • Update FrogBoss detection regions and OCR coordinates for the refreshed anniversary betting resources.
  • Prevent betting on stale or changed lineups and report the activity as stuck when the betting page or controls are unavailable.

Enhancements:

  • Refresh FrogBoss image assets and add detection for the updated betting main page.
  • Share the existing Dashen prediction source list with the Oas strategy.

Tests:

  • Add coverage for Oas persistence, reliability updates, deduplication, fallback behavior, ambiguous predictions, and lineup matching.

Chores:

  • Update ignore rules for newly generated local data.

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

嘿——我发现了 3 个问题

供 AI 代理使用的提示
请处理本次代码审查中的评论:

## 单独评论

### 评论 1
<location path="tasks/FrogBoss/frog_oas.py" line_range="135-171" />
<code_context>
+        for uid in DASHEN_UIDS:
</code_context>
<issue_to_address>
**issue (performance):** `fetch_predictions` 在下注前会为 26 个 UID 中的每一个执行两次同步 HTTP 请求,但没有总体截止时间或并发机制;在最坏情况下,单个请求的超时会使下注流程阻塞数分钟,导致阵容发生变化或下注结束,而 `do_bet` 还没来得及点击。

**触发条件:** 下注倒计时期间,预测服务响应缓慢或部分不可用时。

**建议修复:** 设置有上限的总体截止时间和/或使用并发请求,并使用截止时间前已收集到的预测结果继续执行,而不是等待所有 UID 完成。
</issue_to_address>

### 评论 2
<location path="tasks/FrogBoss/frog_oas.py" line_range="77-84" />
<code_context>
+        # Unverified newcomers start neutral; verified sources use raw win rate.
++        return correct / total if total else 0.5
+
+    def settle(self, signature, winner):
+        if winner not in ('LEFT', 'RIGHT'):
+            return None
+        # Include already settled records when checking ambiguity: never transfer
+        # an old result to a newer decision with an identical lineup.
+        matches = [e for e in self.events if e.get('kind') == 'decision'
+                   and same_lineup(e['signature'], signature)]
+        if len(matches) != 1:
+            self.append('unverified_result', signature=signature, winner=winner,
+                        reason='missing_or_ambiguous_decision')
</code_context>
<issue_to_address>
**issue (bug_risk):** `settle` 会在整个历史记录中搜索阵容匹配的决策,并要求匹配结果恰好只有一个;当同一阵容指纹被用于两场比赛时,后续结果会被记录为 `unverified_result`,且两个决策都不会获得结果,因此对于重复阵容,来源可靠性将无法继续学习。

**触发条件:** 历史中的两场比赛存在符合 20 位 `same_lineup` 阈值的阵容时。

**建议修复:** 持久化并传递与当前下注关联的具体决策 ID 或槽位,然后直接结算该决策,而不是仅根据阵容指纹解析。
</issue_to_address>

### 评论 3
<location path="tasks/FrogBoss/script_task.py" line_range="197-198" />
<code_context>
             logger.info('Right win')
         else:
-            result = True
+            result = None
         return result

     def get_bilibili(self) -> RuleImage:
</code_context>
<issue_to_address>
**issue (bug_risk):** `detect` 被标注为返回 `bool`,其文档字符串也描述了布尔结果,但新的兜底逻辑在无法同时看到结果指示器时返回 `None`;依赖文档所述布尔契约的调用方或重写实现会收到第三种值。

**触发条件:** 既未检测到完整的左方获胜图片对,也未检测到完整的右方获胜图片对时。

**建议修复:** 将类型标注和文档字符串改为 `Optional[bool]`,并说明结果未确定的情况;或者保留布尔契约,并单独处理无法确定的检测结果。
</issue_to_address>

Sourcery 评估

需要人工审查。 有 3 个发现需要优先处理;当选择新的 Oas 策略时,外部获取的预测结果和持久化的历史记录会决定自动下注的方向。过期或错误的数据源、阵容匹配结果或评分决策可能导致下注错误的一方,并永久损失已下注的游戏货币;回滚代码也无法挽回这些损失。

阻塞性发现:tasks/FrogBoss/frog_oas.py:171、tasks/FrogBoss/frog_oas.py:84、tasks/FrogBoss/script_task.py:198


Sourcery 对开源项目免费——如果您喜欢我们的评审,请考虑分享给他人 ✨
Original comment in English

Hey - I've found 3 issues

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

## Individual Comments

### Comment 1
<location path="tasks/FrogBoss/frog_oas.py" line_range="135-171" />
<code_context>
+        for uid in DASHEN_UIDS:
</code_context>
<issue_to_address>
**issue (performance):** `fetch_predictions` performs two synchronous HTTP requests for every one of the 26 UIDs before placing the bet, with no overall deadline or concurrency; in the worst case the per-request timeouts block the betting flow for several minutes, so the lineup changes or betting closes before `do_bet` can click.

**Triggers:** When the prediction service is slow or partially unavailable during the betting countdown.

**Suggested fix:** Use a bounded overall deadline and/or concurrent requests, and proceed with the predictions collected before the deadline instead of waiting for every UID.
</issue_to_address>

### Comment 2
<location path="tasks/FrogBoss/frog_oas.py" line_range="77-84" />
<code_context>
+        # Unverified newcomers start neutral; verified sources use raw win rate.
+        return correct / total if total else 0.5
+
+    def settle(self, signature, winner):
+        if winner not in ('LEFT', 'RIGHT'):
+            return None
+        # Include already settled records when checking ambiguity: never transfer
+        # an old result to a newer decision with an identical lineup.
+        matches = [e for e in self.events if e.get('kind') == 'decision'
+                   and same_lineup(e['signature'], signature)]
+        if len(matches) != 1:
+            self.append('unverified_result', signature=signature, winner=winner,
+                        reason='missing_or_ambiguous_decision')
</code_context>
<issue_to_address>
**issue (bug_risk):** `settle` searches the entire history for decisions with a matching lineup and requires exactly one match; when the same lineup fingerprint is used in two competitions, the later result is recorded as `unverified_result` and neither decision receives an outcome, so source reliability stops learning for repeated lineups.

**Triggers:** When two competitions in the history have lineups within the 20-bit `same_lineup` threshold.

**Suggested fix:** Persist and carry the specific decision ID or slot associated with the active bet, then settle that decision directly rather than resolving it only from the lineup fingerprint.
</issue_to_address>

### Comment 3
<location path="tasks/FrogBoss/script_task.py" line_range="197-198" />
<code_context>
             logger.info('Right win')
         else:
-            result = True
+            result = None
         return result

     def get_bilibili(self) -> RuleImage:
</code_context>
<issue_to_address>
**issue (bug_risk):** `detect` is annotated as returning `bool` and its docstring describes a boolean result, but the new fallback returns `None` when the result indicators are not both visible; callers or overrides relying on the documented boolean contract receive a third value.

**Triggers:** When neither complete left-win nor complete right-win image pair is detected.

**Suggested fix:** Change the annotation and docstring to `Optional[bool]` and document the unresolved-result case, or preserve the boolean contract and handle unresolved detection separately.
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 3 findings to address first, and when the new Oas strategy is selected, externally fetched predictions and persisted history determine which side is automatically wagered on. A stale or incorrect feed, lineup match, or scoring decision can place bets on the wrong side and permanently lose the wagered in-game currency; reverting the code would not recover those losses.

Blocking findings: tasks/FrogBoss/frog_oas.py:171, tasks/FrogBoss/frog_oas.py:84, tasks/FrogBoss/script_task.py:198


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

Comment on lines +135 to +171
for uid in DASHEN_UIDS:
feed_id = None
try:
response = session.get('https://inf.ds.163.com/v1/web/feed/basic/getSomeOneFeeds',
params={'feedTypes': '1,2,3,4,6,7,10,11', 'someOneUid': uid}, timeout=(3, 5))
response.raise_for_status()
feeds = response.json().get('result', {}).get('feeds', [])
if not feeds:
history.append('fetch', uid=uid, accepted=False, reason='no_feed')
continue
feed_id = feeds[0]['id']
response = session.get('https://inf.ds.163.com/v1/web/feed/basic/facade',
params={'feedId': feed_id}, timeout=(3, 5))
response.raise_for_status()
feed = response.json()['result']['feed']
content = feed['content']
if isinstance(content, str):
content = json.loads(content)
body = content['body']['text']
raw_time = feed.get('createTime')
published = None
try:
published = datetime.fromtimestamp(float(raw_time) / 1000)
except (TypeError, ValueError, OverflowError, OSError):
pass
side = parse_side(body)
fresh = published is not None and published.date() == now.date() and published.hour // 2 == now.hour // 2 and published <= now
accepted = fresh and side is not None and (uid, feed_id) not in used
history.append('fetch', uid=uid, feed_id=feed_id, create_time=raw_time,
body=body, side=side, accepted=accepted,
reason='accepted' if accepted else 'stale_unknown_ambiguous_or_duplicate')
if accepted:
predictions.append(dict(uid=uid, side=side, feed_id=feed_id))
except (requests.RequestException, ValueError, KeyError, IndexError, TypeError) as exc:
history.append('fetch', uid=uid, feed_id=feed_id, accepted=False,
reason='request_or_parse_error', error=str(exc))
return predictions

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (performance): fetch_predictions 在下注前会为 26 个 UID 中的每一个执行两次同步 HTTP 请求,但没有总体截止时间或并发机制;在最坏情况下,单个请求的超时会使下注流程阻塞数分钟,导致阵容发生变化或下注结束,而 do_bet 还没来得及点击。

触发条件: 下注倒计时期间,预测服务响应缓慢或部分不可用时。

建议修复: 设置有上限的总体截止时间和/或使用并发请求,并使用截止时间前已收集到的预测结果继续执行,而不是等待所有 UID 完成。

Original comment in English

issue (performance): fetch_predictions performs two synchronous HTTP requests for every one of the 26 UIDs before placing the bet, with no overall deadline or concurrency; in the worst case the per-request timeouts block the betting flow for several minutes, so the lineup changes or betting closes before do_bet can click.

Triggers: When the prediction service is slow or partially unavailable during the betting countdown.

Suggested fix: Use a bounded overall deadline and/or concurrent requests, and proceed with the predictions collected before the deadline instead of waiting for every UID.

Comment on lines +77 to +84
def settle(self, signature, winner):
if winner not in ('LEFT', 'RIGHT'):
return None
# Include already settled records when checking ambiguity: never transfer
# an old result to a newer decision with an identical lineup.
matches = [e for e in self.events if e.get('kind') == 'decision'
and same_lineup(e['signature'], signature)]
if len(matches) != 1:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): settle 会在整个历史记录中搜索阵容匹配的决策,并要求匹配结果恰好只有一个;当同一阵容指纹被用于两场比赛时,后续结果会被记录为 unverified_result,且两个决策都不会获得结果,因此对于重复阵容,来源可靠性将无法继续学习。

触发条件: 历史中的两场比赛存在符合 20 位 same_lineup 阈值的阵容时。

建议修复: 持久化并传递与当前下注关联的具体决策 ID 或槽位,然后直接结算该决策,而不是仅根据阵容指纹解析。

Original comment in English

issue (bug_risk): settle searches the entire history for decisions with a matching lineup and requires exactly one match; when the same lineup fingerprint is used in two competitions, the later result is recorded as unverified_result and neither decision receives an outcome, so source reliability stops learning for repeated lineups.

Triggers: When two competitions in the history have lineups within the 20-bit same_lineup threshold.

Suggested fix: Persist and carry the specific decision ID or slot associated with the active bet, then settle that decision directly rather than resolving it only from the lineup fingerprint.

Comment on lines +197 to 198
result = None
return result

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): detect 被标注为返回 bool,其文档字符串也描述了布尔结果,但新的兜底逻辑在无法同时看到结果指示器时返回 None;依赖文档所述布尔契约的调用方或重写实现会收到第三种值。

触发条件: 既未检测到完整的左方获胜图片对,也未检测到完整的右方获胜图片对时。

建议修复: 将类型标注和文档字符串改为 Optional[bool],并说明结果未确定的情况;或者保留布尔契约,并单独处理无法确定的检测结果。

Original comment in English

issue (bug_risk): detect is annotated as returning bool and its docstring describes a boolean result, but the new fallback returns None when the result indicators are not both visible; callers or overrides relying on the documented boolean contract receive a third value.

Triggers: When neither complete left-win nor complete right-win image pair is detected.

Suggested fix: Change the annotation and docstring to Optional[bool] and document the unresolved-result case, or preserve the boolean contract and handle unresolved detection separately.

@github-actions

Copy link
Copy Markdown
Contributor

Change Summary

  • 更新 FrogBoss 周年庆页面的模板、ROI 和 OCR 坐标,并新增竞猜主页检测。
  • 新增 frog_oas 策略:抓取 Dashen 预测,结合群体票数进行下注,并将决策/结果写入按实例划分的 JSONL 历史。
  • 下注前增加阵容一致性和控件可用性检查;结果识别不确定时不更新 Oas 可靠性。

Reconstructed Intent

点击此处展开
  • 这次改动最可能是为了适配周年庆 UI,同时让 Oas 在外部预测和群体情绪之间做可追溯、可持久化的下注决策。
  • 通过重新截图、页面检测和阵容指纹校验,意图是避免在页面切换或阵容过期后误下注。

Observed Constraints

点击此处展开
  • 新 ROI、OCR 坐标和 I_FROG_CHECK 必须同时匹配周年庆分辨率/页面;入口检测失败会在进入活动后抛出 GameStuckError。
  • Oas 依赖外部接口在下注倒计时内返回,并依赖阵容指纹能稳定区分比赛;当前请求按 26 个 UID 串行执行,每个 UID最多两次请求、单请求超时为 3+5 秒。
  • 结果结算通过历史中所有相似指纹查找唯一 decision,而不是持有当前下注对应的 decision ID;相似或重复阵容会进入 unverified_result。

Intent Alignment

  • 结论:只部分覆盖推断 intent。
  • 页面资源更新、Oas 持久化和下注前二次校验与目标一致;但“可在比赛窗口内可靠完成下注”和“跨回合验证并学习结果”仍依赖未充分约束的时序与关联逻辑。
  • 另外,enter_frog_boss 和新主页检测是所有策略共用的入口,因此这不仅是 Oas 的行为变化;新资源识别不兼容时,原有策略也会被一起阻塞。

Release Risk

  • 风险等级:高
  • fetch_predictions 的串行网络调用没有总截止时间,最坏情况下可能在下注期间阻塞数分钟;即使随后检查阵容,结果也可能只是卡住而不是完成本轮下注。
  • settle 以全历史的模糊指纹匹配决策,重复/近似阵容会停止可靠性学习;若指纹在结果页发生变化,也会持续产生未验证结果。
  • 大量模板/坐标和入口链路同时变化,若周年庆页面、分辨率或资源元数据有偏差,会影响全部 FrogBoss 模式,而不只是新增 Oas。

Validation Gaps

点击此处展开
  • 已看到 Oas 纯逻辑单元测试,但未看到真实周年庆截图上的入口、下注、确认、结算和下一场循环验证。
  • 未看到慢接口、部分接口失败、倒计时耗尽、网络返回重复 feed,以及比赛在抓取期间切换时的端到端验证。
  • 未看到重复/近似阵容跨多场比赛的结算测试;建议让下注流程保存并传递 decision ID,直接结算当前 decision。
  • detect 现在返回 None,但签名仍为 -> bool 且文档只描述布尔值;应明确 Optional 契约或改用独立的未确定状态。

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 #1848 · codex · gpt56 · 12.2 AIC · ⌖ 2.68 AIC · ⊞ 12.1K · ◷

@github-actions

Copy link
Copy Markdown
Contributor

Findings

  • C2 [风险]
    位置:tasks/FrogBoss/frog_oas.py:fetch_predictions
    原因:26 个 UID 顺序执行最多 52 次同步请求,只有单请求超时,没有下注流程的总截止时间,可能等待数分钟后错过下注窗口。
    修改:增加整体 deadline 或并发上限,到时使用已收集结果并明确处理未完成来源。

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 #1848 · codex · gpt56 · 14.2 AIC · ⌖ 2.55 AIC · ⊞ 12.2K · ◷

@runhey
runhey merged commit d1c1b85 into runhey:dev Sep 30, 2026
11 checks passed
ohspecial added a commit to ohspecial/OnmyojiAutoScript that referenced this pull request Sep 30, 2026
迁移 runhey/OnmyojiAutoScript PR runhey#1848 的提交 86b2a7e。
This was referenced Oct 1, 2026
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