public sealed class PlacementLogThe last placement decision per player, bounded. Doc 27 § Diagnostics' `explain`.
Remarks
⚠ The explanation already existed and had nowhere to live, which is the whole reason this type does. PlacementDecision.Explain() has produced the full account since L1 — the filter that excluded each candidate and the score of each survivor — and PlaceResult.Reason carries it back to whoever asked. But that is the only moment it exists: the gate turns it into an HTTP response and it is gone. § Diagnostics asks for explain <player>, which is a question asked after a complaint, by somebody who was not there.
⚠ Bounded, and that is not a detail. This lives in a grain, one per map, in a process that is meant to run for weeks. An unbounded record of every placement is a memory leak with a plausible excuse, and the leak would be worst on exactly the busiest map. What is kept is the last decision per player and at most Capacity of those, oldest evicted first — because the question is always "why am I here now", never "where was I on Tuesday".
The eviction is by insertion order rather than by recency of lookup: a player nobody has asked about is not more disposable than one somebody has, and an LRU would make the support tool's own reads change what the tool can see next.
Fields and properties (2)
public int CapacityHow many players' decisions are kept.
public int CountHow many are held now.
Methods (4)
public void Record(PlacementRecord record)Notes a decision, replacing whatever was known about that player.
public bool TryGet(PlayerKey player, out PlacementRecord? record)What this map last decided about somebody.
public string Explain(PlayerKey player)The explanation for somebody, or a sentence saying there is none.
public IReadOnlyList<PlacementRecord> Recent()Everything held, newest first.
Used by (3)
- MapCoordinatorVixen.Live.Orchestrator
- MapGrainVixen.Live.Orchestrator
- PlacementLogTestsVixen.Live.Orchestrator.Tests