State Model

September 5, 2026 · View on GitHub

This document describes the persistent on-disk state used by TaroCub.

The goal is to answer five practical questions for each file:

  1. Where does it live?
  2. Which module owns it?
  3. What data is authoritative?
  4. What are the write and recovery rules?
  5. How sensitive is it?

This document covers both:

  • authoritative state: files the runtime depends on for behavior
  • operational artifacts: logs, inbox files, backups, and registry files that are useful but not the source of truth for core behavior

Root Layout

Per-instance state lives under:

~/.cctb/<instance>/

Typical files and directories:

.env
config.json
access.json
session.json
runtime-state.json
usage.json
usage.last-good.json
file-workflow.json
cron-jobs.json
board.json
mini-bus.json
delivery-obligations.json
restart-loop.json
audit.log.jsonl
instance.lock.json
workspace/
inbox/
service.stdout.log
service.stderr.log

Some related control-plane state lives one level above the instance:

~/.cctb/.bus-registry.json

Classification

The project should reason about state in four buckets.

1. Authoritative configuration

  • .env
  • config.json

These files define how the instance should run.

2. Authoritative runtime state

  • access.json
  • session.json
  • runtime-state.json
  • usage.json
  • file-workflow.json
  • cron-jobs.json
  • board.json
  • mini-bus.json
  • delivery-obligations.json

These files represent the durable control state of the instance.

3. Append-only or operational evidence

  • audit.log.jsonl
  • service.stdout.log
  • service.stderr.log

These help with auditability and debugging, but the instance should not need them to compute its current truth.

4. Derived or transient artifacts

  • workspace/
  • inbox/
  • backup archives
  • usage.last-good.json (validated recovery snapshot for usage.json)
  • migration leftovers
  • instance.lock.json
  • restart-loop.json (unclean-boot window for the restart-loop breaker; cleared on clean shutdown)
  • .bus-registry.json

These files are important, but they are not all the same. Some are transient coordination files, others are user data or deliverables.

Shared Storage Rules

These rules apply across most state files.

JSON storage primitive

src/state/json-store.ts is the shared primitive for most structured state.

It provides:

  • ENOENT -> default reads
  • atomic temp-file + rename writes
  • owner-only permissions on write (0700 dirs, 0600 files)
  • schema-version stamping
  • downgrade protection when loading newer state
  • quarantine support for unreadable/corrupt files

Implication:

  • if a new state file is structured JSON, it should usually be built on JsonStore
  • if a file is not using JsonStore, the code should explain why

Concurrency rule

Atomic rename prevents partial writes, but it does not prevent lost updates in read-modify-write flows.

Stores that mutate counters or collections must serialize each read-modify-write transaction and every destructive recovery with the same file-scoped mutex across processes. A read that can quarantine/reset state must also hold that mutex; otherwise it can rename a newer writer's valid file as corrupt.

Current examples:

  • SessionStore
  • RuntimeStateStore
  • UsageStore
  • FileWorkflowStore
  • CronStore

Some stores also keep an in-process promise queue to preserve call order, but that queue is not a substitute for the cross-process file mutex.

Security rule

Anything under the instance state directory should be treated as private unless there is a strong reason otherwise.

That includes:

  • bot token
  • pairing/access policy
  • session mappings
  • usage/cost history
  • workflow records
  • scheduled task prompts and history
  • audit events

Per-File Model

.env

Path

<stateDir>/.env

Owner

  • read path: src/service.ts
  • CLI config commands also write and maintain it

Purpose

Stores the Telegram bot token for the instance when it is not provided through the ambient process environment.

The key field is:

  • TELEGRAM_BOT_TOKEN

Authoritative data

The token is authoritative if the service was started without TELEGRAM_BOT_TOKEN already set in the process environment.

Write rules

  • should remain owner-readable only
  • should be updated without clobbering unrelated env lines
  • should not be regenerated from runtime state

Recovery rules

  • if missing, the instance can still start if TELEGRAM_BOT_TOKEN exists in the process environment
  • if missing in both places, startup must fail

Sensitivity

Highest sensitivity.

Compromise of this file is effectively bot compromise.

config.json

Path

<stateDir>/config.json

Owner

This file has multiple readers and writers.

Primary readers:

Primary writers:

Purpose

Stores persistent instance configuration and a small amount of durable control state.

