Retention for Vis-owned state: advisory inventory and bounded cleanup.
ADVISORY (scan observes, purge! acts, vis-agent doctor renders): the
drafts store (~/.vis/drafts). A draft clone is a full copy of a trunk and
survives until someone applies or abandons it, so a machine that drafts daily
and never abandons accumulates gigabytes of dead clones. It holds recoverable
work, so nothing here deletes it on its own: scan is pure observation (no
mutation, never throws) and purge! is the explicit operator action behind
vis-agent doctor --purge. scan reports the gateway journals the same way,
because an operator asking what is reclaimable today should see them.
SELF-DELETING (sweep-stale!, once per process at startup): diagnostic logs,
the gateway journals, the display caches, the rewind stores and old downloaded
Python archives. Those are DERIVED — a log of a process that exited, the wire
replay of a turn the DB already owns, a picture whose bytes are already DB-owned,
the pre-image of an edit nobody will rewind a fortnight later — so they carry
a window instead of a report. sweep-targets is the one list of them. Diagnostic
logs also sweep hourly while the process runs; the other targets remain startup-only.
Journals also self-sweep inside the tailer loop (gateway.bus/sweep!) after a
single idle day, but that is a LIVENESS rule and it only runs while a daemon
does — journals from crashed or never-restarted daemons used to stay forever.
Versioned Python runtime and source trees are never age-swept. An older install
may still serve another process; neither its age nor this binary's pin proves
it is unused. runtime-retention-plan previews candidates without deleting them.
purge! routes draft rows, including discarded-root retries, through
workspace/abandon! so backend bookkeeping owns primary and extra-root release.
A failed release never falls back to raw deletion. Only directories with no row
and journal files are removed directly, confined to the drafts or events store.
Retention for Vis-owned state: advisory inventory and bounded cleanup. ADVISORY (`scan` observes, `purge!` acts, `vis-agent doctor` renders): the drafts store (`~/.vis/drafts`). A draft clone is a full copy of a trunk and survives until someone applies or abandons it, so a machine that drafts daily and never abandons accumulates gigabytes of dead clones. It holds recoverable work, so nothing here deletes it on its own: `scan` is pure observation (no mutation, never throws) and `purge!` is the explicit operator action behind `vis-agent doctor --purge`. `scan` reports the gateway journals the same way, because an operator asking what is reclaimable today should see them. SELF-DELETING (`sweep-stale!`, once per process at startup): diagnostic logs, the gateway journals, the display caches, the rewind stores and old downloaded Python archives. Those are DERIVED — a log of a process that exited, the wire replay of a turn the DB already owns, a picture whose bytes are already DB-owned, the pre-image of an edit nobody will rewind a fortnight later — so they carry a window instead of a report. `sweep-targets` is the one list of them. Diagnostic logs also sweep hourly while the process runs; the other targets remain startup-only. Journals also self-sweep inside the tailer loop (`gateway.bus/sweep!`) after a single idle day, but that is a LIVENESS rule and it only runs while a daemon does — journals from crashed or never-restarted daemons used to stay forever. Versioned Python runtime and source trees are never age-swept. An older install may still serve another process; neither its age nor this binary's pin proves it is unused. `runtime-retention-plan` previews candidates without deleting them. `purge!` routes draft rows, including discarded-root retries, through `workspace/abandon!` so backend bookkeeping owns primary and extra-root release. A failed release never falls back to raw deletion. Only directories with no row and journal files are removed directly, confined to the drafts or events store.
Test seam for the display cache root. nil (production) resolves to
~/.vis/cache, mirroring foundation.mpl-capture/display-cache-file and the
TUI channel's terminal-image cache.
Test seam for the display cache root. `nil` (production) resolves to `~/.vis/cache`, mirroring `foundation.mpl-capture/display-cache-file` and the TUI channel's terminal-image cache.
Test seam for the gateway journal directory. nil (production) resolves to
~/.vis/gateway/events, mirroring the private gateway.bus/events-dir —
journals are addressed by absolute path from several processes, so that
location is a fixed contract rather than a user-facing configurable.
Test seam for the gateway journal directory. `nil` (production) resolves to `~/.vis/gateway/events`, mirroring the private `gateway.bus/events-dir` — journals are addressed by absolute path from several processes, so that location is a fixed contract rather than a user-facing configurable.
Test seam for the diagnostic log directory. nil (production) resolves to
~/.vis/logs, mirroring internal.paths/logs-dir — the location is a
fixed contract shared with the sandbox grant, not a configurable.
Test seam for the diagnostic log directory. `nil` (production) resolves to `~/.vis/logs`, mirroring `internal.paths/logs-dir` — the location is a fixed contract shared with the sandbox grant, not a configurable.
Test seam for the embedded Python state root. nil (production) resolves to
~/.vis/python, mirroring com.blockether.vispython.Locations — the
runtime unpacks each pinned version under runtime/<version>/<platform>
and extracts its shipped sources under sources/<version>.
Test seam for the embedded Python state root. `nil` (production) resolves to `~/.vis/python`, mirroring `com.blockether.vispython.Locations` — the runtime unpacks each pinned version under `runtime/<version>/<platform>` and extracts its shipped sources under `sources/<version>`.
Test seam for the rewind store root. nil (production) resolves to
~/.vis/rewind, mirroring foundation.rewind/*store-root*.
Test seam for the rewind store root. `nil` (production) resolves to `~/.vis/rewind`, mirroring `foundation.rewind/*store-root*`.
Bytes one display cache may still hold once the age pass is done. Age alone does not bound an afternoon that renders thousands of figures, so the newest files up to this budget survive and the oldest go first.
Bytes one display cache may still hold once the age pass is done. Age alone does not bound an afternoon that renders thousands of figures, so the newest files up to this budget survive and the oldest go first.
Delay between diagnostic-log sweeps while a process stays alive: one hour.
Delay between diagnostic-log sweeps while a process stays alive: one hour.
Age past which any self-deleting derived artifact is deleted automatically — diagnostic logs, gateway journals, the display caches, the rewind stores. Two weeks: longer than any plausible debugging or rewind window (a bug reported on Friday is still readable the Monday after next), short enough that a machine which never restarts does not carry a quarter of dead sessions. ONE number for every kind on purpose — a per-kind window is a promise nobody audits, and each kind is reconstructible from the DB or from nothing at all.
Age past which any self-deleting derived artifact is deleted automatically — diagnostic logs, gateway journals, the display caches, the rewind stores. Two weeks: longer than any plausible debugging or rewind window (a bug reported on Friday is still readable the Monday after next), short enough that a machine which never restarts does not carry a quarter of dead sessions. ONE number for every kind on purpose — a per-kind window is a promise nobody audits, and each kind is reconstructible from the DB or from nothing at all.
Age past which unattended state is worth mentioning. Two weeks: long enough that a draft parked over a holiday is not nagged about, short enough that the report still arrives while the operator remembers what the draft was for.
Age past which unattended state is worth mentioning. Two weeks: long enough that a draft parked over a holiday is not nagged about, short enough that the report still arrives while the operator remembers what the draft was for.
(purge! {:keys [db-info is-dry-run] :as opts})Reclaim everything scan reported. Returns the scan augmented with a
:purged vec (each item stamped :is-purged) and :reclaimed-bytes.
With :is-dry-run true nothing is touched: :purged still carries the plan
with every item stamped :is-purged false, so operators can look first.
Reclaim everything `scan` reported. Returns the scan augmented with a `:purged` vec (each item stamped `:is-purged`) and `:reclaimed-bytes`. With `:is-dry-run` true nothing is touched: `:purged` still carries the plan with every item stamped `:is-purged false`, so operators can look first.
(runtime-retention-plan)(runtime-retention-plan {:keys [runtime-version]})Preview keeping the newest installed release and this binary's pinned runtime.
Returns {:is-dry-run true :runtime-version :targets}, with :latest-version,
:retained and :candidates for each runtime/source store. Candidates are NOT
safe-to-delete findings: their process liveness is unverified. No files are
changed. Startup cleanup also leaves runtime and source trees untouched.
Numeric three-part releases are ordered numerically, not by mtime or string.
Unknown version names and symlinked directories are retained. :runtime-version
overrides the current binary's pin for fixture experiments. Missing stores
report empty vectors; unreadable stores report :unavailable? true.
Preview keeping the newest installed release and this binary's pinned runtime.
Returns `{:is-dry-run true :runtime-version :targets}`, with `:latest-version`,
`:retained` and `:candidates` for each runtime/source store. Candidates are NOT
safe-to-delete findings: their process liveness is unverified. No files are
changed. Startup cleanup also leaves runtime and source trees untouched.
Numeric three-part releases are ordered numerically, not by mtime or string.
Unknown version names and symlinked directories are retained. `:runtime-version`
overrides the current binary's pin for fixture experiments. Missing stores
report empty vectors; unreadable stores report `:unavailable? true`.(scan {:keys [db-info days now-ms]})Observe stale drafts and gateway journals. Pure: touches no state and never throws — a missing DB, an absent drafts store, or an unreadable subtree all degrade to empty findings.
Options: :db-info (nil is fine, drafts then reduce to on-disk orphans),
:days (defaults to default-stale-days) and :now-ms for tests.
Observe stale drafts and gateway journals. Pure: touches no state and never throws — a missing DB, an absent drafts store, or an unreadable subtree all degrade to empty findings. Options: `:db-info` (nil is fine, drafts then reduce to on-disk orphans), `:days` (defaults to `default-stale-days`) and `:now-ms` for tests.
(sweep-stale!)(sweep-stale! {:keys [days now-ms] budget-override :budget-bytes})Delete the aged-out derived state of every sweep-targets entry. Returns
{:targets [{:id :root :days :cutoff-ms :file-count :deleted :bytes :dirs-removed :over-budget-deleted}…] :deleted :bytes} — :deleted counts
entries actually removed and :bytes the space reclaimed.
Never throws: a missing directory is zero work, and a permission-denied subtree is skipped rather than allowed to take startup down.
Options, all for tests: :days (overrides every target's window),
:budget-bytes (overrides every byte budget) and :now-ms.
Delete the aged-out derived state of every `sweep-targets` entry. Returns
`{:targets [{:id :root :days :cutoff-ms :file-count :deleted :bytes
:dirs-removed :over-budget-deleted}…] :deleted :bytes}` — `:deleted` counts
entries actually removed and `:bytes` the space reclaimed.
Never throws: a missing directory is zero work, and a permission-denied
subtree is skipped rather than allowed to take startup down.
Options, all for tests: `:days` (overrides every target's window),
`:budget-bytes` (overrides every byte budget) and `:now-ms`.(sweep-stale-async!)(sweep-stale-async! opts)Start the stale-state sweep on a lowest-priority daemon thread, then repeat diagnostic-log cleanup hourly for this process's lifetime. Other targets are swept only at startup. All passes are best-effort and off the first-paint path; a short-lived CLI may exit before its initial pass finishes.
Called once per process. Returns the thread; interrupt it to stop. :interval-ms
overrides the hourly delay for tests. The body is a bound-fn so ALL home seams
convey to every pass rather than falling back to the operator's real ~/.vis.
Start the stale-state sweep on a lowest-priority daemon thread, then repeat diagnostic-log cleanup hourly for this process's lifetime. Other targets are swept only at startup. All passes are best-effort and off the first-paint path; a short-lived CLI may exit before its initial pass finishes. Called once per process. Returns the thread; interrupt it to stop. `:interval-ms` overrides the hourly delay for tests. The body is a `bound-fn` so ALL home seams convey to every pass rather than falling back to the operator's real `~/.vis`.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |