fix: address PR review — variant hash snippet and scaling denominator

- compute_variant_hash: use refractor_tier key, json.dumps with sort_keys
  instead of str(), add variant=0 remapping guard
- Section 5.3.1 step 3: scaling denominator is total_requested_addition,
  not total_requested_reduction

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Cal Corum 2026-04-07 20:33:00 -05:00
parent 3ad893c949
commit dba7e562c4

View File

@ -122,7 +122,7 @@ proportionally so the 108-sum invariant is always preserved. Specifically:
1. Negative deltas are applied first, each capped at the column's current value (0 floor).
2. The total amount actually reduced is computed.
3. Positive deltas are scaled by `actually_reduced / total_requested_reduction` so that
3. Positive deltas are scaled by `actually_reduced / total_requested_addition` so that
additions always equal reductions.
4. A warning is logged when truncation occurs.
@ -230,18 +230,19 @@ are currently always 0. The evolution system uses variant to store evolved versi
variant number derived from a **deterministic hash** of all inputs that affect the card:
```python
import hashlib
import hashlib, json
def compute_variant_hash(player_id: int, evolution_tier: int,
def compute_variant_hash(player_id: int, refractor_tier: int,
cosmetics: list[str] | None) -> int:
"""Compute a stable variant number from evolution + cosmetic state."""
"""Compute a stable variant number from refractor + cosmetic state."""
inputs = {
"player_id": player_id,
"evolution_tier": evolution_tier,
"refractor_tier": refractor_tier,
"cosmetics": sorted(cosmetics or []),
}
raw = hashlib.sha256(str(inputs).encode()).hexdigest()
return int(raw[:8], 16) # 32-bit unsigned integer from first 8 hex chars
raw = hashlib.sha256(json.dumps(inputs, sort_keys=True).encode()).hexdigest()
result = int(raw[:8], 16) # 32-bit unsigned integer from first 8 hex chars
return result if result != 0 else 1 # variant=0 is reserved for base cards
```
- `variant = 0`: Base card (standard, shared across all teams)