Important fields currently include:

  • engine
  • approvalMode
  • locale
  • verbosity
  • budgetUsd
  • effort
  • model
  • resume (legacy migration input only; new bindings are stored per conversation in session.json)
  • bus

Authoritative data

This file is authoritative for instance configuration.

An old instance may still contain resume. Runtime code migrates that value onto the matching session.json record only when the owning session can be identified. New /resume and /detach writes never use the instance-global field.

Write rules

  • must be written atomically
  • the state directory and config.json must remain owner-only (0700 and 0600) even when replacing a pre-existing file with broader permissions
  • readers tolerate missing file by falling back to defaults
  • runtime should not silently overwrite unreadable/corrupt config
  • a web-console engine change clears incompatible provider-session bindings and commits the config update under one session transaction; if the config write fails, the original session bindings are restored before the mutex is released

Current behavior is split:

  • CLI reads treat parse failure as {} and continue
  • delivery/runtime reads log malformed config and run on defaults
  • runtime writes refuse to overwrite unreadable non-ENOENT config

This asymmetry is worth remembering.

Recovery rules

  • missing file means "fresh instance defaults"
  • malformed file currently causes runtime fallback with loud logging, not automatic repair

Sensitivity

Moderate sensitivity.

Usually not credential-bearing, but it can reveal instance topology, bus peers, legacy resume state, model selection, and operator intent.

access.json

Path

<stateDir>/access.json

Owner

src/state/access-store.ts

Purpose

Stores Telegram access policy and pairing state.

Schema:

  • policy: "pairing" | "allowlist"
  • pairedUsers[]
  • allowlist[]
  • pendingPairs[]

Authoritative data

This file is authoritative for:

  • who is allowed to talk to the bot
  • whether pairing or allowlist mode is active
  • outstanding pairing codes

Write rules

Current writes are read-modify-write operations serialized in-process and across processes. Status reads that can trigger corruption recovery use the same file mutex as mutations.

Recovery rules

  • missing file -> default state:
    • policy = pairing
    • empty allowlist/pairs/pending codes
  • corrupt JSON or invalid shape is quarantined and reset to the fail-closed default (pairing, no authorized chats) on a repair-capable operation
  • transient I/O and permission errors are rethrown rather than mistaken for corruption

Sensitivity

High sensitivity.

Leaking this file exposes pairing codes, authorized chats, and chat/user linkage.

session.json

Path

<stateDir>/session.json

Owner

src/state/session-store.ts

Purpose

Maps Telegram and Lark conversations to provider session identifiers and conversation-scoped resumed workspaces.

Schema:

  • chats[]
    • conversationKey (canonical private-chat/group/topic identity)
    • telegramChatId (numeric compatibility key; Lark uses a stable derived value)
    • telegramThreadId (Telegram topic, when present)
    • codexSessionId
    • resume (provider session metadata plus resumed workspace root)
    • suspendedPrevious (binding restored by /detach when available)
    • status
    • updatedAt

Authoritative data

This file is authoritative for durable conversation -> engine session and resumed-workspace binding.

It lets Telegram private chats/topics and Lark private chats/groups/topics continue independently across process restarts. A /resume in one conversation cannot change the file-delivery root or provider session of another conversation.

Write rules

  • reads and writes are serialized with a cross-process file mutex; writes also retain in-process ordering
  • updates are upsert-style by canonical conversationKey, with legacy chat/thread keys normalized on read/write
  • removal supports recovery behavior on corrupt state
  • clearAllThen() holds the session mutex across session clearing plus its durable companion update, and restores the original bindings if that update fails

Recovery rules

This store has the best repair story in the project today.

It can:

  • inspect unreadable state without throwing to the outer system
  • distinguish repairable vs non-repairable failures
  • quarantine corrupt files to *.corrupt.*.bak
  • reset to an empty default state when safe to do so

Sensitivity

Moderate to high sensitivity.

It exposes chat IDs and engine session identifiers, which are operationally sensitive even if not credential-equivalent.

runtime-state.json

Path

<stateDir>/runtime-state.json

Owner

src/state/runtime-state.ts

Purpose

Stores polling progress.

Current schema:

  • lastHandledUpdateId

Authoritative data

This file is authoritative for "how far Telegram polling has durably advanced".

Write rules

  • reads and writes are serialized with a cross-process file mutex; writes also retain in-process ordering
  • updates are monotonic: lower update IDs do not replace higher ones

Recovery rules

  • missing file -> lastHandledUpdateId = null
  • invalid file throws

