Skip to content

Add PileIdentityLedger and Refactor Room Pile Operations - #69

Merged
llsccm merged 19 commits into
devfrom
codex/tracker-pile-identity-phase2
Aug 2, 2026
Merged

Add PileIdentityLedger and Refactor Room Pile Operations#69
llsccm merged 19 commits into
devfrom
codex/tracker-pile-identity-phase2

Conversation

@llsccm

@llsccm llsccm commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • 新功能

    • 提升牌堆身份追踪准确性,支持洗牌、弃牌回收、匿名牌及延迟揭示等场景。
    • 新增“观虚”交换流程追踪,支持牌堆顶与目标手牌的准确交换和位置恢复。
    • 支持顶部、底部、随机及指定位置的牌堆插入与移动。
  • 问题修复

    • 手气卡返还牌堆时正确识别为随机位置,避免误判为牌顶。
    • 改善公共区域牌卡解析,减少暗牌身份覆盖和错误物化。

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • ✅ Review completed - (🔄 Check again to review again)

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c3720749-3c92-4e80-8190-f45162e6163d

📥 Commits

Reviewing files that changed from the base of the PR and between 81a1f1c and caa5d64.

📒 Files selected for processing (2)
  • tests/contracts/pile-identity/pileGenerationPool.test.ts
  • tests/contracts/pile-identity/pileGenerationPoolModel.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/contracts/pile-identity/pileGenerationPoolModel.ts
  • tests/contracts/pile-identity/pileGenerationPool.test.ts

📝 Walkthrough

Walkthrough

本次变更引入 PileIdentityLedger,重构牌堆身份、洗牌、匿名物化和移动同步流程。新增观虚 987/988 交换处理、协议位置解析、纯模型契约测试及相关验证文档。

Changes

牌堆身份账本与 Room 集成

Layer / File(s) Summary
账本契约与核心状态
src/tracker/PileIdentityLedger.ts
新增身份账本、cohort、洗牌过渡、快照、一致性检查和事务回滚。
Room 集成与洗牌物化
src/tracker/Room.ts, src/tracker/CardCounter.ts
Room 同步账本状态,限制匿名槽物化目标,区分初始洗牌与真实代际关闭,并维护 suspended 展示实体。

移动、位置与观虚流程

