Report each tick's outcome and the updater's state to the master

The master saw a scheduler's last run time and nothing of what it did. Each
tick now records, per lane, its outcome, a line on what happened (what
fired, or the spread, contract or hold cap that stopped it) and why the
lane's accounts sat it out, counted by reason with a few names each. It
rides the scheduler status as lastTicks.

Each report also carries the auto-updater's state from the files it keeps
and from git: its last check, a failed update waiting to retry, how far the
checkout is behind origin, and tracked files edited by hand, which stop the
fast-forward pull.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Brandon Li
2026-09-27 18:31:21 -05:00
co-authored by Claude Opus 5.5
parent db0ad99a76
commit ab3132182a
7 changed files with 253 additions and 21 deletions
+48 -3
View File
@@ -191,9 +191,54 @@ export interface SchedulerState {
lastRun: string | null;
intervalSeconds: number;
stopAfterAll?: boolean;
/** Today's random session-open delay in minutes (1–20), drawn once per
* Central-time day. Optional so an older master simply ignores it. */
/** Today's random session-open delay in minutes (0–180, after 5:45 PM
* CT), drawn once per Central-time day. Optional so an older master
* simply ignores it. */
sessionOpenDelayMin?: number;
/** What the last tick did in each lane, and why accounts sat it out.
* Optional so an older master simply ignores it. */
lastTicks?: LaneTick[];
}
/** Accounts that sat a tick out for one reason (dollar amounts folded, so
* like reasons group), with a few of their names. */
export interface TickReason {
reason: string;
count: number;
accounts: string[];
}
/** What the scheduler's last tick did in one lane. */
export interface LaneTick {
/** "futures", or the every-day firm's name. */
lane: string;
/** ISO time of the tick. */
at: string;
/** fired, no-eligible, positions-open, closed, holding-for-sync,
* skipped-in-flight, or "error: …". */
outcome: string;
/** One line on what happened: what fired, or what stopped it. */
detail: string;
/** Why the lane's accounts weren't in the batch, most common first. */
reasons?: TickReason[];
}
/** The auto-updater on this machine (scripts/update-check.mjs), read from
* the files it keeps and from git. */
export interface UpdaterStatus {
/** Its last check (it runs every minute under PM2); null = never ran here. */
lastCheckAt: string | null;
/** What that check found, e.g. "up to date at 1a2b3c4d" or "ERROR: …". */
lastCheck: string | null;
/** An update that failed and waits to retry: at which step, how often. */
failed: { target: string; step: string; at: string; attempts: number } | null;
/** The commit the running build was made from. */
builtCommit: string | null;
/** Commits on origin this checkout doesn't have, as of the updater's
* last fetch; null when git can't say. */
behind: number | null;
/** Tracked files edited on this machine — they can block the pull. */
localChanges: string[];
}
/** The build this instance is running — its checkout's HEAD commit. The
@@ -381,5 +426,5 @@ export type MasterMessage =
export type InstanceMessage =
| { type: 'hello'; instance: string; id?: string; capabilities: InstanceCapabilities; version?: BuildVersion }
| { type: 'report'; firms: FirmStats[]; scheduler: SchedulerState; capabilities?: InstanceCapabilities; version?: BuildVersion }
| { type: 'report'; firms: FirmStats[]; scheduler: SchedulerState; capabilities?: InstanceCapabilities; version?: BuildVersion; updater?: UpdaterStatus }
| { type: 'ack'; id: string; ok: boolean; result?: unknown; error?: string };