This file matters because if its semantics drift from update acknowledgment semantics, the system can either replay or lose updates.

Sensitivity

Low sensitivity, but high correctness importance.

usage.json

Path

<stateDir>/usage.json

Owner

src/state/usage-store.ts

Purpose

Stores cumulative token and cost accounting for the instance.

Schema:

  • totalInputTokens
  • totalOutputTokens
  • totalCachedTokens
  • totalCostUsd
  • requestCount
  • lastUpdatedAt

Authoritative data

This file is authoritative for user-visible cumulative usage and budget comparisons.

Write rules

  • read-modify-write
  • candidate records are schema-validated before persistence
  • writes are serialized both in-process and across processes
  • a successful write updates usage.json, then usage.last-good.json

Important nuance:

usage.last-good.json is recovery state, not a second independently mutable ledger. Callers must always read and mutate through UsageStore.

Recovery rules

  • missing file -> zeroed counters
  • invalid primary + valid usage.last-good.json -> quarantine the primary, restore the validated snapshot, and continue
  • invalid primary + missing/invalid backup -> throw UsageStateCorruptError and leave the corrupt primary in place (fail closed; never reset budget usage to zero)

Sensitivity

Moderate sensitivity.

It reveals usage volume, cost, and activity timing.

cron-jobs.json

Path

<stateDir>/cron-jobs.json

Owner

src/state/cron-store.ts

Purpose

Stores persistent Telegram scheduled tasks.

Schema:

  • jobs[]
    • id
    • chatId
    • userId
    • chatType
    • cronExpr
    • prompt
    • description?
    • enabled
    • runOnce
    • targetAt?
    • sessionMode (new_per_run by default for new jobs; reuse only for explicit continuation jobs; older persisted jobs keep their stored value until updated)
    • mute
    • silent
    • timeoutMins
    • maxFailures
    • createdAt
    • updatedAt
    • lastRunAt?
    • lastSuccessAt?
    • lastError?
    • failureCount
    • runHistory[]

Authoritative data

This file is authoritative for which scheduled jobs exist and whether they are enabled. runOnce jobs are disabled after their first execution attempt. Recurring jobs track consecutive failureCount, keep the latest 10 runHistory entries, and are disabled when failureCount >= maxFailures. Use /cron mode <job-id> new_per_run to update older recurring jobs that were persisted with sessionMode: "reuse" before isolated cron runs became the default.

Write rules

  • built on JsonStore
  • writes are serialized per CronStore instance
  • scheduler and /cron commands should share the active runtime store where possible

Recovery rules

  • missing file -> no scheduled tasks
  • invalid file throws and prevents the cron runtime from starting
  • operator repair should quarantine/reset this file rather than silently dropping jobs

Sensitivity

High sensitivity.

It can contain durable prompts, chat IDs, user IDs, schedule intent, and last error details.

board.json

Path

<stateDir>/board.json

Owner

src/state/board-store.ts

Purpose

Stores durable Kanban task state for /board commands. It is intentionally separate from Mini Bus and Agent Bus topology: the board tracks work, while bus layers decide who can execute work.

Schema:

  • nextTaskId
  • nextRunId
  • tasks[]
    • id
    • title
    • status: todo, ready, running, review, blocked, done, or archived
    • description?
    • acceptanceCriteria[]
    • priority: low, normal, high, or urgent
    • labels[]
    • checklist[]
      • id
      • text
      • done
      • createdAt
      • completedAt?
    • artifacts[]
      • kind
      • value
      • createdAt?
    • review
      • required
      • reviewer?
    • assignee?
    • dependencies[]
    • workspace?
      • mode: default, dir, worktree, or scratch
      • path?
      • branch?
    • blockedReason?
    • summary?
    • createdAt
    • updatedAt
    • completedAt?
    • createdBy
      • chatId
      • userId
      • messageThreadId?
      • conversationKey
    • runs[]
      • id
      • status
      • startedAt
      • lastHeartbeatAt?
      • heartbeatNote?
      • completedAt?
      • summary?
      • error?

Authoritative data

This file is authoritative for Board task ids, task status, dependencies, assignees, blocked reasons, completion summaries, and lightweight run history.

It is also authoritative for card metadata used by planner/dispatcher flows: description, acceptance criteria, priority, labels, checklist, artifacts, review requirement, optional workspace metadata, run heartbeat evidence, and WIP limits.

