Technical Architecture: Operational Automation¶
| Metadata | Specification |
|---|---|
| Document ID | TP-OPER-001 |
| Component | Supervisor, Cranker & Relayer Strategy |
| Last updated | March 2026 |
To ensure a continuous and reliable protocol, TIMLG uses an automated round management system. The current production implementation is the protocol-supervisor-sdk (Node.js), which handles the full lifecycle: round creation, pulse publication, finalization, settlement, sweep, and cleanup.
RoundRegistry¶
The RoundRegistry is a singleton PDA that maintains the global state of the automated pipeline.
- Purpose: Tracks the next available numeric
round_id. - Instruction:
initialize_round_registry(start_round_id)(Admin-only). - Invariant: Ensures that
round_idvalues are strictly sequential and never reused.
Automated Creation Flow¶
The protocol supports a specialized instruction for high-throughput operator pipelines:
create_round_auto¶
This instruction creates a new round without requiring the operator to provide a manual round_id.
- ID Allocation: Reads
next_round_idfrom theRoundRegistry. - State Initialization: Creates the
RoundPDA and its associated token vaults. - Registry Update: Increments
RoundRegistry.next_round_id. - Timing Configuration: Sets the
commit_deadline_slotandreveal_deadline_slotbased on the targeted NIST pulse.
Permissionless Settlement & Auto-Finalization¶
To maximize decentralization and liveness, the settlement process has been hardened:
- Permissionless: Any user can trigger
settle_round_tokensonce the reveal window has passed. - Auto-Finalization: If the round has not been manually finalized, the settlement instruction will automatically transition the round to the
Finalizedstate if the pulse has been set on-chain. - Incremental Processing:
settle_round_tokenssupports processing batches of tickets, making it gas-efficient for high-volume rounds.
Protocol Supervisor SDK¶
The current off-chain infrastructure is implemented in protocol-supervisor-sdk/index.mjs. It runs as a continuous loop and manages the full round lifecycle.
Architecture¶
The supervisor is organized into distinct functional modules executed each tick:
| Module | Responsibility |
|---|---|
| boot | Reads on-chain config (commit/reveal window sizes) and chain state at the start of each tick |
| audit | Scans the on-chain RoundRegistry for all active rounds and their current states |
| scheduler | Determines the next round to create based on the NIST pulse pipeline; calls create_round_auto |
| ORACLE-GAP | Advances latest_finalized_pulse_index if the pipeline is blocked by empty or skipped rounds |
| pulses | Fetches NIST Beacon Chain 2 and publishes set_pulse_signed for rounds that are ready |
| maintenance/finalize | Calls finalize_round for rounds that have passed their reveal deadline and have a pulse |
| settlement | Calls settle_round_tokens for finalized rounds with tickets |
| maintenance/sweep | Calls sweep_unclaimed for rounds past the claim grace period |
| cleanup/close | Calls close_round for swept rounds to recover rent |
Tick cycle¶
Each tick takes approximately 10–15 seconds and covers all modules in sequence. State read at boot is shared across modules within the same tick. This means the supervisor effectively targets a ~6 rounds-per-minute throughput ceiling at peak scheduling.
Scheduler logic¶
The scheduler picks the next pulseIndexTarget from the pool of unregistered pulse indices. A round will be skipped (not created) if:
- The target pulse is already registered in the pipeline
- The current NIST betting window for that pulse is below the minimum required duration
- The target would be beyond the
MAX_FUTURE_PULSE_WINDOW(protects against creating rounds too far ahead of the current chain state)
Round creation and slots
Round commit and reveal deadlines are derived from the current chain slot at creation time, not from the current wall-clock time. NIST pulses arrive approximately every 60 seconds but slot timing may drift. The scheduler uses the current slot as the reference point when computing window offsets.
The ORACLE-GAP mechanism¶
syncLatestPulse is an admin-gated instruction that advances the on-chain latest_finalized_pulse_index (LFP). The supervisor uses it when it detects the LFP has fallen behind the earliest pending round's pulse target.
When it triggers¶
current LFP < (earliest active round's pulseIndexTarget - 1)
What it does¶
- Reads all active rounds from the pipeline
- Computes the minimum LFP needed to allow the earliest blocked round to become eligible for pulse publication
- Calls
syncLatestPulse(target)with that minimum value
Constraints¶
- The program enforces
SyncPulseWouldDecrease: the LFP can only advance, never retreat - Each
syncLatestPulsecall is an on-chain transaction, fully auditable - The sequential constraint on
set_pulse_signed(NonSequentialPulse) limits how many rounds a misaligned LFP can affect
Trust implication¶
The ORACLE-GAP mechanism is a liveness tool with an admin trust dependency. It resolves deadlocks that arise when empty rounds consume pulse index slots. However, because the LFP is app-level state and is advanced by the operator rather than by independent on-chain consensus, this remains a centralized operation bounded by on-chain constraints.
See Oracle Trust Model for the full trust characterization.
User-driven cleanup (ticket rent)¶
Automation manages round creation, pulse posting, finalize/settle, and sweeps. Ticket rent recovery is intentionally user-driven:
close_ticketis signed by the ticket owner and returns the ticket PDA's lamports to the user.- Sweeps do not close user tickets.
This design reduces centralized maintenance and keeps user cleanup permissioned to the owner.
Grace windows
The canonical sweep eligibility is enforced by the program using claim_grace_slots from on-chain Config.
The supervisor may use a shorter local precheck before attempting sweeps, but early attempts will be rejected on-chain.
Empty round handling¶
Rounds created without any ticket commits are detected by the supervisor during the pulse module. For rounds with zero tickets:
- The pulse step is skipped (no
set_pulse_signedsent) - The sweep step runs immediately after the reveal deadline passes
- The close step reclaims rent after sweep
This reduces unnecessary RPC calls and keeps the pipeline clean without modifying the on-chain program.