From ea82d51b593392db7bded3e14ea838414749e6f0 Mon Sep 17 00:00:00 2001 From: Teakowa Date: Tue, 3 Nov 2026 20:46:52 +0800 Subject: [PATCH 1/2] test(probes): record p7 hero-settings client runs Three client runs on 2.25.0.1 - 154504.1 (zh-CN) all matched expect.json: Max Health 375, damage 200 landed as 100, heal 40 landed as 80, and Set Ability Cooldown wrote 20 literally. Refs #11 --- probes/p7-hero-settings/capture-2.txt | 5 +++++ probes/p7-hero-settings/capture-3.txt | 5 +++++ probes/p7-hero-settings/capture.json | 30 ++++++++++++++++++++------- probes/p7-hero-settings/capture.txt | 5 +++++ 4 files changed, 38 insertions(+), 7 deletions(-) create mode 100644 probes/p7-hero-settings/capture-2.txt create mode 100644 probes/p7-hero-settings/capture-3.txt create mode 100644 probes/p7-hero-settings/capture.txt diff --git a/probes/p7-hero-settings/capture-2.txt b/probes/p7-hero-settings/capture-2.txt new file mode 100644 index 0000000..391c0c3 --- /dev/null +++ b/probes/p7-hero-settings/capture-2.txt @@ -0,0 +1,5 @@ +[00:00:18] P7 max_health=375 +[00:00:18] P7 health_after_damage=275 +[00:00:18] P7 health_after_heal=355 +[00:00:18] P7 ability1_cooldown=20 +[00:00:18] P7 done diff --git a/probes/p7-hero-settings/capture-3.txt b/probes/p7-hero-settings/capture-3.txt new file mode 100644 index 0000000..8c8254a --- /dev/null +++ b/probes/p7-hero-settings/capture-3.txt @@ -0,0 +1,5 @@ +[00:00:19] P7 max_health=375 +[00:00:19] P7 health_after_damage=275 +[00:00:19] P7 health_after_heal=355 +[00:00:19] P7 ability1_cooldown=20 +[00:00:19] P7 done diff --git a/probes/p7-hero-settings/capture.json b/probes/p7-hero-settings/capture.json index 301d966..69c82da 100644 --- a/probes/p7-hero-settings/capture.json +++ b/probes/p7-hero-settings/capture.json @@ -1,15 +1,31 @@ { "probe": "p7-hero-settings", "client": { - "version": "", - "date": "", + "version": "2.25.0.1 - 154504.1", + "date": "2026-11-03", "locale": "zh-CN" }, - "runs": 0, + "runs": 3, "probe_sha256": "5aa48b5a6807880ed6531c58486c22d8ca44e56803965db8482cc386c138e504", "hypothesis": "hero settings move the reported player state: health% 150 on Ana (health pool 250) reports Max Health 375; damageReceived% 50 lands a scripted Damage of 200 as 100; healingReceived% 200 lands a scripted Heal of 40 as 80; abilityCooldown% 50 applies to ability cooldowns, while Set Ability Cooldown(player, Ability 1, 20) is expected to write the timer literally and report 20", - "observed": [], - "result": "inconclusive", - "notes": "No captures yet; running the probe in the client is an owner step. The expected lines are hypotheses in expect.json. A cooldown reading of 10 instead of 20 would mean abilityCooldown% scales Set Ability Cooldown as well; either observation is a real result. The settings restrict the lobby to Ana (enabledHeroes), so any player produces the same numbers.", - "sources": [] + "observed": [ + { + "runs": [ + 1, + 2, + 3 + ], + "max_health": 375, + "health_after_damage": 275, + "health_after_heal": 355, + "ability1_cooldown_s": 20 + } + ], + "result": "match", + "notes": "All three runs gave the same four readings. Set Ability Cooldown wrote 20 literally, so abilityCooldown% 50 did not scale the scripted write. The probe measures script-applied damage, healing and cooldown writes, not natural ability cooldowns. The client version was read on 2026-11-03; the versions of runs 1 and 2 were not recorded. Raw logs were received through UU Remote file transfer.", + "sources": [ + "Log-2026-10-27-18-29-27.txt", + "Log-2026-11-02-16-11-32.txt", + "Log-2026-11-03-01-53-07.txt" + ] } diff --git a/probes/p7-hero-settings/capture.txt b/probes/p7-hero-settings/capture.txt new file mode 100644 index 0000000..8c8254a --- /dev/null +++ b/probes/p7-hero-settings/capture.txt @@ -0,0 +1,5 @@ +[00:00:19] P7 max_health=375 +[00:00:19] P7 health_after_damage=275 +[00:00:19] P7 health_after_heal=355 +[00:00:19] P7 ability1_cooldown=20 +[00:00:19] P7 done From db4e62e18d8b76b53ddce92ce9e14fccf110e926 Mon Sep 17 00:00:00 2001 From: Teakowa Date: Tue, 3 Nov 2026 20:55:04 +0800 Subject: [PATCH 2/2] fix(probes): assert p7 capture and update stale docs Remove the stale ignore on the p7 fixture test. State what P7 measured in architecture.md and actions.rs. Name the balance version limit in capture notes. Refs #11 --- crates/athena-sim/src/actions.rs | 4 ++-- crates/athena-sim/tests/fixtures.rs | 7 +++---- docs/architecture.md | 4 ++-- probes/p7-hero-settings/capture.json | 2 +- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/crates/athena-sim/src/actions.rs b/crates/athena-sim/src/actions.rs index 1da6bdd..997a3a7 100644 --- a/crates/athena-sim/src/actions.rs +++ b/crates/athena-sim/src/actions.rs @@ -186,8 +186,8 @@ fn run( return unsupported("setAbilityCooldown arguments"); }; // `Set Ability Cooldown` writes the reported cooldown for - // the slot literally; whether `abilityCooldown%` also - // scales it is what P7 is for. + // the slot literally; P7 measured that `abilityCooldown%` + // does not scale the write. let ids = player_ids(player, &env)?; let slot = button_slot(button)?; let seconds = diff --git a/crates/athena-sim/tests/fixtures.rs b/crates/athena-sim/tests/fixtures.rs index cafd0d7..2f25340 100644 --- a/crates/athena-sim/tests/fixtures.rs +++ b/crates/athena-sim/tests/fixtures.rs @@ -244,14 +244,13 @@ fn p6_wait_behavior() { } #[test] -#[ignore = "no captures yet (`runs` is 0)"] fn p7_hero_settings() { check_probe("p7-hero-settings"); } -/// P7 is `inconclusive`: it has no captures. This test does not assert -/// client behavior; it checks the simulator's modeled player state produces -/// the hypothesis lines in `expect.json`, and that a bare `run_text` — no +/// `p7_hero_settings` asserts the P7 client capture. This test does not +/// assert client behavior; it checks the simulator's modeled player state +/// produces the lines in `expect.json`, and that a bare `run_text` — no /// scenario, so no player — reports the probe `not_modeled`. The values are /// test-loaded so the check does not wait on a workshop-rs release. #[test] diff --git a/docs/architecture.md b/docs/architecture.md index ea3548c..0244c2d 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -64,9 +64,9 @@ The simulator makes these choices only to stay deterministic; each needs a probe - Comparing values of different types with `==` gives false; `Null` equals `0`. Two mocked players compare by scenario `id`. - A mocked player is a scenario `id`; `Event Player` yields `{"type":"player"}`. `Hero Of` yields the catalog member id the declared `hero` resolves to; `Team Of` likewise yields the `Team` member id of the declared `team`, so it compares equal to a `Team` literal. - An event rule fires when the triggering event's `kind` — injected or raised — matches the rule event's catalog id and the event player satisfies the rule's `team` and player (`target`) filters. -- **Modeled, not measured** — no client capture backs the player state table or the `Damage`/`Heal` rules: +- **Modeled, not measured** — probe P7 measured `health%`, `damageReceived%` and `healingReceived%` on scripted `Damage`/`Heal`, and a literal `Set Ability Cooldown` under `abilityCooldown%` 50 (Ana, client 2.25.0.1); nothing else backs the player state table or the `Damage`/`Heal` rules: - Each scenario player has a state-table row built at run start from the `workshop-rs` hero-values file pinned at `CURRENT_VERSION`: a `health` pool, `shield` and `armor` pools where the catalog records them (a hero without the pool has no entry, never a zero), the cooldown seconds of the ability slots the catalog records (`slot` or `slot/variant` keys), and an ultimate charge of `0` toward the catalog's `ultimateCost`. Pools start at their maximum. The program's hero settings then apply: `health%` scales every pool, the `abilityCooldown%` and per-slot `*Cooldown%` scalars scale the reported cooldowns, and the dealt/received scalars feed `Damage`/`Heal` below. Percent scalars authored at several scopes multiply together. A hero the file does not supply, a player with no `hero`, or a hero setting authored for the player that the simulator does not apply (one that moves a reported value — ultimate generation, spawning with ultimate, passive health regeneration or the role passive, headshots-only, spawning without mech, or a cooldown scalar with no reported slot) leaves the row's `world` null; an action that touches that world state (`Damage`, `Heal`, dealt or received) stops the run as `not_modeled`. The exception is a player whose version-2 `state` map declares every `state` key the setting can move — `ultCharge` for the ultimate-charge settings (`ultGen%`, `passiveUltGen%`, `combatUltGen%`, `enableSpawningWithUlt`), `health`, `maxHealth` and `normalizedHealth` for the health ones (`passiveHealthRegen`, `enableRolePassive`): the scenario already supplies the value the setting could move, so the setting is skipped — `state.` stands, the setting itself is not simulated (athena#91). The other unapplied settings have no `state` coverage and keep failing, and an opaque `Raw*` member fails the same way. - - `Health`/`Max Health` read the pools' summed `current`/`max` only while the player declares no version-2 `state` map — a declared `state.health`/`state.maxHealth` answers instead (athena#89); `Ability Cooldown` reads the slot's reported seconds (`0` where the player has no such slot); `Set Ability Cooldown` writes the slot's reported seconds literally — whether `abilityCooldown%` also scales a scripted set is what probe P7 is for. Reading a player's world state is a touch like `Damage`/`Heal`. + - `Health`/`Max Health` read the pools' summed `current`/`max` only while the player declares no version-2 `state` map — a declared `state.health`/`state.maxHealth` answers instead (athena#89); `Ability Cooldown` reads the slot's reported seconds (`0` where the player has no such slot); `Set Ability Cooldown` writes the slot's reported seconds literally; P7 measured that `abilityCooldown%` 50 does not scale a scripted set (20 stays 20). Natural ability cooldowns are not measured. Reading a player's world state is a touch like `Damage`/`Heal`. - `Damage(player, damager, amount)` takes `amount` off the pools in shield, armor, health order: each pool absorbs up to its `current` and the rest spills into the next; health floors at zero and a negative amount does nothing. `Heal(player, healer, amount)` raises the `health` pool by `amount`, capped at `max` — it never exceeds the maximum, never refills shield or armor, and a negative amount does nothing. Both accept a `Player` or an array of players. The amount lands scaled: by the dealer's `damageDealt%` and the target's `damageReceived%` for `Damage`, and by the healer's `healingDealt%` and the target's `healingReceived%` for `Heal`; a `Null` dealer or healer carries no scale. A `damager`/`healer` value that is not a player or `Null` is not modeled. - `Damage`/`Heal` act only on living players (athena#47): the one liveness read — a state cell or the declared `state.isDead`, the same read `Is Alive`/`Is Dead`/`Set Player Health` make, with the health pool deciding where `isDead` cannot answer — gates both, so a dead target's pools do not move and no events raise. A hit that lands raises `Player Took Damage` on the target and `Player Dealt Damage` on a player dealer; a hit that empties `health` writes the `isDead` cell and adds `Player Died` then `Player Dealt Final Blow`; a heal raises `Player Received Healing`/`Player Dealt Healing`. The events bind `Event Player` to the player they happened to and `Attacker`, `Victim`, `Event Damage`/`Event Healing` to the cause; an event value the cause does not bind is `not_modeled`. `Respawn` refills the health pool to `max` alongside its `isDead`/`health` writes — "with full health, even if they were already alive" — and `Resurrect` refills only when it revives a dead target, a living one keeping its health; either revive leaves a player that can die again. - **Modeled, not measured** — spawn state and the host player. No capture covers them: diff --git a/probes/p7-hero-settings/capture.json b/probes/p7-hero-settings/capture.json index 69c82da..fa61e55 100644 --- a/probes/p7-hero-settings/capture.json +++ b/probes/p7-hero-settings/capture.json @@ -22,7 +22,7 @@ } ], "result": "match", - "notes": "All three runs gave the same four readings. Set Ability Cooldown wrote 20 literally, so abilityCooldown% 50 did not scale the scripted write. The probe measures script-applied damage, healing and cooldown writes, not natural ability cooldowns. The client version was read on 2026-11-03; the versions of runs 1 and 2 were not recorded. Raw logs were received through UU Remote file transfer.", + "notes": "All three runs gave the same four readings. Set Ability Cooldown wrote 20 literally, so abilityCooldown% 50 did not scale the scripted write. The probe measures script-applied damage, healing and cooldown writes, not natural ability cooldowns. The client version was read on 2026-11-03; the versions of runs 1 and 2 were not recorded. Balance version: workshop-rs names the client version of its hero-values file as `balanceVersion` (CURRENT_VERSION `2.25.0.0 - 154461.1`), not a named patch. This capture's client is 2.25.0.1 and workshop-rs has no file for it, so the balance version of the Ana 250 health reading is not determinable; the 375 reading only matches a 250 base. Raw logs were received through UU Remote file transfer.", "sources": [ "Log-2026-10-27-18-29-27.txt", "Log-2026-11-02-16-11-32.txt",