It is not authoritative for access control, Mini Bus peers, or Agent Bus peer configuration.

Write rules

  • built on JsonStore
  • writes are serialized with a file mutex so concurrent command handlers and processes do not lose tasks
  • task ids are normalized as B<number>
  • dependency completion promotes waiting todo tasks to ready when all dependencies are done
  • WIP limits are enforced before a task can start a new run
  • default WIP limits are global=3, perAssignee=1, and perConversation=1
  • /board plan <goal> creates a task graph from the current engine's JSON output and stores the resulting dependencies atomically
  • /board heartbeat <id> updates the active run's lastHeartbeatAt and optional heartbeatNote
  • /board recover [minutes] closes stale running attempts as failed and blocks those tasks for operator review
  • /board worktree <id> [path] [branch] stores optional per-task workspace metadata; task metadata by itself does not grant access or change bus topology
  • starting a task is rejected while dependencies are incomplete
  • dependency cycles are rejected when adding a dependency
  • each start creates one run attempt; duplicate concurrent running attempts are rejected
  • /board run <id> starts one ready task, sends the task card to its assignee, then closes the run as done or failed
  • /board run <id> resolves assignees by preferring Mini Bus peers in the current group, then falling back to Agent Bus instance names
  • fail closes the active run as failed and moves the task to blocked
  • tasks with review.required move to review after completion; dependents are promoted only after approval
  • completed tasks retain their original source chat/topic metadata for auditability

Recovery rules

  • missing file -> empty board
  • invalid file throws and prevents /board command handling from using stale or partial task state
  • old/missing counters are normalized from the maximum stored task/run ids

Sensitivity

High sensitivity.

It can contain durable task titles, operator intent, summaries, chat IDs, user IDs, topic IDs, and workflow topology hints.

mini-bus.json

Path

<stateDir>/mini-bus.json

Owner

src/state/mini-bus-store.ts

Purpose

Stores Telegram group-local Mini Bus configuration. A Mini Bus lets one bot treat different topics in the same allowed group as named peers.

Schema:

  • groups
    • <chatId>
      • peers[]
        • name
        • chatId
        • messageThreadId?
        • conversationKey
        • createdAt
        • updatedAt
      • parallel[]
      • chain[]
      • verifier?
      • roles
        • researcher?
        • analyst?
        • writer?
        • reviewer?
      • crew
        • maxResearchQuestions
        • maxRevisionRounds

Authoritative data

This file is authoritative for Mini Bus peer names, default fan/chain order, verifier selection, and Mini crew role mapping inside each Telegram group.

It is not authoritative for Telegram access. Group access still comes from access.json and config.json group mode settings.

Write rules

  • built on JsonStore
  • writes are serialized with a file mutex so concurrent topic registrations do not clobber each other
  • peer names and role names are normalized before persistence
  • removing a peer also removes references from parallel, chain, verifier, and roles

Recovery rules

  • missing file -> no Mini Bus peers configured
  • invalid file throws and prevents Mini Bus command handling from using stale or partial state
  • old records without roles or crew are normalized with default empty roles and default crew limits

Sensitivity

Moderate sensitivity.

It reveals group chat IDs, topic IDs, peer topology, and operator workflow intent. It does not contain bot tokens or engine credentials.

file-workflow.json

Path

<stateDir>/file-workflow.json

Owner

src/state/file-workflow-store.ts

Purpose

Tracks attachment and archive processing workflows that span multiple Telegram messages.

Schema:

  • records[]
    • uploadId
    • chatId
    • userId
    • kind
    • status
    • sourceFiles
    • derivedFiles
    • summary
    • summaryMessageId?
    • extractedPath?
    • createdAt
    • updatedAt

Authoritative data

This file is authoritative for in-progress and resumable file-processing state, especially archive workflows that wait for a follow-up /continue.

Write rules

  • writes and corruption recovery are serialized with a cross-process file mutex; writes also retain in-process ordering
  • ordinary snapshot reads rely on atomic replacement and do not mutate or quarantine state
  • records are append/update/remove by uploadId
  • status is mutated over time; updatedAt is refreshed on mutation

Recovery rules

Like session.json, this store supports:

  • inspect-with-warning
  • corruption detection
  • quarantine to backup
  • reset-based repair

This is important because users can still receive successful Telegram output even if bookkeeping later fails.

Sensitivity

Moderate sensitivity.

