The visibility checklist
For a game where a side doesn't see everything: fog, a hidden hand, a secret. The world holds everything and answers whoever asks it, so every leak below is the game's, made safe by a filter the game puts between the world and what it tells a player. Go down the list for each new thing the game shows, sends or saves.
| What | What it tells | Where the filter stands |
|---|---|---|
| Actor numbers | A number counts every actor made before it, the other side's too: a gap says the other side made something | Never show or send a number; name each actor by the viewer's own label, made in the order the viewer saw it |
| Journal rows | A row names its subject, source, credit and target, seen or not; a row's number counts every row | Pass on only rows whose subject the viewer sees; say an unseen source, credit or target as "unseen"; drop the row's number |
| Previews and forecasts | A plain preview runs every rule, the unseen side's too: a damage forecast against a unit with an unseen medic tells that the medic is there | Ask as the viewer sees the world: CheckAs, PriceAs, PreviewAs, ForecastAs, ChoicesAs, with the actors it sees (WorldHost.Sees) |
| The draw stream | One stream's state tells every next draw; a hidden draw moves it | Give each side its own stream where a side draws in secret; never send a stream's state or the seed |
| Saves and recordings | A save, a capture and a recording hold the whole world, its streams and the seed | Never send one to a player who mustn't see all of it; a peer's sync is the state hash, not the save |
| Refusal words | "needs 50 Ore, has 20" says the other side's bank, where the order named the other side's actor | Word a refusal for the viewer: its own order's need and have; another side's only as "not now" |
A side's view (SideView.Read) | Each actor sees names, whole: its archetype, every pool's amount and maximum, every hold with its source, its links, what it runs, its place; the side's own made actors' ties, which count their caster's activations | Pass the game's sight, the public actors among it; Withhold each pool or effect told of the side's own actors alone (a magazine, a charge, a reload, a cooldown); never send a number, only the view's labels (host.md, "A predicting client") |
An order's answer (SideView.Answer) | The tag, given or refused and why, the activation's count, the actor it made by label where seen | What the game sends beside it, what an order met, it names by LabelOf, 0 where the side didn't see it; never the outcome's words or numbers |
| An auto's candidates | An auto picks among bodies in reach, the unseen among them: who it fired at says who stood there | Answer a fact the auto's target query asks (requires fact(Seen, holder, target) > 0), so the world refuses an unseen target |
Also: a tick told while another side acts (a turn-based game's AI planning) says how long it thought; an open choice's answers are shown only to the side it waits on.
What the shared world rules out
One world, run the same on every peer, is what makes a replay and a hash agree. It also rules out these, so choose with them in mind:
- Lockstep keeps no secret. Under lockstep every peer holds the whole world, so fog or a hidden hand there is a courtesy, not privacy: a player who reads their own memory sees all of it. A game that hides anything runs with server authority, the server holding the world and sending each player what it sees.
- A world rolled back in place hashes as its frame; one restored from text hashes apart. A world rolled back by its snapshots (
S.RollBack, host.md, "A rollback host") hashes as the frame it came from, so rollback peers compare one number. A world restored from a text save lays its rows out anew and hashes apart from its source though the two saves agree: a peer that resyncs from a save can't compare hashes with one that didn't, unless both restore the same save. - A game whose engine owns the physics replays from its recording, not by simulating again, so it can't be a lockstep peer: the engine's steps aren't the world's, and two machines' differ.
- What a game keeps outside the seat (a field of its own, an engine's places, input buffers) is in no world save, hash or view: a host that rolls back or resyncs puts it back itself. What it keeps in the seat is the world's, saved, restored, hashed, recorded and rolled back with it, a side's part told to that side alone (state.md).
- The per-frame snapshot is the session's, not the text save. At the action RPG's wave of 1,226 actors one save takes 9 to 10 ms, against a median frame of about 1.3 ms (the kernel's
.scratch\15\hashcost-run.txt). A rollback host takesS.Take()each frame and rolls back withS.RollBack(tick)in place (host.md, "A rollback host"); the text save is for a quicksave or a resync, taken seldom.
design\24-previews.md, "Who may see what", says what the world itself guarantees a view, and what it leaves to the game.
From ledger-v3's guide/ledger-author/visibility.md, last changed 2026-10-31.