Layer / File(s) Summary
移动解析与公共位置
src/tracker/roomMovement/*, src/tracker/candidate/cardPositions.ts, src/tracker/Zone.ts
移动解析新增公共候选上下文,并按协议范围消费匿名槽。公共区支持顶部、底部、随机和数值插槽。
运行时账本同步与观虚事件
src/tracker/runtime/trackerController.ts, src/tracker/runtime/moveEventHandlers.ts, src/tracker/skill/GuanXu.ts
运行时生成账本移动事件,并为 987/988 注册独立交换流程。
位置协议与手气卡流程
src/handler/PubGsCMoveCard.js, src/handler/specialZones.js, docs/protocols/*
手气卡回堆归一化为随机位置。协议文档记录位置插槽和观虚交换语义。

测试与验证

Layer / File(s) Summary
纯模型与账本测试
tests/contracts/pile-identity/*, tests/tracker/pileIdentityLedger.test.ts
新增世代、批次、基线和真实牌序 oracle 模型,覆盖身份守恒、cohort 投影、降级和跨洗牌流程。
身份与移动回归验证
tests/tracker/*
更新匿名槽、suspended 身份、公共端点、CardCounter、遍历基线和观虚交换测试。
测试范围与开发文档
package.json, tsconfig.tracker.json, AGENTS.md, CLAUDE.md, CONTRIBUTING.md, docs/agents/*, .prettierignore
将牌堆身份契约纳入 tracker 测试范围,并更新编辑规范、验证命令和协议说明。

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Protocol
  participant TrackerController
  participant Room
  participant PileIdentityLedger
  participant GuanXu
  Protocol->>TrackerController: 提交移动事件
  TrackerController->>Room: 执行物理移动
  TrackerController->>PileIdentityLedger: 应用身份移动或揭示
  TrackerController->>GuanXu: 分派 987/988 交换事件
  GuanXu-->>TrackerController: 返回交换后的移动事件
  PileIdentityLedger-->>Room: 提交快照或回滚状态
Loading

Possibly related PRs

  • llsccm/tracker#66:涉及相同的身份账本、suspended 身份、匿名化和增量索引路径。
  • llsccm/tracker#44:涉及相同的匿名牌堆和物化流程。
  • llsccm/tracker#38:涉及相同的观虚 987/988、牌堆顶展示和位置同步流程。
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.07% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title Check ✅ Passed Title check skipped as CodeRabbit has written the PR title.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/tracker-pile-identity-phase2

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot changed the title @pr Add PileIdentityLedger and Refactor Room Pile Operations Aug 1, 2026

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

Actionable comments posted: 4

🧹 Nitpick comments (5)
tests/tracker/helpers/pileGenerationPoolModel.ts (2)

936-946: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

可选:提取重复的「弹出牌顶槽并分类」循环。

drawUnknowndrawAcrossShufflegainUnknownFromPileTopRange 三处使用完全相同的循环体:弹出 pileSlots 末尾,null 计入 playerAnonSlotCount,正 ID 加入 playerHiddenPositiveIDs。提取一个局部 helper 可减少三处重复,并保证后续修改同步。

♻️ 建议改动
+function popBaselineTopSlots(state: BaselineModelState, count: number): void {
+  for (let index = 0; index < count; index += 1) {
+    const slot = state.pileSlots.pop() ?? null
+    if (slot === null) state.playerAnonSlotCount += 1
+    else state.playerHiddenPositiveIDs.add(slot)
+  }
+}

Also applies to: 971-975, 1018-1029

🤖 Prompt for 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.

In `@tests/tracker/helpers/pileGenerationPoolModel.ts` around lines 936 - 946,
提取一个局部 helper,统一执行从 state.pileSlots 末尾弹出槽位并分类的逻辑:弹出 null 时递增
state.playerAnonSlotCount,否则将槽位加入 state.playerHiddenPositiveIDs。更新
drawUnknown、drawAcrossShuffle 和 gainUnknownFromPileTopRange 使用该
helper,保持现有数量校验与循环次数不变。

281-291: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

建议统一 insertExternalAtRandom 的身份归一化。

applyCohortEvent 在 599 行对 insertExternalAtRandom 调用 normalizeIdentityIDs,但世代模型(281-291 行)和基线模型(947-955 行)直接使用 event.cardIDs。如果夹具传入重复 ID 或非正 ID,pileSlotCount 的增量会大于实际加入的身份数,countGenerationSlots(state) === identityUniverse.size 这条守恒断言会失败,而失败原因难以定位。三个模型使用同一套事件序列,归一化行为应保持一致。

♻️ 建议改动
     case 'insertExternalAtRandom': {
       // 外部牌暗置进入牌堆:身份未揭示,属于当前世代候选(§5.8 规则 4)。
-      event.cardIDs.forEach((cardID) => {
+      const cardIDs = normalizeIdentityIDs(event.cardIDs)
+      cardIDs.forEach((cardID) => {
         state.identityUniverse.add(cardID)
         state.locatedIdentityIDs.delete(cardID)
         state.activeIdentityIDs.add(cardID)
         state.suspendedIdentityIDs.delete(cardID)
       })
-      state.pileSlotCount += event.cardIDs.length
+      state.pileSlotCount += cardIDs.length
       return
     }
🤖 Prompt for 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.

In `@tests/tracker/helpers/pileGenerationPoolModel.ts` around lines 281 - 291, 统一
insertExternalAtRandom 的身份归一化逻辑:在世代模型和基线模型中复用 applyCohortEvent 使用的
normalizeIdentityIDs 处理 event.cardIDs,仅将去重且有效的 ID加入 identityUniverse 并更新相关集合,同时让
pileSlotCount 按归一化后的实际 ID 数量递增,确保三个模型行为一致。
tests/tracker/pileGenerationPool.test.ts (2)

1086-1092: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

可选:按需构造 context 字符串。

describeSequence() 在每一步迭代中无条件执行 JSON.stringify(events, null, 2),即使断言通过也会构造完整字符串。该模式出现在 4 个测试中,每个测试遍历 8 个 seed × 40 步。改为把消息传给 Vitest 的惰性形式,或只在断言失败时构造,可以降低测试运行时间。

🤖 Prompt for 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.

In `@tests/tracker/pileGenerationPool.test.ts` around lines 1086 - 1092, 更新这 4
个测试中的断言上下文构造逻辑,避免在每次迭代中无条件调用 describeSequence() 生成 JSON 字符串;改用 Vitest
的惰性消息形式,或仅在断言失败路径构造上下文,同时保持断言内容和失败时的诊断信息不变。

1190-1207: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

属性测试未覆盖 gainFromPilegainUnknownFromPileTopRange

generateSequence 不产生这两类事件,因此该断言的期望列表也不含它们。结果是「从牌堆任意位置取牌」和「牌顶范围取牌」两条路径只由手工用例覆盖,不参与逐步守恒与批次基数检查。这两条路径恰好是批次降级逻辑最容易出错的地方(gainUnknownFromPileTopRange 会触发 mergeAllCohorts)。

建议在生成器中加入这两类事件:gainFromPiletopCohortCandidates() 之外的任意 cohort 取候选,gainUnknownFromPileTopRange 随机选取 rangeSize >= count。需要我提交实现或创建跟踪 issue 吗?

🤖 Prompt for 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.

In `@tests/tracker/pileGenerationPool.test.ts` around lines 1190 - 1207, Update
generateSequence to produce both gainFromPile and gainUnknownFromPileTopRange
events, selecting gainFromPile candidates from cohorts outside
topCohortCandidates() and ensuring gainUnknownFromPileTopRange uses a randomly
selected rangeSize greater than or equal to count. Extend the covered-event
expectation in the “生成器确实覆盖了全部事件类型” test to include both event types so these
paths participate in invariant and batch-size checks.
tests/tracker/anonymousPileSpike.test.ts (1)

9-12: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

getSuspendedIdentityIDs 在两个测试文件中重复定义。 同一个辅助函数被复制成两份实现完全相同的本地函数。后续 suspended 语义变化时,两处会不同步。建议抽到 tests/tracker/helpers/room.ts 中共享导出。

  • tests/tracker/anonymousPileSpike.test.ts#L9-L12:删除本地定义,改为从 ./helpers/room 导入 getSuspendedIdentityIDs
  • tests/tracker/pileDisplayOrder.test.ts#L19-L21:删除本地定义,改为从 ./helpers/room 导入同一个 getSuspendedIdentityIDs
♻️ 建议新增的共享辅助

tests/tracker/helpers/room.ts 中新增:

export function getSuspendedIdentityIDs(room: Room): number[] {
  return Array.from(room.suspendedKnownCards, (card) => card.id).sort((left, right) => left - right)
}
🤖 Prompt for 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.

In `@tests/tracker/anonymousPileSpike.test.ts` around lines 9 - 12, Move the
duplicated getSuspendedIdentityIDs helper into tests/tracker/helpers/room.ts as
a shared export accepting Room; in tests/tracker/anonymousPileSpike.test.ts
lines 9-12 and tests/tracker/pileDisplayOrder.test.ts lines 19-21, remove each
local definition and import the shared helper from ./helpers/room.
🤖 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 `@src/tracker/PileIdentityLedger.ts`:
- Line 195: Update the consistency check in initialize to pass identities.length
to collectConsistencyIssues instead of the raw cardIDs.length, ensuring expected
pile counts use the normalized, deduplicated valid IDs.

In `@src/tracker/roomMovement/sources.ts`:
- Around line 751-758: 更新 isRegularPileDraw 与 takeUnknownCardsFromPublicZone
的分流逻辑:仅在 fromZone 为牌堆且 moveType 为 DRAW 时使用按端点顺序消费明牌的
takeCardsFromPublicZone;非牌堆来源只有在已覆盖暗牌移动路径时才调用
takeUnknownCardsFromPublicZone,否则改用能移除实际明牌实体的路径,避免 moveUnknownCardsForContext
创建匿名占位而保留原区明牌。

In `@tests/tracker/helpers/pileGenerationPoolModel.ts`:
- Around line 1161-1175: Update recycleTrueDiscard to return whether a discard
pile was actually recycled, returning false on an empty trueDiscard and true
after a successful recycle. In the shuffle branch around the shuffleIndex
update, increment shuffleIndex only when recycleTrueDiscard reports true,
keeping empty-discard shuffles from consuming recycledOrders entries.

In `@tests/tracker/traversalBaseline.test.ts`:
- Around line 154-162: 在测试中 materializeDeckIdentities: false 的洗牌场景附近加入中文注释,说明 40
张牌保持匿名槽会导致洗牌遍历全部实体,从而解释 inline snapshot 中
total、cardCounter:update、ambiguousKnownIndex:applyDirty、locationIndex:applyDirty
和 resolveConstraints:playerSnapshotIncremental 的增长;同时补充或运行
materializeDeckIdentities: true 的同一场景遍历快照,确认生产洗牌路径的遍历量未退化。

---

Nitpick comments:
In `@tests/tracker/anonymousPileSpike.test.ts`:
- Around line 9-12: Move the duplicated getSuspendedIdentityIDs helper into
tests/tracker/helpers/room.ts as a shared export accepting Room; in
tests/tracker/anonymousPileSpike.test.ts lines 9-12 and
tests/tracker/pileDisplayOrder.test.ts lines 19-21, remove each local definition
and import the shared helper from ./helpers/room.

In `@tests/tracker/helpers/pileGenerationPoolModel.ts`:
- Around line 936-946: 提取一个局部 helper,统一执行从 state.pileSlots 末尾弹出槽位并分类的逻辑:弹出 null
时递增 state.playerAnonSlotCount,否则将槽位加入 state.playerHiddenPositiveIDs。更新
drawUnknown、drawAcrossShuffle 和 gainUnknownFromPileTopRange 使用该
helper,保持现有数量校验与循环次数不变。
- Around line 281-291: 统一 insertExternalAtRandom 的身份归一化逻辑:在世代模型和基线模型中复用
applyCohortEvent 使用的 normalizeIdentityIDs 处理 event.cardIDs,仅将去重且有效的 ID加入
identityUniverse 并更新相关集合,同时让 pileSlotCount 按归一化后的实际 ID 数量递增,确保三个模型行为一致。

In `@tests/tracker/pileGenerationPool.test.ts`:
- Around line 1086-1092: 更新这 4 个测试中的断言上下文构造逻辑,避免在每次迭代中无条件调用 describeSequence()
生成 JSON 字符串;改用 Vitest 的惰性消息形式,或仅在断言失败路径构造上下文,同时保持断言内容和失败时的诊断信息不变。
- Around line 1190-1207: Update generateSequence to produce both gainFromPile
and gainUnknownFromPileTopRange events, selecting gainFromPile candidates from
cohorts outside topCohortCandidates() and ensuring gainUnknownFromPileTopRange
uses a randomly selected rangeSize greater than or equal to count. Extend the
covered-event expectation in the “生成器确实覆盖了全部事件类型” test to include both event
types so these paths participate in invariant and batch-size checks.
🪄 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 Plus

Run ID: 8bc6635c-ccab-4d01-9689-ca9f9fafba27

📥 Commits

Reviewing files that changed from the base of the PR and between 7f29d6d and 98c26e8.

📒 Files selected for processing (27)
  • .prettierignore
  • CLAUDE.md
  • docs/agents/card_tracker.md
  • docs/agents/testing.md
  • src/handler/PubGsCMoveCard.js
  • src/handler/specialZones.js
  • src/tracker/PileIdentityLedger.ts
  • src/tracker/Room.ts
  • src/tracker/roomMovement.ts
  • src/tracker/roomMovement/sources.ts
  • src/tracker/runtime/moveEventHandlers.ts
  • src/tracker/runtime/trackerController.ts
  • src/tracker/view/publicFieldCandidates.ts
  • tests/tracker/anonymousPileSpike.test.ts
  • tests/tracker/helpers/pileGenerationPoolModel.ts
  • tests/tracker/helpers/trackerController.ts
  • tests/tracker/identityConservation.test.ts
  • tests/tracker/pileDisplayOrder.test.ts
  • tests/tracker/pileGenerationPool.test.ts
  • tests/tracker/pileIdentityLedger.test.ts
  • tests/tracker/pileIdentityLedgerIntegration.test.ts
  • tests/tracker/pubGsCMoveCard.test.ts
  • tests/tracker/publicEndpointCards.test.ts
  • tests/tracker/resolveConstraintsIncrementalIndex.test.ts
  • tests/tracker/specialZones.test.ts
  • tests/tracker/trackerController.test.ts
  • tests/tracker/traversalBaseline.test.ts
💤 Files with no reviewable changes (1)
  • src/handler/specialZones.js

Comment thread src/tracker/PileIdentityLedger.ts Outdated
Comment thread src/tracker/roomMovement/sources.ts
Comment thread tests/tracker/helpers/pileGenerationPoolModel.ts Outdated
Comment thread tests/tracker/traversalBaseline.test.ts Outdated
llsccm added 2 commits August 2, 2026 02:36
按 FromID/ToID 保留牌堆侧与手牌侧交换桶,避免已知身份误走 known-fallback。

换出手牌回堆后仅记录牌顶前 N 张范围候选,并补充目标视角完整协议回归与文档。

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
tests/tracker/pileGenerationPool.test.ts (2)

1034-1050: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

建议复用一次 cohort 状态,减少模型重放。

nonTopCohortCandidates() 先调用 topCohortCandidates(),后者内部又执行一次 runCohortPoolModel(events),因此单次调用会全量重放事件序列两次。生成器在每一步都调用该函数,重放成本随步数呈平方增长。把 cohort 状态计算一次并复用,可保持语义不变。

♻️ 建议的重构
+    /** 取当前牌顶批次里仍可揭示的身份;复用已计算的 cohort 状态。 */
+    const topCandidatesOf = (cohortState: ReturnType<typeof runCohortPoolModel>): CardID[] => {
+      for (let index = cohortState.cohorts.length - 1; index >= 0; index -= 1) {
+        const cohort = cohortState.cohorts[index]
+        if (cohort.remainingPileCount <= 0) continue
+        return sortIDs(cohort.candidateIdentityIDs).filter((cardID) =>
+          availablePileIdentities.has(cardID)
+        )
+      }
+      return []
+    }
+
     /** 搜牌事件故意选择仍有牌在堆、但不属于当前牌顶批次的候选身份。 */
     const nonTopCohortCandidates = (): CardID[] => {
-      const topCandidates = new Set(topCohortCandidates())
       const cohortState = runCohortPoolModel(events)
+      const topCandidates = new Set(topCandidatesOf(cohortState))
       const candidates = new Set<CardID>()
🤖 Prompt for 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.

In `@tests/tracker/pileGenerationPool.test.ts` around lines 1034 - 1050, Update
nonTopCohortCandidates to call runCohortPoolModel(events) only once and derive
both the top-cohort candidates and non-top candidates from that shared
cohortState. Preserve the existing filtering and sorted CardID results while
eliminating the nested topCohortCandidates model replay.

1140-1148: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

删除恒真条件,避免误导读者。

state.discardKnownIDs.length > 0 已经成立时,state.pileSlotCount + state.discardKnownIDs.length >= 1 恒真,minDraw > postShuffleCount 也恒不成立。这两处判断永不生效,会让读者误以为存在需要跳过的场景。

♻️ 建议的重构
-      if (
-        roll < 93 &&
-        state.discardKnownIDs.length > 0 &&
-        state.pileSlotCount + state.discardKnownIDs.length >= 1
-      ) {
+      if (roll < 93 && state.discardKnownIDs.length > 0) {
         // 自动补牌:必须超过洗牌前牌堆量,且不超过洗牌后总量。
         const postShuffleCount = state.pileSlotCount + state.discardKnownIDs.length
         const minDraw = state.pileSlotCount + 1
-        if (minDraw > postShuffleCount) continue
-
         const count = minDraw + pick(postShuffleCount - minDraw + 1)
🤖 Prompt for 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.

In `@tests/tracker/pileGenerationPool.test.ts` around lines 1140 - 1148, Remove
the redundant state.pileSlotCount + state.discardKnownIDs.length >= 1 condition
and the unreachable minDraw > postShuffleCount check from the automatic draw
branch. Keep the existing roll and discardKnownIDs.length guards and the
postShuffleCount/minDraw calculations only if they remain necessary for
meaningful behavior.
🤖 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 `@src/tracker/skill/GuanXu.ts`:
- Around line 87-171: Make resolveProtocolKnownCards and its validation callers
stagePileToExchange, stageHandToExchange, and transferExchangeBucket side-effect
free: add a read-only probe or transactional rollback around Room.materialize
and confirmKnown so failed validation cannot persist CardID identity changes or
mutate card entities. Preserve the existing card selection results for valid
moves, and ensure endpoint materialization cannot consume later anonymous slots
during validation.

---

Nitpick comments:
In `@tests/tracker/pileGenerationPool.test.ts`:
- Around line 1034-1050: Update nonTopCohortCandidates to call
runCohortPoolModel(events) only once and derive both the top-cohort candidates
and non-top candidates from that shared cohortState. Preserve the existing
filtering and sorted CardID results while eliminating the nested
topCohortCandidates model replay.
- Around line 1140-1148: Remove the redundant state.pileSlotCount +
state.discardKnownIDs.length >= 1 condition and the unreachable minDraw >
postShuffleCount check from the automatic draw branch. Keep the existing roll
and discardKnownIDs.length guards and the postShuffleCount/minDraw calculations
only if they remain necessary for meaningful behavior.
🪄 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 Plus

Run ID: a5c8d5f9-3600-48bf-8d3f-73564e3c4e8b

📥 Commits

Reviewing files that changed from the base of the PR and between 98c26e8 and 232b5cb.

📒 Files selected for processing (20)
  • docs/agents/card_tracker.md
  • docs/agents/testing.md
  • docs/protocols/GsCRoleOptTargetNtf-987.md
  • docs/protocols/README.md
  • src/tracker/PileIdentityLedger.ts
  • src/tracker/Room.ts
  • src/tracker/roomMovement.ts
  • src/tracker/roomMovement/sources.ts
  • src/tracker/roomMovement/types.ts
  • src/tracker/runtime/moveEventHandlers.ts
  • src/tracker/skill/GuanXu.ts
  • src/tracker/types.ts
  • tests/tracker/anonymousPileSpike.test.ts
  • tests/tracker/guanXuExchange.test.ts
  • tests/tracker/helpers/pileGenerationPoolModel.ts
  • tests/tracker/helpers/room.ts
  • tests/tracker/pileDisplayOrder.test.ts
  • tests/tracker/pileGenerationPool.test.ts
  • tests/tracker/pileIdentityLedger.test.ts
  • tests/tracker/traversalBaseline.test.ts
🚧 Files skipped from review as they are similar to previous changes (7)
  • src/tracker/roomMovement/sources.ts
  • tests/tracker/anonymousPileSpike.test.ts
  • src/tracker/roomMovement.ts
  • tests/tracker/pileIdentityLedger.test.ts
  • src/tracker/PileIdentityLedger.ts
  • tests/tracker/helpers/pileGenerationPoolModel.ts
  • src/tracker/Room.ts

Comment thread src/tracker/skill/GuanXu.ts Outdated

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/tracker/Room.ts (1)

1187-1219: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

洗牌旧世代关闭不应依赖后续账本调用。

shufflePile() 先取 pileIdentityLedger.getUnresolvedIdentityIDs() 作为 expiringIdentityIDs 快照,随后才将 pileIdentityMove 提交给 applyPileIdentityMove()createPileIdentityMove() 会在洗牌前收集 pileCountBefore,因此随后提交的账本移动事件仍是旧状态;账本洗牌事件不会先于 Room.shufflePile() 关闭旧世代。把 applyPileIdentityMove(...)/账本洗牌事件提前到 Room.shufflePile() 之前,或不在此函数中读取 pileIdentityLedger 作为闭世代依据。

🤖 Prompt for 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.

In `@src/tracker/Room.ts` around lines 1187 - 1219, 调整 shufflePile
的旧世代关闭流程:不要依赖其中读取 pileIdentityLedger.getUnresolvedIdentityIDs()
的快照作为闭世代依据,因为账本洗牌事件会在 Room.shufflePile() 之后才提交。将 applyPileIdentityMove(...)
及其账本事件提前到 shufflePile 执行前,或改用不依赖 pileIdentityLedger 的闭世代依据,同时保留过期身份与洗回身份的正确区分。
🤖 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 `@docs/protocols/GsCRoleOptTargetNtf-987.md`:
- Around line 110-111: 更新步骤 4/5 的回堆说明,明确步骤 5 的协议 CardIDs=[] 仍为空,已知身份 16 不写入线协议
CardIDs。按线协议与内部实体拆分:完整回堆时使用交换桶 sourceCards 按桶内 bottom-first 补充回堆序列;CardCount
表示线协议张数,sourceCards 表示内部实体来源。

In `@tests/tracker/guanXuExchange.test.ts`:
- Around line 11-21: 将观虚测试中的移动类型字面量 11 替换为 src/tracker/MoveEventNormalizer.ts 中的
MOVE_TYPE.EXCHANGE;更新 guanXuMove() 及测试内其他 MoveType 设置,并补充或复用该常量的导入,保持测试行为不变。

---

Outside diff comments:
In `@src/tracker/Room.ts`:
- Around line 1187-1219: 调整 shufflePile 的旧世代关闭流程:不要依赖其中读取
pileIdentityLedger.getUnresolvedIdentityIDs() 的快照作为闭世代依据,因为账本洗牌事件会在
Room.shufflePile() 之后才提交。将 applyPileIdentityMove(...) 及其账本事件提前到 shufflePile
执行前,或改用不依赖 pileIdentityLedger 的闭世代依据,同时保留过期身份与洗回身份的正确区分。
🪄 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 Plus

Run ID: adae2381-787a-4495-a655-dc0ee064d136

📥 Commits

Reviewing files that changed from the base of the PR and between 232b5cb and 74d6fe1.

📒 Files selected for processing (20)
  • docs/agents/card_tracker.md
  • docs/agents/testing.md
  • docs/protocols/GsCRoleOptTargetNtf-987.md
  • docs/protocols/README.md
  • docs/protocols/move-position.md
  • src/tracker/CardCounter.ts
  • src/tracker/Room.ts
  • src/tracker/Zone.ts
  • src/tracker/candidate/cardPositions.ts
  • src/tracker/runtime/trackerController.ts
  • src/tracker/skill/GuanXu.ts
  • tests/tracker/anonymousPileSpike.test.ts
  • tests/tracker/cardCounter.test.ts
  • tests/tracker/guanXuExchange.test.ts
  • tests/tracker/moveEventLogging.test.ts
  • tests/tracker/moveEventNormalizer.test.ts
  • tests/tracker/pileGenerationPool.test.ts
  • tests/tracker/publicEndpointCards.test.ts
  • tests/tracker/resolveConstraintsIncrementalIndex.test.ts
  • tests/tracker/traversalBaseline.test.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • tests/tracker/resolveConstraintsIncrementalIndex.test.ts
  • docs/agents/testing.md
  • tests/tracker/anonymousPileSpike.test.ts
  • tests/tracker/pileGenerationPool.test.ts
  • src/tracker/skill/GuanXu.ts
  • src/tracker/runtime/trackerController.ts

Comment thread docs/protocols/GsCRoleOptTargetNtf-987.md Outdated
Comment thread tests/tracker/guanXuExchange.test.ts
洗牌先提交身份账本过渡,再据此重建物理牌堆和 suspended 投影。

同时迁移牌堆纯模型到 tests/contracts,纳入 tracker 完整回归,并修正文档与观虚测试常量。

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

Actionable comments posted: 2

🤖 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 `@docs/agents/card_tracker.md`:
- Line 53: 将文档中的“协议张数”统一改为“协议牌数”(或“协议卡牌数量”),仅更新该术语表述并保持其余洗牌行为说明不变。

In `@tests/contracts/pile-identity/pileGenerationPoolModel.ts`:
- Around line 601-623: Update the insertExternalAtRandom branch to increment
cohortDegradationCount only when mergeAllCohorts actually merges multiple
cohorts, matching the conditional behavior in gainUnknownFromPileTopRange.
Preserve the existing count and cohort updates while ensuring zero- or
one-cohort cases do not increase the degradation metric.
🪄 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 Plus

Run ID: 205b7b40-61c8-4c73-9fff-3fab8435ea75

📥 Commits

Reviewing files that changed from the base of the PR and between 74d6fe1 and 81a1f1c.

📒 Files selected for processing (18)
  • AGENTS.md
  • CLAUDE.md
  • CONTRIBUTING.md
  • docs/agents/card_tracker.md
  • docs/agents/commands.md
  • docs/agents/conventions.md
  • docs/agents/overview.md
  • docs/agents/testing.md
  • docs/protocols/GsCRoleOptTargetNtf-987.md
  • package.json
  • src/tracker/PileIdentityLedger.ts
  • src/tracker/Room.ts
  • src/tracker/runtime/trackerController.ts
  • tests/contracts/pile-identity/pileGenerationPool.test.ts
  • tests/contracts/pile-identity/pileGenerationPoolModel.ts
  • tests/tracker/guanXuExchange.test.ts
  • tests/tracker/pileIdentityLedgerIntegration.test.ts
  • tsconfig.tracker.json
🚧 Files skipped from review as they are similar to previous changes (5)
  • CLAUDE.md
  • tests/tracker/guanXuExchange.test.ts
  • src/tracker/runtime/trackerController.ts
  • docs/agents/testing.md
  • src/tracker/Room.ts

Comment thread docs/agents/card_tracker.md
Comment thread tests/contracts/pile-identity/pileGenerationPoolModel.ts
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@llsccm

llsccm commented Aug 2, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@llsccm
llsccm merged commit c1038a2 into dev Aug 2, 2026
4 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Aug 2, 2026
@llsccm
llsccm deleted the codex/tracker-pile-identity-phase2 branch August 10, 2026 10:54
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.

1 participant