It contains local file paths, chat IDs, and summaries of processed content.

audit.log.jsonl

Path

<stateDir>/audit.log.jsonl

Owner

src/state/audit-log.ts

Purpose

Append-only operational and forensic event log.

Each line is an AuditEvent with fields such as:

  • timestamp
  • type
  • instanceName
  • chatId
  • userId
  • updateId
  • outcome
  • detail
  • metadata

Authoritative data

This file is not authoritative for current runtime truth.

It is authoritative only as a historical record of what the system attempted and reported.

Write rules

  • append-only JSONL
  • best effort in some call sites
  • no compaction semantics

Callers should never rely on this file for reconstructing canonical current state.

Recovery rules

  • malformed lines are ignored by parsers
  • summaries are best-effort over whatever lines remain parseable

Sensitivity

High sensitivity.

It may contain prompts, error details, chat IDs, workflow metadata, and operational clues.

instance.lock.json

Path

<stateDir>/instance.lock.json

Owner

src/state/instance-lock.ts

Purpose

Ensures only one service process owns an instance state directory at a time.

Schema:

  • pid
  • token
  • acquiredAt

Authoritative data

This file is authoritative only for process exclusivity at startup/runtime, not for user-visible behavior.

Write rules

  • created with exclusive write (wx)
  • stale file is removed only after verifying the recorded process is dead
  • release checks both pid and random token

Recovery rules

  • missing file is normal
  • stale file is automatically pruned
  • live holder means startup must fail

Sensitivity

Low confidentiality sensitivity, high coordination importance.

service.stdout.log and service.stderr.log

Path

  • <stateDir>/service.stdout.log
  • <stateDir>/service.stderr.log

Owner

Service management commands under src/commands/service.ts

Purpose

Operational logs for managed background service processes.

Authoritative data

Not authoritative for runtime behavior.

Useful for diagnosis only.

Write rules

Recovery rules

Safe to truncate or rotate.

Sensitivity

Moderate sensitivity because logs may include prompts, errors, config paths, and stack traces.

workspace/

Path

<stateDir>/workspace/

Owner

Created by service/adapters, then effectively co-owned by the engine and the user.

Purpose

The instance working directory.

This is where:

  • engine tasks operate
  • CLAUDE.md may live
  • generated files may be created before Telegram delivery
  • resumed-session workspace alignment matters

Authoritative data

Not canonical bridge control state, but authoritative as the working tree the engine sees.

Write rules

  • contents are not schema-managed
  • should be treated as user/engine data, not config

Recovery rules

Backed up and restored as part of instance archives.

Sensitivity

Potentially very high, depending on project contents.

inbox/

Path

<stateDir>/inbox/

Owner

Telegram delivery and workflow code.

Purpose

Stores downloaded Telegram attachments and quoted files for local processing.

Authoritative data

Not authoritative long-term control state, but important transient input material for workflows.

Write rules

  • created on demand
  • contains downloaded user data

Recovery rules

Safe to treat as ephemeral operational data, but note that in-progress workflows may still reference files under it.

Sensitivity

High sensitivity because it contains raw user attachments.

Backup archives (*.cctb.gz)

Path

User-chosen output path, not a fixed in-place state file.

Owner

src/state/archive.ts

Purpose

Portable backup/restore format for an instance state directory.

Authoritative data

A backup is authoritative only as a snapshot artifact, not as live state.

Write rules

  • skips symlinks
  • skips oversized files
  • skips regenerable dependency/VCS/scratch directories and operational logs by default
  • streams source file bodies through gzip rather than buffering the complete archive
  • rejects manifests above 10,000 files and archives above the 128 MiB expanded-format limit
  • writes a gzipped custom archive format through a private temporary file before atomic replacement

Recovery rules

  • restore validates archive magic and version
  • restore prevents path traversal
  • restore rejects compressed inputs above 64 MiB, expanded archives above 128 MiB, manifests above 10,000 files, and individual members above 100 MiB
  • restore expands and copies members through bounded streams instead of loading the complete archive or every member into memory
  • restore reapplies restrictive permissions

Sensitivity

Highest sensitivity.

A backup may contain nearly the entire private state of an instance.

.bus-registry.json

Path

<channelRoot>/.bus-registry.json

Where channelRoot = dirname(stateDir), usually ~/.cctb/.

Owner

src/bus/bus-registry.ts

Purpose

Shared control-plane registry of locally running instances participating in the bus.

