← all tickets

43 — Per-target MCTS keys for own-zone card choices (Archives recursion, Sprint, and the ticket-39 decisions)

Status: fixed

Decision (2026-08-02, triage with maintainer): Approved, and widened. Both cautions that made this needs-triage dissolved on inspection:

1. The "must match the Python engine's keys" constraint in the mcts.rs header is dead documentation — ai/mcts.py no longer exists (retired with the port scaffolding, ticket 19). The only Python _action_key left is a local JSON-dump helper in tests/test_mcts2_legality.py:59, which does not constrain tree keys. 2. Per-target keys are sound under determinisation for the decider's own zones: determinise (rust/netrunner-core/src/ai/determinise.rs:28) shuffles only the *opponent's* hidden info — the searcher's own zones are fixed (asserted by the test at determinise.rs:538). So a card_index into the decider's own HQ/grip/Archives names the same card in every determinisation. This is exactly why precision_design:{source}:{card_index} already works.

Scope — six actions, not two. Ticket-39's decisions share the identical flaw (every target collapses onto one type-only edge via the fallback at ai/mcts.rs:138) and the identical soundness argument:

| Action | Decider's zone | Key | |---|---|---| | ArchivesRecur | Corp Archives | archives_recur:{source}:{card_index} | | SprintReturn | Corp HQ | sprint_return:{card_index} | | LongevityTrash | Corp HQ | longevity_trash:{card_index} | | HanseiTrash | Corp HQ | hansei_trash:{card_index} | | AnoeticTrash | Corp HQ | anoetic_trash:{card_index} | | CarnivoreTrash | Runner grip | carnivore_trash:{card_index} |

Decisions on the open design points:

Definition of done:

Comments

2026-08-02: Filed from the review of ticket 41. This is marked for triage because action_key documents compatibility with the Python reference and deliberately aggregates some indices across determinizations; maintainers should confirm the target-key policy before changing that shared tree identity.

2026-08-02: Implemented. All six actions key per target in ai/mcts.rs::action_key; mcts2::observed_action_key falls through to the shared key for all six, so both trees agree. The stale Python-compat claims in the module header and the action_key doc comment are replaced with the aggregate-hidden / distinguish-own-zone policy. Four new unit tests cover three Archives targets (including the archives_fd / archives_fu split), two Sprint targets, all four ticket-39 trash actions, the two type-only Done* companions, and the both-trees-agree property. The fallback audit is filed as ticket 45 (needs-triage). cargo fmt / clippy -D warnings / cargo test --workspace green (144, up from 140); pytest -q 134 passed, unchanged.

2026-08-02: Triaged with the maintainer (grilling session). Approved; scope widened from ArchivesRecur/SprintReturn to all six own-zone card-choice decisions; index-based keys; same identity in both trees; stale Python-compat docs rewritten in-scope; remaining fallback tail handled as an audit + follow-up ticket rather than widening further. Status flipped to ready-for-agent.