setup_stamp
setup_stamp
¶
Setup-stamp primitive: cheap "did the user run setup?" check for the TUI startup path.
Background¶
The TUI's start-up budget is ≤2 s. A real sickbay health check
takes seconds — too slow for an every-launch probe. Instead we drop
a small JSON marker after a successful setup run and compare it
against the currently-installed package versions on each launch:
- match →
OK, no surface - absent →
FIRST_RUN, blocking modal nudges the user to run setup - installed > stamped →
STALE_AFTER_UPDATE, non-blocking banner - installed < stamped →
STALE_AFTER_DOWNGRADE, blocking warning (downgrades aren't tested; explicit override required) - stamp can't be parsed →
STAMP_CORRUPT, treated asFIRST_RUN
Lives in sandbox because it's the lowest layer — every other ecosystem package depends on sandbox, so the primitive is reachable from any frontend without inverting the dep graph.
Resolution detail¶
Package versions are read via importlib.metadata.version —
no subprocess, no parsing, sub-millisecond per package. Total cost
of needs_setup on a happy path: one Path.is_file, one
JSON decode, four to five importlib.metadata lookups. Well under
the 2 s budget.
The set of tracked packages is the v0 ecosystem (terok,
terok-executor, terok-sandbox, terok-shield,
terok-clearance). A package missing from the local install is
ignored on the read side — standalone sandbox installations don't
have terok and shouldn't see STALE_AFTER_DOWNGRADE because of it.
__all__ = ['SetupVerdict', 'clear_stamp', 'needs_setup', 'stamp_path', 'write_stamp']
module-attribute
¶
SetupVerdict
¶
Bases: Enum
Result of needs_setup — five possible states a launch can be in.
OK = 'ok'
class-attribute
instance-attribute
¶
Stamp matches all installed package versions exactly.
FIRST_RUN = 'first_run'
class-attribute
instance-attribute
¶
No stamp on disk — the user has never run setup (or wiped state).
STALE_AFTER_UPDATE = 'stale_after_update'
class-attribute
instance-attribute
¶
At least one installed package is newer than the stamped version.
STALE_AFTER_DOWNGRADE = 'stale_after_downgrade'
class-attribute
instance-attribute
¶
At least one installed package is older than the stamped version.
Downgrades aren't tested and can leave systemd units / state DB in forms the older code can't interpret. Frontends should treat this as a hard stop until the user explicitly overrides.
STAMP_CORRUPT = 'stamp_corrupt'
class-attribute
instance-attribute
¶
Stamp file exists but can't be parsed. Frontends should treat as FIRST_RUN.
stamp_path()
¶
Return the canonical on-disk location of the setup stamp.
Honours the umbrella paths.root resolver so a user who relocates
the state tree (paths.root: /virt/terok in config.yml) sees
the stamp move with it — same place every package would look.
Source code in src/terok_sandbox/setup_stamp.py
needs_setup()
¶
Compare the on-disk stamp against currently-installed package versions.
See SetupVerdict for the five possible outcomes. Designed
to be cheap enough to call on every TUI startup.
Source code in src/terok_sandbox/setup_stamp.py
write_stamp()
¶
Capture the currently-installed versions to disk and return the path.
Called by _handle_sandbox_setup after a successful run. An
atomic temp-file + rename keeps a partial write from leaving a
half-stamp that needs_setup would later flag as STAMP_CORRUPT.
Source code in src/terok_sandbox/setup_stamp.py
clear_stamp()
¶
Remove the stamp file if present. Returns True if a file was removed.
EAFP rather than is_file + unlink: keeps the function
race-safe under a (rare) concurrent terok uninstall instead of
leaking a FileNotFoundError between the existence check and the
unlink. Used by terok uninstall and by tests that want to
simulate a fresh-install state without nuking the rest of the
state tree.
Source code in src/terok_sandbox/setup_stamp.py
installed_versions()
¶
Return {package: version} for every tracked package present in the install.
Missing packages are silently dropped — a standalone terok-sandbox
install doesn't have terok available, and that's fine. The
invariant we check on the read side is that every package the stamp
knows about is also installed (and at the right version).
Source code in src/terok_sandbox/setup_stamp.py
read_stamp(path)
¶
Parse the stamp file, returning the packages mapping.
Raises ValueError if the schema version doesn't match — a
schema bump should be handled explicitly, not silently coerced.