@helipod/fleet 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lease.ts","../src/lease-monitor.ts","../src/fenced-error.ts","../src/commit-notifier.ts","../src/forwarder.ts","../src/balancer.ts","../src/rendezvous.ts","../src/node.ts","../src/switchable-store.ts","../src/replica-tailer.ts","../src/stable-prefix.ts","../src/ranges.ts","../src/reshard.ts","../src/index.ts"],"sourcesContent":["/* Helipod Enterprise. Licensed under the Helipod Commercial License — see ee/LICENSE. */\nimport type { PgClient, PgRow, PgValue } from \"@helipod/docstore-postgres\";\nimport { DEFAULT_SHARD, type ShardId } from \"@helipod/id-codec\";\nimport type { JSONValue } from \"@helipod/values\";\n\n/** The default shard every single-shard caller (B1 tests, the writer-election loop) targets when\n * no explicit `shardId` is passed. B2a generalizes the per-row methods below to any shard id —\n * the `shardId` params all DEFAULT to this, so a B1 call site (`tryAcquire()`, `heartbeat(epoch)`,\n * `seedFrontier(epoch, maxTs)`, …) is byte-identical to before. */\nconst SHARD_ID: ShardId = DEFAULT_SHARD;\n\n/** Default TTL a fresh acquisition/heartbeat extends `expires_at` by, in ms. The LeaseMonitor's\n * probe cadence is derived proportionally (ttl/3 → the historical 5s at this default), leaving\n * headroom for several missed round-trips before a fencer considers this node wedged (D4). A\n * deployment can shorten it via `HELIPOD_FLEET_LEASE_TTL_MS` (ops/test tuning) — see\n * `prepareFleetNode` in `node.ts` for the threading. */\nconst DEFAULT_LEASE_TTL_MS = 15_000;\n\n/**\n * Non-blocking per-shard commit-mutex seam (see `Transactor.tryRunExclusiveOnShard` /\n * `EmbeddedRuntime.tryRunExclusiveOnShard`): run `fn` under shard `shardId`'s commit mutex if that\n * shard is IDLE right now (returns `true`), else skip without running it (returns `false`). \"Idle\"\n * means BOTH the commit mutex is free AND no group-commit batch is staged/flushing — Fleet B4's group\n * commit runs the flush I/O OFF the mutex, so mutex-freedom alone no longer implies \"nothing in\n * flight\". `closeIdleFrontiers` takes this so each idle shard's frontier bump is mutually exclusive\n * with that shard's own commits AND with any mid-flush batch — the fix for the frontier-inversion race\n * (an idle-closer publishing a frontier ahead of an in-flight commit's or batch's not-yet-landed\n * rows). The writer owns both the closer and every shard's commits, so this single-process check is\n * airtight; cross-node closing of a held shard is impossible by design (only the lease holder closes\n * its own held shards).\n */\nexport type TryRunExclusiveOnShard = (shardId: ShardId, fn: () => Promise<void>) => Promise<boolean>;\n\n/** The current fleet writer lease: which epoch is live and which node holds it. */\nexport interface LeaseState {\n epoch: bigint;\n writerUrl: string;\n /** The row's fenced-frontier high-water mark at acquisition time (Fleet B3). On an `ON CONFLICT`\n * re-acquire the upsert leaves `frontier_ts` untouched, so this returns the value an INTERIM owner\n * advanced it to while this node didn't hold the shard — the exact floor the caller feeds to\n * `runtime.observeWriteTimestamp` so a re-acquired shard's write snapshot never sits stale. */\n frontierTs: bigint;\n}\n\n/** `LeaseManager.read()`'s full row — every `shard_leases` column (Fenced Frontier B1, D2). The\n * extra columns beyond `LeaseState` are consumed by the D4 eviction/D5 tailer-frontier work; this\n * class only writes them (frontier_ts/prev_ts advance via the commit-guard SQL installed in\n * `node.ts`, never through this class directly), so they're returned loosely typed for now. */\nexport interface LeaseRow extends LeaseState {\n writerAppName: string | null;\n /** Raw Postgres value for the TIMESTAMPTZ column (a `Date` under `NodePgClient`, ISO-ish string\n * under PGlite) — not a `LeaseManager` client's job to interpret; a heartbeat/fence caller only\n * cares about row-count effects, not the wall-clock value. */\n expiresAt: unknown;\n frontierTs: bigint;\n prevTs: bigint;\n}\n\nexport interface LeaseManagerOptions {\n /** URL this node advertises as the writer, recorded into shard_leases on acquire. */\n advertiseUrl: string;\n /** This node's Postgres `application_name` (see `fleetApplicationName`), recorded on acquire so\n * a D4 eviction fencer can `pg_terminate_backend` the exact wedged holder's connection. */\n applicationName?: string;\n /** Interval between tryAcquire() attempts inside acquireLoop(). Default 2000ms. */\n retryMs?: number;\n /** How long a fresh acquisition/heartbeat extends `expires_at` by, in ms. Default 15000ms. The\n * whole failover clock scales with this: a wedged writer's lease expires this long after its last\n * heartbeat, so a follower's eviction can't fire before then. Shortened by\n * `HELIPOD_FLEET_LEASE_TTL_MS` for the wedged-writer E2E (and available to operators as tuning);\n * the LeaseMonitor's probe cadence is derived from it so a live writer always renews in time. */\n ttlMs?: number;\n}\n\nconst DEFAULT_RETRY_MS = 2000;\n\n/** Effectively-once forwarding (Fleet B3, D3): the `fleet_idempotency.value_json` cap. A recorded\n * mutation result larger than this is NOT stored — the row keeps `value_json = NULL` and\n * `oversized = true` instead, so a replay reports `valueMissing: true` rather than growing this\n * control table unboundedly on a large mutation return value. The WRITE itself is unaffected\n * either way (this cap only governs the best-effort RESULT-VALUE cache, not the commit). */\nexport const IDEMPOTENCY_VALUE_CAP_BYTES = 64 * 1024;\n\n/** How long a `fleet_idempotency` row survives before the sweep reclaims it (Fleet B3, D3) — a\n * retry arriving after this window re-executes rather than replaying (documented boundary;\n * retries are seconds-scale in practice, so 1h is generous headroom). */\nconst IDEMPOTENCY_TTL_INTERVAL = \"1 hour\";\n\n/** A `fleet_idempotency` row read back for replay (Fleet B3, D3). `hasValue` distinguishes a\n * genuinely-recorded value (including a mutation that legitimately returned JSON `null`, which is\n * still stored as the TEXT `\"null\"`) from `value_json` being SQL NULL — the crash-window\n * (commit landed, the post-run value UPDATE never ran) and the oversized-cap cases both leave\n * `value_json` SQL NULL, and both replay as `valueMissing: true` uniformly. */\nexport interface IdempotencyReplay {\n commitTs: bigint;\n hasValue: boolean;\n value: JSONValue | null;\n oversized: boolean;\n}\n\nfunction toBigIntOrZero(v: PgValue | undefined): bigint {\n if (v === null || v === undefined) return 0n;\n return typeof v === \"bigint\" ? v : BigInt(v as number | string);\n}\n\n/**\n * True if `e` is a Postgres lock-acquisition timeout (`lock_timeout` fired). `evictExpired`'s\n * `SELECT ... FOR UPDATE` runs under `SET LOCAL lock_timeout='2s'`, so if a wedged writer is mid-\n * commit and still holds the row lock, the fencer waits at most 2s and then this fires — treated as\n * \"couldn't fence this tick, retry next tick\" rather than an error surfaced to the acquire loop.\n * SQLSTATE `55P03` is `lock_not_available`; the message match is a belt-and-braces fallback.\n */\nfunction isLockTimeoutError(e: unknown): boolean {\n if (e && typeof e === \"object\") {\n if ((e as { code?: unknown }).code === \"55P03\") return true;\n const msg = (e as { message?: unknown }).message;\n if (typeof msg === \"string\" && /lock[_ ]?timeout|lock_not_available/i.test(msg)) return true;\n }\n return false;\n}\n\nfunction rowToLeaseRow(row: PgRow): LeaseRow {\n return {\n epoch: row.epoch as bigint,\n writerUrl: row.writer_url as string,\n writerAppName: (row.writer_app_name as string | null | undefined) ?? null,\n expiresAt: row.expires_at,\n frontierTs: toBigIntOrZero(row.frontier_ts),\n prevTs: toBigIntOrZero(row.prev_ts),\n };\n}\n\n/**\n * Coordinates the single-writer lease across a fleet of nodes sharing one Postgres database.\n * The advisory lock (PgClient.tryAcquireWriterLock) is the FAST-PATH mutual-exclusion primitive;\n * `shard_leases` is the fencing token + discovery row + frontier chain — one row per shard (B1:\n * only `'default'`) so any node (including read replicas forwarding writes) can find the current\n * writer's URL/epoch, and so `PostgresDocStore`'s installed commit guard can verify — inside every\n * commit transaction — that the writer holding the advisory lock is STILL the epoch on file (see\n * `node.ts`'s `installCommitGuard`). `epoch` bumps on every acquisition (D2); `frontier_ts`/\n * `prev_ts` are the durable-commit chain the guard advances (D3) — this class never writes them\n * itself beyond seeding them to 0 on first creation.\n *\n * Liveness: the LeaseMonitor's periodic probe IS `heartbeat()` (see `node.ts`) — one round-trip\n * serves liveness-probe + TTL maintenance + fence verification, per D2. `heartbeat()` returning 0\n * rows means this node's epoch has been superseded (fenced) even though its connection is still\n * alive — a DEFINITIVE loss, distinct from the probe-miss tolerance used for transient blips.\n */\nexport class LeaseManager {\n private readonly client: PgClient;\n /** This node's advertised URL, recorded onto `shard_leases`/`fleet_nodes`. Public so the balancer\n * can use it as this node's rendezvous identity (`ShardLeaseBalancer.myUrl`) without threading it\n * separately through `startFleetNode`. */\n readonly advertiseUrl: string;\n private readonly applicationName: string | null;\n private readonly retryMs: number;\n /** The lease TTL in ms this manager stamps onto `expires_at`. Public so the LeaseMonitor can\n * derive its probe cadence from the SAME knob (see `startFleetNode`) — a live writer must renew\n * well within the TTL. */\n readonly ttlMs: number;\n /** `ttlMs` as a whole-ms integer, ready to interpolate into the `interval '<n> milliseconds'` SQL\n * below. Integer-coerced (never a fraction/NaN) so the interpolation can't produce invalid SQL. */\n private readonly ttlMsSql: number;\n private timer: ReturnType<typeof setTimeout> | null = null;\n private stopped = false;\n /** Per-shard epoch map: `shardId → the epoch this node most recently acquired for it`. B1 tracked\n * ONE `lastEpoch` (default shard only); B2a's writer holds N shards, each fenced against its own\n * epoch, so the commit guard/heartbeat/idle-closer look up `currentEpoch(shardId)`. Updated on\n * every successful per-shard `tryAcquire(shardId)` (including re-promotion's epoch bumps) so the\n * guard always fences against the CURRENT epoch, not a boot snapshot. A shard absent from the\n * map is one this node has never acquired. */\n private readonly lastEpochByShard = new Map<ShardId, bigint>();\n\n constructor(client: PgClient, opts: LeaseManagerOptions) {\n this.client = client;\n this.advertiseUrl = opts.advertiseUrl;\n this.applicationName = opts.applicationName ?? null;\n this.retryMs = opts.retryMs ?? DEFAULT_RETRY_MS;\n this.ttlMs = opts.ttlMs ?? DEFAULT_LEASE_TTL_MS;\n // Guard the SQL-interpolated value: a whole positive integer of ms. A non-positive/NaN TTL would\n // produce a lease that's born already-expired (or invalid SQL), so clamp to the default instead.\n const rounded = Math.round(this.ttlMs);\n this.ttlMsSql = Number.isFinite(rounded) && rounded > 0 ? rounded : DEFAULT_LEASE_TTL_MS;\n }\n\n /**\n * Idempotent DDL: creates shard_leases if it doesn't already exist, and — when `shardIds` is\n * non-empty — pre-seeds a row for every shard in the list (Fleet B3, D4: the concurrent-boot\n * count-gate fix, reversing B2a's \"no pre-seeding\" call).\n *\n * B2a originally left this deliberately EMPTY (no pre-seeded rows): a bare `frontier_ts = 0` row\n * created at DDL time, on a database that already held documents (a pre-`--fleet` upgrade), would\n * be momentarily visible at `frontier_ts = 0` to a concurrently-booting sync node — `count(*) = N`\n * AND `min(frontier_ts) = 0` would fake-report ready with an EMPTY replica (the F1×N hole,\n * recurring ×N). That is why row existence used to be tied to a REAL, frontier-seeded acquisition\n * (`tryAcquire`) rather than to `setup()`.\n *\n * The reversal here is safe ONLY because the seed now travels WITH the row: `documentsExist` (the\n * caller's `documentsTableExists` probe, run BEFORE calling this) selects the exact same\n * `frontierSeedExpr` fragment `tryAcquire` uses — `0` on a fresh database (no `documents` table\n * yet: correct, there is no history to protect against), or `(SELECT COALESCE(MAX(ts), 0) FROM\n * documents)` on an upgrade (`documents` already exists: correct, the row is born at the true\n * high-water mark, never momentarily at 0). A pre-seeded row is created UNACQUIRED — `epoch = 0`,\n * `writer_url = NULL`, already-expired `expires_at` — so the FIRST real `tryAcquire` still lands on\n * its `ON CONFLICT` branch and bumps `epoch` from 0 to 1, byte-identical to a fresh INSERT's\n * `epoch = 1`; every existing epoch/ownership assertion in the test suite is unaffected. Idempotent\n * (`ON CONFLICT (shard_id) DO NOTHING`): a row already created by a peer's concurrent `setup()` or\n * by a real acquisition is left untouched — this can only ever RAISE a row into existence, never\n * clobber one. With every shard row present immediately, the tailer's `count(*) < NUM_SHARDS →\n * not-ready` gate is satisfied the instant `setup()` returns — a concurrent multi-writer boot no\n * longer stalls waiting for a writer to finish its acquire-all pass. See `node.ts`'s\n * `prepareFleetNode` for the `documentsTableExists` probe + call site, and `replica-tailer.ts`'s\n * `readFrontier` for the count gate.\n */\n /** Run one DDL statement, swallowing the concurrent-boot duplicate-object race family\n * (23505 unique_violation / 42P07 duplicate_table / 42710 duplicate_object — the third face\n * is \"type <table> already exists\", the table's composite rowtype, which is what two nodes\n * racing CREATE TABLE IF NOT EXISTS actually surface). The statement's objective — the\n * object exists — is achieved when any of these fires; anything else propagates. Mirrors\n * docstore-postgres setupSchema's discipline; added when the SIMULTANEOUS multi-writer boot\n * E2E caught the unguarded race here (Plan A's extra boot DDL widened the window). */\n private async ddl(stmt: string): Promise<void> {\n try {\n await this.client.query(stmt);\n } catch (e) {\n const code = (e as { code?: unknown } | null)?.code;\n if (code !== \"23505\" && code !== \"42P07\" && code !== \"42710\") throw e;\n }\n }\n\n async setup(shardIds: readonly ShardId[] = [], documentsExist = false): Promise<void> {\n await this.ddl(`\n CREATE TABLE IF NOT EXISTS shard_leases (\n shard_id TEXT PRIMARY KEY,\n epoch BIGINT NOT NULL,\n writer_url TEXT,\n writer_app_name TEXT,\n expires_at TIMESTAMPTZ NOT NULL,\n frontier_ts BIGINT NOT NULL DEFAULT 0,\n prev_ts BIGINT NOT NULL DEFAULT 0\n )\n `);\n // `fleet_nodes` presence table (B2b, D3 — the bootstrap-deadlock fix). Every fleet node, INCLUDING\n // a shardless sync node that appears in no `shard_leases` row, heartbeats its row here, so it is\n // visible in every peer's live set and thus a rendezvous participant. Without this table a\n // shardless node is invisible → never assigned a shard → never holds one → scale-out never\n // happens (and the incumbent, not seeing the newcomer, releases nothing). Run as its own statement\n // (single-statement drivers like PGlite), mirroring the schema discipline in `docstore-postgres`.\n await this.ddl(`\n CREATE TABLE IF NOT EXISTS fleet_nodes (\n advertise_url TEXT PRIMARY KEY,\n epoch BIGINT NOT NULL,\n expires_at TIMESTAMPTZ NOT NULL\n )\n `);\n // `fleet_idempotency` (B3, D3 — effectively-once forwarding): one row per forwarded logical\n // write, INSERTed by the commit guard (`node.ts`'s `installCommitGuard`) INSIDE the same\n // transaction as the commit itself — atomic by construction, so a `key` PK collision aborts\n // the whole commit (the concurrent-duplicate race's loser path). `value_json` is filled in by\n // `recordIdempotencyValue` AFTER the run completes (the value isn't known inside the commit\n // txn) — best-effort, so a crash between commit and that UPDATE leaves it NULL; `oversized`\n // distinguishes \"too big to cache\" from \"not recorded yet\", though both replay as\n // `valueMissing: true` (see `IdempotencyReplay`). `created_at` drives the 1h sweep\n // (`sweepIdempotency`), run on the balancer beat.\n await this.ddl(`\n CREATE TABLE IF NOT EXISTS fleet_idempotency (\n key TEXT PRIMARY KEY,\n commit_ts BIGINT NOT NULL,\n value_json TEXT,\n oversized BOOLEAN NOT NULL DEFAULT false,\n created_at TIMESTAMPTZ NOT NULL DEFAULT now()\n )\n `);\n\n if (shardIds.length === 0) return;\n // Batched pre-seed, one row per shard, all sharing the SAME `frontierSeedExpr` snapshot (the\n // subquery is re-evaluated per VALUES row within the one statement's snapshot, so every row gets\n // an identical seed). `epoch = 0`/`writer_url = NULL`/already-expired `expires_at` mark the row as\n // UNACQUIRED — see the class doc comment above for why the first real `tryAcquire` still bumps\n // epoch 0 -> 1, byte-identical to a fresh INSERT. `ON CONFLICT DO NOTHING`: idempotent against a\n // concurrent peer's `setup()` (same shard list) or a row a real acquisition already created.\n const frontierSeed = this.frontierSeedExpr(documentsExist);\n const params: string[] = [];\n const values = shardIds.map((shardId, i) => {\n params.push(shardId);\n return `($${i + 1}, 0, NULL, NULL, now(), ${frontierSeed}, 0)`;\n });\n await this.client.query(\n `INSERT INTO shard_leases (shard_id, epoch, writer_url, writer_app_name, expires_at, frontier_ts, prev_ts)\n VALUES ${values.join(\", \")}\n ON CONFLICT (shard_id) DO NOTHING`,\n params,\n );\n }\n\n /**\n * The `frontier_ts` seed SQL fragment shared by `setup()`'s row pre-seed and `tryAcquire()`'s\n * first-creation INSERT (Fleet B3, D4 — the one place this reasoning is written down): `0` when the\n * caller has verified `documents` does not exist yet (a fresh database — no history to protect\n * against), else `(SELECT COALESCE(MAX(ts), 0) FROM documents)` (an upgrade — the row is born at the\n * store's true high-water mark, never momentarily visible below it). Both call sites gate this on\n * the SAME `documentsTableExists` probe (`node.ts`), so a row is never seeded incorrectly regardless\n * of which of the two code paths creates it first.\n */\n private frontierSeedExpr(documentsExist: boolean): string {\n return documentsExist ? `(SELECT COALESCE(MAX(ts), 0) FROM documents)` : `0`;\n }\n\n /**\n * Upsert this node's `fleet_nodes` presence row (B2b, D3), extending `expires_at` by the lease TTL.\n * Called at boot (BEFORE the writer-election `tryAcquire`, so a losing node is already visible when\n * it boots sync) and on every balancer beat / writer probe — the node's liveness signal now. A node\n * whose process dies stops heartbeating; its row expires after the TTL and it drops out of every\n * survivor's `liveNodes()`, re-converging the rendezvous assignment. `epoch` increments per beat —\n * carried only for observability/debugging (which incarnation of a node the row belongs to); the\n * live-set membership check keys off `expires_at`, not `epoch`.\n */\n async heartbeatPresence(): Promise<void> {\n await this.client.query(\n `INSERT INTO fleet_nodes (advertise_url, epoch, expires_at)\n VALUES ($1, 1, now() + interval '${this.ttlMsSql} milliseconds')\n ON CONFLICT (advertise_url) DO UPDATE SET\n epoch = fleet_nodes.epoch + 1,\n expires_at = now() + interval '${this.ttlMsSql} milliseconds'`,\n [this.advertiseUrl],\n );\n }\n\n /**\n * The live fleet node set (B2b, D3): distinct unexpired `fleet_nodes` advertise URLs, UNION the live\n * `shard_leases` writer URLs (belt-and-braces — a writer whose presence heartbeat momentarily lapsed\n * but whose shard lease is still live is unambiguously alive). Every node computes rendezvous over\n * this set, so they all derive the same shard→owner assignment. Expiry is `expires_at >= now()` per\n * the DB's OWN clock, authoritative against host clock skew.\n */\n async liveNodes(): Promise<string[]> {\n const rows = await this.client.query(\n `SELECT advertise_url AS url FROM fleet_nodes WHERE expires_at >= now()\n UNION\n SELECT writer_url AS url FROM shard_leases WHERE writer_url IS NOT NULL AND expires_at >= now()`,\n );\n return rows.map((r) => r.url as string).filter((u): u is string => typeof u === \"string\" && u.length > 0);\n }\n\n /**\n * Per-shard ownership snapshot for the balancer (B2b, D3): for each EXISTING `shard_leases` row, its\n * `writer_url` (null = orphaned) and whether it has expired per the DB clock. A shard with no row is\n * simply absent from the map — the balancer treats an absent shard as acquirable (never created, or\n * fully reaped), the same as an orphaned one. Read-only; the balancer decides acquire/release from it.\n */\n async readShardOwnership(): Promise<Map<ShardId, { writerUrl: string | null; expired: boolean }>> {\n const rows = await this.client.query(\n `SELECT shard_id, writer_url, (expires_at < now()) AS expired FROM shard_leases`,\n );\n const map = new Map<ShardId, { writerUrl: string | null; expired: boolean }>();\n for (const r of rows) {\n map.set(r.shard_id as ShardId, {\n writerUrl: (r.writer_url as string | null | undefined) ?? null,\n expired: r.expired === true,\n });\n }\n return map;\n }\n\n /**\n * Self-fence a shard this node currently holds, for a GRACEFUL balancer release (B2b, D3): bump the\n * epoch (so this node's own subsequent commit/heartbeat on the now-stale epoch fences cleanly),\n * clear `writer_url` (so the shard reads as orphaned and its rightful rendezvous owner acquires it),\n * and GREATEST-bump `frontier_ts` from the shared sequence (so F never regresses across the handoff).\n * Predicated on this node's currently-held epoch — a silent no-op if the shard is already fenced/\n * relinquished (`currentEpoch === null`). The caller runs this only when the shard is fully IDLE —\n * `runtime.tryRunExclusiveOnShard` grants the mutex only if no commit holds it AND no group-commit\n * batch is staged/flushing (Fleet B4), so no in-flight commit's OR batch's frontier write races the\n * GREATEST-bump here; the release is deferred a beat if the shard is busy rather than fencing\n * mid-flush (see `releaseShard` in `node.ts`). A mutation that begins mid-execute after the fence\n * simply hits `FencedError` at its own commit (OCC-retryable, the forwarder re-routes the retry to\n * the new owner). Mirrors `evictExpired`'s frontier-bump SQL, but unconditional on expiry (this is a\n * voluntary handoff, not an eviction of a wedged peer).\n */\n async selfFence(shardId: ShardId): Promise<void> {\n const epoch = this.currentEpoch(shardId);\n if (epoch === null) return;\n await this.client.query(\n `UPDATE shard_leases SET\n epoch = epoch + 1,\n writer_url = NULL,\n writer_app_name = NULL,\n frontier_ts = GREATEST(frontier_ts, (SELECT nextval('helipod_ts')))\n WHERE shard_id = $1 AND epoch = $2`,\n [shardId, epoch],\n );\n }\n\n /**\n * The epoch this node most recently acquired for `shardId` (via `tryAcquire`), or `null` if it\n * never has. Read live — not a boot-time snapshot — by the commit guard and the heartbeat probe,\n * so a re-promotion's epoch bump (another `tryAcquire` call) is picked up automatically with no\n * extra threading between `prepareFleetNode`/`startFleetNode`/`promoteFleetNode`. Defaults to the\n * default shard so B1 call sites (`currentEpoch()`) are unchanged.\n */\n currentEpoch(shardId: ShardId = SHARD_ID): bigint | null {\n return this.lastEpochByShard.get(shardId) ?? null;\n }\n\n /** The (shard, epoch) pairs this node currently holds — the input to the batched heartbeat,\n * all-rows seed, and idle-shard closer (all fence per-row against the epoch on file). A snapshot\n * of the live per-shard epoch map, so it reflects any re-promotion's epoch bumps. */\n heldPairs(): Array<{ shardId: ShardId; epoch: bigint }> {\n return [...this.lastEpochByShard].map(([shardId, epoch]) => ({ shardId, epoch }));\n }\n\n /**\n * Drop `shardId` from this node's held-epoch map (Fenced Frontier B2b, D2 — per-shard relinquish).\n * After this call `currentEpoch(shardId)` returns `null`, so:\n * - the commit guard's \"no acquired epoch\" branch fences any straggler commit on `shardId`\n * cleanly (rather than a stale epoch happening to still match a row some other node has since\n * re-fenced and moved on from);\n * - `heldPairs()` (and therefore `heartbeatAll()`/`closeIdleFrontiers()`/`seedFrontierAll()`) stop\n * including this shard.\n * Idempotent: forgetting a shard this node doesn't currently hold is a silent no-op — the\n * relinquish dispatcher (`node.ts`) relies on exactly this for ITS OWN idempotency, via\n * `currentEpoch(shardId) === null` as its \"already relinquished\" check. Deliberately does NOT touch\n * the `shard_leases` ROW — only the caller's advisory-lock release (`PgClient.releaseShardLock`) and\n * this in-memory forget are relinquish's job; the row itself was already epoch-bumped by whoever\n * fenced this node (or will lapse via TTL), and a future re-acquire (`tryAcquire`) is a fresh INSERT/\n * ON CONFLICT UPDATE regardless of what this map remembers.\n */\n forgetShard(shardId: ShardId): void {\n this.lastEpochByShard.delete(shardId);\n }\n\n /**\n * One non-blocking attempt: takes the advisory lock (fast path); on success, runs the fencing\n * upsert against `shard_leases` (bumping `epoch`, recording this node's URL/app-name, extending\n * `expires_at`) and returns the new state. On failure to take the lock, returns null.\n * `prev_ts` is seeded to 0 on first creation only, and `frontier_ts` to either 0 or the store's\n * current `MAX(ts)` (see `seedFrontierFromDocuments`) — an `ON CONFLICT` re-acquisition (including\n * promotion) leaves BOTH untouched, so the durable-commit chain survives across epochs (D3 depends\n * on this: frontier must never reset just because the writer changed).\n *\n * `seedFrontierFromDocuments` (the F1×N residual-window fix): when a row is FIRST created, seed its\n * `frontier_ts` to `MAX(ts)` from the `documents` log inside the same INSERT — atomically, so the\n * row is NEVER momentarily visible at `frontier_ts = 0` on a pre-loaded store (which would let a\n * concurrently-booting sync node pass its `count == N ∧ min-F` ready gate with an empty replica).\n * Pass `true` only when the `documents` table is known to exist (post-`setupSchema`, or a pre-loaded\n * store) — the caller guards this; `false` (the default, and the only safe value pre-DDL on a fresh\n * database) creates the row at `frontier_ts = 0`, which is correct precisely because a fresh store\n * holds no data. `seedFrontierAll` remains the idempotent belt-and-braces second pass.\n */\n async tryAcquire(\n shardId: ShardId = SHARD_ID,\n slot = 0,\n seedFrontierFromDocuments = false,\n ): Promise<LeaseState | null> {\n // Per-slot advisory lock (B2a, D1 hazard (c)): each slot's lock is taken on THAT shard's\n // dedicated commit connection (`tryAcquireShardLock(slot)`), so the connection's death releases\n // exactly that slot. The two-int lock space is disjoint from the legacy single-int writer lock,\n // so slot locks never collide with it. When the client has no pool (a single-node `NodePgClient`\n // or the PGlite test double), fall back to the legacy `tryAcquireWriterLock()` — one lock guards\n // the whole (single) writer, exactly B1's behavior.\n const acquired = this.client.tryAcquireShardLock\n ? await this.client.tryAcquireShardLock(slot)\n : await this.client.tryAcquireWriterLock();\n if (!acquired) return null;\n\n // Seed a FIRST-creation frontier from the store's current max (atomic with the INSERT) when the\n // caller vouches `documents` exists; else 0. The `frontier_ts < $N`-style guards elsewhere and\n // `GREATEST` on every later write mean this only ever RAISES the seed, never regresses it.\n const frontierSeed = this.frontierSeedExpr(seedFrontierFromDocuments);\n const rows = await this.client.query(\n `INSERT INTO shard_leases (shard_id, epoch, writer_url, writer_app_name, expires_at, frontier_ts, prev_ts)\n VALUES ($1, 1, $2, $3, now() + interval '${this.ttlMsSql} milliseconds', ${frontierSeed}, 0)\n ON CONFLICT (shard_id) DO UPDATE SET\n epoch = shard_leases.epoch + 1,\n writer_url = $2,\n writer_app_name = $3,\n expires_at = now() + interval '${this.ttlMsSql} milliseconds'\n RETURNING epoch, writer_url, frontier_ts`,\n [shardId, this.advertiseUrl, this.applicationName],\n );\n const row = rows[0];\n if (!row) throw new Error(\"shard_leases upsert returned no row\");\n const state: LeaseState = {\n epoch: row.epoch as bigint,\n writerUrl: row.writer_url as string,\n // On a re-acquire this is the frontier an interim owner left; on a fresh INSERT it's the seed\n // (`frontierSeed` — store max or 0). Feeds `runtime.observeWriteTimestamp` at every acquisition.\n frontierTs: toBigIntOrZero(row.frontier_ts as PgValue | undefined),\n };\n this.lastEpochByShard.set(shardId, state.epoch);\n return state;\n }\n\n /**\n * Extend `expires_at` for this node's `epoch` — the LeaseMonitor's periodic probe (D2: one\n * round-trip serves liveness-probe + TTL maintenance + fence verification). Returns the number\n * of rows updated: 1 = still this node's epoch (TTL extended), 0 = fenced — some other node has\n * bumped the epoch (a D4 eviction) and this node no longer holds the lease, even though its\n * connection never dropped. Callers (see `node.ts`) treat 0 as definitive lease loss.\n */\n async heartbeat(epoch: bigint, shardId: ShardId = SHARD_ID): Promise<number> {\n const rows = await this.client.query(\n `UPDATE shard_leases SET expires_at = now() + interval '${this.ttlMsSql} milliseconds'\n WHERE shard_id = $1 AND epoch = $2\n RETURNING epoch`,\n [shardId, epoch],\n );\n return rows.length;\n }\n\n /**\n * Batched heartbeat over EVERY (shard, epoch) pair this node holds — one UPDATE per beat (B2a):\n * the writer holds N leases and must renew all of them in a single round-trip, not N. Returns\n * `{ updated, expected, fencedShardIds }` where `expected` is how many pairs this node believes it\n * holds, `updated` is how many rows actually matched, and `fencedShardIds` (B2b, D2) is PRECISELY\n * which held shards did NOT match — diffing the `RETURNING shard_id` rows against the held set —\n * so the caller can relinquish exactly those shards rather than treat `updated < expected` as an\n * undifferentiated whole-node signal. `updated < expected` (equivalently `fencedShardIds.length >\n * 0`) means at least one shard's epoch was superseded; `fencedShardIds` is always `[]` when this\n * node holds nothing (never a writer) — see the early return. The `(shard_id, epoch) IN ((..),(..))`\n * tuple form fences per row.\n */\n async heartbeatAll(): Promise<{ updated: number; expected: number; fencedShardIds: ShardId[] }> {\n const pairs = this.heldPairs();\n if (pairs.length === 0) return { updated: 0, expected: 0, fencedShardIds: [] };\n const { clause, params } = this.tupleInClause(pairs, 0);\n const rows = await this.client.query(\n `UPDATE shard_leases SET expires_at = now() + interval '${this.ttlMsSql} milliseconds'\n WHERE (shard_id, epoch) IN (${clause})\n RETURNING shard_id`,\n params,\n );\n const renewedIds = new Set(rows.map((r) => r.shard_id as ShardId));\n const fencedShardIds = pairs.filter((p) => !renewedIds.has(p.shardId)).map((p) => p.shardId);\n return { updated: rows.length, expected: pairs.length, fencedShardIds };\n }\n\n /**\n * Read-only expiry check: does the lease row exist AND is `expires_at` in the past, per the DB's\n * OWN clock? Used as the acquire loop's per-tick pre-gate before the heavier `evictExpired`\n * transaction — a healthy (live) lease must NOT make every follower take the row lock every tick and\n * contend with the writer's commit guard, so the common case stays a single cheap SELECT. The\n * comparison is `now()` in SQL (not `read().expiresAt` in JS) so it's authoritative against clock\n * skew between a follower's host and Postgres.\n */\n async isExpired(shardId: ShardId = SHARD_ID): Promise<boolean> {\n const rows = await this.client.query(\n `SELECT 1 FROM shard_leases WHERE shard_id = $1 AND expires_at < now()`,\n [shardId],\n );\n return rows.length > 0;\n }\n\n /**\n * Fencing-first eviction of an EXPIRED lease (Fenced Frontier B1, D4). Bumps `epoch` (fencing the\n * wedged holder — its next commit guard / heartbeat now matches 0 rows), clears `writer_url`/\n * `writer_app_name`, and advances `frontier_ts`, all predicated on the lease actually being\n * expired. Returns `{ fenced: true, oldAppName }` capturing the evicted holder's `writer_app_name`\n * (so the acquire loop can `pg_terminate_backend` its lingering connection); `{ fenced: false }`\n * when the row is live (no-op) OR the row lock couldn't be taken within `lock_timeout` (retry next\n * tick — never throws that to the loop).\n *\n * Why a `SELECT ... FOR UPDATE` then a separate `UPDATE`, NOT a single `UPDATE ... RETURNING (SELECT\n * writer_app_name FROM cte)`: on Postgres, RETURNING — and the inlined CTE subquery it evaluates —\n * sees the NEW (already-nulled) row, so a single statement reads back NULL for the old app name\n * (verified on PGlite; a `MATERIALIZED` CTE with its own `FOR UPDATE` instead collides with the\n * same-statement UPDATE's row lock and yields zero rows). The two-statement form captures the old\n * value cleanly, and the `FOR UPDATE` takes the very row lock a concurrent commit-guard UPDATE\n * contends on — serializing eviction against an in-flight commit. That contention is single-\n * connection-untestable and covered E2E only (see the test header).\n */\n async evictExpired(shardId: ShardId = SHARD_ID): Promise<{ fenced: boolean; oldAppName: string | null }> {\n try {\n return await this.client.transaction(async (tx) => {\n // `lock_timeout` scoped to THIS transaction (auto-reset at COMMIT/ROLLBACK): if the wedged\n // holder is mid-commit and still holds the row lock, wait at most 2s, then the FOR UPDATE\n // below fires a lock_timeout error → caught outside → {fenced:false}, retry next tick.\n await tx.query(`SET LOCAL lock_timeout = '2s'`);\n const sel = await tx.query(\n `SELECT writer_app_name FROM shard_leases WHERE shard_id = $1 AND expires_at < now() FOR UPDATE`,\n [shardId],\n );\n if (sel.length === 0) return { fenced: false, oldAppName: null }; // live (or gone) — no-op\n const oldAppName = (sel[0]!.writer_app_name as string | null | undefined) ?? null;\n // BINDING HANDOFF (Task 1 review): `frontier_ts` MUST stay inside the GREATEST —\n // `frontier_ts = GREATEST(frontier_ts, (SELECT nextval('helipod_ts')))`, NEVER `nextval`\n // alone. `frontier_ts` is the true high-water mark (the commit guard maintains it >= every\n // committed ts), while the `helipod_ts` sequence can LAG reality in a mixed\n // write()/commitWrite store. Architectural invariant: the production primary is pure-\n // commitWrite, so the sequence never lags maxTimestamp there; `frontier_ts` in this GREATEST\n // is what makes eviction safe even if that ever changes. The row is already locked by the\n // SELECT FOR UPDATE above, so the bare shard_id WHERE targets exactly that expired row.\n await tx.query(\n `UPDATE shard_leases SET\n epoch = epoch + 1,\n writer_url = NULL,\n writer_app_name = NULL,\n frontier_ts = GREATEST(frontier_ts, (SELECT nextval('helipod_ts')))\n WHERE shard_id = $1`,\n [shardId],\n );\n return { fenced: true, oldAppName };\n });\n } catch (e) {\n // A lock_timeout (couldn't take the row lock in 2s) is expected under contention — surface it as\n // a no-op-this-tick, not an error. The transaction() wrapper has already ROLLBACK'd.\n if (isLockTimeoutError(e)) return { fenced: false, oldAppName: null };\n throw e;\n }\n }\n\n /**\n * Kill the evicted holder's lingering Postgres backend(s) by `application_name` so its session-level\n * advisory writer lock is released and the NEXT acquire tick can win. Matches the fleet E2E's query\n * shape exactly, including the `pid <> pg_backend_pid()` self-exclusion (the fencer never terminates\n * its own connection — its app name differs anyway, so this is belt-and-braces). Best-effort: if the\n * backend is already gone, the query simply affects zero rows.\n */\n async terminateBackend(appName: string): Promise<void> {\n // B2a: also terminate the wedged holder's PER-SHARD commit-pool backends. Those connections\n // (`<appName>-commit-<shard>`, see `NodePgClient`'s pool) hold the per-slot advisory locks — the\n // exact locks a survivor's acquire-all needs. Terminating ONLY the pinned backend (`= $1`) would\n // release the writer-election lock but leave the shard locks held by the SIGSTOP'd process's\n // still-alive commit connections, so the survivor would spin forever unable to acquire slots\n // 1…N-1. Matching `$1` OR `$1 || '-commit-%'` frees every one of the wedged node's locks at once.\n // (`writer_app_name` records the BASE name; the suffix is appended per shard by the pool.)\n await this.client.query(\n `SELECT pg_terminate_backend(pid) FROM pg_stat_activity\n WHERE (application_name = $1 OR application_name LIKE $1 || '-commit-%') AND pid <> pg_backend_pid()`,\n [appName],\n );\n }\n\n /**\n * A tick observed the advisory-lock try FAIL — another backend still holds the writer lock. If the\n * lease has ALSO expired, that holder is wedged (its heartbeat stopped) while its connection lingers\n * (a hung/paused process still owns the advisory lock, so no other node can acquire). Fence it\n * (`evictExpired` bumps the epoch) then terminate its backend to release the lock; the next tick's\n * advisory try then succeeds → normal acquisition → promotion. No-op when the lease is still live.\n */\n private async maybeEvictWedged(): Promise<void> {\n if (!(await this.isExpired())) return;\n const { fenced, oldAppName } = await this.evictExpired();\n // Skip termination when there's no recorded app name — nothing to target (and a null-name lease\n // predates app-name stamping / was hand-written). The epoch bump alone already fenced the holder.\n if (fenced && oldAppName !== null) await this.terminateBackend(oldAppName);\n }\n\n /** Loop tryAcquire() every retryMs until it succeeds, then invoke onAcquired once. stop() cancels.\n * On a tick where the advisory try fails AND the lease has expired, the wedged holder is fenced +\n * its backend terminated (`maybeEvictWedged`) so a later tick can take over. */\n acquireLoop(onAcquired: (s: LeaseState) => void): void {\n this.stopped = false;\n\n const schedule = () => {\n if (this.stopped) return;\n this.timer = setTimeout(attempt, this.retryMs);\n };\n\n const attempt = (): void => {\n if (this.stopped) return;\n void (async () => {\n try {\n const state = await this.tryAcquire();\n if (this.stopped) return;\n if (state) {\n onAcquired(state);\n return; // acquired — the loop is done (no reschedule)\n }\n // Advisory try failed this tick: if the lease has expired, fence + evict the wedged holder\n // so the next tick can win. Any error here falls through to the catch → reschedule.\n await this.maybeEvictWedged();\n } catch {\n // Transient error (dropped connection, eviction/terminate race) — never let the loop die;\n // just retry next tick.\n }\n schedule();\n })();\n };\n\n this.timer = setTimeout(attempt, this.retryMs);\n }\n\n /** Cancels any pending acquireLoop() retry. */\n stop(): void {\n this.stopped = true;\n if (this.timer !== null) {\n clearTimeout(this.timer);\n this.timer = null;\n }\n }\n\n /**\n * F1 fix (Fenced Frontier B1 whole-branch review, BLOCKER): seed `frontier_ts` up to at least\n * `maxTs` — the writer-BOOT step that closes the \"pre-loaded database\" hole. `tryAcquire()` only\n * seeds `frontier_ts` to 0 on the row's FIRST creation (see above); a single-node Postgres `serve`\n * that accumulates real data BEFORE `--fleet` is ever turned on has no `shard_leases` row at all,\n * so the first `tryAcquire()` after enabling `--fleet` creates one at `frontier_ts=0` even though\n * the store already holds history. Because the tailer targets `F=frontier_ts` (not\n * `primary.maxTimestamp()`, see `replica-tailer.ts`'s D5), a fresh sync node's ready gate\n * (`wm=0 < target=0`) is then a silent no-op — it reports ready with an EMPTY replica while the\n * primary holds everything. Callers must invoke this at WRITER BOOT, after this node's own\n * `setupSchema()` has definitely run (the `documents` table this reads may not exist before\n * that — see `prepareFleetNode`/`startFleetNode`'s boot ordering) and BEFORE the node is reported\n * ready; a later promotion does NOT need to call this — by then `frontier_ts` is already live,\n * tracking every commit via the guard installed by `installCommitGuard`.\n *\n * `GREATEST` makes this a no-op on an already-live fleet (frontier already tracks every commit)\n * and on re-acquisition — never regresses `frontier_ts`. Epoch-fenced like every other\n * `shard_leases` write: a stale `epoch` here (this node lost the writer race to someone else\n * between its `tryAcquire()` and this call) affects 0 rows rather than clobbering the new\n * writer's state — that writer's own commit guard is the source of truth for `frontier_ts` going\n * forward regardless. Deliberately does NOT touch `prev_ts`: this is a seed of the high-water\n * mark, not a commit, so there is no new \"previous commit\" to record — the next REAL commit's\n * guard sets `prev_ts := frontier_ts` (now the seeded value) exactly as it always does.\n */\n async seedFrontier(epoch: bigint, maxTs: bigint, shardId: ShardId = SHARD_ID): Promise<void> {\n await this.client.query(\n `UPDATE shard_leases SET frontier_ts = GREATEST(frontier_ts, $1) WHERE shard_id = $2 AND epoch = $3`,\n [maxTs, shardId, epoch],\n );\n }\n\n /**\n * All-rows frontier seed (B2a — the F1×N fix): seed EVERY shard this node holds up to `maxTs` in\n * ONE batched, per-row-epoch-fenced UPDATE, run at writer boot BEFORE the node reports ready. The\n * same reasoning as single-shard `seedFrontier` applies to every row at once: any future commit on\n * any shard takes a later `nextval`, so seeding all held frontiers to the store's current max can\n * never over-shoot a real commit, and `GREATEST` keeps it a no-op on an already-live fleet.\n * Epoch-fenced per pair (`(shard_id, epoch) IN (...)`), so a shard this node lost between acquiring\n * it and this call is simply skipped rather than clobbered. See `node.ts`'s writer boot.\n */\n async seedFrontierAll(maxTs: bigint): Promise<void> {\n const pairs = this.heldPairs();\n if (pairs.length === 0) return;\n const { clause, params } = this.tupleInClause(pairs, 1);\n await this.client.query(\n `UPDATE shard_leases SET frontier_ts = GREATEST(frontier_ts, $1) WHERE (shard_id, epoch) IN (${clause})`,\n [maxTs, ...params],\n );\n }\n\n /**\n * Per-shard idle-shard frontier closing (B2a, D5 — needed the moment N>1: an idle shard pins the\n * fleet's `F = min(frontier_ts)`). Allocate a single fresh `nextval` `N` from the shared\n * `helipod_ts` sequence per beat, then for EACH held shard advance its frontier up to `N` —\n * `UPDATE ... SET frontier_ts = GREATEST(frontier_ts, $N) WHERE shard_id=$s AND epoch=$e AND\n * frontier_ts < $N` — but run each shard's UPDATE UNDER THAT SHARD'S COMMIT MUTEX\n * (`runExclusiveOnShard`), skipping any shard currently mid-commit (mutex busy → left for the next\n * beat). Returns the `nextval` used (the ceiling this beat closed idle shards up to).\n *\n * Why skip-if-busy, not the old bare batched UPDATE (the frontier-inversion fix): the commit\n * guard writes `frontier_ts := commitTs` for a commit that drew its ts `T` from the SAME sequence,\n * *inside* the commit transaction — which runs under the shard's commit mutex (single-commit) or at\n * FLUSH time for a group-commit batch (Fleet B4). If the closer drew `N > T` and bare-wrote\n * `frontier_ts = N` while that commit's/batch's rows had not yet landed, a tailer could read `F ≥\n * N`, pull `(watermark, N]`, and MISS `T`'s rows when they land afterward (silent replica miss), or\n * the guard's later write of `T` would trip a frontier-regression assert. `runExclusiveOnShard`\n * treats a shard as available only when it is fully IDLE — mutex free AND no staged/flushing\n * group-commit batch (`ShardWriter.hasInFlightWork()`): group commit runs the flush OFF the mutex,\n * so a mid-flush batch (ts's already drawn, rows not yet landed) reads BUSY even though the mutex is\n * free, and is skipped for the next beat. Given that, the closer and that shard's commits are\n * mutually exclusive on this (single, writer-owned) node: any commit/batch STARTED before the draw\n * either holds the mutex or is staged/flushing → skipped this beat; any commit/batch that STARTS\n * after the closer's `nextval` draws its `T` at commit/flush time, AFTER `N`, so `T > N` and\n * `GREATEST` keeps `frontier_ts ≥ N` with no regression and nothing in-flight ever sits below `N`.\n * Cross-node closing of a held shard is impossible by design (only\n * the lease holder closes its own held shards; orphan bumping via `evictExpired` targets\n * writer-less rows, where no commit can be in flight). Epoch-fenced per pair. No-op (returns the\n * allocated ts anyway) when this node holds nothing.\n */\n async closeIdleFrontiers(runExclusiveOnShard: TryRunExclusiveOnShard): Promise<bigint> {\n const pairs = this.heldPairs();\n // ONE ceiling per beat. Drawn OUTSIDE any shard mutex — a bare `nextval` is monotone and the\n // `frontier_ts < $N` + `GREATEST` guards below tolerate it lagging or leading a concurrent commit.\n const tsRows = await this.client.query(`SELECT nextval('helipod_ts') AS ts`);\n const newTs = toBigIntOrZero(tsRows[0]?.ts as PgValue | undefined);\n for (const { shardId, epoch } of pairs) {\n // Skip-if-busy: an in-flight commit holds this shard's mutex, OR a group-commit batch is\n // staged/flushing (Fleet B4 — flush runs off the mutex), so `runExclusiveOnShard` returns false\n // and we leave the shard for the next beat — that commit/batch will itself set `frontier_ts` to\n // its own (later) commit ts, which is `≥ N` anyway.\n await runExclusiveOnShard(shardId, async () => {\n await this.client.query(\n `UPDATE shard_leases SET frontier_ts = GREATEST(frontier_ts, $1)\n WHERE shard_id = $2 AND epoch = $3 AND frontier_ts < $1`,\n [newTs, shardId, epoch],\n );\n });\n }\n return newTs;\n }\n\n /**\n * Orphan frontier bumping (B2b, D4): advance the frontier of every WRITER-LESS shard row\n * (`writer_url IS NULL`) that lags `ceiling`, so an unassigned/relinquished/expired shard never\n * pins the fleet's `F = min(frontier_ts)` below the live commit position. Runs on the WRITER beat\n * alongside `closeIdleFrontiers` (which only ever touches THIS node's OWN held rows via\n * `heldPairs()` and so structurally cannot un-pin a shard nobody holds).\n *\n * Safe with NO commit mutex, unlike `closeIdleFrontiers`: a writer-less shard has no in-flight\n * commit by construction — its last writer was fenced (epoch-bumped, `writer_url` nulled) BEFORE\n * the row became orphaned, so nothing can be mid-commit writing `frontier_ts` on it. The `UPDATE`'s\n * own row lock serializes any two writers racing this bump, and `GREATEST` + `frontier_ts < ceiling`\n * keep it monotone regardless. Reuses the SAME `ceiling` (one `nextval` per beat) the idle closer\n * drew, so a beat costs one sequence draw, not two.\n */\n async bumpOrphanFrontiers(ceiling: bigint): Promise<void> {\n await this.client.query(\n `UPDATE shard_leases SET frontier_ts = GREATEST(frontier_ts, $1)\n WHERE writer_url IS NULL AND frontier_ts < $1`,\n [ceiling],\n );\n }\n\n /** Reads the current lease row for `shardId` (discovery for forwarding, plus the full fencing/\n * frontier state); null if none exists yet. Defaults to the default shard (B1 call sites). */\n async read(shardId: ShardId = SHARD_ID): Promise<LeaseRow | null> {\n const rows = await this.client.query(\n `SELECT epoch, writer_url, writer_app_name, expires_at, frontier_ts, prev_ts\n FROM shard_leases WHERE shard_id = $1`,\n [shardId],\n );\n const row = rows[0];\n if (!row) return null;\n return rowToLeaseRow(row);\n }\n\n /** All shard rows' `(shard_id, frontier_ts)` — the fleet-wide frontier picture the writer's\n * frontier-lag monitor reads to compute `min(frontier_ts)` + which shard is pinning it (D5's\n * health observability). Ordered by frontier ascending so `rows[0]` is the pinning shard. */\n async readAllFrontiers(): Promise<Array<{ shardId: ShardId; frontierTs: bigint }>> {\n const rows = await this.client.query(\n `SELECT shard_id, frontier_ts FROM shard_leases ORDER BY frontier_ts ASC, shard_id ASC`,\n );\n return rows.map((r) => ({ shardId: r.shard_id as ShardId, frontierTs: toBigIntOrZero(r.frontier_ts) }));\n }\n\n /**\n * Read back `key`'s `fleet_idempotency` row for a replay decision (Fleet B3, D3), or `null` if no\n * such key has ever committed (a genuine miss — proceed to run). Called by `packages/cli`'s\n * `/_fleet/run` handler BOTH before running (the SELECT-first check) and after catching a\n * unique_violation on this table (the concurrent-duplicate race's loser re-selecting the\n * winner's row). See `IdempotencyReplay` for what `hasValue`/`oversized` distinguish.\n */\n async lookupIdempotency(key: string): Promise<IdempotencyReplay | null> {\n const rows = await this.client.query(\n `SELECT commit_ts, value_json, oversized FROM fleet_idempotency WHERE key = $1`,\n [key],\n );\n const row = rows[0];\n if (!row) return null;\n const raw = row.value_json as string | null | undefined;\n return {\n commitTs: toBigIntOrZero(row.commit_ts as PgValue | undefined),\n hasValue: raw !== null && raw !== undefined,\n value: raw !== null && raw !== undefined ? (JSON.parse(raw) as JSONValue) : null,\n oversized: row.oversized === true,\n };\n }\n\n /**\n * Best-effort post-run recording of a forwarded mutation's return VALUE onto its already-committed\n * `fleet_idempotency` row (Fleet B3, D3) — the value isn't known inside the commit transaction (the\n * guard only sees `commitTs`), so this runs AFTER `runtime.run`/`runAction`/`runSystem` returns,\n * from `packages/cli`'s `/_fleet/run` handler. Over `IDEMPOTENCY_VALUE_CAP_BYTES` → `value_json`\n * stays/goes NULL and `oversized = true` instead of storing it (a replay then reports\n * `valueMissing: true`, same as the crash-window case where this UPDATE never ran at all). A\n * missing row (no matching `key` — e.g. a no-op mutation that staged nothing, so the guard never\n * ran) silently affects 0 rows; the caller doesn't need to check for that itself.\n */\n async recordIdempotencyValue(key: string, value: JSONValue): Promise<void> {\n const json = JSON.stringify(value ?? null);\n if (Buffer.byteLength(json, \"utf8\") > IDEMPOTENCY_VALUE_CAP_BYTES) {\n await this.client.query(\n `UPDATE fleet_idempotency SET value_json = NULL, oversized = true WHERE key = $1`,\n [key],\n );\n return;\n }\n await this.client.query(\n `UPDATE fleet_idempotency SET value_json = $1, oversized = false WHERE key = $2`,\n [json, key],\n );\n }\n\n /**\n * Reclaim `fleet_idempotency` rows older than the TTL (Fleet B3, D3) — a cheap indexed (PK-only\n * table, no index needed at this scale) delete run on the balancer beat of every WRITER-ish node\n * (see `ShardLeaseBalancerDeps.sweepIdempotency` / `node.ts`'s wiring). A retry arriving after a\n * row has been swept simply re-executes (documented boundary — retries are seconds-scale, the\n * sweep window is 1h).\n */\n async sweepIdempotency(): Promise<void> {\n await this.client.query(`DELETE FROM fleet_idempotency WHERE created_at < now() - interval '${IDEMPOTENCY_TTL_INTERVAL}'`);\n }\n\n /**\n * Build a `(shard_id, epoch) IN ((...),(...))` VALUES-list clause + its flat params array for a\n * batched per-row-fenced statement, with placeholder numbers starting AFTER `offset` positional\n * params the caller already consumed (e.g. a leading `$1 = maxTs`). Returns `{ clause, params }`\n * where `params` is `[shardA, epochA, shardB, epochB, …]` in placeholder order.\n */\n private tupleInClause(\n pairs: ReadonlyArray<{ shardId: ShardId; epoch: bigint }>,\n offset: number,\n ): { clause: string; params: PgValue[] } {\n const tuples: string[] = [];\n const params: PgValue[] = [];\n for (const { shardId, epoch } of pairs) {\n const a = offset + params.length + 1;\n const b = offset + params.length + 2;\n tuples.push(`($${a}, $${b})`);\n params.push(shardId, epoch);\n }\n return { clause: tuples.join(\", \"), params };\n }\n}\n","/* Helipod Enterprise. Licensed under the Helipod Commercial License — see ee/LICENSE. */\n/**\n * Fleet writer liveness monitor (Task 4, C4). Runs ONLY while a node is the writer. Its job: notice\n * when this node has lost its exclusive writer lease and exit the process so it can rejoin the fleet\n * as a fresh sync node (exit-and-rejoin) — rather than lingering as a zombie writer that believes it\n * still owns the lock while some other node has taken over.\n *\n * Three independent loss signals feed it:\n *\n * - `connectionLost()` — DEFINITIVE. The advisory lock lives on `NodePgClient`'s single pinned\n * connection, which never reconnects (see `NodePgClient.ensure()`); if that connection closes or\n * errors, the session-level `pg_advisory_lock` is released by Postgres the instant the backend\n * goes away. So a closed pinned connection == lease definitely lost → exit immediately.\n *\n * - `fenced()` — DEFINITIVE (Fenced Frontier B1, D2/D3). The connection is still alive, but this\n * node's epoch has been superseded — either the heartbeat probe found 0 rows for `(shard_id,\n * epoch)`, or an epoch-fenced commit guard's UPDATE matched 0 rows. Both mean some OTHER node\n * now holds the lease, so — exactly like `connectionLost()` — this bypasses the probe-miss\n * tolerance below (which exists only for transient/ambiguous blips; a fenced epoch never is)\n * and exits immediately.\n *\n * - `probe()` misses — a BACKSTOP for a silently-wedged connection that isn't emitting error/end\n * events (e.g. a half-open TCP connection). The probe is a caller-supplied liveness round-trip\n * (`() => client.query(\"SELECT 1\")`); it must NEVER be `pg_try_advisory_lock` — that is re-entrant\n * on the session already holding the lock and would leak a lock count on every probe. We tolerate\n * `maxMisses` consecutive failures (transient blips) and exit on the NEXT one; any success resets\n * the counter. Each probe is itself bounded by `probeTimeoutMs` (default `probeMs`) via\n * `Promise.race` — a silently-wedged connection (e.g. a half-open TCP socket) can leave\n * `SELECT 1` hanging forever with no error/end event; without a per-probe timeout `inFlight`\n * would stay true and every subsequent tick would early-return, so misses would never accrue and\n * this exact backstop would never fire. A timed-out probe counts as a miss; if the underlying\n * query later settles anyway, that late settlement is discarded (`Promise.race` only ever acts on\n * whichever of the probe/timeout settles first) — no reset, no double-count. `inFlight` still\n * clears once the race settles, so the next tick starts its own fresh attempt regardless of what\n * the abandoned probe call eventually does.\n *\n * `onExit` is injected: production passes `(reason) => { console.error(...); process.exit(1); }`;\n * tests pass a spy. It fires AT MOST ONCE — the first of (connectionLost, probe-exhaustion) wins,\n * and `stop()` (graceful shutdown / promotion hand-off) halts everything so nothing fires after.\n */\n\nexport interface LeaseMonitorDeps {\n /** Liveness round-trip against the pinned writer connection. MUST be a plain query (e.g.\n * `SELECT 1`), NEVER `pg_try_advisory_lock` (re-entrant → leaks a lock count per probe). */\n probe: () => Promise<void>;\n /** Fired at most once when the lease is deemed lost. Production: `console.error` + `process.exit(1)`. */\n onExit: (reason: string) => void;\n /** Interval between probes. Default 5000ms. */\n probeMs?: number;\n /** Consecutive probe failures tolerated before exit — the NEXT (maxMisses+1-th) miss exits. Default 3. */\n maxMisses?: number;\n /** Per-probe timeout — a probe that hasn't settled by this point counts as a miss (the wedged\n * connection is abandoned, not awaited further). Default `probeMs`. */\n probeTimeoutMs?: number;\n}\n\nconst DEFAULT_PROBE_MS = 5000;\nconst DEFAULT_MAX_MISSES = 3;\n\nexport class LeaseMonitor {\n private readonly probe: () => Promise<void>;\n private readonly onExit: (reason: string) => void;\n private readonly probeMs: number;\n private readonly maxMisses: number;\n private readonly probeTimeoutMs: number;\n private timer: ReturnType<typeof setInterval> | null = null;\n private misses = 0;\n private inFlight = false;\n private exited = false;\n private stopped = false;\n\n constructor(deps: LeaseMonitorDeps) {\n this.probe = deps.probe;\n this.onExit = deps.onExit;\n this.probeMs = deps.probeMs ?? DEFAULT_PROBE_MS;\n this.maxMisses = deps.maxMisses ?? DEFAULT_MAX_MISSES;\n this.probeTimeoutMs = deps.probeTimeoutMs ?? this.probeMs;\n }\n\n /** Begin probing every `probeMs`. Idempotent; a no-op once stopped or after exit. */\n start(): void {\n if (this.timer !== null || this.stopped || this.exited) return;\n this.timer = setInterval(() => void this.tick(), this.probeMs);\n }\n\n private async tick(): Promise<void> {\n // Skip if we're shutting down, already exited, or a prior probe is still outstanding (never let\n // slow probes stack up — a wedged connection could leave one hanging indefinitely).\n if (this.stopped || this.exited || this.inFlight) return;\n this.inFlight = true;\n let timeoutHandle: ReturnType<typeof setTimeout> | null = null;\n try {\n // Bound the probe with `probeTimeoutMs` via Promise.race: whichever of (probe settles, timeout\n // fires) happens first wins the race outcome; the loser is simply never looked at again. If the\n // probe later resolves or rejects after the timeout already won, `Promise.race`'s internal\n // resolve/reject on that already-settled race is a no-op — nothing in this function observes\n // it, so it cannot reset the miss counter or double-count as a success.\n const probeSettled = Promise.resolve()\n .then(() => this.probe())\n .then(() => \"success\" as const);\n const timedOutMarker = new Promise<\"timeout\">((resolve) => {\n timeoutHandle = setTimeout(() => resolve(\"timeout\"), this.probeTimeoutMs);\n });\n const result = await Promise.race([probeSettled, timedOutMarker]);\n if (this.stopped || this.exited) return;\n if (result === \"timeout\") {\n this.recordMiss(\"timed out\");\n } else {\n this.misses = 0; // any success resets the streak\n }\n } catch {\n if (this.stopped || this.exited) return;\n this.recordMiss(\"failed\");\n } finally {\n if (timeoutHandle !== null) clearTimeout(timeoutHandle);\n this.inFlight = false;\n }\n }\n\n private recordMiss(mode: \"timed out\" | \"failed\"): void {\n this.misses += 1;\n if (this.misses > this.maxMisses) {\n this.fireExit(`writer lease probe ${mode} (${this.misses} consecutive times)`);\n }\n }\n\n /** DEFINITIVE lease loss (pinned connection closed/errored) → exit immediately. */\n connectionLost(): void {\n if (this.stopped || this.exited) return;\n this.fireExit(\"writer lease lost: database connection closed\");\n }\n\n /** DEFINITIVE lease loss (epoch superseded — heartbeat or commit guard found 0 rows for this\n * node's epoch) → exit immediately, mirroring `connectionLost()`. Idempotent/at-most-once via\n * the same `fireExit` guard — safe to call from both the heartbeat probe and a commit guard. */\n fenced(reason?: string): void {\n if (this.stopped || this.exited) return;\n this.fireExit(`writer lease fenced: ${reason ?? \"epoch superseded by another node\"}`);\n }\n\n private fireExit(reason: string): void {\n if (this.exited) return;\n this.exited = true;\n this.clearTimer();\n this.onExit(reason);\n }\n\n /** Halt all probing and disarm exit — graceful shutdown or promotion hand-off. */\n stop(): void {\n this.stopped = true;\n this.clearTimer();\n }\n\n private clearTimer(): void {\n if (this.timer !== null) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n}\n","/* Helipod Enterprise. Licensed under the Helipod Commercial License — see ee/LICENSE. */\n/**\n * Thrown when this node's epoch has been superseded by another writer (Fenced Frontier B1, D2/D3).\n * Two sources:\n *\n * - `LeaseManager.heartbeat(epoch)` finds zero rows matching `(shard_id, epoch)` — some other\n * node has fenced this one (bumped the epoch, e.g. the D4 wedged-writer eviction path) and\n * this node's lease is gone even though it never lost its Postgres connection.\n * - `PostgresDocStore`'s installed commit guard's epoch-predicated `UPDATE` matches zero rows —\n * a straggler commit that raced a fencer and lost; the whole transaction aborts.\n *\n * Both are DEFINITIVE lease loss — exactly like a dropped connection — and are routed to\n * `LeaseMonitor.fenced()` for immediate exit (bypassing the probe-miss tolerance, which exists\n * only for transient/ambiguous blips; a fenced epoch is never ambiguous).\n */\nexport class FencedError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"FencedError\";\n }\n}\n","/* Helipod Enterprise. Licensed under the Helipod Commercial License — see ee/LICENSE. */\n/**\n * Cross-process commit propagation for a Postgres-backed fleet (scale-seam #4, multi-process\n * variant): the in-memory `EmbeddedWriteFanoutAdapter` only fans a commit out within ONE process.\n * `NotifyingFanoutAdapter` (writer side) wraps it so every publish ALSO does\n * `pg_notify('helipod_commits', …)`; each follower's `ReplicaTailer` (`replica-tailer.ts`)\n * LISTENs for that channel (plus a wall-clock poll fallback, since NOTIFY delivery is not\n * guaranteed while a listener connection is reconnecting) and, on each wake, verbatim-applies the\n * primary's MVCC log onto its local replica and derives what to invalidate from that same batch —\n * no in-process `OplogDelta` ever crosses a process boundary.\n *\n * The `CommitChannelClient` seam below (the LISTEN/NOTIFY + parameterized-query slice of\n * `NodePgClient`) is shared by both the writer-side adapter here and the follower-side\n * `ReplicaTailer`. The slice-1 `CommitTailer` (which derived-only, never applied to a replica)\n * was removed in slice 2 once `ReplicaTailer` subsumed it.\n */\nimport type { PgQuerier } from \"@helipod/docstore-postgres\";\nimport type { EmbeddedWriteFanoutAdapter, EmbeddedWriteFanoutPayload, FanoutListener } from \"@helipod/runtime-embedded\";\n\n/** Exported (not just module-private) so other in-package NOTIFY senders — e.g. `node.ts`'s\n * `FrontierMonitor` notify-on-advance (T3.5) — target the exact same channel a `ReplicaTailer`\n * LISTENs on, without re-typing the literal a third time. */\nexport const COMMIT_CHANNEL = \"helipod_commits\";\n\n/**\n * The narrow slice of `NodePgClient` this module (and `ReplicaTailer`) depends on (LISTEN/NOTIFY\n * plus a plain parameterized query) — kept as a structural interface, matching the `PgClient` seam's\n * own philosophy of never tying engine/fleet logic to a concrete driver class. A `NodePgClient`\n * instance satisfies this; so does any test double that implements the same shape.\n */\nexport interface CommitChannelClient extends PgQuerier {\n /** LISTEN on `channel`; returns a closer. Rejecting (e.g. no LISTEN support) is tolerated by\n * `ReplicaTailer.start()`, which falls back to poll-only. */\n listen(channel: string, onNotify: (payload: string) => void): Promise<() => Promise<void>>;\n notify(channel: string, payload: string): Promise<void>;\n}\n\n/** Writer side: wraps the in-memory adapter; every publish ALSO does\n * `pg_notify('helipod_commits', String(commitTs))` so followers wake promptly instead of\n * waiting out the poll interval. NOTIFY is a latency optimization only — the poll fallback in\n * `CommitTailer` is the correctness path if it's ever dropped or a listener misses it. */\nexport class NotifyingFanoutAdapter implements EmbeddedWriteFanoutAdapter {\n constructor(\n private readonly inner: EmbeddedWriteFanoutAdapter,\n private readonly client: CommitChannelClient,\n ) {}\n\n publish(payload: EmbeddedWriteFanoutPayload): void {\n this.inner.publish(payload);\n // Fire-and-forget: a NOTIFY failure (e.g. transient connection hiccup) must not break the\n // in-process fan-out that just happened above — followers still catch up via the poll loop.\n void this.client.notify(COMMIT_CHANNEL, String(payload.commitTs)).catch(() => {});\n }\n\n subscribe(listener: FanoutListener): () => void {\n return this.inner.subscribe(listener);\n }\n}\n","/* Helipod Enterprise. Licensed under the Helipod Commercial License — see ee/LICENSE. */\n/**\n * `WriteForwarder` — the non-owner side of the fleet write path. Implements the engine's\n * per-shard `WriteRouter` seam (B2b, D1): for any shard this node does NOT currently hold,\n * `forward()` POSTs the call to that shard's owner (`/_fleet/run`, discovered per-shard from the\n * `shard_leases` row) and returns its JSON result. `isLocalWriter(shardId)` is a live view of the\n * node's held-shard set (`LeaseManager.currentEpoch(shardId) !== null` — the SAME source of truth\n * `relinquish()` uses for its own idempotency check), so a shard acquired/relinquished mid-flight\n * (balancer rebalancing, failover) takes effect on the very next call — no caching, no stale role.\n *\n * The forwarder learns each shard's writer URL from that shard's `shard_leases` discovery row (via\n * `LeaseManager.read(shardId)`), never from static config — so a failover to a new owner is picked\n * up by re-reading the lease. `writerUrlFor(shardId)` caches per shard (one node normally forwards\n * the same shard repeatedly) and refreshes on a POST failure, retrying once — same shape as the\n * shipped single-shard `writerUrl()` this replaces, generalized per shard.\n *\n * Single-hop guard (B2b, D1 spec-review edit): every forward body carries `forwarded: true`. If it\n * lands on a node that is ALSO not the shard's owner (a point-in-time race during rebalance\n * convergence), the receiver's `/_fleet/run` handler rejects with a typed, retryable\n * `NotShardOwnerError` instead of re-forwarding itself (which would let a forward chase a moving\n * target unboundedly). `forward()` treats that ONE error shape like a transport failure — refresh\n * the shard's cached URL and retry once — then surfaces whatever the second attempt does. Any OTHER\n * typed `HelipodError` (an OCC conflict, a validation failure, …) means a LIVE owner answered\n * DEFINITIVELY and is re-thrown unchanged, exactly as before.\n *\n * Task 3 (read-your-own-writes): `/_fleet/run`'s response carries the write's `commitTs`\n * (stringified — bigints don't survive `JSON.stringify`). If a `ReplicaTailer` has been attached\n * via `attachTailer()` (this node is a fleet SYNC node reading off a local replica), `forward()`\n * waits for that replica's watermark to reach `commitTs` before resolving — otherwise a client that\n * just wrote through this node could immediately read its own write's absence off a replica that\n * hasn't caught up yet. `promote()` also releases any pending wait: once this node becomes the\n * writer, replica catch-up is no longer the right thing to block on.\n */\nimport type { WriteRouter, ClientReplay } from \"@helipod/runtime-embedded\";\nimport { DEFAULT_SHARD, type ShardId } from \"@helipod/id-codec\";\nimport type { JSONValue } from \"@helipod/values\";\nimport { isHelipodError, helipodErrorFromJSON, NOT_SHARD_OWNER_CODE, type HelipodErrorJSON } from \"@helipod/errors\";\nimport type { LeaseManager } from \"./lease\";\nimport type { ReplicaTailer } from \"./replica-tailer\";\n\n/** Strip a single trailing slash so `${writerUrl}/_fleet/run` never doubles up (`//_fleet/run`). */\nfunction trimTrailingSlash(url: string): string {\n return url.endsWith(\"/\") ? url.slice(0, -1) : url;\n}\n\nexport interface WriteForwarderOptions {\n /** Admin bearer token — the `/_fleet/run` endpoint authenticates with the deployment admin key. */\n adminKey: string;\n /** This node's own advertised URL (recorded on the lease when/if it becomes the writer). */\n selfUrl: string;\n}\n\n/** Milliseconds to wait for the local replica to catch up to a forwarded write's `commitTs`\n * before giving up and serving the (possibly stale) read anyway. */\nconst RYOW_WAIT_MS = 5000;\n\n/**\n * The narrow seam `WriteForwarder` needs from `ReplicaTailer` — declared locally (rather than\n * typing `attachTailer` as `ReplicaTailer` itself) so tests can pass a lightweight structural stub\n * instead of standing up a real tailer (which needs a live Postgres primary + replica store).\n * A real `ReplicaTailer` satisfies this trivially since it's a strict subset of its public API.\n */\nexport type ReplicaWaiter = Pick<ReplicaTailer, \"waitFor\" | \"release\">;\n\nexport class WriteForwarder implements WriteRouter {\n private tailer: ReplicaWaiter | undefined;\n /** Guard each distinct malformed-response warning to once per process (independently — an absent\n * commitTs and an unparseable one are different failure modes and each deserves its own log\n * line) so a bad/old writer response doesn't spam the log on every subsequent forwarded write. */\n private warnedMissingCommitTs = false;\n private warnedUnparseableCommitTs = false;\n /** Per-shard writer-URL cache (B2b, T2): populated on first forward for a shard, refreshed on a\n * POST failure (transport error OR a not-the-owner rejection) and retried once. A node normally\n * forwards the same shard repeatedly, so caching avoids a `shard_leases` read on every call. */\n private readonly writerUrlCache = new Map<ShardId, string>();\n\n constructor(\n private readonly lease: LeaseManager,\n private readonly opts: WriteForwarderOptions,\n ) {}\n\n /** Attach the local `ReplicaTailer` this node reads off, enabling the read-your-own-writes wait\n * in `forward()`. Fleet WRITER nodes never call this — they have no replica to wait on. */\n attachTailer(t: ReplicaWaiter): void {\n this.tailer = t;\n }\n\n /** Called on promotion (sync → writer-ish). Releases any read-your-own-writes wait in flight —\n * this node no longer serves reads off a replica for its own forwarded writes, so waiting on\n * catch-up would only add latency. `isLocalWriter` itself needs no flip here: it already reads\n * the live `LeaseManager` state directly (see below), which promotion's `tryAcquire` calls\n * update as a side effect.\n *\n * NOTE (Fleet B3): a HYBRID promotion (multi-writer) does NOT call this — a hybrid keeps its\n * replica + tailer running past promotion and STILL serves reads (and forwarded writes to shards\n * it doesn't own) off the replica, so releasing the RYOW waits would be wrong. Only the\n * single-writer failover promotion (`promoteFleetNode`, no replica read path afterward) calls it. */\n promote(): void {\n this.tailer?.release();\n }\n\n /**\n * Fleet B3 (D2) — the HYBRID own-commit RYOW gate. Wired as the runtime's `beforeNotify` drain\n * hook: awaited before a LOCALLY-committed mutation's subscription re-runs fire, so those re-runs\n * (which read this node's replica, via the hybrid query path) don't observe the commit's absence on\n * a replica that hasn't applied it yet. Delegates to the SAME attached `ReplicaTailer.waitFor` the\n * forwarded-write RYOW uses (`attachTailer`), so local and forwarded writes share one catch-up\n * primitive. No-op when no tailer is attached (a single-writer node with no replica, or before the\n * tailer exists) or when nothing committed (`0n`). A timeout is swallowed — reactivity is\n * best-effort; the read path stays correct regardless (the re-run just fires against a replica that\n * is still catching up, no worse than the pre-gate behavior).\n */\n async waitForReplica(commitTs: bigint): Promise<void> {\n if (!this.tailer || commitTs === 0n) return;\n await this.tailer.waitFor(commitTs, RYOW_WAIT_MS);\n }\n\n /**\n * True iff this node currently holds `shardId`'s write lease (B2b, D1: per-shard membership, not\n * a whole-node binary role). `LeaseManager.currentEpoch(shardId) !== null` is the SAME live\n * held-set accessor `relinquish()` uses as its own idempotency check (`node.ts`) — so this can\n * never disagree with what the commit guard / relinquish dispatcher consider \"held\". Consulted\n * fresh on every call (never cached): a shard acquired or relinquished mid-flight (balancer\n * rebalance, failover, promotion) takes effect on the very next mutation.\n */\n isLocalWriter(shardId: ShardId = DEFAULT_SHARD): boolean {\n return this.lease.currentEpoch(shardId) !== null;\n }\n\n async forward(\n kind: \"mutation\" | \"action\",\n path: string,\n args: JSONValue,\n identity: string | null,\n shardId: ShardId = DEFAULT_SHARD,\n dedup?: { clientId: string; seq: number },\n ): Promise<{ value: JSONValue; commitTs?: number; shardId?: string; replay?: ClientReplay }> {\n // `forwarded: true` (B2b, D1 spec-review edit — the single-hop guard): tells the receiver this\n // is a fleet-internal hop, so IT must check ownership itself rather than trust the caller and\n // potentially re-forward unboundedly. `shardId` is what the receiver resolves the current owner\n // (and checks itself against) from.\n //\n // `idempotencyKey` (Fleet B3, D3 — effectively-once forwarding): minted ONCE, here, per LOGICAL\n // write — BEFORE the first attempt — and reused verbatim across the retry-once (a transport\n // failure or a stale-owner rejection) and the eventual re-routed POST. The receiving `/_fleet/\n // run` handler uses it to make a duplicate delivery replay rather than re-execute: two attempts\n // that both carry this SAME key can only ever land ONE durable write (see node.ts's commit guard\n // + packages/cli's http-handler catch-and-replay). A fresh UUID per `forward()` CALL (not\n // per-POST) is what makes this \"one key per logical write\" rather than \"one key per HTTP hop\".\n // `clientId`/`seq` (Receipted Outbox): the durable client dedup key rides the forward so the\n // OWNER classifies it (verdict §(c) repair 3) — coexists with the per-hop `idempotencyKey` (the\n // two are disjoint dedup mechanisms; the owner's classification runs BEFORE the fleet pre-select,\n // Risk R2). Absent for a non-outbox mutation, bit-for-bit today's body.\n const body = {\n path,\n args,\n identity,\n kind,\n shardId,\n forwarded: true,\n idempotencyKey: crypto.randomUUID(),\n ...(dedup ? { clientId: dedup.clientId, seq: dedup.seq } : {}),\n };\n const first = await this.writerUrlFor(shardId);\n let result: { value: JSONValue; commitTs?: string; shardId?: string; clientReplay?: ClientReplay };\n try {\n result = await this.post(first, body);\n } catch (firstErr) {\n // A HelipodError here means a LIVE node answered DEFINITIVELY. Two cases:\n // - `NOT_SHARD_OWNER_CODE` (the single-hop guard's answer): the cached URL is stale — this is\n // exactly a transport-style failure from the forwarder's perspective, worth ONE retry\n // against a freshly-read (hopefully current) owner.\n // - any OTHER typed error (an OCC conflict, a validation failure, the shard guard, …): the\n // mutation reached an owner and it DECIDED. Re-forwarding would only re-run it against the\n // same target, so propagate the typed error UNCHANGED (its status/code/retryable survive).\n // A non-HelipodError (fetch rejected: the owner may have failed over or the connection\n // blipped) is the original TRANSPORT-failure retry case, unchanged from before.\n const shouldRetry = !isHelipodError(firstErr) || firstErr.code === NOT_SHARD_OWNER_CODE;\n if (!shouldRetry) throw firstErr;\n let second: string;\n try {\n second = await this.refreshWriterUrlFor(shardId);\n } catch {\n throw firstErr;\n }\n result = await this.post(second, body);\n }\n // Owner-side client-dedup replay (Receipted Outbox): the owner classified this dedup forward as a\n // replay of a recorded verdict — surface it up so the sync node builds a `MutationReplay` instead\n // of a fresh ack. No replica RYOW wait: a replay committed nothing this call.\n if (result.clientReplay) {\n return { value: result.clientReplay.value ?? null, replay: result.clientReplay };\n }\n await this.waitForReplicaCatchUp(path, result.commitTs);\n return {\n value: result.value,\n // `commitTs` is stringified over the wire (bigints don't survive JSON) — coerced to `number`\n // here to match the `WriteRouter` seam's contract (consistent with how every other commitTs\n // consumer at this precision layer already converts, e.g. `Number(r.oplog?.commitTs ?? 0)` in\n // `runtime-embedded`'s sync path). The RYOW wait above already parsed the STRING via `BigInt`\n // directly, so full precision was preserved for the one place that actually needs it.\n commitTs: result.commitTs !== undefined ? Number(result.commitTs) : undefined,\n shardId: result.shardId,\n };\n }\n\n /** Discover shard `shardId`'s current writer URL — cached after the first read. */\n private async writerUrlFor(shardId: ShardId): Promise<string> {\n const cached = this.writerUrlCache.get(shardId);\n if (cached !== undefined) return cached;\n return this.refreshWriterUrlFor(shardId);\n }\n\n /** Force a fresh `shard_leases` read for `shardId`, overwriting any cached URL — the refresh half\n * of `writerUrlFor`'s cache, also used directly by `forward()`'s retry-once path. */\n private async refreshWriterUrlFor(shardId: ShardId): Promise<string> {\n const state = await this.lease.read(shardId);\n if (!state) throw new Error(`fleet: no writer lease found for shard '${shardId}' — cannot forward write`);\n this.writerUrlCache.set(shardId, state.writerUrl);\n return state.writerUrl;\n }\n\n private async post(\n writerUrl: string,\n body: {\n path: string;\n args: JSONValue;\n identity: string | null;\n kind: \"mutation\" | \"action\";\n shardId: ShardId;\n forwarded: boolean;\n idempotencyKey: string;\n clientId?: string;\n seq?: number;\n },\n ): Promise<{ value: JSONValue; commitTs?: string; shardId?: string; clientReplay?: ClientReplay }> {\n const res = await fetch(`${trimTrailingSlash(writerUrl)}/_fleet/run`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", authorization: `Bearer ${this.opts.adminKey}` },\n body: JSON.stringify(body),\n });\n const text = await res.text();\n let parsed: {\n value?: JSONValue;\n error?: string;\n errorJson?: HelipodErrorJSON;\n commitTs?: string;\n shardId?: string;\n /** Effectively-once forwarding (Fleet B3, D3): true when the receiver replayed a\n * previously-committed write instead of re-executing. Informational only here — `forward()`\n * surfaces `value`/`commitTs` uniformly regardless of whether this hop was a replay. */\n replayed?: boolean;\n /** Set instead of `value` when the replayed row's value wasn't recorded (the crash-window or\n * oversized-cap case) — `parsed.value ?? null` below already surfaces this as `value: null`. */\n valueMissing?: boolean;\n /** Receipted Outbox: the owner classified this dedup forward as a client-verdict replay — a\n * distinct field from the fleet `replayed`/`valueMissing` per-hop idempotency replay above. */\n clientReplay?: ClientReplay;\n };\n try {\n parsed = text ? (JSON.parse(text) as typeof parsed) : {};\n } catch {\n parsed = {};\n }\n if (!res.ok || parsed.error !== undefined) {\n // Rehydrate the writer's TYPED error when it serialized one (`errorJson`), so its\n // status/code/retryable identity survives the hop — the sync node's `/api/run` then maps it to\n // the same 4xx/5xx the writer would have returned locally. Falls back to a plain Error (an old\n // writer without `errorJson`, or a non-JSON body) so a mixed-version fleet still surfaces the\n // message.\n if (parsed.errorJson) throw helipodErrorFromJSON(parsed.errorJson);\n throw new Error(parsed.error ?? `fleet: writer /_fleet/run returned HTTP ${res.status}`);\n }\n return { value: parsed.value ?? null, commitTs: parsed.commitTs, shardId: parsed.shardId, clientReplay: parsed.clientReplay };\n }\n\n /** Waits for the local replica to observe `commitTsStr`, when a tailer is attached. No-op on a\n * fleet WRITER node (no tailer attached) or when the write committed nothing (`0`/absent). */\n private async waitForReplicaCatchUp(path: string, commitTsStr: string | undefined): Promise<void> {\n if (!this.tailer) return;\n if (commitTsStr === undefined) {\n if (!this.warnedMissingCommitTs) {\n this.warnedMissingCommitTs = true;\n console.warn(\n `fleet: writer's /_fleet/run response for ${path} had no commitTs — skipping read-your-own-writes wait`,\n );\n }\n return;\n }\n let commitTs: bigint;\n try {\n commitTs = BigInt(commitTsStr);\n } catch {\n if (!this.warnedUnparseableCommitTs) {\n this.warnedUnparseableCommitTs = true;\n console.warn(\n `fleet: writer's /_fleet/run response for ${path} had an unparseable commitTs ${JSON.stringify(commitTsStr)} — skipping read-your-own-writes wait`,\n );\n }\n return;\n }\n if (commitTs === 0n) return; // nothing committed (e.g. a read-only/no-op run) — nothing to wait for\n\n const outcome = await this.tailer.waitFor(commitTs, RYOW_WAIT_MS);\n if (outcome === \"timeout\") {\n console.warn(\n `fleet: read-your-own-writes wait timed out after ${RYOW_WAIT_MS}ms for ${path} at commitTs ${commitTs}`,\n );\n }\n }\n}\n","/* Helipod Enterprise. Licensed under the Helipod Commercial License — see ee/LICENSE. */\n/**\n * `ShardLeaseBalancer` — the deterministic, coordinator-free shard placement loop (B2b, D3).\n *\n * Every fleet node (writer OR sync) runs one. Each ~2s beat:\n * 1. HEARTBEAT this node's `fleet_nodes` presence row (its liveness signal — the balancer is the\n * presence heartbeat for a shardless SYNC node, which has no `shard_leases` row and no\n * LeaseMonitor; a writer node's LeaseMonitor probe also heartbeats presence, redundantly and\n * harmlessly).\n * 2. READ the live node set (`fleet_nodes` ∪ live `shard_leases` holders) and compute this node's\n * rendezvous TARGET shards — the shards HRW assigns to `myUrl` over that set. Every node derives\n * the same assignment from the same rows (`rendezvous.ts`), so there is nothing to negotiate.\n * 3. If this node is a pure SYNC node (`!isWriterish()`) and any NON-default target is currently\n * acquirable (orphaned/expired/missing) — a peer released it, or its holder died — request the\n * shipped whole-node PROMOTION (sync → writer-ish); a promoted node then acquires on the next\n * steps. (The DEFAULT shard has its own shipped election path — `LeaseManager.acquireLoop` — so\n * it is not a promotion trigger here; that avoids a redundant second promotion driver racing the\n * election.)\n * 4. Writer-ish node: ACQUIRE any target shard it does not hold that is acquirable (orphaned/\n * expired/missing). This is failover — un-damped and prompt; it NEVER touches a live non-target\n * holder's row (advisory locks + fencing already guarantee at most one holder, so acquisition is\n * always safe).\n * 5. Writer-ish node, under DAMPING (live set identical for ≥2 consecutive beats): gracefully\n * RELEASE any held shard NOT in its target set — a point-in-time self-fence (`releaseShard`, wired\n * in `node.ts`) that hands the shard to its rightful owner, which acquires it on its own next\n * beat (~2s), no TTL wait, no failover event. Damping keeps a flapping membership from thrashing\n * placement; acquisition (step 4) is intentionally NOT damped so a real death recovers promptly.\n *\n * The balancer owns ZERO SQL beyond the three lease reads — all acquire/release/promote effects are\n * injected thunks (`node.ts` wires them over `LeaseManager`/the runtime), so this class is a pure\n * orchestrator and unit-testable with lightweight fakes.\n */\nimport { DEFAULT_SHARD, shardIdList, type ShardId } from \"@helipod/id-codec\";\nimport { rendezvousOwner } from \"./rendezvous\";\n\n/** The narrow slice of `LeaseManager` the balancer reads — a structural interface so tests can pass a\n * fake, and so the balancer never reaches past these three reads into the lease's write surface. */\nexport interface BalancerLease {\n /** Upsert this node's `fleet_nodes` presence row, extending `expires_at` by the lease TTL. */\n heartbeatPresence(): Promise<void>;\n /** Distinct unexpired advertise URLs — `fleet_nodes` ∪ live `shard_leases.writer_url` holders. */\n liveNodes(): Promise<string[]>;\n /** Per-shard ownership snapshot: for each existing `shard_leases` row, its `writer_url` (null =\n * orphaned) and whether it has expired per the DB clock. A shard with NO row is absent from the map\n * (treated as acquirable). */\n readShardOwnership(): Promise<Map<ShardId, { writerUrl: string | null; expired: boolean }>>;\n}\n\nexport interface ShardLeaseBalancerDeps {\n lease: BalancerLease;\n /** This node's advertised URL — its identity in the rendezvous candidate set. */\n myUrl: string;\n /** Shard count (the fleet's fixed NUM_SHARDS). Drives the `shardIdList` this balancer ranges over. */\n numShards: number;\n /** Live per-shard held-set membership (`LeaseManager.currentEpoch(shardId) !== null`). */\n isHeld(shardId: ShardId): boolean;\n /** Is this node writer-ish (has completed promotion / booted as the writer)? A pure sync node only\n * heartbeats presence and may request promotion; it never acquires/releases. */\n isWriterish(): boolean;\n /** Acquire `shardId`'s lease (+ its per-slot advisory lock), evicting a wedged expired holder if\n * needed. Returns whether the shard is now held. One tick's attempt — a miss retries next beat. */\n tryAcquireShard(shardId: ShardId): Promise<boolean>;\n /** Gracefully release a held shard (point-in-time self-fence under the shard's commit mutex, then\n * the T3 relinquish-unwind) so its rightful owner can acquire it. */\n releaseShard(shardId: ShardId): Promise<void>;\n /** Run the shipped whole-node promotion (sync → writer-ish). Idempotent at the node level. */\n requestPromotion(): Promise<void>;\n /**\n * Fleet B3, D3 (effectively-once forwarding): reclaim `fleet_idempotency` rows older than the\n * TTL — a cheap indexed delete, run on every WRITER-ish beat (see `LeaseManager.sweepIdempotency`).\n * Optional so an older/stub `ShardLeaseBalancerDeps` (and every existing balancer test) needs no\n * change; a pure sync node never has this called regardless (see `tick()`).\n */\n sweepIdempotency?(): Promise<void>;\n /**\n * Multi-writer scale-out mode (B2b, D3 — the \"writer nodes vs sync nodes\" scaling knob, off by\n * default). When OFF (the default, and the shipped single-writer behavior): this node's target set is\n * EVERY shard (the sole writer owns them all), the balancer NEVER gracefully releases a live-held\n * shard to a peer, and a pure sync node is NEVER auto-promoted by rendezvous — additional nodes stay\n * READ REPLICAS (sync), reading off their local replica whose tailer sees every shard's commits.\n * Failover acquisition (picking up an orphaned/expired shard) and presence heartbeating are ON\n * regardless. When ON: full rendezvous distribution — each live node owns and writes its HRW share,\n * peers gracefully release a newcomer's share, and a sync node promotes to claim an orphaned share.\n * (Enabling it makes a joining node a CO-WRITER, whose own subscriptions do not yet receive\n * cross-writer reactivity for shards it doesn't hold — that is T6's proving ground.)\n */\n multiWriter?: boolean;\n /** Beat interval (ms). Default 2000. */\n beatMs?: number;\n /** Structured-log seam for a tick error, defaults to `console.error`. */\n log?: (msg: string) => void;\n}\n\nconst DEFAULT_BEAT_MS = 2000;\n\nexport class ShardLeaseBalancer {\n private readonly shards: ShardId[];\n private readonly multiWriter: boolean;\n private readonly beatMs: number;\n private readonly log: (msg: string) => void;\n private timer: ReturnType<typeof setInterval> | null = null;\n private stopped = false;\n private running = false;\n /** Canonical (sorted, comma-joined) live set from the PREVIOUS beat — damping compares against it:\n * a RELEASE only fires when the current live set equals this (identical for ≥2 consecutive beats). */\n private previousLiveSet: string | null = null;\n\n constructor(private readonly deps: ShardLeaseBalancerDeps) {\n this.shards = shardIdList(deps.numShards);\n this.multiWriter = deps.multiWriter ?? false;\n this.beatMs = deps.beatMs ?? DEFAULT_BEAT_MS;\n this.log = deps.log ?? ((m: string) => console.error(m));\n }\n\n /** Begin the periodic beat. The FIRST beat fires after `beatMs` (never synchronously) — prompt boot\n * acquisition is done explicitly via `acquireTargetsNow()`, not the periodic loop. Idempotent. */\n start(): void {\n if (this.timer !== null || this.stopped) return;\n this.timer = setInterval(() => void this.tick(), this.beatMs);\n }\n\n stop(): void {\n this.stopped = true;\n if (this.timer !== null) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n\n /** Resolve the live candidate set for a beat: the DB's live nodes ∪ this node itself (a node is\n * always live to itself — belt-and-braces so its own boot never depends on its presence row having\n * landed/propagated yet). Returns both the URL array (rendezvous input) and its canonical form. */\n private async liveCandidates(): Promise<{ urls: string[]; canonical: string }> {\n const live = await this.deps.lease.liveNodes();\n const set = new Set(live);\n set.add(this.deps.myUrl);\n const urls = [...set];\n return { urls, canonical: [...set].sort().join(\",\") };\n }\n\n /** This node's target shards. In single-writer mode (the default) the sole writer's targets are ALL\n * shards — byte-identical to B2a's acquire-all — so a joining node never steals a share. In\n * multi-writer mode it is this node's rendezvous (HRW) share over `liveUrls`. */\n private targetsFor(liveUrls: readonly string[]): Set<ShardId> {\n if (!this.multiWriter) return new Set(this.shards);\n const targets = new Set<ShardId>();\n for (const s of this.shards) {\n if (rendezvousOwner(s, liveUrls) === this.deps.myUrl) targets.add(s);\n }\n return targets;\n }\n\n /** A shard is acquirable iff it has no row (absent from the map), is orphaned (`writer_url NULL`), or\n * has expired — i.e. NOT held live by a peer. Acquisition only ever targets these; a live non-target\n * holder is never fenced by the balancer (that's failover's job). */\n private acquirable(\n shardId: ShardId,\n ownership: Map<ShardId, { writerUrl: string | null; expired: boolean }>,\n ): boolean {\n const o = ownership.get(shardId);\n return o === undefined || o.writerUrl === null || o.expired;\n }\n\n /**\n * Un-damped acquire pass over this node's CURRENT rendezvous targets — called at writer boot and on\n * promotion so the node holds its share PROMPTLY (before the ready line / before the first periodic\n * beat), rather than waiting out a 2s tick. In a single-node fleet the target set is EVERY shard, so\n * this acquires all N — byte-identical steady state to B2a's acquire-all. Seeds `previousLiveSet` so\n * the first periodic beat treats the boot membership as the damping baseline.\n */\n async acquireTargetsNow(): Promise<void> {\n const { urls, canonical } = await this.liveCandidates();\n const ownership = await this.deps.lease.readShardOwnership();\n const targets = this.targetsFor(urls);\n for (const s of this.shards) {\n if (targets.has(s) && !this.deps.isHeld(s) && this.acquirable(s, ownership)) {\n await this.deps.tryAcquireShard(s);\n }\n }\n this.previousLiveSet = canonical;\n }\n\n /** One balancer beat (see the class doc for the five steps). Never throws — a tick error is logged\n * and the loop continues; the next beat retries against fresh state. */\n async tick(): Promise<void> {\n if (this.stopped || this.running) return; // never overlap two beats\n this.running = true;\n try {\n await this.deps.lease.heartbeatPresence();\n const { urls, canonical } = await this.liveCandidates();\n const stable = canonical === this.previousLiveSet;\n this.previousLiveSet = canonical;\n\n const ownership = await this.deps.lease.readShardOwnership();\n const targets = this.targetsFor(urls);\n\n if (!this.deps.isWriterish()) {\n // Pure sync node: in MULTI-WRITER mode only, PROMOTE when a non-default target has come free (a\n // peer released it, or its holder died). The default shard is handled by the shipped acquire-\n // loop election, so it is excluded here. In single-writer mode a sync node stays a read replica\n // (only the election promotes it), so its reactivity keeps flowing through its replica tailer.\n if (this.multiWriter) {\n const wantsPromotion = [...targets].some(\n (s) => s !== DEFAULT_SHARD && this.acquirable(s, ownership),\n );\n if (wantsPromotion) await this.deps.requestPromotion();\n }\n return;\n }\n\n // Writer-ish: ACQUIRE acquirable targets not yet held (un-damped — prompt failover; ALWAYS on,\n // even in single-writer mode, so a sole writer picks up every orphaned/expired shard).\n for (const s of this.shards) {\n if (targets.has(s) && !this.deps.isHeld(s) && this.acquirable(s, ownership)) {\n await this.deps.tryAcquireShard(s);\n }\n }\n\n // RELEASE held non-targets — MULTI-WRITER only, and DAMPED (live set identical for ≥2 beats).\n // In single-writer mode `targets` is every shard, so there is nothing to release anyway; the\n // guard is belt-and-braces (and documents that graceful scale-out is the opt-in behavior).\n if (this.multiWriter && stable) {\n for (const s of this.shards) {\n if (this.deps.isHeld(s) && !targets.has(s)) {\n await this.deps.releaseShard(s);\n }\n }\n }\n\n // Fleet B3, D3: sweep expired `fleet_idempotency` rows on every writer-ish beat. Own try/catch\n // so a sweep hiccup never overshadows (or is overshadowed by) this beat's acquire/release work,\n // which has already completed by this point regardless.\n if (this.deps.sweepIdempotency) {\n try {\n await this.deps.sweepIdempotency();\n } catch (e) {\n this.log(`fleet: idempotency sweep failed: ${e instanceof Error ? e.message : String(e)}`);\n }\n }\n } catch (e) {\n this.log(`fleet: balancer tick failed: ${e instanceof Error ? e.message : String(e)}`);\n } finally {\n this.running = false;\n }\n }\n}\n","/* Helipod Enterprise. Licensed under the Helipod Commercial License — see ee/LICENSE. */\n/**\n * Rendezvous (highest-random-weight) hashing for the shard balancer (B2b, D3).\n *\n * Every fleet node runs the SAME pure function over the SAME live-node set (discovered from\n * `fleet_nodes` ∪ live `shard_leases` holders — see `LeaseManager.liveNodes`), so all nodes derive\n * an identical shard→owner assignment with NOTHING to negotiate. For each shard we compute a stable\n * 64-bit weight `hash(shardId, advertiseUrl)` per candidate node and pick the max — the owner. When\n * the membership set changes, HRW moves ONLY the shards whose max-weight node changed (minimality),\n * so a join/leave reshuffles a bounded, minimal set of shards rather than the whole ring.\n *\n * The weight is FNV-1a-64 over the UTF-8 bytes of `${shardId}\u0000${advertiseUrl}` — the same\n * hashing discipline `@helipod/id-codec`'s jump-hash router uses (FNV-1a-64 → a well-mixed 64-bit\n * key), reimplemented locally rather than importing that package's private helper so the rendezvous\n * weight function is self-contained and its exact bytes are pinned here. It MUST stay a pure function\n * of the two strings and identical across nodes/releases — every node's placement decision depends on\n * byte-for-byte agreement.\n */\nimport type { ShardId } from \"@helipod/id-codec\";\n\nconst U64_MASK = 0xffffffffffffffffn;\nconst FNV_OFFSET_BASIS = 0xcbf29ce484222325n;\nconst FNV_PRIME = 0x100000001b3n;\n\nconst utf8 = new TextEncoder();\n\n/** FNV-1a 64-bit hash of a byte string → a well-mixed 64-bit key (mirrors id-codec's `fnv1a64`). */\nfunction fnv1a64(bytes: Uint8Array): bigint {\n let h = FNV_OFFSET_BASIS;\n for (let i = 0; i < bytes.length; i++) {\n h ^= BigInt(bytes[i]!);\n h = (h * FNV_PRIME) & U64_MASK;\n }\n return h;\n}\n\n/**\n * The rendezvous weight of `advertiseUrl` for `shardId` — a stable 64-bit value. A space separates\n * the two fields so `(\"s1\",\"x\")` and `(\"s\",\"1x\")` can never collide into the same input — safe\n * because neither `shardId` nor `advertiseUrl` ever contains a space (shard ids are short identifiers\n * like `\"default\"`/`\"s1\"`; advertise URLs are `scheme://host:port` with no whitespace).\n */\nexport function rendezvousWeight(shardId: ShardId, advertiseUrl: string): bigint {\n return fnv1a64(utf8.encode(`${shardId}\u0000${advertiseUrl}`));\n}\n\n/**\n * The owner of `shardId` under rendezvous hashing over `liveUrls`: the node with the maximum weight,\n * ties broken by the lexicographically-smaller URL (so the choice is fully deterministic even in the\n * astronomically unlikely event of a 64-bit weight collision). Returns `\"\"` for an empty candidate\n * set (no live node — the caller always includes at least its own URL, so this is defensive only).\n * Pure and allocation-light; identical output on every node given the same `liveUrls` (order-\n * independent — the max/tie-break does not depend on the input array's order).\n */\nexport function rendezvousOwner(shardId: ShardId, liveUrls: readonly string[]): string {\n let bestUrl = \"\";\n let bestWeight = -1n;\n for (const url of liveUrls) {\n const w = rendezvousWeight(shardId, url);\n if (w > bestWeight || (w === bestWeight && url < bestUrl)) {\n bestWeight = w;\n bestUrl = url;\n }\n }\n return bestUrl;\n}\n","/* Helipod Enterprise. Licensed under the Helipod Commercial License — see ee/LICENSE. */\n/**\n * Fleet node composition (Task 6). Two entry points `helipod serve --fleet` calls around the\n * shared `bootProject` boot core:\n *\n * - `prepareFleetNode` — constructs the Postgres client + read-only store, sets up the lease\n * table, and makes ONE `tryAcquire()` attempt. Its result decides the whole boot: acquired →\n * a WRITER (writable Postgres store as the runtime store, drivers on, forwarder pre-promoted);\n * not acquired → a SYNC replica. A sync node does NOT run Postgres as its runtime store — it\n * boots a LOCAL file-backed embedded replica (`SqliteDocStore` at `<dataDir>/fleet-replica.db`)\n * behind a `SwitchableDocStore`, and reads/serves everything off that replica; the (read-only)\n * Postgres store is kept only as the tail source + promotion swap target. BOTH roles get the\n * pg_notify-wrapping `NotifyingFanoutAdapter` — a sync node's is inert until (if) it's later\n * promoted, at which point its commits immediately wake the remaining followers instead of\n * degrading them to the poll fallback for good. It returns the exact `createEmbeddedRuntime`\n * option deltas the caller threads through `bootProject`.\n *\n * - `startFleetNode` — called AFTER the runtime is built. For a sync node it starts the\n * `ReplicaTailer` (verbatim MVCC apply onto the local replica + cross-process reactive fan-out;\n * its `start()` doesn't resolve until the replica has caught up to the primary, which is this\n * node's ready gate) and the lease acquire loop, and on promotion runs the CRITICAL PROMOTION\n * ORDER (`promoteFleetNode`). For a writer node it just returns handles (already promoted).\n *\n * The HTTP layer consumes `FleetHandles`: `role()` decides whether to proxy public httpActions to\n * the writer, `writerUrl()` is that proxy target, `onPromoted()` lets it drop the proxy once this\n * node becomes the writer.\n */\nimport { rmSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { NodePgClient, PostgresDocStore } from \"@helipod/docstore-postgres\";\nimport { SqliteDocStore, NodeSqliteAdapter, BunSqliteAdapter } from \"@helipod/docstore-sqlite\";\nimport type { DatabaseAdapter } from \"@helipod/docstore-sqlite\";\nimport type { DocStore } from \"@helipod/docstore\";\nimport type { JSONValue } from \"@helipod/values\";\nimport { CommitGuardRejection } from \"@helipod/errors\";\nimport { DEFAULT_SHARD, shardIdList, type ShardId } from \"@helipod/id-codec\";\nimport {\n InMemoryWriteFanoutAdapter,\n clientReceiptsGuard,\n type EmbeddedRuntime,\n type EmbeddedWriteFanoutAdapter,\n type WriteRouter,\n} from \"@helipod/runtime-embedded\";\nimport { LeaseManager, type TryRunExclusiveOnShard, type IdempotencyReplay } from \"./lease\";\nimport { LeaseMonitor } from \"./lease-monitor\";\nimport { ShardLeaseBalancer } from \"./balancer\";\nimport { FencedError } from \"./fenced-error\";\nimport { NotifyingFanoutAdapter, COMMIT_CHANNEL } from \"./commit-notifier\";\nimport { WriteForwarder } from \"./forwarder\";\nimport { SwitchableDocStore } from \"./switchable-store\";\nimport { ReplicaTailer, type AppliedInvalidation } from \"./replica-tailer\";\nimport { keyToPointRange, docKeyToPointRange } from \"./ranges\";\n\n// Re-exported for existing callers/tests (`test/point-range.test.ts` imports these from\n// `../src/node`, and `index.ts` publicly exports `keyToPointRange` from here) — the\n// implementations now live in `ranges.ts` (moved, not copied) so `replica-tailer.ts` can reuse\n// them without a node.ts <-> replica-tailer.ts import cycle. See ranges.ts for the doc comments.\nexport { keyToPointRange, docKeyToPointRange } from \"./ranges\";\n\n/** The filename of a sync node's local embedded replica, under the serve data dir. */\nexport const REPLICA_DB_FILENAME = \"fleet-replica.db\";\n\n/** Default lease TTL (ms) when `HELIPOD_FLEET_LEASE_TTL_MS` is unset — mirrors `lease.ts`'s own\n * default so the two never drift. */\nexport const DEFAULT_LEASE_TTL_MS = 15_000;\n\n/** Default number of shards a fleet node runs (B2a). T5 owns the persist-once/env/`HELIPOD_FLEET_\n * SHARDS` story; this task threads it as a plain parameter (`prepareFleetNode`'s `numShards` dep),\n * defaulting here. The one node holds ALL N shard leases, commits in parallel across them (per-shard\n * commit-connection pool + per-shard `ShardedTransactor` mutexes), and F = min over the N frontiers. */\nexport const DEFAULT_NUM_SHARDS = 8;\n\n/** Idle-shard frontier-closing cadence (B2a, D5). The periodic beat runs every `FRONTIER_BEAT_MS`;\n * a local commit additionally schedules a coalesced beat `FRONTIER_COALESCE_MS` later (so an idle\n * shard un-pins F within ~10ms of a commit on a sibling shard, not the full 100ms). */\nexport const FRONTIER_BEAT_MS = 100;\nexport const FRONTIER_COALESCE_MS = 10;\n/** Frontier-lag warn threshold (ms): if `min(frontier_ts)` hasn't advanced in this long, the writer\n * logs a warning naming the pinning shard (D5 observability). Also the health endpoint's warn line. */\nexport const FRONTIER_LAG_WARN_MS = 5_000;\n\n/** A point-in-time frontier-lag reading for the health endpoint (D5): the fleet-wide fenced frontier\n * (`min(frontier_ts)` across all shard rows), how long (wall-clock ms) it has been stuck at that\n * value, and which shard is holding it there. */\nexport interface FrontierStats {\n frontier: bigint;\n lagMs: number;\n pinningShard: ShardId;\n}\n\n/**\n * Fleet frontier-lag monitor + (writer-only) idle-shard closer (B2a, D5). One runs per fleet node:\n *\n * - On the WRITER (`closeIdle: true`) each beat first CLOSES idle shards — `lease.closeIdleFrontiers`\n * allocates one `nextval` and advances every held shard whose frontier lags it — so an idle shard\n * can't pin `F = min(frontier_ts)` below the live commit position for more than a beat. A local\n * commit also schedules a coalesced beat (~10ms) so F reacts promptly to writes on sibling shards.\n * - On EITHER role each beat then READS all shard frontiers to compute `min` + the pinning shard and\n * track how long `min` has been stuck (wall-clock since it last advanced) → the `FrontierStats`\n * the health endpoint reports. A lag past `lagWarnMs` logs a warning naming the pinning shard\n * (once per stall, reset when it recovers), the console signal D5 asks for.\n *\n * A sync node runs it read-only (`closeIdle: false`) — it holds no leases, so it must NOT allocate\n * `nextval` (only the writer drives the frontier); it just observes whether the fleet frontier is\n * advancing.\n */\nexport class FrontierMonitor {\n private timer: ReturnType<typeof setInterval> | null = null;\n private coalesceTimer: ReturnType<typeof setTimeout> | null = null;\n private stopped = false;\n private running = false;\n private cached: FrontierStats | null = null;\n /** The last-observed `min(frontier_ts)` and the wall-clock time it was first seen — lag is the age\n * of the CURRENT min (how long it's been stuck), so both reset whenever min advances. */\n private lastMin: bigint | null = null;\n private minSinceMs: number;\n private warned = false;\n /** D4 — replica-lag tracking: wall-clock time this node's OWN tailer watermark was first observed\n * BEHIND the fleet frontier F, or `null` while it's caught up. Mirrors `minSinceMs`/`lastMin`'s\n * \"age of the current stuck condition\" shape, but for the replica catch-up gap rather than F's own\n * advance. Reset the instant `wm` reaches `F` again — a transient blip re-arms silently. */\n private replicaLagSinceMs: number | null = null;\n private replicaLagWarned = false;\n\n constructor(\n private readonly lease: LeaseManager,\n private readonly opts: {\n closeIdle: boolean;\n /** Per-shard commit-mutex seam the idle-frontier closer runs each bump under (see\n * `closeIdleFrontiers`). Required when `closeIdle` is true; ignored otherwise. */\n runExclusiveOnShard?: TryRunExclusiveOnShard;\n beatMs?: number;\n coalesceMs?: number;\n lagWarnMs?: number;\n now?: () => number;\n warn?: (msg: string) => void;\n /**\n * D4 — this node's own local replica-tailer watermark, when it has one: a sync node's\n * `ReplicaTailer`, or (in the hybrid/multi-writer regime) a writer's own read-replica tailer.\n * Omitted for a non-hybrid writer (it reads the primary directly — no replica, no lag to track).\n * Compared against the fleet frontier `F = min(frontier_ts)` each beat; `wm` falling more than\n * `lagWarnMs` behind `F` logs ONE operator warning naming this node's replica (`lease.advertiseUrl`\n * — there is only ever one replica per node, so naming the NODE identifies it), silent below the\n * threshold and while caught up. Same shape/once-ness as the pinning-shard warning above; applies\n * identically whether this monitor is a sync node's or a hybrid writer's (same `beat()` code path).\n */\n tailerWatermark?: () => bigint;\n /**\n * T3.5 (the fleet-connections bench's notify-diagnosis fix): fired at most once per beat, only\n * when this beat's `closeIdleFrontiers`/`bumpOrphanFrontiers` (or a concurrent commit) actually\n * pushed the fleet ceiling `F = min(frontier_ts)` past what the PRIOR beat observed. Neither\n * closer NOTIFYs on its own bare `UPDATE` — without this, an idle-shard close that finally\n * un-pins F is invisible to every `ReplicaTailer`'s LISTEN, and delivery silently falls through\n * to the tailer's `DEFAULT_POLL_MS` (1000ms) fallback even though NOTIFY itself is wired and\n * fires within ~1ms of the real commit (see `.superpowers/sdd/notify-diagnosis.md`). Omitted\n * entirely on a sync node (`closeIdle: false`) — only the writer's own beat performs the\n * advancing work, so only it needs to announce it. The callback owns its own failure handling\n * (fire-and-forget, matching `NotifyingFanoutAdapter.publish`'s own NOTIFY) — a rejected notify\n * must not, and structurally cannot, break the beat.\n */\n notifyOnAdvance?: (ceiling: bigint) => void;\n },\n ) {\n this.minSinceMs = (opts.now ?? Date.now)();\n }\n\n private get now(): () => number {\n return this.opts.now ?? Date.now;\n }\n\n start(): void {\n if (this.stopped || this.timer !== null) return;\n void this.beat(); // seed stats immediately so /api/health has a reading from the first request\n this.timer = setInterval(() => void this.beat(), this.opts.beatMs ?? FRONTIER_BEAT_MS);\n }\n\n /** Schedule a single coalesced beat `coalesceMs` out — called on each local commit so an idle\n * sibling shard un-pins F within ~10ms instead of waiting out the periodic beat. Multiple commits\n * inside the window collapse onto one beat. */\n triggerCoalesced(): void {\n if (this.stopped || this.coalesceTimer !== null) return;\n this.coalesceTimer = setTimeout(() => {\n this.coalesceTimer = null;\n void this.beat();\n }, this.opts.coalesceMs ?? FRONTIER_COALESCE_MS);\n }\n\n private async beat(): Promise<void> {\n if (this.stopped || this.running) return; // never overlap two beats (one nextval per beat)\n this.running = true;\n try {\n if (this.opts.closeIdle) {\n if (!this.opts.runExclusiveOnShard) {\n throw new Error(\"fleet: FrontierMonitor closeIdle requires a runExclusiveOnShard seam (bug)\");\n }\n // Close THIS node's held idle shards up to a fresh ceiling, then reuse that SAME ceiling\n // (one nextval/beat) to un-pin any ORPHANED shard's frontier (B2b, D4) — a shard nobody holds\n // (a peer died and its rows expired, or a graceful release before its new owner acquired)\n // would otherwise pin F below the live commit position indefinitely. WRITER beat only\n // (`closeIdle` is false on a sync node), so orphans move iff at least one writer is alive.\n const ceiling = await this.lease.closeIdleFrontiers(this.opts.runExclusiveOnShard);\n await this.lease.bumpOrphanFrontiers(ceiling);\n }\n const rows = await this.lease.readAllFrontiers();\n if (rows.length === 0) return;\n const min = rows[0]!.frontierTs; // ordered ascending → first row is the pinning shard\n const pinningShard = rows[0]!.shardId;\n const nowMs = this.now();\n const minBefore = this.lastMin; // snapshot the PRIOR beat's reading before this one overwrites it\n if (this.lastMin === null || min > this.lastMin) {\n this.lastMin = min;\n this.minSinceMs = nowMs;\n this.warned = false;\n // Notify-on-advance (T3.5): only when (a) this is the writer's own idle-closing beat, and (b)\n // there WAS a prior beat to compare against (skip the very first/cold-start beat — nothing\n // \"advanced\" relative to no baseline) — so this fires at most once per beat, only on a real\n // advance, never on a no-op close. See the constructor doc comment above for the full story.\n if (this.opts.closeIdle && minBefore !== null && this.opts.notifyOnAdvance) {\n try {\n this.opts.notifyOnAdvance(min);\n } catch {\n // A misbehaving callback must not interrupt the rest of THIS beat's bookkeeping (cached\n // stats, lag warnings below) — narrower than the outer catch-all, which would otherwise\n // also skip those for the remainder of the beat.\n }\n }\n }\n const lagMs = nowMs - this.minSinceMs;\n this.cached = { frontier: min, lagMs, pinningShard };\n const lagWarnMs = this.opts.lagWarnMs ?? FRONTIER_LAG_WARN_MS;\n if (lagMs > lagWarnMs && !this.warned) {\n this.warned = true;\n (this.opts.warn ?? ((m: string) => console.warn(m)))(\n `fleet: frontier stuck for ${lagMs}ms at ${min} — shard '${pinningShard}' is pinning F`,\n );\n }\n // D4 — replica-lag warning: this node's own tailer watermark falling behind the fleet frontier.\n // Same shape as the pinning-shard warning above (age-of-current-condition tracking, warn once,\n // silent below threshold, re-arms on recovery), applied to `wm` vs `F` instead of `min`'s own\n // advance. Only when this monitor was given a tailer to watch (sync nodes always have one; a\n // non-hybrid writer reads the primary directly and has none — `tailerWatermark` is omitted there).\n if (this.opts.tailerWatermark) {\n const wm = this.opts.tailerWatermark();\n if (wm < min) {\n if (this.replicaLagSinceMs === null) this.replicaLagSinceMs = nowMs;\n const replicaLagMs = nowMs - this.replicaLagSinceMs;\n if (replicaLagMs > lagWarnMs && !this.replicaLagWarned) {\n this.replicaLagWarned = true;\n (this.opts.warn ?? ((m: string) => console.warn(m)))(\n `fleet: replica for '${this.lease.advertiseUrl}' lagging ${replicaLagMs}ms behind frontier ${min} (watermark ${wm})`,\n );\n }\n } else {\n this.replicaLagSinceMs = null;\n this.replicaLagWarned = false;\n }\n }\n } catch {\n // A transient read/close failure must not kill the beat loop — the next beat retries. (On the\n // writer, a persistent failure to close idle shards surfaces as growing lag, which is exactly\n // what the warn above reports.)\n } finally {\n this.running = false;\n }\n }\n\n /** The most recent frontier reading, or null if no beat has completed yet. `lagMs` is recomputed\n * against the current clock so a caller between beats still sees a fresh age. */\n stats(): FrontierStats | null {\n if (this.cached === null) return null;\n return { ...this.cached, lagMs: this.now() - this.minSinceMs };\n }\n\n stop(): void {\n this.stopped = true;\n if (this.timer !== null) {\n clearInterval(this.timer);\n this.timer = null;\n }\n if (this.coalesceTimer !== null) {\n clearTimeout(this.coalesceTimer);\n this.coalesceTimer = null;\n }\n }\n}\n\n/**\n * D4 — a generic async-op serializer: returns a `run(op)` function where every queued `op` executes\n * only after the PREVIOUS one has settled (resolved OR rejected — `.then(op, op)`, so one op\n * rejecting never wedges the chain for the next). Callers that fire-and-forget a burst of overlapping\n * async calls (see `startFleetNode`'s `startDriversChained`/`stopDriversOnlyChained`) get a\n * deterministic EXECUTION order matching the ISSUE order, even when the callee itself is merely\n * idempotent (idempotence alone doesn't prevent a later-issued-but-faster call from resolving before\n * an earlier one, which is the race this closes). Each call to `createAsyncChain()` returns an\n * independent chain — callers needing one shared serialization point construct exactly one instance\n * and route every op through the same returned function.\n */\nexport function createAsyncChain(): (op: () => Promise<void>) => Promise<void> {\n let tail: Promise<void> = Promise.resolve();\n return (op: () => Promise<void>): Promise<void> => {\n const settled = tail.then(op, op);\n tail = settled.then(\n () => undefined,\n () => undefined,\n );\n return settled;\n };\n}\n\n/**\n * Derive the failover cadences from a single knob, the lease TTL. Every timing that must stay in a\n * fixed ratio to the TTL is computed here so one env var (`HELIPOD_FLEET_LEASE_TTL_MS`) scales the\n * whole clock coherently — a live writer must renew (probe) several times per TTL, and a follower\n * must retry-acquire several times per TTL, or a shortened TTL would either expire a healthy writer's\n * lease or notice a wedged one too slowly. The ratios are chosen so the DEFAULT TTL (15000ms)\n * reproduces the historical hard-coded constants EXACTLY — `probeMs = ttl/3 = 5000` (the old\n * `LeaseMonitor` default) and `retryMs = ttl*2/15 = 2000` (the old `LeaseManager` default) — so the\n * production default is byte-for-byte behavior-identical; only a shortened TTL (the wedged-writer\n * E2E's 4000ms, or an operator's tuning) changes anything.\n */\nexport function fleetProbeMs(ttlMs: number): number {\n return Math.max(1, Math.round(ttlMs / 3));\n}\nexport function fleetAcquireRetryMs(ttlMs: number): number {\n return Math.max(1, Math.round((ttlMs * 2) / 15));\n}\n\n/**\n * Bounded-writer-session timeouts (Fenced Frontier B1, D4) applied to every fleet node's pinned\n * Postgres connection — the single `NodePgClient` `prepareFleetNode` builds is the writer-capable one\n * (a sync node's same connection becomes the writer's on promotion via `pgStore.setWritable()`), so\n * it is bounded from boot. `idle_in_transaction=5s` kills a transaction a wedged writer leaves open\n * mid-commit (releasing the row lock a fencer's `evictExpired` needs); `statement=10s` caps any single\n * runaway statement. A NON-fleet single-node `serve`/`dev` (`makeStore` in `packages/cli`) constructs\n * `NodePgClient` WITHOUT this option and stays unbounded — see that call site.\n */\nexport const FLEET_WRITER_SESSION_TIMEOUTS = { idleInTransactionMs: 5_000, statementMs: 10_000 };\n\n/**\n * `persistence_globals` key a fleet deployment stamps once on the primary (C7) and every sync\n * node mirrors locally onto its replica. A replica file is a rebuildable mirror of ONE primary —\n * reused against a DIFFERENT primary (e.g. a data dir copied/reattached to another deployment) it\n * would otherwise silently serve foreign rows, since the file itself carries no identity. The\n * tailer never replicates `persistence_globals` (it applies only `documents`/`indexes` rows), so\n * this stamp can only ever land on the replica via a direct local write — see\n * `reconcileReplicaIdentity`.\n */\nexport const FLEET_DEPLOYMENT_ID_KEY = \"fleet:deploymentId\";\n\n/** Delete a SQLite replica file and its `-wal`/`-shm` sidecars — shared by the corrupted-file\n * recovery in `openSyncReplica` and the foreign-replica rebuild in `reconcileReplicaIdentity`. */\nfunction deleteReplicaFile(path: string): void {\n for (const suffix of [\"\", \"-wal\", \"-shm\"]) rmSync(path + suffix, { force: true });\n}\n\n/**\n * The `application_name` a fleet node stamps on its Postgres backends, derived from its advertise\n * URL so every node on a host is distinguishable in `pg_stat_activity`. Uses the URL's port (unique\n * per node on a host); if the URL is unparseable or portless, falls back to the raw string so the\n * name is always deterministic and non-empty. Exported so failover tooling/tests can reconstruct a\n * specific node's discriminator without guessing.\n */\n/**\n * True if the `documents` MVCC-log table already exists on `client`'s database. Used at writer\n * election (which runs BEFORE `setupSchema` creates the table) to decide whether a first-created\n * shard-lease row can safely seed its frontier from `SELECT MAX(ts) FROM documents` — referencing a\n * non-existent `documents` in that INSERT subquery would fail to plan on a fresh database. `to_regclass`\n * returns NULL for an absent relation rather than erroring, so this is a safe pre-DDL probe.\n */\nasync function documentsTableExists(client: NodePgClient): Promise<boolean> {\n const rows = await client.query(`SELECT to_regclass('documents') IS NOT NULL AS present`);\n return rows[0]?.present === true;\n}\n\nexport function fleetApplicationName(advertiseUrl: string): string {\n let discriminator = advertiseUrl;\n try {\n const port = new URL(advertiseUrl).port;\n if (port) discriminator = port;\n } catch {\n // Unparseable advertise URL — keep the raw string as the discriminator.\n }\n return `helipod-fleet-${discriminator}`;\n}\n\n/** Pick the SQLite adapter for the active runtime — Bun is primary (`bun:sqlite`), Node is\n * supported (`node:sqlite`). Same runtime split `packages/cli`'s `makeStore` uses; hardcoding\n * `NodeSqliteAdapter` would crash a Bun-hosted `helipod serve --fleet` with \"no such built-in\n * module: node:sqlite\" the moment a sync node tries to open its replica. */\nfunction replicaAdapter(path: string): DatabaseAdapter {\n const isBun = typeof (globalThis as { Bun?: unknown }).Bun !== \"undefined\";\n return isBun ? new BunSqliteAdapter({ path }) : new NodeSqliteAdapter({ path });\n}\n\n/**\n * Whether this deployment runs in MULTI-WRITER mode (`HELIPOD_FLEET_MULTI_WRITER`), read in ONE\n * place so `prepareFleetNode` (which decides the runtime store/queryStore wiring) and\n * `startFleetNode` (which decides the tailer/promotion wiring) can never disagree about a node's\n * shape. Multi-writer IS the hybrid regime (Fleet B3): every writer-ish node keeps a local replica\n * and serves queries from it while committing to the primary. Off (the production default) → the\n * shipped single-writer topology: the sole writer holds every shard and reads the primary, additional\n * nodes are pure read-replica sync nodes — no hybrid machinery anywhere (byte-identical to B2b).\n */\nexport function fleetMultiWriterEnabled(): boolean {\n return /^(1|true|yes)$/i.test(process.env.HELIPOD_FLEET_MULTI_WRITER ?? \"\");\n}\n\n/**\n * Whether group commit (Fleet B4) is enabled (`HELIPOD_GROUP_COMMIT`), read the SAME way as\n * `fleetMultiWriterEnabled` above — one place, so every `runtimeOptions` construction site in\n * `prepareFleetNode` reads the identical value. Threaded straight into `createEmbeddedRuntime`\n * (`EmbeddedRuntimeOptions.groupCommit`), which routes every shard's commits through the two-buffer\n * stage-then-flush committer loop. Default OFF at Fleet B4/T4 — T5 owns flipping the production\n * default once the throughput win is E2E-proven; unset/anything else → the byte-identical\n * single-commit path every shard already runs.\n */\nexport function groupCommitEnabled(): boolean {\n return /^(1|true|yes)$/i.test(process.env.HELIPOD_GROUP_COMMIT ?? \"\");\n}\n\nexport interface FleetHandles {\n role(): \"sync\" | \"writer\";\n /** The current writer's URL — the proxy target for public httpActions handled on a sync node. */\n writerUrl(): Promise<string>;\n /** Register a callback fired once, when this node is promoted from sync to writer. */\n onPromoted(cb: () => void): void;\n /** The current frontier-lag reading (D5 health observability): `min(frontier_ts)` across shards,\n * how long it's been stuck (ms), and the pinning shard. Null before the first frontier beat, or if\n * no shard rows exist yet. */\n frontierStats(): FrontierStats | null;\n /**\n * Group-commit counters (Fleet B4, T4 health observability): `EmbeddedRuntime.groupCommitStats()`'s\n * aggregate reading plus a derived `flushesPerSec` — a rolling delta between successive calls\n * (`(flushCount now - flushCount at the prior call) / elapsed seconds`), the simplest honest\n * throughput signal without a dedicated timer. The first call after boot (or after any gap) has no\n * prior sample, so it reports 0 for that one call. Structurally all-zero when `HELIPOD_GROUP_\n * COMMIT` is off (the underlying counters are never touched on the single-commit path) — never\n * null, unlike `frontierStats` (no \"before the first beat\" gating applies here).\n */\n groupCommitStats(): { lastBatchSize: number; maxBatchSize: number; flushCount: number; flushesPerSec: number };\n /** Per-shard ownership (B2b, D1): does THIS node currently hold `shardId`'s write lease? Backs\n * the `/_fleet/run` single-hop guard (`packages/cli`'s `http-handler.ts`) — delegates straight to\n * `WriteForwarder.isLocalWriter`, the same live held-set view the executor's own per-shard\n * router and `relinquish()` consult. */\n isLocalWriter(shardId: ShardId): boolean;\n /**\n * Effectively-once forwarding (Fleet B3, D3): read back `key`'s `fleet_idempotency` row for a\n * replay decision. Delegates to `LeaseManager.lookupIdempotency` — the SAME control table the\n * commit guard (`installCommitGuard`) writes into, on the SAME `client`, so a lookup immediately\n * after a catch always sees a just-committed sibling's row. `packages/cli`'s `/_fleet/run`\n * handler calls this BOTH before running (SELECT-first) and after catching a unique_violation on\n * this table (the concurrent-duplicate race's loser re-selecting the winner's row).\n */\n idempotencyLookup(key: string): Promise<IdempotencyReplay | null>;\n /** Best-effort post-run recording of a forwarded mutation's return value — see\n * `LeaseManager.recordIdempotencyValue`. */\n idempotencyRecordValue(key: string, value: JSONValue): Promise<void>;\n stop(): Promise<void>;\n}\n\n/** The createEmbeddedRuntime option deltas the caller threads through `bootProject`. `store` is the\n * node's RUNTIME (WRITE) store: the writable Postgres store for a writer, the `SwitchableDocStore`\n * (over the local replica, until promotion swaps in the Postgres store) for a single-writer sync\n * node, and — for a HYBRID (multi-writer) node — ALWAYS the Postgres store (mutations commit to the\n * primary), paired with `queryStore` for the replica-backed read path. */\nexport interface FleetRuntimeOptions {\n store: DocStore;\n writeRouter: WriteRouter;\n deferDrivers: boolean;\n fanoutAdapter?: EmbeddedWriteFanoutAdapter;\n /** Number of shards this node's runtime runs (B2a). Threaded to `createEmbeddedRuntime`, which\n * builds ONE `ShardedTransactor` (N per-shard mutexes) over the pooled store instead of the\n * single-shard `SingleWriterTransactor` when >1 — so cross-shard commits run in parallel. */\n numShards: number;\n /**\n * Fleet B3 hybrid nodes (D1) — the replica-backed QUERY store (the `SwitchableDocStore` over the\n * local replica). Set ONLY on a hybrid (multi-writer) node: `store` (above) is the primary, where\n * mutations commit, while queries/subscriptions read this replica store. `createEmbeddedRuntime`\n * builds a separate query-path transactor + QueryRuntime over it, and routes `observeTimestamp`\n * (fed by this node's ReplicaTailer post-apply) to the query oracle so a query snapshot never\n * exceeds the replica watermark. Absent → every query runs against `store` (single-writer/sync/\n * non-fleet), byte-identical to before B3.\n */\n queryStore?: DocStore;\n /**\n * Receipted Outbox (verdict §(c) placement) — the AUTHORITATIVE receipts store the Connect\n * handshake classifies/prunes against. Set to the PRIMARY (`pgStore`) on a SYNC node so the\n * handshake never reads the local replica (which carries no `client_mutations`/`client_floors`\n * receipts → spurious `known:false` resets / false kill-after-commit failures). Threaded straight\n * into `createEmbeddedRuntime`. Absent → the runtime uses `store` (writer boots, where `store` IS\n * the primary; and every non-fleet deployment). See `EmbeddedRuntimeOptions.receiptsStore`.\n */\n receiptsStore?: DocStore;\n /**\n * Fleet B3 hybrid RYOW (D2) — awaited in the runtime's serial fan-out `drain()` before a local\n * commit's subscription re-runs, so those re-runs (reading the replica) don't observe the commit's\n * absence on a replica that hasn't applied it yet. Wired to `forwarder.waitForReplica`. Set only on\n * a hybrid node. Absent → the drain is byte-identical to before B3.\n */\n beforeNotify?: (commitTs: bigint) => Promise<void>;\n /**\n * Fleet B4 (T4): group commit — resolved once via `groupCommitEnabled()` (above) and threaded\n * uniformly onto every boot shape (writer/sync × single-writer/hybrid). Unset/false →\n * `createEmbeddedRuntime` builds the byte-identical single-commit path, as shipped.\n */\n groupCommit?: boolean;\n /**\n * Triggers D1 — the stable-prefix accessor for `DriverContext.readLog`. In a fleet, N per-shard\n * commit connections land timestamps out of order, so the log tail is gap-free ONLY below\n * `min(shard_leases.frontier_ts)` (the fenced fleet frontier). Wired here to exactly that read (the\n * same `readAllFrontiers`-min the frontier-lag monitor uses), so `readLog` never surfaces — nor\n * skips — a change above an in-flight gap. Threaded onto every boot shape; consulted only when a\n * driver runs (post-promotion on a sync node), by which point `store` points at the primary.\n */\n stablePrefix?: () => Promise<bigint | null>;\n /**\n * Receipted Outbox — receipts-guard ownership handoff. Always `true` for a fleet node: fleet owns\n * installing the `clientReceiptsGuard()` exactly-once barrier on the CONCRETE Postgres store in\n * `armWriter` (before the epoch fence, release-on-re-arm), NOT on `store` — which for a sync node is\n * a `SwitchableDocStore` the runtime would register the guard on, only for it to silently vanish on\n * the promotion swapTo (leaving a promoted single-writer node's client mutations un-receipted → a\n * resent (clientId, seq) re-executes). Threaded to `createEmbeddedRuntime` so its `create()` skips\n * its own registration. See `EmbeddedRuntimeOptions.externalReceiptsGuard` and `armWriter`.\n */\n externalReceiptsGuard?: boolean;\n}\n\nexport interface FleetPrep {\n client: NodePgClient;\n /** The Postgres store. Writer: the runtime store (writable). Sync: the tail source + promotion\n * swap target (read-only until promoted) — NOT the runtime store (`runtimeOptions.store` is the\n * `SwitchableDocStore` over the local replica for a sync node). */\n pgStore: PostgresDocStore;\n /** The local file-backed replica the runtime reads queries through, and the switchable wrapper it\n * points at. Present for a single-writer SYNC boot (runtime store = the switchable) AND for a\n * HYBRID (multi-writer) boot of EITHER role (the switchable is `runtimeOptions.queryStore`, the\n * read path beside the primary write store). Absent only for a single-writer WRITER boot (no\n * replica — it reads the primary). */\n replica?: SqliteDocStore;\n switchable?: SwitchableDocStore;\n /** The on-disk path of `replica`, threaded through to `startFleetNode` so its C7\n * `reconcileReplicaIdentity` call (deferred there — see that function's doc comment) can rebuild\n * the file in place if needed. Present whenever `replica` is (sync boot, or any hybrid boot). */\n replicaPath?: string;\n lease: LeaseManager;\n forwarder: WriteForwarder;\n role: \"sync\" | \"writer\";\n /** The shard count decided at boot — threaded through to `startFleetNode` (acquire-all loop,\n * all-rows seed, per-shard commit guard, idle closer) and the tailer's `count(*) < N` ready gate. */\n numShards: number;\n runtimeOptions: FleetRuntimeOptions;\n}\n\n/**\n * Open (or recover) the on-disk SQLite replica file itself — no `SwitchableDocStore` wrapper. A\n * corrupted replica file (open or `setupSchema` throws — e.g. a torn write from a hard crash) is not\n * fatal: the file is a rebuildable mirror of the primary, so delete it and retry ONCE (a fresh\n * replica re-tails from scratch); a second failure is a real environment problem and propagates.\n * Also clears the SQLite `-wal`/`-shm` sidecars so a stale journal can't re-corrupt the fresh file.\n *\n * Shared by `openSyncReplica` (first boot, wraps the result in a NEW switchable) and\n * `reconcileReplicaIdentity`'s foreign-replica rebuild path, which instead repoints an EXISTING\n * switchable via `swapTo()` — see that function's doc comment for why minting a new switchable there\n * would be wrong.\n */\nasync function openReplicaFile(replicaPath: string): Promise<SqliteDocStore> {\n try {\n const replica = new SqliteDocStore(replicaAdapter(replicaPath));\n await replica.setupSchema();\n return replica;\n } catch (e) {\n console.warn(\n `fleet: local replica at ${replicaPath} failed to open (${e instanceof Error ? e.message : String(e)}) — ` +\n `deleting and rebuilding from the primary`,\n );\n deleteReplicaFile(replicaPath);\n // Retry ONCE — a second failure here is not a corrupt-file problem and must surface.\n const replica = new SqliteDocStore(replicaAdapter(replicaPath));\n await replica.setupSchema();\n return replica;\n }\n}\n\n/**\n * Open the sync node's local file-backed replica (`SqliteDocStore`) and wrap it in a fresh\n * `SwitchableDocStore`. See `openReplicaFile` for the corrupted-file recovery behavior.\n */\nexport async function openSyncReplica(\n replicaPath: string,\n): Promise<{ replica: SqliteDocStore; switchable: SwitchableDocStore }> {\n const replica = await openReplicaFile(replicaPath);\n return { replica, switchable: new SwitchableDocStore(replica) };\n}\n\n/**\n * C7: reconcile the sync node's local replica identity against the primary's `fleet:deploymentId`\n * stamp — called by `startFleetNode`'s sync path, immediately BEFORE the tailer is started. (An\n * earlier version of this code called it from `prepareFleetNode`, right after `openSyncReplica`\n * opened the replica — but that runs BEFORE `bootProject`, and `persistence_globals` (which\n * `pgStore.getGlobal` below reads) is only created by `store.setupSchema()` inside `bootProject`'s\n * `createEmbeddedRuntime`. On a fresh multi-node CONCURRENT first boot, a sync node could hit this\n * before ANY node's schema DDL had run and crash with \"relation persistence_globals does not exist\".\n * `startFleetNode`'s sync path now runs `pgStore.setupSchema()` itself — idempotent DDL, no writer\n * lock in read-only mode — immediately before calling this, so the check is self-sufficient on a\n * fresh database regardless of the writer's boot progress; see `startFleetNode` for the wiring.) A\n * replica file is only ever safe to tail\n * onto when it's either brand new or already stamped for THIS primary; otherwise it may carry rows\n * from a different deployment (e.g. a data dir reused/copied across environments) and must be\n * rebuilt before a single row is served off it.\n *\n * Cases:\n * - primary has no stamp yet (this sync node won the boot race against the writer): mint-adopt via\n * `writeGlobalIfAbsent` on the PG store — race-safe by contract, so every node that hits this\n * converges on whichever write landed first.\n * - fresh replica (no data, no stamp): adopt the primary's id locally, no warning, no rebuild.\n * - stamps match: proceed as-is.\n * - mismatch, or data present without a stamp (a pre-C7 replica): warn, delete the replica file\n * (+ `-wal`/`-shm`), reopen a fresh one, and adopt the primary's id onto it. The rebuild repoints\n * the CALLER's existing `switchable` via `swapTo()` rather than minting a new `SwitchableDocStore`\n * — by the time this runs (inside `startFleetNode`), that switchable is already the runtime's live\n * store (threaded from `prepareFleetNode` through `bootProject`), so replacing the object instead\n * of repointing it would orphan the runtime on the stale (deleted) replica file.\n */\nexport async function reconcileReplicaIdentity(deps: {\n pgStore: PostgresDocStore;\n replica: SqliteDocStore;\n switchable: SwitchableDocStore;\n replicaPath: string;\n}): Promise<{ replica: SqliteDocStore; switchable: SwitchableDocStore }> {\n const { pgStore, replicaPath } = deps;\n\n let primaryId = await pgStore.getGlobal(FLEET_DEPLOYMENT_ID_KEY);\n if (primaryId === null) {\n // The writer hasn't booted (or minted) yet — mint-adopt from here instead. Whichever node's\n // write wins the race is authoritative; re-read to pick up the actual winner (may not be ours).\n await pgStore.writeGlobalIfAbsent(FLEET_DEPLOYMENT_ID_KEY, crypto.randomUUID());\n primaryId = await pgStore.getGlobal(FLEET_DEPLOYMENT_ID_KEY);\n }\n\n const replicaId = await deps.replica.getGlobal(FLEET_DEPLOYMENT_ID_KEY);\n if (replicaId === primaryId) {\n return { replica: deps.replica, switchable: deps.switchable }; // already stamped for this primary\n }\n\n const hasData = (await deps.replica.maxTimestamp()) > 0n;\n if (replicaId === null && !hasData) {\n // Fresh replica — nothing foreign to worry about, just adopt silently.\n await deps.replica.writeGlobalIfAbsent(FLEET_DEPLOYMENT_ID_KEY, primaryId as JSONValue);\n return { replica: deps.replica, switchable: deps.switchable };\n }\n\n // Mismatch, or data present without a stamp (predates C7) — this file may carry rows from a\n // different deployment. Not fatal: rebuild from scratch, same recovery as a corrupted file.\n console.warn(\n `fleet: local replica at ${replicaPath} does not match the primary's deployment id ` +\n `(foreign replica, or predates identity stamping) — deleting and rebuilding from the primary`,\n );\n await deps.replica.close();\n deleteReplicaFile(replicaPath);\n const freshReplica = await openReplicaFile(replicaPath);\n await freshReplica.writeGlobalIfAbsent(FLEET_DEPLOYMENT_ID_KEY, primaryId as JSONValue);\n // Repoint the EXISTING switchable — do NOT mint a new one (see the doc comment above): whatever\n // holds a reference to `deps.switchable` (the runtime store, for a sync node) must keep working.\n deps.switchable.swapTo(freshReplica);\n return { replica: freshReplica, switchable: deps.switchable };\n}\n\n/**\n * Decide writer-vs-sync BEFORE the runtime is constructed: one `tryAcquire()` after the lease\n * table exists. This must run before `bootProject` because the acquire result determines the\n * store's writability, the fan-out adapter, whether drivers are deferred, and the forwarder's\n * starting role — all of which are `createEmbeddedRuntime` inputs.\n */\nexport async function prepareFleetNode(deps: {\n databaseUrl: string;\n advertiseUrl: string;\n adminKey: string;\n /** The serve data dir — the sync node's local replica is created at `<dataDir>/fleet-replica.db`. */\n dataDir: string;\n /** Lease TTL in ms — the single knob the whole failover clock scales from (see `fleetProbeMs`/\n * `fleetAcquireRetryMs`). Threaded from serve's fleet config, which reads\n * `HELIPOD_FLEET_LEASE_TTL_MS` (ops/test tuning; the wedged-writer E2E uses 4000). Default 15000\n * reproduces the historical constants exactly. */\n leaseTtlMs?: number;\n /** Number of shards this fleet runs (B2a). This task threads it as a plain parameter (default 8);\n * T5 owns the persist-once/`HELIPOD_FLEET_SHARDS`/mismatch-fail-fast story. Drives the commit\n * pool's connection set, the acquire-all loop, and the runtime's `ShardedTransactor`. */\n numShards?: number;\n}): Promise<FleetPrep> {\n const leaseTtlMs = deps.leaseTtlMs ?? DEFAULT_LEASE_TTL_MS;\n const numShards = deps.numShards ?? DEFAULT_NUM_SHARDS;\n // Canonical ordered shard ids (`[\"default\",\"s1\",…,\"s{N-1}\"]`) — the ONE source of truth for the\n // slot↔shardId contract shared by the commit pool (`commitPool.shards[slot]`), the per-slot\n // advisory locks (`tryAcquireShardLock(slot)`), and the acquire-all loop below. `shards[0]` is the\n // default shard (the writer-election slot).\n const shards = shardIdList(numShards);\n // Tag this node's Postgres backends so they're identifiable in `pg_stat_activity` — an operator can\n // see which fleet node owns a connection, and the writer self-exit E2E targets exactly one node's\n // backends via `pg_terminate_backend(... WHERE application_name = ...)`. Derived from the advertise\n // URL's port (unique per node on a host); falls back to the whole advertise URL if it has no port.\n const applicationName = fleetApplicationName(deps.advertiseUrl);\n // Writer-capable connection: bound its session (D4) — see FLEET_WRITER_SESSION_TIMEOUTS. Non-fleet\n // constructions (packages/cli's makeStore) pass no sessionTimeouts and stay unbounded.\n const client = new NodePgClient({\n connectionString: deps.databaseUrl,\n applicationName,\n sessionTimeouts: FLEET_WRITER_SESSION_TIMEOUTS,\n // Per-shard commit-connection pool (B2a, D1): one dedicated connection per shard for `commitWrite`\n // transactions, so different shards' commits run as genuinely concurrent Postgres transactions\n // (the pinned connection keeps heartbeats/eviction/setup/queries + LISTEN). Each slot's advisory\n // lock is taken on its own connection, so a shard's connection death releases exactly that shard.\n commitPool: { shards },\n });\n // Read-only until (and unless) this node wins the lease. A follower still runs the idempotent\n // DDL in setupSchema but does NOT contend for the writer advisory lock (see PostgresDocStore).\n const pgStore = new PostgresDocStore(client, { readOnly: true });\n // `applicationName` is recorded on the lease row (writer_app_name) so a future D4 eviction\n // fencer can `pg_terminate_backend` the exact wedged holder's connection by name.\n const lease = new LeaseManager(client, {\n advertiseUrl: deps.advertiseUrl,\n applicationName,\n ttlMs: leaseTtlMs,\n retryMs: fleetAcquireRetryMs(leaseTtlMs),\n });\n const forwarder = new WriteForwarder(lease, { adminKey: deps.adminKey, selfUrl: deps.advertiseUrl });\n\n // EVERY fleet node — writer or sync — gets the pg_notify-wrapping fan-out adapter, not just the\n // node that wins the lease at boot. A sync node never commits (`InMemoryWriteFanoutAdapter.publish`\n // is only ever invoked by a LOCAL commit), so wrapping it here is inert until this node is\n // eventually promoted (see the promotion order in `startFleetNode`) — at which point its commits\n // immediately NOTIFY the remaining followers instead of leaving them degraded to the `pollMs`\n // fallback in the tailer for the rest of the process lifetime.\n const fanoutAdapter = new NotifyingFanoutAdapter(new InMemoryWriteFanoutAdapter(), client);\n\n // Probed ONCE, up front — nothing between here and `startFleetNode`'s sync/writer branches creates\n // `documents` (that's `bootProject`'s `store.setupSchema()`, which runs AFTER this function\n // returns), so this single read is valid for every seed decision below: `lease.setup()`'s all-N-row\n // pre-seed (D4) AND the default shard's own `tryAcquire` seed (the original F1×N residual-window\n // fix) both gate on the SAME boolean — a fresh database (no `documents` yet) seeds every row's\n // frontier to 0 (correct: no history to protect), an upgrade (already exists) seeds every row to the\n // store's real max (correct: never momentarily visible below it).\n const documentsExist = await documentsTableExists(client);\n // D4 — pre-seed all N shard rows at DDL time (same seed as tryAcquire's first-creation INSERT; see\n // `LeaseManager.setup`'s doc comment for why this reversal of B2a's \"no pre-seeding\" call is safe):\n // the tailer's `count(*) < numShards → not-ready` gate is satisfied the instant this returns, so a\n // concurrent multi-writer boot no longer stalls waiting for a writer's acquire-all pass to finish.\n await lease.setup(shards, documentsExist);\n // B2b, D3: write this node's `fleet_nodes` presence row FIRST — BEFORE the writer-election\n // `tryAcquire`, so a node that LOSES the election and boots sync is already visible in every peer's\n // live set (and thus a rendezvous participant) from the instant it exists, not only once it holds a\n // shard. This is the bootstrap-deadlock fix: a shardless node must be discoverable or scale-out\n // never happens. Idempotent upsert; the balancer/probe re-heartbeats it on the TTL clock.\n await lease.heartbeatPresence();\n // Writer election is the DEFAULT shard's lock (slot 0). In B2a single-node the node that wins it\n // holds ALL shards (the remaining slots are acquired in `startFleetNode`'s writer/promotion arming);\n // drivers run on the default-shard holder only (D5). `tryAcquire` takes slot 0's per-shard lock in\n // pool mode, else the legacy writer lock (PGlite/no-pool) — same election either way. The row was\n // very likely already created (seeded) by `lease.setup()` above, so this normally lands on the\n // `ON CONFLICT` branch (frontier untouched, already correctly seeded) — `documentsExist` is passed\n // regardless as belt-and-braces for the (never, in production) case this is the row's first creation.\n const acquired = await lease.tryAcquire(DEFAULT_SHARD, 0, documentsExist);\n\n // Fleet B3: multi-writer IS the hybrid regime. A hybrid node — of EITHER boot role — keeps a local\n // replica and serves queries from it while committing to the primary, so BOTH branches below open\n // the replica and wire it as `runtimeOptions.queryStore` (the write store stays the PRIMARY). The\n // `beforeNotify` RYOW gate delegates to `forwarder.waitForReplica` (which the forwarder answers via\n // the tailer `startFleetNode` attaches). Off → the shipped single-writer/sync store wiring below.\n const multiWriter = fleetMultiWriterEnabled();\n const replicaPath = join(deps.dataDir, REPLICA_DB_FILENAME);\n const beforeNotify = (commitTs: bigint): Promise<void> => forwarder.waitForReplica(commitTs);\n // Fleet B4 (T4): group commit — resolved ONCE here, threaded uniformly onto every\n // `runtimeOptions` literal below regardless of boot shape (writer/sync × single-writer/hybrid).\n const groupCommit = groupCommitEnabled();\n // Triggers D1 — the fleet stable prefix `readLog` scans to: `min(shard_leases.frontier_ts)` across\n // all shard rows (the same fenced frontier the frontier-lag monitor reads). `readAllFrontiers`\n // returns rows ordered by frontier ascending, so `[0]` is the pinning shard. Null while no shard\n // row exists yet (pre-seed boot) → `readLog` falls back to `store.maxTimestamp()`.\n const stablePrefix = async (): Promise<bigint | null> => {\n const rows = await lease.readAllFrontiers();\n return rows.length > 0 ? rows[0]!.frontierTs : null;\n };\n\n if (acquired) {\n // Writer boot: make the Postgres store writable and promote the forwarder so writes execute\n // locally. C7: the deployment-id mint (writeGlobalIfAbsent) needs `persistence_globals` to already\n // exist, which `bootProject`'s `createEmbeddedRuntime` only creates via `store.setupSchema()`\n // AFTER this function returns — so the mint itself happens in `startFleetNode`'s writer branch,\n // not here. See that comment for the full rationale.\n pgStore.setWritable();\n forwarder.promote();\n if (multiWriter) {\n // HYBRID writer boot: the runtime commits to the writable Postgres store (primary) but serves\n // queries from a local replica (queryStore). `startFleetNode` starts the ReplicaTailer over that\n // replica. Drivers ON (this node holds the default ring at boot).\n const { replica, switchable } = await openSyncReplica(replicaPath);\n return {\n client, pgStore, replica, switchable, replicaPath, lease, forwarder, role: \"writer\", numShards,\n runtimeOptions: {\n store: pgStore, writeRouter: forwarder, deferDrivers: false, fanoutAdapter, numShards,\n queryStore: switchable, beforeNotify, groupCommit, stablePrefix, externalReceiptsGuard: true,\n },\n };\n }\n // Single-writer boot: the runtime runs directly on the writable Postgres store — no replica, no\n // switchable, no query-path split (it reads the primary, as shipped).\n return {\n client, pgStore, lease, forwarder, role: \"writer\", numShards,\n runtimeOptions: { store: pgStore, writeRouter: forwarder, deferDrivers: false, fanoutAdapter, numShards, groupCommit, stablePrefix, externalReceiptsGuard: true },\n };\n }\n\n // Sync boot: open the local file-backed replica behind a SwitchableDocStore. Drivers deferred until\n // (if) promoted; writes forwarded to the current writer.\n //\n // C7: the replica's deployment-id stamp is reconciled against the primary's in `startFleetNode`,\n // right before the tailer starts — NOT here. `persistence_globals` (which the reconcile reads via\n // `pgStore.getGlobal`) is only created by `store.setupSchema()` inside `bootProject`'s\n // `createEmbeddedRuntime`, which runs AFTER this function returns; reading it here would crash on a\n // concurrent multi-node first boot, before ANY node's schema DDL has run. See\n // `reconcileReplicaIdentity`'s doc comment for the full rationale.\n const { replica, switchable } = await openSyncReplica(replicaPath);\n if (multiWriter) {\n // HYBRID sync boot: the runtime's WRITE store is the (read-only-until-promoted) PRIMARY, and the\n // replica is the queryStore. Unlike the single-writer sync node below (whose runtime store IS the\n // replica, swapped to the primary on promotion), a hybrid's store is ALREADY the primary — so a\n // promotion just makes it writable (no swapTo) and the tailer KEEPS running to serve replica reads.\n // No local commit lands on the read-only primary meanwhile (writes forward via `forwarder`).\n return {\n client, pgStore, replica, switchable, replicaPath, lease, forwarder, role: \"sync\", numShards,\n runtimeOptions: {\n // `receiptsStore: pgStore` — the Connect handshake classifies/prunes against the PRIMARY, not\n // the replica (which carries no receipts). Redundant here (`store` IS `pgStore` for a hybrid),\n // but set explicitly so the sync-node invariant is uniform across both sync shapes.\n store: pgStore, writeRouter: forwarder, deferDrivers: true, fanoutAdapter, numShards,\n queryStore: switchable, receiptsStore: pgStore, beforeNotify, groupCommit, stablePrefix, externalReceiptsGuard: true,\n },\n };\n }\n // Single-writer sync boot: the runtime store is the replica behind the SwitchableDocStore; the\n // read-only Postgres store is the tail source + promotion swap target only. `receiptsStore: pgStore`\n // routes the Connect handshake's outbox classification/ack-prune to the authoritative PRIMARY —\n // without it, the handshake reads the replica (no receipts) and spuriously resets the client\n // (verdict §(c) placement; the mutation-path dedup already forwards its own classification to the\n // owner via `forwarder`, so only the handshake needed this seam). See `receiptsStore`'s doc comment.\n return {\n client, pgStore, replica, switchable, replicaPath, lease, forwarder, role: \"sync\", numShards,\n runtimeOptions: { store: switchable, writeRouter: forwarder, deferDrivers: true, fanoutAdapter, numShards, receiptsStore: pgStore, groupCommit, stablePrefix, externalReceiptsGuard: true },\n };\n}\n\nexport interface StartFleetNodeDeps {\n client: NodePgClient;\n /** The Postgres store — the tail source + promotion swap target (sync), or the live runtime store\n * (writer, in which case `startFleetNode` just returns handles). */\n pgStore: PostgresDocStore;\n runtime: EmbeddedRuntime;\n lease: LeaseManager;\n forwarder: WriteForwarder;\n /** Sync only: the local replica the tailer applies onto, and the switchable the runtime reads\n * through (swapped to the Postgres store on promotion). Absent/ignored for a writer boot. */\n replica?: SqliteDocStore;\n switchable?: SwitchableDocStore;\n /** Sync only: `replica`'s on-disk path — needed here (not just in `prepareFleetNode`) because the\n * C7 `reconcileReplicaIdentity` check now runs in THIS function, right before `tailer.start()`. */\n replicaPath?: string;\n /** Process-exit indirection (C4/C5). Injected so tests observe exits instead of killing the runner;\n * defaults to `console.error` + `process.exit(1)`. Fires on writer lease loss (the lease monitor)\n * and on a failed promotion step. */\n onExit?: (reason: string) => void;\n /** Number of shards this node runs (B2a) — from `prepareFleetNode`'s decision (`FleetPrep.numShards`).\n * The writer/promotion arming acquires all N shard leases (slots 1…N-1 beyond the default), seeds\n * all N frontiers before ready, and drives the idle-shard closer over them. Defaults to 1 so an\n * older single-shard call site (the B1 lifecycle tests that drive `startFleetNode` directly) is\n * byte-identical — one shard, one lease, one frontier. */\n numShards?: number;\n}\n\n/** Production exit policy: log and terminate so the node restarts and rejoins the fleet as a fresh\n * sync node. Overridable via `StartFleetNodeDeps.onExit` (tests inject a spy). */\nfunction defaultFleetExit(reason: string): void {\n console.error(`fleet: ${reason} — exiting so this node restarts and rejoins as a sync replica`);\n process.exit(1);\n}\n\n/** The seam the C5 promotion wrap touches — narrow structural spies over the promotion sequence,\n * monitor start, promoted-callback fan-out, and the exit indirection. */\nexport interface PromotionRunDeps {\n /** The CRITICAL PROMOTION ORDER (`promoteFleetNode`), as a thunk. */\n promote: () => Promise<void>;\n /** Start the writer lease monitor — this node is now the writer and must self-exit on lease loss. */\n startMonitor: () => void;\n /** Notify the http layer to drop its writer proxy. */\n firePromoted: () => void;\n /** Exit indirection — any promotion-step failure routes here (a half-promoted node must not linger). */\n onExit: (reason: string) => void;\n}\n\n/**\n * C5 promotion error policy: wrap the promotion sequence so ANY step failure is caught, logged, and\n * turned into an exit rather than left as a silent unhandled rejection with the node stuck\n * half-promoted (writable pg store, un-swapped runtime, no drivers). On success the lease monitor is\n * started (writer self-exit is now armed) and the http layer is told to drop its proxy. Fires exit at\n * most once by construction — it's invoked once per node (guarded by the caller's `promoting` flag).\n */\nexport async function runPromotion(deps: PromotionRunDeps): Promise<void> {\n try {\n await deps.promote();\n deps.startMonitor(); // this node is the writer now — arm self-exit-on-lease-loss\n deps.firePromoted();\n } catch (e) {\n deps.onExit(`promotion failed (${e instanceof Error ? e.message : String(e)})`);\n }\n}\n\n/** The minimal seams the CRITICAL PROMOTION ORDER touches — narrow structural interfaces (not the\n * concrete runtime/store/tailer classes) so the sequence + its ordering can be unit-tested with\n * lightweight spies. A real runtime/`PostgresDocStore`/`SwitchableDocStore`/`ReplicaTailer` satisfy\n * these trivially. */\nexport interface PromotionDeps {\n runtime: { observeTimestamp(ts: bigint): void; startDrivers(): Promise<void> };\n pgStore: { maxTimestamp(): Promise<bigint>; setWritable(): void };\n switchable: { swapTo(next: DocStore): void };\n forwarder: { promote(): void };\n tailer: { stop(): Promise<void> };\n replica: { close(): void | Promise<void> };\n}\n\n/**\n * The CRITICAL PROMOTION ORDER (see design §1), run exactly once when a sync node wins the lease:\n *\n * 1. `observeTimestamp(maxTimestamp())` — advance the local oracle past ALL primary history, so\n * this node's first allocated write ts can't collide with or precede one already committed.\n * 2. `pgStore.setWritable()` — the Postgres store now accepts writes.\n * 3. `switchable.swapTo(pgStore)` — the runtime store repoints from the local replica to the\n * (now writable) Postgres store; all subsequent reads/writes go straight to Postgres.\n * 4. `forwarder.promote()` — local writes execute here instead of being forwarded (also releases\n * any in-flight read-your-own-writes waits on the replica — moot now).\n * 5. `await tailer.stop()` — stop tailing; the writer drives its OWN fan-out from here on. Must\n * precede closing the replica (the tailer writes to it).\n * 6. close the swapped-out replica (its file is left on disk — a rebuildable mirror).\n * 7. `await runtime.startDrivers()` — scheduler/reaper/etc. wake now that this node is the writer.\n */\nexport async function promoteFleetNode(deps: PromotionDeps): Promise<void> {\n deps.runtime.observeTimestamp(await deps.pgStore.maxTimestamp()); // 1\n deps.pgStore.setWritable(); // 2\n deps.switchable.swapTo(deps.pgStore as unknown as DocStore); // 3\n deps.forwarder.promote(); // 4 (also releases RYOW waits)\n await deps.tailer.stop(); // 5 (before closing the replica)\n await deps.replica.close(); // 6 (swapped-out delegate)\n await deps.runtime.startDrivers(); // 7\n}\n\n/**\n * Install the epoch-fenced commit guard (Fenced Frontier B1, D3) on `pgStore`. Runs inside every\n * `commitWrite` transaction, after the row inserts, before COMMIT — the SAME row as the lease\n * (`shard_leases`) advances the durable-commit frontier chain (`prev_ts := frontier_ts, frontier_ts\n * := commitTs`) predicated on THIS node's epoch still being current, so frontier publication,\n * fencing, and the lease are one row with zero extra round-trips. `lease.currentEpoch()` is read\n * LIVE on every commit (not a snapshot taken at install time) so a later re-promotion's epoch bump\n * is honored automatically. Zero rows updated (a stale/superseded epoch) throws `FencedError`, which\n * aborts the whole transaction — AND calls `onFenced(shardId, reason)` before throwing so the caller\n * can react (B2b, D2: `startFleetNode` wires this straight to `relinquish(shardId, reason)` — drop\n * JUST this shard, keep serving everything else — never to a whole-node exit; see `relinquish` below\n * for why `LeaseMonitor.fenced()`/`onExit` are NOT reached from here anymore). Called at writer boot\n * AND on promotion success — see the two call sites below.\n *\n * Returns the `addCommitGuard` unregister handle (Receipted Outbox decision 2 — the guard\n * slot→chain migration). `armWriter` re-arms on EVERY promotion; a caller that calls\n * `installCommitGuard` again WITHOUT first calling the PRIOR returned unregister function stacks a\n * duplicate epoch-fence guard on the chain — duplicate frontier bumps + duplicate\n * `fleet_idempotency` INSERTs at the same ts, so every subsequent forwarded commit self-PK-collides\n * and aborts. See `armWriter`'s `unregisterCommitGuard` handling below for the required pattern.\n */\nexport function installCommitGuard(\n pgStore: PostgresDocStore,\n lease: LeaseManager,\n onFenced: (shardId: ShardId, reason: string) => void,\n): () => void {\n return pgStore.addCommitGuard(async (q, units, shardId) => {\n // Fleet B4 (batch-shaped guard): `commitWriteBatch` invokes this ONCE per transaction over ALL its\n // units (`{ts, meta}` in unit/ts order); a single `commitWrite` reaches here as a one-unit array.\n // We fence ONCE, advance the frontier ONCE to the batch's last ts, and loop the per-unit idempotency\n // INSERTs each at its own ts. ANY throw here aborts the WHOLE batch — no unit lands (D1).\n //\n // B2a: the guard is PER-SHARD. `commitWriteBatch` routes each batch to its shard's connection and\n // passes that `shardId` here; fence against THAT shard's epoch (the per-shard epoch map) and\n // advance THAT row's frontier chain. A batch on shard s2 whose s2 epoch was superseded aborts\n // and relinquishes ONLY s2 (B2b), while the other shards' commits are unaffected.\n const epoch = lease.currentEpoch(shardId);\n if (epoch === null) {\n // Structurally shouldn't happen — the guard is only ever installed after this node has acquired\n // every shard it commits on (writer boot / promotion arming). Treat defensively as fenced rather\n // than let an inconsistent guard silently allow an unfenced commit through.\n onFenced(shardId, `commit guard invoked with no acquired epoch for shard '${shardId}'`);\n throw new FencedError(`commit fenced: this node has not acquired a shard_leases epoch for shard '${shardId}'`);\n }\n // The batch's frontier lands at ts_N (the last, largest unit ts) — the units are ts-ordered, so\n // this is the batch high-water mark. `frontier_ts = GREATEST(frontier_ts, $1)`, not a bare `= $1`\n // — two layers of defense against a frontier regression: (1) the idle-shard closer now takes THIS\n // shard's commit mutex before bumping its frontier (`closeIdleFrontiers`), so nothing can have\n // raised it mid-commit on the same epoch, and a cross-epoch writer is fenced by the `epoch = $3`\n // predicate; (2) GREATEST makes the write monotone regardless. The tailer already tolerates\n // `frontier_ts` exceeding the last committed doc ts, so keeping the strictly-larger is always safe.\n // `prev_ts := frontier_ts` records the pre-BATCH frontier as the chain's previous link — the whole\n // batch appears atomically to the tailer as ts's 1..N landing with F = ts_N (D3).\n const tsN = units[units.length - 1]!.ts;\n const rows = await q.query(\n `UPDATE shard_leases SET prev_ts = frontier_ts, frontier_ts = GREATEST(frontier_ts, $1) WHERE shard_id = $2 AND epoch = $3 RETURNING epoch`,\n [tsN, shardId, epoch],\n );\n if (rows.length === 0) {\n onFenced(shardId, `commit guard found 0 rows for shard '${shardId}' epoch ${epoch} — superseded by another writer`);\n throw new FencedError(`commit fenced: epoch no longer current for shard '${shardId}'`);\n }\n\n // Fleet B3, D3 — effectively-once forwarding, PER UNIT (B4): when a unit carries an idempotency key\n // (`RunOptions.commitMeta` → ... → `commitWriteBatch`'s per-unit `meta`), INSERT its `fleet_idempotency`\n // row at THAT unit's own ts, in the SAME transaction — atomic by construction. Looping per unit is\n // what makes the batch-shaped guard correct: a single last-ts guard call would drop units 1..N-1's\n // rows and stamp the wrong ts. A `key` PK collision (the concurrent-duplicate race's loser: another\n // commit already claimed this key) surfaces as a Postgres `unique_violation` (23505). We convert it\n // to a typed `CommitGuardRejection` carrying THIS unit's index (Receipted Outbox, decision 2): under\n // group commit the transactor's committer splits out ONLY this offending unit and re-flushes the\n // innocent co-batched remainder, instead of the pre-fix behavior where the raw throw aborted the\n // whole batch and every co-batched unit was rejected as collateral. On the single-commit path\n // (a one-unit batch) it propagates as that mutation's own rejection. Either way `packages/cli`'s\n // `/_fleet/run` handler detects `rejectionCode === \"FLEET_IDEMPOTENCY_CONFLICT\"` (never an app-schema\n // unique violation) and re-SELECTs the winner's commitTs as a replay. Any OTHER error propagates\n // raw. Non-forwarded / non-fleet commits carry no meta, so this is a silent no-op — the whole\n // idempotency machinery costs nothing outside a forwarded write.\n for (let i = 0; i < units.length; i++) {\n const unit = units[i]!;\n if (unit.meta?.idempotencyKey) {\n try {\n await q.query(`INSERT INTO fleet_idempotency (key, commit_ts) VALUES ($1, $2)`, [\n unit.meta.idempotencyKey,\n unit.ts,\n ]);\n } catch (e) {\n if ((e as { code?: unknown }).code === \"23505\") {\n throw new CommitGuardRejection(i, \"FLEET_IDEMPOTENCY_CONFLICT\", `key=${unit.meta.idempotencyKey}`, {\n cause: e,\n });\n }\n throw e;\n }\n }\n }\n });\n}\n\n/** The narrow seams `relinquish` needs — deliberately structural (not the concrete `NodePgClient`) so\n * it's unit-testable with a stub, and reusable by T4's balancer without depending on `startFleetNode`'s\n * internal closures. */\nexport interface RelinquishDeps {\n lease: LeaseManager;\n /** `releaseShardLock` is consulted defensively (`?.`) — absent on a poolless/PGlite client, though\n * every real B2b fleet node runs in pool mode and always has it. */\n client: { releaseShardLock?: (slot: number) => Promise<void> };\n /** Ordered shard list (index = slot) — how `shardId`'s per-slot advisory lock is found for\n * `releaseShardLock`. The same list `prepareFleetNode`/`startFleetNode` derive via `shardIdList`. */\n shards: readonly ShardId[];\n /** Structured-log seam, defaults to `console.error`. Tests inject a spy. */\n log?: (msg: string) => void;\n /**\n * Invoked when the DEFAULT shard is relinquished (B2b, D5 — \"drivers follow the default shard\"):\n * `startFleetNode` wires this to `runtime.stopDriversOnly()`, so the moment this node loses the\n * default ring the scheduler/workflow/cron/reaper drivers go quiet (a different node now owns that\n * ring). Optional — the balancer/relinquish unit tests that don't care about drivers omit it, in\n * which case relinquishing the default shard just drops the shard with no driver side effect.\n */\n onDefaultRelinquished?: () => void;\n}\n\n/**\n * Per-shard relinquish dispatcher (Fenced Frontier B2b, D2): the reduction a `FencedError` on shard\n * `s` gets now — \"drop `s`, keep serving everything else\" — instead of B1/B2a's \"kill the node\".\n * Routed to from the commit guard's `onFenced` (a fence discovered mid-commit — that commit itself\n * still aborts and propagates `FencedError` to its caller, OCC-retryable; relinquish is the SIDE\n * EFFECT, not a swallow), the batched heartbeat's `fencedShardIds` (a fence discovered on the probe\n * beat), and a per-shard commit-connection loss.\n *\n * Idempotent per shard: `lease.currentEpoch(shardId) === null` means this shard is already forgotten\n * (a prior relinquish call, or a shard this node never held) — a silent no-op, so callers never need\n * to track \"have I already relinquished this\" themselves.\n *\n * 1. `lease.forgetShard(shardId)` — drops the held-epoch entry, so the commit guard's \"no acquired\n * epoch\" branch fences any straggler commit on `s` cleanly, and `heartbeatAll`/`closeIdleFrontiers`\n * stop touching it.\n * 2. Release `s`'s per-slot advisory lock (`PgClient.releaseShardLock`) — UNLESS `opts.connectionLost`:\n * a dead commit connection already released its session-scoped lock the instant the backend went\n * away, so there is nothing left to release (and no live connection to run the unlock query on).\n * 3. Log one structured line. Relinquishing the DEFAULT shard additionally WARNS that drivers keep\n * running (scheduler/workflow/cron/reaper stay armed on this node) until a later task wires\n * `stopDriversOnly` (D5) — driver stop/start is deliberately NOT built here.\n *\n * Deliberately does NOT touch `LeaseMonitor` and never calls `onExit` — the whole point of B2b is that\n * a per-shard fence must no longer escalate to a whole-node exit. `LeaseMonitor` stays reserved for\n * pinned-connection loss and probe exhaustion (definitive WHOLE-NODE loss); see `startFleetNode`.\n */\nexport function relinquish(\n deps: RelinquishDeps,\n shardId: ShardId,\n reason: string,\n opts: { connectionLost?: boolean } = {},\n): void {\n if (deps.lease.currentEpoch(shardId) === null) return; // idempotent: not held (already gone, or never)\n deps.lease.forgetShard(shardId);\n const log = deps.log ?? ((m: string) => console.error(m));\n log(\n `fleet: relinquish shard='${shardId}' reason='${reason}'` +\n (opts.connectionLost ? \" (via commit-connection loss — its slot lock is already gone)\" : \"\"),\n );\n if (shardId === DEFAULT_SHARD) {\n // B2b, D5: losing the default ring stops this node's drivers (a peer now runs the scheduler). The\n // node keeps serving everything else — `stopDriversOnly` never disposes the sync handler.\n log(`fleet: relinquished the default shard — stopping drivers (scheduler/workflow/cron/reaper)`);\n deps.onDefaultRelinquished?.();\n }\n if (opts.connectionLost) return; // the lock died with the connection — nothing left to release\n const slot = deps.shards.indexOf(shardId);\n if (slot < 0 || !deps.client.releaseShardLock) return;\n void deps.client.releaseShardLock(slot).catch((e: unknown) => {\n log(\n `fleet: releaseShardLock(${slot}) for shard '${shardId}' failed: ${e instanceof Error ? e.message : String(e)}`,\n );\n });\n}\n\n/**\n * Acquire one non-default shard's lease as the writer (B2a acquire-all). `tryAcquire(shardId, slot)`\n * epoch-bumps that shard's row (fencing any prior holder) and takes its per-shard advisory lock. If\n * the lock is still held by a wedged prior holder AND that shard's lease has expired, fence + evict +\n * terminate its backend (the same fencing-first eviction the default-shard acquire loop uses) and\n * retry. Bounded by a generous deadline (~10 lease TTLs): the common failover frees every slot at once\n * when the default-shard loop terminates the whole wedged node, so this normally succeeds on the first\n * try (fresh boot) or right after one eviction. Exceeding the deadline throws → promotion/boot fails →\n * the node exits and rejoins fresh, never silently running as a partial-shard writer.\n */\nexport async function acquireShardAsWriter(\n lease: LeaseManager,\n shardId: ShardId,\n slot: number,\n retryMs: number,\n seedFrontierFromDocuments = false,\n): Promise<void> {\n const deadline = Date.now() + Math.max(1, retryMs) * 75; // ~10 TTLs at the default cadence ratios\n for (;;) {\n // `seedFrontierFromDocuments`: writer-boot arming passes true (post-`setupSchema`, so `documents`\n // exists) so a FIRST-created shard row is born seeded to the store max — never momentarily visible\n // at frontier 0 (the F1×N residual-window fix). A re-acquire (ON CONFLICT) preserves the live\n // frontier regardless, so this is inert on promotion where the rows already exist.\n const state = await lease.tryAcquire(shardId, slot, seedFrontierFromDocuments);\n if (state) return;\n // Lock held — if this shard's lease has expired, its holder is wedged: fence + terminate so the\n // next attempt's advisory try can win. No-op when the lease is still live (a real concurrent\n // holder, which B2a single-node never has — belt-and-braces for the B2b multi-node future).\n if (await lease.isExpired(shardId)) {\n const { fenced, oldAppName } = await lease.evictExpired(shardId);\n if (fenced && oldAppName !== null) await lease.terminateBackend(oldAppName);\n }\n if (Date.now() > deadline) {\n throw new Error(`fleet: could not acquire shard '${shardId}' (slot ${slot}) lease within the deadline`);\n }\n await new Promise((r) => setTimeout(r, Math.max(1, retryMs)));\n }\n}\n\n/**\n * Pure throughput derivation for group-commit health (Fleet B4, T4): a rolling delta of\n * `flushCount` between two `groupCommitStats()` reads, over the elapsed wall-clock time — the\n * simplest honest `flushesPerSec` signal without a dedicated timer/interval. `prevReadMs === null`\n * (no prior sample — the first read after boot, or after any gap) and a non-positive elapsed time\n * (a clock that hasn't advanced, or moved backward) both report 0 rather than a division artifact.\n * Extracted as a standalone pure function so it's unit-testable without booting a fleet node.\n */\nexport function deriveFlushesPerSec(\n prevReadMs: number | null,\n prevFlushCount: number,\n nowMs: number,\n nowFlushCount: number,\n): number {\n if (prevReadMs === null || nowMs <= prevReadMs) return 0;\n return Math.max(0, (nowFlushCount - prevFlushCount) / ((nowMs - prevReadMs) / 1000));\n}\n\n/**\n * Wire the running fleet node. A writer node is already fully live (promoted in `prepareFleetNode`,\n * drivers started at `create()`) — it just gets handles. A sync node starts the replica tailer (its\n * `start()` catch-up is the node's ready gate) and the lease acquire loop, and promotes on acquire\n * via `promoteFleetNode`.\n */\nexport async function startFleetNode(deps: StartFleetNodeDeps): Promise<FleetHandles> {\n const { client, pgStore, runtime, lease, forwarder, switchable, replicaPath } = deps;\n const numShards = deps.numShards ?? 1;\n const shards = shardIdList(numShards);\n let replica = deps.replica;\n const onExit = deps.onExit ?? defaultFleetExit;\n const promotedCbs: Array<() => void> = [];\n // The frontier-lag monitor + (writer-only) idle-shard closer. A sync node runs it read-only so\n // /api/health can report the fleet frontier; arming as writer replaces it with an idle-closing one.\n let frontierMonitor: FrontierMonitor | null = null;\n let unsubscribeCommits: (() => void) | null = null;\n // The commit-guard chain's unregister handle for the CURRENT `armWriter` arm (Receipted Outbox\n // decision 2 — the guard slot→chain migration). `armWriter` re-arms on EVERY promotion; with\n // append-only `addCommitGuard` semantics a naive re-add on each arm would STACK a duplicate\n // epoch-fence guard → duplicate frontier bumps + duplicate `fleet_idempotency` INSERTs at the\n // same ts → self-PK-collision → every forwarded commit aborts. Captured here so `armWriter`\n // releases the PRIOR registration before installing the new one (see `armWriter` below).\n let unregisterCommitGuard: (() => void) | null = null;\n // The client-receipts guard's unregister handle for the CURRENT `armWriter` arm (Receipted Outbox —\n // the promotion-barrier hole). Fleet OWNS this guard on the CONCRETE `pgStore`, because the runtime\n // was booted with `externalReceiptsGuard` (`prepareFleetNode`'s runtimeOptions) so it registered\n // NOTHING itself: a sync node's runtime store is a `SwitchableDocStore` over the replica, and\n // `swapTo(pgStore)` does NOT re-forward registered guards — a runtime-registered receipts guard would\n // silently vanish on promotion, leaving a promoted single-writer node's client mutations un-receipted\n // (dedup miss → a resent (clientId, seq) re-executes). `armWriter` installs it here, on `pgStore`,\n // BEFORE the epoch fence (receipts-before-fence ordering, verdict §(c) R6) and with the SAME\n // release-on-re-arm discipline the fence uses (a naive re-add on each promotion would stack a\n // duplicate → self-PK-collision on `client_mutations` → every subsequent keyed commit aborts).\n let unregisterReceiptsGuard: (() => void) | null = null;\n\n // Group-commit health counters (Fleet B4, T4): `flushesPerSec` is a rolling delta between\n // successive `groupCommitStats()` calls — the simplest honest throughput signal without a\n // dedicated timer/interval. `runtime.groupCommitStats()` is structurally all-zero when\n // `groupCommit` is off (see its doc comment), so this closure needs no separate on/off branch —\n // the delta of two zero readings is zero, same as never having flushed.\n let lastGroupCommitReadMs: number | null = null;\n let lastFlushCount = 0;\n const groupCommitStats = (): { lastBatchSize: number; maxBatchSize: number; flushCount: number; flushesPerSec: number } => {\n const stats = runtime.groupCommitStats();\n const now = Date.now();\n const flushesPerSec = deriveFlushesPerSec(lastGroupCommitReadMs, lastFlushCount, now, stats.flushCount);\n lastGroupCommitReadMs = now;\n lastFlushCount = stats.flushCount;\n return { ...stats, flushesPerSec };\n };\n\n const firePromoted = (): void => {\n for (const cb of promotedCbs) {\n try {\n cb();\n } catch {\n // A misbehaving http-layer callback must not abort promotion.\n }\n }\n };\n\n // B2b, D3: this node's writer-ish state for the balancer. A writer boot is writer-ish from the\n // start; a sync node flips this true when it promotes (below). The balancer only ACQUIRES/RELEASES\n // shards while writer-ish; a pure sync node only heartbeats presence and may request promotion.\n let writerish = forwarder.isLocalWriter();\n // Guards the whole-node promotion so it runs at most once, whichever trigger fires first — the\n // shipped default-shard `acquireLoop` election OR the balancer's generalized trigger (a sync node\n // whose rendezvous targets include an orphaned non-default shard). Both route through the same\n // `runPromotion` via `doPromote`.\n let promoting = false;\n // Indirection so the balancer (constructed below, before the sync branch wires the real promotion\n // sequence) can trigger promotion without a definition cycle. Stays a no-op on a writer boot (a\n // writer never self-promotes) and until the sync branch assigns the real trigger.\n let doPromote: () => void = () => {};\n\n // D4 — driver-chain serialization: every `startDrivers()`/`stopDriversOnly()` call site below fires\n // fire-and-forget (`void ...()`), from several independent triggers (the balancer's per-shard\n // acquire, `relinquish`'s default-shard drop, and either promotion path) that can land in the SAME\n // tick — a default-shard acquire immediately followed by a fence, or vice versa. Each op is\n // individually idempotent on the runtime (`driversStarted` is reset/re-checked), but idempotence\n // alone does NOT order two overlapping async calls: `startDrivers()`'s `for (const d of\n // this.drivers) await d.start(...)` loop can still be mid-flight when an unawaited `stopDriversOnly()`\n // issued a moment later actually RESOLVES first (its own loop may simply have less to await), so\n // \"last call wins\" is not guaranteed by the runtime alone — the calls must be serialized in the\n // ORDER THEY WERE ISSUED via `createAsyncChain()` (below) — scoped to this ONE node's driver\n // lifecycle (a fresh chain per `startFleetNode` call), not shared across nodes.\n const chainDriverOp = createAsyncChain();\n const startDriversChained = (): Promise<void> => chainDriverOp(() => runtime.startDrivers());\n const stopDriversOnlyChained = (): Promise<void> => chainDriverOp(() => runtime.stopDriversOnly());\n\n // B2b, D5 — \"drivers follow the default shard\": the scheduler/workflow/cron/reaper drivers run on\n // EXACTLY the node that currently holds the DEFAULT ring (the ring the scheduler's own unsharded\n // tables live on). Acquiring the default shard (re)starts them; relinquishing OR gracefully\n // releasing it stops them (both routed through `relinquish`, which fires `onDefaultRelinquished`).\n // `startDrivers`/`stopDriversOnly` are idempotent both ways, so these fire freely on every event —\n // routed through `chainDriverOp` (above) so overlapping fires stay ORDERED, not just idempotent.\n const relinquishDeps: RelinquishDeps = {\n lease,\n client,\n shards,\n onDefaultRelinquished: () => void stopDriversOnlyChained(),\n };\n\n // One-tick acquire of a single shard's lease (+ its per-slot advisory lock) for the balancer. Mirrors\n // `acquireShardAsWriter`'s fencing-first eviction of a wedged EXPIRED holder, but as a SINGLE attempt\n // (a miss just retries on the next balancer beat, rather than looping to a deadline) so a beat never\n // blocks. `seedFrontierFromDocuments = true`: a first-created row is born seeded to the store max\n // (post-`setupSchema`, `documents` exists on every path the balancer runs), never momentarily at 0.\n const tryAcquireShard = async (shardId: ShardId): Promise<boolean> => {\n const slot = shards.indexOf(shardId);\n if (slot < 0) return false;\n let state = await lease.tryAcquire(shardId, slot, true);\n // Lock held — if this shard's lease has expired, its holder is wedged/dead: fence + terminate so\n // the retry's advisory try can win. No-op when the lease is still live (a real non-target holder,\n // which the balancer must NOT steal — so acquisition simply fails this beat and is left alone).\n if (!state && (await lease.isExpired(shardId))) {\n const { fenced, oldAppName } = await lease.evictExpired(shardId);\n if (fenced && oldAppName !== null) await lease.terminateBackend(oldAppName);\n state = await lease.tryAcquire(shardId, slot, true);\n }\n if (!state) return false;\n // Fleet B3 hazard fix: floor this node's WRITE oracle for `shardId` to the row's fenced frontier.\n // `frontier_ts` is >= every prior commit on this shard by the fence invariant (the commit guard\n // writes `frontier_ts = GREATEST(frontier_ts, commitTs)` inside each commit txn), INCLUDING commits\n // an interim owner made while this node didn't hold the shard. Without this, a shard this node\n // RELEASED (its `ShardWriter` stays in the transactor Map, only the fleet epoch dropped) and now\n // RE-ACQUIRES keeps that writer's oracle frozen at this node's own last commit — on a hybrid,\n // `observeTimestamp` feeds the QUERY oracle, so nothing else advances the write side — and the next\n // RMW mutation snapshots below the interim commits and silently loses the update. A no-op on a\n // fresh/never-released shard (frontier == our own max). See `EmbeddedRuntime.observeWriteTimestamp`.\n runtime.observeWriteTimestamp(state.frontierTs);\n // D5: acquiring the default ring (re)starts this node's drivers — idempotent, so a writer boot that\n // already started them at create() is a no-op; a failover/multi-writer node that takes over the\n // default shard wakes them here.\n if (shardId === DEFAULT_SHARD) void startDriversChained();\n return true;\n };\n\n // Graceful point-in-time RELEASE of a held shard the rendezvous assignment no longer gives this node\n // (B2b, D3): under the shard's commit mutex (so no in-flight commit's frontier write races it),\n // self-fence the row (epoch+1, writer_url NULL, frontier GREATEST-bump) then run the T3 relinquish\n // unwind (drop the held-epoch entry + release the slot lock). The rightful owner acquires it on its\n // own next beat — no TTL wait, no failover event. A mutation mid-execute at release time hits\n // `FencedError` at commit (OCC-retryable; the forwarder re-routes the retry to the new owner).\n //\n // Skip-if-busy (Fleet B4): `tryRunExclusiveOnShard` now returns `false` when the shard has a\n // staged/flushing group-commit batch too, not just a mutex-held commit. If it returns `false` we do\n // NOT relinquish — we leave the shard held and let the balancer's next beat retry (the shard is\n // still a non-target, so the release fires again). Fencing mid-flush would be SAFE — the epoch bump\n // cleanly fences the in-flight batch, so its `commitWriteBatch` hits `FencedError` and NOTHING lands\n // below the bumped frontier — but pointlessly disruptive (the whole batch rejects + its callers\n // retry). Waiting one beat for the flush to drain, then fencing a genuinely-idle shard, is the\n // better posture and costs at most a beat of extra hold. (Failover eviction of a DEAD peer is\n // row-lock-based via `evictExpired`, not this mutex path, and so is unaffected.)\n const releaseShard = async (shardId: ShardId): Promise<void> => {\n const fenced = await runtime.tryRunExclusiveOnShard(shardId, async () => {\n await lease.selfFence(shardId);\n });\n if (!fenced) return; // shard busy (commit or in-flight batch) — retry next beat, still held\n relinquish(relinquishDeps, shardId, \"balancer graceful release (no longer a rendezvous target)\");\n };\n\n // The rendezvous shard balancer (B2b, D3) — runs on EVERY node. Its `requestPromotion` routes through\n // `doPromote` (wired by the sync branch); `isWriterish` gates acquire/release; the acquire/release\n // thunks are the two above. Beat cadence scales with the lease TTL (2000ms at the default 15000ms).\n // Multi-writer scale-out is OPT-IN (`HELIPOD_FLEET_MULTI_WRITER`), off by default — see the\n // balancer's `multiWriter` doc. Off = single writer holds all shards + additional nodes are read\n // replicas (the shipped single-writer/sync-replica behavior, byte-identical to B2a); the balancer\n // still heartbeats presence (the bootstrap fix) and performs FAILOVER acquisition regardless. On =\n // full rendezvous distribution across co-writers, and (Fleet B3) every writer-ish node is a HYBRID:\n // it keeps its replica + real ReplicaTailer and serves queries from the replica while committing to\n // the primary. The SAME `fleetMultiWriterEnabled()` `prepareFleetNode` reads to decide the store/\n // queryStore wiring — so the two halves can never disagree about whether this node is a hybrid.\n const multiWriter = fleetMultiWriterEnabled();\n const balancer = new ShardLeaseBalancer({\n lease,\n myUrl: lease.advertiseUrl,\n numShards,\n multiWriter,\n isHeld: (shardId) => lease.currentEpoch(shardId) !== null,\n isWriterish: () => writerish,\n tryAcquireShard,\n releaseShard,\n requestPromotion: async () => {\n doPromote();\n },\n // Fleet B3, D3: reclaim expired `fleet_idempotency` rows on every writer-ish beat (cheap indexed\n // delete) — see `LeaseManager.sweepIdempotency`. The balancer runs `sweepIdempotency` only while\n // `isWriterish()`; a pure sync node holds no writer-side state to sweep.\n sweepIdempotency: () => lease.sweepIdempotency(),\n beatMs: fleetAcquireRetryMs(lease.ttlMs),\n });\n\n // Shared invalidation sink (B2b): advance this node's oracle past a learned ts + push a reactive\n // transition into the sync handler, derived from ONE pulled batch. Used by BOTH the sync node's\n // replica tailer AND the writer-ish node's derive-only listener (D5/T5-c) — the wiring is identical\n // because both end at \"invalidate my own live subscriptions\"; only whether the batch was also\n // applied to a replica differs (the tailer's mode, not this sink's concern).\n const invalidationSink = async (inv: AppliedInvalidation): Promise<void> => {\n // Wrapped so a rejection never surfaces as an unhandled promise rejection (the tailer awaits this);\n // reactivity is best-effort — reads stay correct regardless.\n try {\n runtime.observeTimestamp(inv.newMaxTs);\n const ranges = [\n ...inv.writtenKeys.map((k) => keyToPointRange(k.indexId, k.key)),\n ...inv.writtenDocs.map((d) => docKeyToPointRange(d.tableId, d.internalId)),\n ];\n const commitTs = Number(inv.newMaxTs);\n await runtime.handler.notifyWrites({\n tables: inv.writtenTables,\n ranges,\n commitTs,\n });\n // Trigger-wake gap fix: `notifyWrites` above only re-runs live QUERY subscriptions — it never\n // touches `commitSubs`, the driver `onCommit` fan-out (that only fires from THIS node's own\n // local `adapter.subscribe`, in `packages/runtime-embedded`). Without this, a driver here (e.g.\n // `@helipod/triggers`) never wakes on a co-writer's commit and instead sleeps up to its own\n // wall-clock beat — delivery is still guaranteed (the durable cursor), this is latency-only.\n // `inv.writtenTables` is already ENCODED STORAGE-TABLE IDS (see `AppliedInvalidation`'s doc\n // comment in `replica-tailer.ts`), the same format `notifyExternalCommit` expects (it applies\n // the identical translation `adapter.subscribe`'s local path uses). No-op on a node with no\n // registered drivers.\n runtime.notifyExternalCommit({ tables: inv.writtenTables, ranges, commitTs });\n } catch (e) {\n console.error(\"fleet: replica invalidation failed\", e);\n }\n };\n\n // Fleet B3 (D1) — the HYBRID replica read path. In MULTI-WRITER mode EVERY writer-ish node keeps a\n // local replica and serves queries from it, so it ALWAYS runs the REAL ReplicaTailer (verbatim apply\n // + derive-only invalidation), never the B2b derive-only `invalidateOnly` listener (which is now\n // superseded on this path — the mode remains in `replica-tailer.ts` for its own tests). Shared by a\n // hybrid WRITER boot and a hybrid PROMOTION (the tailer never stops across promotion, so there is no\n // handoff gap to seed around — the B2b `seedWm` machinery is gone from this path).\n //\n // Reconciles the replica's deployment identity (post-DDL — createEmbeddedRuntime ran\n // `pgStore.setupSchema()` for a hybrid, whose runtime WRITE store IS `pgStore`), opens the tailer\n // over the replica, gates on catch-up to F (the ready gate), and attaches it to the forwarder so\n // BOTH forwarded-write RYOW and the own-commit `beforeNotify` gate resolve against the same replica\n // watermark. `replica`/`switchable`/`replicaPath` are guaranteed present on any hybrid boot by\n // `prepareFleetNode` (both roles open the replica in multi-writer mode).\n const startHybridTailer = async (): Promise<ReplicaTailer> => {\n if (!replica || !switchable || !replicaPath) {\n throw new Error(\n \"fleet: hybrid boot requires a replica + switchable store + replicaPath (bug: prepareFleetNode multi-writer path must provide them)\",\n );\n }\n await pgStore.setupSchema(); // idempotent (readOnly skips the writer lock); C7 self-sufficiency\n const reconciled = await reconcileReplicaIdentity({ pgStore, replica, switchable, replicaPath });\n replica = reconciled.replica; // may be a freshly-rebuilt replica; `switchable` was repointed in place\n const t = new ReplicaTailer(client, pgStore, replica, { numShards, onInvalidation: invalidationSink });\n await t.start(); // READY GATE: resolves after the replica has caught up to F.\n // Read-your-own-writes (forwarded writes) AND the own-commit `beforeNotify` gate both wait on this.\n forwarder.attachTailer(t);\n return t;\n };\n // The hybrid replica tailer, once started (writer boot, or on promotion). Stopped on shutdown; NEVER\n // stopped on promotion (unlike the single-writer path). Null on a single-writer node (no replica).\n let hybridTailer: ReplicaTailer | null = null;\n\n // The writer lease monitor (C4). Runs ONLY while this node is the writer: constructed lazily at\n // writer boot OR on promotion (never on a sync node). A sync node's connection loss is survivable —\n // its reads keep working off the local replica (slice 2) — so `monitor` stays null and the\n // connection-lost callback below is a no-op until (if) this node becomes the writer.\n let monitor: LeaseMonitor | null = null;\n const startWriterMonitor = (): void => {\n monitor = new LeaseMonitor({\n // Heartbeat-as-probe (Fenced Frontier B1, D2): one round-trip serves liveness-probe + TTL\n // maintenance + fence verification — NEVER pg_try_advisory_lock (re-entrant on the holding\n // session). `lease.currentEpoch()` is read live so a re-promotion's epoch bump is honored.\n probe: async () => {\n // B2b, D3 (the sanctioned evolution of the B1/T3 probe): the probe's liveness question is now\n // \"can I heartbeat my PRESENCE row\" — heartbeat `fleet_nodes` ALWAYS. That is a plain query on\n // the pinned connection, so a genuine connection loss makes it THROW → accrues toward the\n // miss-exhaustion backstop → whole-node exit, preserving B1's exit semantics for real\n // connection loss (the LeaseMonitor stays wired for exactly that). Held shard leases are\n // heartbeated too, but ONLY when this node holds any — in the balancer world zero-held is a\n // VALID state (a node whose targets all moved away), so the old `expected === 0` throw is GONE:\n // it would wrongly self-exit a legitimately-shardless writer-ish node via miss-exhaustion.\n // B2a/B2b, D2: a superseded epoch is a PER-SHARD signal — `fencedShardIds` names exactly which\n // held shards did NOT renew, each relinquished individually without touching `onExit`.\n await lease.heartbeatPresence();\n if (lease.heldPairs().length === 0) return; // zero-held: presence beat is the whole liveness check\n const { fencedShardIds } = await lease.heartbeatAll();\n for (const fencedShardId of fencedShardIds) {\n relinquish(\n relinquishDeps,\n fencedShardId,\n \"batched heartbeat found a superseded epoch\",\n );\n }\n },\n onExit: (reason) => onExit(`writer lease lost: ${reason}`),\n // Probe cadence scales with the lease TTL (same knob the LeaseManager stamps expires_at from),\n // so a live writer always renews several times per TTL — a shortened TTL (e.g. the wedged-writer\n // E2E's 4000ms) must not let a HEALTHY writer's own lease expire between probes. At the default\n // 15000ms TTL this is exactly the historical 5000ms probe.\n probeMs: fleetProbeMs(lease.ttlMs),\n });\n monitor.start();\n };\n\n // Register the connection-lost hook ONCE, here — routed to the monitor only when this node is the\n // writer (monitor non-null). A dropped pinned connection is definitive WHOLE-NODE lease loss (the\n // advisory lock is released the instant that backend goes away, and the pinned connection is what\n // every non-commit query — heartbeats, eviction, setup — runs on), so it exits immediately. This is\n // the ONE loss signal `relinquish` never handles: there is no \"just this shard\" reading of losing\n // the connection every shard's bookkeeping depends on.\n client.onConnectionLost?.(() => monitor?.connectionLost());\n // B2b, D2: a dead PER-SHARD commit connection is that shard's fence, and ONLY that shard's — the\n // shard's session-scoped advisory lock died WITH the connection (so `relinquish` must skip\n // `releaseShardLock`: there is no live connection left to run the unlock on, and the lock is already\n // gone), but every other shard's commit connection — and this node's writer status — is unaffected.\n client.onShardConnectionLost?.((shardId) =>\n relinquish(relinquishDeps, shardId, \"commit connection lost\", { connectionLost: true }),\n );\n\n /**\n * ROLE-ARM this node as a writer-ish node (B2b, D3 — the armWriter SPLIT). Runs at writer boot AND on\n * promotion. Unlike B2a's `armWriter`, this NO LONGER hard-loops an acquire-all over slots 1…N-1\n * (that would fence a live peer in a multi-writer fleet). Instead:\n * 1. `balancer.acquireTargetsNow()` — a single un-damped pass acquiring only this node's CURRENT\n * rendezvous TARGET shards that are orphaned/expired/missing. In a single-node fleet the target\n * set is EVERY shard, so this acquires all N — byte-identical steady state to B2a's acquire-all\n * (the E2E single-node scenarios are that proof). In a multi-node fleet it acquires only this\n * node's share; the balancer's periodic beat does all ongoing (re)distribution.\n * 2. `seed=true` (fresh writer boot only): seed ALL now-held frontiers up to the store's max BEFORE\n * ready (the F1×N fix). Promotion passes `seed=false` — the frontiers are already live.\n * 3. Install the per-shard epoch-fenced commit guard.\n * 4. Start the idle-shard closer / frontier-lag monitor and wire a coalesced beat to local commits.\n */\n const armWriter = async (seed: boolean): Promise<void> => {\n await balancer.acquireTargetsNow();\n if (seed) await lease.seedFrontierAll(await pgStore.maxTimestamp());\n // B2b, D2: a guard-discovered fence relinquishes JUST that shard — never routes to\n // `monitor`/`onExit`. The aborting commit's own `FencedError` still propagates to its caller\n // (OCC-retryable) regardless; relinquish is the side effect, not a swallow.\n //\n // Receipted Outbox (the promotion-barrier hole): install the client-receipts guard FIRST — on the\n // CONCRETE `pgStore`, ahead of the epoch fence — so it survives promotion (a runtime-registered one\n // would sit on the sync node's `SwitchableDocStore` and vanish on `swapTo(pgStore)`). Same\n // release-on-re-arm discipline as the fence (below): release the prior arm before re-adding, or a\n // double-promotion stacks a duplicate → `client_mutations` self-PK-collision on every keyed commit.\n // Ordering matters: `addCommitGuard` is append-only, so registering receipts BEFORE the fence keeps\n // receipts first in the guard chain on the promoted node too (verdict §(c) R6). Non-fleet\n // deployments never reach here — the runtime owns their receipts guard (`externalReceiptsGuard`\n // unset), registered on their concrete `options.store` at construction.\n unregisterReceiptsGuard?.();\n // `clientReceiptsGuard()` is store-agnostic (`void | Promise<void>` — its SQLite branch is\n // synchronous), but `PostgresDocStore.addCommitGuard` expects the async `PgCommitGuard` shape.\n // `pgStore` is always Postgres, so the guard's Postgres branch always returns a Promise; wrap it in\n // an `async` adapter to satisfy the `Promise<void>` return without a cast.\n const receiptsGuard = clientReceiptsGuard();\n unregisterReceiptsGuard = pgStore.addCommitGuard(async (q, units, shardId) => {\n await receiptsGuard(q, units, shardId);\n });\n // Receipted Outbox decision 2 (the spec-review-flagged hazard): `armWriter` re-arms on EVERY\n // promotion, and `addCommitGuard` is append-only — release the PRIOR arm's guard registration\n // BEFORE installing the new one, or every re-arm stacks a duplicate epoch-fence guard (dup\n // frontier bumps + dup `fleet_idempotency` INSERTs at the same ts → self-PK-collision → every\n // forwarded commit aborts).\n unregisterCommitGuard?.();\n unregisterCommitGuard = installCommitGuard(pgStore, lease, (fencedShardId, reason) =>\n relinquish(relinquishDeps, fencedShardId, reason),\n );\n // Idle-shard closing only matters when N>1 (with a single shard nothing else can pin F, and the\n // closer would needlessly advance the lone frontier past real commits via `nextval`). At N=1 the\n // monitor is read-only — health stats without mutating the frontier — so single-shard behavior is\n // byte-identical to B1.\n const closeIdle = numShards > 1;\n // The idle-frontier closer takes each shard's commit mutex before bumping it (the frontier-\n // inversion fix), via the runtime's per-shard exclusion seam over the same `ShardedTransactor`\n // that this writer's commits run on. Only consulted when `closeIdle` is true.\n frontierMonitor = new FrontierMonitor(lease, {\n closeIdle,\n runExclusiveOnShard: (shardId, fn) => runtime.tryRunExclusiveOnShard(shardId, fn),\n // D4 — replica-lag warning: a hybrid writer keeps a local read-replica tailer (`hybridTailer`,\n // already started above/on the prior sync boot by the time `armWriter` runs) even though it\n // commits to the primary — watch ITS watermark against F too. A non-hybrid writer has no\n // replica (reads the primary directly), so this is omitted there — nothing to lag.\n tailerWatermark: multiWriter ? () => hybridTailer!.watermark() : undefined,\n // T3.5: wake every follower's LISTEN the instant an idle/orphan shard close (silently, by bare\n // UPDATE) actually un-pins F — reusing the SAME channel `NotifyingFanoutAdapter` NOTIFYs on a\n // real commit, so a `ReplicaTailer` armed on either wakes identically. Fire-and-forget +\n // swallow, exactly like `NotifyingFanoutAdapter.publish`'s own NOTIFY: a transient connection\n // hiccup here must not break this beat — the poll fallback remains the correctness backstop.\n notifyOnAdvance: (ceiling) => {\n void client.notify(COMMIT_CHANNEL, String(ceiling)).catch(() => {});\n },\n });\n frontierMonitor.start();\n // Coalesced idle-close on each LOCAL commit: a commit on one shard schedules a ~10ms beat so idle\n // sibling shards un-pin F promptly instead of waiting out the 100ms periodic beat. `?.` — a stub\n // runtime in unit tests may omit the fan-out adapter; the periodic beat is the correctness path.\n if (closeIdle) {\n unsubscribeCommits = runtime.writeFanoutAdapter?.subscribe(() => frontierMonitor?.triggerCoalesced()) ?? null;\n }\n };\n\n // Writer boot: store already writable, forwarder promoted, drivers running. Role-arm this node as a\n // writer-ish node (B2b, D3): `armWriter(true)` acquires its rendezvous targets NOW (= all N shards\n // in a single-node fleet, so all N frontier rows exist + are seeded BEFORE ready — the F1×N fix and\n // the byte-identity path), seeds all held frontiers, installs the commit guard, and starts the idle-\n // closer. Then arm the writer lease monitor (writer from the first tick) and START the balancer,\n // which maintains placement (acquire orphaned targets on failover, gracefully release non-targets\n // as peers join) from here on.\n if (forwarder.isLocalWriter()) {\n // Fleet B3 — HYBRID writer boot (multi-writer): stand up the replica read path (the REAL tailer)\n // BEFORE arming the writer half, so queries serve from the replica from the ready tick on. Since\n // B3-T4, `setup()` pre-seeds all N `shard_leases` rows (frontier = MAX(ts) via the shared probe),\n // so the tailer's ready gate sees the TRUE F here: a fresh database resolves immediately (F = 0,\n // nothing to apply), and a PRE-LOADED upgrade does a FULL replica bootstrap to F = MAX(ts) before\n // ready — no early-ready window. Single-writer boot (multi-writer off): no replica, reads hit the\n // primary as shipped.\n if (multiWriter) hybridTailer = await startHybridTailer();\n await armWriter(true);\n startWriterMonitor();\n balancer.start();\n // C7: mint the deployment id once, now that `bootProject` has run `pgStore.setupSchema()`\n // (this runs AFTER `prepareFleetNode` — `persistence_globals` doesn't exist before that).\n // Race-safe no-op if it's already set (e.g. this writer restarted, or a sync node minted it\n // first while this node was still booting). Sync nodes read this to detect a foreign-primary\n // replica file and rebuild rather than serve it. On a hybrid boot `startHybridTailer`'s reconcile\n // may already have mint-adopted it (writer lost the race) — this stays a race-safe no-op then.\n await pgStore.writeGlobalIfAbsent(FLEET_DEPLOYMENT_ID_KEY, crypto.randomUUID());\n return {\n role: () => \"writer\",\n writerUrl: async () => (await lease.read())?.writerUrl ?? \"\",\n onPromoted: (cb) => promotedCbs.push(cb),\n frontierStats: () => frontierMonitor?.stats() ?? null,\n groupCommitStats,\n isLocalWriter: (shardId) => forwarder.isLocalWriter(shardId),\n idempotencyLookup: (key) => lease.lookupIdempotency(key),\n idempotencyRecordValue: (key, value) => lease.recordIdempotencyValue(key, value),\n stop: async () => {\n monitor?.stop();\n balancer.stop();\n frontierMonitor?.stop();\n unsubscribeCommits?.();\n unregisterCommitGuard?.();\n lease.stop();\n await hybridTailer?.stop();\n // Hybrid writer boot: this node owns the replica (queryStore) lifecycle — serve closes the\n // WRITE store (`pgStore`), never the switchable, so close it here after the tailer stops.\n if (hybridTailer) await switchable?.close();\n },\n };\n }\n\n // Sync boot invariant: prepareFleetNode's sync branch always provides all three.\n if (!replica || !switchable || !replicaPath) {\n throw new Error(\n \"fleet: sync node start requires a replica + switchable store + replicaPath (bug: prepareFleetNode sync boot must provide them)\",\n );\n }\n\n // C7: make this node SELF-SUFFICIENT on a fresh database — run the idempotent Postgres DDL here,\n // before anything below reads the shared tables. A sync node's own `bootProject` ran\n // `setupSchema()` on the LOCAL replica only (slice 2 made its runtime store the\n // `SwitchableDocStore` over the replica — slice 1, where the runtime store was `pgStore` itself,\n // had this covered as a side effect, and slice 2 silently lost it); on a fresh multi-node\n // CONCURRENT first boot the writer's `bootProject` may still be mid-flight, so nothing has\n // necessarily created `persistence_globals`/`documents`/`indexes` on Postgres yet when the stamp\n // check below (or the tailer's first `maxTimestamp()`) reads them. Read-only contract: the store\n // is `readOnly` here, so `setupSchema()` runs the `CREATE ... IF NOT EXISTS` DDL but skips the\n // writer advisory lock (see `PostgresDocStore.setupSchema`) — safe for any number of followers to\n // run concurrently with the writer's own DDL.\n await pgStore.setupSchema();\n\n // C7: reconcile the replica's deployment-id stamp against the primary's — post-DDL-guaranteed by\n // the `setupSchema()` call directly above — and always BEFORE the tailer starts (a foreign or\n // pre-C7 replica must be rebuilt before a single row is tailed onto it). Deferred here from\n // `prepareFleetNode` for exactly this reason — see `reconcileReplicaIdentity`'s doc comment.\n const reconciled = await reconcileReplicaIdentity({ pgStore, replica, switchable, replicaPath });\n replica = reconciled.replica; // may be a freshly-rebuilt replica; `switchable` was repointed in place\n\n // Sync boot: verbatim-apply the primary's MVCC log onto the local replica AND drive cross-process\n // reactive fan-out from the SAME applied batch. `start()` gates on bootstrap catch-up, so this\n // node isn't reported ready (serve prints its ready line only after `startFleetNode` returns)\n // until the replica has caught up to the FENCED FRONTIER F (Fenced Frontier B1, D5 — the tailer\n //\n // F1 note: a sync node never seeds `frontier_ts` itself — it doesn't hold the epoch, so it\n // structurally can't (see `LeaseManager.seedFrontier`'s epoch fencing). If THIS node wins the boot\n // race and starts tailing before any writer has ever seeded the frontier (e.g. against a database\n // that was populated single-node, pre-`--fleet`), its ready gate targets whatever F is on the row\n // at that moment — 0, if no writer has booted yet — and it reports ready with an empty replica\n // exactly like the bug this fix addresses. That's an accepted, BOUNDED window: it heals the moment\n // ANY fleet writer boots (the writer-boot seed above), not on the far looser \"first post-upgrade\n // commit\" the old code silently relied on. Widening the sync node's own ready gate to wait for\n // frontier >= the primary's live max is deliberately NOT done — it would either dead-lock forever\n // on a fleet with no writer yet, or duplicate the writer's own seed logic on the read-only side.\n // reads `shard_leases.frontier_ts` itself, via the SAME `client` passed below, rather than\n // `pgStore.maxTimestamp()`; nothing extra to wire here) — a fresh follower never serves a read\n // that's arbitrarily behind, and never pulls a commit that raced past the last fence check. On\n // each applied batch: advance the oracle, translate written keys/docs into point ranges, and\n // push the transition into the sync handler.\n const tailer = new ReplicaTailer(client, pgStore, replica, {\n // B2a: the ready gate is F = min(frontier_ts) over all N shard rows, and the tailer refuses to\n // treat a partial `shard_leases` (count < numShards) as ready.\n numShards,\n // Same sink the writer-ish derive-only listener uses (D5/T5-c) — observe the ts + fan invalidation\n // into the sync handler; only the replica-apply (this tailer's default mode) differs.\n onInvalidation: invalidationSink,\n });\n await tailer.start(); // READY GATE: resolves only after the replica has caught up to the primary.\n // Enable read-your-own-writes: a client that wrote through this node waits for the replica's\n // watermark to reach that write's commitTs before its next read is served off the replica. On a\n // HYBRID node this same wait ALSO backs the own-commit `beforeNotify` gate (D2) once promoted.\n forwarder.attachTailer(tailer);\n // Fleet B3: on a HYBRID (multi-writer) sync node this same tailer KEEPS RUNNING across promotion\n // (the promotion below adds the writer half without stopping it), so track it as `hybridTailer` for\n // the shutdown path. On a single-writer sync node it's stopped/closed by `promoteFleetNode` instead.\n if (multiWriter) hybridTailer = tailer;\n\n // Read-only frontier-lag monitor so /api/health reports the fleet frontier + pinning shard even on\n // a sync node. It holds no leases, so `closeIdle:false` — it must NOT allocate `nextval` (only the\n // writer drives the frontier); it just observes whether F is advancing. Replaced by the writer's\n // idle-closing monitor if this node is promoted (armWriter stops this one first). D4: a sync node\n // ALWAYS has a local tailer (`tailer`, above) — watch its watermark against F for the replica-lag\n // warning, regardless of single-writer vs hybrid mode.\n frontierMonitor = new FrontierMonitor(lease, { closeIdle: false, tailerWatermark: () => tailer.watermark() });\n frontierMonitor.start();\n\n // The CRITICAL PROMOTION ORDER, wrapped by C5 error policy — runs at most once, whichever trigger\n // fires first: the shipped DEFAULT-shard `acquireLoop` election (below), OR the balancer's\n // generalized trigger (a sync node whose rendezvous targets include an orphaned NON-default shard —\n // routed here via `doPromote`, B2b, D3). The shared `promoting` guard (declared at the top) makes\n // the two triggers idempotent at the node level.\n const triggerPromotion = (): void => {\n if (promoting) return;\n promoting = true;\n void runPromotion({\n // The lease row (default shard) is already upserted by the tryAcquire() inside acquireLoop when\n // the election path fires; the balancer path promotes first, then acquires its targets below.\n promote: async () => {\n if (multiWriter) {\n // Fleet B3 — HYBRID promotion: ADD the writer half WITHOUT tearing down the read path. The\n // runtime WRITE store is ALREADY `pgStore` (a hybrid's queries route to `queryStore`=replica),\n // so there is NO `switchable.swapTo`; the ReplicaTailer KEEPS RUNNING (queries keep serving\n // from the replica, and foreign + own commits keep being invalidated with NO handoff gap — so\n // none of B2b's `seedWm`/derive-only-listener machinery is needed here), and the forwarder\n // KEEPS its tailer (forwarded writes to shards this node still doesn't own keep their RYOW\n // wait). Deliberately NOT `promoteFleetNode`: its swap + `tailer.stop()` + `replica.close()`\n // are single-writer-only, and its `observeTimestamp(maxTimestamp())` would push the QUERY\n // oracle above the replica watermark and read holes (only the tailer's own post-apply sink may\n // advance it — D1). Just make the store writable and arm the writer half beside the tailer.\n pgStore.setWritable();\n frontierMonitor?.stop();\n unsubscribeCommits?.();\n unsubscribeCommits = null;\n await armWriter(false);\n writerish = true;\n // \"Drivers follow the default shard\": `armWriter`'s default-shard acquisition (re)started them\n // if this node took the default ring; stop them if it promoted for a NON-default shard only.\n if (lease.currentEpoch(DEFAULT_SHARD) === null) void stopDriversOnlyChained();\n return;\n }\n // Single-writer FAILOVER promotion (multi-writer off): the shipped CRITICAL PROMOTION ORDER —\n // swap the runtime store from the replica to the (now writable) primary, stop the tailer + close\n // the replica (this node reads the primary directly from here on), observe the primary max onto\n // the write oracle, start drivers. No replica read path survives, so nothing tails afterward.\n // `replica` is a `let` reassigned inside `startHybridTailer` (a nested closure), which defeats\n // TS control-flow narrowing here — but the sync-boot invariant above threw unless it was\n // present, and `reconcileReplicaIdentity` reassigned it to a non-null store, so it is defined.\n await promoteFleetNode({\n // D4: `startDrivers` routed through the SAME driver chain as every other call site, so this\n // promotion's step 7 (`await runtime.startDrivers()`) is ordered against any overlapping\n // `stopDriversOnly()`/`startDrivers()` fired from the balancer or a relinquish, rather than\n // racing the runtime's own bare call directly.\n runtime: { observeTimestamp: (ts) => runtime.observeTimestamp(ts), startDrivers: startDriversChained },\n pgStore,\n switchable,\n forwarder,\n tailer,\n replica: replica!,\n });\n // Swap the read-only frontier monitor for the writer's idle-closing one, and acquire this\n // node's rendezvous targets. `seed=false`: promotion never re-seeds frontiers (they're already\n // live — a dead writer's high-water is preserved through the epoch-bumping re-acquire).\n // `armWriter` also installs the per-shard commit guard (closes over `monitor` by reference, so\n // a fence AFTER `startMonitor` runs still reaches the now-non-null monitor).\n frontierMonitor?.stop();\n unsubscribeCommits?.();\n unsubscribeCommits = null;\n await armWriter(false);\n // Now writer-ish: the already-running balancer's next beat will acquire/release to converge.\n writerish = true;\n if (lease.currentEpoch(DEFAULT_SHARD) === null) void stopDriversOnlyChained();\n },\n startMonitor: startWriterMonitor,\n firePromoted,\n onExit,\n });\n };\n // The balancer's generalized promotion trigger routes here (was a no-op until now).\n doPromote = triggerPromotion;\n // The shipped DEFAULT-shard election path (fast failover — grabs the freed advisory lock the instant\n // the prior writer dies, without waiting out any presence TTL) also triggers the same promotion.\n lease.acquireLoop((state) => {\n // Fleet B3 hazard fix (default-shard re-acquire): floor the WRITE oracle to the election-won lease\n // row's fenced frontier before promotion arms the writer half. This is the ONLY observeWriteTimestamp\n // for a re-acquired DEFAULT shard on the election path — `armWriter`'s `acquireTargetsNow` won't\n // re-acquire the default shard (the election already holds it, so `isHeld` is true → skipped). Same\n // stale-snapshot hazard the balancer's `tryAcquireShard` guards above; see observeWriteTimestamp.\n runtime.observeWriteTimestamp(state.frontierTs);\n triggerPromotion();\n // \"Drivers follow the default shard\": winning the DEFAULT-shard election means this node now holds\n // the default ring, so its scheduler/cron/reaper/workflow drivers must run. The balancer's\n // `tryAcquireShard` starts them when IT acquires a shard, but the DEFAULT shard is acquired via THIS\n // election path (which `acquireTargetsNow` deliberately skips once the election holds it), and the\n // multi-writer HYBRID promotion branch below only ever STOPS drivers (never starts) — so without\n // this, a rendezvous/failover MOVE of the default shard onto an already-promoted co-writer would\n // leave its drivers silent (scheduled jobs enqueued on it never dispatch). Idempotent and\n // chain-ordered against the promotion branch's own stop/start, so a redundant fire is a safe no-op\n // (e.g. single-writer failover, where `promoteFleetNode` already starts them).\n void startDriversChained();\n });\n\n // Start the balancer on the sync node too: it heartbeats this node's presence (its liveness signal —\n // a shardless sync node has no shard_leases row and no LeaseMonitor), and requests promotion when\n // its rendezvous share includes an orphaned non-default shard. Its first beat fires after ~2s.\n balancer.start();\n\n return {\n role: () => (forwarder.isLocalWriter() ? \"writer\" : \"sync\"),\n writerUrl: async () => (await lease.read())?.writerUrl ?? \"\",\n onPromoted: (cb) => promotedCbs.push(cb),\n frontierStats: () => frontierMonitor?.stats() ?? null,\n groupCommitStats,\n isLocalWriter: (shardId) => forwarder.isLocalWriter(shardId),\n idempotencyLookup: (key) => lease.lookupIdempotency(key),\n idempotencyRecordValue: (key, value) => lease.recordIdempotencyValue(key, value),\n stop: async () => {\n monitor?.stop(); // disarm writer self-exit BEFORE the connection is closed (if promoted)\n balancer.stop();\n frontierMonitor?.stop();\n unsubscribeCommits?.();\n unregisterCommitGuard?.();\n lease.stop();\n await tailer.stop();\n // Fleet B3: a HYBRID sync node's runtime WRITE store is `pgStore` (serve closes THAT on\n // shutdown), and its promotion never swaps the replica out — so serve never closes the\n // switchable/replica (the queryStore). Close it here, after the tailer stops writing to it. A\n // single-writer sync node's runtime store IS the switchable (serve closes it) or it was closed\n // by `promoteFleetNode` on promotion, so this node must NOT close it in that mode (double close).\n if (multiWriter) await switchable?.close();\n // This node owns the Postgres store's lifecycle (it's not the serve runtime store for a\n // single-writer sync node). Close it here so the pg connection is released; `NodePgClient.close()`\n // is idempotent, so a later `switchable.close()` (single-writer, if promotion swapped it in) OR\n // serve's own `store.close()` on `pgStore` (hybrid) is a safe no-op.\n await pgStore.close();\n },\n };\n}\n","/* Helipod Enterprise. Licensed under the Helipod Commercial License — see ee/LICENSE. */\nimport type {\n CommitGuardUnit,\n ClientVerdictRecord,\n ClientVerdictWrite,\n CommitUnit,\n ConflictStrategy,\n DocStore,\n DocumentLogEntry,\n IndexWrite,\n Interval,\n LatestDocument,\n Order,\n PrevRevQuery,\n SchemaSetupOptions,\n ShardId,\n TimestampRange,\n InternalDocumentId,\n} from \"@helipod/docstore\";\nimport type { JSONValue } from \"@helipod/values\";\n\n/**\n * A `DocStore` that forwards every call to a swappable inner delegate, so a replica-to-primary\n * promotion (Task 4) can become a single atomic pointer swap instead of a coordinated teardown of\n * every in-flight caller.\n *\n * Atomicity contract: each method reads `this.delegate` exactly once, at call entry, into a local\n * binding, and completes its whole operation against that snapshot. A call already in progress when\n * `swapTo()` runs finishes against the OLD delegate; a call started after `swapTo()` returns sees\n * the NEW one. There is no instant where a single call is torn between two delegates. This holds for\n * the async generators too (`index_scan`/`load_documents`): the delegate is captured before the\n * first `yield`, so a scan already draining rows from the old store keeps draining the old store to\n * completion even if `swapTo()` runs concurrently.\n *\n * `close()` semantics: closes only the CURRENT delegate (whatever `this.delegate` is at the moment\n * `close()` is called). It does NOT close a delegate that was swapped out by an earlier `swapTo()` —\n * this class has no memory of former delegates once replaced. Closing a swapped-out (e.g. demoted\n * primary, or promoted-from replica) delegate is the lifecycle owner's responsibility (Task 4\n * decides when that's safe — e.g. after draining its in-flight callers), not this wrapper's.\n */\nexport class SwitchableDocStore implements DocStore {\n private delegate: DocStore;\n\n constructor(initial: DocStore) {\n this.delegate = initial;\n }\n\n /** Atomically repoint all future calls at `next`. Does not touch the outgoing delegate. */\n swapTo(next: DocStore): void {\n this.delegate = next;\n }\n\n /** The delegate current calls are being forwarded to. */\n current(): DocStore {\n return this.delegate;\n }\n\n async setupSchema(options?: SchemaSetupOptions): Promise<void> {\n const d = this.delegate;\n return d.setupSchema(options);\n }\n\n async write(\n documents: readonly DocumentLogEntry[],\n indexUpdates: readonly IndexWrite[],\n conflictStrategy: ConflictStrategy,\n shardId?: ShardId,\n ): Promise<void> {\n const d = this.delegate;\n return d.write(documents, indexUpdates, conflictStrategy, shardId);\n }\n\n async commitWrite(\n documents: readonly DocumentLogEntry[],\n indexUpdates: readonly IndexWrite[],\n shardId?: ShardId,\n // Additive 4th param (Fleet B3, D3 — opaque commit metadata): forwarded through mechanically,\n // same as every other argument this pass-through wrapper already relays untouched.\n opts?: { meta?: Record<string, string> },\n ): Promise<bigint> {\n const d = this.delegate;\n return d.commitWrite(documents, indexUpdates, shardId, opts);\n }\n\n async commitWriteBatch(units: readonly CommitUnit[], shardId?: ShardId): Promise<bigint[]> {\n const d = this.delegate;\n return d.commitWriteBatch(units, shardId);\n }\n\n /** Forwards to the CURRENT delegate at call entry, same atomicity contract as every other\n * method here — but note the resulting registration is NOT itself re-forwarded on a later\n * `swapTo()`: the guard lands on whichever concrete store was `this.delegate` at the moment\n * `addCommitGuard` was called, and stays registered there even after the switchable repoints\n * elsewhere. In practice fleet code (`node.ts`) always calls `addCommitGuard` on the concrete\n * `PostgresDocStore` directly (never through this wrapper), so this pass-through exists purely\n * for `DocStore` interface conformance. */\n addCommitGuard(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- mirrors DocStore.addCommitGuard\n guard: (q: any, units: readonly CommitGuardUnit[], shardId: ShardId) => void | Promise<void>,\n ): () => void {\n const d = this.delegate;\n return d.addCommitGuard(guard);\n }\n\n async get(id: InternalDocumentId, readTimestamp?: bigint): Promise<LatestDocument | null> {\n const d = this.delegate;\n return d.get(id, readTimestamp);\n }\n\n async *index_scan(\n indexId: string,\n tableId: string,\n readTimestamp: bigint,\n interval: Interval,\n order: Order,\n limit?: number,\n ): AsyncGenerator<readonly [Uint8Array, LatestDocument]> {\n const d = this.delegate; // captured before the first yield — see class docstring\n yield* d.index_scan(indexId, tableId, readTimestamp, interval, order, limit);\n }\n\n async *load_documents(\n range: TimestampRange,\n order: Order,\n limit?: number,\n ): AsyncGenerator<DocumentLogEntry> {\n const d = this.delegate; // captured before the first yield — see class docstring\n yield* d.load_documents(range, order, limit);\n }\n\n async previous_revisions(\n queries: readonly PrevRevQuery[],\n ): Promise<Map<string, DocumentLogEntry>> {\n const d = this.delegate;\n return d.previous_revisions(queries);\n }\n\n async scan(tableId: string, readTimestamp?: bigint): Promise<LatestDocument[]> {\n const d = this.delegate;\n return d.scan(tableId, readTimestamp);\n }\n\n async count(tableId: string): Promise<number> {\n const d = this.delegate;\n return d.count(tableId);\n }\n\n async maxTimestamp(): Promise<bigint> {\n const d = this.delegate;\n return d.maxTimestamp();\n }\n\n async getGlobal(key: string): Promise<JSONValue | null> {\n const d = this.delegate;\n return d.getGlobal(key);\n }\n\n async writeGlobal(key: string, value: JSONValue): Promise<void> {\n const d = this.delegate;\n return d.writeGlobal(key, value);\n }\n\n async writeGlobalIfAbsent(key: string, value: JSONValue): Promise<boolean> {\n const d = this.delegate;\n return d.writeGlobalIfAbsent(key, value);\n }\n\n // ── Client mutation receipts (the Receipted Outbox, verdict §(c)) — pass-through ──────────────\n\n async getClientVerdict(identity: string, clientId: string, seq: number): Promise<ClientVerdictRecord | null> {\n const d = this.delegate;\n return d.getClientVerdict(identity, clientId, seq);\n }\n\n async getClientFloor(identity: string, clientId: string): Promise<number | null> {\n const d = this.delegate;\n return d.getClientFloor(identity, clientId);\n }\n\n async recordClientVerdict(identity: string, clientId: string, seq: number, record: ClientVerdictWrite): Promise<void> {\n const d = this.delegate;\n return d.recordClientVerdict(identity, clientId, seq, record);\n }\n\n async updateClientVerdictValue(identity: string, clientId: string, seq: number, value: JSONValue): Promise<void> {\n const d = this.delegate;\n return d.updateClientVerdictValue(identity, clientId, seq, value);\n }\n\n async pruneClientMutations(\n identity: string,\n clientId: string,\n opts: { ackedThrough?: number; ttlBeforeMs?: number },\n ): Promise<{ prunedThroughSeq: number }> {\n const d = this.delegate;\n return d.pruneClientMutations(identity, clientId, opts);\n }\n\n async sweepExpiredClientMutations(beforeMs: number): Promise<{ deletedCount: number }> {\n const d = this.delegate;\n return d.sweepExpiredClientMutations(beforeMs);\n }\n\n close(): void | Promise<void> {\n const d = this.delegate;\n return d.close();\n }\n}\n","/* Helipod Enterprise. Licensed under the Helipod Commercial License — see ee/LICENSE. */\n/**\n * `ReplicaTailer` (Fleet slice 2, Task 2; Fenced Frontier B1, D5/D6) — tails the Postgres\n * primary's MVCC log VERBATIM onto a local embedded replica `DocStore` (an in-process SQLite\n * instance, in the intended deployment), deriving invalidation ranges straight from the SAME\n * batch it just applied — not a separate query — so a follower's reactive fan-out is provably\n * consistent with what actually landed on the replica.\n *\n * Evolves `CommitTailer` (`commit-notifier.ts`, slice 1)'s LISTEN + poll wake posture, the\n * `draining` re-entrancy guard, and watermark-advances-only-after-`onInvalidation`-resolves\n * semantics — but diverges in structural ways `CommitTailer` never needed:\n *\n * 1. VERBATIM APPLY — `CommitTailer` only ever derived ranges to wake a LIVE in-process runtime;\n * it never touched a second store. This class additionally re-materializes the primary's\n * actual `DocumentLogEntry`/`IndexWrite` rows onto a real replica `DocStore` via `write(...,\n * \"Overwrite\")`, so the replica is a byte-for-byte MVCC mirror (historical reads included),\n * not just a wake signal.\n * 2. BOOTSTRAP CATCH-UP — a fresh replica starts at watermark 0 (or wherever it last left off),\n * which can be arbitrarily far behind the primary. `start()` doesn't resolve until the\n * replica has caught up to the FENCED FRONTIER `F` AT CALL TIME (the ready gate), batching\n * the catch-up in `batchSize`-sized ticks instead of one unbounded pull.\n * 3. FENCED-FRONTIER TARGETING (D5) — the pull target is no longer `primary.maxTimestamp()` (the\n * log's live high-water mark, which can include a commit that raced past the last fence\n * check under contention) but `F = shard_leases.frontier_ts` — the durably-fenced, dense\n * prefix the epoch-fenced commit guard (`node.ts`'s `installCommitGuard`) advances inside\n * every commit transaction. At one shard F advances exactly with commits, so this is\n * behavior-identical to the old target in the steady state; the difference only matters\n * under a wedged-writer fencing race (B1 D3/D4), where `maxTimestamp()` could momentarily\n * run ahead of what's actually safe to consider durable. See `stable-prefix.ts` for the\n * `StablePrefixTs` brand this introduces.\n * 4. DENSITY ASSERTIONS (D5) — defense-in-depth: the construction (D1 store-allocated ts + D3\n * epoch-fenced commits) is what actually PREVENTS a skipped commit from ever landing on a\n * replica, but the apply loop additionally verifies it, per document entry, before applying:\n * the replica's current head for that doc must chain from `prev_ts` exactly (or be absent,\n * for an insert). A violation throws `DensityViolationError` — crash loudly rather than serve\n * silently corrupted state; the operator remedy is the already-shipped delete-and-re-bootstrap\n * (a replica file is a rebuildable mirror).\n *\n * `CommitTailer` was the slice-1 derive-only precursor; slice 2 (Task 4) deleted it once this class\n * subsumed its wake/derive posture with verbatim replica apply. `AppliedInvalidation` below carries\n * the invalidation shape (identical members to what `CommitTailer.DerivedInvalidation` had).\n *\n * Per-tick pipeline (see the class body for the full step-by-step):\n * 1. `F = await readFrontier()` (D5: `shard_leases.frontier_ts`, branded `StablePrefixTs`); no-op\n * if `<= watermark`. F is asserted non-decreasing across reads (D5's other defense-in-depth\n * invariant) — a regression means `shard_leases` itself was corrupted/hand-tampered.\n * 2. Pull `DocumentLogEntry` rows for `(watermark, F]` via `primary.load_documents`, capped at\n * `batchSize` — but never splitting a single commit's ts group across ticks (a transaction\n * shares exactly one commit `ts` across all its writes, see `postgres-docstore.ts`'s\n * `write()` doc comment; if the batch fills mid-way through a ts group, the remaining\n * same-ts rows are drained too before capping, so a partial transaction's writes are never\n * applied on the replica).\n * 3. Pull the matching `indexes` rows for the SAME `(watermark, cappedMax]` via raw SQL and\n * invert `postgres-docstore.ts`'s `write()` serialization exactly: `deleted=true` → the\n * `Deleted` variant, else `NonClustered` carrying the decoded `docId`.\n * 4. Density-assert the batch (D5) against the replica's PRE-apply state, THEN\n * `replica.write(docs, indexWrites, \"Overwrite\")` — verbatim, idempotent re-apply.\n * 5. Build `AppliedInvalidation` from the SAME in-memory batch (index-derived writtenTables/\n * writtenKeys, DISTINCT-by-(tableId,internalId) writtenDocs from the doc entries).\n * 6. `await onInvalidation(inv)`, THEN advance the watermark (branded `StablePrefixTs`), THEN\n * resolve any satisfied `waitFor()`s — a throwing/slow handler must not cause a range to be\n * silently skipped.\n */\nimport type { PostgresDocStore } from \"@helipod/docstore-postgres\";\nimport type {\n DatabaseIndexValue,\n DocStore,\n DocumentLogEntry,\n IndexWrite,\n InternalDocumentId,\n} from \"@helipod/docstore\";\nimport { decodeStorageTableId, encodeStorageTableId } from \"@helipod/id-codec\";\nimport type { CommitChannelClient } from \"./commit-notifier\";\nimport { stablePrefixFromFrontier, type StablePrefixTs } from \"./stable-prefix\";\n\nconst COMMIT_CHANNEL = \"helipod_commits\";\nconst DEFAULT_POLL_MS = 1000;\nconst DEFAULT_BATCH_SIZE = 1000;\n/** Default shard count (B1 single-shard behavior) when `numShards` is unset — `min(frontier_ts)` over\n * the one `default` row, `count(*) >= 1`, byte-identical to B1's `WHERE shard_id = 'default'`. */\nconst DEFAULT_NUM_SHARDS = 1;\n\n/** Stable string key for a document identity — used to dedupe/track per-doc state across a\n * batch (both the density-assertion running-head cache below and `writtenDocs`'s DISTINCT). */\nfunction docDedupeKey(id: InternalDocumentId): string {\n return `${encodeStorageTableId(id.tableNumber)}|${Buffer.from(id.internalId).toString(\"hex\")}`;\n}\n\n/** Human-readable doc label shared by `DensityViolationError`'s message. */\nfunction docLabel(id: InternalDocumentId): string {\n return `table=${encodeStorageTableId(id.tableNumber)} internalId=${Buffer.from(id.internalId).toString(\"hex\")}`;\n}\n\n/** Normalizes a `shard_leases.frontier_ts` (BIGINT) read-back to `bigint` — normally already a\n * `bigint` (both `NodePgClient` and the PGlite test client normalize int8 columns), but coerced\n * defensively rather than trusting a specific driver's normalization here. */\nfunction toBigInt(v: unknown): bigint {\n if (typeof v === \"bigint\") return v;\n if (typeof v === \"number\" || typeof v === \"string\") return BigInt(v);\n throw new Error(`fleet: expected shard_leases.frontier_ts to be a BIGINT-like value, got ${typeof v}`);\n}\n\n/**\n * Thrown by the apply loop's density assertion (D5, defense-in-depth — the construction, D1 store-\n * allocated ts + D3 epoch-fenced commits, is the actual guarantee that prevents this) when a\n * document entry's `prev_ts` doesn't chain from the replica's actual current head: either a\n * non-null `prev_ts` that doesn't match (or is missing entirely — no live head), or a null\n * `prev_ts` (an insert) where the replica already has a live head. Either shape means a commit\n * touching this document was skipped somewhere between the primary and this replica — serving\n * reads off it from here on would be silent corruption, so the tailer crashes loudly instead. The\n * shipped operator remedy is deleting the local replica file and letting it re-bootstrap from the\n * primary (a replica is always a rebuildable mirror).\n */\nexport class DensityViolationError extends Error {\n constructor(\n readonly docId: InternalDocumentId,\n readonly expectedPrevTs: bigint | null,\n readonly actualHeadTs: bigint | null,\n ) {\n super(\n `fleet: replica density violation for doc (${docLabel(docId)}) — expected prev_ts ` +\n `${expectedPrevTs === null ? \"null (insert — replica must have no live head)\" : String(expectedPrevTs)}, ` +\n `but the replica's actual head ts is ${actualHeadTs === null ? \"null (no live head)\" : String(actualHeadTs)}. ` +\n `A commit touching this document was skipped between the primary and this replica; delete ` +\n `<replica path>/fleet-replica.db to re-bootstrap.`,\n );\n this.name = \"DensityViolationError\";\n }\n}\n\n/** Mirrors slice 1's `DerivedInvalidation` shape byte-for-byte (see the module doc comment for why\n * this is a deliberate parallel type, not an import). `newMaxTs` is the tick's APPLIED ceiling,\n * which may be less than the primary's live `maxTimestamp()` when a batch was capped. */\nexport interface AppliedInvalidation {\n newMaxTs: bigint;\n /** DISTINCT `table_id` values touched, as strings (the storage-encoded table id). */\n writtenTables: string[];\n /** Raw written index keys — point invalidation input, NOT yet point ranges. */\n writtenKeys: Array<{ indexId: string; key: Uint8Array }>;\n /** DISTINCT `(table_id, internal_id)` pairs written in this batch, deduped from the applied\n * `DocumentLogEntry` rows themselves (one entry per doc regardless of how many revisions or\n * index rows accompanied it in this batch). Point invalidation input for the DOCUMENT\n * keyspace, NOT yet point ranges — same split as `writtenKeys` above. */\n writtenDocs: Array<{ tableId: string; internalId: Uint8Array }>;\n}\n\nexport interface ReplicaTailerOptions {\n /**\n * Tailer mode (B2b, D5/T5-c):\n * - `\"replica\"` (default, sync node): verbatim-apply the primary's MVCC log onto the local replica\n * `DocStore` AND derive invalidation from the applied batch — the shipped follower behavior.\n * - `\"invalidateOnly\"` (writer-ish node in MULTI-WRITER mode): DERIVE-ONLY. The node already has\n * every shard's data (it reads the primary directly), so it never applies to a replica and never\n * runs the density assertions — it only pulls `(watermark, F]` to derive what a FOREIGN writer's\n * commit touched, then fires `onInvalidation` so its own live subscriptions re-run and its oracle\n * observes the new ts. Watermark seeds at boot F (only invalidate commits from here on, not\n * re-derive all history). In this mode the `replica` constructor arg is NEVER dereferenced.\n */\n mode?: \"replica\" | \"invalidateOnly\";\n /** Wall-clock poll fallback interval, in ms. Default 1000. */\n pollMs?: number;\n /** Max `DocumentLogEntry` rows pulled per tick (bootstrap catch-up + steady state). Default\n * 1000. A tick may apply slightly more than this to avoid splitting a commit's ts group. */\n batchSize?: number;\n /** Number of shards the fleet runs (B2a). The tailer's target is `F = min(frontier_ts)` over ALL\n * shard rows, and it refuses to treat a partial `shard_leases` (`count(*) < numShards`) as ready —\n * a half-created lease table must not fake a min (belt-and-braces against the F1×N hole). Default\n * 1 → B1's single-shard behavior. */\n numShards?: number;\n /** Invoked once per non-empty applied batch, in watermark order, AFTER the batch has already\n * been written to the replica. The watermark only advances after this resolves. */\n onInvalidation: (inv: AppliedInvalidation) => Promise<void>;\n}\n\ntype WaitOutcome = \"reached\" | \"timeout\" | \"released\";\n\ninterface Waiter {\n ts: bigint;\n settle: (outcome: WaitOutcome) => void;\n timer: ReturnType<typeof setTimeout>;\n}\n\n/** Verbatim log-apply tailer: primary Postgres MVCC log -> local replica `DocStore`, plus the\n * batch-derived invalidation feed and the `waitFor` read-your-own-writes primitive Task 3 needs. */\nexport class ReplicaTailer {\n private readonly mode: \"replica\" | \"invalidateOnly\";\n private readonly pollMs: number;\n private readonly batchSize: number;\n private readonly numShards: number;\n private readonly onInvalidation: (inv: AppliedInvalidation) => Promise<void>;\n /** The tailer's own applied high-water mark — a `StablePrefixTs` (D6): only ever seeded from the\n * replica's own persisted `maxTimestamp()` (a prior run's watermark, on restart) or advanced to\n * a freshly-read/capped `F`. Never assigned a raw, un-branded `bigint` directly. */\n private wm: StablePrefixTs = stablePrefixFromFrontier(0n);\n /** The last-observed fenced frontier (D5) — tracked purely to assert F never regresses across\n * reads (`null` = no read yet, so the first `readFrontier()` establishes the baseline without\n * asserting anything). */\n private lastF: StablePrefixTs | null = null;\n private timer: ReturnType<typeof setInterval> | undefined;\n private unlisten: (() => Promise<void>) | undefined;\n private stopped = true;\n /** Reentrancy guard: a NOTIFY wake and a poll tick can land back-to-back — only one\n * pull-apply-invalidate walk runs at a time, so `onInvalidation` never sees overlapping ranges,\n * and the bootstrap loop in `start()` never races a concurrent LISTEN-triggered tick. */\n private draining = false;\n private readonly waiters = new Set<Waiter>();\n\n constructor(\n private readonly client: CommitChannelClient,\n private readonly primary: PostgresDocStore,\n private readonly replica: DocStore,\n opts: ReplicaTailerOptions,\n ) {\n this.mode = opts.mode ?? \"replica\";\n this.pollMs = opts.pollMs ?? DEFAULT_POLL_MS;\n this.batchSize = opts.batchSize ?? DEFAULT_BATCH_SIZE;\n this.numShards = opts.numShards ?? DEFAULT_NUM_SHARDS;\n this.onInvalidation = opts.onInvalidation;\n }\n\n /** Plain `bigint` on purpose (not the branded `StablePrefixTs`) — external callers (tests, the\n * `PromotionDeps` seam) only ever compare/print this value; widening away the internal brand at\n * the public boundary costs nothing and avoids forcing every caller to know about the brand. */\n watermark(): bigint {\n return this.wm;\n }\n\n /**\n * Reads the fenced frontier `F` (Fenced Frontier B1 D5, generalized to N shards in B2a) —\n * `F = min(frontier_ts)` over ALL `shard_leases` rows — via the same `CommitChannelClient` already\n * threaded in for LISTEN/NOTIFY. The min is the dense prefix the WHOLE fleet has durably fenced: a\n * replica may serve reads up to it and never past a commit that hasn't been fenced on every shard.\n *\n * Belt-and-braces (B2a — the F1×N hole otherwise recurs ×N): treat `count(*) < numShards` as\n * F=0-equivalent (NOT ready). A half-created `shard_leases` — some shards claimed+seeded, others not\n * yet — must not let `min` over the present rows fake a ready frontier; the writer's acquire-all +\n * seed-all completes (all N rows present, each seeded ≥ max) BEFORE it reports ready, so a real min\n * only appears once every shard is genuinely fenced. `count(*) = 0` (fresh fleet, pre-acquisition)\n * is the same F=0.\n *\n * Asserts F is monotonically non-decreasing across reads once the count gate is satisfied (D5's\n * defense-in-depth invariant) — a regression can only mean `shard_leases` was corrupted/hand-\n * tampered. The assertion is skipped while `count(*) < numShards` (F is a placeholder 0 there, so a\n * later real min is legitimately larger, not a regression).\n */\n private async readFrontier(): Promise<StablePrefixTs> {\n const rows = await this.client.query(\n `SELECT COALESCE(MIN(frontier_ts), 0) AS min_frontier, COUNT(*) AS n FROM shard_leases`,\n );\n const row = rows[0];\n const count = row === undefined ? 0 : Number(toBigInt(row.n));\n if (count < this.numShards) return stablePrefixFromFrontier(0n); // partial/absent lease table — not ready\n const raw = row === undefined ? 0n : toBigInt(row.min_frontier);\n const f = stablePrefixFromFrontier(raw);\n if (this.lastF !== null && f < this.lastF) {\n throw new Error(\n `fleet: frontier regression detected — min(shard_leases.frontier_ts) went from ${this.lastF} to ${f}. ` +\n `F must be monotonically non-decreasing; this indicates a lease row was corrupted or hand-tampered.`,\n );\n }\n this.lastF = f;\n return f;\n }\n\n /**\n * @param seedWm ONLY consulted in `\"invalidateOnly\"` mode (ignored in `\"replica\"` mode, which always\n * seeds from the replica's own persisted high-water mark — see below). When provided, seeds the\n * watermark from THIS value instead of a fresh `readFrontier()` read.\n *\n * Fixes the PROMOTION-HANDOFF INVALIDATION GAP (B2b whole-branch review): a promoting node stops\n * its `ReplicaTailer` (sync mode) at some watermark `W`, then starts this derive-only listener.\n * Between the tailer's stop and the listener's start, a co-writer's commit can land and bump the\n * fenced frontier `F` past `W` — if the listener then seeds from a FRESH `readFrontier()` (i.e.\n * that same later `F`), it treats everything up to `F` as already-known and never derives/\n * invalidates the `(W, F]` range, even though nothing ever actually invalidated it: the sync\n * tailer was already stopped, and this listener starts past it. A subscription open across the\n * promotion goes silently stale for exactly those commits.\n *\n * The caller (`node.ts`'s `startWriterInvalidationListener`) closes this gap by passing the\n * OUTGOING tailer's own final `watermark()` (captured right after `tailer.stop()`) as `seedWm` on\n * promotion, so the listener picks up exactly where the tailer left off — contiguous coverage,\n * with the tailer's own last-applied range harmlessly re-derived (idempotent double-invalidation).\n * Writer BOOT (no prior tailer, so no gap by construction) omits `seedWm` and keeps the original\n * fresh-`readFrontier()` behavior.\n */\n async start(seedWm?: bigint): Promise<void> {\n this.stopped = false;\n if (this.mode === \"invalidateOnly\") {\n if (seedWm !== undefined) {\n // Promotion handoff: pick up exactly where the just-stopped sync tailer left off, not\n // wherever the frontier happens to be NOW (see the `seedWm` doc above for the gap this closes).\n this.wm = stablePrefixFromFrontier(seedWm);\n } else {\n // Writer-ish node (multi-writer, D5/T5-c): seed the watermark at the CURRENT fenced frontier F.\n // This node already holds every shard's data on the primary it reads from, so it must only\n // invalidate FOREIGN commits that land from HERE ON — NOT re-derive all of history. There is\n // nothing to bootstrap/apply, so skip the catch-up loop entirely; the LISTEN+poll wake armed\n // below drives every subsequent derive-only tick. (`readFrontier()` returns a `StablePrefixTs`,\n // so seeding `wm` from it keeps the brand invariant.)\n this.wm = await this.readFrontier();\n }\n } else {\n // Seed from the REPLICA's own high-water mark (0 for a fresh replica, or wherever a\n // previous run left off) — this is what makes catch-up resumable across restarts. This IS a\n // prior watermark (this node's own last-applied frontier), so it's a legitimate StablePrefixTs.\n this.wm = stablePrefixFromFrontier(await this.replica.maxTimestamp());\n const target = await this.readFrontier();\n\n // Bootstrap catch-up: repeat batch-capped ticks until the replica has caught up to the FENCED\n // FRONTIER F AT CALL TIME (the ready gate). Writes that land after this point are the\n // LISTEN+poll loop's job below, same as CommitTailer.\n while (!this.stopped && this.wm < target) {\n await this.tick();\n }\n }\n // `stop()` can land while the bootstrap loop above is awaiting a `tick()` — it already cleared\n // (then-undefined) `timer`/`unlisten` and is done, so falling through to arm either here would\n // leak a listener/timer `stop()` never gets a chance to tear down. Re-check before arming.\n if (this.stopped) return;\n\n try {\n this.unlisten = await this.client.listen(COMMIT_CHANNEL, () => {\n void this.tick();\n });\n } catch {\n // LISTEN unsupported (e.g. a test double, or a transient connection issue) — the poll\n // loop below is the correctness path regardless, so this is not fatal to start().\n this.unlisten = undefined;\n }\n if (this.stopped) {\n // stop() landed while the (possibly slow) listen() call above was in flight.\n if (this.unlisten !== undefined) {\n const unlisten = this.unlisten;\n this.unlisten = undefined;\n await unlisten();\n }\n return;\n }\n\n this.timer = setInterval(() => void this.tick(), this.pollMs);\n }\n\n async stop(): Promise<void> {\n this.stopped = true;\n if (this.timer !== undefined) {\n clearInterval(this.timer);\n this.timer = undefined;\n }\n if (this.unlisten !== undefined) {\n const unlisten = this.unlisten;\n this.unlisten = undefined;\n await unlisten();\n }\n }\n\n /** Resolves when `watermark() >= ts` (immediately if already true), or when `release()` fires.\n * Task 3's read-your-own-writes primitive: a client that just committed at `ts` can wait for\n * a follower's replica to have caught up before serving that client's next read from it. */\n waitFor(ts: bigint, timeoutMs: number): Promise<WaitOutcome> {\n if (this.wm >= ts) return Promise.resolve(\"reached\");\n return new Promise<WaitOutcome>((resolve) => {\n const waiter: Waiter = {\n ts,\n settle: (outcome) => {\n clearTimeout(waiter.timer);\n this.waiters.delete(waiter);\n resolve(outcome);\n },\n timer: setTimeout(() => waiter.settle(\"timeout\"), timeoutMs),\n };\n this.waiters.add(waiter);\n });\n }\n\n /** Releases ALL pending `waitFor()`s with `\"released\"` (e.g. this node was just promoted to\n * writer, or is shutting down, and callers should stop waiting on replica catch-up). */\n release(): void {\n for (const w of [...this.waiters]) w.settle(\"released\");\n }\n\n private wakeSatisfiedWaiters(): void {\n for (const w of [...this.waiters]) {\n if (this.wm >= w.ts) w.settle(\"reached\");\n }\n }\n\n private async tick(): Promise<void> {\n if (this.stopped || this.draining) return;\n this.draining = true;\n try {\n await this.drainOnce();\n } catch (e) {\n if (e instanceof DensityViolationError) {\n // A density violation means a commit was skipped between the primary and this replica — the\n // replica is corrupt and can only serve silently-wrong reads from here on. HALT PERMANENTLY:\n // the fire-and-forget `void this.tick()` callers (the LISTEN wake + the pollMs setInterval)\n // would otherwise re-hit the exact same violation every tick forever (watermark frozen, an\n // endless error loop), since the divergence is on disk and never self-heals. `stop()` clears\n // the interval + closes LISTEN so no further ticks run; the logged message already carries the\n // operator remedy (delete the replica file and re-bootstrap from the primary). Not rethrown:\n // this is the terminal handling, not a transient error to propagate.\n console.error(e.message);\n await this.stop();\n return;\n }\n throw e;\n } finally {\n this.draining = false;\n }\n }\n\n /** One pull-apply-invalidate walk. Split out from `tick()` so `tick()` can wrap it with the\n * DensityViolationError halt handling without that catch swallowing the `draining` bookkeeping. */\n private async drainOnce(): Promise<void> {\n const F = await this.readFrontier();\n if (F <= this.wm) return; // spurious wake — nothing new since last apply (or no lease yet)\n\n const { docs, cappedAt } = await this.pullDocs(this.wm, F);\n const appliedMax = stablePrefixFromFrontier(cappedAt ?? F);\n\n const indexRows = await this.client.query(\n `SELECT index_id, key, ts, table_id, internal_id, deleted FROM indexes WHERE ts > $1 AND ts <= $2 ORDER BY ts ASC`,\n [this.wm, appliedMax],\n );\n\n if (docs.length === 0 && indexRows.length === 0) {\n // B2a: F advanced past the watermark but the range `(wm, F]` holds NO rows. This is the\n // idle-shard-closing case: the writer advances an idle shard's frontier via a bare `nextval`\n // (D5) with no backing document, so `min(frontier_ts)` can legitimately run AHEAD of the last\n // committed doc's ts. The replica IS caught up to F (there is provably nothing to apply in the\n // range — and never will be, since any future commit takes a still-later `nextval`), so ADVANCE\n // the watermark to F. Without this the bootstrap loop (`while wm < target`) would spin forever\n // waiting for documents that will never exist in this range, and RYOW `waitFor(F)` would hang.\n // (Single-shard B1 never reaches here: with the idle-closer off, F only advances alongside a\n // real commit, so an F>wm range is never empty.)\n this.wm = appliedMax;\n this.wakeSatisfiedWaiters();\n return;\n }\n\n // Verbatim apply — ONLY in \"replica\" mode. An \"invalidateOnly\" writer-ish node (D5/T5-c) has no\n // replica and already holds this data on the primary it reads; it skips the apply AND the density\n // assertions (which the invalidate-only sink has no replica head to check against — the pull-\n // through-F contract below is what guarantees no missed range regardless). See the mode doc.\n if (this.mode === \"replica\") {\n // Invert postgres-docstore.ts's write() serialization exactly: `deleted` -> the Deleted\n // variant (table_id/internal_id are NULL on those rows and must not be read), else\n // NonClustered carrying the decoded docId.\n const indexWrites: IndexWrite[] = indexRows.map((r) => {\n const deleted = r.deleted as boolean;\n const value: DatabaseIndexValue = deleted\n ? { type: \"Deleted\" }\n : {\n type: \"NonClustered\",\n docId: {\n tableNumber: decodeStorageTableId(r.table_id as string),\n internalId: r.internal_id as Uint8Array,\n },\n };\n return {\n ts: r.ts as bigint,\n update: { indexId: r.index_id as string, key: r.key as Uint8Array, value },\n };\n });\n\n // Density assertions (D5, defense-in-depth) — MUST run against the replica's PRE-apply\n // state, so before the write() below (which would otherwise make every check trivially\n // pass, since the entry itself would already be its own head by the time it's checked).\n await this.assertDensity(docs);\n\n // Verbatim apply — exactly what load_documents yielded, plus the reconstructed index\n // writes, under \"Overwrite\" so a second application of the same range is a safe no-op.\n await this.replica.write(docs, indexWrites, \"Overwrite\");\n }\n\n const tableIds = new Set<string>();\n for (const r of indexRows) if (r.table_id !== null) tableIds.add(String(r.table_id));\n const writtenTables = [...tableIds];\n const writtenKeys = indexRows.map((r) => ({ indexId: String(r.index_id), key: r.key as Uint8Array }));\n\n const seenDocs = new Set<string>();\n const writtenDocs: Array<{ tableId: string; internalId: Uint8Array }> = [];\n for (const d of docs) {\n const dedupeKey = docDedupeKey(d.id);\n if (seenDocs.has(dedupeKey)) continue;\n seenDocs.add(dedupeKey);\n writtenDocs.push({ tableId: encodeStorageTableId(d.id.tableNumber), internalId: d.id.internalId });\n }\n\n await this.onInvalidation({ newMaxTs: appliedMax, writtenTables, writtenKeys, writtenDocs });\n // Advance ONLY after onInvalidation resolves — a throwing/slow handler must not cause this\n // range to be silently skipped on the next tick.\n this.wm = appliedMax;\n this.wakeSatisfiedWaiters();\n }\n\n /**\n * Density assertion (D5, defense-in-depth): for EVERY document entry in this batch, in\n * `DocumentLogEntry` order, the replica's head for that document IMMEDIATELY BEFORE this entry\n * lands must chain from `entry.prev_ts` exactly — `prev_ts !== null` requires a live head equal\n * to it; `prev_ts === null` (an insert) requires no live head at all. Throws `DensityViolationError`\n * on the first mismatch.\n *\n * IDEMPOTENT RE-APPLY exception: if the replica's head is ALREADY at this exact entry's own\n * `ts`, that's not a violation — it's this exact revision being re-applied (the whole class is\n * built around `\"Overwrite\"` idempotency, e.g. a restart re-walking an already-applied range).\n * Since `ts` is the log's globally unique per-shard commit position, a head landing on it can\n * only mean this precise commit already landed here, never an unrelated collision.\n *\n * A batch can carry more than one revision of the SAME document (it was written more than once\n * inside the pulled `(wm, F]` range), so \"the head immediately before this entry\" is a running\n * per-batch simulation — seeded from the replica's REAL state (`replica.get`) the first time a\n * doc is encountered, then advanced in-memory to each entry's own `ts` as it's validated —\n * rather than re-reading the replica for every entry (which would see later, not-yet-applied\n * entries' predecessor as still absent).\n */\n private async assertDensity(docs: readonly DocumentLogEntry[]): Promise<void> {\n const headTs = new Map<string, bigint | null>();\n for (const d of docs) {\n const key = docDedupeKey(d.id);\n let head = headTs.get(key);\n if (head === undefined) {\n const existing = await this.replica.get(d.id);\n head = existing ? existing.ts : null;\n }\n if (head !== d.ts) {\n // Not already-applied — must chain from prev_ts exactly (see the idempotency note above).\n if (d.prev_ts !== null) {\n if (head === null || head !== d.prev_ts) throw new DensityViolationError(d.id, d.prev_ts, head);\n } else if (head !== null) {\n throw new DensityViolationError(d.id, null, head);\n }\n }\n headTs.set(key, d.ts);\n }\n }\n\n /**\n * Pull `DocumentLogEntry` rows for `(after, upTo]` from `load_documents`, capped at\n * `this.batchSize` — but if the cap lands mid-way through a group of rows sharing the same\n * commit `ts`, keep draining until that ts group is fully collected before stopping. A single\n * transaction shares exactly one commit `ts` across every document it wrote (see\n * `postgres-docstore.ts`'s `write()`), so cutting a batch mid-group would apply a transaction's\n * writes partially, which `load_documents`'s `(after, cap]`-shaped next-tick range would then\n * never revisit (the excluded rows share `ts === cap`, which the next tick's range excludes as\n * its own lower bound).\n *\n * `TimestampRange` is `{minInclusive, maxExclusive}` (see `packages/docstore/src/types.ts`) —\n * the half-open opposite skew from the `(after, upTo]` shape this tailer needs, so the bounds\n * are translated with a `+1n` offset on both sides (safe: `ts` is a monotonic integer log\n * position, never a real number needing density guarantees).\n */\n private async pullDocs(\n after: bigint,\n upTo: bigint,\n ): Promise<{ docs: DocumentLogEntry[]; cappedAt: bigint | null }> {\n const docs: DocumentLogEntry[] = [];\n let cappedAt: bigint | null = null;\n const gen = this.primary.load_documents({ minInclusive: after + 1n, maxExclusive: upTo + 1n }, \"asc\");\n for await (const entry of gen) {\n if (cappedAt !== null && entry.ts !== cappedAt) break; // ts group complete — stop here\n docs.push(entry);\n if (cappedAt === null && docs.length >= this.batchSize) cappedAt = entry.ts;\n }\n return { docs, cappedAt };\n }\n}\n","/* Helipod Enterprise. Licensed under the Helipod Commercial License — see ee/LICENSE. */\n/**\n * `StablePrefixTs` (Fenced Frontier B1, D6) — a compile-time brand over `bigint` marking a\n * timestamp as a member of the FENCED FRONTIER: the stable prefix of the primary's MVCC log that\n * `ReplicaTailer` is allowed to pull from, per D5. A raw `bigint` (e.g. `primary.maxTimestamp()`,\n * which reports the log's live high-water mark INCLUDING any commit that raced past the last fence\n * check) is NOT a `StablePrefixTs` — only a value read straight off `shard_leases.frontier_ts`, or\n * a watermark previously derived from one, is.\n *\n * This is deliberately narrow: it brands ONLY `ReplicaTailer`'s internal pull target (`F`) and its\n * own watermark (`wm`), which must never advance past `F` (D5's \"wm never exceeds F\" invariant).\n * It does NOT brand `waitFor`'s public `ts` parameter — that's a caller-supplied `commitTs` (a raw\n * log position by nature, e.g. forwarded from `WriteForwarder`'s `/_fleet/run` response), and RYOW\n * correctness only needs `wm >= ts`, which is a plain bigint comparison regardless of which side is\n * branded. Branding that parameter too would just force every call site to launder a raw commitTs\n * through the constructor for no safety benefit.\n *\n * The sole constructor, `stablePrefixFromFrontier`, is intentionally the ONLY way to produce one —\n * assigning a raw `bigint` to a `StablePrefixTs`-typed binding without going through it is a\n * compile error (see `replica-tailer.test.ts`'s `@ts-expect-error` cases). At runtime this is a\n * plain `bigint`; the brand (`__stablePrefix`) exists purely in the type system and costs nothing.\n */\nexport type StablePrefixTs = bigint & { readonly __stablePrefix: unique symbol };\n\n/**\n * The sole constructor. Call this ONLY where a value is actually a frontier — a fresh read of\n * `shard_leases.frontier_ts` (via the tailer's `CommitChannelClient`), or a watermark already\n * derived from a prior `StablePrefixTs` (e.g. the replica's own persisted `maxTimestamp()` on\n * restart, which IS this node's last-applied frontier). Do not use this to launder an arbitrary\n * `bigint` (e.g. `primary.maxTimestamp()`, or a document's raw `ts`) into the brand — that value is\n * NOT guaranteed to be a durably-fenced, dense prefix and defeats the whole point of the type.\n */\nexport function stablePrefixFromFrontier(raw: bigint): StablePrefixTs {\n return raw as StablePrefixTs;\n}\n","/* Helipod Enterprise. Licensed under the Helipod Commercial License — see ee/LICENSE. */\n/**\n * Thin re-export. `keyToPointRange`/`docKeyToPointRange` originally lived here (Tier 3 Slice 1/2);\n * Tier 3 Slice 8, Task 8.1 extracted them verbatim into `@helipod/id-codec` (see that package's\n * `point-range.ts` for the full doc — including why `id-codec`, not `index-key-codec`, is the\n * cycle-free canonical home) so `ee/packages/objectstore-substrate`'s replica reactive-tailer wiring\n * could reuse the exact same conversion without depending on `@helipod/fleet`. This module now\n * just re-exports both functions so fleet's own public API (`node.ts`/`index.ts`) and existing\n * tests (`test/point-range.test.ts`) are byte-for-byte unaffected by the move.\n */\nexport { keyToPointRange, docKeyToPointRange } from \"@helipod/id-codec\";\n","/* Helipod Enterprise. Licensed under the Helipod Commercial License — see ee/LICENSE. */\n/**\n * The offline fleet reshard tool (B5 Part 1, Task 9.1): change a STOPPED Postgres fleet's shard\n * count N→M by updating the persist-once `fleet:numShards` global + creating/deleting\n * `shard_leases` lane rows — atomically, in one transaction — and NOTHING else. Because a shard is\n * a logical commit-serialization lane over one shared store (`documents.shard_id` is decorative;\n * routing always recomputes `shardIdForKeyValue(key, numShards)` fresh), resharding moves no rows:\n * only which lane FUTURE commits for a key serialize through changes. See\n * `docs/dev/research/write-sharding/b5-reshard-and-object-storage.md` (Part 1) and\n * `docs/superpowers/plans/2026-02-20-fleet-reshard-b5.md` for the full design.\n *\n * Safety rests on the STOPPED-FLEET precondition (no `--force`): a live node makes the old-N and\n * new-M epochs potentially overlap in time, which is out of scope (needs an epoch-fence vocabulary\n * this tool doesn't have — see the plan's \"online reshard\" scope boundary). A quiesced fleet makes\n * the two epochs strictly non-overlapping, so changing a key's lane between them is as safe as any\n * config change to a stopped system.\n *\n * `F = min(frontier_ts)` is monotone across a reshard: new lanes are seeded at `MAX(ts)` (never\n * below the true high-water mark — the same F1 seed `LeaseManager.setup()`/`tryAcquire()` use, see\n * `frontierSeedExpr` in `./lease.ts`), retained lanes are GREATEST-bumped up to that same floor\n * (never lowered — a documented, safe deviation from \"retained rows untouched\": raise-only can\n * never regress F, and it proactively heals a lane whose frontier legitimately lags `MAX(ts)` after\n * a crash stop — no `selfFence` ran, so nothing bumped it since the last idle-closer beat — the\n * same healing a node boot's `seedFrontierAll` would eventually do), and deleting a lane can only\n * raise or hold `min(frontier_ts)`, never lower it. Net effect: EVERY post-reshard lane is\n * `>= MAX(ts)`, making the post-verify's F1 check a true post-condition rather than a best-effort one.\n */\nimport type { PgClient, PgQuerier, PgRow, PgValue } from \"@helipod/docstore-postgres\";\nimport { DEFAULT_SHARD, shardIdList, type ShardId } from \"@helipod/id-codec\";\n\n/** The `persistence_globals` key the resolved shard count is stamped under — byte-identical to\n * `packages/cli/src/boot.ts`'s `NUM_SHARDS_GLOBAL_KEY` (kept as an independent literal here: the\n * ee `@helipod/fleet` package has no dependency on core `packages/cli`, mirroring the same\n * independent-literal choice `boot.ts`'s own doc comment makes for `DEFAULT_NUM_SHARDS`). */\nexport const NUM_SHARDS_GLOBAL_KEY = \"fleet:numShards\";\n\n/** Thrown when `reshardFleet` is asked to run against a fleet with any live `fleet_nodes` or\n * `shard_leases.writer_url` row — the hard stopped-fleet precondition, no `--force` escape hatch.\n * `liveUrls` names every live node/writer URL found, so the operator error is actionable. */\nexport class ReshardFleetLiveError extends Error {\n readonly liveUrls: string[];\n\n constructor(liveUrls: string[]) {\n super(\n `refusing to reshard: ${liveUrls.length} node(s) still live: ${liveUrls.join(\", \")} — ` +\n `scale the fleet to zero first`,\n );\n this.name = \"ReshardFleetLiveError\";\n this.liveUrls = liveUrls;\n }\n}\n\n/** Thrown when the post-commit verification pass finds the reshard did not land as expected —\n * should be impossible (a guard against a logic bug, not an expected operational outcome). */\nexport class ReshardVerificationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ReshardVerificationError\";\n }\n}\n\n/** Thrown when `reshardFleet` is pointed at a Postgres database that has never run a fleet on it —\n * no `shard_leases`/`fleet_nodes` tables. Without this pre-gate, the live-fleet gate query below\n * would throw a raw `relation \"fleet_nodes\" does not exist`, which reads like an internal SQL bug\n * rather than the operator-actionable \"you haven't booted a fleet here yet\" that it actually is. */\nexport class ReshardNotAFleetError extends Error {\n constructor() {\n super(\n \"this database is not a fleet store (no shard_leases/fleet_nodes tables) — a fleet is \" +\n \"initialized by `helipod serve --fleet`; run the fleet at least once before resharding\",\n );\n this.name = \"ReshardNotAFleetError\";\n }\n}\n\nexport interface ReshardResult {\n previousShards: number;\n newShards: number;\n /** Shard ids newly created (present in the target set, absent from the prior lane set). */\n created: string[];\n /** Shard ids removed (present in the prior lane set, absent from the target set). Never includes\n * `\"default\"` — it is a member of `shardIdList(M)` for every `M >= 1` and so can never be a\n * target-set omission. */\n deleted: string[];\n /** `min(frontier_ts)` across every post-reshard lane, as a decimal string (frontier_ts is a\n * Postgres BIGINT — carried as a string rather than risk a JS-number precision loss). */\n frontierFloor: string;\n}\n\nfunction toBigIntOrZero(v: PgValue | undefined): bigint {\n if (v === null || v === undefined) return 0n;\n return typeof v === \"bigint\" ? v : BigInt(v as number | string);\n}\n\n/** True if the `documents` table exists yet — gates which frontier-seed SQL fragment is safe to\n * interpolate (a literal `FROM documents` reference fails to even PARSE against a database that\n * has never run `setupSchema()`, so this must be checked before that text is ever built). Mirrors\n * `LeaseManager`'s own `documentsTableExists`-gated `frontierSeedExpr` reasoning (see `./lease.ts`). */\nasync function documentsTableExists(q: PgQuerier): Promise<boolean> {\n const rows = await q.query(`SELECT to_regclass('documents') IS NOT NULL AS exists`);\n return rows[0]?.exists === true;\n}\n\n/** `MAX(ts)` over `documents`, or `0n` when the table doesn't exist yet (a fresh/never-written\n * store — there is no history to protect against). */\nasync function maxDocumentsTs(q: PgQuerier): Promise<bigint> {\n if (!(await documentsTableExists(q))) return 0n;\n const rows = await q.query(`SELECT COALESCE(MAX(ts), 0) AS m FROM documents`);\n return toBigIntOrZero(rows[0]?.m as PgValue | undefined);\n}\n\n/** Read `fleet:numShards` back the same way `resolveNumShards` (`packages/cli/src/boot.ts`) does:\n * `Number(JSON.parse(value))`. Returns `null` when the global has never been written. */\nasync function readNumShardsGlobal(q: PgQuerier): Promise<number | null> {\n const rows = await q.query(`SELECT value FROM persistence_globals WHERE key = $1`, [NUM_SHARDS_GLOBAL_KEY]);\n const row = rows[0];\n if (!row) return null;\n return Number(JSON.parse(row.value as string));\n}\n\nfunction shardIdSet(rows: PgRow[]): Set<ShardId> {\n return new Set(rows.map((r) => r.shard_id as ShardId));\n}\n\n/**\n * Change a STOPPED Postgres fleet's shard count from whatever it currently is to `opts.targetShards`.\n * See the module doc comment for the full safety argument. Steps (verbatim to the plan, plus the\n * not-a-fleet pre-gate):\n * 1. validate `targetShards >= 1`\n * 2. probe that this is actually a fleet store (`shard_leases`/`fleet_nodes` exist) —\n * `ReshardNotAFleetError` otherwise, before the next step's raw SQL can throw an opaque\n * \"relation does not exist\"\n * 3. refuse if any `fleet_nodes`/`shard_leases` row is live (`ReshardFleetLiveError`)\n * 4. read the current lane set + the current `fleet:numShards` global\n * 5. one transaction: upsert the global, INSERT new lanes (seeded at `MAX(ts)`), DELETE surplus\n * lanes, then GREATEST-bump every remaining lane's frontier up to that same `MAX(ts)` floor\n * (heals a retained lane that crash-stopped below it — see the module doc comment)\n * 6. post-verify (count/set/frontier-floor/global) — `ReshardVerificationError` on any mismatch\n */\nexport async function reshardFleet(client: PgClient, opts: { targetShards: number }): Promise<ReshardResult> {\n const { targetShards } = opts;\n if (!Number.isInteger(targetShards) || targetShards < 1) {\n throw new RangeError(`reshardFleet: targetShards must be an integer >= 1, got ${targetShards}`);\n }\n\n // 2. Not-a-fleet pre-gate: without this, a fresh/never-fleeted Postgres database makes the live-\n // fleet gate query below (step 3) throw a raw `relation \"fleet_nodes\" does not exist` — technically\n // correct but reads like an internal bug rather than \"you haven't booted a fleet here yet\".\n const fleetProbe = await client.query(\n `SELECT to_regclass('shard_leases') IS NOT NULL AND to_regclass('fleet_nodes') IS NOT NULL AS is_fleet`,\n );\n if (fleetProbe[0]?.is_fleet !== true) {\n throw new ReshardNotAFleetError();\n }\n\n // 3. Precondition — stopped fleet. Live means EITHER an unexpired fleet_nodes presence row OR an\n // unexpired shard_leases row with a writer_url — the exact `liveNodes()` query shape from\n // `./lease.ts`, run directly here (no LeaseManager instance needed for a one-shot read).\n const liveRows = await client.query(\n `SELECT advertise_url AS url FROM fleet_nodes WHERE expires_at >= now()\n UNION\n SELECT writer_url AS url FROM shard_leases WHERE writer_url IS NOT NULL AND expires_at >= now()`,\n );\n const liveUrls = liveRows\n .map((r) => r.url as string)\n .filter((u): u is string => typeof u === \"string\" && u.length > 0);\n if (liveUrls.length > 0) throw new ReshardFleetLiveError(liveUrls);\n\n // 4. Read current state.\n const laneRows = await client.query(`SELECT shard_id FROM shard_leases`);\n const currentLanes = shardIdSet(laneRows);\n const persistedNumShards = await readNumShardsGlobal(client);\n const previousShards = persistedNumShards ?? currentLanes.size;\n\n const target = shardIdList(targetShards);\n const targetSet = new Set(target);\n const created = target.filter((id) => !currentLanes.has(id));\n const deleted = [...currentLanes].filter((id) => !targetSet.has(id));\n // Invariant: \"default\" is a member of shardIdList(M) for every M >= 1, so it can never be a\n // target-set omission — assert rather than silently drop it if this ever regresses.\n if (deleted.includes(DEFAULT_SHARD)) {\n throw new ReshardVerificationError(`internal invariant violation: \"${DEFAULT_SHARD}\" lane marked for deletion`);\n }\n\n // 5. One transaction: global upsert + lane INSERTs (seeded at MAX(ts)) + lane DELETEs + a\n // GREATEST-bump of every REMAINING lane's frontier up to that same MAX(ts) floor.\n await client.transaction(async (tx) => {\n const seedFragment = (await documentsTableExists(tx))\n ? `(SELECT COALESCE(MAX(ts), 0) FROM documents)`\n : `0`;\n\n await tx.query(\n `INSERT INTO persistence_globals (key, value) VALUES ($1, $2)\n ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value`,\n [NUM_SHARDS_GLOBAL_KEY, JSON.stringify(String(targetShards))],\n );\n\n for (const shardId of created) {\n // UNACQUIRED row shape — verbatim to `LeaseManager.setup()`'s pre-seed: epoch=0,\n // writer_url=NULL, writer_app_name=NULL, expires_at=now() (already-expired-equivalent — a\n // fresh acquire's `ON CONFLICT` branch still bumps epoch 0->1), frontier_ts=<seed>, prev_ts=0.\n await tx.query(\n `INSERT INTO shard_leases (shard_id, epoch, writer_url, writer_app_name, expires_at, frontier_ts, prev_ts)\n VALUES ($1, 0, NULL, NULL, now(), ${seedFragment}, 0)`,\n [shardId],\n );\n }\n\n for (const shardId of deleted) {\n await tx.query(`DELETE FROM shard_leases WHERE shard_id = $1`, [shardId]);\n }\n\n // Heal every REMAINING lane (retained + just-created) up to the F1 floor — matches boot's\n // `LeaseManager.seedFrontierAll` healing exactly, see the module doc comment. `GREATEST` only\n // ever RAISES a lane's frontier, so this is a no-op for a lane already >= the floor (the common\n // case — a live-fenced fleet's frontiers already track every commit) and only actually moves a\n // lane that legitimately lagged, e.g. a retained lane left behind by a crash stop (`kill -9`,\n // no `selfFence` ran). This is what makes the post-verify below a TRUE post-condition rather\n // than a best-effort check: after this statement, every post-reshard lane is >= MAX(ts).\n await tx.query(`UPDATE shard_leases SET frontier_ts = GREATEST(frontier_ts, ${seedFragment})`);\n });\n\n // 6. Post-verify (read-only, after commit). The F1 floor check below is now a true post-condition\n // — the in-tx GREATEST-bump above guarantees every lane is >= MAX(ts) — rather than a best-effort\n // check that could throw on a legitimately-lagging retained lane the tx never touched.\n const postLaneRows = await client.query(`SELECT shard_id, frontier_ts FROM shard_leases`);\n const postLaneIds = postLaneRows.map((r) => r.shard_id as ShardId);\n const postSet = new Set(postLaneIds);\n const setMatches = postLaneIds.length === targetShards && target.every((id) => postSet.has(id));\n if (!setMatches) {\n throw new ReshardVerificationError(\n `reshard post-verify failed: expected shard_leases set ${JSON.stringify(target)}, got ${JSON.stringify(postLaneIds)}`,\n );\n }\n\n const frontierValues = postLaneRows.map((r) => toBigIntOrZero(r.frontier_ts as PgValue | undefined));\n const minFrontier = frontierValues.reduce((a, b) => (b < a ? b : a));\n const maxTs = await maxDocumentsTs(client);\n if (minFrontier < maxTs) {\n throw new ReshardVerificationError(\n `reshard post-verify failed: min(frontier_ts)=${minFrontier} < MAX(ts)=${maxTs} (the F1 floor)`,\n );\n }\n\n const globalNumShards = await readNumShardsGlobal(client);\n if (globalNumShards !== targetShards) {\n throw new ReshardVerificationError(\n `reshard post-verify failed: fleet:numShards reads back ${globalNumShards}, expected ${targetShards}`,\n );\n }\n\n return {\n previousShards,\n newShards: targetShards,\n created,\n deleted,\n frontierFloor: minFrontier.toString(),\n };\n}\n","/* Helipod Enterprise. Licensed under the Helipod Commercial License — see ee/LICENSE. */\nexport const FLEET_VERSION = \"0.0.0\";\nexport {\n LeaseManager,\n type LeaseState,\n type LeaseRow,\n type LeaseManagerOptions,\n type IdempotencyReplay,\n IDEMPOTENCY_VALUE_CAP_BYTES,\n} from \"./lease\";\nexport { LeaseMonitor, type LeaseMonitorDeps } from \"./lease-monitor\";\nexport { FencedError } from \"./fenced-error\";\nexport { NotifyingFanoutAdapter, type CommitChannelClient } from \"./commit-notifier\";\nexport { WriteForwarder, type WriteForwarderOptions, type ReplicaWaiter } from \"./forwarder\";\nexport { ShardLeaseBalancer, type ShardLeaseBalancerDeps, type BalancerLease } from \"./balancer\";\nexport { rendezvousOwner, rendezvousWeight } from \"./rendezvous\";\nexport {\n prepareFleetNode,\n startFleetNode,\n runPromotion,\n acquireShardAsWriter,\n installCommitGuard,\n relinquish,\n FrontierMonitor,\n createAsyncChain,\n fleetApplicationName,\n fleetMultiWriterEnabled,\n groupCommitEnabled,\n deriveFlushesPerSec,\n REPLICA_DB_FILENAME,\n FLEET_WRITER_SESSION_TIMEOUTS,\n DEFAULT_NUM_SHARDS,\n keyToPointRange,\n type FleetHandles,\n type FleetPrep,\n type FleetRuntimeOptions,\n type FrontierStats,\n type StartFleetNodeDeps,\n type PromotionRunDeps,\n type RelinquishDeps,\n} from \"./node\";\nexport { SwitchableDocStore } from \"./switchable-store\";\nexport { docKeyToPointRange } from \"./ranges\";\nexport {\n ReplicaTailer,\n DensityViolationError,\n type AppliedInvalidation,\n type ReplicaTailerOptions,\n} from \"./replica-tailer\";\nexport { stablePrefixFromFrontier, type StablePrefixTs } from \"./stable-prefix\";\nexport {\n reshardFleet,\n ReshardFleetLiveError,\n ReshardVerificationError,\n ReshardNotAFleetError,\n NUM_SHARDS_GLOBAL_KEY,\n type ReshardResult,\n} from \"./reshard\";\n"],"mappings":"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","names":["DEFAULT_SHARD","DEFAULT_SHARD","DEFAULT_SHARD","DEFAULT_SHARD","shardIdList","COMMIT_CHANNEL","DEFAULT_LEASE_TTL_MS","DEFAULT_NUM_SHARDS","shardIdList","DEFAULT_SHARD","replica","switchable","reconciled","DEFAULT_SHARD","shardIdList","toBigIntOrZero","documentsTableExists"]}