Schema:

  • instances[instanceName]
    • port
    • pid
    • secret
    • updatedAt

Authoritative data

This file is authoritative for local instance discovery on the bus.

It is not part of a single instance's isolated state; it is shared across sibling instances.

Write rules

  • currently plain read-modify-write, not JsonStore
  • should be treated as coordination state
  • liveness is verified via /api/health, not by trusting the file alone

Recovery rules

  • missing/corrupt registry -> empty registry
  • stale entries are pruned by active probing

Sensitivity

High sensitivity for local control-plane security because it contains bus secrets and routing info.

Files That Are Not Canonical State

These files may exist under the state directory but should not be treated as authoritative business state:

  • runtime.log
  • rotated logs like audit.log.jsonl.1
  • engine-home.migrated-*
  • temporary *.tmp files
  • transient Telegram-out directories

They matter operationally, but no feature should depend on them as the sole source of truth.

Current Gaps

These are the most important state-model gaps in the current code.

1. config.json has multiple owners

That is manageable, but only if all writers keep using atomic write and we stay disciplined about which fields are runtime state vs operator config.

2. Not every JSON store has the same repair semantics

session.json and file-workflow.json are more mature here than access.json, usage.json, and runtime-state.json.

3. Some coordination files do not use JsonStore

That is not automatically wrong, but the difference should be intentional and documented.

4. Shared-state files and per-instance files are easy to conflate

.bus-registry.json is not just another instance file. It belongs to the local mesh, not one bot.

  1. Keep this file updated whenever a new persistent file is introduced.
  2. Normalize repair behavior across state stores where it materially helps operators.
  3. Remove the legacy config.json.resume compatibility path after all supported upgrade windows have migrated.
  4. Keep docs/security-boundaries.md aligned whenever a state file changes trust or sensitivity.

delivery-obligations.json

Path

<stateDir>/delivery-obligations.json

Owner

src/state/delivery-obligation-store.ts. Written by the Lark service process during ordinary-turn final delivery and by the boot-time sweep.

Purpose

Durable delivery-obligation ledger (Hermes-inspired): one row per outbound final engine response with checkpoints around the send (pendingattemptingdelivered/failed). A row reaches delivered only after every requested artifact and text chunk receives a definite success; a rejected or ambiguous artifact ACK keeps the row failed and the turn partial. On boot, sweepRecoverable claims undelivered rows whose owning process is dead and src/lark/delivery-recovery.ts redelivers them — plainly for pending (send never started), with a visible ♻️ recovered-reply marker for attempting/failed (the platform may already have the message; honest at-least-once, never a silent duplicate).

Write rules

  • Atomic tmp+rename writes serialized by a file mutex; every operation is best-effort and must never block or fail an actual send.
  • Attempts are capped (3) and rows older than 24h are abandoned — a poison reply cannot crash-loop redelivery, and a day-old reply never suddenly reappears.
  • Bounded: settled rows pruned after 7 days, 200-row cap, replies over 200KB are never recorded (Doc-overflow territory).
  • Kill-switch: CCTB_DELIVERY_LEDGER=off disables recording and sweeping.
  • Recovery parses persisted responses through the normal guarded artifact pipeline. It may replay send.file, send.image, send.audio, send.video, send.batch, and whole-response file: blocks, but it strips cron and all other side-effect tools rather than executing them again.
  • Artifact identity uses the real file (device/inode, with canonical-path fallback), so structured and legacy tags cannot resend one file through symlink, hard-link, or case aliases.
  • Image cards split only after an explicit platform size rejection. Timeout, disconnect, and other ambiguous acknowledgements stop without an immediate retry and surface a “request a resend” notice.

Recovery rules

Corrupt file → treated as empty and rewritten on the next record; never fatal.

restart-loop.json

Path

<stateDir>/restart-loop.json

Owner

src/runtime/restart-loop-guard.ts.

Purpose

Rolling window of UNCLEAN boot timestamps (boot recovered a stale service lock = previous run died without clean shutdown). Three unclean boots inside 10 minutes trips the breaker: that boot skips boot-recovery work (interrupted-turn marking, delivery-ledger redelivery) so a poison replay cannot keep killing a supervised service; live traffic is still served. Operator restarts shut down cleanly, release the lock, and are never counted; a clean shutdown also deletes this file.

Recovery rules

All failures fail OPEN (no trip). Delete the file to manually reset the window.