The on-disk half of the game: one directory of real files per stratum.
A gate opens for one access code, and that code is written into the stratum's files rather
than carried as an item. Scriber.Console is what reads them. Solving a stratum is: walk
into the gate to learn its node state, grep the records at the console for that state,
then unseal with the key on the line that matches.
What a stratum looks like on disk
<home>/runs/<seed>/stratum-2/
README what this stratum is, and which commands exist
manifest node records, one of which carries the gate's key
logs/ from stratum 3 onwards, the manifest sharded one record per file
gate.log the gate controller's log
.seal the SHA-256 of the access code, never the code itself
unsealed created by `unseal/2` when a code is acceptedExactly one record carries state=<gate_state/2> and that record's key= is the access
code from code/2. The other records are decoys wearing other states and other keys. From
depth 3 onwards the records move into logs/, one per file, and manifest says so.
Neither .seal nor gate.log contains the code or the gate's state, so reading every file
in the directory is not enough to solve the stratum on its own.
Where it lives
home/0 resolves the root directory: $SCRIBER_HOME, else $XDG_STATE_HOME/scriber, else
~/.local/state/scriber. Nothing is ever deleted on the game's own initiative — runs
accumulate one directory per seed until destroy/1 removes one.
Example
dir = Scriber.Lattice.prepare(1234, 1)
Scriber.Lattice.unsealed?(1234, 1)
#=> false
Summary
Functions
The access code that opens a stratum's gate: eight lowercase hex characters.
Delete a run's whole directory, every stratum and marker in it. Raises on failure.
The node state naming which record carries the gate's key.
The directory every run is kept under.
Write the stratum's files, creating the directory if needed, and return its path.
The directory holding a whole run, named for its seed.
The seeds of every run still on disk, most recently modified first.
The directory for one stratum of a run.
Record on disk that this stratum's gate has been opened.
Whether this stratum's gate has been opened from the console.
Functions
@spec code(integer(), pos_integer()) :: String.t()
The access code that opens a stratum's gate: eight lowercase hex characters.
A pure function of seed and depth. The game never shows this to the player; it is
written into exactly one record by prepare/2 and has to be found there.
@spec destroy(integer()) :: :ok
Delete a run's whole directory, every stratum and marker in it. Raises on failure.
@spec gate_state(integer(), pos_integer()) :: String.t()
The node state naming which record carries the gate's key.
A pure function of seed and depth, drawn from a fixed vocabulary of state words. No
decoy record ever wears this state, so exactly one record in the stratum matches it. The
player learns it by walking into the gate, not from any file.
@spec home() :: Path.t()
The directory every run is kept under.
Resolved in order: $SCRIBER_HOME, then $XDG_STATE_HOME/scriber, then
~/.local/state/scriber. An environment variable that is empty, unset, or holds a relative
path counts as absent, as the XDG base directory specification requires. When the system
reports no home directory, the temporary directory stands in for ~.
@spec prepare(integer(), pos_integer()) :: Path.t()
Write the stratum's files, creating the directory if needed, and return its path.
Writes .seal, README, the records (manifest, or logs/shard-N.log from depth 3), and
gate.log, overwriting any that exist. Idempotent: everything written is derived from
seed and depth, so re-preparing a stratum reproduces it byte for byte.
Files this function does not write are left alone, including the unsealed marker, so
re-preparing an opened stratum does not seal it again.
The directory holding a whole run, named for its seed.
@spec runs() :: [integer()]
The seeds of every run still on disk, most recently modified first.
Directory names that are not whole integers are ignored, as is a missing runs directory,
which yields [].
@spec stratum_dir(integer(), pos_integer()) :: Path.t()
The directory for one stratum of a run.
@spec unseal(integer(), pos_integer()) :: :ok
Record on disk that this stratum's gate has been opened.
Writes the marker unsealed/2 looks for. The marker survives prepare/2, so a stratum
stays open once opened. Always returns :ok, including when the write fails because the
stratum directory does not exist.
@spec unsealed?(integer(), pos_integer()) :: boolean()
Whether this stratum's gate has been opened from the console.