@cloudbitmaps/core 0.8.2 → 0.10.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.
- package/NOTICE +4 -4
- package/README.md +28 -6
- package/dist/chunk-BUPDGZRR.js +461 -0
- package/dist/chunk-BUPDGZRR.js.map +7 -0
- package/dist/core/audit.d.ts +127 -0
- package/dist/core/bit-route.d.ts +21 -0
- package/dist/core/blob.d.ts +34 -0
- package/dist/core/budget.d.ts +66 -0
- package/dist/core/codec.d.ts +114 -0
- package/dist/core/concurrency.d.ts +15 -0
- package/dist/core/consistency.d.ts +73 -0
- package/dist/core/cooperative.d.ts +78 -0
- package/dist/core/cost.d.ts +102 -0
- package/dist/core/crbm/crc32c.d.ts +10 -0
- package/dist/core/crbm/format.d.ts +116 -0
- package/dist/core/crbm/reader.d.ts +69 -0
- package/dist/core/crbm/varint.d.ts +13 -0
- package/dist/core/crbm/writer.d.ts +39 -0
- package/dist/core/crbm-storage-source.d.ts +432 -0
- package/dist/core/crypto.d.ts +80 -0
- package/dist/core/determinism.d.ts +42 -0
- package/dist/core/discover.d.ts +75 -0
- package/dist/core/due-index.d.ts +55 -0
- package/dist/core/engine.d.ts +204 -0
- package/dist/core/erase-id.d.ts +141 -0
- package/dist/core/erasure.d.ts +179 -0
- package/dist/core/errors.d.ts +120 -0
- package/dist/core/generation-gc.d.ts +52 -0
- package/dist/core/keys.d.ts +23 -0
- package/dist/core/load.d.ts +102 -0
- package/dist/core/lru.d.ts +69 -0
- package/dist/core/metrics.d.ts +132 -0
- package/dist/core/name-codec.d.ts +79 -0
- package/dist/core/pinned-storage-source.d.ts +69 -0
- package/dist/core/ports.d.ts +340 -0
- package/dist/core/registry-scan.d.ts +38 -0
- package/dist/core/retention-sweep.d.ts +190 -0
- package/dist/core/retention.d.ts +67 -0
- package/dist/core/retry.d.ts +65 -0
- package/dist/core/rollback.d.ts +71 -0
- package/dist/core/validate.d.ts +20 -0
- package/dist/driver-kit.d.ts +10 -0
- package/dist/driver-kit.js +314 -0
- package/dist/driver-kit.js.map +7 -0
- package/dist/drivers/_shared/aws-errors.d.ts +18 -0
- package/dist/drivers/_shared/keys.d.ts +27 -0
- package/dist/drivers/_shared/object-registry-keys.d.ts +28 -0
- package/dist/drivers/_shared/object-registry.d.ts +84 -0
- package/dist/drivers/_shared/registry.d.ts +62 -0
- package/dist/drivers/backends.d.ts +49 -0
- package/dist/drivers/crypto.d.ts +38 -0
- package/dist/drivers/localfs/fs-util.d.ts +20 -0
- package/dist/drivers/localfs/paths.d.ts +33 -0
- package/dist/drivers/localfs/registry.d.ts +28 -0
- package/dist/drivers/localfs/storage.d.ts +19 -0
- package/dist/drivers/memory.d.ts +57 -0
- package/dist/drivers/retry/retrying-drivers.d.ts +90 -0
- package/dist/export/index.d.ts +92 -0
- package/dist/index.d.ts +85 -2534
- package/dist/index.js +3076 -2978
- package/dist/index.js.map +7 -1
- package/dist/testing/fuzz-core.d.ts +14 -0
- package/package.json +19 -115
- package/dist/azure/index.cjs +0 -368
- package/dist/azure/index.cjs.map +0 -1
- package/dist/azure/index.d.cts +0 -48
- package/dist/azure/index.d.ts +0 -48
- package/dist/azure/index.js +0 -304
- package/dist/azure/index.js.map +0 -1
- package/dist/cassandra/index.cjs +0 -265
- package/dist/cassandra/index.cjs.map +0 -1
- package/dist/cassandra/index.d.cts +0 -52
- package/dist/cassandra/index.d.ts +0 -52
- package/dist/cassandra/index.js +0 -204
- package/dist/cassandra/index.js.map +0 -1
- package/dist/chunk-7LMLYSVJ.js +0 -43
- package/dist/chunk-7LMLYSVJ.js.map +0 -1
- package/dist/chunk-L54FL5DW.js +0 -203
- package/dist/chunk-L54FL5DW.js.map +0 -1
- package/dist/chunk-NUIDEEFZ.js +0 -91
- package/dist/chunk-NUIDEEFZ.js.map +0 -1
- package/dist/chunk-SNJVZ227.js +0 -35
- package/dist/chunk-SNJVZ227.js.map +0 -1
- package/dist/chunk-YEHMG6W2.js +0 -6
- package/dist/chunk-YEHMG6W2.js.map +0 -1
- package/dist/dynamodb/index.cjs +0 -740
- package/dist/dynamodb/index.cjs.map +0 -1
- package/dist/dynamodb/index.d.cts +0 -106
- package/dist/dynamodb/index.d.ts +0 -106
- package/dist/dynamodb/index.js +0 -469
- package/dist/dynamodb/index.js.map +0 -1
- package/dist/gcs/index.cjs +0 -343
- package/dist/gcs/index.cjs.map +0 -1
- package/dist/gcs/index.d.cts +0 -46
- package/dist/gcs/index.d.ts +0 -46
- package/dist/gcs/index.js +0 -279
- package/dist/gcs/index.js.map +0 -1
- package/dist/index.cjs +0 -4608
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -2535
- package/dist/mongodb/index.cjs +0 -260
- package/dist/mongodb/index.cjs.map +0 -1
- package/dist/mongodb/index.d.cts +0 -45
- package/dist/mongodb/index.d.ts +0 -45
- package/dist/mongodb/index.js +0 -199
- package/dist/mongodb/index.js.map +0 -1
- package/dist/mysql/index.cjs +0 -281
- package/dist/mysql/index.cjs.map +0 -1
- package/dist/mysql/index.d.cts +0 -56
- package/dist/mysql/index.d.ts +0 -56
- package/dist/mysql/index.js +0 -211
- package/dist/mysql/index.js.map +0 -1
- package/dist/ports-5BQTGKze.d.cts +0 -356
- package/dist/ports-5BQTGKze.d.ts +0 -356
- package/dist/postgres/index.cjs +0 -273
- package/dist/postgres/index.cjs.map +0 -1
- package/dist/postgres/index.d.cts +0 -54
- package/dist/postgres/index.d.ts +0 -54
- package/dist/postgres/index.js +0 -203
- package/dist/postgres/index.js.map +0 -1
- package/dist/redis/index.cjs +0 -257
- package/dist/redis/index.cjs.map +0 -1
- package/dist/redis/index.d.cts +0 -42
- package/dist/redis/index.d.ts +0 -42
- package/dist/redis/index.js +0 -197
- package/dist/redis/index.js.map +0 -1
- package/dist/s3/index.cjs +0 -891
- package/dist/s3/index.cjs.map +0 -1
- package/dist/s3/index.d.cts +0 -112
- package/dist/s3/index.d.ts +0 -112
- package/dist/s3/index.js +0 -555
- package/dist/s3/index.js.map +0 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/bit-route.ts","../src/core/chunk.ts","../src/core/budget.ts","../src/core/cooperative.ts","../src/core/keys.ts","../src/core/metrics.ts","../src/core/retry.ts","../src/core/engine.ts","../src/core/lru.ts","../src/core/cost.ts","../src/core/audit.ts","../src/core/codec.ts","../src/core/crypto.ts","../src/core/crbm/crc32c.ts","../src/core/crbm/varint.ts","../src/core/crbm/format.ts","../src/core/crbm/reader.ts","../src/core/crbm/writer.ts","../src/core/crbm-cold-source.ts","../src/core/compaction.ts","../src/export/index.ts","../src/core/blob.ts","../src/drivers/memory.ts","../src/drivers/localfs/paths.ts","../src/drivers/localfs/fs-util.ts","../src/drivers/localfs/cold.ts","../src/drivers/localfs/warm.ts","../src/drivers/localfs/registry.ts","../src/drivers/crypto.ts","../src/core/erasure.ts","../src/core/consistency.ts","../src/drivers/retry/retrying-drivers.ts"],"names":["gen","total","op","YIELD_EVERY_IDS","DEFAULT_MAX_BITMAP_BYTES","FS","open","createHash","HEADER_BYTES","readdir","mkdir","dirname","randomUUID","unlink","DEFAULT_MAX_ROW_BYTES","rename","listGenerations"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * BitRouteSplitter — maps a 32-bit id to its chunk (top 16 bits) and remainder\n * (bottom 16 bits), per the data model.\n */\nimport { ValidationError } from './errors';\n\nexport const U32_MAX = 0xffff_ffff;\nexport const CHUNK_COUNT = 0x1_0000; // 65,536 possible chunk keys\nconst LOW_16 = 0xffff;\n\nexport interface BitRoute {\n /** Top 16 bits — the chunk key (0..65535). */\n readonly chunkKey: number;\n /** Bottom 16 bits — the value within the chunk (0..65535). */\n readonly remainder: number;\n}\n\n/** Split a u32 id into `{ chunkKey, remainder }`. Throws `ValidationError` for non-u32 input. */\nexport function splitId(id: number): BitRoute {\n if (!Number.isInteger(id) || id < 0 || id > U32_MAX) {\n throw new ValidationError(`id must be an integer in 0..${U32_MAX}; got ${id}`);\n }\n return { chunkKey: id >>> 16, remainder: id & LOW_16 };\n}\n\n/**\n * Recombine a chunk key + remainder back into the u32 id. Precondition: `chunkKey` is a validated\n * 16-bit value (tier-derived keys are validated upstream in the engine before reaching here, per\n * invariant 5); `remainder` is masked to 16 bits.\n */\n/**\n * Largest legal value inside a chunk payload. A chunk covers `CHUNK_COUNT` ids, so remainders run\n * `[0, CHUNK_COUNT - 1]`. Exported so the engine can assert it on untrusted tier bytes.\n */\nexport const MAX_REMAINDER = CHUNK_COUNT - 1;\n\nexport function joinId(chunkKey: number, remainder: number): number {\n return (((chunkKey & LOW_16) << 16) >>> 0) + (remainder & LOW_16);\n}\n","/**\n * Tombstone-aware chunk model + the effective-set merge.\n *\n * A chunk's Warm state is a delta over Cold: `{ adds, removes }`, kept **disjoint**.\n * The effective set is `(cold ∪ adds) \\ removes`. This module owns that logic plus the\n * (de)serialization of a delta to the opaque bytes a Warm driver stores.\n */\nimport type { CodecBitmap, CodecInterface } from './codec';\nimport { MAX_REMAINDER } from './bit-route';\nimport { IntegrityError, UnsupportedError } from './errors';\n\nexport interface ChunkDelta {\n readonly adds: CodecBitmap;\n readonly removes: CodecBitmap;\n}\n\nexport function emptyDelta(codec: CodecInterface): ChunkDelta {\n return { adds: codec.empty(), removes: codec.empty() };\n}\n\n/** `add(x)`: x enters `adds`, leaves `removes` — preserving the disjoint invariant (I1). */\nexport function applyAdd(delta: ChunkDelta, remainder: number): void {\n delta.adds.add(remainder);\n delta.removes.remove(remainder);\n}\n\n/** `remove(x)`: x enters `removes`, leaves `adds` — preserving the disjoint invariant (I1). */\nexport function applyRemove(delta: ChunkDelta, remainder: number): void {\n delta.removes.add(remainder);\n delta.adds.remove(remainder);\n}\n\n/**\n * `add` for a whole batch at once — set-wise, not id-by-id.\n *\n * Identical in meaning to calling {@link applyAdd} for every remainder in `ids`, including the disjoint\n * invariant (I1): everything added leaves `removes`. It exists because the streaming `addMany` path already\n * holds its pending ids as a bitmap, and folding that in with two native set operations rather than 2N of them\n * is the difference between one call and millions.\n */\nexport function applyAddAll(delta: ChunkDelta, ids: CodecBitmap): void {\n delta.adds.orInPlace(ids);\n delta.removes.andNotInPlace(ids);\n}\n\n/** {@link applyAddAll}'s mirror: `remove` for a whole batch, preserving the same disjoint invariant. */\nexport function applyRemoveAll(delta: ChunkDelta, ids: CodecBitmap): void {\n delta.removes.orInPlace(ids);\n delta.adds.andNotInPlace(ids);\n}\n\n/** The effective set of a chunk: `(cold ∪ adds) \\ removes`. Does not mutate its inputs. */\nexport function effective(cold: CodecBitmap, delta: ChunkDelta): CodecBitmap {\n const out = cold.clone();\n out.orInPlace(delta.adds);\n out.andNotInPlace(delta.removes);\n return out;\n}\n\n/**\n * Current Warm-row delta schema version — a pre-1.0 format-freeze prerequisite (Phase G). The delta is\n * an internal cross-tier transport, not a user-facing format, but a **1-byte version prefix** lets a reader\n * fail-closed on bytes written by a future, incompatible writer instead of misparsing them — the pre-1.0\n * format-freeze guarantee. Bump only on a backward-incompatible layout change; a reader rejects any version\n * it doesn't recognize (`UnsupportedError`). The versioned on-disk Cold format is `.crbm` (Phase 2).\n */\nexport const WARM_DELTA_VERSION = 1;\nconst VERSION_BYTES = 1;\nconst HEADER_BYTES = 4; // u32 LE addsLen, after the version byte\n\n/** Encode a delta to bytes: `[u8 version][u32 LE addsLen][adds portable][removes portable]`. */\nexport function encodeDelta(delta: ChunkDelta): Uint8Array {\n const adds = delta.adds.serialize();\n const removes = delta.removes.serialize();\n const out = new Uint8Array(VERSION_BYTES + HEADER_BYTES + adds.length + removes.length);\n out[0] = WARM_DELTA_VERSION;\n new DataView(out.buffer).setUint32(VERSION_BYTES, adds.length, true);\n out.set(adds, VERSION_BYTES + HEADER_BYTES);\n out.set(removes, VERSION_BYTES + HEADER_BYTES + adds.length);\n return out;\n}\n\n/**\n * Decode a delta from bytes, size-capping each bitmap (S1). Rejects an unrecognized schema version with\n * `UnsupportedError` (fail-closed) and malformed bytes with `IntegrityError`.\n */\nexport function decodeDelta(\n bytes: Uint8Array,\n maxBitmapBytes: number,\n codec: CodecInterface,\n): ChunkDelta {\n if (bytes.length < VERSION_BYTES + HEADER_BYTES) {\n throw new IntegrityError(`delta too short: ${bytes.length}B`);\n }\n const version = bytes[0];\n if (version !== WARM_DELTA_VERSION) {\n throw new UnsupportedError(\n `Warm delta schema version ${version} is unsupported (this build reads v${WARM_DELTA_VERSION})`,\n );\n }\n // Cap the whole row, not just each half — a hostile Warm tier shouldn't be able to amplify a chunk\n // to ~2× the per-bitmap cap before the per-bitmap checks fire.\n const totalCap = 2 * maxBitmapBytes + VERSION_BYTES + HEADER_BYTES;\n if (bytes.length > totalCap) {\n throw new IntegrityError(`delta is ${bytes.length}B, exceeds cap ${totalCap}B`);\n }\n const addsStart = VERSION_BYTES + HEADER_BYTES;\n const addsLen = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(\n VERSION_BYTES,\n true,\n );\n const addsEnd = addsStart + addsLen;\n if (addsLen > bytes.length - addsStart) {\n throw new IntegrityError(\n `delta addsLen ${addsLen} exceeds payload ${bytes.length - addsStart}`,\n );\n }\n const adds = codec.safeDeserialize(bytes.subarray(addsStart, addsEnd), maxBitmapBytes);\n const removes = codec.safeDeserialize(bytes.subarray(addsEnd), maxBitmapBytes);\n // A warm delta is a CHUNK payload: both halves hold 16-bit remainders. Same reasoning as the cold path in\n // the engine — the length checks above bound size, and CRC/AEAD only prove the bytes are the bytes that were\n // written, so a corrupt or hostile row can still carry a value >= 65536 that `joinId` would mask into a\n // fabricated id in another chunk's space. One `maximum()` per half, not per id.\n assertRemainderRange(adds, 'adds');\n assertRemainderRange(removes, 'removes');\n return { adds, removes };\n}\n\n/** Shared by both delta halves; `maximum` is optional on the seam, so a codec without it opts out. */\nfunction assertRemainderRange(bitmap: CodecBitmap, half: 'adds' | 'removes'): void {\n const max = bitmap.maximum?.();\n if (max !== undefined && max > MAX_REMAINDER) {\n throw new IntegrityError(\n `warm delta ${half} holds value ${max}, outside the 16-bit remainder range [0, ${MAX_REMAINDER}] — ` +\n `the stored row is corrupt or was not written by this codec`,\n );\n }\n}\n","/**\n * Per-op denial-of-wallet budget (Decision #3 / invariant T3). A read/admin op is refused\n * **before it fans out** if its projected fan-out would exceed `maxRequests` — so one runaway\n * `count`/`iterate`/`intersect`/`subjectReport`/`eraseSubject` can't drive unbounded RCU/GET cost on a shared\n * backend. The check is O(1) (a single comparison against the already-known fan-out size), so the hot path is\n * untouched. Each request's payload is separately size-capped (the safe-deserialize ceiling), so bounding the\n * fan-out count transitively bounds bytes — the budget is intentionally count-based, not a second byte\n * accumulator that would add per-chunk work.\n *\n * **What the count is.** For the read ops it is the number of Cold **chunk fetches** (`count`/`iterate`: one per\n * effective chunk; `intersect`: surviving keys × operands). For the admin scans it is the number of **segments\n * fanned out to** (`subjectReport`: one tier-merged `has()` each; `eraseSubject`: one force-compaction each) —\n * i.e. it bounds the *breadth* of the fan-out, not the request total of each segment's own compaction. That's\n * the right lever for a runaway (a million-segment sweep); it is not a byte/request meter.\n */\n\nimport { BudgetExceededError, ValidationError } from './errors';\n\nexport interface Budget {\n /** Max units of fan-out (Cold chunk fetches, or segments scanned) one op may issue before it is refused. */\n readonly maxRequests: number;\n}\n\n/**\n * Default: **on but generous** — even a full single-segment scan (≤ 65 536 chunks) or a large single-namespace\n * admin scan stays well under it; it exists to catch a true runaway (a million-segment scan, a pathological\n * intersection). Tune it down for tighter multi-tenant control, or set `budget: false` to disable.\n */\nexport const DEFAULT_BUDGET: Budget = { maxRequests: 1_000_000 };\n\n/** A store/per-op budget option: partial overrides, or `false` to disable entirely. */\nexport type BudgetOption = Partial<Budget> | false;\n\n/** Resolve a budget option against a fallback to a concrete `Budget`, or `null` when disabled. Validates. */\nexport function resolveBudget(opt: BudgetOption | undefined, fallback: Budget): Budget | null {\n if (opt === false) return null; // explicitly disabled\n const maxRequests = opt?.maxRequests ?? fallback.maxRequests;\n if (!Number.isInteger(maxRequests) || maxRequests < 1) {\n throw new ValidationError(`budget.maxRequests must be a positive integer; got ${maxRequests}`);\n }\n return { maxRequests };\n}\n\n/**\n * Resolve a **per-op** budget override against the store's own resolved budget (never the raw global default):\n * `undefined` inherits the store budget as-is (including a disabled `null`); a partial `{}` / omitted\n * `maxRequests` inherits the store's *tightening* (so a per-op passthrough of an absent config value can't\n * silently lift a tight tenant ceiling back to the generous default); `{ maxRequests }` replaces it; `false`\n * disables. Falls back to {@link DEFAULT_BUDGET} only when the store itself has no budget (disabled).\n */\nexport function resolvePerOpBudget(\n opt: BudgetOption | undefined,\n storeBudget: Budget | null,\n): Budget | null {\n if (opt === undefined) return storeBudget;\n return resolveBudget(opt, storeBudget ?? DEFAULT_BUDGET);\n}\n\n/**\n * Refuse an op whose projected fan-out exceeds the budget. **Call before fan-out**, with the exact fan-out size\n * the op is about to issue (Cold chunk fetches, or segments to scan). O(1). No-op when `budget` is `null`\n * (disabled).\n */\nexport function checkBudget(budget: Budget | null, projectedRequests: number, op: string): void {\n if (budget !== null && projectedRequests > budget.maxRequests) {\n throw new BudgetExceededError(\n `${op} would fan out to ${projectedRequests} units, over the per-op budget of ` +\n `${budget.maxRequests} — raise \\`budget.maxRequests\\`, override it per-op, or set \\`budget: false\\``,\n );\n }\n}\n\n/**\n * Drain an async iterable into an array, refusing **as soon as** the budget is exceeded.\n *\n * This exists because the obvious spelling is wrong in a way that is easy to miss:\n *\n * ```ts\n * for await (const rec of registry.list(ns)) recs.push(rec);\n * checkBudget(budget, recs.length, op); // ← too late; the memory is already spent\n * ```\n *\n * That pattern bounds the **fan-out** but not the **enumeration**, so a tight budget refuses the work only\n * after paying for the list — which defeats the purpose. It was measured buffering 20,000 registry records\n * under `budget: { maxRequests: 2 }` before throwing. Draining incrementally bounds resident memory to\n * `O(budget)` instead of `O(fleet)`.\n *\n * **The error message is deliberately vaguer than `checkBudget`'s.** It reports \"more than N\" rather than an\n * exact total, because knowing the exact total requires finishing the scan — which is precisely the cost being\n * refused. An honest approximation beats an expensive exact number.\n *\n * A `null` budget (`budget: false`) means the caller has explicitly opted out of fan-out limits, so this\n * degrades to a plain drain.\n */\nexport async function collectWithinBudget<T>(\n source: AsyncIterable<T>,\n budget: Budget | null,\n op: string,\n): Promise<T[]> {\n const out: T[] = [];\n for await (const item of source) {\n out.push(item);\n // Checked INSIDE the loop, and `>` not `>=`, so the threshold matches `checkBudget` exactly: a budget of N\n // admits exactly N units and refuses the N+1'th.\n if (budget !== null && out.length > budget.maxRequests) {\n throw new BudgetExceededError(\n `${op} would fan out to more than ${budget.maxRequests} units, over the per-op budget — the scan was ` +\n `abandoned at that point rather than completed, so no exact total is available. Raise ` +\n `\\`budget.maxRequests\\`, override it per-op, or set \\`budget: false\\``,\n );\n }\n }\n return out;\n}\n","/**\n * Cooperative yielding for the long CPU-bound loops.\n *\n * Everything this library does on the hot read path is small. Bulk-load is the exception: it is the one place\n * where a single call legitimately occupies the CPU for hundreds of milliseconds, and Node has exactly one thread\n * to occupy. Measured on a 1M-id load, 62,455 chunks: **442 ms wall, and 450 ms during which the event loop did\n * not turn at all**. Wire that to a request handler and every other in-flight request on the instance — health\n * checks included — waits out the whole load.\n *\n * The fix is not to make the work asynchronous. That was measured too, and it is a 7x *regression*: handing each\n * chunk's insert to the threadpool costs ~9 µs of dispatch against ~1.5 µs of actual work once ids are spread\n * across ~62,000 chunks (636 ms versus 92 ms). The work is genuinely CPU-bound and genuinely small per chunk;\n * the only thing wrong with it is that it never stops to let anyone else go. So the fix is to keep the work\n * synchronous and periodically hand the loop back.\n *\n * TWO TRAPS, both of which make a plausible implementation measure as no change at all:\n *\n * 1. **`await Promise.resolve()` — and equally `Clock.sleep(0)` — do nothing.** Both resolve on a microtask, and\n * the microtask queue drains to empty before the event loop advances a single phase. A loop awaiting them\n * yields to other *microtasks* and to nothing else; no pending I/O callback runs. Measured: 555 ms of\n * starvation against a 568 ms unyielded baseline **on the synthetic yield-primitive benchmark below** —\n * a different, smaller workload than the 442 ms end-to-end load above, which is why the two baselines\n * differ. The yield must be a **macrotask** — hence\n * `Clock.yieldNow`, backed by `setImmediate` in production wiring.\n * 2. **Yielding per unit of work costs more than the work.** The yield has to be periodic, and `everyN` has to be\n * large enough that its cost disappears into the batch it interrupts.\n *\n * At `everyN = 1024` over that same synthetic workload the trade is close to free: 569 ms wall against a 568 ms\n * baseline, with the worst event-loop gap down from 568 ms to 13.8 ms.\n *\n * **Three experiments, three sets of numbers — do not mix them.** (a) The end-to-end 1M-id bulk load:\n * 442 ms wall / 450 ms blocked before, 256 ms / 19 ms after. (b) This synthetic yield-primitive comparison:\n * 568 ms / 568 ms unyielded, 569 ms / 13.8 ms with `setImmediate`. (c) A per-chunk insert microbenchmark:\n * 92 ms sync versus 636 ms via the threadpool. Quoting a baseline from one against a result from another is\n * how this file previously published a 92 ms operation with 819 ms of starvation inside it.\n */\n/**\n * The only part of a `Clock` that yielding actually needs.\n *\n * Deliberately looser than `Clock` so the compaction path can opt in: `CompactionDeps.clock` is declared as\n * `Pick<Clock, 'now'>` plus optional yield members, because its callers (including the `compact-segments` CLI)\n * have always supplied a bare `{ now }`. Requiring a full `Clock` there would have been a breaking change for\n * every one of them — which is exactly why the compaction yield shipped as dead code: the type could not carry\n * a clock capable of yielding.\n */\nexport interface Yielder {\n yieldNow?(): Promise<void>;\n sleep?(ms: number): Promise<void>;\n}\n\n/**\n * How many units of work pass between yields. Sized so the yield is unmeasurable against the batch it interrupts\n * (~60 yields across a 1M-id load) while still capping any single blocking stretch in the low tens of ms.\n */\nexport const YIELD_EVERY = 1024;\n\n/**\n * Build a periodic yield.\n *\n * Call the returned function **once per unit of work**. It returns `null` on the vast majority of calls — nothing\n * to await, nothing allocated — and a promise only on the `everyN`th, so the caller pays for a yield only when\n * one actually happens:\n *\n * ```ts\n * const tick = yieldEvery(clock);\n * for (const item of millions) {\n * work(item);\n * const pause = tick();\n * if (pause !== null) await pause;\n * }\n * ```\n *\n * The two-line shape is deliberate. `await tick()` would read better and would force a microtask turn on every\n * single iteration — an unconditional cost on the very loop this exists to keep fast.\n *\n * With no `clock` the result always returns `null`: the loop runs exactly as it did before this existed, so\n * adding a yield point to a code path can never change behaviour for a caller who did not opt in. `core/` cannot\n * supply a clock itself — it is timer-free by lint, which is the whole reason scheduling goes through the seam —\n * so `@cloudbitmaps/roaring` pre-binds a real one and flavor users get this with no wiring at all.\n */\nexport function yieldEvery(\n clock: Yielder | undefined,\n everyN: number = YIELD_EVERY,\n): () => Promise<void> | null {\n if (clock === undefined) return () => null;\n // Resolved once here rather than re-tested every yield.\n //\n // A clock predating `yieldNow` falls back to `sleep(1)`, which yields on a *timer-backed* clock at ~1 ms of\n // dead wall-clock apiece (measured: +10% on the load above). It does NOT yield on a clock whose `sleep`\n // ignores its argument and resolves on a microtask — `InstantClock` and `SimClock` both do, deliberately.\n // Those are non-production wirings where yielding is meaningless, and both now say so by implementing\n // `yieldNow` as an explicit no-op rather than arriving here by accident.\n const sleep = clock.sleep;\n const pause =\n clock.yieldNow !== undefined\n ? (): Promise<void> => clock.yieldNow!()\n : sleep !== undefined\n ? (): Promise<void> => sleep.call(clock, 1)\n : undefined;\n if (pause === undefined) return () => null; // a clock that can neither yield nor sleep: nothing to do\n let n = 0;\n return () => {\n if (++n < everyN) return null;\n n = 0;\n return pause();\n };\n}\n","/**\n * Canonical key encoding for a segment / chunk — one source of truth, used by both the storage\n * drivers and the HOT cache (DRY). The encoding is collision-proof and injection-proof:\n *\n * - The field delimiter (a space) and the \"no namespace\" sentinel (`/`) are characters the name\n * grammar forbids in a namespace/segment — so they can never appear inside\n * a name, can't be injected across the delimiter, and the absent-namespace case (`undefined`) is\n * encoded distinctly from any real namespace (an empty string is rejected by the grammar anyway).\n */\nimport type { ChunkRef, SegmentRef } from './ports';\n\nconst FIELD = ' ';\nconst NO_NAMESPACE = '/';\n\nexport function segmentKey(ref: SegmentRef): string {\n return `${ref.namespace ?? NO_NAMESPACE}${FIELD}${ref.segment}`;\n}\n\nexport function segmentPrefix(ref: SegmentRef): string {\n return `${segmentKey(ref)}${FIELD}`;\n}\n\nexport function chunkRefKey(ref: ChunkRef): string {\n return `${segmentPrefix(ref)}${ref.chunkKey}`;\n}\n\n/**\n * HOT-cache key for a chunk scoped to a specific Cold **generation** — {@link chunkRefKey} plus the generation\n * (space-delimited, injection-proof exactly as above). Keying the decoded-chunk cache by generation means a\n * compaction bump naturally misses the cache instead of serving a stale pre-compaction chunk (gap #4); the\n * superseded-generation entries age out under the LRU ceiling (no active purge needed).\n */\nexport function chunkGenKey(ref: ChunkRef, generation: number): string {\n return `${chunkRefKey(ref)}${FIELD}${generation}`;\n}\n","/**\n * Metrics seam (Phase 5a) — an injected sink the engine pushes typed events\n * to, exactly like the `Clock`/`Rng`/driver seams keep `core/` pure and storage-agnostic.\n *\n * Design: the library emits **neutral domain events** and stays vendor-agnostic — you (or a ~12-line\n * adapter) map them to OpenTelemetry / Datadog / a log line. The default is a **no-op**, and emission is\n * skipped entirely when no sink is wired (near-zero overhead, no telemetry dependency). Events carry **raw\n * observations** (bytes, counts, ms); turning those into billable units / dollars is the cost model's job\n * (Phase 5b), which keeps rates pluggable.\n *\n * Two caveats for sink authors: `onEvent` runs **synchronously on the I/O path**, so keep it cheap and\n * non-blocking (offload batching/network to your own async queue); and `segment`/`namespace` are\n * caller-controlled strings that may be PII and are **unbounded-cardinality** — do not map them to\n * per-series metric labels unless they're known low-cardinality and PII-free. See the getting-started\n * \"Observability\" section.\n */\n\n/** The segment operations that emit an `op` latency event (timed with the injected clock, at the facade). */\nexport type MetricOpName =\n | 'add'\n | 'remove'\n | 'addMany'\n | 'removeMany'\n | 'claimMany'\n | 'has'\n | 'count'\n | 'intersectInto'\n | 'unionInto'\n | 'andNotInto';\n\n/**\n * One observability event. A discriminated union on `kind` — new variants can be added over time without\n * breaking consumers (they switch on the kinds they care about). `namespace` is the segment's namespace\n * (absent ⇒ the default namespace). Segment names are identifiers, never bitmap contents (threat model:\n * never log PII / bitmap bits).\n */\nexport type MetricEvent =\n | {\n readonly kind: 'cold.get';\n readonly namespace?: string;\n readonly segment: string;\n /** Bytes returned (0 if the chunk was absent — a GET still happened). */\n readonly bytes: number;\n /**\n * Elapsed wall time of the read — includes any transient-retry backoff on the cold call. From the\n * injected clock, clamped to ≥ 0 (0 under the no-wait test clock).\n */\n readonly ms: number;\n }\n | { readonly kind: 'cache'; readonly hit: boolean }\n | {\n readonly kind: 'warm.read';\n readonly namespace?: string;\n readonly segment: string;\n /** Bytes read — a single-row get, or the summed rows of a list scan. */\n readonly bytes: number;\n }\n | {\n readonly kind: 'warm.write';\n readonly namespace?: string;\n readonly segment: string;\n /** Bytes of the committed delta row (emitted only on a successful conditional write). */\n readonly bytes: number;\n }\n | {\n readonly kind: 'retry';\n /** `occ` = optimistic-concurrency conflict backoff; `transient` = infrastructure-fault backoff. */\n readonly reason: 'occ' | 'transient';\n /** 1-based number of the attempt about to be retried. */\n readonly attempt: number;\n readonly delayMs: number;\n }\n | {\n readonly kind: 'intersect';\n /**\n * Which chunk-aligned combine this was. **Optional for backward compatibility** — absent means\n * `'intersect'`, which is all this event reported before `union`/`andNot` existed.\n *\n * For `'union'` over its *include* operands alone, `skippedChunks` is 0 by construction — union reads\n * every chunk of every operand, so there is nothing to prune. It can still be non-zero when a union\n * carries `exclude` operands, because a suppression list may hold keys no include does and those are\n * legitimately never fetched. So: 0 is the expected shape for a plain union, not a guarantee.\n */\n readonly op?: 'intersect' | 'union' | 'andNot';\n /** Operand count, including any `exclude` (suppression) operands. */\n readonly operands: number;\n /**\n * Distinct chunk **keys** selected to fetch — for `'intersect'`, those present in every operand.\n *\n * **Keys, not requests.** The actual cold GETs are roughly `fetchedChunks × operands`, plus one per\n * `exclude` that holds a given key, which is why this number is smaller than what the per-op budget\n * charges for the same call. The two are different units by design; if you are reconciling a bill, the\n * budget's accounting is the one that models requests.\n */\n readonly fetchedChunks: number;\n /**\n * **Distinct** chunk-keys pruned — never fetched (the chunk-skipping saving). Counts distinct keys,\n * not per-operand GETs, so it under-states the true GET saving when 3+ operands partially overlap.\n */\n readonly skippedChunks: number;\n }\n | {\n readonly kind: 'compaction';\n readonly namespace?: string;\n readonly segment: string;\n /** True iff this call committed a new generation. */\n readonly compacted: boolean;\n /** Why nothing was committed (when `compacted` is false) — the `CompactionResult.reason` (Phase D). */\n readonly reason?: string;\n /** Dirty Warm chunks pinned at scan time. */\n readonly dirtyChunks: number;\n /** Archived Warm rows actually purged (≤ dirtyChunks). */\n readonly purged: number;\n /** Elapsed wall time of the attempt (injected clock, ≥ 0; 0 under the no-wait test clock). */\n readonly ms: number;\n }\n | { readonly kind: 'op'; readonly name: MetricOpName; readonly ms: number };\n\n/**\n * The sink you plug in. One method, synchronous, fire-and-forget. It must never throw back into the\n * caller — `CloudRoaring` wraps a user sink with {@link safeMetrics} so a buggy sink can't break I/O.\n */\nexport interface IMetricsSink {\n onEvent(event: MetricEvent): void;\n}\n\n/** The default sink: discards everything, zero overhead. Used whenever no sink is wired. */\nexport const NOOP_METRICS: IMetricsSink = {\n onEvent(): void {\n /* discard */\n },\n};\n\n/**\n * Wrap a sink so a throwing/buggy `onEvent` can never break the data path — observability is strictly\n * best-effort. `CloudRoaring` applies this to the user-supplied sink at construction.\n */\nexport function safeMetrics(sink: IMetricsSink): IMetricsSink {\n if (sink === NOOP_METRICS) return sink;\n return {\n onEvent(event: MetricEvent): void {\n try {\n sink.onEvent(event);\n } catch {\n /* swallow — a metrics sink must never break a read/write */\n }\n },\n };\n}\n\n/** Accumulated totals — the shape returned by {@link CountingMetricsSink.snapshot}. */\nexport interface MetricsSnapshot {\n readonly cold: { readonly gets: number; readonly bytes: number; readonly totalMs: number };\n readonly warm: {\n readonly reads: number;\n readonly readBytes: number;\n readonly writes: number;\n readonly writeBytes: number;\n };\n readonly cache: { readonly hits: number; readonly misses: number };\n readonly retries: { readonly occ: number; readonly transient: number };\n readonly intersect: {\n readonly calls: number;\n readonly fetchedChunks: number;\n readonly skippedChunks: number;\n };\n readonly compaction: {\n readonly attempts: number;\n readonly committed: number;\n readonly dirtyChunks: number;\n readonly purged: number;\n readonly totalMs: number;\n };\n readonly ops: Readonly<\n Record<MetricOpName, { readonly count: number; readonly totalMs: number }>\n >;\n}\n\nconst OP_NAMES: readonly MetricOpName[] = [\n 'add',\n 'remove',\n 'addMany',\n 'removeMany',\n 'has',\n 'count',\n 'intersectInto',\n];\n\n/**\n * A ready-made sink that tallies events into a {@link MetricsSnapshot} — handy for tests, quick scripts,\n * and (Phase 5b) as the grounded-request-cost source behind `costReport()`. `snapshot()` returns an\n * independent copy; `reset()` zeroes the counters.\n */\nexport class CountingMetricsSink implements IMetricsSink {\n private cold = { gets: 0, bytes: 0, totalMs: 0 };\n private warm = { reads: 0, readBytes: 0, writes: 0, writeBytes: 0 };\n private cache = { hits: 0, misses: 0 };\n private retries = { occ: 0, transient: 0 };\n private intersect = { calls: 0, fetchedChunks: 0, skippedChunks: 0 };\n private compaction = { attempts: 0, committed: 0, dirtyChunks: 0, purged: 0, totalMs: 0 };\n private ops: Record<MetricOpName, { count: number; totalMs: number }> =\n CountingMetricsSink.zeroOps();\n\n private static zeroOps(): Record<MetricOpName, { count: number; totalMs: number }> {\n // null-proto so a type-violating event.name (e.g. '__proto__') can never reach Object.prototype\n const ops = Object.create(null) as Record<MetricOpName, { count: number; totalMs: number }>;\n for (const name of OP_NAMES) ops[name] = { count: 0, totalMs: 0 };\n return ops;\n }\n\n onEvent(event: MetricEvent): void {\n switch (event.kind) {\n case 'cold.get':\n this.cold.gets += 1;\n this.cold.bytes += event.bytes;\n this.cold.totalMs += event.ms;\n break;\n case 'cache':\n if (event.hit) this.cache.hits += 1;\n else this.cache.misses += 1;\n break;\n case 'warm.read':\n this.warm.reads += 1;\n this.warm.readBytes += event.bytes;\n break;\n case 'warm.write':\n this.warm.writes += 1;\n this.warm.writeBytes += event.bytes;\n break;\n case 'retry':\n if (event.reason === 'occ') this.retries.occ += 1;\n else this.retries.transient += 1;\n break;\n case 'intersect':\n this.intersect.calls += 1;\n this.intersect.fetchedChunks += event.fetchedChunks;\n this.intersect.skippedChunks += event.skippedChunks;\n break;\n case 'compaction':\n this.compaction.attempts += 1;\n if (event.compacted) this.compaction.committed += 1;\n this.compaction.dirtyChunks += event.dirtyChunks;\n this.compaction.purged += event.purged;\n this.compaction.totalMs += event.ms;\n break;\n case 'op': {\n const op = this.ops[event.name];\n op.count += 1;\n op.totalMs += event.ms;\n break;\n }\n default: {\n const exhaustive: never = event;\n return exhaustive;\n }\n }\n }\n\n snapshot(): MetricsSnapshot {\n const ops = Object.create(null) as Record<MetricOpName, { count: number; totalMs: number }>;\n for (const name of OP_NAMES) ops[name] = { ...this.ops[name] };\n return {\n cold: { ...this.cold },\n warm: { ...this.warm },\n cache: { ...this.cache },\n retries: { ...this.retries },\n intersect: { ...this.intersect },\n compaction: { ...this.compaction },\n ops,\n };\n }\n\n reset(): void {\n this.cold = { gets: 0, bytes: 0, totalMs: 0 };\n this.warm = { reads: 0, readBytes: 0, writes: 0, writeBytes: 0 };\n this.cache = { hits: 0, misses: 0 };\n this.retries = { occ: 0, transient: 0 };\n this.intersect = { calls: 0, fetchedChunks: 0, skippedChunks: 0 };\n this.compaction = { attempts: 0, committed: 0, dirtyChunks: 0, purged: 0, totalMs: 0 };\n this.ops = CountingMetricsSink.zeroOps();\n }\n}\n","/**\n * `withRetry` — the one retry/backoff primitive.\n *\n * A pure, storage-agnostic helper: it knows nothing about HTTP, AWS, or any SDK. It retries an operation\n * while the operation keeps failing with a **retryable** error (by default {@link TransientError}), waiting\n * a bounded, jittered, exponentially-growing delay between attempts. Time and randomness are **injected**\n * (the determinism seam) — production wires a `setTimeout`-backed clock + a real RNG; the\n * simulator wires virtual ones — so a backoff schedule is replayable from a seed and unit tests run with no\n * real sleeping.\n *\n * It deliberately does **not** retry deterministic failures ({@link WriteConflictError},\n * {@link ValidationError}, {@link IntegrityError}, {@link NotFoundError}, …): retrying those either can't\n * help or would be incorrect. OCC conflicts are retried by a *separate* loop (the engine's read-modify-write)\n * because each retry must re-read and re-apply, not blindly replay the same call.\n */\nimport type { Clock, Rng } from './determinism';\nimport { isTransientError, ValidationError } from './errors';\n\nexport interface RetryPolicy {\n /** Total attempts including the first (so `maxAttempts: 4` = 1 try + 3 retries). Must be ≥ 1. */\n readonly maxAttempts: number;\n /** Delay before the first retry, in ms. Grows by `backoffFactor` each subsequent retry. */\n readonly baseDelayMs: number;\n /** Upper bound on a single (pre-jitter) delay, in ms — caps the exponential growth. */\n readonly maxDelayMs: number;\n /** Exponential growth factor between retries (e.g. 2 ⇒ base, 2·base, 4·base, …). */\n readonly backoffFactor: number;\n /**\n * `'full'` ⇒ the actual wait is uniform in `[0, computed]` (AWS-recommended full jitter: decorrelates\n * concurrent retriers so they don't reconverge into a thundering herd). `'none'` ⇒ wait exactly `computed`.\n */\n readonly jitter: 'full' | 'none';\n}\n\n/**\n * Conservative defaults: 4 attempts, 50ms → 100 → 200 (×2), capped at 2s, full jitter. Tuned for a cloud\n * backend's brief throttle/5xx blip — enough to ride out a transient fault without turning a hard outage\n * into a long hang. Override per store/driver if your latency budget differs.\n */\nexport const DEFAULT_RETRY_POLICY: RetryPolicy = {\n maxAttempts: 4,\n baseDelayMs: 50,\n maxDelayMs: 2_000,\n backoffFactor: 2,\n jitter: 'full',\n};\n\n/** Backoff for the engine's OCC conflict loop — local contention resolves fast, so smaller + tighter. */\nexport const DEFAULT_OCC_BACKOFF: RetryPolicy = {\n maxAttempts: 1, // attempts are owned by the engine's loop; this policy only supplies the delay schedule\n baseDelayMs: 5,\n maxDelayMs: 200,\n backoffFactor: 2,\n jitter: 'full',\n};\n\nexport interface RetryDeps {\n readonly clock: Clock;\n readonly rng: Rng;\n /** Override which errors are retryable. Default: any {@link TransientError} (incl. `TimeoutError`). */\n readonly isRetryable?: (err: unknown) => boolean;\n /** Optional hook (observability) fired before each backoff wait. `attempt` is 1-based (the one that failed). */\n readonly onRetry?: (info: { attempt: number; delayMs: number; err: unknown }) => void;\n}\n\n/** Default classifier: retry transient infrastructure faults only. */\nexport function isTransient(err: unknown): boolean {\n return isTransientError(err);\n}\n\n/**\n * Backoff delay (ms) for the retry that follows a given 1-based attempt, before jitter is applied. Exposed\n * for tests and the engine's OCC loop. `attempt` 1 ⇒ `baseDelayMs`, 2 ⇒ `base·factor`, … capped at `maxDelayMs`.\n */\nexport function backoffDelayMs(policy: RetryPolicy, attempt: number): number {\n const raw = policy.baseDelayMs * policy.backoffFactor ** (attempt - 1);\n return Math.min(policy.maxDelayMs, raw);\n}\n\n/** Apply the policy's jitter to a computed delay using the injected RNG. */\nexport function applyJitter(policy: RetryPolicy, delayMs: number, rng: Rng): number {\n if (policy.jitter === 'none') return delayMs;\n return rng.next() * delayMs; // full jitter: uniform in [0, delayMs)\n}\n\n/**\n * Run `op`, retrying transient failures per `policy`. Resolves with `op`'s result, or rejects with the last\n * error once attempts are exhausted (or immediately for a non-retryable error). The thrown error is always\n * the *operation's* error — never a wrapper — so callers keep their typed-error branching.\n */\nexport async function withRetry<T>(\n op: () => Promise<T>,\n policy: RetryPolicy,\n deps: RetryDeps,\n): Promise<T> {\n const retryable = deps.isRetryable ?? isTransient;\n // `Math.max(1, x)` guards 0 and negatives but NOT NaN — `Math.max(1, NaN)` is NaN, and `1 <= NaN` is false,\n // so the loop below would never execute: `op()` never called, and the function rejects with the literal\n // `undefined` from `lastErr`. Every write would silently no-op without touching the backend, and callers\n // would catch a non-Error. Reachable from ordinary wiring — `maxAttempts: Number(process.env.X)` with the\n // var unset is NaN. Fail loudly instead, and floor it so a fractional value can't sleep on a final attempt\n // that never happens.\n if (!Number.isFinite(policy.maxAttempts) || policy.maxAttempts < 1) {\n throw new ValidationError(\n `retry.maxAttempts must be a finite number >= 1 (got ${String(policy.maxAttempts)})`,\n );\n }\n const attempts = Math.floor(policy.maxAttempts);\n let lastErr: unknown;\n for (let attempt = 1; attempt <= attempts; attempt++) {\n try {\n return await op();\n } catch (err) {\n lastErr = err;\n if (attempt >= attempts || !retryable(err)) throw err;\n const delayMs = applyJitter(policy, backoffDelayMs(policy, attempt), deps.rng);\n deps.onRetry?.({ attempt, delayMs, err });\n await deps.clock.sleep(delayMs);\n }\n }\n // Unreachable: the loop either returns or throws. Satisfies the type checker.\n throw lastErr;\n}\n","/**\n * SegmentEngine — the in-memory core: routing + tombstone merge + the HOT cache, exposing the read/write\n * ops over the driver interfaces. Storage-agnostic and time/random-free\n * (the determinism seam): all I/O is via injected drivers; the cache carries its own `Clock`.\n */\nimport { splitId, joinId, CHUNK_COUNT, MAX_REMAINDER } from './bit-route';\nimport type { CodecBitmap, CodecInterface } from './codec';\nimport {\n emptyDelta,\n applyAdd,\n applyRemove,\n applyAddAll,\n applyRemoveAll,\n effective,\n encodeDelta,\n decodeDelta,\n} from './chunk';\nimport type { ChunkDelta } from './chunk';\nimport { checkBudget, DEFAULT_BUDGET, resolvePerOpBudget } from './budget';\nimport type { Budget, BudgetOption } from './budget';\nimport { mapWithConcurrency } from './concurrency';\nimport { yieldEvery } from './cooperative';\nimport type { Clock, Rng } from './determinism';\nimport {\n BudgetExceededError,\n IntegrityError,\n ValidationError,\n WriteConflictError,\n isWriteConflictError,\n} from './errors';\nimport { chunkGenKey, chunkRefKey } from './keys';\nimport type { BoundedLru } from './lru';\nimport { NOOP_METRICS, safeMetrics } from './metrics';\nimport type { IMetricsSink } from './metrics';\nimport { NO_ROW } from './ports';\nimport type {\n ChunkRef,\n ColdChunkSource,\n IWarmDriver,\n SegmentRef,\n SegmentSize,\n WarmReadOptions,\n WarmRow,\n} from './ports';\nimport { DEFAULT_OCC_BACKOFF, applyJitter, backoffDelayMs } from './retry';\nimport type { RetryPolicy } from './retry';\n\nconst DEFAULT_MAX_BITMAP_BYTES = 1 << 20; // 1 MiB per bitmap — generous; real chunks are far smaller\nconst DEFAULT_MAX_RETRIES = 16;\n/** Max overlapping-chunk intersections in flight — bounds memory + concurrent reads (invariant 6). */\nconst DEFAULT_INTERSECT_CONCURRENCY = 8;\n/**\n * Ids staged as uncompressed numbers before `mutateMany` folds them into per-chunk bitmaps.\n *\n * Caps the *transient* uncompressed overhead regardless of stream length — **measured ~28 MB** at this value\n * (1M ids spread across ~65,000 chunks; not the ~8 MB a naive 8-bytes-per-number estimate suggests, because the\n * cost is dominated by per-array and Map overhead across tens of thousands of small arrays). What persists\n * across the whole call is the compressed bitmaps this folds into, which for the same 5M ids measured **11 MB\n * against 212 MB** held as JS numbers. Matches bulk-load's `BULK_FLUSH_IDS`, which has the same shape.\n */\nconst MUTATE_STAGE_IDS = 1 << 20;\n/** Ids between cooperative yields while ingesting — see `cooperative.ts` and bulk-load's matching constant. */\nconst YIELD_EVERY_IDS = 1 << 14;\n\n/**\n * Pure no-wait clock / zero RNG used when the engine is constructed without a time source (e.g. unit tests\n * that don't exercise backoff). `sleep` resolves on a microtask (no timer — `core/` is timer-free) and the\n * RNG returns 0, so OCC backoff collapses to \"retry immediately\" — the pre-4b behaviour. Production wiring\n * (`CloudRoaring`) injects a real `setTimeout`-backed clock + RNG, enabling genuine jittered backoff.\n */\nclass InstantClock implements Clock {\n now(): number {\n return 0;\n }\n sleep(): Promise<void> {\n return Promise.resolve();\n }\n /**\n * An explicit no-op, so the intent is stated rather than inferred.\n *\n * Without it, `yieldEvery` would fall back to `sleep(1)` — and this clock's `sleep` ignores its argument and\n * resolves on a microtask, so the \"yield\" would silently do nothing while every doc comment claimed it did\n * something. This wiring has no real event loop to be courteous to (it is the clock used when nobody injects\n * one), so no-op is the right behaviour; it just has to be a decision rather than an accident.\n */\n yieldNow(): Promise<void> {\n return Promise.resolve();\n }\n}\nclass ZeroRng implements Rng {\n next(): number {\n return 0;\n }\n}\n\n/**\n * Default ceiling on resident warm-delta bytes for a single segment scan: 64 MiB.\n *\n * Chosen to be generous enough that no realistic segment trips it — a maximally-wide segment of 65,536 chunks\n * would need ~1 KiB of warm delta per chunk to reach it — while still being small enough to keep a modest\n * container (a 512 MiB Lambda, say) alive rather than OOM-killed when a pathological segment or a hostile\n * caller shows up.\n */\nexport const DEFAULT_MAX_WARM_SCAN_BYTES = 64 * 1024 * 1024;\n\n/**\n * Default number of Warm chunk writes in flight per `addMany`/`removeMany`: **4**.\n *\n * The flusher was serial by default, which meant a 100-chunk `addMany` against a backend with ~10 ms of\n * round-trip latency spent a full second doing nothing but waiting — one round-trip at a time, on work that has\n * no ordering requirement between chunks. Distinct chunks are independent OCC rows.\n *\n * **Why 4 and not more.** The number is chosen against the *backend's* tolerance, not the client's appetite. A\n * write here is a read-modify-write, so 4 in flight is up to 8 concurrent requests per `addMany` call — and a\n * server handling many concurrent calls multiplies that again. Provisioned-capacity backends answer a burst\n * with throttling, which is free only while retries can absorb it (4 attempts, exponential backoff, full\n * jitter). Swept against a **modelled** backend — an in-process fake that throttles on concurrent requests in\n * flight, not a real DynamoDB — 64 chunks, 5 trials each, counting a lost id or a surfaced error as a failure:\n *\n * ```text\n * backend capacity: 1 2 4 8\n * writeConcurrency 4: 0/5 0/5 0/5 0/5\n * writeConcurrency 8: 0/5 0/5 0/5 0/5\n * writeConcurrency 16: 0/5 0/5 0/5 0/5\n * writeConcurrency 32: 3/5 0/5 0/5 0/5 ← retry budget exhausted\n * ```\n *\n * So the retry machinery holds far past 4; 4 is deliberately conservative, sitting 8x below the first observed\n * failure against the harshest backend modelled. The remaining headroom is spent on the multiplier this table\n * does not capture — many concurrent `addMany` calls sharing one backend — rather than on more throughput per\n * call. A caller who knows their capacity can raise it.\n *\n * Raise it if your backend is provisioned for it (on-demand DynamoDB, or a Postgres pool sized to match); set\n * it to `1` for the previous strictly-serial behaviour.\n */\nexport const DEFAULT_WRITE_CONCURRENCY = 4;\n\nexport interface EngineDeps {\n readonly warm: IWarmDriver;\n readonly cold: ColdChunkSource;\n /** Optional HOT cache of decoded (immutable) Cold chunks. */\n readonly cache?: BoundedLru<string, CodecBitmap>;\n readonly maxBitmapBytes?: number;\n /**\n * The bitmap codec — **required**. `core/` is\n * codec-agnostic: it can have no default, because the concrete codec lives in a *flavor* package that depends\n * on core (a default here would invert that arrow). A flavor's facade injects it — `@cloudbitmaps/roaring`\n * passes `roaringCodec` — so applications never see this.\n */\n readonly codec: CodecInterface;\n readonly maxRetries?: number;\n /** Injected for jittered OCC backoff + replayable tests; defaults to an instant clock / zero RNG. */\n readonly clock?: Clock;\n readonly rng?: Rng;\n /** Backoff schedule between OCC conflict retries; defaults to {@link DEFAULT_OCC_BACKOFF}. */\n readonly occBackoff?: RetryPolicy;\n /** Observability sink (Phase 5a); defaults to a no-op. Assumed exception-safe (the facade wraps it). */\n readonly metrics?: IMetricsSink;\n /**\n * Warm read consistency for the READ paths (`has`/`count`/`iterate`/`intersect`); default `'strong'`\n * (read-your-writes). `'eventual'` trades read-after-write for ~½ the DynamoDB RCU (gap #9). The OCC\n * read-modify-write path is always strong regardless (correctness).\n */\n readonly warmReadConsistency?: 'strong' | 'eventual';\n /**\n * Max Warm chunk writes in flight per `addMany`/`removeMany` (the bounded flusher).\n * Default {@link DEFAULT_WRITE_CONCURRENCY}.\n *\n * Each chunk is its own OCC row, so distinct chunks never conflict with each other and fanning them out is\n * safe. Raise it for more throughput against a backend with capacity to spare; set it to `1` for strictly\n * serial writes.\n *\n * As before, `addMany`/`removeMany` are **not atomic**: a mid-flush failure can leave a partial result. What\n * concurrency changes is only *how much* of the batch may already have landed when the first error surfaces —\n * the flusher stops scheduling on the first failure, but writes already in flight still settle.\n */\n readonly writeConcurrency?: number;\n /**\n * Hard ceiling on the bytes one warm scan may hold resident, in bytes. Default {@link DEFAULT_MAX_WARM_SCAN_BYTES}.\n *\n * **Separate from `budget`, and enforced even when `budget: false`.** The budget bounds *cost* — billable\n * requests — which is a different axis from memory, and conflating the two is what let a segment with\n * thousands of warm chunks materialise ~12 MB before a `maxRequests: 2` budget could refuse it. It is also\n * why `intersect` cannot use the budget as a memory bound: its budget is `common keys × operands`, a product\n * that one wide operand can legitimately exceed in row count while staying entirely legal.\n *\n * Always on, because a ceiling that `budget: false` switches off is missing at exactly the moment it is\n * needed. Configurable, because a ceiling you cannot raise is a landmine for a legitimately large segment.\n */\n readonly maxWarmScanBytes?: number;\n /**\n * Per-op denial-of-wallet budget (07 Decision #3 / T3), already resolved by the facade: a {@link Budget} to\n * enforce, or `null` to disable. Undefined ⇒ {@link DEFAULT_BUDGET} (a direct engine construction still gets\n * the generous default). Read ops refuse before fan-out if they'd exceed it.\n */\n readonly budget?: Budget | null;\n}\n\ntype Mutator = (delta: ChunkDelta, ids: CodecBitmap) => void;\n\n/** One resolved operand of a chunk-aligned combine: its key set + warm deltas + pinned generation. */\ninterface Operand {\n readonly seg: SegmentRef;\n readonly warmRows: Map<number, Uint8Array>;\n readonly keys: Set<number>;\n readonly gen: number | null | undefined;\n}\n\nexport class SegmentEngine {\n private readonly warm: IWarmDriver;\n private readonly cold: ColdChunkSource;\n private readonly cache: BoundedLru<string, CodecBitmap> | undefined;\n private readonly codec: CodecInterface;\n private readonly maxBitmapBytes: number;\n private readonly maxRetries: number;\n private readonly clock: Clock;\n private readonly rng: Rng;\n private readonly occBackoff: RetryPolicy;\n private readonly metrics: IMetricsSink;\n private readonly metricsOn: boolean;\n /** Consistency for READ-path Warm fetches (precomputed; OCC RMW passes strong explicitly, see `warmGet`). */\n private readonly readOpts: WarmReadOptions;\n private readonly writeConcurrency: number;\n private readonly maxWarmScanBytes: number;\n /** Resolved per-op budget (null = disabled); undefined deps ⇒ the generous default. See {@link checkBudget}. */\n private readonly budget: Budget | null;\n\n constructor(deps: EngineDeps) {\n this.warm = deps.warm;\n this.cold = deps.cold;\n this.cache = deps.cache;\n this.codec = deps.codec;\n this.maxBitmapBytes = deps.maxBitmapBytes ?? DEFAULT_MAX_BITMAP_BYTES;\n this.maxRetries = deps.maxRetries ?? DEFAULT_MAX_RETRIES;\n this.clock = deps.clock ?? new InstantClock();\n this.rng = deps.rng ?? new ZeroRng();\n this.occBackoff = deps.occBackoff ?? DEFAULT_OCC_BACKOFF;\n this.readOpts = { consistent: (deps.warmReadConsistency ?? 'strong') !== 'eventual' };\n this.writeConcurrency = deps.writeConcurrency ?? DEFAULT_WRITE_CONCURRENCY;\n this.maxWarmScanBytes = deps.maxWarmScanBytes ?? DEFAULT_MAX_WARM_SCAN_BYTES;\n if (!Number.isFinite(this.maxWarmScanBytes) || this.maxWarmScanBytes < 1) {\n throw new ValidationError(\n `maxWarmScanBytes must be a finite number >= 1 (got ${String(deps.maxWarmScanBytes)})`,\n );\n }\n // undefined ⇒ the generous default; null ⇒ explicitly disabled (must not be re-defaulted by `??`).\n this.budget = deps.budget === undefined ? DEFAULT_BUDGET : deps.budget;\n // Wrap for defense-in-depth (idempotent for the no-op) so even a direct engine construction with a\n // throwing sink can't break the data path; `metricsOn` short-circuits all emission when unused.\n this.metrics = safeMetrics(deps.metrics ?? NOOP_METRICS);\n this.metricsOn = this.metrics !== NOOP_METRICS;\n }\n\n add(seg: SegmentRef, id: number): Promise<void> {\n const { chunkKey, remainder } = splitId(id);\n return this.readModifyWrite(seg, chunkKey, (d) => applyAdd(d, remainder));\n }\n\n remove(seg: SegmentRef, id: number): Promise<void> {\n const { chunkKey, remainder } = splitId(id);\n return this.readModifyWrite(seg, chunkKey, (d) => applyRemove(d, remainder));\n }\n\n addMany(seg: SegmentRef, ids: Iterable<number> | AsyncIterable<number>): Promise<void> {\n return this.mutateMany(seg, ids, applyAddAll);\n }\n\n removeMany(seg: SegmentRef, ids: Iterable<number> | AsyncIterable<number>): Promise<void> {\n return this.mutateMany(seg, ids, applyRemoveAll);\n }\n\n /**\n * **Atomically claim ids: add them, and return only the ones that were not already there.**\n *\n * The durable analogue of Redis `SETBIT` returning the prior bit — the primitive an exactly-once \"have I\n * already processed / already sent to this id?\" check needs. `has()` then `add()` cannot do this: two workers\n * can both read absent and both proceed.\n *\n * **Bulk on purpose.** The per-id shape is the one this library is worst at, because a Warm write rewrites a\n * whole 64K-id chunk bitmap: claiming 5,000 ids one at a time costs ~5,000 writes and ~23 MB, and claiming\n * them in one call costs 1 write and ~8 KB. So this takes a batch and does one OCC read-modify-write per\n * distinct chunk — Redis's semantics at this library's cost shape, rather than Redis's cost shape.\n *\n * **Atomicity is per id, which is the guarantee that matters here.** Each id lives in exactly one chunk, and a\n * chunk is one OCC row, so for any id exactly one concurrent claimer sees it as new. It is NOT atomic across\n * chunks (neither is `addMany`) — a mid-flight failure can leave some chunks claimed. Re-running is safe:\n * already-claimed ids simply come back as not-new.\n *\n * **The presence test consults Cold, not just the Warm delta.** Checking `adds` alone would report an id as\n * newly claimed when a compaction had already folded it into a Cold generation — silently breaking\n * exactly-once on any segment that has ever been compacted. The check is the full effective set,\n * `(cold ∪ adds) \\ removes`.\n *\n * Returns the claimed ids grouped nowhere in particular — order is unspecified.\n */\n async claimMany(seg: SegmentRef, ids: Iterable<number>): Promise<number[]> {\n // Group by chunk first: the whole point is one write per chunk rather than one per id.\n const byChunk = new Map<number, number[]>();\n for (const id of ids) {\n const { chunkKey, remainder } = splitId(id);\n const bucket = byChunk.get(chunkKey);\n if (bucket) bucket.push(remainder);\n else byChunk.set(chunkKey, [remainder]);\n }\n const gen = await this.currentGen(seg);\n const perChunk = await mapWithConcurrency(\n [...byChunk],\n this.writeConcurrency,\n async ([chunkKey, remainders]) => {\n const cold = (await this.coldChunk({ ...seg, chunkKey }, gen)) ?? this.codec.empty();\n // `claimed` is assigned — never appended to — because `readModifyWrite` re-runs this callback on an OCC\n // conflict. Accumulating across attempts would report an id as newly claimed by us when the retry showed\n // it had been claimed by the winner of the race, which is exactly the guarantee being sold.\n let claimed: number[] = [];\n await this.readModifyWrite(seg, chunkKey, (delta) => {\n const present = effective(cold, delta);\n claimed = remainders.filter((r) => !present.has(r));\n for (const r of claimed) applyAdd(delta, r);\n });\n return claimed.map((r) => joinId(chunkKey, r));\n },\n );\n return perChunk.flat();\n }\n\n async has(seg: SegmentRef, id: number, opts?: WarmReadOptions): Promise<boolean> {\n const { chunkKey, remainder } = splitId(id);\n const ref: ChunkRef = { ...seg, chunkKey };\n // Default: honor the store's warmReadConsistency (gap #9). Callers that need read-your-writes regardless\n // (the GDPR subjectReport/eraseSubject membership check) pass `{ consistent: true }` to force strong.\n const row = await this.warmGet(ref, opts ?? this.readOpts);\n if (row) {\n const delta = decodeDelta(row.bytes, this.maxBitmapBytes, this.codec);\n if (delta.removes.has(remainder)) return false;\n if (delta.adds.has(remainder)) return true;\n }\n const cold = await this.coldChunk(ref, await this.currentGen(seg));\n return cold ? cold.has(remainder) : false;\n }\n\n async count(seg: SegmentRef): Promise<number> {\n const warmRows = await this.collectWarm(seg, 'count', this.budget?.maxRequests ?? null);\n // Cheap count (Phase 5c): when the Cold source can serve per-chunk cardinality from its `.crbm` index,\n // a warm-delta-free chunk is counted straight from the index — no payload fetch/decode — and only the\n // dirty chunks (those with a Warm delta) are merged. A source without that capability, or a segment with\n // no Cold generation, falls back to fetching + merging every effective chunk.\n //\n // Generation resolution ordering (gap #4): resolve `gen` **after** the shape read (`cardinalities` /\n // `chunkKeys`), matching `intersect`. A non-null shape read means the source resolved and cached a non-null\n // snapshot, so `gen` can't then come back null while cold data is present. Resolving `gen` *first* races a\n // segment's very first publish — `gen` reads null (no registry record yet), the shape read then sees the\n // freshly-published generation, and the stale null `gen` would make `coldChunk` skip cold for dirty chunks\n // (a silent undercount). `gen` and the shape read share the one snapshot, so within a call shorter than\n // `coldGenTtlMs` the count is generation-consistent — **absent cache-pressure eviction**: if the reader\n // cache (`maxOpenSegments`, gap #1) evicts this segment mid-call, the re-read re-resolves fresh (bypassing\n // the TTL), which can hop generations even sub-TTL. Likewise a *long* count that straddles a mid-call TTL\n // boundary during a compaction can mix generations — either way a bounded, transient skew that converges\n // next call (never a torn read: each chunk is still a whole, immutable generation). Full intra-op snapshot\n // isolation is deferred (gap #4).\n const cardinalities = this.cold.cardinalities ? await this.cold.cardinalities(seg) : null;\n if (!cardinalities) {\n const chunkKeys = await this.chunkKeys(seg, warmRows);\n checkBudget(this.budget, chunkKeys.length, 'count'); // one cold fetch per effective chunk (before fan-out)\n const gen = await this.currentGen(seg);\n let total = 0;\n for (const chunkKey of chunkKeys) {\n total += (await this.effectiveChunk(seg, chunkKey, warmRows, gen)).size;\n }\n return total;\n }\n // Cheap path: only the dirty (Warm) chunks are fetched; clean chunks are counted from the index (0 reads).\n checkBudget(this.budget, warmRows.size, 'count');\n const gen = await this.currentGen(seg);\n const keys = new Set<number>(warmRows.keys());\n for (const k of cardinalities.keys()) keys.add(k);\n let total = 0;\n for (const k of keys) {\n this.assertChunkKeyInRange(k);\n total += warmRows.has(k)\n ? (await this.effectiveChunk(seg, k, warmRows, gen)).size // dirty: merge (Cold ∪ adds) \\ removes\n : (cardinalities.get(k) ?? 0); // clean: index cardinality, zero payload reads\n }\n return total;\n }\n\n /** Whether the Cold source can measure segment size (for grounded cost); false ⇒ storage isn't grounded. */\n get supportsColdSize(): boolean {\n return typeof this.cold.sizeOf === 'function';\n }\n\n /** Grounded Cold size of a segment's current generation (cost reporting), or null if it has no generation. */\n segmentSize(seg: SegmentRef): Promise<SegmentSize | null> {\n return this.cold.sizeOf ? this.cold.sizeOf(seg) : Promise.resolve(null);\n }\n\n async *iterate(seg: SegmentRef): AsyncGenerator<number> {\n const warmRows = await this.collectWarm(seg, 'iterate', this.budget?.maxRequests ?? null);\n const chunkKeys = await this.chunkKeys(seg, warmRows);\n checkBudget(this.budget, chunkKeys.length, 'iterate'); // one cold fetch per effective chunk (before fan-out)\n const gen = await this.currentGen(seg); // after the shape read (see `count`) — avoids a first-publish undercount\n for (const chunkKey of chunkKeys) {\n const eff = await this.effectiveChunk(seg, chunkKey, warmRows, gen);\n for (const remainder of eff) yield joinId(chunkKey, remainder);\n }\n }\n\n /**\n * `segs[0] ∩ segs[1] ∩ …`, minus every id in `options.exclude` — streamed ascending.\n *\n * The `exclude` operands are what make suppression **compose without materialising**. Applying suppression\n * afterwards (intersect into a temp segment, then remove) writes an intermediate segment that nobody wants;\n * applying it here folds it into the same chunk-aligned pass. It is also cheaper than it looks: an exclude\n * operand is read **only at the keys that survived the intersection** — the cost is bounded by the\n * audience's surviving key count and **never scales with the size of the suppression list**. Subtracting a\n * 61,000-chunk global opt-out list costs at most one read per surviving key, not 61,000.\n *\n * ---\n *\n * Chunk-skipping intersection. Computes\n * `seg[0] ∩ seg[1] ∩ …` and streams the result ids ascending. It aligns each segment's *effective*\n * chunk-key set (Warm ∪ Cold), keeps only keys present in **all** operands (a key missing from any\n * operand can't contribute → its **Cold chunks are never fetched** — the core saving), then for each\n * surviving key merges tiers per operand (operand fetches run in parallel) and hands the buffers to the\n * roaring engine for the AND, streaming results through a bounded in-flight window.\n *\n * **Memory:** the Cold payload footprint is bounded by the window (`concurrency × operands × chunk`), not\n * by segment size — that's the Lambda-friendly property. The **Warm** side, however, is snapshotted up\n * front (`collectWarm` per operand), so total memory also carries each operand's Warm size. Under\n * Topology-A (read-mostly; compaction keeps Warm small) that's negligible; a streaming Warm/Cold\n * merge-join for large Warm is Phase 4.\n *\n * Generation-consistent within the call (normal case): each operand's current generation is resolved **once**\n * up front (before the fan-out) and threaded into every chunk read, so a concurrent compaction can't corrupt\n * or tear the result — every chunk read is a whole, checksum-verified, immutable generation (finding C10).\n * The edge a *long* call can hit: if it straddles a mid-call `coldGenTtlMs` boundary and a compaction has\n * committed, an operand's not-yet-read chunks may re-resolve forward to the newer generation (a generation\n * hop within one long call) — the call never crashes or returns a torn object, but may mix generations. That\n * window is a single TTL (default 2 s), not the multi-cycle GC-sweep window it took pre-Phase-B. A shorter call\n * is unaffected **unless the reader cache evicts an operand mid-call** (`maxOpenSegments`, gap #1): the re-read\n * re-resolves fresh (bypassing the TTL), which can hop generations even sub-TTL — still whole/immutable per\n * read, never torn. Full intra-op snapshot isolation is deferred (gap #4).\n */\n intersect(\n segs: readonly SegmentRef[],\n options?: { concurrency?: number; budget?: BudgetOption; exclude?: readonly SegmentRef[] },\n ): AsyncGenerator<number> {\n return this.combine(segs, options?.exclude ?? [], 'all', 'intersect', options);\n }\n\n /**\n * `segs[0] ∪ segs[1] ∪ …`, minus every id in `options.exclude` — streamed ascending.\n *\n * **Union is the one composite read with no chunk-skipping**, and that is a property of the operation rather\n * than of this implementation: an id in *any* operand belongs to the result, so every chunk of every operand\n * has to be read. `intersect` can prune a key absent from any operand; union cannot prune anything. It is\n * budgeted exactly like `intersect` so a wide union is refused rather than quietly billed.\n */\n union(\n segs: readonly SegmentRef[],\n options?: { concurrency?: number; budget?: BudgetOption; exclude?: readonly SegmentRef[] },\n ): AsyncGenerator<number> {\n return this.combine(segs, options?.exclude ?? [], 'any', 'union', options);\n }\n\n /**\n * `seg \\ (excludes[0] ∪ excludes[1] ∪ …)` — streamed ascending. Suppression on its own.\n *\n * Reads every chunk of `seg` (any of them may survive) but each exclude **only where it overlaps `seg`**, so\n * the cost scales with the segment being filtered rather than with the size of the suppression list.\n */\n andNot(\n seg: SegmentRef,\n excludes: readonly SegmentRef[],\n options?: { concurrency?: number; budget?: BudgetOption },\n ): AsyncGenerator<number> {\n return this.combine([seg], excludes, 'all', 'andNot', options);\n }\n\n private async *combine(\n segs: readonly SegmentRef[],\n excludeSegs: readonly SegmentRef[],\n mode: 'all' | 'any',\n op: 'intersect' | 'union' | 'andNot',\n options?: { concurrency?: number; budget?: BudgetOption },\n ): AsyncGenerator<number> {\n // Validated HERE rather than in the public wrappers, deliberately. `combine` is an async generator, so a\n // throw surfaces when the caller first iterates — which is the behaviour `intersect` has always had, and\n // `await expect(collect(engine.intersect([]))).rejects` in the suite depends on it. Guarding in the\n // wrappers would make them throw synchronously instead, a silent breaking change for anyone whose\n // try/catch sits around the iteration. Delegating through `yield*` would restore it at the cost of a\n // microtask per id on the hottest streaming path, which is not a trade worth making for an error case.\n if (segs.length === 0) {\n throw new ValidationError(`${op} requires at least one segment`);\n }\n if (op === 'andNot' && excludeSegs.length === 0) {\n throw new ValidationError('andNot requires at least one segment to subtract');\n }\n const limit = options?.concurrency ?? DEFAULT_INTERSECT_CONCURRENCY;\n if (!Number.isInteger(limit) || limit < 1) {\n throw new ValidationError(\n `concurrency must be a positive integer; got ${options?.concurrency}`,\n );\n }\n // Per-op budget override (else the store budget); resolved before any I/O so a bad value fails fast. A\n // partial override inherits the store's tightening (not the generous default) — see resolvePerOpBudget.\n const budget = resolvePerOpBudget(options?.budget, this.budget);\n\n // ① Index-map extraction: each operand's effective key set (Warm ∪ Cold) + its current generation, resolved\n // ONCE here (not per chunk) so the fan-out below adds no per-chunk generation re-resolve. Only metadata so far.\n const extract = async (seg: SegmentRef) => {\n // see collectWarm: this budget is a product, not a row count;\n const warmRows = await this.collectWarm(seg, op, null);\n const keys = await this.chunkKeys(seg, warmRows);\n const gen = await this.currentGen(seg);\n return { seg, warmRows, keys: new Set(keys), gen };\n };\n const [operands, excludes] = await Promise.all([\n Promise.all(segs.map(extract)),\n Promise.all(excludeSegs.map(extract)),\n ]);\n\n // ② Key alignment. Candidate keys come from the INCLUDE operands only — an exclude can subtract ids from a\n // chunk but can never introduce one, so a key no include holds cannot appear in the result however large\n // the suppression list is. That asymmetry is what makes suppression cheap here.\n //\n // 'all' (intersect / andNot): keys present in EVERY include. Start from the smallest set to minimize the\n // scan — a key missing from any operand cannot survive the AND.\n // 'any' (union): keys present in ANY include. No pruning is possible; see `union`'s note.\n const candidates: number[] = [];\n if (mode === 'all') {\n const pivot = operands.reduce((a, b) => (a.keys.size <= b.keys.size ? a : b));\n for (const k of pivot.keys) {\n if (operands.every((o) => o.keys.has(k))) candidates.push(k);\n }\n } else {\n const seen = new Set<number>();\n for (const o of operands) for (const k of o.keys) seen.add(k);\n for (const k of seen) candidates.push(k);\n }\n candidates.sort((a, b) => a - b); // defensive: `chunkKeys` already returns sorted; don't rely on it\n const common = candidates;\n\n // Denial-of-wallet budget (before the fan-out AND before we emit a \"work done\" metric): the heavy cost is\n // one cold fetch per surviving key per operand — refuse up front if that would exceed the budget (07\n // Decision #3 / T3). Placed above the metric so a refused intersect doesn't report chunks it never fetched.\n //\n // Units are the chunk reads this will actually issue, counted per key: every include present at that key\n // (all of them under 'all'), plus only those excludes that hold the key. Counting excludes as always-present\n // would refuse work that costs nothing — the whole point of the asymmetry above. For a plain `intersect`\n // with no excludes this reduces to `common.length * operands.length`, exactly as before.\n let units = 0;\n for (const key of common) {\n for (const o of operands) if (mode === 'all' || o.keys.has(key)) units += 1;\n for (const e of excludes) if (e.keys.has(key)) units += 1;\n }\n checkBudget(budget, units, op);\n\n // Emit the chunk-skipping efficiency: `fetched` = shared keys we'll read, `skipped` = distinct keys\n // pruned across all operands (never fetched — the core saving). Bounded metadata work, no extra I/O.\n if (this.metricsOn) {\n const distinctKeys = new Set<number>();\n for (const op of operands) {\n for (const k of op.keys) distinctKeys.add(k);\n }\n for (const e of excludes) for (const k of e.keys) distinctKeys.add(k);\n // `fetchedChunks` counts **distinct chunk keys**, not per-operand reads — its long-standing documented\n // unit, asserted by the bench anchors and the metrics tests. Deliberately NOT changed to match the\n // budget's request count: they measure different things on purpose (keys vs billable requests), and\n // silently redefining a published observability field in a patch release would break every dashboard\n // built on it. The relationship is documented on the event instead.\n this.metrics.onEvent({\n kind: 'intersect',\n op,\n operands: segs.length + excludes.length,\n fetchedChunks: common.length,\n // Never negative: under 'any' every candidate key came from some operand, so `distinctKeys` is a\n // superset of `common`; excludes only ever add keys here.\n skippedChunks: distinctKeys.size - common.length,\n });\n }\n\n // ③–⑤ Surgical streaming AND through a bounded, order-preserving window: fetch+intersect at most\n // `limit` keys concurrently, yield each key's ids before priming far ahead (bounded Cold footprint).\n // Each task resolves to a value (never rejects) so an error on one key can't leave the other in-flight\n // promises unhandled — we surface it, in key order, when its slot is drained.\n type Slot = { key: number; result: CodecBitmap | null; error?: unknown };\n const startAt = (key: number): Promise<Slot> =>\n this.combineChunk(operands, excludes, mode, key).then(\n (result) => ({ key, result }),\n (error: unknown) => ({ key, result: null, error }),\n );\n\n const inFlight: Array<Promise<Slot>> = [];\n let next = 0;\n while (next < common.length && inFlight.length < limit) inFlight.push(startAt(common[next++]!));\n while (inFlight.length > 0) {\n const slot = await inFlight.shift()!; // FIFO over ascending keys ⇒ ascending output\n if (next < common.length) inFlight.push(startAt(common[next++]!));\n if (slot.error !== undefined) throw slot.error;\n if (slot.result && !slot.result.isEmpty) {\n for (const remainder of slot.result) yield joinId(slot.key, remainder);\n }\n }\n }\n\n /**\n * The AND of one chunk key across all operands (tier-merged per operand), or `null` if empty. Operand\n * chunks are fetched **in parallel** (the spec's parallel byte-range reads). `acc` takes ownership of the\n * first operand's effective chunk and mutates it in place — safe because `effectiveChunk` always returns\n * a FRESH bitmap (never a cached/shared Cold instance), so this can't poison the HOT cache.\n */\n private async combineChunk(\n operands: ReadonlyArray<Operand>,\n excludes: ReadonlyArray<Operand>,\n mode: 'all' | 'any',\n chunkKey: number,\n ): Promise<CodecBitmap | null> {\n // Under 'any' an include may simply not hold this key; skip it rather than fetching a certainly-empty\n // chunk. Under 'all' every include holds every candidate key by construction, so the filter is a no-op.\n const present = mode === 'all' ? operands : operands.filter((o) => o.keys.has(chunkKey));\n if (present.length === 0) return null;\n const chunks = await Promise.all(\n present.map((op) => this.effectiveChunk(op.seg, chunkKey, op.warmRows, op.gen)),\n );\n const acc = chunks[0]!; // fresh, owned (see method note)\n for (let i = 1; i < chunks.length; i++) {\n if (mode === 'all') {\n acc.andInPlace(chunks[i]!);\n if (acc.isEmpty) return null; // once empty, the remaining operands can't revive it\n } else {\n acc.orInPlace(chunks[i]!);\n }\n }\n if (acc.isEmpty) return null;\n\n // Suppression, folded into the same pass. Only excludes that actually hold this key are fetched — this is\n // where a large global opt-out list stops being expensive. Fetched lazily rather than alongside the\n // includes above, because an AND that collapsed to empty means there is nothing left to suppress.\n const relevant = excludes.filter((e) => e.keys.has(chunkKey));\n if (relevant.length > 0) {\n const cuts = await Promise.all(\n relevant.map((e) => this.effectiveChunk(e.seg, chunkKey, e.warmRows, e.gen)),\n );\n for (const cut of cuts) {\n acc.andNotInPlace(cut);\n if (acc.isEmpty) return null;\n }\n }\n return acc;\n }\n\n /**\n * Materialize `seg[0] ∩ seg[1] ∩ …` into `dest` via batched `addMany` (streaming, bounded memory).\n * **Not atomic** — like `addMany`, ids land chunk-by-chunk; a failure mid-stream leaves a partial result.\n * `dest` is added to, not replaced.\n */\n async intersectInto(\n dest: SegmentRef,\n segs: readonly SegmentRef[],\n options?: {\n concurrency?: number;\n batchSize?: number;\n budget?: BudgetOption;\n exclude?: readonly SegmentRef[];\n },\n ): Promise<void> {\n await this.drainInto(dest, this.intersect(segs, options), options?.batchSize);\n }\n\n /**\n * Materialize `segs[0] ∪ segs[1] ∪ …` (minus `options.exclude`) into `dest`. **Not atomic**, like\n * {@link intersectInto}. See {@link union} for why this one cannot skip any chunk.\n */\n async unionInto(\n dest: SegmentRef,\n segs: readonly SegmentRef[],\n options?: {\n concurrency?: number;\n batchSize?: number;\n budget?: BudgetOption;\n exclude?: readonly SegmentRef[];\n },\n ): Promise<void> {\n await this.drainInto(dest, this.union(segs, options), options?.batchSize);\n }\n\n /** Materialize `seg \\ (excludes…)` into `dest`. **Not atomic**, like {@link intersectInto}. */\n async andNotInto(\n dest: SegmentRef,\n seg: SegmentRef,\n excludes: readonly SegmentRef[],\n options?: { concurrency?: number; batchSize?: number; budget?: BudgetOption },\n ): Promise<void> {\n await this.drainInto(dest, this.andNot(seg, excludes, options), options?.batchSize);\n }\n\n /**\n * Stream a combine's results into `dest` in bounded batches.\n *\n * `dest` is **added to, not replaced**, and this is **not atomic** — ids land chunk-by-chunk, so a failure\n * mid-stream leaves a partial result, exactly as `addMany` does. Batching keeps memory bounded no matter how\n * large the result is.\n */\n private async drainInto(\n dest: SegmentRef,\n source: AsyncIterable<number>,\n batchSizeOption?: number,\n ): Promise<void> {\n const batchSize = Math.max(1, batchSizeOption ?? 4096);\n let batch: number[] = [];\n for await (const id of source) {\n batch.push(id);\n if (batch.length >= batchSize) {\n await this.addMany(dest, batch);\n batch = [];\n }\n }\n if (batch.length > 0) await this.addMany(dest, batch);\n }\n\n /**\n * Group ids by chunk, then apply each chunk's whole batch in a single OCC read-modify-write.\n *\n * Accepts a **sync or async** iterable, so an Athena/BigQuery cursor streams straight in without the caller\n * hand-batching `page → addMany(page)`.\n *\n * **The pending ids are held as BITMAPS, not as JS numbers, and that is the load-bearing choice.** Streaming\n * input is unbounded by definition, so something has to give. The obvious answer — buffer N ids, flush them to\n * the backend, repeat — bounds memory and is quietly catastrophic on cost: with ids arriving in arbitrary\n * order, every flush touches nearly every chunk again, so an 11M-id stream at a 1M-id buffer would issue\n * **11x** the OCC round-trips of a single pass. In a library whose headline claim is honest cost, silently\n * multiplying someone's write bill by the size of their input is not a bounded-memory strategy; it is a\n * different bug.\n *\n * So the staging buffer is capped, but it folds into per-chunk **compressed bitmaps** rather than being\n * written out. Peak memory is the roaring representation of the ids seen so far — which is what the segment\n * itself costs, and the floor for any implementation that writes each chunk exactly once — while the backend\n * still sees exactly one read-modify-write per distinct chunk regardless of stream length. Above the staging cap\n * this holds less than the previous sync-only version, which kept every remainder as an uncompressed JS\n * number; below it — the common `addMany` — nothing is compacted until the end and the two are comparable.\n * The guarantee is that a stream of *any* length stays bounded, not that every call got smaller.\n *\n * There is no way to do better without a sorted stream: a chunk can only be written once it is known that no\n * further ids for it will arrive, and unsorted input never gives that guarantee. Callers streaming *very*\n * large sets want `bulkLoadCrbmGeneration` instead — it writes one immutable Cold object rather than tens of\n * thousands of warm rows. The crossover is documented in the guide.\n */\n private async mutateMany(\n seg: SegmentRef,\n ids: Iterable<number> | AsyncIterable<number>,\n apply: Mutator,\n ): Promise<void> {\n const byChunk = new Map<number, CodecBitmap>();\n const staged = new Map<number, number[]>();\n let pending = 0;\n const tickId = yieldEvery(this.clock, YIELD_EVERY_IDS); // async ingest only — see the sync loop's note\n\n /** Fold the staged remainders into their chunks' bitmaps, releasing the uncompressed buffers. */\n const compact = (): void => {\n for (const [chunkKey, rems] of staged) {\n if (rems.length === 0) continue;\n const existing = byChunk.get(chunkKey);\n if (existing === undefined) byChunk.set(chunkKey, this.codec.fromValues(rems));\n else existing.addMany(rems);\n rems.length = 0;\n }\n pending = 0;\n };\n\n const stage = (id: number): void => {\n const { chunkKey, remainder } = splitId(id); // validates the u32 range\n let rems = staged.get(chunkKey);\n if (rems === undefined) {\n rems = [];\n staged.set(chunkKey, rems);\n }\n rems.push(remainder);\n pending += 1;\n };\n\n // Two loops rather than one over a normalising wrapper: routing a sync source through an async generator\n // forces a microtask per id and measured 20x on the bulk-load path. Arrays and Sets are the common input.\n if (Symbol.asyncIterator in ids) {\n for await (const id of ids as AsyncIterable<number>) {\n stage(id);\n if (pending >= MUTATE_STAGE_IDS) compact();\n const pause = tickId();\n if (pause !== null) await pause;\n }\n } else {\n // A SYNC source is drained with no `await` inside the loop, and that is a correctness requirement rather\n // than an optimisation. An async function body runs synchronously up to its first `await`, so a sync\n // input has always been effectively **snapshotted** at call time — `addMany(buf)` without awaiting, then\n // mutating `buf`, could not lose ids. Yielding mid-loop silently broke that: with a yield every\n // `YIELD_EVERY_IDS`, a caller who recycled a 40,000-id scratch buffer before awaiting landed exactly\n // 16,384 ids and got **no error**. Size-dependent, so no small test would ever show it.\n //\n // Nothing is lost by draining eagerly here. The input is already fully in memory (that is what makes it\n // sync), the loop costs ~11 ms per 1M ids, and the operation's real time is the OCC round-trips below,\n // which yield naturally. Streaming callers who want cooperative ingest pass an async iterable.\n for (const id of ids as Iterable<number>) {\n stage(id);\n if (pending >= MUTATE_STAGE_IDS) compact();\n }\n }\n compact();\n\n // Bounded flusher: one OCC read-modify-write per distinct chunk, at most `writeConcurrency` in flight.\n // Distinct chunks are independent OCC rows, so fanning them out is safe; as before, a mid-flush failure can\n // leave a partial result (`addMany`/`removeMany` are not atomic).\n await mapWithConcurrency([...byChunk], this.writeConcurrency, ([chunkKey, bitmap]) =>\n this.readModifyWrite(seg, chunkKey, (d) => {\n apply(d, bitmap);\n }),\n );\n }\n\n /** OCC read-modify-write on a chunk's Warm delta, retrying on conflict (bounded). */\n private async readModifyWrite(\n seg: SegmentRef,\n chunkKey: number,\n mutate: (delta: ChunkDelta) => void,\n ): Promise<void> {\n const ref: ChunkRef = { ...seg, chunkKey };\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n const row = await this.warmGet(ref);\n const delta = row\n ? decodeDelta(row.bytes, this.maxBitmapBytes, this.codec)\n : emptyDelta(this.codec);\n mutate(delta);\n const encoded = encodeDelta(delta);\n try {\n await this.warm.putConditional(ref, encoded, row ? row.token : NO_ROW);\n if (this.metricsOn) {\n this.metrics.onEvent({\n kind: 'warm.write',\n namespace: ref.namespace,\n segment: ref.segment,\n bytes: encoded.length,\n });\n }\n return;\n } catch (err) {\n if (isWriteConflictError(err) && attempt < this.maxRetries) {\n // Jittered backoff so concurrent writers to a hot chunk don't reconverge into a tight retry storm\n // (full jitter decorrelates them). Instant under the default no-wait clock; real under production wiring.\n const delayMs = applyJitter(\n this.occBackoff,\n backoffDelayMs(this.occBackoff, attempt + 1),\n this.rng,\n );\n if (this.metricsOn) {\n this.metrics.onEvent({ kind: 'retry', reason: 'occ', attempt: attempt + 1, delayMs });\n }\n await this.clock.sleep(delayMs);\n continue;\n }\n throw err;\n }\n }\n throw new WriteConflictError(`OCC retries exhausted for chunk ${chunkKey}`);\n }\n\n /** `warm.get` + a `warm.read` metric (read bytes = the row size, 0 if absent). */\n private async warmGet(ref: ChunkRef, opts?: WarmReadOptions): Promise<WarmRow | null> {\n // No `opts` ⇒ the driver default (strong) — the OCC read-modify-write path relies on that; read paths pass\n // `this.readOpts` so `warmReadConsistency: 'eventual'` can lighten them (gap #9).\n const row = await this.warm.get(ref, opts);\n if (this.metricsOn) {\n this.metrics.onEvent({\n kind: 'warm.read',\n namespace: ref.namespace,\n segment: ref.segment,\n bytes: row ? row.bytes.length : 0,\n });\n }\n return row;\n }\n\n private async collectWarm(\n seg: SegmentRef,\n op: string,\n rowCeiling: number | null,\n ): Promise<Map<number, Uint8Array>> {\n const rows = new Map<number, Uint8Array>();\n let bytes = 0;\n // Read path (count/iterate/intersect): honor warmReadConsistency (gap #9).\n //\n // The budget is enforced HERE, per row, not after the drain. Every caller below used to check it only once\n // this Map was complete, which bounded the fan-out but not the enumeration: a segment can hold up to 65,536\n // chunks, each row individually capped by `decodeDelta` but the aggregate capped nowhere. Measured, a\n // `budget: { maxRequests: 2 }` store still materialised 3,000 chunks / 12 MB before `count()` threw — i.e.\n // the advertised denial-of-wallet protection could only refuse *after* paying the memory cost, which\n // contradicts the bounded-memory invariant. Checking inside the loop makes resident memory O(budget).\n for await (const row of this.warm.listChunks(seg, this.readOpts)) {\n rows.set(row.chunkKey, row.bytes);\n bytes += row.bytes.length;\n // The byte ceiling applies to EVERY read op, including intersect, and ignores `budget` entirely — see\n // `maxWarmScanBytes`. This is the bound that makes `budget: false` safe and that covers intersect, whose\n // product-shaped budget cannot express a memory limit.\n if (bytes > this.maxWarmScanBytes) {\n throw new BudgetExceededError(\n `${op} would hold more than ${this.maxWarmScanBytes} bytes of warm deltas resident for one segment ` +\n `— the scan was abandoned there rather than completed. Raise \\`maxWarmScanBytes\\`, narrow the ` +\n `segment, or compact it so fewer chunks carry warm deltas. (This ceiling is independent of ` +\n `\\`budget\\` and stays in force when \\`budget: false\\`.)`,\n );\n }\n // `>` and `rows.size` (not a raw counter): a duplicate chunkKey overwrites rather than growing the Map,\n // so the size is the true resident row count and matches what the post-drain check used to compare.\n //\n // `rowCeiling` is passed per-op rather than read from `this.budget`, because the budget means different\n // quantities per operation and applying it blindly TIGHTENS the contract:\n // - count / iterate: their eventual check is against `chunkKeys.length`, and warm keys are a SUBSET of\n // chunkKeys — so if warm rows alone exceed the budget, the existing check was going to fail too.\n // Checking early is therefore equivalent-or-earlier, never stricter. Safe to pass the budget.\n // - intersect: its eventual check is `common.length × operands.length`, a PRODUCT over the keys common\n // to every operand. One wide operand can hold far more warm rows than the product while still being\n // legal — so passing the budget here would refuse work the documented contract allows. It gets `null`\n // and remains unbounded pending a decision on an explicit memory ceiling. An existing budget test\n // caught exactly this, which is why the distinction is spelled out rather than assumed.\n if (rowCeiling !== null && rows.size > rowCeiling) {\n throw new BudgetExceededError(\n `${op} would read more than ${rowCeiling} warm chunk rows, over the per-op budget — ` +\n `the scan was abandoned at that point rather than completed, so no exact total is available. ` +\n `Raise \\`budget.maxRequests\\`, override it per-op, or set \\`budget: false\\``,\n );\n }\n }\n if (this.metricsOn) {\n this.metrics.onEvent({\n kind: 'warm.read',\n namespace: seg.namespace,\n segment: seg.segment,\n bytes,\n });\n }\n return rows;\n }\n\n private async chunkKeys(seg: SegmentRef, warmRows: Map<number, Uint8Array>): Promise<number[]> {\n const keys = new Set<number>(warmRows.keys());\n for (const k of await this.cold.listChunkKeys(seg)) keys.add(k);\n for (const k of keys) this.assertChunkKeyInRange(k);\n return [...keys].sort((a, b) => a - b);\n }\n\n /**\n * Tier-derived keys are untrusted (invariant 5) — fail fast on a corrupt/out-of-range key rather than\n * letting it flow into `joinId` and produce a bogus id.\n */\n private assertChunkKeyInRange(k: number): void {\n if (!Number.isInteger(k) || k < 0 || k >= CHUNK_COUNT) {\n throw new IntegrityError(`chunk key from a tier is out of range: ${k}`);\n }\n }\n\n /**\n * The other half of invariant 5, and the one that was missing: a chunk payload holds **remainders** — 16-bit\n * offsets within one chunk — so every value must be `<= 0xffff`.\n *\n * Nothing upstream established that. The byte cap bounds *size*, and CRC/AEAD prove the bytes are the bytes\n * that were written — which anyone able to write the tier satisfies trivially. A value `>= 65536` then\n * reaches `joinId`, which masks it (`remainder & 0xffff`) and emits a **fabricated id belonging to a\n * different chunk's id space**: indistinguishable from real data, inflating `count()` and creating spurious\n * `intersect` matches. Compaction is the only path that already failed loud (`CrbmWriter` rejects\n * `cardinality > 65536`), which merely turns the same row into a permanently poison segment.\n *\n * Costs one `maximum()` per chunk, not per id — `maximum` is optional on the codec seam precisely so a codec\n * that cannot answer in O(1) opts out instead of making the read path walk every value.\n */\n private assertChunkPayloadInRange(bitmap: CodecBitmap, chunkKey: number): void {\n const max = bitmap.maximum?.();\n if (max !== undefined && max > MAX_REMAINDER) {\n throw new IntegrityError(\n `chunk ${chunkKey} payload holds value ${max}, outside the 16-bit remainder range ` +\n `[0, ${MAX_REMAINDER}] — the stored object is corrupt or was not written by this codec`,\n );\n }\n }\n\n private async effectiveChunk(\n seg: SegmentRef,\n chunkKey: number,\n warmRows: Map<number, Uint8Array>,\n gen: number | null | undefined,\n ): Promise<CodecBitmap> {\n const warmBytes = warmRows.get(chunkKey);\n const delta = warmBytes\n ? decodeDelta(warmBytes, this.maxBitmapBytes, this.codec)\n : emptyDelta(this.codec);\n const cold = (await this.coldChunk({ ...seg, chunkKey }, gen)) ?? this.codec.empty();\n // Always return a fresh bitmap: `effective` clones Cold before any in-place op, so callers can\n // never mutate the (shared, cached) Cold instance. This is now LOAD-BEARING: `intersectChunk` mutates\n // the returned bitmap in place via `andInPlace`. A single-tier fast path that returns the cached Cold\n // by reference would silently poison the HOT cache through that path — it stays deferred (Phase 5 perf)\n // and MUST come with a read-only bitmap view.\n return effective(cold, delta);\n }\n\n /** The segment's current generation, resolved once per op (`undefined` ⇒ source can't report it). */\n private currentGen(seg: SegmentRef): Promise<number | null | undefined> {\n return this.cold.currentGeneration\n ? this.cold.currentGeneration(seg)\n : Promise.resolve(undefined);\n }\n\n /**\n * Decode a Cold chunk. `gen` is the segment's current generation, resolved **once per op** by the caller (not\n * per chunk — that would put a registry re-resolve on every chunk of a count/intersect). The HOT cache is\n * keyed by it (gap #4), so a compaction that advances the generation misses the cache and re-reads the new\n * bytes instead of serving a stale decoded chunk (an erased id can't resurrect from a cached pre-compaction\n * chunk). `gen === null` ⇒ the source reports no current generation ⇒ no cold bytes for any chunk, so skip the\n * fetch entirely (also avoids a redundant re-resolve on the warm-only path). `gen === undefined` ⇒ the source\n * can't report a generation (pins one for its lifetime) ⇒ the key stays generation-free (unchanged behaviour).\n * Superseded-generation entries age out under the LRU ceiling — no active purge.\n */\n private async coldChunk(\n ref: ChunkRef,\n gen: number | null | undefined,\n ): Promise<CodecBitmap | null> {\n if (gen === null) return null;\n const cacheKey = gen === undefined ? chunkRefKey(ref) : chunkGenKey(ref, gen);\n if (this.cache) {\n const cached = this.cache.get(cacheKey);\n if (cached) {\n if (this.metricsOn) this.metrics.onEvent({ kind: 'cache', hit: true });\n return cached;\n }\n if (this.metricsOn) this.metrics.onEvent({ kind: 'cache', hit: false });\n }\n const startedAt = this.metricsOn ? this.clock.now() : 0;\n const bytes = await this.cold.getChunk(ref);\n if (this.metricsOn) {\n this.metrics.onEvent({\n kind: 'cold.get',\n namespace: ref.namespace,\n segment: ref.segment,\n bytes: bytes ? bytes.length : 0,\n ms: Math.max(0, this.clock.now() - startedAt),\n });\n }\n if (!bytes) return null;\n const bitmap = this.codec.safeDeserialize(bytes, this.maxBitmapBytes);\n this.assertChunkPayloadInRange(bitmap, ref.chunkKey);\n this.cache?.set(cacheKey, bitmap);\n return bitmap;\n }\n}\n","/**\n * Bounded LRU cache with optional TTL — the HOT tier's memory ceiling (finding C6).\n *\n * Time comes from an injected `Clock` (never `Date.now()`) so the cache is deterministic\n * under simulation.\n *\n * The cache can be bounded by entry **count** (`maxEntries`, always) and, optionally, by an aggregate\n * **byte weight** (`maxBytes`). The byte bound exists for values whose footprint is large and uneven — the\n * cold reader cache, where one entry pins a fully-parsed `.crbm` index that can be ~6 MB for a wide segment\n * yet a few hundred bytes for a small one (gap #1: a count-only bound lets 1024 wide indices blow a Lambda's\n * memory even though the count is \"in bounds\"). Weights arrive **after** insertion (a cached reader is a\n * pending promise; its size is known only once it resolves), so weight is reported via {@link setWeight} and\n * eviction re-runs then.\n */\nimport type { Clock } from './determinism';\nimport { ValidationError } from './errors';\n\nexport interface LruOptions {\n /** Hard ceiling on entries; the least-recently-used is evicted past it. */\n readonly maxEntries: number;\n /**\n * Optional aggregate byte ceiling across all entries' reported weights (see {@link BoundedLru.setWeight}).\n * When set, the least-recently-used entries are evicted until the total is within budget — in addition to\n * the `maxEntries` bound. Omit for a pure count-bounded cache (weights stay 0, no byte eviction).\n */\n readonly maxBytes?: number;\n /** Optional time-to-live in ms; an entry older than this is treated as absent. */\n readonly ttlMs?: number;\n /** Only `now()` is used (never `sleep`), so a count-only cache can pass a minimal time source. */\n readonly clock: Pick<Clock, 'now'>;\n}\n\ninterface Entry<V> {\n readonly value: V;\n readonly expiresAt: number; // Infinity when no TTL\n bytes: number; // reported weight (0 until setWeight); summed against maxBytes\n}\n\nexport class BoundedLru<K, V> {\n private readonly map = new Map<K, Entry<V>>();\n private readonly maxEntries: number;\n private readonly maxBytes: number | undefined;\n private readonly ttlMs: number | undefined;\n private readonly clock: Pick<Clock, 'now'>;\n private totalBytes = 0;\n\n constructor(options: LruOptions) {\n if (!Number.isInteger(options.maxEntries) || options.maxEntries < 1) {\n throw new ValidationError(`maxEntries must be a positive integer; got ${options.maxEntries}`);\n }\n if (\n options.maxBytes !== undefined &&\n (!(options.maxBytes > 0) || !Number.isFinite(options.maxBytes))\n ) {\n throw new ValidationError(\n `maxBytes must be a positive finite number; got ${options.maxBytes}`,\n );\n }\n if (options.ttlMs !== undefined && (!(options.ttlMs > 0) || !Number.isFinite(options.ttlMs))) {\n throw new ValidationError(`ttlMs must be a positive finite number; got ${options.ttlMs}`);\n }\n this.maxEntries = options.maxEntries;\n this.maxBytes = options.maxBytes;\n this.ttlMs = options.ttlMs;\n this.clock = options.clock;\n }\n\n get(key: K): V | undefined {\n const entry = this.map.get(key);\n if (entry === undefined) return undefined;\n if (entry.expiresAt <= this.clock.now()) {\n this.drop(key, entry);\n return undefined;\n }\n // Refresh recency: re-insert so it becomes most-recently-used.\n this.map.delete(key);\n this.map.set(key, entry);\n return entry.value;\n }\n\n /** Read a value **without** counting as an access (recency unchanged, no purge on expiry). */\n peek(key: K): V | undefined {\n return this.map.get(key)?.value;\n }\n\n set(key: K, value: V): void {\n const prev = this.map.get(key);\n if (prev !== undefined) this.totalBytes -= prev.bytes;\n this.map.delete(key);\n const expiresAt = this.ttlMs === undefined ? Infinity : this.clock.now() + this.ttlMs;\n this.map.set(key, { value, expiresAt, bytes: 0 });\n while (this.map.size > this.maxEntries) {\n const oldest = this.map.keys().next();\n if (oldest.done === true) break;\n this.dropKey(oldest.value);\n }\n this.evictToBudget(key);\n }\n\n /**\n * Report an entry's byte weight (typically once a cached promise resolves and its size is known). Updates\n * the running total and evicts the least-recently-used entries if the aggregate now exceeds `maxBytes`.\n * Recency is **not** changed. The `key` being weighted is protected from this eviction pass (we just\n * populated it) — so a single entry larger than the whole budget is kept rather than immediately dropped.\n */\n setWeight(key: K, bytes: number): void {\n if (!(bytes >= 0) || !Number.isFinite(bytes)) {\n // Guard the running total against a NaN/negative weight, which no removal path could ever restore.\n throw new ValidationError(`weight must be a non-negative finite number; got ${bytes}`);\n }\n const entry = this.map.get(key);\n if (entry === undefined) return;\n this.totalBytes += bytes - entry.bytes;\n entry.bytes = bytes;\n this.evictToBudget(key);\n }\n\n private evictToBudget(protectKey: K): void {\n if (this.maxBytes === undefined) return;\n while (this.totalBytes > this.maxBytes && this.map.size > 1) {\n const oldest = this.oldestExcept(protectKey);\n if (oldest === undefined) break; // only the protected key remains\n this.dropKey(oldest);\n }\n }\n\n /** The least-recently-used key that is not `protectKey`, or undefined if none other exists. */\n private oldestExcept(protectKey: K): K | undefined {\n for (const key of this.map.keys()) {\n if (key !== protectKey) return key;\n }\n return undefined;\n }\n\n private dropKey(key: K): void {\n const entry = this.map.get(key);\n if (entry !== undefined) this.drop(key, entry);\n }\n\n private drop(key: K, entry: Entry<V>): void {\n this.totalBytes -= entry.bytes;\n this.map.delete(key);\n }\n\n /** Membership test that does NOT count as an access (recency is unchanged). Purges if expired. */\n has(key: K): boolean {\n const entry = this.map.get(key);\n if (entry === undefined) return false;\n if (entry.expiresAt <= this.clock.now()) {\n this.drop(key, entry);\n return false;\n }\n return true;\n }\n\n delete(key: K): boolean {\n const entry = this.map.get(key);\n if (entry === undefined) return false;\n this.drop(key, entry);\n return true;\n }\n\n clear(): void {\n this.map.clear();\n this.totalBytes = 0;\n }\n\n /** Current entry count (may include not-yet-evicted expired entries). */\n get size(): number {\n return this.map.size;\n }\n\n /** Current aggregate reported weight (bytes) across all entries. */\n get weightBytes(): number {\n return this.totalBytes;\n }\n}\n","/**\n * Cost model & estimator (Phase 5b) — pure, `core/`-safe (no I/O, time, or\n * SDK). Turns the verified economics into a first-class library API:\n *\n * - {@link estimateCost} — **planning** mode: pure what-if from segment sizes + a workload (sizing/sales).\n * - `segment.costReport()` (wired in `index.ts`) — **grounded** mode: the segment's real size from the\n * `.crbm` index (free + exact, no payload reads) + a supplied workload for request rates. (Whole-store\n * aggregation is a later phase.)\n *\n * Guiding split (08 decision #3): **formulas are the spec; rates are a pluggable {@link PricingProfile}.**\n * The report always emits a {@link CostReport.verdict} that includes the lose-zone — it never hides where an\n * always-on cache (Redis) wins.\n *\n * Model scope (kept deliberately simple, and stated in `assumptions.notes`): S3→same-region egress is free\n * and internet egress is not modeled; Warm delta storage is treated as negligible (it's tiny — only dirty\n * chunks); request cost is derived from the supplied workload rates (deriving it from live metrics counters\n * is a later refinement — the cost-completeness events are deferred).\n */\nimport { CHUNK_COUNT } from './bit-route';\nimport { ValidationError } from './errors';\n\n/** Pluggable rate card. Rates differ by cloud/region/term and drift over time; the formulas don't. */\nexport interface PricingProfile {\n readonly name: string;\n readonly cold: {\n /** S3 GET (per **million** requests). A ranged GET bills as a full GET. */\n readonly getPerMillion: number;\n /** S3 PUT (per million). */\n readonly putPerMillion: number;\n readonly storagePerGiBMonth: number;\n };\n readonly warm: {\n /** DynamoDB read-request-units (per million). */\n readonly rruPerMillion: number;\n /** DynamoDB write-request-units (per million). **0 models a provisioned/flat tier** (no per-write charge). */\n readonly wruPerMillion: number;\n /** KiB billed per read unit (DynamoDB: 4). */\n readonly readUnitKiB: number;\n /** KiB billed per write unit (DynamoDB: 1 — the write cost driver). */\n readonly writeUnitKiB: number;\n readonly storagePerGiBMonth: number;\n /** Strongly-consistent reads bill 1 RRU/unit; eventually-consistent bill 0.5. */\n readonly stronglyConsistent: boolean;\n };\n /** The always-on baseline to compare against (e.g. an ElastiCache HA cluster). */\n readonly redis: { readonly monthlyUSD: number };\n}\n\n/**\n * Default profile — **AWS us-east-1, on-demand**, mid-2026, from the fact-checked\n * published pricing rather than copied from a blog post. Override it for your region, cloud, or committed term.\n */\nexport const AWS_US_EAST_1_ONDEMAND: PricingProfile = {\n name: 'aws-us-east-1-ondemand',\n cold: { getPerMillion: 0.4, putPerMillion: 5.0, storagePerGiBMonth: 0.023 },\n warm: {\n rruPerMillion: 0.125,\n wruPerMillion: 0.625,\n readUnitKiB: 4,\n writeUnitKiB: 1,\n storagePerGiBMonth: 0.25,\n stronglyConsistent: true,\n },\n redis: { monthlyUSD: 346 }, // ElastiCache HA: 1 primary + 2 replicas (cache.m7g.large); ~$115 single-node\n};\n\nexport const DEFAULT_PRICING: PricingProfile = AWS_US_EAST_1_ONDEMAND;\n\n/** Which write path is live. `A` = Hot+Cold read-mostly (writes via bulk-load); `B` = live Warm writes. */\nexport type Topology = 'A' | 'B';\n\n/** Sustained access pattern. All rates default to 0; unspecified ⇒ that op contributes nothing. */\nexport interface Workload {\n readonly readsPerSec?: number;\n readonly writesPerSec?: number;\n readonly intersectsPerSec?: number;\n /** HOT-cache hit rate in `[0, 1]` — hits are free; only misses cost. Default 0. */\n readonly cacheHitRate?: number;\n /** Avg serialized chunk/item size (KiB) — drives read/write units. Default 8 (a full roaring bitmap container). */\n readonly avgItemKiB?: number;\n /** Cold chunks fetched per intersection (the chunk-skipping survivors). Default 1. */\n readonly chunksPerIntersect?: number;\n /**\n * Compaction cycles per month across the modeled data (gap #10). Default **0** ⇒ compaction is not modeled\n * and the report *discloses* the omission (rather than silently under-reporting). Set it to fold in the\n * background job that usually dominates operational cost.\n */\n readonly compactionsPerMonth?: number;\n /**\n * Cold chunks re-read per compaction cycle — the whole generation (clean chunks are copied through, 1 GET\n * each). Default: derived from `coldBytes / avgItemKiB` (i.e. the whole modeled cold set is one generation —\n * exact for a single-segment/grounded report; for a multi-segment fleet set this to your *per-segment* chunk\n * count). This whole-generation re-read is the dominant compaction term.\n */\n readonly chunksPerCompaction?: number;\n /** Dirty Warm rows purged per compaction — the secondary RRU-read + WRU-delete term. Default 0. */\n readonly dirtyChunksPerCompaction?: number;\n}\n\n/** One (group of) segment(s) for planning. `count` = how many like this (default 1). */\nexport interface SegmentSizing {\n readonly sizeBytes?: number;\n readonly cardinality?: number;\n /** Number of segments with these characteristics. Default 1. */\n readonly count?: number;\n}\n\nexport interface EstimateInput {\n readonly segments: readonly SegmentSizing[];\n readonly workload?: Workload;\n readonly topology?: Topology;\n readonly pricing?: PricingProfile;\n}\n\n/**\n * A self-relative cost hint. See {@link CostReport.advisories}.\n *\n * `code` is the stable, machine-readable identity — branch on it rather than parsing `message`.\n */\nexport interface CostAdvisory {\n /**\n * `'batchable-writes'` — the modeled write count far exceeds the number of distinct Warm rows the data can\n * occupy, so each row is being rewritten many times over. If those ids ever arrive together, `addMany()`\n * collapses them to one write per chunk and bulk-load writes Cold directly.\n */\n readonly code: 'batchable-writes';\n /** Human-readable, safe to log or print. Carries the numbers that triggered it. */\n readonly message: string;\n /** The modeled cost of the term this advisory is about (USD/month). */\n readonly currentUSD: number;\n /**\n * A **floor**, not a promise: the same term if the writes were perfectly batched into one write per distinct\n * Warm row. Real batching lands between this and {@link CostAdvisory.currentUSD}, depending on how the ids\n * actually arrive — which the estimator cannot know.\n */\n readonly batchedFloorUSD: number;\n}\n\nexport interface CostReport {\n readonly monthlyUSD: {\n readonly byTier: { readonly hot: number; readonly warm: number; readonly cold: number };\n readonly byOp: {\n readonly reads: number;\n readonly writes: number;\n readonly intersects: number;\n readonly storage: number;\n /** Background compaction (whole-generation re-read + PUT + Warm purge). 0 unless `compactionsPerMonth` is set. */\n readonly compaction: number;\n };\n readonly total: number;\n };\n /**\n * Sustained rate at which the pay-per-use model's cost passes the flat Redis baseline (per axis, the other\n * at 0), **evaluated at this report's `cacheHitRate` + `avgItemKiB`** — so a higher cache-hit rate raises\n * `readsPerSec` (cache hits are free). `Infinity` means that axis never crosses (e.g. a flat/provisioned\n * tier, or a 100% cache-hit rate). The published anchors (~26 writes/s, ~329 reads/s) are at `cacheHitRate: 0`.\n */\n readonly redisCrossover: { readonly writesPerSec: number; readonly readsPerSec: number };\n readonly verdict: 'win-big' | 'win' | 'lose-zone';\n readonly rationale: string;\n /**\n * Zero or more **self-relative** hints: places this workload is paying more than *this same library* would\n * charge for the same outcome. Distinct from {@link CostReport.verdict}, which only compares against the flat\n * Redis baseline — a workload can beat Redis by 40× and still be 100× more expensive than it needs to be, and\n * the verdict alone would call that `win-big` and say nothing.\n *\n * Empty is the normal case. Advisories never change the dollar figures; they are additive commentary, and each\n * carries a machine-readable {@link CostAdvisory.code} so consumers don't string-match.\n */\n readonly advisories: readonly CostAdvisory[];\n readonly assumptions: {\n readonly cacheHitRate: number;\n readonly pricingName: string;\n /** True when segment **sizes** were real (grounded `costReport`), false for a pure `estimateCost`. */\n readonly grounded: boolean;\n readonly topology: Topology;\n readonly notes: readonly string[];\n };\n}\n\nconst SECONDS_PER_MONTH = 730 * 3600; // 2,628,000 — the research's convention\nconst GIB = 1024 ** 3;\n\n/** Fail-fast at the boundary: reject non-finite / negative inputs rather than leak NaN into the report. */\nfunction requireFiniteNonNeg(n: number, field: string): number {\n if (!Number.isFinite(n) || n < 0) {\n throw new ValidationError(`${field} must be a finite number >= 0; got ${n}`);\n }\n return n;\n}\n\n/** As above, but for divisors that must be strictly positive (a 0-KiB unit would divide to Infinity). */\nfunction requireFinitePos(n: number, field: string): number {\n if (!Number.isFinite(n) || n <= 0) {\n throw new ValidationError(`${field} must be a finite number > 0; got ${n}`);\n }\n return n;\n}\n\nfunction clamp01(n: number): number {\n return n < 0 ? 0 : n > 1 ? 1 : n;\n}\n\n/** Rough bytes for a segment when only cardinality is known: 2 B/value (array-container upper bound, B6/B7). */\nfunction sizingBytes(spec: SegmentSizing): number {\n if (spec.sizeBytes !== undefined) return requireFiniteNonNeg(spec.sizeBytes, 'segment.sizeBytes');\n if (spec.cardinality !== undefined) {\n return requireFiniteNonNeg(spec.cardinality, 'segment.cardinality') * 2;\n }\n return 0;\n}\n\n/**\n * Fire `batchable-writes` only once a Warm row is being rewritten at least this many times over the month.\n * Below it there is little to amortize — at a ratio of 1 you are already at one write per row.\n */\nconst BATCHABLE_WRITE_RATIO = 8;\n\n/**\n * …and only when acting on it is worth real money. Without this the advisory nags about pennies on any\n * write-shaped workload, and an advisory that cries wolf is worse than no advisory at all.\n */\nconst BATCHABLE_MIN_SAVINGS_USD = 1;\n\n/**\n * Derive the self-relative advisories. **Pure** — no I/O, clock, or randomness, so it stays inside the\n * deterministic core seam and is directly unit-testable.\n *\n * `maxWarmRows` must be a HARD upper bound on the distinct Warm rows the modeled data can occupy, never an\n * estimate. That direction matters: the trigger is `writes / maxWarmRows`, so *over*-stating the bound makes the\n * advisory quieter (a false negative — it misses a case it could have flagged) while *under*-stating it makes the\n * advisory fire on workloads that are already optimal (a false positive, which trains people to ignore it). The\n * bound is therefore taken from the id space itself — a 16-bit chunk key means at most {@link CHUNK_COUNT} rows\n * per segment — tightened by declared cardinality only, which cannot exceed the row count either. Byte-derived\n * cardinality is deliberately NOT used: `sizingBytes`'s 2 B/value convention understates a dense bitmap\n * container by ~16×, which would understate the bound and produce exactly the false positives above.\n */\nfunction deriveAdvisories(input: {\n readonly writes: number;\n readonly writesUSD: number;\n readonly maxWarmRows: number;\n readonly warmWriteUSD: number;\n}): readonly CostAdvisory[] {\n const { writes, writesUSD, maxWarmRows, warmWriteUSD } = input;\n const out: CostAdvisory[] = [];\n\n if (writes > 0 && writesUSD > 0 && maxWarmRows > 0) {\n const ratio = writes / maxWarmRows;\n const batchedFloorUSD = maxWarmRows * warmWriteUSD;\n const savings = writesUSD - batchedFloorUSD;\n if (ratio >= BATCHABLE_WRITE_RATIO && savings >= BATCHABLE_MIN_SAVINGS_USD) {\n out.push({\n code: 'batchable-writes',\n message:\n `${Math.round(writes).toLocaleString('en-US')} writes/mo against data occupying at most ` +\n `${maxWarmRows.toLocaleString('en-US')} Warm rows — each row rewritten ~${Math.round(ratio).toLocaleString('en-US')}× ` +\n `($${writesUSD.toFixed(2)}/mo). IF these ids ever arrive together, addMany() collapses them to one ` +\n `write per chunk and bulkLoadCrbmGeneration writes Cold directly, taking the write term toward ` +\n `$${batchedFloorUSD.toFixed(2)}/mo. If they genuinely arrive one at a time (real-time qualification), ` +\n `add() is the correct path and this is simply what it costs.`,\n currentUSD: writesUSD,\n batchedFloorUSD,\n });\n }\n }\n\n return out;\n}\n\n/** Core report builder shared by planning + grounded modes. `coldBytes` is total across all segments. */\nfunction buildReport(input: {\n readonly coldBytes: number;\n readonly workload: Workload;\n readonly topology: Topology;\n readonly pricing: PricingProfile;\n readonly grounded: boolean;\n readonly extraNotes?: readonly string[];\n /** Hard upper bound on distinct Warm rows the modeled data can occupy. See {@link deriveAdvisories}. */\n readonly maxWarmRows: number;\n}): CostReport {\n const { topology, pricing, grounded } = input;\n const { cold, warm, redis } = pricing;\n const S = SECONDS_PER_MONTH;\n\n // The pricing profile is a public, caller-supplied boundary input too — validate every rate that feeds\n // the report so a malformed profile fails fast rather than leaking NaN/Infinity dollars + a bogus verdict.\n requireFiniteNonNeg(cold.getPerMillion, 'pricing.cold.getPerMillion');\n requireFiniteNonNeg(cold.putPerMillion, 'pricing.cold.putPerMillion'); // now consumed by the compaction term\n requireFiniteNonNeg(cold.storagePerGiBMonth, 'pricing.cold.storagePerGiBMonth');\n requireFiniteNonNeg(warm.rruPerMillion, 'pricing.warm.rruPerMillion');\n requireFiniteNonNeg(warm.wruPerMillion, 'pricing.warm.wruPerMillion');\n requireFinitePos(warm.readUnitKiB, 'pricing.warm.readUnitKiB');\n requireFinitePos(warm.writeUnitKiB, 'pricing.warm.writeUnitKiB');\n requireFiniteNonNeg(redis.monthlyUSD, 'pricing.redis.monthlyUSD');\n\n const coldBytes = requireFiniteNonNeg(input.coldBytes, 'coldBytes');\n const cacheHitRate = clamp01(\n requireFiniteNonNeg(input.workload.cacheHitRate ?? 0, 'cacheHitRate'),\n );\n const readsPerSec = requireFiniteNonNeg(input.workload.readsPerSec ?? 0, 'readsPerSec');\n const writesPerSec = requireFiniteNonNeg(input.workload.writesPerSec ?? 0, 'writesPerSec');\n const intersectsPerSec = requireFiniteNonNeg(\n input.workload.intersectsPerSec ?? 0,\n 'intersectsPerSec',\n );\n const avgItemKiB = requireFiniteNonNeg(input.workload.avgItemKiB ?? 8, 'avgItemKiB');\n const chunksPerIntersect = requireFiniteNonNeg(\n input.workload.chunksPerIntersect ?? 1,\n 'chunksPerIntersect',\n );\n const compactionsPerMonth = requireFiniteNonNeg(\n input.workload.compactionsPerMonth ?? 0,\n 'compactionsPerMonth',\n );\n const avgItemBytes = avgItemKiB * 1024;\n const derivedChunks = avgItemBytes > 0 ? Math.ceil(coldBytes / avgItemBytes) : 0;\n const chunksPerCompaction = requireFiniteNonNeg(\n input.workload.chunksPerCompaction ?? derivedChunks,\n 'chunksPerCompaction',\n );\n const dirtyChunksPerCompaction = requireFiniteNonNeg(\n input.workload.dirtyChunksPerCompaction ?? 0,\n 'dirtyChunksPerCompaction',\n );\n\n // Per-op unit costs (USD). `Math.max(1, ...)` enforces DynamoDB's ≥1-unit-per-request billing.\n const rruMult = warm.stronglyConsistent ? 1 : 0.5;\n const warmReadUSD =\n Math.max(1, Math.ceil(avgItemKiB / warm.readUnitKiB)) * rruMult * (warm.rruPerMillion / 1e6);\n const warmWriteUSD =\n Math.max(1, Math.ceil(avgItemKiB / warm.writeUnitKiB)) * (warm.wruPerMillion / 1e6);\n const coldGetUSD = cold.getPerMillion / 1e6; // same-region egress is free; internet egress not modeled\n\n // Monthly op volumes.\n const missFraction = 1 - cacheHitRate;\n const readMisses = readsPerSec * S * missFraction;\n const writes = writesPerSec * S;\n const intersects = intersectsPerSec * S;\n\n // Storage (monthly, exact when grounded). Warm delta storage is treated as negligible (only dirty chunks).\n const storageUSD = (coldBytes / GIB) * cold.storagePerGiBMonth;\n\n // Request costs by op. Topology-A reads hit Cold (S3 GET); Topology-B reads hit the Warm tier; Topology-A\n // has no per-op writes (writes arrive via bulk-load). Intersection fetches the surviving Cold chunks.\n const readsUSD = topology === 'A' ? readMisses * coldGetUSD : readMisses * warmReadUSD;\n const writesUSD = topology === 'B' ? writes * warmWriteUSD : 0;\n const intersectsUSD = intersects * chunksPerIntersect * coldGetUSD;\n\n // Compaction (gap #10): per cycle, re-read the whole generation (chunksPerCompaction Cold GETs — the\n // dominant term), write one new `.crbm` (a PUT), and purge the dirty Warm rows (an RRU read + a WRU delete).\n // Same-region GET/PUT egress is free; the GC delete of the superseded generation is free (not modeled).\n const putUSD = cold.putPerMillion / 1e6;\n const compactionColdUSD = compactionsPerMonth * (chunksPerCompaction * coldGetUSD + putUSD);\n const compactionWarmUSD =\n compactionsPerMonth * dirtyChunksPerCompaction * (warmReadUSD + warmWriteUSD);\n const compactionUSD = compactionColdUSD + compactionWarmUSD;\n\n const total = readsUSD + writesUSD + intersectsUSD + storageUSD + compactionUSD;\n\n const warmTierUSD = (topology === 'B' ? readsUSD + writesUSD : 0) + compactionWarmUSD;\n const coldTierUSD =\n storageUSD + (topology === 'A' ? readsUSD : 0) + intersectsUSD + compactionColdUSD;\n\n // Crossovers: sustained rate (other axis 0) where request cost alone passes (redis − fixed storage),\n // evaluated at this report's cache posture (misses) and item size (units).\n const headroom = Math.max(0, redis.monthlyUSD - storageUSD);\n const perReadUSD = topology === 'A' ? coldGetUSD : warmReadUSD;\n const writesCross =\n topology === 'B' && warmWriteUSD > 0 ? headroom / (S * warmWriteUSD) : Infinity;\n const readsCross =\n perReadUSD > 0 && missFraction > 0 ? headroom / (S * perReadUSD * missFraction) : Infinity;\n\n const verdict: CostReport['verdict'] =\n total <= redis.monthlyUSD * 0.1 ? 'win-big' : total < redis.monthlyUSD ? 'win' : 'lose-zone';\n\n const dominant = Math.max(readsUSD, writesUSD, intersectsUSD, storageUSD, compactionUSD);\n let driver = 'storage';\n if (dominant === writesUSD && writesUSD > 0)\n driver = 'warm writes (the per-1KiB WRU cost driver)';\n else if (dominant === readsUSD && readsUSD > 0)\n driver = topology === 'A' ? 'cold reads (S3 GETs)' : 'warm reads';\n else if (dominant === intersectsUSD && intersectsUSD > 0) driver = 'intersection cold fetches';\n else if (dominant === compactionUSD && compactionUSD > 0)\n driver = 'compaction (whole-generation re-read)';\n const rationale =\n verdict === 'lose-zone'\n ? `pay-per-use total $${total.toFixed(2)}/mo exceeds the $${redis.monthlyUSD}/mo flat baseline; dominated by ${driver}`\n : verdict === 'win-big'\n ? `$${total.toFixed(2)}/mo — ≤10% of the $${redis.monthlyUSD}/mo baseline; dominated by ${driver}`\n : `$${total.toFixed(2)}/mo, under the $${redis.monthlyUSD}/mo baseline; dominated by ${driver}`;\n\n const notes = [\n 'S3→same-region egress treated as free; internet egress is not modeled.',\n 'Warm delta storage treated as negligible (only dirty chunks).',\n 'Request cost is from the supplied workload rates (live-metrics-derived request cost is a later phase).',\n compactionsPerMonth > 0\n ? `Compaction modeled: ${compactionsPerMonth}/mo × (${chunksPerCompaction} Cold GET + 1 PUT${dirtyChunksPerCompaction > 0 ? ` + ${dirtyChunksPerCompaction}-row Warm purge` : ''}); the whole-generation re-read dominates. GC delete of the superseded generation is free (not modeled).`\n : 'Compaction is NOT modeled — set workload.compactionsPerMonth (+ chunksPerCompaction) to include the whole-generation re-read that dominates operational cost.',\n ...(input.extraNotes ?? []),\n ];\n\n return {\n monthlyUSD: {\n byTier: { hot: 0, warm: warmTierUSD, cold: coldTierUSD },\n byOp: {\n reads: readsUSD,\n writes: writesUSD,\n intersects: intersectsUSD,\n storage: storageUSD,\n compaction: compactionUSD,\n },\n total,\n },\n redisCrossover: { writesPerSec: writesCross, readsPerSec: readsCross },\n verdict,\n rationale,\n // Topology-A has no per-op writes (they arrive via bulk-load), so `writesUSD` is 0 there and the advisory\n // cannot fire — correctly, since bulk-load is already the batched path.\n advisories: deriveAdvisories({\n writes,\n writesUSD,\n maxWarmRows: requireFiniteNonNeg(input.maxWarmRows, 'maxWarmRows'),\n warmWriteUSD,\n }),\n assumptions: { cacheHitRate, pricingName: pricing.name, grounded, topology, notes },\n };\n}\n\n/**\n * **Planning** cost estimate — pure, no instance or live data needed (sizing, sales, what-if). Segment sizes\n * are taken as given (or roughly derived from cardinality); use the grounded `segment.costReport()` for\n * exact, real sizes. See {@link CostReport}.\n */\nexport function estimateCost(input: EstimateInput): CostReport {\n const topology = input.topology ?? 'A';\n const pricing = input.pricing ?? DEFAULT_PRICING;\n const workload = input.workload ?? {};\n let coldBytes = 0;\n // Hard bound on distinct Warm rows: a 16-bit chunk key caps a segment at CHUNK_COUNT rows, and a segment can\n // never occupy more rows than it holds ids — so declared `cardinality` tightens it. `sizeBytes`-only specs get\n // the un-tightened cap rather than a byte-derived guess, which would understate it (see `deriveAdvisories`).\n let maxWarmRows = 0;\n for (const spec of input.segments) {\n const count = Math.floor(requireFiniteNonNeg(spec.count ?? 1, 'segment.count'));\n coldBytes += sizingBytes(spec) * count;\n const perSegment =\n spec.cardinality !== undefined\n ? Math.min(\n Math.floor(requireFiniteNonNeg(spec.cardinality, 'segment.cardinality')),\n CHUNK_COUNT,\n )\n : CHUNK_COUNT;\n maxWarmRows += perSegment * count;\n }\n return buildReport({ coldBytes, workload, topology, pricing, grounded: false, maxWarmRows });\n}\n\n/**\n * **Grounded** report from a real segment byte total (from the `.crbm` index) + a supplied workload. Used by\n * `Segment.costReport()` in `index.ts`. `grounded` defaults to true (the size is exact, not estimated); the\n * caller passes `grounded: false` + a note when the Cold source can't measure size.\n */\nexport function groundedReport(input: {\n readonly coldBytes: number;\n readonly grounded?: boolean;\n readonly workload?: Workload;\n readonly topology?: Topology;\n readonly pricing?: PricingProfile;\n readonly extraNotes?: readonly string[];\n /**\n * Hard upper bound on distinct Warm rows, for the advisories. Defaults to {@link CHUNK_COUNT} — this models\n * ONE segment, and a 16-bit chunk key caps a segment there. `SegmentSize` carries only `sizeBytes` today, so\n * an exact per-segment chunk count would need a driver-interface change; the id-space cap needs nothing and is\n * sound in the safe direction (it can only make the advisory quieter).\n */\n readonly maxWarmRows?: number;\n}): CostReport {\n return buildReport({\n coldBytes: input.coldBytes,\n workload: input.workload ?? {},\n topology: input.topology ?? 'A',\n pricing: input.pricing ?? DEFAULT_PRICING,\n grounded: input.grounded ?? true,\n extraNotes: input.extraNotes,\n maxWarmRows: input.maxWarmRows ?? CHUNK_COUNT,\n });\n}\n","/**\n * Audit sink (Phase 5d) — an injected, no-op-by-default seam for **security/compliance** events, distinct\n * from the metrics sink (5a). Different audience (an audit log / SIEM, not a dashboard), different retention,\n * and only the compliance-relevant *state changes* — never routine reads/writes (that's the metrics sink).\n * It doubles as the GDPR Art. 30 \"record of processing\" surface: publishes, compactions, and erasures.\n *\n * Like `Clock`/`Rng`/`IMetricsSink`, it's injected (into the lifecycle operations that emit — compaction,\n * bulk-load, erasure) and wrapped exception-safe, so a buggy sink can never break the operation it observes.\n * Events are vendor-neutral and carry no timestamp/actor — the sink runs synchronously at the event, so it\n * stamps its own time / attaches the caller identity (keeps `core/` free of ambient time). As with metrics,\n * `segment`/`namespace` are caller-controlled strings that may be PII — treat them accordingly when routing.\n *\n * Not (yet) emitted: **KEK rotation** — rotation here is operator-side keystore reconfiguration (key-id-tagged\n * wrappings, no data re-encryption), so there is no library call to hook. A future `rewrapSegment()` op would\n * add a `kek.rotate` variant; until then, audit key changes at your keystore-config layer.\n */\n\n/** A security/compliance-relevant state change. Vendor-neutral; the sink adds its own timestamp/actor. */\nexport type AuditEvent =\n | {\n /** A new immutable Cold generation *became the segment's current generation* (via bulk-load publish). */\n readonly kind: 'segment.publish';\n readonly namespace?: string;\n readonly segment: string;\n readonly generation: number;\n }\n | {\n /** Compaction committed a new generation (emitted at the durable commit, before Warm-row purge). */\n readonly kind: 'segment.compact';\n readonly namespace?: string;\n readonly segment: string;\n readonly generation: number;\n }\n | {\n /**\n * A segment was **crypto-shredded** — its wrapped DEK(s) are gone, so its at-rest Cold bytes are now\n * permanently unreadable. Emitted only for a genuine key shred, never for a cleartext tombstone (which\n * leaves the Cold bytes readable) or an idempotent re-run.\n */\n readonly kind: 'segment.erase';\n readonly namespace?: string;\n readonly segment: string;\n }\n | {\n /**\n * A segment was **disposed of** — tombstoned and its storage reclaimed (Warm rows + Cold generations\n * deleted) by `dropSegment`, *without* a key shred.\n *\n * Deliberately a separate kind from {@link AuditEvent} `segment.erase`, and the distinction is the point.\n * `segment.erase` attests that bytes are unreadable **everywhere, backups included** — the only claim that\n * survives WORM. Deleting an object is strictly weaker: a noncurrent version, a cross-region replica or a\n * PITR snapshot can still hold the cleartext. Emitting one kind for both would make a compliance dashboard\n * over-attest, so a cleartext drop gets this instead.\n *\n * An **encrypted** segment dropped via `dropSegment` emits **both** — `segment.erase` for the key shred and\n * this for the storage reclamation — because both things genuinely happened.\n *\n * `generationsDeleted` is how many Cold generations went. It can be 0 (a segment whose bytes were already\n * gone), and it does not promise the storage is now fully reclaimed: check `DropResult.generationsRemaining`\n * for that.\n */\n readonly kind: 'segment.dispose';\n readonly namespace?: string;\n readonly segment: string;\n readonly generationsDeleted: number;\n }\n | {\n /** A namespace erasure was executed. `segmentsShredded` is the count actually crypto-shredded (may be 0). */\n readonly kind: 'namespace.erase';\n readonly namespace: string;\n readonly segmentsShredded: number;\n };\n\n/** The `kind` discriminant of an {@link AuditEvent}. */\nexport type AuditEventKind = AuditEvent['kind'];\n\n/** Sink for {@link AuditEvent}s. Injected via the lifecycle options; the default is {@link NOOP_AUDIT}. */\nexport interface IAuditSink {\n onEvent(event: AuditEvent): void;\n}\n\n/** The default sink: records nothing. */\nexport const NOOP_AUDIT: IAuditSink = {\n onEvent(): void {\n /* discard */\n },\n};\n\n/**\n * Wrap a sink so a throwing/buggy `onEvent` can never break the lifecycle operation it observes — audit is\n * strictly observation. Returns {@link NOOP_AUDIT} unchanged (so the no-op case skips even the try/catch alloc).\n */\nexport function safeAudit(sink: IAuditSink): IAuditSink {\n if (sink === NOOP_AUDIT) return sink;\n return {\n onEvent(event: AuditEvent): void {\n try {\n sink.onEvent(event);\n } catch {\n /* swallow — an audit sink must never break the operation it observes */\n }\n },\n };\n}\n\n/** A ready-made sink that records events into an in-memory list — handy for tests + simple audit trails. */\nexport class RecordingAuditSink implements IAuditSink {\n private readonly recorded: AuditEvent[] = [];\n\n onEvent(event: AuditEvent): void {\n this.recorded.push(event);\n }\n\n /** An independent copy of the recorded events, in emission order. */\n snapshot(): AuditEvent[] {\n return this.recorded.map((e) => ({ ...e }));\n }\n\n reset(): void {\n this.recorded.length = 0;\n }\n}\n","/**\n * The **bitmap-codec seam**.\n *\n * `core/` is **codec-agnostic**: `SegmentEngine`, compaction, and the `.crbm` read/write helpers only ever\n * construct and combine bitmaps through the {@link CodecInterface} factory + the {@link CodecBitmap} value type\n * defined here — never a concrete implementation. The flagship codec is roaring (`roaringCodec`, today in\n * `core/bitmap.ts`; it moves to `@cloudbitmaps/roaring` when the package split lands); `@cloudbitmaps/bitset`\n * (plain bitset) and `@cloudbitmaps/soaring` plug in behind the same seam with zero engine or driver changes.\n *\n * **Homogeneity contract:** a single store uses a single codec, so every {@link CodecBitmap} an operation sees\n * was produced by the same {@link CodecInterface}. The binary set ops ({@link CodecBitmap.orInPlace} etc.) may\n * therefore assume `other` is the same concrete type and are not required to interoperate across codecs.\n * (Corollary: a decoded-chunk HOT cache is codec-specific — never share one `cache` across engines built with\n * different codecs, or a cached bitmap from codec A could reach codec B's in-place op. The `CloudRoaring` facade\n * mints the cache per store, so this cannot arise in normal use.)\n *\n * **Interface surface = exactly what the engine needs**, kept general enough for the known fast-follow codecs\n * (positional/rank-select access + raw-bitset interop that `@cloudbitmaps/bitset` will add live on that\n * package's own extended value type, not here — the engine never calls them). The one codec-linked concern\n * this seam intentionally leaves in the format layer is the `.crbm` **payload codec id**\n * (`PAYLOAD_CODEC_ROARING_PORTABLE` / `KNOWN_PAYLOAD_CODEC_IDS` in `crbm/format.ts`): it is stamped in the footer\n * and validated on read. That generalization is **done** as of 0.7.0 — the field was `roaringSerializationId`\n * and validated by equality against a single constant, which would have frozen a codec-specific name into the\n * format at `1.0`. It is now a registry the reader checks membership against, so a future codec is a one-line\n * registration rather than a major format version. Still deliberately outside this interface: a codec declares\n * its bytes, the seam does not.\n */\n\nimport { ValidationError } from './errors';\n\n/**\n * The value type a codec produces — a mutable set of `u32` with set algebra and portable (de)serialization.\n * This is the shape `SafeBitmap` already has; the engine holds these, caches them, and merges tiers with them.\n */\nexport interface CodecBitmap {\n /** Serialize with the codec's **stable, portable** format (never a frozen/unsafe variant). */\n serialize(): Uint8Array;\n add(value: number): void;\n addMany(values: Iterable<number>): void;\n remove(value: number): void;\n removeMany(values: Iterable<number>): void;\n has(value: number): boolean;\n /** Cardinality. */\n readonly size: number;\n readonly isEmpty: boolean;\n /** A deep copy — mutating the clone must not touch the original (the HOT cache relies on this). */\n clone(): CodecBitmap;\n /** In-place union `this = this ∪ other`. `other` is from the same codec (see the homogeneity contract). */\n orInPlace(other: CodecBitmap): void;\n /** In-place difference `this = this \\ other`. */\n andNotInPlace(other: CodecBitmap): void;\n /** In-place intersection `this = this ∩ other`. */\n andInPlace(other: CodecBitmap): void;\n /** Ascending iterator over the set values. */\n [Symbol.iterator](): IterableIterator<number>;\n toArray(): number[];\n /**\n * The largest value in the set, or `undefined` when empty.\n *\n * **Optional, and deliberately so.** The engine uses it for one thing: asserting that a payload it is about\n * to interpret **as a chunk** holds only 16-bit remainders (see {@link assertChunkPayload}). A codec that\n * cannot answer this in better than O(n) should simply omit it — the engine then skips the check rather\n * than walking every value on the read path, which is the one thing this must never cost.\n *\n * Roaring answers it in O(1) from its container index, so the flagship codec implements it.\n */\n maximum?(): number | undefined;\n /**\n * Re-encode for size, in place, immediately before a **cold** write. Representation only — this must never\n * change membership, and `serialize()` afterwards must decode back to exactly the same set.\n *\n * **Optional, like {@link maximum}.** A codec whose encoding has no size decision to make (a plain bitset has\n * one representation and nothing to choose) simply omits it, and the engine skips the call.\n *\n * WHY THIS EXISTS. Roaring picks per container between an array, a bitset and a RUN — but the run choice is\n * not automatic in any implementation: it is a `runOptimize()` pass you have to ask for, and nothing here was\n * asking. So two of the three container types were ever used, and run-shaped data paid list or bitmap prices\n * for a run. Measured on the shipped codec: a contiguous 1,000,000-id range serialized to 128.1 KiB where\n * run-encoding needs **0.2 KiB** (570×), and a 2,000-run shape 536.5 KiB against **8.5 KiB** (63×). Sparse\n * data is unchanged, because there are no runs to find — the pass is not a gamble.\n *\n * WHY ONLY ON THE COLD PATH. This is called where a whole immutable generation is written, so its cost\n * amortizes over a write that is already serializing and checksumming every chunk. It is deliberately NOT\n * called on the warm delta path (`chunk.ts`), which runs per operation: the hot path must not pay for a\n * rare-ish win, per KISS/YAGNI. Warm rows are short-lived and get folded into a cold generation by\n * compaction, where they are optimized then.\n */\n optimize?(): void;\n}\n\n/**\n * A pluggable bitmap codec — the factory the codec-agnostic engine constructs {@link CodecBitmap}s through.\n * Implementations **must** size-cap before handing untrusted bytes to any native decoder and use a safe\n * (never a trusting/frozen) deserializer (threat model S1).\n */\nexport interface CodecInterface {\n /** An empty set. */\n empty(): CodecBitmap;\n /** A set seeded from an iterable of `u32` values. */\n fromValues(values: Iterable<number>): CodecBitmap;\n /**\n * Size-cap (`bytes.length <= maxBytes`) then portable-deserialize. Throws `IntegrityError` when the input\n * exceeds the cap or fails to decode — the native decoder is never handed unbounded or unsafe-format input.\n */\n safeDeserialize(bytes: Uint8Array, maxBytes: number): CodecBitmap;\n}\n\n/**\n * Resolve a codec that a **public core entry point** was given, failing fast when it is missing.\n *\n * Why these entry points take `codec?` rather than a required field: `bulkLoadCrbmGeneration` /\n * `compactSegment` / `runExport` are call-compatible public API, and core cannot supply a default (the concrete\n * codec lives in a *flavor* package that depends on core — a default here would invert that arrow). A **flavor**\n * package binds the codec for its users (`@cloudbitmaps/roaring` re-exports codec-bound wrappers), so an\n * application never reaches this throw; only someone calling `@cloudbitmaps/core` directly — i.e. a flavor or\n * driver author — can, and for them the typed error names exactly what to pass.\n */\nexport function requireCodec(codec: CodecInterface | undefined, api: string): CodecInterface {\n if (codec === undefined) {\n throw new ValidationError(\n `${api} needs a bitmap codec: pass \\`codec\\` (e.g. \\`roaringCodec\\` from @cloudbitmaps/roaring). ` +\n `@cloudbitmaps/core is codec-agnostic and has no default — install a flavor package, whose ` +\n `equivalents bind the codec for you.`,\n );\n }\n return codec;\n}\n","/**\n * Encryption seams — the **pure** interfaces `core/` depends on so the codec can encrypt/decrypt without\n * importing `node:crypto` (lint-banned here, like `Clock`/`Rng`/drivers). Concrete AES-256-GCM lives outside\n * `core/` (`src/drivers/crypto.ts`) and is injected. The envelope scheme: a per-segment DEK wrapped under an\n * operator-held KEK, so discarding the DEK crypto-shreds the segment. Per-chunk AEAD over the `.crbm` payloads + index; a per-segment **DEK** wrapped (envelope\n * encryption) under one or more **KEK**s by an {@link IKeystore}; the wrapped DEK(s) live in the registry, so\n * crypto-shred = delete them.\n */\n\n/** One AEAD result: a fresh per-message nonce, the ciphertext, and the authentication tag. */\nexport interface AeadSealed {\n readonly nonce: Uint8Array;\n readonly ciphertext: Uint8Array;\n readonly tag: Uint8Array;\n}\n\n/**\n * Authenticated encryption bound to a single key (a segment's DEK). `aad` (associated data) is authenticated\n * but not encrypted — the codec passes each chunk's `(namespace, segment, generation, chunkKey)` identity\n * ({@link aadFor}), so a chunk's ciphertext can't be silently relocated to another segment/generation/chunk or\n * the index, even by someone who can rewrite Cold objects. The seam is symmetric and self-framing-agnostic:\n * the caller decides where the nonce/tag go (inline with a chunk, or in the footer for the index).\n */\nexport interface Aead {\n /** Encrypt `plaintext`, authenticating `aad`. Returns a fresh nonce + ciphertext + tag. */\n seal(plaintext: Uint8Array, aad: Uint8Array): AeadSealed;\n /**\n * Decrypt + verify. Throws {@link IntegrityError} on **any** mismatch (wrong key, tampered ciphertext/tag,\n * or `aad` that doesn't match what was sealed) — never returns wrong-but-plausible plaintext.\n */\n open(sealed: AeadSealed, aad: Uint8Array): Uint8Array;\n}\n\n/**\n * A DEK wrapped under one KEK. A segment stores a **list** of these (one per KEK it was wrapped under — e.g.\n * an active KEK plus an offline recovery KEK), so losing one KEK isn't fatal and KEK rotation needs no\n * data re-encryption. `keyId` names which KEK; `wrapped` is the opaque wrapped-key blob (base64). Carries no\n * plaintext key material — safe to store in the registry next to the (encrypted) data.\n */\nexport interface WrappedDek {\n readonly keyId: string;\n readonly wrapped: string;\n}\n\n/**\n * Envelope key management — the injected seam between the codec and however the operator holds key material\n * (in-process BYOK by default; KMS/Vault as optional adapters later). Async so a remote keystore (KMS) fits\n * the same interface. Never exposes raw key bytes to `core/`: it returns an {@link Aead} bound to the DEK.\n */\nexport interface IKeystore {\n /**\n * Mint a fresh per-segment DEK, wrapped under the active KEK (and any recovery KEK). Returns the wrapping(s)\n * to persist in the registry plus an {@link Aead} to encrypt this segment's chunks with.\n */\n createDek(): Promise<{ wrapped: WrappedDek[]; aead: Aead }>;\n /**\n * Reconstruct the {@link Aead} from a segment's stored wrappings by unwrapping with any KEK currently held.\n * Throws {@link KeyUnavailableError} if it holds none of the referenced KEKs (lost key, or a shredded\n * segment whose wrappings were deleted).\n */\n openDek(wrapped: readonly WrappedDek[]): Promise<Aead>;\n}\n\n/**\n * What the encrypting codec needs: the {@link Aead} for this segment's DEK plus a way to build the AAD for a\n * given scope (`'index'` or a chunkKey). Built per (segment, generation) by the cold-source bridge so the\n * codec itself stays segment-agnostic.\n */\nexport interface CrbmCrypto {\n readonly aead: Aead;\n aadFor(scope: number | 'index'): Uint8Array;\n}\n\nconst AAD_VERSION = 1;\nconst SCOPE_CHUNK = 0;\nconst SCOPE_INDEX = 1;\n\n/**\n * Build the AEAD associated-data binding a chunk (or the index) to its exact location:\n * `v1 ‖ len(namespace) ‖ namespace ‖ len(segment) ‖ segment ‖ generation ‖ scope ‖ chunkKey`. Length-prefixed\n * so distinct `(namespace, segment)` pairs can never collide. Pure (no crypto) — just the authenticated label.\n */\nexport function aadFor(\n ref: { readonly namespace?: string; readonly segment: string },\n generation: number,\n scope: number | 'index',\n): Uint8Array {\n const enc = new TextEncoder();\n const ns = enc.encode(ref.namespace ?? '');\n const seg = enc.encode(ref.segment);\n const out = new Uint8Array(1 + 2 + ns.length + 2 + seg.length + 8 + 1 + 4);\n const view = new DataView(out.buffer);\n let o = 0;\n out[o] = AAD_VERSION;\n o += 1;\n view.setUint16(o, ns.length, true);\n o += 2;\n out.set(ns, o);\n o += ns.length;\n view.setUint16(o, seg.length, true);\n o += 2;\n out.set(seg, o);\n o += seg.length;\n view.setBigUint64(o, BigInt(generation), true);\n o += 8;\n out[o] = scope === 'index' ? SCOPE_INDEX : SCOPE_CHUNK;\n o += 1;\n view.setUint32(o, scope === 'index' ? 0 : scope, true);\n return out;\n}\n","/**\n * CRC32C (Castagnoli, polynomial 0x1EDC6F41) — the pre-deserialize integrity screen for `.crbm`\n * payloads, index, and footer.\n *\n * Pure TypeScript, table-driven: `core/` may not import `crypto`/`node:crypto` (the determinism lint\n * enforces it), and a from-scratch implementation is what the cross-language golden corpus will be pinned\n * against. CRC32C (not CRC32) is the locked choice — it matches the hardware-accelerated checksum used\n * by SSE/iSCSI/Btrfs, and it is the algorithm the `.crbm` format locks in.\n */\n\n/** Reflected CRC32C lookup table (256 entries), built once from the reflected polynomial. */\n/**\n * Slicing-by-8 tables. `TABLES[0]` is the classic byte-at-a-time table; each subsequent table is the previous\n * one advanced by another byte position, which is what lets the loop below consume 8 bytes per iteration\n * instead of one.\n */\nconst TABLES = ((): Uint32Array[] => {\n const POLY = 0x82f63b78; // bit-reflected 0x1EDC6F41\n const t0 = new Uint32Array(256);\n for (let n = 0; n < 256; n++) {\n let c = n;\n for (let k = 0; k < 8; k++) c = c & 1 ? POLY ^ (c >>> 1) : c >>> 1;\n t0[n] = c >>> 0;\n }\n const tables = [t0];\n for (let k = 1; k < 8; k++) {\n const prev = tables[k - 1] as Uint32Array;\n const next = new Uint32Array(256);\n for (let n = 0; n < 256; n++) {\n const v = prev[n] as number;\n next[n] = ((v >>> 8) ^ (t0[v & 0xff] as number)) >>> 0;\n }\n tables.push(next);\n }\n return tables;\n})();\nconst T0 = TABLES[0] as Uint32Array;\nconst T1 = TABLES[1] as Uint32Array;\nconst T2 = TABLES[2] as Uint32Array;\nconst T3 = TABLES[3] as Uint32Array;\nconst T4 = TABLES[4] as Uint32Array;\nconst T5 = TABLES[5] as Uint32Array;\nconst T6 = TABLES[6] as Uint32Array;\nconst T7 = TABLES[7] as Uint32Array;\n\nexport function crc32c(bytes: Uint8Array, seed = 0): number {\n let crc = (seed ^ 0xffffffff) >>> 0;\n let i = 0;\n // Eight bytes per iteration. Identical output to the byte-at-a-time form — this is the standard\n // slicing-by-8 arrangement of the same polynomial, not a different checksum — but it amortises the table\n // lookups and the loop overhead across eight bytes. That matters because this runs over the whole `.crbm`\n // index on every reader open, where the byte-at-a-time version measured ~3.3 ms/MiB and up to ~27 ms for a\n // maximally-sized index, all of it a synchronous stall on Node's only thread.\n const n8 = bytes.length - (bytes.length % 8);\n for (; i < n8; i += 8) {\n crc ^=\n (bytes[i] as number) |\n ((bytes[i + 1] as number) << 8) |\n ((bytes[i + 2] as number) << 16) |\n ((bytes[i + 3] as number) << 24);\n crc =\n ((T7[crc & 0xff] as number) ^\n (T6[(crc >>> 8) & 0xff] as number) ^\n (T5[(crc >>> 16) & 0xff] as number) ^\n (T4[(crc >>> 24) & 0xff] as number) ^\n (T3[bytes[i + 4] as number] as number) ^\n (T2[bytes[i + 5] as number] as number) ^\n (T1[bytes[i + 6] as number] as number) ^\n (T0[bytes[i + 7] as number] as number)) >>>\n 0;\n }\n // Tail: whatever did not divide by 8, byte-at-a-time.\n for (; i < bytes.length; i++) {\n crc = ((T0[(crc ^ (bytes[i] as number)) & 0xff] as number) ^ (crc >>> 8)) >>> 0;\n }\n return (crc ^ 0xffffffff) >>> 0;\n}\n","/**\n * LEB128 unsigned varint codec for the `.crbm` chunk index.\n *\n * The index is delta+varint encoded so a full 16-bit span stays ~400–650 KB instead of ~900 KB of\n * fixed triplets (finding B6). All index varint values are small (chunk-key deltas ≤ 65535,\n * cardinalities ≤ 65536, payload lengths bounded by a size cap) — well within 32 bits — so this codec\n * accepts unsigned integers in `[0, 0xffffffff]` and rejects anything wider as a programming error.\n */\nimport { IntegrityError } from '../errors';\n\nconst U32_CEIL = 0x1_0000_0000; // 2^32\n\n/** Append the LEB128 encoding of a u32 `value` to `out`. */\nexport function writeVarint(out: number[], value: number): void {\n if (!Number.isInteger(value) || value < 0 || value >= U32_CEIL) {\n throw new RangeError(`varint value must be a u32; got ${value}`);\n }\n let v = value;\n while (v > 0x7f) {\n out.push((v & 0x7f) | 0x80);\n v >>>= 7;\n }\n out.push(v);\n}\n\nexport interface VarintRead {\n readonly value: number;\n /** Offset just past the bytes consumed. */\n readonly next: number;\n}\n\n/**\n * Decode a LEB128 varint from `bytes` starting at `offset`. Throws `IntegrityError` on a truncated or\n * over-long (> 5-byte / > u32) encoding — the bytes are untrusted, so a malformed index must fail\n * cleanly, never loop or overflow.\n */\nexport function readVarint(bytes: Uint8Array, offset: number): VarintRead {\n let result = 0;\n let shift = 0;\n let pos = offset;\n for (let i = 0; i < 5; i++) {\n if (pos >= bytes.length) {\n throw new IntegrityError('varint truncated past end of buffer');\n }\n const byte = bytes[pos]!;\n pos += 1;\n // The 5th byte may contribute at most 4 bits (32 total); reject wider.\n if (i === 4 && byte > 0x0f) {\n throw new IntegrityError('varint exceeds u32 range');\n }\n result += (byte & 0x7f) * 2 ** shift;\n if ((byte & 0x80) === 0) {\n return { value: result, next: pos };\n }\n shift += 7;\n }\n throw new IntegrityError('varint exceeds u32 range');\n}\n","/**\n * Frozen `.crbm` v1.0 layout constants.\n *\n * These byte widths/offsets are pinned by the Phase-2a golden corpus and must never change for v1 —\n * a new layout is a new format version. All multi-byte integers are little-endian (v1 fixes LE).\n */\n\n/** 4-byte magic at both file ends: \"CRBM\". */\nexport const MAGIC = Uint8Array.of(0x43, 0x52, 0x42, 0x4d);\n\nexport const VERSION_MAJOR = 1;\nexport const VERSION_MINOR = 0;\n\n/** Front preamble: magic(4) + version_major(1) + version_minor(1) + reserved(2). */\nexport const PREAMBLE_BYTES = 8;\n\n/** Payloads begin immediately after the preamble. */\nexport const PAYLOAD_START = PREAMBLE_BYTES;\n\n/** Fixed footer size (v1.0). */\nexport const FOOTER_BYTES = 104;\n\n/** Byte offsets of each field within the 104-byte footer. */\nexport const FOOTER = {\n indexOffset: 0, // u64\n indexLength: 8, // u64\n indexCrc32c: 16, // u32\n flags: 20, // u32\n payloadCodecId: 24, // u16 — was `roaringSerializationId`; same offset, same width, wider meaning\n elementWidth: 26, // u8\n containerCodec: 27, // u8\n versionMajor: 28, // u8\n versionMinor: 29, // u8\n reserved2: 30, // u16\n generation: 32, // u64\n indexNonce: 40, // 12 B\n indexTag: 52, // 16 B\n keyId: 68, // 16 B\n chunkCount: 84, // u32\n totalCardinality: 88, // u64\n footerCrc32c: 96, // u32 — covers footer bytes [0, 96)\n endMagic: 100, // char[4]\n} as const;\n\n/** Footer bytes covered by `footer_crc32c` (everything before the CRC field). */\nexport const FOOTER_CRC_COVERAGE = FOOTER.footerCrc32c; // 96\n\n/** `flags` bit positions. */\nexport const FLAG_ENCRYPTED = 1 << 0;\nexport const FLAG_INDEX_COMPRESSED = 1 << 1; // reserved\nexport const FLAG_LITTLE_ENDIAN = 1 << 2; // =1 in v1\n\n/** Flag bits a v1 reader understands; any bit outside this mask is an unsupported feature. */\nexport const KNOWN_FLAGS = FLAG_ENCRYPTED | FLAG_LITTLE_ENDIAN;\n\n/**\n * Default element width: 32-bit ids (the u32 member space). `64` is the *reserved* escape above the\n * ~4.29 B-ids/segment u32 ceiling; a v1 (32-bit) reader must **reject** a 64-bit generation rather than feed\n * it to the 32-bit deserializer (which would mis-count fleet-wide). A future 64-bit generation is therefore a\n * **major**-version bump (auto-rejected by old readers), never a silent minor one — see\n * {@link CrbmReader.open} validates this.\n */\nexport const ELEMENT_WIDTH_32 = 32;\n\n/**\n * **Which codec produced the chunk payloads.** Recorded in the footer, validated on read.\n *\n * `.crbm` is a shared container: the index, the CRC32Cs, the AEAD framing and the generation model are all\n * codec-independent, and **only the chunk payload bytes belong to a flavor** (hence *Chunked Remote BitMap* —\n * see `04-CRBM-FORMAT`). This field is what lets one container hold either, the same way ZIP tags each member\n * with a compression method.\n *\n * **Why this is not named `roaringSerializationId` any more.** It was, and the name was a trap waiting for the\n * `1.0` format freeze. A second codec is genuinely expected — `soaring` is a planned Roaring *variant*, so its\n * serialized bytes are unlikely to be roaring-portable, and it lands *after* `1.0`. A field frozen under a\n * codec-specific name cannot be reinterpreted later without a major format version, so generalizing it is a\n * one-line change now and an expensive one after the freeze. The byte layout is untouched: same offset (24),\n * same width (u16), same golden corpus.\n *\n * **Ids are permanent once published.** Add to {@link KNOWN_PAYLOAD_CODEC_IDS} when a codec ships; never\n * reuse or renumber. Ids are deliberately *not* pre-allocated for codecs that do not exist — a reserved number\n * for an unbuilt codec is a guess about a format nobody has designed.\n */\nexport const PAYLOAD_CODEC_ROARING_PORTABLE = 1;\n\n/**\n * Every payload codec id this reader can decode.\n *\n * The reader validates membership rather than equality with a single constant. That is the whole point of the\n * generalization: an unknown id is rejected with a typed error naming it, so an old reader meeting a\n * future-codec generation **fails closed** — the correct direction, and the reason a store built on one codec\n * can never silently misread another's bytes as its own. (The homogeneity contract means one store is one\n * codec, so meeting a foreign generation implies misconfiguration, and a loud rejection is exactly what you\n * want there.)\n */\nexport const KNOWN_PAYLOAD_CODEC_IDS: ReadonlySet<number> = new Set([\n PAYLOAD_CODEC_ROARING_PORTABLE,\n]);\n\n/**\n * The only container codec v1 defines: `0` = none (payloads are stored as the portable roaring serialization\n * with no extra container-level transform). A non-zero codec is a future format feature; a v1 reader rejects\n * it ({@link UnsupportedError}) rather than mis-decode. Stamped by the writer, validated by the reader.\n */\nexport const CONTAINER_CODEC_NONE = 0;\n\n/**\n * Default speculative-tail-read size. The spec's worst-case index (a full 16-bit span) is ~400–650 KB,\n * so 256 KB collapses the read to a single GET for the vast majority of real (sparse/medium) segments;\n * only near-full-span segments take the documented second GET.\n */\nexport const DEFAULT_TAIL_BYTES = 256 * 1024;\n\n/**\n * Hard cap on the index region a reader will fetch/parse from one (untrusted) object. The index is read\n * whole on the cheap `open()`/`count()` path, so it must be bounded before allocation — generously\n * above the ~650 KB full-span worst case, well below a denial-of-wallet allocation.\n */\nexport const DEFAULT_MAX_INDEX_BYTES = 8 * 1024 * 1024;\n\n/** Hard cap on a single chunk payload, defending the native deserializer against oversized input. */\nexport const DEFAULT_MAX_PAYLOAD_BYTES = 16 * 1024 * 1024;\n\n/** A chunk's cardinality is in `[1, 65536]` (empty chunks are never written). */\nexport const MAX_CHUNK_CARDINALITY = 0x1_0000;\n\n/** Fixed width of a per-chunk CRC32C field in the index (high-entropy → not varint). */\nexport const CRC32C_BYTES = 4;\n\n/**\n * v1 AEAD framing sizes (AES-256-GCM), fixed by the format exactly like the roaring serialization id — a\n * different cipher is a new format version. An encrypted chunk payload is stored as `nonce ‖ ciphertext ‖ tag`;\n * the encrypted **index**'s nonce/tag live in the footer's reserved `indexNonce`/`indexTag` slots. Matches\n * {@link FOOTER.indexNonce} (12 B) and {@link FOOTER.indexTag} (16 B).\n */\nexport const AEAD_NONCE_BYTES = 12;\nexport const AEAD_TAG_BYTES = 16;\n","/**\n * `CrbmReader` — speculative-tail-read reader for one `.crbm` generation.\n *\n * `open()` fetches the object's tail in **one GET** (footer + usually the whole index), verifies the\n * footer/index CRCs, and parses the delta+varint index into a map. `getChunk()` then range-GETs a single\n * payload and verifies its CRC32C **before** any native deserialize — every byte from storage is\n * untrusted (F3/F4).\n *\n * **Encryption (Phase 4e).** When the footer's `FLAG_ENCRYPTED` is set, a {@link CrbmCrypto} must be supplied:\n * the index is AES-256-GCM-decrypted (nonce/tag from the footer) and each chunk payload is decrypted after its\n * on-disk CRC passes. The footer's `chunkCount`/`totalCardinality` are zero on an encrypted object (metadata is\n * hidden), so both are derived from the decrypted index; AEAD authentication (incl. the per-location AAD)\n * replaces the cleartext-count cross-check.\n */\nimport { IntegrityError, UnsupportedError, ValidationError } from '../errors';\nimport type { BlobReader } from '../blob';\nimport type { CrbmCrypto } from '../crypto';\nimport { crc32c } from './crc32c';\nimport { readVarint } from './varint';\nimport {\n AEAD_NONCE_BYTES,\n AEAD_TAG_BYTES,\n CONTAINER_CODEC_NONE,\n CRC32C_BYTES,\n DEFAULT_MAX_INDEX_BYTES,\n DEFAULT_MAX_PAYLOAD_BYTES,\n DEFAULT_TAIL_BYTES,\n ELEMENT_WIDTH_32,\n FLAG_ENCRYPTED,\n FLAG_LITTLE_ENDIAN,\n FOOTER,\n FOOTER_BYTES,\n FOOTER_CRC_COVERAGE,\n KNOWN_FLAGS,\n MAGIC,\n MAX_CHUNK_CARDINALITY,\n PAYLOAD_START,\n PREAMBLE_BYTES,\n KNOWN_PAYLOAD_CODEC_IDS,\n PAYLOAD_CODEC_ROARING_PORTABLE,\n VERSION_MAJOR,\n} from './format';\n\nexport interface CrbmIndexEntry {\n readonly chunkKey: number;\n readonly offset: number;\n readonly length: number;\n readonly cardinality: number;\n readonly crc32c: number;\n}\n\n/**\n * Estimated retained JS heap for one parsed index entry, used to weight the reader-cache byte bound\n * ({@link CrbmReader.retainedIndexBytes}). In V8 an entry costs: a `Map` slot (~48–64 B: two pointer slots +\n * hash chaining), the {@link CrbmIndexEntry} object (~40–56 B: header + 5 fields, where `offset`/`crc32c`\n * routinely exceed the 2³¹ SMI range and box as heap doubles, +16 B each), and one `orderedKeys` array slot\n * (~8 B) — realistically ~130–160 B. Rounded UP to 160 so the bound **over-counts** (a configured N-byte\n * ceiling pins ≤ N of real heap, never more), keeping the aggregate memory guarantee on the safe side. A\n * stable upper proxy, not an exact figure.\n */\nconst RETAINED_BYTES_PER_INDEX_ENTRY = 160;\n\nexport interface CrbmReaderOptions {\n /** Speculative tail size in bytes (default 256 KB; clamped up to at least the footer size). */\n readonly tailBytes?: number;\n /** Hard cap on a single chunk payload length (default 16 MB). */\n readonly maxPayloadBytes?: number;\n /** Hard cap on the whole index region fetched/parsed from one object (default 8 MB). */\n readonly maxIndexBytes?: number;\n /** Decryption context for an encrypted object (its DEK's AEAD + AAD builder). Required iff `FLAG_ENCRYPTED`. */\n readonly crypto?: CrbmCrypto;\n}\n\nfunction magicMatches(bytes: Uint8Array, offset: number): boolean {\n return (\n bytes[offset] === MAGIC[0] &&\n bytes[offset + 1] === MAGIC[1] &&\n bytes[offset + 2] === MAGIC[2] &&\n bytes[offset + 3] === MAGIC[3]\n );\n}\n\n/** Read a u64 footer field, rejecting values past JS safe-integer range (precision would be lost). */\nfunction readU64(view: DataView, offset: number, field: string): number {\n const big = view.getBigUint64(offset, true);\n if (big > BigInt(Number.MAX_SAFE_INTEGER)) {\n throw new IntegrityError(`.crbm ${field} ${big} exceeds safe-integer range`);\n }\n return Number(big);\n}\n\nexport class CrbmReader {\n private constructor(\n private readonly blob: BlobReader,\n private readonly objectSize: number,\n readonly generation: number,\n readonly totalCardinality: number,\n private readonly entries: Map<number, CrbmIndexEntry>,\n private readonly orderedKeys: number[],\n /** True when `open()` satisfied the index from the tail GET alone (no second range read). */\n readonly servedFromTail: boolean,\n /** Set iff the object is encrypted — used to decrypt each chunk payload in {@link getChunk}. */\n private readonly crypto: CrbmCrypto | undefined,\n ) {}\n\n /** Total object bytes (from the one-GET tail read) — for grounded storage cost (Phase 5b). */\n get sizeBytes(): number {\n return this.objectSize;\n }\n\n /**\n * Estimated retained JS heap of this reader's parsed index — the weight the cold reader cache bounds on\n * (gap #1: a wide segment's index dominates the reader's footprint). `entries.size` scales with the number\n * of resident chunks (≤ 65536), so this is `entries.size × {@link RETAINED_BYTES_PER_INDEX_ENTRY}`.\n */\n get retainedIndexBytes(): number {\n return this.entries.size * RETAINED_BYTES_PER_INDEX_ENTRY;\n }\n\n /** Per-chunk cardinality (`chunkKey → count`) from the parsed index — no payload reads (Phase 5c cheap count). */\n cardinalities(): Map<number, number> {\n const out = new Map<number, number>();\n for (const [chunkKey, entry] of this.entries) out.set(chunkKey, entry.cardinality);\n return out;\n }\n\n static async open(blob: BlobReader, options: CrbmReaderOptions = {}): Promise<CrbmReader> {\n // Always fetch at least a footer's worth, regardless of a smaller caller request.\n const tailBytes = Math.max(options.tailBytes ?? DEFAULT_TAIL_BYTES, FOOTER_BYTES);\n const maxPayloadBytes = options.maxPayloadBytes ?? DEFAULT_MAX_PAYLOAD_BYTES;\n const maxIndexBytes = options.maxIndexBytes ?? DEFAULT_MAX_INDEX_BYTES;\n const { bytes: tail, size } = await blob.getTail(tailBytes);\n\n if (size < PREAMBLE_BYTES + FOOTER_BYTES || tail.length < FOOTER_BYTES) {\n throw new IntegrityError(`.crbm too small: ${size}B`);\n }\n\n // --- Footer (last 104 bytes of the tail) ---\n const footer = tail.subarray(tail.length - FOOTER_BYTES);\n if (!magicMatches(footer, FOOTER.endMagic)) {\n throw new IntegrityError('.crbm end magic mismatch');\n }\n const fview = new DataView(footer.buffer, footer.byteOffset, footer.byteLength);\n const storedFooterCrc = fview.getUint32(FOOTER.footerCrc32c, true);\n if (crc32c(footer.subarray(0, FOOTER_CRC_COVERAGE)) !== storedFooterCrc) {\n throw new IntegrityError('.crbm footer CRC mismatch');\n }\n const versionMajor = footer[FOOTER.versionMajor]!;\n if (versionMajor !== VERSION_MAJOR) {\n throw new UnsupportedError(`.crbm major version ${versionMajor} not supported`);\n }\n const flags = fview.getUint32(FOOTER.flags, true);\n const encrypted = (flags & FLAG_ENCRYPTED) !== 0;\n if (encrypted && options.crypto === undefined) {\n throw new ValidationError('.crbm is encrypted but no decryption key (crypto) was provided');\n }\n if ((flags & FLAG_LITTLE_ENDIAN) === 0) {\n throw new UnsupportedError('.crbm big-endian layout not supported (v1 is little-endian)');\n }\n if ((flags & ~KNOWN_FLAGS) !== 0) {\n throw new UnsupportedError(`.crbm has unknown flag bits set: 0x${flags.toString(16)}`);\n }\n\n // Payload-decoding contract: the\n // reader must decode with the *same* element width, roaring serialization, and container codec the writer\n // stamped — a mismatch means the payloads are a format this v1 (32-bit, portable, uncompressed) reader can't\n // safely deserialize, so reject up front rather than feed them to the 32-bit deserializer and mis-count\n // fleet-wide. A 64-bit generation is the reserved >4.29 B-ids/segment escape and is a **major**-version bump\n // (auto-rejected here), never a silent minor one. All three fields are inside FOOTER_CRC_COVERAGE (verified).\n const elementWidth = footer[FOOTER.elementWidth]!;\n if (elementWidth !== ELEMENT_WIDTH_32) {\n throw new UnsupportedError(\n `.crbm element_width ${elementWidth} not supported (v1 reads 32-bit ids; 64-bit is a future major version)`,\n );\n }\n // Membership, not equality: the field says which codec wrote the payloads, and this reader accepts every\n // id it can actually decode. An unknown one fails closed rather than being handed to a decoder that would\n // misread it — see KNOWN_PAYLOAD_CODEC_IDS for why that direction is the safe one.\n const payloadCodecId = fview.getUint16(FOOTER.payloadCodecId, true);\n if (!KNOWN_PAYLOAD_CODEC_IDS.has(payloadCodecId)) {\n throw new UnsupportedError(\n `.crbm payload_codec_id ${payloadCodecId} not supported by this build ` +\n `(known: ${[...KNOWN_PAYLOAD_CODEC_IDS].join(', ')}; ` +\n `${PAYLOAD_CODEC_ROARING_PORTABLE}=roaring portable). A generation written by a different codec ` +\n `is rejected rather than decoded — a store uses one codec throughout.`,\n );\n }\n const containerCodec = footer[FOOTER.containerCodec]!;\n if (containerCodec !== CONTAINER_CODEC_NONE) {\n throw new UnsupportedError(\n `.crbm container_codec ${containerCodec} not supported (v1 defines only ${CONTAINER_CODEC_NONE}=none)`,\n );\n }\n\n const indexOffset = readU64(fview, FOOTER.indexOffset, 'index_offset');\n const indexLength = readU64(fview, FOOTER.indexLength, 'index_length');\n const indexCrc = fview.getUint32(FOOTER.indexCrc32c, true);\n const chunkCount = fview.getUint32(FOOTER.chunkCount, true);\n const totalCardinality = readU64(fview, FOOTER.totalCardinality, 'total_cardinality');\n const generation = readU64(fview, FOOTER.generation, 'generation');\n\n // Bounds + size cap on the index region before trusting/fetching it.\n if (indexOffset < PAYLOAD_START || indexOffset + indexLength > size - FOOTER_BYTES) {\n throw new IntegrityError(\n `.crbm index region [${indexOffset}, +${indexLength}) out of bounds`,\n );\n }\n if (indexLength > maxIndexBytes) {\n throw new IntegrityError(`.crbm index ${indexLength}B exceeds cap ${maxIndexBytes}B`);\n }\n\n // Validate the front preamble too, but only when this GET already covers it (no extra request).\n const tailCoversFrom = size - tail.length;\n if (tailCoversFrom === 0) {\n if (!magicMatches(tail, 0) || tail[4] !== versionMajor) {\n throw new IntegrityError('.crbm preamble magic/version mismatch with footer');\n }\n }\n\n // --- Index: already in the tail, or one more GET ---\n let indexBytes: Uint8Array;\n let servedFromTail: boolean;\n if (indexOffset >= tailCoversFrom) {\n const start = indexOffset - tailCoversFrom;\n indexBytes = tail.subarray(start, start + indexLength);\n servedFromTail = true;\n } else {\n indexBytes = await blob.getRange(indexOffset, indexLength);\n servedFromTail = false;\n }\n if (crc32c(indexBytes) !== indexCrc) {\n throw new IntegrityError('.crbm index CRC mismatch');\n }\n\n // Decrypt the index (nonce/tag from the footer) before parsing; AAD binds it to this (segment, generation).\n // A wrong key / tampered index / wrong context fails here as an IntegrityError — never a wrong parse.\n const indexForParse = encrypted\n ? options.crypto!.aead.open(\n {\n nonce: footer.subarray(FOOTER.indexNonce, FOOTER.indexNonce + AEAD_NONCE_BYTES),\n ciphertext: indexBytes,\n tag: footer.subarray(FOOTER.indexTag, FOOTER.indexTag + AEAD_TAG_BYTES),\n },\n options.crypto!.aadFor('index'),\n )\n : indexBytes;\n\n const { entries, orderedKeys, cardinalitySum } = parseIndex(\n indexForParse,\n size,\n maxPayloadBytes,\n );\n if (encrypted) {\n // Footer count/cardinality are zeroed on an encrypted object; the decrypted index is authoritative (and\n // already AEAD-authenticated, AAD-bound to this object), so derive the total from it.\n if (chunkCount !== 0 || totalCardinality !== 0) {\n throw new IntegrityError(\n '.crbm encrypted footer must zero chunk_count + total_cardinality',\n );\n }\n } else {\n // F2 (cleartext): the footer total + count must match the index — don't trust the footer blindly.\n if (entries.size !== chunkCount) {\n throw new IntegrityError(\n `.crbm chunk_count ${chunkCount} != ${entries.size} index entries`,\n );\n }\n if (cardinalitySum !== totalCardinality) {\n throw new IntegrityError(\n `.crbm total_cardinality ${totalCardinality} != Σ index cardinality ${cardinalitySum}`,\n );\n }\n }\n\n return new CrbmReader(\n blob,\n size,\n generation,\n cardinalitySum,\n entries,\n orderedKeys,\n servedFromTail,\n options.crypto,\n );\n }\n\n /** Chunk keys present in this generation, ascending. */\n chunkKeys(): number[] {\n return this.orderedKeys.slice();\n }\n\n /** Segment cardinality from the footer (no payload reads) — the cheap `count()` path. */\n count(): number {\n return this.totalCardinality;\n }\n\n has(chunkKey: number): boolean {\n return this.entries.has(chunkKey);\n }\n\n /**\n * Range-GET one chunk's payload, verifying its CRC32C before returning. Returns `null` if the chunk is\n * absent. Throws `IntegrityError` on a CRC mismatch (the bytes must never reach the native\n * deserializer). The returned buffer is a **read-only view** owned by the reader/driver — callers must\n * not mutate it.\n */\n async getChunk(chunkKey: number): Promise<Uint8Array | null> {\n const e = this.entries.get(chunkKey);\n if (e === undefined) return null;\n // Re-validate bounds at read time (defense in depth — a buggy caller or future mutable index path).\n if (e.offset < PAYLOAD_START || e.offset + e.length > this.objectSize - FOOTER_BYTES) {\n throw new IntegrityError(`chunk ${chunkKey} payload out of bounds`);\n }\n const bytes = await this.blob.getRange(e.offset, e.length);\n if (crc32c(bytes) !== e.crc32c) {\n throw new IntegrityError(`chunk ${chunkKey} payload CRC mismatch`);\n }\n if (this.crypto === undefined) return bytes;\n // Encrypted: on-disk frame is nonce ‖ ciphertext ‖ tag. Decrypt (AAD-bound to this chunkKey) after the CRC\n // passes — a wrong key / tamper / relocated chunk fails as an IntegrityError, never a wrong payload.\n if (bytes.length < AEAD_NONCE_BYTES + AEAD_TAG_BYTES) {\n throw new IntegrityError(`chunk ${chunkKey} encrypted payload too short`);\n }\n return this.crypto.aead.open(\n {\n nonce: bytes.subarray(0, AEAD_NONCE_BYTES),\n ciphertext: bytes.subarray(AEAD_NONCE_BYTES, bytes.length - AEAD_TAG_BYTES),\n tag: bytes.subarray(bytes.length - AEAD_TAG_BYTES),\n },\n this.crypto.aadFor(chunkKey),\n );\n }\n}\n\n// Exported for the coverage-guided fuzz harness (test-strategy T3), which fuzzes the hand-written index parser\n// directly on raw bytes — bypassing the CRC wall that mutational fuzzing can't cross. NOT part of the public\n// API surface (`src/index.ts`); reached only via `src/testing/fuzz-support.ts` → the gitignored `fuzz/build/`.\nexport function parseIndex(\n indexBytes: Uint8Array,\n objectSize: number,\n maxPayloadBytes: number,\n): { entries: Map<number, CrbmIndexEntry>; orderedKeys: number[]; cardinalitySum: number } {\n const entries = new Map<number, CrbmIndexEntry>();\n const orderedKeys: number[] = [];\n let pos = 0;\n let prevKey = 0;\n let prevEnd = PAYLOAD_START;\n let cardinalitySum = 0;\n\n // Parse entries until the index region is exactly consumed (chunk_count is hidden on encrypted objects, so\n // the byte length is the bound — readVarint throws on any overrun, so a malformed index fails cleanly).\n for (let i = 0; pos < indexBytes.length; i++) {\n const keyDelta = readVarint(indexBytes, pos);\n const offDelta = readVarint(indexBytes, keyDelta.next);\n const len = readVarint(indexBytes, offDelta.next);\n const card = readVarint(indexBytes, len.next);\n pos = card.next;\n if (pos + CRC32C_BYTES > indexBytes.length) {\n throw new IntegrityError('.crbm index truncated (missing payload CRC)');\n }\n const crc =\n (indexBytes[pos]! |\n (indexBytes[pos + 1]! << 8) |\n (indexBytes[pos + 2]! << 16) |\n (indexBytes[pos + 3]! << 24)) >>>\n 0;\n pos += CRC32C_BYTES;\n\n const chunkKey = prevKey + keyDelta.value;\n const offset = prevEnd + offDelta.value;\n // Unsigned deltas mean keys can only stay flat or rise; a 0 delta after the first is a duplicate.\n if (i > 0 && keyDelta.value === 0) {\n throw new IntegrityError(`.crbm index has a duplicate chunkKey ${chunkKey}`);\n }\n if (chunkKey > 0xffff) throw new IntegrityError(`.crbm chunkKey ${chunkKey} out of range`);\n if (len.value === 0 || len.value > maxPayloadBytes) {\n throw new IntegrityError(`.crbm chunk ${chunkKey} length ${len.value} invalid`);\n }\n if (card.value < 1 || card.value > MAX_CHUNK_CARDINALITY) {\n throw new IntegrityError(`.crbm chunk ${chunkKey} cardinality ${card.value} invalid`);\n }\n if (offset < PAYLOAD_START || offset + len.value > objectSize - FOOTER_BYTES) {\n throw new IntegrityError(`.crbm chunk ${chunkKey} payload out of bounds`);\n }\n\n entries.set(chunkKey, {\n chunkKey,\n offset,\n length: len.value,\n cardinality: card.value,\n crc32c: crc,\n });\n orderedKeys.push(chunkKey);\n cardinalitySum += card.value;\n prevKey = chunkKey;\n prevEnd = offset + len.value;\n }\n // The loop ends only when pos === indexBytes.length exactly (each entry consumes a whole record; a partial\n // trailing record makes readVarint or the CRC bound throw), so there are never unconsumed trailing bytes.\n return { entries, orderedKeys, cardinalitySum };\n}\n","/**\n * `CrbmWriter` — streaming, constant-memory writer for one immutable `.crbm` generation.\n *\n * Chunks are appended in **ascending chunkKey order**; the writer holds only the small index in memory\n * (offsets aren't known until payloads are written — which is exactly why the index is a footer).\n *\n * **Encryption (Phase 4e, opt-in via `crypto`).** When a {@link CrbmCrypto} is supplied, each chunk payload is\n * AES-256-GCM-sealed (`nonce ‖ ciphertext ‖ tag`, AAD = its chunkKey) and the whole index is sealed too (its\n * nonce/tag go in the footer). The footer then sets `FLAG_ENCRYPTED` and **zeroes `chunkCount` +\n * `totalCardinality`** so a leaked object reveals neither how many chunks nor how many ids it holds — the\n * reader derives both from the decrypted index. The per-chunk CRC covers the *encrypted* on-disk bytes.\n */\nimport { ValidationError } from '../errors';\nimport type { CrbmCrypto } from '../crypto';\nimport { crc32c } from './crc32c';\nimport { writeVarint } from './varint';\nimport type { BlobSink } from '../blob';\nimport {\n CONTAINER_CODEC_NONE,\n ELEMENT_WIDTH_32,\n FLAG_ENCRYPTED,\n FLAG_LITTLE_ENDIAN,\n FOOTER,\n FOOTER_BYTES,\n FOOTER_CRC_COVERAGE,\n MAGIC,\n MAX_CHUNK_CARDINALITY,\n PAYLOAD_START,\n PREAMBLE_BYTES,\n PAYLOAD_CODEC_ROARING_PORTABLE,\n VERSION_MAJOR,\n VERSION_MINOR,\n} from './format';\n\nexport interface CrbmWriterOptions {\n /** Self-describing generation number (also encoded in the object key). */\n readonly generation: number;\n /**\n * Which codec produced the chunk payloads. Defaults to {@link PAYLOAD_CODEC_ROARING_PORTABLE}.\n *\n * Renamed from `roaringSerializationId` in 0.7.0 — same footer field, same offset and width, generalized\n * because `.crbm` is a shared container and a second codec is expected before the format freezes.\n */\n readonly payloadCodecId?: number;\n readonly elementWidth?: number;\n /** When set, payloads + index are AES-256-GCM-encrypted, bound to `(segment, generation, scope)` via AAD. */\n readonly crypto?: CrbmCrypto;\n}\n\ninterface IndexEntry {\n readonly chunkKey: number;\n readonly offset: number;\n readonly length: number;\n readonly cardinality: number;\n readonly crc32c: number;\n}\n\nexport class CrbmWriter {\n private readonly entries: IndexEntry[] = [];\n private offset = PAYLOAD_START;\n private lastKey = -1;\n private totalCardinality = 0;\n private preambleWritten = false;\n private finished = false;\n\n constructor(\n private readonly sink: BlobSink,\n private readonly options: CrbmWriterOptions,\n ) {\n if (!Number.isInteger(options.generation) || options.generation < 0) {\n throw new ValidationError(\n `generation must be a non-negative integer; got ${options.generation}`,\n );\n }\n }\n\n /**\n * Append one chunk's payload (the roaring-serialized bytes) with its cardinality. `chunkKey` must be\n * strictly greater than the previous one (ascending, no duplicates); `cardinality` is `[1, 65536]`.\n */\n async addChunk(chunkKey: number, payload: Uint8Array, cardinality: number): Promise<void> {\n if (this.finished) throw new ValidationError('CrbmWriter already finished');\n if (!Number.isInteger(chunkKey) || chunkKey < 0 || chunkKey > 0xffff) {\n throw new ValidationError(`chunkKey must be a u16; got ${chunkKey}`);\n }\n if (chunkKey <= this.lastKey) {\n throw new ValidationError(\n `chunkKey ${chunkKey} not strictly ascending (last ${this.lastKey})`,\n );\n }\n if (!Number.isInteger(cardinality) || cardinality < 1 || cardinality > MAX_CHUNK_CARDINALITY) {\n throw new ValidationError(\n `cardinality must be in [1, ${MAX_CHUNK_CARDINALITY}]; got ${cardinality}`,\n );\n }\n if (payload.length === 0) throw new ValidationError('chunk payload must be non-empty');\n\n await this.ensurePreamble();\n // Encrypt (if configured) to the on-disk bytes; the CRC + index length cover what actually lands on disk.\n const stored = this.options.crypto ? this.sealChunk(chunkKey, payload) : payload;\n await this.sink.write(stored);\n this.entries.push({\n chunkKey,\n offset: this.offset,\n length: stored.length,\n cardinality,\n crc32c: crc32c(stored),\n });\n this.offset += stored.length;\n this.totalCardinality += cardinality;\n this.lastKey = chunkKey;\n }\n\n /** Seal one chunk payload into the on-disk frame `nonce ‖ ciphertext ‖ tag`, bound to its chunkKey. */\n private sealChunk(chunkKey: number, payload: Uint8Array): Uint8Array {\n const crypto = this.options.crypto!;\n const sealed = crypto.aead.seal(payload, crypto.aadFor(chunkKey));\n const out = new Uint8Array(sealed.nonce.length + sealed.ciphertext.length + sealed.tag.length);\n out.set(sealed.nonce, 0);\n out.set(sealed.ciphertext, sealed.nonce.length);\n out.set(sealed.tag, sealed.nonce.length + sealed.ciphertext.length);\n return out;\n }\n\n /** Write the index region + the fixed footer. After this the object is complete and immutable. */\n async finish(): Promise<void> {\n if (this.finished) throw new ValidationError('CrbmWriter already finished');\n await this.ensurePreamble();\n\n const indexPlain = this.encodeIndex();\n // Encrypt the index too (its nonce/tag go in the footer); a leaked object then reveals no chunk metadata.\n let indexRegion = indexPlain;\n let indexNonce: Uint8Array | undefined;\n let indexTag: Uint8Array | undefined;\n if (this.options.crypto !== undefined) {\n const sealed = this.options.crypto.aead.seal(indexPlain, this.options.crypto.aadFor('index'));\n indexRegion = sealed.ciphertext;\n indexNonce = sealed.nonce;\n indexTag = sealed.tag;\n }\n const indexOffset = this.offset;\n await this.sink.write(indexRegion);\n this.offset += indexRegion.length;\n\n const footer = this.buildFooter(indexOffset, indexRegion, indexNonce, indexTag);\n await this.sink.write(footer);\n this.finished = true;\n }\n\n private async ensurePreamble(): Promise<void> {\n if (this.preambleWritten) return;\n const preamble = new Uint8Array(PREAMBLE_BYTES);\n preamble.set(MAGIC, 0);\n preamble[4] = VERSION_MAJOR;\n preamble[5] = VERSION_MINOR;\n // bytes 6-7 reserved = 0\n await this.sink.write(preamble);\n this.preambleWritten = true;\n }\n\n private encodeIndex(): Uint8Array {\n const out: number[] = [];\n let prevKey = 0;\n let prevEnd = PAYLOAD_START;\n for (const e of this.entries) {\n writeVarint(out, e.chunkKey - prevKey);\n writeVarint(out, e.offset - prevEnd);\n writeVarint(out, e.length);\n writeVarint(out, e.cardinality);\n // crc32c is high-entropy → fixed 4-byte LE, not varint.\n out.push(\n e.crc32c & 0xff,\n (e.crc32c >>> 8) & 0xff,\n (e.crc32c >>> 16) & 0xff,\n (e.crc32c >>> 24) & 0xff,\n );\n prevKey = e.chunkKey;\n prevEnd = e.offset + e.length;\n }\n return Uint8Array.from(out);\n }\n\n private buildFooter(\n indexOffset: number,\n indexRegion: Uint8Array,\n indexNonce: Uint8Array | undefined,\n indexTag: Uint8Array | undefined,\n ): Uint8Array {\n const encrypted = this.options.crypto !== undefined;\n const footer = new Uint8Array(FOOTER_BYTES);\n const view = new DataView(footer.buffer);\n view.setBigUint64(FOOTER.indexOffset, BigInt(indexOffset), true);\n view.setBigUint64(FOOTER.indexLength, BigInt(indexRegion.length), true);\n view.setUint32(FOOTER.indexCrc32c, crc32c(indexRegion), true);\n view.setUint32(FOOTER.flags, FLAG_LITTLE_ENDIAN | (encrypted ? FLAG_ENCRYPTED : 0), true);\n view.setUint16(\n FOOTER.payloadCodecId,\n this.options.payloadCodecId ?? PAYLOAD_CODEC_ROARING_PORTABLE,\n true,\n );\n footer[FOOTER.elementWidth] = this.options.elementWidth ?? ELEMENT_WIDTH_32;\n footer[FOOTER.containerCodec] = CONTAINER_CODEC_NONE;\n footer[FOOTER.versionMajor] = VERSION_MAJOR;\n footer[FOOTER.versionMinor] = VERSION_MINOR;\n // When encrypted, the index's AEAD nonce/tag live in these reserved slots; key_id stays zero (the wrapped\n // DEKs live in the registry, not the object). Unencrypted: all crypto fields stay zero.\n if (indexNonce !== undefined) footer.set(indexNonce, FOOTER.indexNonce);\n if (indexTag !== undefined) footer.set(indexTag, FOOTER.indexTag);\n view.setBigUint64(FOOTER.generation, BigInt(this.options.generation), true);\n // Hide chunk count + cardinality on an encrypted object (a leak reveals neither); the reader derives both\n // from the decrypted index. Cleartext objects keep them for the O(1) count()/validation path.\n view.setUint32(FOOTER.chunkCount, encrypted ? 0 : this.entries.length, true);\n view.setBigUint64(FOOTER.totalCardinality, BigInt(encrypted ? 0 : this.totalCardinality), true);\n view.setUint32(FOOTER.footerCrc32c, crc32c(footer.subarray(0, FOOTER_CRC_COVERAGE)), true);\n footer.set(MAGIC, FOOTER.endMagic);\n return footer;\n }\n}\n","/**\n * Bridges the `.crbm` archive format to the engine's Cold seam (decision 4).\n *\n * `CrbmColdChunkSource` implements the Phase-1 {@link ColdChunkSource} over an {@link IColdDriver}: it\n * pins a segment's latest generation, opens its {@link CrbmReader} once, and serves per-chunk payloads —\n * so the **engine is unchanged**, it just reads real on-disk generations now. `writeCrbmGeneration` is\n * the inverse seed primitive (a generation built from in-memory bitmaps), the basis for the Phase-3\n * bulk-load and Phase-4 compaction writers.\n */\nimport { type IAuditSink, NOOP_AUDIT, safeAudit } from './audit';\nimport {\n CapabilityError,\n KeyUnavailableError,\n ValidationError,\n WriteConflictError,\n isNotFoundError,\n isWriteConflictError,\n} from './errors';\nimport type { BlobReader } from './blob';\nimport { yieldEvery } from './cooperative';\nimport type { Yielder } from './cooperative';\nimport type { Clock } from './determinism';\nimport { BoundedLru } from './lru';\nimport { splitId } from './bit-route';\nimport { segmentKey } from './keys';\nimport { aadFor } from './crypto';\nimport type { CrbmCrypto, IKeystore, WrappedDek } from './crypto';\nimport { validateChunkRef, validateSegmentRef } from './validate';\nimport type {\n ChunkRef,\n ColdChunkSource,\n GenKey,\n IColdDriver,\n IRegistryDriver,\n SegmentRef,\n SegmentSize,\n} from './ports';\nimport { CrbmReader } from './crbm/reader';\nimport type { CrbmReaderOptions } from './crbm/reader';\nimport { CrbmWriter } from './crbm/writer';\nimport type { CodecBitmap, CodecInterface } from './codec';\nimport { requireCodec } from './codec';\n\nexport interface CrbmColdChunkSourceOptions extends CrbmReaderOptions {\n /**\n * Optional {@link IRegistryDriver}. When provided, the current generation is resolved via the registry's\n * authoritative `currentGen` (one cheap strong read) instead of a `list` scan of every generation — the\n * Phase-4c retirement of that scan. When absent, the source falls back to the `list`-scan (so the\n * in-memory / simple setups keep working with no registry). The resolved generation is cached and\n * **re-resolved on a short TTL** ({@link currentGenTtlMs}, needs a {@link clock}) so a long-lived source\n * observes a compaction's new generation within the TTL instead of pinning one generation forever (gap #4).\n */\n readonly registry?: IRegistryDriver;\n /**\n * Optional {@link IKeystore} for reading **encrypted** segments (Phase 4e). When a segment's registry record\n * carries wrapped DEK(s), the source unwraps the DEK via this keystore and decrypts each chunk/index. Reading\n * an encrypted segment without a keystore throws {@link KeyUnavailableError}; cleartext segments ignore it.\n * Requires a `registry` (that's where the wrapped DEKs live).\n */\n readonly keystore?: IKeystore;\n /**\n * Enforce that every segment read is encrypted (Phase 4e). When true, resolving a **cleartext** segment (no\n * wrapped DEKs) throws {@link KeyUnavailableError} — a guard against silently reading a segment that should\n * have been encrypted. Off by default (encryption is opt-in).\n */\n readonly requireEncryption?: boolean;\n /**\n * Time source for the current-generation TTL refresh (gap #4) — the determinism seam; `core/` never reads\n * ambient time. Refresh needs **both** a clock and a `registry`; without either the source **pins** the\n * first-resolved generation for its lifetime (the pre-Phase-B behaviour). The `CloudRoaring` facade passes its\n * clock automatically, so wiring a `registry` is enough to get live cross-generation invalidation.\n */\n readonly clock?: Pick<Clock, 'now'>;\n /**\n * How long (ms) a resolved `currentGen` is trusted before the next read re-resolves it (default 2000) — the\n * bound on read staleness after a compaction: a reader may serve the prior generation for up to this long,\n * then converges. Lazy (checked on read — no timer); ≤ one cheap registry read per segment per window, and a\n * new {@link CrbmReader} is opened only when the generation actually changed. `0` (or no clock) ⇒ pin forever.\n */\n readonly currentGenTtlMs?: number;\n /**\n * Hard ceiling on how many segments' readers (each holding a fully-parsed `.crbm` index) are cached at once\n * (default 1024) — a memory bound for a long-running server (gap #1). Past it, the least-recently-used\n * segment's reader is evicted; the next read of an evicted segment re-opens it (one cheap tail GET, since\n * generations are immutable). Raise it for a big hot working set of small segments.\n */\n readonly maxOpenSegments?: number;\n /**\n * Aggregate byte ceiling on the parsed `.crbm` indices resident in the reader cache (default 64 MiB) — the\n * **second half of the gap #1 fix**. `maxOpenSegments` alone bounds by *count*, but a wide/dense segment's\n * parsed index can be several MB, so 1024 wide indices could pin ~GBs and blow a small heap (e.g. a 128 MB\n * Lambda) while the count is nominally \"in bounds\". This caps the summed {@link CrbmReader.retainedIndexBytes}\n * across cached readers; the least-recently-used reader is evicted once the total would exceed it — whichever\n * of the count/byte bounds binds first. Lower it for memory-tight deployments with wide segments; a single\n * segment whose index alone exceeds the budget is still cached (it can't be shrunk) but nothing else alongside.\n */\n readonly maxOpenIndexBytes?: number;\n}\n\n/** Adapt one `(driver, key)` pair to the codec's `BlobReader` seam. */\nfunction coldBlobReader(driver: IColdDriver, key: GenKey): BlobReader {\n return {\n getRange(offset, length) {\n return driver.getRange(key, offset, length);\n },\n getTail(maxBytes) {\n return driver.getTail(key, maxBytes);\n },\n };\n}\n\n/** The generation target `resolveTarget` produces: which generation is current + its DEK wrappings (if encrypted). */\ntype Target = { generation: number; wrappedDeks?: readonly WrappedDek[] };\n\n/** A memoized per-segment reader plus the time it was installed, for the current-generation TTL refresh (gap #4). */\ninterface Snapshot {\n readonly reader: Promise<CrbmReader | null>;\n readonly installedAtMs: number;\n}\n\n/** Default TTL (ms) for re-resolving a segment's `currentGen` — the bound on post-compaction read staleness. */\nconst DEFAULT_CURRENT_GEN_TTL_MS = 2000;\n/**\n * How many buffered remainders bulk-load holds before flushing them into their chunk bitmaps. Bounds the\n * transient JS-side buffer to **~28 MB measured** irrespective of input size, while keeping batches large\n * enough that the per-id JS↔native crossing is amortised away.\n */\nconst BULK_FLUSH_IDS = 1 << 20;\n/**\n * Ids between ingest-loop yields. 16x coarser than the per-chunk cadence because the per-id work is ~40 ns\n * (a `splitId` and an array push) against ~1.3 µs per chunk — matching cadences would put the yield cost on the\n * wrong side of the work it interrupts. Sized against the *slowest* ingest, an in-memory async generator at\n * ~220 ns/id, so the resulting stretch stays a few ms there and well under 1 ms on a plain array.\n */\nconst YIELD_EVERY_IDS = 1 << 14;\n\n/** Default ceiling on cached segment readers (each holds a parsed `.crbm` index) — the steady-state count bound. */\nconst DEFAULT_MAX_OPEN_SEGMENTS = 1024;\n\n/** Default aggregate ceiling (bytes) on resident parsed indices in the reader cache — the steady-state byte bound. */\nconst DEFAULT_MAX_OPEN_INDEX_BYTES = 64 * 1024 * 1024;\n\nexport class CrbmColdChunkSource implements ColdChunkSource {\n /**\n * One resolved reader per segment, re-resolved on a short TTL ({@link CrbmColdChunkSourceOptions.currentGenTtlMs},\n * needs a clock). Within the TTL a segment's Cold bytes are treated as an immutable snapshot; when the TTL\n * elapses the next read cheaply re-resolves `currentGen` and, only if it advanced (a compaction committed),\n * opens the new generation — so a long-lived source observes new generations within the TTL rather than\n * pinning one forever (gap #4). The engine pairs this with a **generation-keyed** HOT cache so a bump never\n * serves a stale decoded chunk. Without a clock or a registry the source pins the first generation for its\n * lifetime (pre-Phase-B behaviour). A segment with no generation yet is not memoized, so it's re-checked until\n * one exists. **Bounded** by a {@link BoundedLru} ({@link CrbmColdChunkSourceOptions.maxOpenSegments}, default\n * 1024): past the ceiling the least-recently-used segment's reader (and its parsed index) is evicted — the\n * steady-state memory bound (gap #1); re-opening an evicted segment is one cheap tail GET.\n */\n private readonly snapshots: BoundedLru<string, Snapshot>;\n private readonly registry: IRegistryDriver | undefined;\n private readonly keystore: IKeystore | undefined;\n private readonly requireEncryption: boolean;\n private readonly readerOptions: CrbmReaderOptions;\n private readonly clock: Pick<Clock, 'now'> | undefined;\n private readonly currentGenTtlMs: number;\n\n constructor(\n private readonly driver: IColdDriver,\n options: CrbmColdChunkSourceOptions = {},\n ) {\n if (!driver.capabilities().rangeRead) {\n throw new CapabilityError('Cold driver must support range reads (rangeRead)');\n }\n const {\n registry,\n keystore,\n requireEncryption,\n clock,\n currentGenTtlMs,\n maxOpenSegments,\n maxOpenIndexBytes,\n ...readerOptions\n } = options;\n if (keystore !== undefined && registry === undefined) {\n throw new CapabilityError(\n 'a keystore needs a registry (that is where wrapped DEKs are stored)',\n );\n }\n if (requireEncryption === true && registry === undefined) {\n // Without a registry the source can't see wrapped DEKs or `destroyed` tombstones (it list-scans cold),\n // so encryption can't be enforced or even observed here — fail fast rather than mislead.\n throw new CapabilityError('requireEncryption needs a registry');\n }\n this.registry = registry;\n this.keystore = keystore;\n this.requireEncryption = requireEncryption ?? false;\n this.readerOptions = readerOptions;\n this.clock = clock;\n this.currentGenTtlMs = currentGenTtlMs ?? DEFAULT_CURRENT_GEN_TTL_MS;\n // Bound the reader cache by BOTH count and aggregate parsed-index bytes (gap #1). No TTL on the LRU itself —\n // the currentGen TTL is handled separately via each snapshot's `installedAtMs`; these ceilings only bound how\n // many segment readers/indices stay resident. Each reader's byte weight is reported once it resolves (below).\n // The cache never compares against wall-clock, so a zero clock is fine when none is injected.\n this.snapshots = new BoundedLru<string, Snapshot>({\n maxEntries: maxOpenSegments ?? DEFAULT_MAX_OPEN_SEGMENTS,\n maxBytes: maxOpenIndexBytes ?? DEFAULT_MAX_OPEN_INDEX_BYTES,\n clock: clock ?? { now: () => 0 },\n });\n }\n\n /** The current resolved reader for a segment, refreshing on the TTL (gap #4). Cheap within the TTL window. */\n private resolvedReader(ref: SegmentRef): Promise<CrbmReader | null> {\n const key = segmentKey(ref);\n const existing = this.snapshots.get(key);\n if (existing === undefined) return this.install(key, this.resolveLatest(ref)).reader;\n if (!this.expired(existing.installedAtMs)) return existing.reader;\n // Expired: install the in-flight refresh **synchronously** (before any await) so concurrent readers in this\n // window coalesce onto the one re-resolve — ≤ one registry read + at most one reopen per segment per window\n // (no boundary thundering-herd). computeRefreshedReader reuses the prior reader unless the generation moved.\n return this.install(key, this.computeRefreshedReader(ref, existing)).reader;\n }\n\n /** TTL elapsed: cheaply re-resolve `currentGen`; reopen only if it actually changed, else reuse the prior reader. */\n private async computeRefreshedReader(\n ref: SegmentRef,\n existing: Snapshot,\n ): Promise<CrbmReader | null> {\n const current = await existing.reader.catch(() => null);\n let target: Target | null | undefined;\n try {\n target = await this.resolveTarget(ref);\n } catch {\n target = undefined; // transient resolve fault\n }\n // Transient resolve fault: keep serving the prior reader if it's alive; if it's dead (null/failed open),\n // reopen rather than re-arm a dead snapshot (else the segment reads empty for a whole TTL window).\n if (target === undefined) return current ?? this.resolveLatest(ref);\n if (target === null) return null; // segment gone / destroyed\n if (current !== null && target.generation === current.generation) return current; // unchanged — reuse\n return this.openForTarget(ref, target); // advanced / appeared / prior open was dead — reopen fresh\n }\n\n /**\n * Memoize a reader-promise as the segment's snapshot at `now()`, forgetting it later if it resolves to\n * null / throws (identity-guarded, so a stale cleanup never clobbers a fresher snapshot). Installing the\n * (pending) promise **synchronously** is what lets concurrent callers coalesce onto one in-flight resolve.\n */\n private install(key: string, reader: Promise<CrbmReader | null>): Snapshot {\n const snap: Snapshot = { reader, installedAtMs: this.now() };\n this.snapshots.set(key, snap);\n const forgetIfStale = (): void => {\n if (this.snapshots.get(key) === snap) this.snapshots.delete(key);\n };\n reader.then((r) => {\n if (r === null) {\n forgetIfStale();\n return;\n }\n // Report the parsed index's footprint so the cache can bound aggregate resident bytes (gap #1). Identity-\n // guarded via `peek` (no recency change) so a since-replaced snapshot doesn't mis-weight the fresh entry.\n if (this.snapshots.peek(key) === snap) this.snapshots.setWeight(key, r.retainedIndexBytes);\n }, forgetIfStale);\n return snap;\n }\n\n private now(): number {\n return this.clock ? this.clock.now() : 0;\n }\n\n private expired(installedAtMs: number): boolean {\n // Refresh needs a clock (the TTL) AND a registry (the *cheap* `currentGen` read the design assumes —\n // without one, re-resolution is a full cold `list`-scan, and a registry-less setup is single-process\n // local, not the separate-daemon Topology-B where stale reads arise). Otherwise: pin for the lifetime.\n return (\n this.clock !== undefined &&\n this.registry !== undefined &&\n this.currentGenTtlMs > 0 &&\n this.clock.now() - installedAtMs >= this.currentGenTtlMs\n );\n }\n\n /**\n * The segment's current generation number (gap #4) — the engine keys its HOT chunk cache by this so a\n * compaction bump is observed instead of serving a stale decoded chunk. Served from the (TTL-refreshed)\n * snapshot, so no extra backend read within the TTL window. `null` if the segment has no committed generation.\n */\n async currentGeneration(ref: SegmentRef): Promise<number | null> {\n const reader = await this.resolvedReader(ref);\n return reader?.generation ?? null;\n }\n\n private async resolveLatest(ref: SegmentRef): Promise<CrbmReader | null> {\n const target = await this.resolveTarget(ref);\n if (target === null) return null;\n return this.openForTarget(ref, target);\n }\n\n /** Open a {@link CrbmReader} for an already-resolved generation target (decrypting if the segment is encrypted). */\n private async openForTarget(ref: SegmentRef, target: Target): Promise<CrbmReader | null> {\n const genKey: GenKey = {\n namespace: ref.namespace,\n segment: ref.segment,\n generation: target.generation,\n };\n const crypto = await this.cryptoForRead(ref, target.generation, target.wrappedDeks);\n return CrbmReader.open(coldBlobReader(this.driver, genKey), { ...this.readerOptions, crypto });\n }\n\n /**\n * The current generation + its DEK wrappings: the registry's authoritative record (one strong read), or a\n * `list` scan for the max generation when there's no registry (a registry-less source can only read cleartext\n * — there's nowhere a wrapped DEK could live).\n */\n private async resolveTarget(ref: SegmentRef): Promise<Target | null> {\n if (this.registry !== undefined) {\n const record = await this.registry.get(ref);\n if (record === null) return null;\n // A crypto-shredded segment reads as empty — its DEK is gone, so its Cold bytes are unrecoverable.\n if (record.status === 'destroyed') return null;\n return { generation: record.currentGen, wrappedDeks: record.wrappedDeks };\n }\n let maxGen = -1;\n for await (const key of this.driver.list(ref)) {\n if (key.generation > maxGen) maxGen = key.generation;\n }\n return maxGen < 0 ? null : { generation: maxGen };\n }\n\n /** Build the per-generation decryption context for an encrypted segment (undefined for cleartext). */\n private async cryptoForRead(\n ref: SegmentRef,\n generation: number,\n wrappedDeks: readonly WrappedDek[] | undefined,\n ): Promise<CrbmCrypto | undefined> {\n if (wrappedDeks === undefined || wrappedDeks.length === 0) {\n if (this.requireEncryption) {\n throw new KeyUnavailableError(\n `requireEncryption: segment \"${ref.segment}\" is cleartext but encryption is required`,\n );\n }\n return undefined; // cleartext segment\n }\n if (this.keystore === undefined) {\n throw new KeyUnavailableError(\n `segment \"${ref.segment}\" is encrypted but this CrbmColdChunkSource has no keystore`,\n );\n }\n const aead = await this.keystore.openDek(wrappedDeks);\n return { aead, aadFor: (scope) => aadFor(ref, generation, scope) };\n }\n\n async getChunk(ref: ChunkRef): Promise<Uint8Array | null> {\n validateChunkRef(ref);\n return this.withFreshSnapshot(ref, (reader) => reader.getChunk(ref.chunkKey), null);\n }\n\n async listChunkKeys(ref: SegmentRef): Promise<number[]> {\n validateSegmentRef(ref);\n return this.withFreshSnapshot(ref, (reader) => reader.chunkKeys(), []);\n }\n\n async sizeOf(ref: SegmentRef): Promise<SegmentSize | null> {\n validateSegmentRef(ref);\n return this.withFreshSnapshot<SegmentSize | null>(\n ref,\n (reader) => ({ sizeBytes: reader.sizeBytes }),\n null,\n );\n }\n\n async cardinalities(ref: SegmentRef): Promise<ReadonlyMap<number, number> | null> {\n validateSegmentRef(ref);\n return this.withFreshSnapshot<ReadonlyMap<number, number> | null>(\n ref,\n (reader) => reader.cardinalities(),\n null,\n );\n }\n\n /**\n * Run `read` against the pinned snapshot, healing the one torn-read window compaction's GC can open: if the\n * generation we pinned was superseded *and* swept (the grace window elapsed) mid-read, the Cold driver throws\n * {@link NotFoundError}. Rather than surface that as a query failure (**I5**), we drop the stale snapshot,\n * re-resolve `currentGen`, and retry once — the read then serves the newer (committed, immutable) generation,\n * a monotonic move forward. A *second* NotFound is pathological (GC outrunning resolution) and propagates\n * rather than fabricate an absent answer — never return a wrong result. `ifGone` is returned only when the\n * segment legitimately has no committed generation at all (cold is empty). The single retry is bounded.\n */\n private async withFreshSnapshot<T>(\n ref: SegmentRef,\n read: (reader: CrbmReader) => T | Promise<T>,\n ifGone: T,\n ): Promise<T> {\n const key = segmentKey(ref);\n for (let attempt = 0; attempt < 2; attempt++) {\n const pending = this.resolvedReader(ref);\n const reader = await pending;\n if (reader === null) return ifGone;\n try {\n return await read(reader);\n } catch (err) {\n // Only a vanished pinned generation is recoverable here, and only on the first try; anything else\n // (corruption, a real second miss) propagates / falls through.\n if (!isNotFoundError(err) || attempt === 1) throw err;\n // Force re-resolution to the current generation — but only evict the exact stale snapshot we just read\n // from (matched by its reader promise), so we don't clobber a fresher one a concurrent call installed.\n const cur = this.snapshots.get(key);\n if (cur !== undefined && cur.reader === pending) this.snapshots.delete(key);\n }\n }\n return ifGone;\n }\n}\n\n/**\n * Write one immutable generation from in-memory bitmaps (the seed / bulk-load primitive). Chunks are\n * sorted ascending and empty bitmaps skipped (empty chunks are never stored). Returns the driver's\n * `{ size, sha256 }` for the written object. Pass `options.crypto` to AES-256-GCM-encrypt the generation\n * (the caller builds it from the segment's DEK + a `(segment, generation)`-bound {@link aadFor}).\n */\nexport function writeCrbmGeneration(\n driver: IColdDriver,\n key: GenKey,\n chunks: Iterable<{ chunkKey: number; bitmap: CodecBitmap }>,\n options: { crypto?: CrbmCrypto; clock?: Yielder } = {},\n): Promise<{ size: number; sha256: string }> {\n const sorted = [...chunks].sort((a, b) => a.chunkKey - b.chunkKey);\n // The single longest blocking stretch in a bulk load: serialize + CRC32C + frame, once per chunk, ~62,000\n // times. `await writer.addChunk(...)` looks like it yields and does not — the sink buffers in memory, so the\n // promise is already resolved and awaiting it is a microtask. See {@link yieldEvery}.\n const tick = yieldEvery(options.clock);\n return driver.putImmutable(key, async (sink) => {\n const writer = new CrbmWriter(sink, { generation: key.generation, crypto: options.crypto });\n for (const { chunkKey, bitmap } of sorted) {\n if (bitmap.isEmpty) continue;\n // Run-encode before serializing. Cold generations are immutable and read many times, so the one-off cost\n // here buys every later read a smaller fetch — see CodecBitmap.optimize for the measured factors and for\n // why the per-operation warm path does not do this.\n bitmap.optimize?.();\n await writer.addChunk(chunkKey, bitmap.serialize(), bitmap.size);\n const pause = tick();\n if (pause !== null) await pause;\n }\n await writer.finish();\n });\n}\n\n/** What {@link writeCrbmGenerationStream} wrote: the driver's `{ size, sha256 }` + a tally of the generation. */\nexport interface StreamWriteResult {\n readonly size: number;\n readonly sha256: string;\n /** Non-empty chunk keys written, in ascending order (for the compaction verify, since the stream is consumed). */\n readonly chunkKeys: number[];\n /** Total ids written. */\n readonly cardinality: number;\n}\n\n/**\n * Streaming variant of {@link writeCrbmGeneration} for **constant-memory** compaction (Phase 4f): consumes an\n * **already-ascending** async stream of `{ chunkKey, bitmap }`, feeding each to the codec and freeing it,\n * instead of materializing the whole generation. Paired with a streaming cold sink (S3 multipart / LocalFs temp\n * file), peak memory is ~one chunk + one part. Returns a tally so the caller can verify the re-opened object\n * without re-iterating the (now-consumed) stream. Input **must** be ascending by `chunkKey` — the codec rejects\n * an out-of-order chunk; empty bitmaps are skipped.\n */\nexport async function writeCrbmGenerationStream(\n driver: IColdDriver,\n key: GenKey,\n chunks: AsyncIterable<{ chunkKey: number; bitmap: CodecBitmap }>,\n options: { crypto?: CrbmCrypto; clock?: Yielder } = {},\n): Promise<StreamWriteResult> {\n const chunkKeys: number[] = [];\n let cardinality = 0;\n // Compaction runs this over a whole segment. The `for await` is not itself a yield — a stream backed by\n // already-resident chunks resolves on a microtask — so it needs the same periodic macrotask as the\n // non-streaming writer above.\n const tick = yieldEvery(options.clock);\n const { size, sha256 } = await driver.putImmutable(key, async (sink) => {\n const writer = new CrbmWriter(sink, { generation: key.generation, crypto: options.crypto });\n for await (const { chunkKey, bitmap } of chunks) {\n if (bitmap.isEmpty) continue;\n bitmap.optimize?.(); // same cold-write rationale as the non-streaming writer above\n await writer.addChunk(chunkKey, bitmap.serialize(), bitmap.size);\n chunkKeys.push(chunkKey);\n cardinality += bitmap.size;\n const pause = tick();\n if (pause !== null) await pause;\n }\n await writer.finish();\n });\n return { size, sha256, chunkKeys, cardinality };\n}\n\n/**\n * Point a segment's registry `currentGen` at `key.generation` — the publish step that makes a freshly-written\n * generation the authoritative latest (so registry-aware readers see it). **Forward-only and idempotent:**\n * if the registry has no row it creates one; if it's already at/ahead of `key.generation` it's a no-op (an\n * out-of-order/duplicate publish never regresses the pointer); otherwise it advances via compare-and-swap,\n * retrying a few times under contention. Separated from the Cold write so callers can publish atomically\n * after the immutable object is durable (write-then-publish).\n */\nexport async function publishGeneration(\n registry: IRegistryDriver,\n key: GenKey,\n options: { wrappedDeks?: readonly WrappedDek[] } = {},\n): Promise<boolean> {\n for (let attempt = 0; attempt < 5; attempt++) {\n const record = await registry.get(key);\n try {\n if (record === null) {\n // First publish for the segment — carry the wrapped DEK(s) so encrypted reads can resolve the key.\n await registry.create(key, {\n currentGen: key.generation,\n wrappedDeks: options.wrappedDeks,\n });\n } else if (record.status === 'destroyed') {\n // Closes the window between a writer's own destroyed-check and its publish.\n //\n // `bulkLoadCrbmGeneration` reads the registry record once, refuses if it is already destroyed, and then\n // spends a KMS call plus a whole object write before getting here — seconds to minutes on a large load.\n // A `destroySegment` landing inside that window used to be invisible to this function: it compares only\n // `currentGen`, so it would advance the pointer on a destroyed record, leaving an object encrypted with\n // the DEK that destroy had just shredded — permanently unreadable, still paid for, and attached to a\n // segment the registry says was erased.\n //\n // Checking here rather than at the caller is what makes it a fence instead of a second guess: this\n // record was re-read moments ago inside the retry loop, so the check and the CAS that follows it see the\n // same state. `erasure.ts` notes that coupling the write path to destruction was left as \"a later\n // hardening\" — for the publish step, this is it.\n throw new ValidationError(\n `segment \"${key.segment}\" was destroyed (crypto-shredded) while generation ${key.generation} was ` +\n `being written — refusing to publish it; the written object is unreadable. Use a new segment.`,\n );\n } else if (record.currentGen > key.generation) {\n return false; // a newer generation is already current — forward-only, never regress\n } else if (record.currentGen === key.generation) {\n return true; // already exactly current (an idempotent re-publish) — nothing to advance\n } else {\n await registry.compareAndSwap(key, record.token, { currentGen: key.generation });\n }\n return true; // created or advanced the pointer to key.generation → it is now current\n } catch (err) {\n if (isWriteConflictError(err)) continue; // lost the race — re-read and retry\n throw err;\n }\n }\n // Exhausted: only possible if competing writers kept advancing currentGen — which likely already satisfies\n // the forward-only goal. Confirm before reporting failure, so a lost-every-race-but-already-current case\n // isn't a spurious error. Whether *this* generation is the current one decides the returned flag.\n const final = await registry.get(key);\n if (final !== null && final.currentGen >= key.generation)\n return final.currentGen === key.generation;\n throw new WriteConflictError(\n `publishGeneration: contention setting currentGen for ${key.segment}`,\n );\n}\n\n/** What a bulk-load wrote — the driver's `{ size, sha256 }` plus a summary of the built generation. */\nexport interface BulkLoadResult {\n /** Bytes written to the Cold object. */\n readonly size: number;\n /** The driver's content hash of the object. */\n readonly sha256: string;\n /** Distinct non-empty chunks written (≤ 65536). */\n readonly chunkCount: number;\n /** Total distinct ids in the generation (post-dedup). */\n readonly cardinality: number;\n}\n\n/**\n * **Bulk-load** a whole immutable generation from a flat id source — the batch \"seed/rebuild\" entry point.\n * Unlike {@link writeCrbmGeneration} (which takes pre-grouped bitmaps), this\n * consumes an arbitrary, **unsorted** stream of u32 ids (sync or async) and routes each into its chunk's\n * Roaring bitmap as it goes. The input is consumed lazily and ids dedup on insert, so memory is bounded by\n * the **built generation** — the in-memory Roaring representation of the *distinct* set (≤ one bitmap per\n * non-empty chunk) — not by the input length: you can stream a billion duplicate-heavy ids and hold only the\n * distinct result. Note this is `O(distinct set)`, **not** window-bounded like {@link SegmentEngine.intersect}:\n * bulk-load holds the whole generation in RAM, which suits batch seed/rebuild jobs but not an\n * unbounded-cardinality stream (a segment larger than RAM needs external-merge / pre-sorted input — later phase).\n *\n * Each id must be an integer in `[0, 2³²)` ({@link splitId} throws {@link ValidationError} otherwise) — the\n * source is consumed lazily, so a bad id aborts mid-stream without writing a partial object (the driver\n * commits only after the callback resolves). An empty source writes a valid empty generation.\n *\n * Writing a fresh full snapshot of a segment; merging a new delta into the *existing* Cold (compaction) is\n * Phase 4. The caller picks the generation number in `key` and a `ColdChunkSource` serves the **highest**, so\n * pick a known-fresh number (on an empty segment, `0`): a too-high number silently shadows real data, and\n * re-using an existing generation throws {@link WriteConflictError} (write-once). Registry-assigned\n * generations arrive in Phase 4.\n */\nexport async function bulkLoadCrbmGeneration(\n driver: IColdDriver,\n key: GenKey,\n ids: Iterable<number> | AsyncIterable<number>,\n options: {\n registry?: IRegistryDriver;\n keystore?: IKeystore;\n requireEncryption?: boolean;\n audit?: IAuditSink;\n /** Bitmap codec. Optional in the type; a **flavor** package binds it ({@link requireCodec}). */\n codec?: CodecInterface;\n /**\n * Injected clock. Supplying one makes bulk-load **cooperative**: it yields the event loop periodically so a\n * long load does not stall everything else on the process. Without it the load still completes, just\n * without yielding — which is the pre-existing behaviour, kept so this is purely additive.\n *\n * `@cloudbitmaps/roaring` supplies a real clock by default, so flavor users get cooperative behaviour with\n * no wiring. `core/` cannot default it: it is timer-free by lint, which is exactly why waiting goes through\n * this seam rather than `setTimeout`.\n */\n clock?: Clock;\n } = {},\n): Promise<BulkLoadResult> {\n if (options.keystore === undefined && options.requireEncryption === true) {\n throw new ValidationError('requireEncryption: bulk-load needs a keystore to write encrypted');\n }\n const codec = requireCodec(options.codec, 'bulkLoadCrbmGeneration');\n const byChunk = new Map<number, CodecBitmap>();\n // Batched per chunk, not one native `add()` per id.\n //\n // The obvious loop — `bitmap.add(remainder)` for every id — crosses the JS↔native boundary once per id, and\n // measured **1,679 ms for 1M ids** with no yield point anywhere in it. Since this is a synchronous stretch on\n // Node's only thread, a caller who wires it to a request handler stalls every other request on that instance\n // for over a second (measured separately: a 0.7 ms health check took 275 ms).\n //\n // Buffering the remainders and inserting them per chunk in one `fromValues`/`addMany` call amortises that\n // boundary crossing across the whole batch.\n //\n // WHY THE BUFFER IS CAPPED. Bucketing *everything* first and inserting once per chunk at the end is faster\n // still, but it holds every remainder as a JS number before any bitmap compression happens — and with up to\n // 65,536 chunks in play that is unbounded in exactly the way this library refuses to be. So the buffer is\n // flushed whenever the total pending count crosses `BULK_FLUSH_IDS`, bounding the extra memory regardless of\n // input size or key distribution while still getting the batching win. That bound is **~28 MB measured** at\n // 1M staged ids across ~65,000 chunks — not the ~8 MB a naive 8-bytes-per-number estimate gives, because the\n // cost is dominated by per-array and Map overhead across tens of thousands of small arrays.\n const pendingByChunk = new Map<number, number[]>();\n let pending = 0;\n // Yield periodically, NOT per chunk — see {@link yieldEvery} for why per-unit async is a 7x regression here.\n const tickChunk = yieldEvery(options.clock);\n const tickId = yieldEvery(options.clock, YIELD_EVERY_IDS);\n // Yield every N chunks, NOT per chunk. Measured: handing each chunk's insert to the threadpool\n // (`fromArrayAsync`) costs ~9 µs of dispatch against ~1.5 µs of actual work once ids are spread across\n // ~61,000 chunks — 636 ms versus 92 ms, a 7x regression that would have undone the per-chunk batching this\n // function already does. Keeping the inserts synchronous and interrupting them periodically gets the\n // starvation fix without the cost — measured on the per-chunk insert microbenchmark: 88 ms wall against a\n // 92 ms unyielded baseline. The whole-load end-to-end figures are a DIFFERENT experiment and live in\n // `cooperative.ts`; an earlier version of this comment spliced the two, pairing a 92 ms operation with\n // 819 ms of starvation, which is impossible on its face.\n //\n // The yield must be a REAL macrotask. `await Promise.resolve()` is a microtask and never lets I/O run, which\n // is the trap that makes naive \"just await something\" fixes measure as no change at all.\n const flushPending = async (): Promise<void> => {\n for (const [chunkKey, rems] of pendingByChunk) {\n if (rems.length === 0) continue;\n const existingBitmap = byChunk.get(chunkKey);\n if (existingBitmap === undefined) byChunk.set(chunkKey, codec.fromValues(rems));\n else existingBitmap.addMany(rems);\n rems.length = 0;\n const pause = tickChunk();\n if (pause !== null) await pause;\n }\n pending = 0;\n };\n /** Bucket one id. Returns true when the pending buffer is full and must be flushed. */\n const ingest = (id: number): boolean => {\n const { chunkKey, remainder } = splitId(id); // validates the u32 range\n let bucket = pendingByChunk.get(chunkKey);\n if (bucket === undefined) {\n bucket = [];\n pendingByChunk.set(chunkKey, bucket);\n }\n bucket.push(remainder);\n return ++pending >= BULK_FLUSH_IDS;\n };\n // The two ingest loops are deliberately NOT collapsed into one `for await` over a normalising wrapper.\n //\n // That is the tidier code and it was measured at **20x** the cost: routing a sync source through an async\n // generator forces a microtask per id, and over 1M ids that is 224 ms against 11 ms for a plain `for..of` —\n // 55% of a whole bulk load spent on iteration protocol rather than on work. Since an array, a Set and a\n // generator are what callers actually hand this function most of the time, the sync path is the common one.\n //\n // Note that `for await` yields nothing to the event loop either way: a microtask per id still drains before\n // the loop turns a phase. Both paths therefore need the same explicit yield.\n if (Symbol.asyncIterator in ids) {\n for await (const id of ids as AsyncIterable<number>) {\n if (ingest(id)) await flushPending();\n const pause = tickId();\n if (pause !== null) await pause;\n }\n } else {\n for (const id of ids as Iterable<number>) {\n if (ingest(id)) await flushPending();\n const pause = tickId();\n if (pause !== null) await pause;\n }\n }\n await flushPending();\n\n let cardinality = 0;\n const chunks: Array<{ chunkKey: number; bitmap: CodecBitmap }> = [];\n for (const [chunkKey, bitmap] of byChunk) {\n // Every chunk in the map received at least one id, so no bitmap here is empty.\n cardinality += bitmap.size; // a native call per chunk — 5 ms across 62,000 of them, so it yields too\n chunks.push({ chunkKey, bitmap });\n const pause = tickChunk();\n if (pause !== null) await pause;\n }\n\n if (options.keystore !== undefined && options.registry === undefined) {\n throw new ValidationError('bulk-load encryption requires a registry to store the wrapped DEK');\n }\n // Read the segment's record once (when a registry is wired): to refuse writing to a crypto-shredded segment\n // (which would create unreadable/unreachable bytes), and to reuse its DEK if it's encrypted.\n const existing = options.registry !== undefined ? await options.registry.get(key) : null;\n if (existing?.status === 'destroyed') {\n throw new ValidationError(\n `segment \"${key.segment}\" is destroyed (crypto-shredded) — refusing to write; use a new segment`,\n );\n }\n\n // Encryption (opt-in): reuse the segment's existing DEK, or mint a fresh one on first write.\n let crypto: CrbmCrypto | undefined;\n let newWrapped: readonly WrappedDek[] | undefined;\n if (options.keystore !== undefined) {\n if (existing?.wrappedDeks !== undefined && existing.wrappedDeks.length > 0) {\n const aead = await options.keystore.openDek(existing.wrappedDeks); // reuse the segment's DEK\n crypto = { aead, aadFor: (scope) => aadFor(key, key.generation, scope) };\n } else {\n const minted = await options.keystore.createDek();\n newWrapped = minted.wrapped;\n crypto = { aead: minted.aead, aadFor: (scope) => aadFor(key, key.generation, scope) };\n }\n }\n\n const { size, sha256 } = await writeCrbmGeneration(driver, key, chunks, {\n crypto,\n clock: options.clock,\n });\n // Publish only after the immutable object is durable (write-then-publish): a registry-aware reader should\n // never point at a generation that isn't fully written. A freshly minted DEK is stored on this publish.\n if (options.registry !== undefined) {\n const becameCurrent = await publishGeneration(options.registry, key, {\n wrappedDeks: newWrapped,\n });\n // Audit the publish only when this generation actually *became* the current one — not when a\n // forward-only publish no-oped because a newer generation was already current (the event's contract is\n // \"became the segment's current generation\"). Needs a registry to have a \"current generation\" at all.\n if (becameCurrent) {\n safeAudit(options.audit ?? NOOP_AUDIT).onEvent({\n kind: 'segment.publish',\n namespace: key.namespace,\n segment: key.segment,\n generation: key.generation,\n });\n }\n }\n return { size, sha256, chunkCount: chunks.length, cardinality };\n}\n","/**\n * Crash-safe compaction — the 2-phase commit that folds Warm deltas into a fresh immutable Cold generation\n * (invariants I3/I4/I5).\n *\n * Memory (Phase 4f): a generation is merged **and written as a stream** — {@link mergeChunksStream} yields one\n * merged chunk at a time and {@link writeCrbmGenerationStream} feeds each to a streaming cold sink (S3 multipart\n * / LocalFs temp file), freeing it. The cold generation is merged and written as a stream, so peak COLD-side\n * memory is ~one chunk + one upload part + the cold reader's index. Caveat: `collectDirty` first materializes\n * the whole dirty Warm delta set in memory, so total peak also scales with the dirty-warm working set (up to a\n * whole segment for an all-warm/never-compacted segment) — pinning only `{chunkKey,token}` + lazy re-read is a\n * deferred fix (gap #12).\n *\n * The algorithm, per chunk: `newCold(k) = (cold_g(k) ∪ adds(k)) \\ removes(k)` — exactly the read-time\n * effective set ({@link effective}), so the segment's visible set is unchanged (**I3**). Steps:\n *\n * 1. LEASE acquire the per-segment compaction lease (status→compacting; steal an expired one)\n * 2. PIN g := registry.currentGen; archive each dirty chunk's OCC token (`v_archived`)\n * 3. RECONCILE delete orphan Cold generations > g (a crashed prior stage), safe under the lease\n * 4. MERGE build gen g+1: dirty chunks merged, clean chunks copied through\n * 5. STAGE write segment.<g+1>.crbm (immutable, write-once)\n * 6. VERIFY re-open it; its chunk-key set + footer cardinality must equal the merge (+ the codec's CRC checks)\n * 7. SWAP registry.currentGen := g+1, release the lease — CONDITIONAL on the lease token (atomic commit)\n * 8. PURGE delete each archived Warm row CONDITIONAL on token == v_archived (a write after the scan has a\n * newer token → its purge fails → it survives into the next dirty set: **no lost writes, I4**)\n *\n * **Correctness without a lock:** the commit is the conditional `currentGen` swap; write-once generations +\n * version-fenced purge make even two concurrent compactions safe (the loser's staged generation is an orphan\n * GC'd later; no torn read — readers are pinned to a committed generation, **I5**). The lease only avoids that\n * wasted duplicate work.\n *\n * Pure orchestration over the injected driver interfaces + an injected {@link Clock} (timer-free; the daemon\n * layer owns scheduling/heartbeat). A crash at *any* step is recoverable: nothing is destructive until after\n * the commit, and the swap is atomic.\n */\nimport { type IAuditSink, NOOP_AUDIT, safeAudit } from './audit';\nimport type { CodecBitmap, CodecInterface } from './codec';\nimport { requireCodec } from './codec';\nimport { decodeDelta, effective, emptyDelta } from './chunk';\nimport type { ChunkDelta } from './chunk';\nimport type { BlobReader } from './blob';\nimport type { Yielder } from './cooperative';\nimport type { Clock } from './determinism';\nimport type { IMetricsSink } from './metrics';\nimport {\n KeyUnavailableError,\n ValidationError,\n WriteConflictError,\n isWriteConflictError,\n} from './errors';\nimport { segmentKey } from './keys';\nimport { aadFor } from './crypto';\nimport type { Aead, CrbmCrypto, IKeystore, WrappedDek } from './crypto';\nimport { writeCrbmGenerationStream } from './crbm-cold-source';\nimport { CrbmReader } from './crbm/reader';\nimport type {\n ChunkRef,\n GenKey,\n IColdDriver,\n IRegistryDriver,\n IWarmDriver,\n SegmentRef,\n Token,\n} from './ports';\n\nconst DEFAULT_MAX_BITMAP_BYTES = 1 << 20;\n/** Default compaction-lease duration. Generous: a compaction longer than this risks being stolen (safe — the\n * commit is fenced on the lease token — but wasteful). The daemon layer can renew (heartbeat) for big segments. */\nconst DEFAULT_LEASE_MS = 60_000;\n/** Default consecutive-failure count at/after which discovery quarantines (skips) a poison segment (gap #2). */\nconst DEFAULT_QUARANTINE_THRESHOLD = 5;\n/** Default cooldown before a quarantined segment is retried once, so a transient fault can self-heal (gap #2). */\nconst DEFAULT_QUARANTINE_COOLDOWN_MS = 5 * 60_000;\n\nexport interface CompactionDeps {\n readonly cold: IColdDriver;\n readonly warm: IWarmDriver;\n readonly registry: IRegistryDriver;\n /**\n * Injected time source for lease expiry (the determinism seam — `core/` never reads ambient time).\n *\n * `now` is required; `sleep`/`yieldNow` are **optional and used only for cooperative yielding** while writing\n * a generation. Supplying a full {@link Clock} (the facade does) makes compaction hand the event loop back\n * periodically instead of blocking it for the whole write; supplying a bare `{ now }` keeps the previous\n * uninterrupted behaviour. Optional rather than required because every existing caller passes `{ now }`, and\n * requiring more would be a breaking change — the reason the yield below shipped unreachable the first time.\n */\n readonly clock: Pick<Clock, 'now'> & Partial<Pick<Clock, 'sleep' | 'yieldNow'>>;\n readonly maxBitmapBytes?: number;\n /**\n * Bitmap codec — compaction only merges bitmaps through it. Optional in the type so this\n * stays call-compatible public API; a **flavor** package binds it (see {@link requireCodec}).\n */\n readonly codec?: CodecInterface;\n /**\n * Keystore for **encrypted** segments (Phase 4e). An encrypted segment (its registry record carries wrapped\n * DEK(s)) reuses that same DEK: compaction unwraps it to decrypt the old generation and encrypt the new one.\n * A bootstrap (gen 0) with a keystore mints a fresh DEK. Compacting an encrypted segment without a keystore\n * throws {@link KeyUnavailableError}. Absent ⇒ cleartext compaction (unless {@link requireEncryption}).\n */\n readonly keystore?: IKeystore;\n /** When true, refuse to write a cleartext generation — a segment without a keystore-backed DEK throws. */\n readonly requireEncryption?: boolean;\n /**\n * Optional observability sink (Phase D, gap #2). `compactSegment` emits one `compaction` event per attempt\n * (committed or not, timed). Assumed exception-safe (the `CloudRoaring` facade wraps the user sink); the emit\n * is additionally guarded so a throwing sink can never break compaction. Absent ⇒ no emission.\n */\n readonly metrics?: IMetricsSink;\n}\n\nexport interface CompactionOptions {\n /** Opaque id of this worker — the lease owner (e.g. `host:pid:uuid`). Required so a steal is attributable. */\n readonly owner: string;\n /** Lease duration in ms (default 60s). */\n readonly leaseMs?: number;\n /**\n * Optional audit sink (Phase 5d). A `segment.compact` event is emitted once per **committed** generation\n * (never on a no-op/contention path). Exception-safe; the default records nothing.\n */\n readonly audit?: IAuditSink;\n}\n\nexport interface CompactionResult {\n readonly segment: string;\n readonly namespace?: string;\n /** True iff a new generation was committed. */\n readonly compacted: boolean;\n /**\n * Why nothing was committed, when `compacted` is false: `'clean'` (no dirty rows), `'leased-by-other'`\n * (a live lease elsewhere), `'lease-lost'` (our lease was stolen before the commit — staged gen is an\n * orphan, no rows purged), `'superseded'` (a concurrent publish/bulk-load advanced `currentGen` past the\n * generation we pinned — we abort so RECONCILE never deletes the just-published generation; the next cycle\n * re-pins the new current gen; gap #5), `'bootstrap-raced'` (another worker wrote gen 0; our rows are left\n * for the next compaction), `'stage-conflict'` (a generation write-conflict we couldn't reconcile),\n * `'destroyed'` (the segment was crypto-shredded — terminal), or `'error'` (an isolated per-segment fault\n * recorded by {@link runCompactionCycle}).\n */\n readonly reason?: string;\n /** The fault message when `reason === 'error'` (a per-segment failure isolated by {@link runCompactionCycle}). */\n readonly error?: string;\n readonly fromGen: number | null;\n readonly toGen?: number;\n readonly dirtyChunks: number;\n /** Archived Warm rows actually purged (≤ dirtyChunks; the rest were rewritten post-scan and survive). */\n readonly purged: number;\n readonly survived: number;\n}\n\n/** A dirty chunk pinned at scan time: its merged delta + the OCC token to fence its purge against. */\ninterface PinnedChunk {\n readonly chunkKey: number;\n readonly delta: ChunkDelta;\n readonly token: Token;\n}\n\n/**\n * Fail fast on bad lease config at the boundary: an empty owner makes a lease steal unattributable, and a\n * non-positive/NaN leaseMs would produce a lease that's already expired (or never), silently defeating the\n * lease's whole job. Cheap to check once, up front, so a misconfigured daemon errors immediately. Exported so\n * callers that mutate **before** compacting (e.g. `CloudRoaring.eraseSubject`, which writes a `remove` tombstone\n * first) can validate the options up front rather than after the tombstone is written.\n */\nexport function validateCompactionOptions(options: CompactionOptions): void {\n if (typeof options.owner !== 'string' || options.owner.length === 0) {\n throw new ValidationError(\n 'compaction: options.owner must be a non-empty string (the lease owner id)',\n );\n }\n if (\n options.leaseMs !== undefined &&\n (!Number.isFinite(options.leaseMs) || options.leaseMs <= 0)\n ) {\n throw new ValidationError(\n `compaction: options.leaseMs must be a positive finite number; got ${options.leaseMs}`,\n );\n }\n}\n\n/**\n * Compact one segment. A no-op (returns `compacted: false`) if it has no dirty Warm rows or another worker\n * holds a live lease. Never throws on the normal contention/lease-loss paths — those are reported in `reason`.\n * Emits a `compaction` metric event per attempt (Phase D, gap #2) when a sink is wired, timing the attempt.\n */\nexport async function compactSegment(\n ref: SegmentRef,\n deps: CompactionDeps,\n options: CompactionOptions,\n): Promise<CompactionResult> {\n validateCompactionOptions(options);\n const startedAt = deps.clock.now();\n const emit = (\n r: Pick<CompactionResult, 'compacted' | 'reason' | 'dirtyChunks' | 'purged'>,\n ): void => {\n if (deps.metrics === undefined) return;\n try {\n deps.metrics.onEvent({\n kind: 'compaction',\n namespace: ref.namespace,\n segment: ref.segment,\n compacted: r.compacted,\n reason: r.reason,\n dirtyChunks: r.dirtyChunks,\n purged: r.purged,\n ms: Math.max(0, deps.clock.now() - startedAt),\n });\n } catch {\n /* metrics must never break compaction */\n }\n };\n try {\n const result = await compactSegmentInner(ref, deps, options);\n emit(result);\n return result;\n } catch (err) {\n // A genuine fault (non-contention) — surface it, but still record the attempt (reason 'error') so a\n // poison segment is visible; `runCompactionCycle` isolates it + bumps consecutiveFailures.\n emit({ compacted: false, reason: 'error', dirtyChunks: 0, purged: 0 });\n throw err;\n }\n}\n\nasync function compactSegmentInner(\n ref: SegmentRef,\n deps: CompactionDeps,\n options: CompactionOptions,\n): Promise<CompactionResult> {\n const now = (): number => deps.clock.now();\n const maxBytes = deps.maxBitmapBytes ?? DEFAULT_MAX_BITMAP_BYTES;\n const leaseMs = options.leaseMs ?? DEFAULT_LEASE_MS;\n const base = { segment: ref.segment, namespace: ref.namespace };\n const audit = safeAudit(options.audit ?? NOOP_AUDIT);\n // Emit the audit record the moment a generation is *durably committed* — before the (idempotent, fenced,\n // resumable-next-cycle) Warm purge, so a post-commit purge fault can never drop the compliance record for a\n // generation that is already the authoritative current one. Called only on the two committed paths.\n const auditCompacted = (generation: number): void =>\n audit.onEvent({\n kind: 'segment.compact',\n namespace: ref.namespace,\n segment: ref.segment,\n generation,\n });\n // The crypto context for one generation of this segment, given its DEK's AEAD (undefined ⇒ cleartext). The\n // AAD binds each chunk/index to (segment, generation), so reading gen g and writing gen g+1 use distinct\n // contexts over the same DEK.\n const cryptoAt = (aead: Aead | undefined, generation: number): CrbmCrypto | undefined =>\n aead === undefined ? undefined : { aead, aadFor: (scope) => aadFor(ref, generation, scope) };\n const record = await deps.registry.get(ref);\n\n // A crypto-shredded segment is terminal — never resurrect it by compacting (that would re-encrypt under a\n // DEK whose wrappings are gone, or re-acquire a lease on a `destroyed` row). Leave it as the tombstone it is.\n if (record !== null && record.status === 'destroyed') {\n return {\n ...base,\n compacted: false,\n reason: 'destroyed',\n fromGen: record.currentGen,\n dirtyChunks: 0,\n purged: 0,\n survived: 0,\n };\n }\n\n // ── Bootstrap: a segment with no registry row (never compacted / bulk-loaded). No cold base, no lease\n // needed — the registry `create` is the exclusivity point. Two workers can race here, and gen 0 is\n // write-once, so at most one *writes* it; the other(s) only see a conflict. Critically, an adopter must NOT\n // purge its pinned Warm rows against a gen 0 it didn't write — that gen may not reflect them, which would be\n // a lost write (**I4**). So only the worker that actually wrote gen 0 purges; an adopter just ensures the\n // pointer exists and leaves its Warm rows for the next (normal) compaction to fold over the committed gen 0. ──\n if (record === null) {\n const pinned = await collectDirty(\n deps.warm,\n ref,\n maxBytes,\n requireCodec(deps.codec, 'compactSegment'),\n );\n if (pinned.length === 0)\n return {\n ...base,\n compacted: false,\n reason: 'clean',\n fromGen: null,\n dirtyChunks: 0,\n purged: 0,\n survived: 0,\n };\n // Encryption: mint a fresh per-segment DEK for gen 0 (or write cleartext). If we lose the gen-0 write race\n // our minted DEK is simply discarded — the winner's DEK (in the winning registry.create) is authoritative.\n let aead: Aead | undefined;\n let wrappedDeks: readonly WrappedDek[] | undefined;\n if (deps.keystore !== undefined) {\n const minted = await deps.keystore.createDek();\n aead = minted.aead;\n wrappedDeks = minted.wrapped;\n } else if (deps.requireEncryption === true) {\n throw new ValidationError(\n `requireEncryption: segment \"${ref.segment}\" needs a keystore to bootstrap encrypted`,\n );\n }\n const gen0: GenKey = { namespace: ref.namespace, segment: ref.segment, generation: 0 };\n const stream = mergeChunksStream(ref, null, pinned, deps, maxBytes, undefined);\n let wrote = true;\n let tally: { chunkKeys: number[]; cardinality: number } | undefined;\n try {\n tally = await writeCrbmGenerationStream(deps.cold, gen0, stream, {\n clock: deps.clock, // cooperative if the caller's clock can yield; a no-op if it only tells the time\n crypto: cryptoAt(aead, 0),\n });\n } catch (err) {\n // A concurrent bootstrap (or a crashed prior attempt) already wrote gen 0 — adopt it, don't fail.\n if (!isWriteConflictError(err)) throw err;\n wrote = false;\n }\n if (wrote && tally !== undefined) {\n await verifyGeneration(deps.cold, gen0, tally, cryptoAt(aead, 0)); // verify only bytes we wrote\n }\n try {\n await deps.registry.create(ref, {\n currentGen: 0,\n dirtyChunkCount: 0,\n status: 'active',\n wrappedDeks,\n });\n } catch (err) {\n if (!isWriteConflictError(err)) throw err; // a concurrent bootstrap published the pointer first\n }\n if (!wrote)\n // We adopted another worker's gen 0; our Warm rows may not be in it, so purging them could lose data.\n // Leave them — the next normal compaction merges them over the now-committed gen 0. No loss, no torn read.\n return {\n ...base,\n compacted: false,\n reason: 'bootstrap-raced',\n fromGen: null,\n dirtyChunks: pinned.length,\n purged: 0,\n survived: pinned.length,\n };\n auditCompacted(0); // gen 0 is now the committed current generation (write-once object + registry row)\n const { purged, survived } = await purgeAfterCommit(deps.warm, ref, pinned);\n return {\n ...base,\n compacted: true,\n fromGen: null,\n toGen: 0,\n dirtyChunks: pinned.length,\n purged,\n survived,\n };\n }\n\n // ── Normal path: acquire/steal the lease. ──\n const expired = record.leaseExpiresAt === undefined || record.leaseExpiresAt <= now();\n const ownedByOther =\n record.status === 'compacting' && !expired && record.leaseOwner !== options.owner;\n if (ownedByOther) {\n return {\n ...base,\n compacted: false,\n reason: 'leased-by-other',\n fromGen: record.currentGen,\n dirtyChunks: 0,\n purged: 0,\n survived: 0,\n };\n }\n let leaseToken: Token;\n try {\n const res = await deps.registry.compareAndSwap(ref, record.token, {\n status: 'compacting',\n leaseOwner: options.owner,\n leaseExpiresAt: now() + leaseMs,\n });\n leaseToken = res.token;\n } catch (err) {\n if (isWriteConflictError(err)) {\n return {\n ...base,\n compacted: false,\n reason: 'leased-by-other',\n fromGen: record.currentGen,\n dirtyChunks: 0,\n purged: 0,\n survived: 0,\n };\n }\n throw err;\n }\n\n const g = record.currentGen;\n try {\n // Resolve the segment's DEK first (encrypted segments reuse it across generations). Doing it BEFORE the\n // gap-#5 re-read keeps a potentially slow keystore/KMS `openDek` OUT of the fence window below. Inside the\n // try so a failure releases the lease; KeyUnavailableError here is a genuine fault (lost key) — it propagates.\n let aead: Aead | undefined;\n if (record.wrappedDeks !== undefined && record.wrappedDeks.length > 0) {\n if (deps.keystore === undefined) {\n throw new KeyUnavailableError(\n `segment \"${ref.segment}\" is encrypted but compaction has no keystore`,\n );\n }\n aead = await deps.keystore.openDek(record.wrappedDeks);\n } else if (deps.requireEncryption === true) {\n throw new ValidationError(`requireEncryption: segment \"${ref.segment}\" is cleartext`);\n }\n\n // Fence RECONCILE against a concurrent publish/bulk-load (gap #5). `publishGeneration` /\n // `bulkLoadCrbmGeneration` CAS on the *current* token, NOT the lease, so one can advance `currentGen`\n // past `g` after our pre-lease read. Re-read it now that we hold the lease: if it moved, our compaction\n // basis (g) is stale and RECONCILE (`deleteGenerationsAbove(g)`) would delete the just-published\n // generation. Abort cleanly (nothing destructive has run) and let the next cycle re-pin.\n //\n // This closes the publish-completed-before-RECONCILE window. RESIDUAL (deferred — only lease-aware\n // publishing, the heavier option (a), fully closes it): a publish that lands *during* the sweep below,\n // after this re-read, is not caught, and its blast radius is NOT merely \"a narrower lost update\" — if the\n // raced publish picks gen == g+1 it's a silent whole-generation lost update; if it picks gen > g+1 the\n // sweep deletes the object `currentGen` now points at, leaving a dangling pointer (reads AND the next\n // compaction both throw, with no self-heal). Self-healing recovery here is a known deferral.\n const live = await deps.registry.get(ref);\n if (live === null || live.currentGen !== g) {\n // Best-effort: in this very race the superseding publish already bumped the record's token, so this CAS\n // typically conflicts and no-ops (swallowed) — the lease then recovers via expiry/steal, not here.\n await releaseLease(deps, ref, leaseToken);\n return {\n ...base,\n compacted: false,\n reason: 'superseded',\n fromGen: g,\n dirtyChunks: 0,\n purged: 0,\n survived: 0,\n };\n }\n\n // RECONCILE: drop orphan generations > g (a crashed prior stage). Safe — we hold the lease (exclusive), `g`\n // was just re-confirmed current, and readers are pinned to a committed gen ≤ g, so nothing references a gen > g.\n await deleteGenerationsAbove(deps.cold, ref, g);\n\n const pinned = await collectDirty(\n deps.warm,\n ref,\n maxBytes,\n requireCodec(deps.codec, 'compactSegment'),\n );\n if (pinned.length === 0) {\n await releaseLease(deps, ref, leaseToken); // nothing to do — give the lease back\n return {\n ...base,\n compacted: false,\n reason: 'clean',\n fromGen: g,\n dirtyChunks: 0,\n purged: 0,\n survived: 0,\n };\n }\n\n const newGen = g + 1;\n // Read the old generation under its (gen g) crypto; stream-write the new one under its (gen g+1) crypto.\n const stream = mergeChunksStream(ref, g, pinned, deps, maxBytes, cryptoAt(aead, g));\n await stageGeneration(\n deps.cold,\n { namespace: ref.namespace, segment: ref.segment, generation: newGen },\n stream,\n cryptoAt(aead, newGen),\n deps.clock,\n );\n\n // SWAP (commit) — conditional on the lease token. If our lease was stolen/expired-and-taken, this fails and\n // we abort *before* purging: the staged generation becomes an orphan (GC'd later), and not one Warm row was\n // deleted, so there is no data loss. We must NOT release the lease here — it belongs to the thief now.\n try {\n await deps.registry.compareAndSwap(ref, leaseToken, {\n currentGen: newGen,\n status: 'active',\n leaseOwner: undefined,\n leaseExpiresAt: undefined,\n dirtyChunkCount: 0,\n lastCompactedAt: now(), // dead-man's-switch (gap #2): a stale value = a stuck segment\n consecutiveFailures: 0, // a successful commit clears any prior poison-quarantine streak\n });\n } catch (err) {\n if (isWriteConflictError(err)) {\n return {\n ...base,\n compacted: false,\n reason: 'lease-lost',\n fromGen: g,\n dirtyChunks: pinned.length,\n purged: 0,\n survived: 0,\n };\n }\n throw err;\n }\n\n // The conditional currentGen swap above is the atomic commit — audit here, before purge.\n auditCompacted(newGen);\n const { purged, survived } = await purgeAfterCommit(deps.warm, ref, pinned);\n return {\n ...base,\n compacted: true,\n fromGen: g,\n toGen: newGen,\n dirtyChunks: pinned.length,\n purged,\n survived,\n };\n } catch (err) {\n // Abnormal exit before the commit (corrupt Warm row, cold I/O fault, or a stage write-conflict): release\n // the lease so the segment isn't stuck `compacting` until expiry. A WriteConflict here is a staging\n // conflict (an orphan we couldn't reconcile) — report it cleanly; any other error is a genuine fault, so\n // propagate it for the caller to handle (`runCompactionCycle` isolates per-segment failures).\n await releaseLease(deps, ref, leaseToken).catch(() => undefined);\n if (isWriteConflictError(err)) {\n return {\n ...base,\n compacted: false,\n reason: 'stage-conflict',\n fromGen: g,\n dirtyChunks: 0,\n purged: 0,\n survived: 0,\n };\n }\n throw err;\n }\n}\n\n/**\n * Garbage-collect superseded Cold generations for a segment: everything strictly below `currentGen`, keeping\n * the most recent `keep` of them as a grace window for in-flight readers pinned to a just-superseded\n * generation (**I5**). Generations ≥ `currentGen` are never touched. Returns the generations deleted.\n *\n * **Except on a `destroyed` segment, where EVERY generation is garbage** and the grace window is meaningless.\n * A tombstoned segment resolves no generation at all, so no reader is or can become pinned to one; and nothing\n * else in the library would ever collect them — the reconcile path that deletes generations above `currentGen`\n * returns early on a destroyed row, so without this those objects are billed forever.\n *\n * That state is reachable in practice: a `dropSegment` whose Cold sweep threw part-way, or a compaction that was\n * already staging when the tombstone landed and finished writing its object afterwards. `dropSegment` re-sweeps\n * and reports whatever it could not reclaim in `generationsRemaining`, but a drop that was never re-run leaves a\n * residual, and this is what eventually collects it under a running daemon.\n */\nexport async function gcOrphanGenerations(\n ref: SegmentRef,\n deps: Pick<CompactionDeps, 'cold' | 'registry'>,\n options: { keep?: number } = {},\n): Promise<number[]> {\n const keep = Math.max(0, options.keep ?? 1);\n const record = await deps.registry.get(ref);\n if (record === null) return []; // no authoritative pointer → don't delete anything\n const current = record.currentGen;\n const gens: number[] = [];\n for await (const key of deps.cold.list(ref)) gens.push(key.generation);\n const toDelete =\n record.status === 'destroyed'\n ? gens.sort((a, b) => a - b) // all of it: no reader can be pinned to a tombstoned segment\n : // Delete generations below current, except the newest `keep` of them (the grace window).\n gens\n .filter((g) => g < current)\n .sort((a, b) => b - a) // newest-first\n .slice(keep);\n for (const generation of toDelete) {\n await deps.cold.delete({ namespace: ref.namespace, segment: ref.segment, generation });\n }\n return toDelete;\n}\n\n/** Collect + decode every live Warm row, pinning each chunk's OCC token for the fenced purge. */\nasync function collectDirty(\n warm: IWarmDriver,\n ref: SegmentRef,\n maxBytes: number,\n codec: CodecInterface,\n): Promise<PinnedChunk[]> {\n const out: PinnedChunk[] = [];\n for await (const row of warm.listChunks(ref)) {\n out.push({\n chunkKey: row.chunkKey,\n token: row.token,\n delta: decodeDelta(row.bytes, maxBytes, codec),\n });\n }\n return out;\n}\n\n/**\n * Yield the new generation's chunks **ascending**: dirty chunks merged `(cold ∪ adds) \\ removes`, clean chunks\n * copied through. An async generator so the writer streams them in constant memory (Phase 4f) — only one merged\n * chunk + the cold reader's index are live at a time, never the whole cold generation. (The pinned\n * Warm-delta map is still fully in memory — see the module caveat.)\n */\nasync function* mergeChunksStream(\n ref: SegmentRef,\n g: number | null,\n pinned: PinnedChunk[],\n deps: CompactionDeps,\n maxBytes: number,\n readCrypto: CrbmCrypto | undefined,\n): AsyncGenerator<{ chunkKey: number; bitmap: CodecBitmap }> {\n const codec = requireCodec(deps.codec, 'compactSegment');\n const dirty = new Map(pinned.map((p) => [p.chunkKey, p.delta]));\n const reader =\n g === null\n ? null\n : await openReader(\n deps.cold,\n { namespace: ref.namespace, segment: ref.segment, generation: g },\n readCrypto,\n );\n // The union of cold keys + dirty keys (a clean cold chunk is copied through unchanged), ascending.\n const keys = new Set<number>(dirty.keys());\n if (reader !== null) for (const k of reader.chunkKeys()) keys.add(k);\n\n for (const chunkKey of [...keys].sort((a, b) => a - b)) {\n const coldBytes = reader === null ? null : await reader.getChunk(chunkKey);\n const cold = coldBytes === null ? codec.empty() : codec.safeDeserialize(coldBytes, maxBytes);\n const merged = effective(cold, dirty.get(chunkKey) ?? emptyDelta(codec));\n if (!merged.isEmpty) yield { chunkKey, bitmap: merged };\n }\n}\n\n/** Stream-write the new generation (write-once), then re-open it to verify it round-trips what we merged. */\nasync function stageGeneration(\n cold: IColdDriver,\n key: GenKey,\n chunks: AsyncIterable<{ chunkKey: number; bitmap: CodecBitmap }>,\n crypto: CrbmCrypto | undefined,\n /** Threaded purely so the write can yield the event loop; see {@link CompactionDeps.clock}. */\n clock: Yielder | undefined,\n): Promise<void> {\n // The normal path deletes orphan generations > g first, so a write-conflict here is a real race (a\n // concurrent compaction beat us to this generation) — let it surface as the staging conflict it is.\n const tally = await writeCrbmGenerationStream(cold, key, chunks, { crypto, clock });\n await verifyGeneration(cold, key, tally, crypto);\n}\n\n/**\n * Re-open a freshly written generation and assert it round-trips exactly what we merged: same per-chunk key\n * set *and* same total cardinality (on top of the codec's own per-chunk CRC + footer checks). `expected` is the\n * streaming writer's tally (the stream is consumed, so we can't re-iterate it) — the key-set comparison catches\n * a dropped/extra chunk that a cardinality-only check could miss when two errors cancel out.\n */\nasync function verifyGeneration(\n cold: IColdDriver,\n key: GenKey,\n expected: { chunkKeys: number[]; cardinality: number },\n crypto: CrbmCrypto | undefined,\n): Promise<void> {\n const expectedCount = expected.cardinality;\n const expectedKeys = [...expected.chunkKeys].sort((a, b) => a - b);\n const reader = await openReader(cold, key, crypto);\n const actualKeys = [...reader.chunkKeys()].sort((a, b) => a - b);\n const keysMatch =\n actualKeys.length === expectedKeys.length && actualKeys.every((k, i) => k === expectedKeys[i]);\n if (!keysMatch) {\n throw new WriteConflictError(\n `compaction verify failed for ${key.segment}.${key.generation}: chunk-key set mismatch (${actualKeys.length} vs ${expectedKeys.length})`,\n );\n }\n if (reader.count() !== expectedCount) {\n throw new WriteConflictError(\n `compaction verify failed for ${key.segment}.${key.generation}: cardinality ${reader.count()} != ${expectedCount}`,\n );\n }\n}\n\n/** Version-fenced purge: delete each archived Warm row iff its token is unchanged; a newer one survives (I4). */\nasync function purge(\n warm: IWarmDriver,\n ref: SegmentRef,\n pinned: PinnedChunk[],\n): Promise<{ purged: number; survived: number }> {\n let purged = 0;\n let survived = 0;\n for (const { chunkKey, token } of pinned) {\n const chunkRef: ChunkRef = { namespace: ref.namespace, segment: ref.segment, chunkKey };\n try {\n await warm.deleteConditional(chunkRef, token);\n purged += 1;\n } catch (err) {\n if (!isWriteConflictError(err)) throw err;\n survived += 1; // rewritten after the scan → keep it for the next dirty set\n }\n }\n return { purged, survived };\n}\n\n/**\n * Purge archived Warm rows **after** a durable commit. Best-effort: the generation is already committed, and the\n * purge is fenced + idempotent (any row left behind simply re-folds — unchanged — on the next cycle, **I4**), so\n * a transient Warm fault here must NOT be attributed to compaction, which succeeded. Swallow it and report the\n * commit; the next cycle purges the remainder. Returns 0-purged on fault (the pinned rows survive, to be retried).\n * (Mirrors the best-effort `gcOrphanGenerations` call in {@link runCompactionCycle} — both are post-commit cleanup.)\n */\nasync function purgeAfterCommit(\n warm: IWarmDriver,\n ref: SegmentRef,\n pinned: PinnedChunk[],\n): Promise<{ purged: number; survived: number }> {\n return purge(warm, ref, pinned).catch(() => ({ purged: 0, survived: pinned.length }));\n}\n\n/**\n * Delete every Cold generation strictly greater than `g` (crashed-stage orphans). Called under the lease with\n * `g` == the generation just **re-confirmed current** (gap #5) — never a stale pre-lease value, or a\n * concurrently published generation could be deleted. currentGen and below (which readers may be pinned to)\n * are never touched.\n */\nasync function deleteGenerationsAbove(\n cold: IColdDriver,\n ref: SegmentRef,\n g: number,\n): Promise<void> {\n for await (const key of cold.list(ref)) {\n if (key.generation > g) await cold.delete(key);\n }\n}\n\n/** Best-effort lease release (set status back to active). Swallows a conflict — the lease will simply expire. */\nasync function releaseLease(\n deps: CompactionDeps,\n ref: SegmentRef,\n leaseToken: Token,\n): Promise<void> {\n try {\n await deps.registry.compareAndSwap(ref, leaseToken, {\n status: 'active',\n leaseOwner: undefined,\n leaseExpiresAt: undefined,\n });\n } catch (err) {\n if (!isWriteConflictError(err)) throw err;\n }\n}\n\n/** Open a {@link CrbmReader} for one generation over the cold driver's range/tail reads (decrypting if `crypto`). */\nfunction openReader(\n cold: IColdDriver,\n key: GenKey,\n crypto: CrbmCrypto | undefined,\n): Promise<CrbmReader> {\n const blob: BlobReader = {\n getRange: (offset, length) => cold.getRange(key, offset, length),\n getTail: (maxBytes) => cold.getTail(key, maxBytes),\n };\n return CrbmReader.open(blob, { crypto });\n}\n\n// ──────────────────────────────────────────────────────────────────────────────────────────────────────\n// Discovery + daemon cycle (Option A: no hot-path coupling — the write path never touches the registry). To\n// scale toward 100K segments (gap #3), discovery is **shardable** (each worker drains ~1/N of Warm), consumes\n// the `dirtyChunkCount` hint for change-guarded CAS + urgency ordering, and **quarantines** poison segments\n// (gap #2). It still drains Warm per in-shard segment to *count* dirty rows for correctness (O(total warm /\n// shards)); turning that into O(dirty) needs the deferred cheap-enumeration seam (GSI/Select:COUNT — gap #3).\n// ──────────────────────────────────────────────────────────────────────────────────────────────────────\n\nexport interface DiscoveryOptions {\n /** Scope discovery to one namespace (registry `list(namespace)`). */\n readonly namespace?: string;\n /** Minimum dirty Warm rows for a segment to be a candidate (default 1). */\n readonly threshold?: number;\n /**\n * Extra segments to consider beyond the registry's known set. Discovery enumerates `registry.list()`, which\n * only contains segments that have a committed generation — a brand-new **all-warm** segment isn't there\n * yet, so name it here (or bulk-load it once) for the daemon to pick it up.\n */\n readonly candidates?: readonly SegmentRef[];\n /**\n * Shard this worker's slice of the fleet (gap #3). With `totalShards > 1`, discovery considers only segments\n * whose **stable hash** (FNV-1a of the segment key, mod `totalShards`) falls in `shard` (0-based). Run N\n * daemons with `{ shard: i, totalShards: N }` to partition the fleet N ways — each **drains and compacts** only\n * its ~1/N of segments per cycle. NB: the registry enumeration + in-memory candidate set stay O(total segments)\n * per worker (the hash needs the key, which only the scan yields); only the Warm drain + compaction shard. The\n * O(dirty) indexed-enumeration seam that would shard the scan too is deferred (gap #3). Default: handle all.\n */\n readonly shard?: number;\n readonly totalShards?: number;\n /**\n * Poison-segment quarantine (gap #2): a segment whose `consecutiveFailures` has reached this threshold is\n * skipped by discovery (not even drained) until `quarantineCooldownMs` since its last registry update has\n * elapsed — then it's retried once (a transient fault self-heals; a persistent one re-quarantines). Default 5.\n */\n readonly quarantineThreshold?: number;\n /** Cooldown (ms) before a quarantined segment is retried once (default 5 min). */\n readonly quarantineCooldownMs?: number;\n}\n\nexport interface CompactionCandidate {\n readonly ref: SegmentRef;\n readonly dirtyChunks: number;\n readonly currentGen: number | null;\n /** Epoch-ms of the segment's last successful compaction (undefined = never) — the urgency tie-break. */\n readonly lastCompactedAt?: number;\n}\n\nfunction validateShard(shard: number, totalShards: number): void {\n if (!Number.isInteger(totalShards) || totalShards < 1) {\n throw new ValidationError(`totalShards must be a positive integer; got ${totalShards}`);\n }\n if (!Number.isInteger(shard) || shard < 0 || shard >= totalShards) {\n throw new ValidationError(`shard must be an integer in [0, ${totalShards}); got ${shard}`);\n }\n}\n\n/** Deterministic FNV-1a shard assignment for a segment key — dependency-free, stable across workers/restarts. */\nfunction shardOf(key: string, totalShards: number): number {\n let h = 0x811c9dc5;\n for (let i = 0; i < key.length; i++) {\n h ^= key.charCodeAt(i);\n h = Math.imul(h, 0x0100_0193);\n }\n return (h >>> 0) % totalShards;\n}\n\ninterface KnownSegment {\n readonly ref: SegmentRef;\n readonly currentGen: number | null;\n readonly token?: Token;\n readonly dirtyHint: number;\n readonly consecutiveFailures: number;\n readonly updatedAt: number;\n readonly lastCompactedAt?: number;\n}\n\n/**\n * Find segments worth compacting: those in this worker's shard with ≥ `threshold` dirty Warm rows, excluding\n * quarantined poison segments (gap #2). Enumerates the registry (optionally one namespace) plus explicit\n * `candidates`, then for each in-shard, non-quarantined segment drains `warm.listChunks` to count dirty rows —\n * O(total warm / shards) (turning that into O(dirty) needs the deferred GSI/Select:COUNT seam, gap #3). Refreshes\n * the `dirtyChunkCount` hint only when it **changed** (change-guarded CAS — no idle-segment write storm).\n */\nexport async function findCompactable(\n deps: Pick<CompactionDeps, 'warm' | 'registry' | 'clock'>,\n options: DiscoveryOptions = {},\n): Promise<CompactionCandidate[]> {\n const threshold = Math.max(1, options.threshold ?? 1);\n const totalShards = options.totalShards ?? 1;\n const shard = options.shard ?? 0;\n validateShard(shard, totalShards);\n const quarantineThreshold = options.quarantineThreshold ?? DEFAULT_QUARANTINE_THRESHOLD;\n const cooldownMs = options.quarantineCooldownMs ?? DEFAULT_QUARANTINE_COOLDOWN_MS;\n const now = deps.clock.now();\n\n const known = new Map<string, KnownSegment>();\n for await (const rec of deps.registry.list(options.namespace)) {\n known.set(segmentKey(rec), {\n ref: { namespace: rec.namespace, segment: rec.segment },\n currentGen: rec.currentGen,\n token: rec.token,\n dirtyHint: rec.dirtyChunkCount,\n consecutiveFailures: rec.consecutiveFailures ?? 0,\n updatedAt: rec.updatedAt,\n lastCompactedAt: rec.lastCompactedAt,\n });\n }\n for (const ref of options.candidates ?? []) {\n const k = segmentKey(ref);\n if (!known.has(k)) {\n known.set(k, { ref, currentGen: null, dirtyHint: 0, consecutiveFailures: 0, updatedAt: 0 });\n }\n }\n\n const out: CompactionCandidate[] = [];\n for (const [key, seg] of known) {\n // Shard filter (gap #3): a worker handles only its slice, so it drains ~1/N of Warm per cycle.\n if (totalShards > 1 && shardOf(key, totalShards) !== shard) continue;\n // Poison-segment quarantine (gap #2): skip a repeatedly-failing segment — don't even drain it — until the\n // cooldown since its last update elapses, then let it retry once. Transient faults self-heal; persistent\n // ones re-quarantine on the next failure.\n if (seg.consecutiveFailures >= quarantineThreshold && now - seg.updatedAt < cooldownMs)\n continue;\n\n let dirty = 0;\n for await (const row of deps.warm.listChunks(seg.ref)) {\n void row;\n dirty += 1;\n }\n // Change-guarded CAS (gap #3): rewrite the hint only when it actually moved — no per-idle-segment write.\n if (seg.token !== undefined && dirty !== seg.dirtyHint) {\n try {\n await deps.registry.compareAndSwap(seg.ref, seg.token, { dirtyChunkCount: dirty });\n } catch (err) {\n if (!isWriteConflictError(err)) throw err;\n }\n }\n if (dirty >= threshold) {\n out.push({\n ref: seg.ref,\n dirtyChunks: dirty,\n currentGen: seg.currentGen,\n lastCompactedAt: seg.lastCompactedAt,\n });\n }\n }\n return out;\n}\n\n/** What one {@link runCompactionCycle} did: candidates found, how many committed, how many the budget deferred. */\nexport interface CompactionCycleResult {\n /** In-shard, non-quarantined segments over threshold this cycle. */\n readonly candidates: number;\n /** How many committed a new generation. */\n readonly compacted: number;\n /** Candidates left unprocessed by the `maxSegments` budget — run again to drain them. */\n readonly deferred: number;\n readonly results: CompactionResult[];\n}\n\n/**\n * Run one discovery → compact → GC cycle. The CLI/daemon calls this once (Lambda) or on a loop (K8s/ECS).\n * Candidates are processed **most-dirty first** (tie-broken by oldest/never-compacted), and an optional\n * `maxSegments` budget caps the **compact/GC** work per cycle — the rest are `deferred` to the next cycle\n * (urgency ordering keeps the hottest from starving). The budget bounds only compaction: discovery (the registry\n * scan + in-shard Warm drain + urgency sort) is paid in full each cycle, so at very large fleets discovery — not\n * compaction — is the per-cycle floor; the deferred resumable cursor (gap #3) is what will bound it. Per-segment\n * faults are isolated **and** counted toward quarantine (gap #2), so one poison segment can neither abort the\n * cycle nor silently freeze.\n */\nexport async function runCompactionCycle(\n deps: CompactionDeps,\n options: CompactionOptions & DiscoveryOptions & { keep?: number; maxSegments?: number },\n): Promise<CompactionCycleResult> {\n validateCompactionOptions(options); // fail fast even when discovery finds zero candidates\n if (\n options.maxSegments !== undefined &&\n (!Number.isInteger(options.maxSegments) || options.maxSegments < 1)\n ) {\n // A positive integer or nothing. (0 as \"compact none\" is a footgun; negatives were silently \"unlimited\".)\n throw new ValidationError(`maxSegments must be a positive integer; got ${options.maxSegments}`);\n }\n const found = await findCompactable(deps, options);\n // Urgency ordering (gap #3): most-dirty first, tie-broken by oldest/never-compacted (undefined ⇒ 0 ⇒ first),\n // so a limited budget spends where it matters and the backlog can't starve the hottest segments.\n found.sort(\n (a, b) => b.dirtyChunks - a.dirtyChunks || (a.lastCompactedAt ?? 0) - (b.lastCompactedAt ?? 0),\n );\n const budget = options.maxSegments; // validated to a positive integer (or undefined) above\n const picked = budget !== undefined ? found.slice(0, budget) : found;\n\n const results: CompactionResult[] = [];\n let compacted = 0;\n for (const { ref } of picked) {\n // Isolate per-segment faults: a poison-pill segment (corrupt Warm row, cold I/O error) must not abort the\n // whole cycle — record it, count it toward quarantine, and move on to the healthy segments.\n try {\n const result = await compactSegment(ref, deps, options);\n results.push(result);\n if (result.compacted) {\n compacted += 1;\n // Orphan GC is best-effort cleanup (the next cycle's GC catches up the backlog), and the new generation is\n // already durably committed — so a GC fault must NOT be attributed to compaction. Isolate it from the\n // fault path below: otherwise a transient cold/registry error here would bump this *healthy* segment's\n // consecutiveFailures toward quarantine and push a phantom `error` result for a segment that succeeded.\n await gcOrphanGenerations(ref, deps, { keep: options.keep }).catch(() => undefined);\n }\n } catch (err) {\n await bumpFailure(deps, ref).catch(() => undefined); // best-effort; quarantine only needs it eventually\n results.push({\n segment: ref.segment,\n namespace: ref.namespace,\n compacted: false,\n reason: 'error',\n error: err instanceof Error ? err.message : String(err),\n fromGen: null,\n dirtyChunks: 0,\n purged: 0,\n survived: 0,\n });\n }\n }\n return { candidates: found.length, compacted, deferred: found.length - picked.length, results };\n}\n\n/**\n * Increment a segment's `consecutiveFailures` toward poison-quarantine (gap #2) after an isolated compaction\n * fault. Best-effort + conditional: a lost CAS (a concurrent writer) is harmless — the count just advances on a\n * later failing cycle. A successful compaction resets it to 0 (in the commit swap).\n */\nasync function bumpFailure(deps: Pick<CompactionDeps, 'registry'>, ref: SegmentRef): Promise<void> {\n const rec = await deps.registry.get(ref);\n if (rec === null) return; // no row yet (a bootstrap fault) — nothing to quarantine against\n try {\n await deps.registry.compareAndSwap(ref, rec.token, {\n consecutiveFailures: (rec.consecutiveFailures ?? 0) + 1,\n });\n } catch (err) {\n if (!isWriteConflictError(err)) throw err;\n }\n}\n","/**\n * Segment **export (\"eject\")** — dump every registered segment's current *effective* set to a portable file,\n * using only public read APIs, so your data is readable **without CloudRoaring** (a first-class exit path;\n * see the README \"Your data stays yours\" section).\n *\n * Two formats:\n * - `'roaring'` (default) — one **portable RoaringBitmap32** per segment (the cross-language CRoaring format,\n * loadable by any roaring library in Java/Go/Python/Rust/C++/…). Compact; builds one bitmap in memory per\n * segment.\n * - `'ndjson'` — newline-delimited ids, streamed (constant memory, any segment size); zero dependencies to read.\n *\n * The engine is **storage-agnostic and I/O-free**: it enumerates via an {@link IRegistryDriver}, reads the\n * tier-merged effective set via a store's `segment(...).iterate()`, and writes bytes through an injected\n * {@link ExportSink} — so it never imports `node:fs` (the `export-segments` CLI supplies a filesystem sink; a\n * test supplies an in-memory one; you could supply an S3 uploader). Crypto-shredded (`destroyed`) segments are\n * skipped (their bytes are unrecoverable); an encrypted segment is decrypted transparently **iff** the store was\n * wired with its keystore — so the export is **cleartext**, and protecting it is on you.\n *\n * **Enumeration** = the registry's known set (segments with a committed cold generation) **plus** any explicit\n * {@link ExportOptions.candidates}. A brand-new **all-warm** segment — written only via real-time\n * `add()`/`remove()`, never compacted — isn't in the registry yet, so name it in `candidates` (CLI:\n * `CR_EXPORT_SEGMENTS`) to include it, or compact/bulk-load it once first. This mirrors the compaction daemon's\n * discovery contract (see `findCompactable`).\n *\n * **Per-segment fault isolation:** a segment that can't be read (a corrupt cold object, or an encrypted segment\n * when the store has no keystore) is recorded in the manifest's {@link ExportManifest.failed} list and the export\n * **continues** — one bad segment never blocks the rest. Its partial output is aborted, so a truncated file never\n * masquerades as complete. Therefore \"a manifest exists\" means *the run finished*, not that every segment\n * succeeded — check `failed` (the CLI also exits non-zero when it's non-empty).\n */\nimport type { CodecInterface } from '../core/codec';\nimport { requireCodec } from '../core/codec';\nimport type { IRegistryDriver, SegmentRef } from '../core/ports';\nimport { validateSegmentRef } from '../core/validate';\n\n/** Output format for {@link runExport} / `CloudRoaring.exportSegments`. */\nexport type ExportFormat = 'roaring' | 'ndjson';\n\n/** A writer for one segment's output — inject a filesystem file, an S3 upload, stdout, or a test buffer. */\nexport interface ExportWriter {\n /** Append bytes (called one or more times; for `ndjson`, batched line chunks; for `roaring`, once). */\n write(bytes: Uint8Array): Promise<void> | void;\n /** **Commit** the output — called once, only on success (all bytes written). Finalize/flush/rename here. */\n close(): Promise<void> | void;\n /**\n * **Discard** a partial output — called instead of `close()` if a fault occurs mid-segment, so a truncated file\n * never masquerades as complete (e.g. delete the temp file). Optional; sinks with nothing to undo can omit it.\n */\n abort?(): Promise<void> | void;\n}\n\n/** A destination the export writes each segment to. `ext` is `.roaring` or `.ndjson`. */\nexport interface ExportSink {\n open(ref: SegmentRef, ext: string): Promise<ExportWriter> | ExportWriter;\n}\n\nexport interface ExportOptions {\n /** Output format; defaults to `'roaring'`. */\n readonly format?: ExportFormat;\n /**\n * Bitmap codec used to build the exported bitmap for the `'roaring'` format. Optional in the\n * type so this stays call-compatible public API; a **flavor** package binds it (see `requireCodec`). Not needed\n * for `'ndjson'`, which streams plain ids.\n */\n readonly codec?: CodecInterface;\n /** Scope the export to one namespace; omit to export every registered segment. */\n readonly namespace?: string;\n /** `ndjson` flush threshold in ~bytes (ids are ASCII, so ≈ chars); defaults to 64 KiB. */\n readonly ndjsonBatchBytes?: number;\n /**\n * Extra segments to export beyond the registry's known set. The registry only lists segments with a committed\n * cold generation, so an **all-warm** segment (written via real-time `add()`/`remove()`, never compacted) must\n * be named here to be included (CLI: `CR_EXPORT_SEGMENTS`). Deduped against the registry set; when `namespace`\n * is set, only candidates in that namespace are exported.\n */\n readonly candidates?: readonly SegmentRef[];\n}\n\n/** Per-segment result recorded in the {@link ExportManifest}. */\nexport interface ExportedSegment {\n readonly segment: string;\n readonly namespace?: string;\n /** Ids written (the segment's effective cardinality at export time). */\n readonly count: number;\n /** Bytes written to the sink for this segment. */\n readonly bytes: number;\n}\n\n/**\n * A segment that could **not** be exported — recorded rather than aborting the whole run (fault isolation), so a\n * single corrupt/undecryptable segment never blocks the rest of the dump.\n */\nexport interface ExportFailure {\n readonly segment: string;\n readonly namespace?: string;\n /** Why it failed (an error message) — e.g. a corrupt cold object, or an encrypted segment with no keystore. */\n readonly error: string;\n}\n\n/** What {@link runExport} produced — a self-describing summary the CLI persists as `manifest.json`. */\nexport interface ExportManifest {\n /** Schema version of this manifest shape (currently `1`) — insurance for evolving the format post-1.0. */\n readonly version: number;\n readonly format: ExportFormat;\n readonly totalSegments: number;\n readonly totalIds: number;\n readonly segments: readonly ExportedSegment[];\n /**\n * Segments that could not be read (empty when everything succeeded). Its presence in the manifest is the point:\n * \"a manifest exists\" ⇒ the run finished, **not** that every segment succeeded — always check this list.\n */\n readonly failed: readonly ExportFailure[];\n}\n\n/** The minimal read surface the export needs from a store — a `CloudRoaring` satisfies this structurally. */\nexport interface SegmentReader {\n segment(name: string, options?: { namespace?: string }): { iterate(): AsyncIterable<number> };\n}\n\nconst DEFAULT_NDJSON_BATCH_BYTES = 64 * 1024;\n\nconst errMessage = (err: unknown): string => (err instanceof Error ? err.message : String(err));\n/** A dedup key for a ref; namespace can't contain a space (grammar), and '' uniquely denotes the default ns. */\nconst refKey = (ref: SegmentRef): string => `${ref.namespace ?? ''} ${ref.segment}`;\n\n/**\n * Export every enumerated segment's effective set through `sink`. Enumerates via `registry` (+ any\n * `options.candidates`), reads via `reader` (the store). Returns a manifest. `CloudRoaring.exportSegments` is the\n * public entry — it calls this with its own store + registry (so enumeration and the read path provably share one\n * registry).\n *\n * **Fault isolation:** a per-segment read/write fault aborts that segment's partial (so a truncated file never\n * looks complete), records it in `failed`, and the run continues — one bad segment never blocks the rest. A\n * `close()` fault is likewise recorded (never triggering `abort()` — they're mutually exclusive).\n *\n * Re-running overwrites the segments it re-exports but does **not** prune files for segments that have since\n * disappeared — export to a fresh directory for a clean dump. For a *current* image, run against a\n * freshly-constructed store: a store's cold source pins each segment's generation for its lifetime, so a\n * long-lived store that has since been compacted would export the pinned (stale) view.\n */\nexport async function runExport(\n reader: SegmentReader,\n registry: IRegistryDriver,\n sink: ExportSink,\n options: ExportOptions = {},\n): Promise<ExportManifest> {\n const format = options.format ?? 'roaring';\n const ext = format === 'roaring' ? '.roaring' : '.ndjson';\n const batchCap = options.ndjsonBatchBytes ?? DEFAULT_NDJSON_BATCH_BYTES;\n const candidates = options.candidates ?? [];\n const segments: ExportedSegment[] = [];\n const failed: ExportFailure[] = [];\n let totalIds = 0;\n // Only track seen keys when there are candidates to dedup against — keeps the common (no-candidates) path from\n // building a set over the whole registry.\n const seen = candidates.length > 0 ? new Set<string>() : null;\n\n const exportRef = async (ref: SegmentRef): Promise<void> => {\n let writer: ExportWriter | undefined;\n let count = 0;\n let bytes = 0;\n try {\n validateSegmentRef(ref); // defense-in-depth: registry rows AND user-named candidates are untrusted here\n const ids = reader.segment(ref.segment, { namespace: ref.namespace }).iterate();\n writer = await sink.open(ref, ext);\n if (format === 'roaring') {\n const bm = requireCodec(options.codec, \"runExport({ format: 'roaring' })\").empty();\n for await (const id of ids) {\n bm.add(id);\n count += 1;\n }\n const out = bm.serialize(); // portable RoaringBitmap32 — the cross-language CRoaring format\n await writer.write(out);\n bytes = out.length;\n } else {\n let buf = '';\n for await (const id of ids) {\n buf += `${id}\\n`;\n count += 1;\n if (buf.length >= batchCap) {\n const b = Buffer.from(buf, 'utf8');\n await writer.write(b);\n bytes += b.length;\n buf = '';\n }\n }\n if (buf.length > 0) {\n const b = Buffer.from(buf, 'utf8');\n await writer.write(b);\n bytes += b.length;\n }\n }\n } catch (err) {\n // Read/write fault: discard the partial (best-effort, so a failing cleanup can't mask the real fault),\n // record it, and move on — one bad segment never blocks the rest.\n if (writer !== undefined) {\n try {\n await writer.abort?.();\n } catch {\n /* best-effort cleanup */\n }\n }\n failed.push({ segment: ref.segment, namespace: ref.namespace, error: errMessage(err) });\n return;\n }\n // Commit outside the write try: a `close()` failure must NOT also trigger `abort()` (they're mutually\n // exclusive — abort on a write fault, close on success — so a custom sink never double-finalizes). A close\n // fault is still isolated: recorded, not thrown.\n try {\n await writer.close();\n } catch (err) {\n failed.push({ segment: ref.segment, namespace: ref.namespace, error: errMessage(err) });\n return;\n }\n segments.push({ segment: ref.segment, namespace: ref.namespace, count, bytes });\n totalIds += count;\n };\n\n for await (const rec of registry.list(options.namespace)) {\n if (rec.status === 'destroyed') continue; // crypto-shredded → bytes unrecoverable; nothing to export\n if (seen !== null) seen.add(refKey(rec));\n await exportRef({ segment: rec.segment, namespace: rec.namespace });\n }\n for (const ref of candidates) {\n if (options.namespace !== undefined && ref.namespace !== options.namespace) continue; // respect the ns filter\n const key = refKey(ref);\n if (seen !== null && seen.has(key)) continue; // already exported via the registry (or a duplicate candidate)\n seen?.add(key);\n await exportRef(ref);\n }\n return { version: 1, format, totalSegments: segments.length, totalIds, segments, failed };\n}\n","/**\n * The byte-IO seam the `.crbm` codec reads/writes through.\n *\n * Deliberately tiny and driver-independent: a `BlobSink` is a streaming append target (the writer needs\n * no random access), a `BlobReader` supports the speculative tail read + bounded range reads. An\n * `IColdDriver` (Phase 2b) adapts a `GenKey` to these; the in-memory impls below let the format be\n * golden-tested and let the in-memory cold tier hold a real `.crbm` with no filesystem.\n */\nimport { ValidationError } from './errors';\n\n/** Streaming append target for a single object being written. */\nexport interface BlobSink {\n write(bytes: Uint8Array): Promise<void>;\n}\n\n/**\n * Random/tail read access to a single finished object. The total size comes back from `getTail` (the\n * codec's entry point), so there's no separate `size()` — keeping the seam minimal for driver authors.\n */\nexport interface BlobReader {\n /** Exactly `length` bytes starting at `offset`. Out-of-range is a `ValidationError`, never a short read. */\n getRange(offset: number, length: number): Promise<Uint8Array>;\n /** The last `min(maxBytes, size)` bytes plus the total size — the one-GET footer+index path. */\n getTail(maxBytes: number): Promise<{ bytes: Uint8Array; size: number }>;\n}\n\n/** In-memory `BlobSink` that accumulates written bytes; `bytes()` returns the concatenation. */\nexport class BufferSink implements BlobSink {\n private readonly chunks: Uint8Array[] = [];\n private length = 0;\n\n write(bytes: Uint8Array): Promise<void> {\n // Copy: callers may reuse their buffer after write() resolves.\n this.chunks.push(bytes.slice());\n this.length += bytes.length;\n return Promise.resolve();\n }\n\n bytes(): Uint8Array {\n const out = new Uint8Array(this.length);\n let offset = 0;\n for (const chunk of this.chunks) {\n out.set(chunk, offset);\n offset += chunk.length;\n }\n return out;\n }\n}\n\n/** In-memory `BlobReader` over a fixed byte buffer. */\nexport class BufferReader implements BlobReader {\n constructor(private readonly buffer: Uint8Array) {}\n\n getRange(offset: number, length: number): Promise<Uint8Array> {\n if (\n !Number.isInteger(offset) ||\n !Number.isInteger(length) ||\n offset < 0 ||\n length < 0 ||\n offset + length > this.buffer.length\n ) {\n throw new ValidationError(\n `range [${offset}, ${offset + length}) out of bounds for ${this.buffer.length}-byte blob`,\n );\n }\n return Promise.resolve(this.buffer.subarray(offset, offset + length));\n }\n\n getTail(maxBytes: number): Promise<{ bytes: Uint8Array; size: number }> {\n const size = this.buffer.length;\n const take = Math.min(Math.max(maxBytes, 0), size);\n return Promise.resolve({ bytes: this.buffer.subarray(size - take), size });\n }\n}\n","/**\n * In-memory drivers — the Phase-1 backing for the engine.\n * They store **serialized bytes + an OCC token** (not live objects), so the engine's\n * serialize / safe-deserialize / size-cap / OCC paths are genuinely exercised. In Phase 2 these\n * become the conformance-suite's first target and the simulator's fault-injecting fakes.\n *\n * Not in `core/` (this is a driver), so it may hold concrete state.\n */\nimport { createHash } from 'node:crypto';\nimport { BufferSink } from '../core/blob';\nimport type { BlobSink } from '../core/blob';\nimport { NotFoundError, ValidationError, WriteConflictError } from '../core/errors';\nimport { chunkRefKey, segmentKey, segmentPrefix } from '../core/keys';\nimport { validateChunkRef, validateSegmentRef } from '../core/validate';\nimport { NO_ROW } from '../core/ports';\nimport type {\n ChunkRef,\n ColdCaps,\n ColdChunkSource,\n GenKey,\n IColdDriver,\n IRegistryDriver,\n IWarmDriver,\n NewRegistryRecord,\n NoRow,\n RegCaps,\n RegistryPatch,\n RegistryRecord,\n SegmentRef,\n SegmentSize,\n Token,\n WarmRow,\n} from '../core/ports';\nimport {\n applyRegistryPatch,\n recordFromNew,\n validateNewRegistryRecord,\n validateRegistryPatch,\n} from './_shared/registry';\n\ninterface StoredRow {\n token: Token;\n bytes: Uint8Array;\n chunkKey: number;\n prefix: string;\n}\n\nexport class MemoryWarmDriver implements IWarmDriver {\n private readonly rows = new Map<string, StoredRow>();\n private seq = 0;\n\n // Monotonic, unique-per-write token → equality-safe and ABA-free.\n private nextToken(): Token {\n this.seq += 1;\n return String(this.seq);\n }\n\n // In-memory reads are always strongly consistent — the `WarmReadOptions` hint would be a no-op, so the\n // structurally-optional param is simply omitted (still satisfies IWarmDriver).\n async get(ref: ChunkRef): Promise<WarmRow | null> {\n validateChunkRef(ref);\n const row = this.rows.get(chunkRefKey(ref));\n return row ? { token: row.token, bytes: row.bytes } : null;\n }\n\n async putConditional(\n ref: ChunkRef,\n bytes: Uint8Array,\n expected: Token | NoRow,\n ): Promise<{ token: Token }> {\n validateChunkRef(ref);\n const key = chunkRefKey(ref);\n const existing = this.rows.get(key);\n if (expected === NO_ROW) {\n if (existing) throw new WriteConflictError(`row already exists for chunk ${ref.chunkKey}`);\n } else if (!existing || existing.token !== expected) {\n throw new WriteConflictError(`OCC token mismatch for chunk ${ref.chunkKey}`);\n }\n const token = this.nextToken();\n this.rows.set(key, { token, bytes, chunkKey: ref.chunkKey, prefix: segmentPrefix(ref) });\n return { token };\n }\n\n async deleteConditional(ref: ChunkRef, expected: Token): Promise<void> {\n validateChunkRef(ref);\n const key = chunkRefKey(ref);\n const existing = this.rows.get(key);\n if (!existing || existing.token !== expected) {\n throw new WriteConflictError(`OCC token mismatch for chunk ${ref.chunkKey}`);\n }\n this.rows.delete(key);\n }\n\n async *listChunks(ref: SegmentRef): AsyncIterable<{ chunkKey: number } & WarmRow> {\n validateSegmentRef(ref);\n const prefix = segmentPrefix(ref);\n const rows = [...this.rows.values()].filter((r) => r.prefix === prefix);\n rows.sort((a, b) => a.chunkKey - b.chunkKey); // ascending chunkKey\n for (const row of rows) {\n yield { chunkKey: row.chunkKey, token: row.token, bytes: row.bytes };\n }\n }\n}\n\nexport class MemoryColdChunkSource implements ColdChunkSource {\n private readonly chunks = new Map<string, Uint8Array>();\n\n async getChunk(ref: ChunkRef): Promise<Uint8Array | null> {\n validateChunkRef(ref);\n return this.chunks.get(chunkRefKey(ref)) ?? null;\n }\n\n async listChunkKeys(ref: SegmentRef): Promise<number[]> {\n validateSegmentRef(ref);\n const prefix = segmentPrefix(ref);\n const keys: number[] = [];\n for (const key of this.chunks.keys()) {\n if (key.startsWith(prefix)) keys.push(Number(key.slice(prefix.length)));\n }\n return keys;\n }\n\n async sizeOf(ref: SegmentRef): Promise<SegmentSize | null> {\n validateSegmentRef(ref);\n const prefix = segmentPrefix(ref);\n let sizeBytes = 0;\n let found = false;\n for (const [key, bytes] of this.chunks) {\n if (!key.startsWith(prefix)) continue;\n found = true;\n sizeBytes += bytes.length;\n }\n return found ? { sizeBytes } : null;\n }\n\n /** Test/seed helper — populate immutable Cold bytes for a chunk (no bulk-load path until Phase 3). */\n seed(ref: ChunkRef, bytes: Uint8Array): void {\n validateChunkRef(ref); // keep seed symmetric with the validated read path\n this.chunks.set(chunkRefKey(ref), bytes);\n }\n}\n\nexport interface MemoryRegistryDriverOptions {\n /** Injected clock for `createdAt`/`updatedAt`; defaults to `Date.now` (drivers may use ambient time). */\n readonly now?: () => number;\n}\n\n/**\n * In-memory {@link IRegistryDriver} — one record per segment under OCC. The token is a single global,\n * monotonic, never-reused counter (so a record recreated after `delete` always gets a strictly-greater\n * token → ABA-safe even though `delete` removes the row physically). Mirrors {@link MemoryWarmDriver}.\n */\nexport class MemoryRegistryDriver implements IRegistryDriver {\n private readonly rows = new Map<string, RegistryRecord>();\n private readonly now: () => number;\n private seq = 0;\n\n constructor(options: MemoryRegistryDriverOptions = {}) {\n this.now = options.now ?? (() => Date.now());\n }\n\n private nextToken(): Token {\n this.seq += 1;\n return String(this.seq);\n }\n\n capabilities(): RegCaps {\n return { strongRead: true };\n }\n\n async get(ref: SegmentRef): Promise<RegistryRecord | null> {\n validateSegmentRef(ref);\n const row = this.rows.get(segmentKey(ref));\n return row ? structuredClone(row) : null; // clone out: callers can't mutate stored (nested) state\n }\n\n async create(ref: SegmentRef, record: NewRegistryRecord): Promise<{ token: Token }> {\n validateSegmentRef(ref);\n validateNewRegistryRecord(record);\n const key = segmentKey(ref);\n if (this.rows.has(key)) {\n throw new WriteConflictError(`registry row already exists for segment ${ref.segment}`);\n }\n const token = this.nextToken();\n // clone in: the caller's (nested) retention/residency can't alias stored state (value semantics, parity\n // with the serialize-based persistent drivers).\n this.rows.set(key, structuredClone(recordFromNew(ref, record, this.now(), token)));\n return { token };\n }\n\n async compareAndSwap(\n ref: SegmentRef,\n expected: Token,\n patch: RegistryPatch,\n ): Promise<{ token: Token }> {\n validateSegmentRef(ref);\n validateRegistryPatch(patch);\n const key = segmentKey(ref);\n const existing = this.rows.get(key);\n if (!existing || existing.token !== expected) {\n throw new WriteConflictError(`OCC token mismatch for registry row ${ref.segment}`);\n }\n const token = this.nextToken();\n this.rows.set(key, structuredClone(applyRegistryPatch(existing, patch, this.now(), token)));\n return { token };\n }\n\n async *list(namespace?: string): AsyncIterable<RegistryRecord> {\n for (const row of this.rows.values()) {\n if (namespace === undefined || row.namespace === namespace) yield structuredClone(row);\n }\n }\n\n async delete(ref: SegmentRef): Promise<void> {\n validateSegmentRef(ref);\n this.rows.delete(segmentKey(ref)); // idempotent; token uniqueness is global so a recreate is ABA-safe\n }\n}\n\n/**\n * In-memory {@link IColdDriver} — write-once immutable generation objects as opaque bytes. A \"dumb byte\n * mover\" (understands neither roaring nor `.crbm`), so it's a faithful cold backend for tests, the compaction\n * simulator, and a zero-setup local cold tier. Mirrors the LocalFs/S3 contract (write-once, range/tail reads).\n */\nexport class MemoryColdDriver implements IColdDriver {\n private readonly objects = new Map<string, Uint8Array>();\n\n capabilities(): ColdCaps {\n return { rangeRead: true, maxObjectBytes: Number.MAX_SAFE_INTEGER, conditionalPut: true };\n }\n\n async putImmutable(\n key: GenKey,\n write: (sink: BlobSink) => Promise<void>,\n ): Promise<{ size: number; sha256: string }> {\n const k = genObjectKey(key); // validates ref + generation\n const sink = new BufferSink();\n await write(sink);\n const body = sink.bytes();\n if (this.objects.has(k)) {\n throw new WriteConflictError(\n `generation already exists (write-once): ${key.segment}.${key.generation}`,\n );\n }\n this.objects.set(k, body);\n return { size: body.length, sha256: createHash('sha256').update(body).digest('hex') };\n }\n\n async getRange(key: GenKey, offset: number, length: number): Promise<Uint8Array> {\n if (!Number.isInteger(offset) || !Number.isInteger(length) || offset < 0 || length < 0) {\n throw new ValidationError(`invalid range offset=${offset} length=${length}`);\n }\n const body = this.require(key);\n if (offset + length > body.length) {\n throw new ValidationError(\n `range [${offset}, ${offset + length}) out of bounds for ${body.length}B`,\n );\n }\n return body.slice(offset, offset + length);\n }\n\n async getTail(key: GenKey, maxBytes: number): Promise<{ bytes: Uint8Array; size: number }> {\n const body = this.require(key);\n const take = Math.min(Math.max(maxBytes, 0), body.length);\n return { bytes: body.slice(body.length - take), size: body.length };\n }\n\n async delete(key: GenKey): Promise<void> {\n this.objects.delete(genObjectKey(key)); // idempotent\n }\n\n async *list(ref: SegmentRef): AsyncIterable<GenKey> {\n validateSegmentRef(ref);\n const prefix = `${segmentKey(ref)} `;\n for (const k of this.objects.keys()) {\n if (k.startsWith(prefix)) {\n yield {\n namespace: ref.namespace,\n segment: ref.segment,\n generation: Number(k.slice(prefix.length)),\n };\n }\n }\n }\n\n private require(key: GenKey): Uint8Array {\n const body = this.objects.get(genObjectKey(key));\n if (body === undefined) {\n throw new NotFoundError(`no such generation: ${key.segment}.${key.generation}`);\n }\n return body;\n }\n}\n\n/** Collision-proof object key for a generation: `<segmentKey> <generation>` (space is forbidden in names). */\nfunction genObjectKey(key: GenKey): string {\n validateSegmentRef(key);\n if (!Number.isInteger(key.generation) || key.generation < 0) {\n throw new ValidationError(`generation must be a non-negative integer; got ${key.generation}`);\n }\n return `${segmentKey(key)} ${key.generation}`;\n}\n","/**\n * Logical-ref → filesystem-path mapping for the LocalFs drivers (decision 6).\n *\n * Names are re-validated here at the driver boundary — defense in depth, even though the engine already\n * validates (S2) — so a driver is safe against traversal/injection even if driven directly. The default\n * (absent) namespace maps to `_default`, which can never collide with a real namespace because the name\n * grammar forbids a leading underscore.\n */\nimport { join } from 'node:path';\nimport { ValidationError } from '@/core/errors';\nimport { validateChunkRef, validateSegmentRef } from '@/core/validate';\nimport type { ChunkRef, GenKey, SegmentRef } from '@/core/ports';\nimport { namespacePart } from '../_shared/keys';\n\n/** Directory holding all of a namespace's segment objects. */\nexport function segmentsDir(root: string, ref: SegmentRef): string {\n validateSegmentRef(ref);\n return join(root, namespacePart(ref.namespace), 'segments');\n}\n\n/** Absolute path of one `.crbm` generation object. */\nexport function coldObjectPath(root: string, key: GenKey): string {\n validateSegmentRef(key);\n if (!Number.isInteger(key.generation) || key.generation < 0) {\n throw new ValidationError(`generation must be a non-negative integer; got ${key.generation}`);\n }\n return join(segmentsDir(root, key), `${key.segment}.${key.generation}.crbm`);\n}\n\n/** Filename pattern for a segment's generations: `<segment>.<gen>.crbm`. */\nexport function coldObjectFilename(segment: string, generation: number): string {\n return `${segment}.${generation}.crbm`;\n}\n\n/** Parse a generation number out of a `<segment>.<gen>.crbm` filename, or `null` if it doesn't match. */\nexport function parseGeneration(segment: string, filename: string): number | null {\n const prefix = `${segment}.`;\n const suffix = '.crbm';\n if (!filename.startsWith(prefix) || !filename.endsWith(suffix)) return null;\n const middle = filename.slice(prefix.length, filename.length - suffix.length);\n // Canonical decimal only: no leading zeros (so `s.07.crbm` can't alias `s.7.crbm`), and within\n // safe-integer range. The writer only ever emits the canonical form.\n if (!/^(0|[1-9]\\d*)$/.test(middle)) return null;\n const gen = Number(middle);\n return Number.isSafeInteger(gen) ? gen : null;\n}\n\nconst WARM_ROW_SUFFIX = '.row';\nconst CHUNK_KEY_MAX = 0xffff;\n\n/** Directory holding a segment's Warm rows (one file per dirty chunk). */\nexport function warmSegmentDir(root: string, ref: SegmentRef): string {\n validateSegmentRef(ref);\n return join(root, namespacePart(ref.namespace), 'warm', ref.segment);\n}\n\n/** Absolute path of one chunk's Warm row file. */\nexport function warmRowPath(root: string, ref: ChunkRef): string {\n validateChunkRef(ref); // segment/namespace grammar + chunkKey range, one source of truth\n return join(warmSegmentDir(root, ref), `${ref.chunkKey}${WARM_ROW_SUFFIX}`);\n}\n\nconst REGISTRY_SUFFIX = '.reg';\n\n/** Directory holding a namespace's registry rows (one file per segment). */\nexport function registryDir(root: string, namespace: string | undefined): string {\n return join(root, namespacePart(namespace), 'registry');\n}\n\n/** Absolute path of one segment's registry row file: `<ns>/registry/<segment>.reg`. */\nexport function registryRowPath(root: string, ref: SegmentRef): string {\n validateSegmentRef(ref);\n return join(registryDir(root, ref.namespace), `${ref.segment}${REGISTRY_SUFFIX}`);\n}\n\n/**\n * Parse a segment name out of a `<segment>.reg` filename, or `null` if it doesn't match — including any\n * file whose stem isn't a valid segment name. A stricter parser (mirroring `parseChunkRow`) means a stray\n * or planted `.reg` file makes `list()` *skip* it, never abort the whole enumeration on a boundary throw.\n */\nexport function parseRegistryRow(filename: string): string | null {\n if (!filename.endsWith(REGISTRY_SUFFIX)) return null;\n const segment = filename.slice(0, filename.length - REGISTRY_SUFFIX.length);\n try {\n validateSegmentRef({ segment });\n } catch {\n return null;\n }\n return segment;\n}\n\n/** Parse a chunk key out of a `<chunkKey>.row` filename, or `null` if it doesn't match (canonical only). */\nexport function parseChunkRow(filename: string): number | null {\n if (!filename.endsWith(WARM_ROW_SUFFIX)) return null;\n const middle = filename.slice(0, filename.length - WARM_ROW_SUFFIX.length);\n if (!/^(0|[1-9]\\d*)$/.test(middle)) return null;\n const chunkKey = Number(middle);\n return chunkKey <= CHUNK_KEY_MAX ? chunkKey : null;\n}\n","/**\n * Shared filesystem helpers for the LocalFs drivers (cold/warm, and the Phase-4 registry) — one source\n * of truth for error-code matching, the symlink-refusal flag, and directory durability.\n */\nimport { constants as FS } from 'node:fs';\nimport { open } from 'node:fs/promises';\nimport { TransientError } from '@/core/errors';\n\ninterface NodeError extends Error {\n code?: string;\n}\n\n/** True when `err` is a Node system error with the given `code` (e.g. `'ENOENT'`, `'EEXIST'`). */\nexport const isCode = (err: unknown, code: string): boolean =>\n err instanceof Error && (err as NodeError).code === code;\n\n/**\n * Filesystem error codes that are transient — a retry after a brief backoff often succeeds: the resource is\n * busy (`EBUSY`), the OS asked us to retry (`EAGAIN`), or we hit the open-file-descriptor ceiling\n * (`EMFILE`/`ENFILE`, common under heavy concurrency once earlier handles close). A networked FS may also\n * surface `ETIMEDOUT`.\n */\nconst TRANSIENT_FS_CODES = new Set(['EBUSY', 'EAGAIN', 'EMFILE', 'ENFILE', 'ETIMEDOUT']);\n\nexport const isFsTransient = (err: unknown): boolean =>\n err instanceof Error && TRANSIENT_FS_CODES.has((err as NodeError).code ?? '');\n\n/**\n * Reclassify a transient filesystem fault as a retryable {@link TransientError} (so the retry decorator can\n * ride it out); everything else — including the driver's own typed errors — propagates unchanged.\n */\nexport const mapFsError = (err: unknown): unknown =>\n isFsTransient(err)\n ? new TransientError(`transient filesystem fault: ${(err as NodeError).code}`, { cause: err })\n : err;\n\n/**\n * `O_NOFOLLOW` where the platform supports it (absent on Windows → 0). OR it into an `open` flag set so a\n * symlink **at the final path component** is refused rather than followed outside the storage root.\n * Containment of symlinked *directory* components assumes the root itself is not attacker-writable.\n */\nexport const O_NOFOLLOW = FS.O_NOFOLLOW ?? 0;\n\n/** Best-effort parent-directory fsync so a just-published `rename`/`link` survives a crash (C13). */\nexport async function fsyncDir(dir: string): Promise<void> {\n try {\n const handle = await open(dir, 'r');\n try {\n await handle.sync();\n } finally {\n await handle.close();\n }\n } catch {\n // Some platforms reject directory fsync; durability of the entry is then best-effort.\n }\n}\n","/**\n * `LocalFsColdDriver` — a zero-cloud {@link IColdDriver} backed by the local filesystem.\n *\n * Generations are write-once immutable files. A new object is streamed to a temp file (with its content\n * hashed in-flight), `fsync`-ed, then published with an atomic `link` that fails if the destination\n * already exists — so a generation can never be silently overwritten, and a crash leaves only an orphan\n * temp file, never a torn object (C13). Drivers do filesystem I/O and may use `node:crypto`; only `core/`\n * is bound by the determinism lint.\n */\nimport { constants as FS } from 'node:fs';\nimport { createHash, randomUUID } from 'node:crypto';\nimport { link, mkdir, open, readdir, unlink } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { NotFoundError, ValidationError, WriteConflictError } from '@/core/errors';\nimport type { BlobSink } from '@/core/blob';\nimport type { ColdCaps, GenKey, IColdDriver, SegmentRef } from '@/core/ports';\nimport { coldObjectPath, parseGeneration, segmentsDir } from './paths';\nimport { O_NOFOLLOW, fsyncDir, isCode, mapFsError } from './fs-util';\n\nexport class LocalFsColdDriver implements IColdDriver {\n constructor(private readonly root: string) {}\n\n capabilities(): ColdCaps {\n return { rangeRead: true, maxObjectBytes: Number.MAX_SAFE_INTEGER, conditionalPut: false };\n }\n\n async putImmutable(\n key: GenKey,\n write: (sink: BlobSink) => Promise<void>,\n ): Promise<{ size: number; sha256: string }> {\n const finalPath = coldObjectPath(this.root, key);\n await mkdir(dirname(finalPath), { recursive: true });\n\n const tmpPath = `${finalPath}.${randomUUID()}.tmp`;\n // 'wx' = O_CREAT|O_EXCL|O_WRONLY; add O_NOFOLLOW so a pre-planted symlink can't redirect the write.\n const handle = await open(tmpPath, FS.O_CREAT | FS.O_EXCL | FS.O_WRONLY | O_NOFOLLOW);\n const hash = createHash('sha256');\n let size = 0;\n const sink: BlobSink = {\n async write(bytes) {\n await handle.write(bytes);\n hash.update(bytes);\n size += bytes.length;\n },\n };\n\n try {\n await write(sink);\n await handle.sync();\n } catch (err) {\n await handle.close().catch(() => {});\n await unlink(tmpPath).catch(() => {});\n throw mapFsError(err);\n }\n await handle.close();\n\n // Atomic write-once publish: link fails with EEXIST if the generation already exists.\n try {\n await link(tmpPath, finalPath);\n } catch (err) {\n await unlink(tmpPath).catch(() => {});\n if (isCode(err, 'EEXIST')) {\n // A generation is write-once; a collision is a concurrency/state condition, not bad input.\n // Identify it by the logical key only — never leak the absolute filesystem path.\n throw new WriteConflictError(\n `generation already exists (write-once): ${key.segment}.${key.generation}`,\n );\n }\n throw mapFsError(err);\n }\n await unlink(tmpPath).catch(() => {});\n await fsyncDir(dirname(finalPath));\n return { size, sha256: hash.digest('hex') };\n }\n\n async getRange(key: GenKey, offset: number, length: number): Promise<Uint8Array> {\n if (!Number.isInteger(offset) || !Number.isInteger(length) || offset < 0 || length < 0) {\n throw new ValidationError(`invalid range offset=${offset} length=${length}`);\n }\n const handle = await this.openRead(key);\n try {\n const { size } = await handle.stat();\n if (offset + length > size) {\n throw new ValidationError(\n `range [${offset}, ${offset + length}) out of bounds for ${size}B`,\n );\n }\n const buf = Buffer.alloc(length);\n if (length > 0) await handle.read(buf, 0, length, offset);\n return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);\n } finally {\n await handle.close();\n }\n }\n\n async getTail(key: GenKey, maxBytes: number): Promise<{ bytes: Uint8Array; size: number }> {\n const handle = await this.openRead(key);\n try {\n const { size } = await handle.stat();\n const take = Math.min(Math.max(maxBytes, 0), size);\n const buf = Buffer.alloc(take);\n if (take > 0) await handle.read(buf, 0, take, size - take);\n return { bytes: new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength), size };\n } finally {\n await handle.close();\n }\n }\n\n async delete(key: GenKey): Promise<void> {\n // Idempotent: deleting an absent generation is a no-op (GC may race / retry).\n await unlink(coldObjectPath(this.root, key)).catch((err) => {\n if (!isCode(err, 'ENOENT')) throw mapFsError(err);\n });\n }\n\n async *list(ref: SegmentRef): AsyncIterable<GenKey> {\n const dir = segmentsDir(this.root, ref);\n let names: string[];\n try {\n names = await readdir(dir);\n } catch (err) {\n if (isCode(err, 'ENOENT')) return; // no generations yet\n throw mapFsError(err);\n }\n for (const name of names) {\n const generation = parseGeneration(ref.segment, name);\n if (generation !== null) {\n yield { namespace: ref.namespace, segment: ref.segment, generation };\n }\n }\n }\n\n private async openRead(key: GenKey): Promise<Awaited<ReturnType<typeof open>>> {\n try {\n return await open(coldObjectPath(this.root, key), FS.O_RDONLY | O_NOFOLLOW);\n } catch (err) {\n if (isCode(err, 'ENOENT')) {\n throw new NotFoundError(`no such generation: ${key.segment}.${key.generation}`);\n }\n // A symlink at the object path is rejected (ELOOP) — treat as not-found, don't follow it.\n if (isCode(err, 'ELOOP')) {\n throw new NotFoundError(\n `generation path is a symlink, refusing: ${key.segment}.${key.generation}`,\n );\n }\n throw mapFsError(err);\n }\n }\n}\n","/**\n * `LocalFsWarmDriver` — a zero-cloud, persistent {@link IWarmDriver} backed by the local filesystem.\n *\n * One file per dirty chunk holds `[u32 counter][u8 deleted][payload]` (an internal, unversioned row —\n * it never leaves the local FS and the driver is its sole reader/writer). The OCC token is the counter\n * stringified — monotonic, never reused: it advances even across a delete (via a **tombstone**), so a\n * deleted-then-recreated row never re-issues an old token (ABA-safe). Every mutation is\n * write-temp → fsync(file) → atomic rename → fsync(dir), and read-modify-write is serialized per row\n * in-process so concurrent writers form a single CAS chain with no lost updates. (Cross-*process* CAS on\n * a local FS is out of scope — the production OCC backends are DynamoDB et al.; LocalFs is the dev/test\n * tier. `WarmCaps`/`capabilities()` + batch paths are likewise deferred with topology validation →\n * Phase 4.)\n */\nimport { constants as FS } from 'node:fs';\nimport { randomUUID } from 'node:crypto';\nimport { mkdir, open, readdir, rename, unlink } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { IntegrityError, WriteConflictError } from '@/core/errors';\nimport { NO_ROW } from '@/core/ports';\nimport type { ChunkRef, IWarmDriver, NoRow, SegmentRef, Token, WarmRow } from '@/core/ports';\nimport { parseChunkRow, warmRowPath, warmSegmentDir } from './paths';\nimport { O_NOFOLLOW, fsyncDir, isCode, mapFsError } from './fs-util';\n\nconst HEADER_BYTES = 5; // u32 counter (LE) + u8 deleted flag\nconst COUNTER_MAX = 0xffffffff; // token counter is stored as a u32\n/** Defensive cap on a single row read from (untrusted) storage, before allocation. */\nconst DEFAULT_MAX_ROW_BYTES = 64 * 1024 * 1024;\n\ninterface Row {\n readonly counter: number;\n readonly deleted: boolean;\n readonly bytes: Uint8Array;\n}\n\nexport class LocalFsWarmDriver implements IWarmDriver {\n /** Per-row promise chain — serializes read-modify-write so an in-process CAS never loses an update. */\n private readonly chain = new Map<string, Promise<unknown>>();\n\n constructor(\n private readonly root: string,\n private readonly maxRowBytes: number = DEFAULT_MAX_ROW_BYTES,\n ) {}\n\n // Methods are `async` so boundary-validation throws (warmRowPath) surface as rejections, not sync throws.\n // LocalFs reads are always strongly consistent (single filesystem) — the `WarmReadOptions` hint would be a\n // no-op, so the structurally-optional param is simply omitted (still satisfies IWarmDriver).\n async get(ref: ChunkRef): Promise<WarmRow | null> {\n const row = await this.readRow(warmRowPath(this.root, ref));\n return row && !row.deleted ? { token: String(row.counter), bytes: row.bytes } : null;\n }\n\n async putConditional(\n ref: ChunkRef,\n bytes: Uint8Array,\n expected: Token | NoRow,\n ): Promise<{ token: Token }> {\n const path = warmRowPath(this.root, ref);\n return this.withRowLock(path, async () => {\n const current = await this.readRow(path);\n const live = current !== null && !current.deleted;\n if (expected === NO_ROW) {\n if (live) throw new WriteConflictError(`row already exists: chunk ${ref.chunkKey}`);\n const counter = current ? current.counter + 1 : 0; // advance across a tombstone (ABA-safe)\n await this.writeRow(path, counter, false, bytes);\n return { token: String(counter) };\n }\n if (!live || String(current.counter) !== expected) {\n throw new WriteConflictError(`OCC conflict on chunk ${ref.chunkKey}`);\n }\n await this.writeRow(path, current.counter + 1, false, bytes);\n return { token: String(current.counter + 1) };\n });\n }\n\n async deleteConditional(ref: ChunkRef, expected: Token): Promise<void> {\n const path = warmRowPath(this.root, ref);\n return this.withRowLock(path, async () => {\n const current = await this.readRow(path);\n if (current === null || current.deleted || String(current.counter) !== expected) {\n throw new WriteConflictError(`OCC conflict on delete of chunk ${ref.chunkKey}`);\n }\n // Tombstone (keep the counter advancing) rather than unlink — preserves ABA-safety.\n await this.writeRow(path, current.counter + 1, true, new Uint8Array());\n });\n }\n\n async *listChunks(ref: SegmentRef): AsyncIterable<{ chunkKey: number } & WarmRow> {\n const dir = warmSegmentDir(this.root, ref);\n let names: string[];\n try {\n names = await readdir(dir);\n } catch (err) {\n if (isCode(err, 'ENOENT')) return;\n throw mapFsError(err);\n }\n // Ascending chunkKey order. readdir order is unspecified, so sort.\n const keys = names\n .map((n) => parseChunkRow(n))\n .filter((k): k is number => k !== null)\n .sort((a, b) => a - b);\n for (const chunkKey of keys) {\n const row = await this.readRow(warmRowPath(this.root, { ...ref, chunkKey }));\n if (row && !row.deleted) yield { chunkKey, token: String(row.counter), bytes: row.bytes };\n }\n }\n\n private async readRow(path: string): Promise<Row | null> {\n let handle;\n try {\n handle = await open(path, FS.O_RDONLY | O_NOFOLLOW);\n } catch (err) {\n if (isCode(err, 'ENOENT') || isCode(err, 'ELOOP')) return null;\n throw mapFsError(err);\n }\n try {\n const { size } = await handle.stat();\n if (size > this.maxRowBytes) {\n throw new IntegrityError(`warm row ${size}B exceeds cap ${this.maxRowBytes}B`);\n }\n // A published row is always whole (atomic rename of a fully-written temp); a shorter-than-header\n // file means corruption/tampering — fail fast rather than silently reporting \"absent\".\n if (size < HEADER_BYTES) {\n throw new IntegrityError(`warm row truncated: ${size}B < ${HEADER_BYTES}B header`);\n }\n const buf = await handle.readFile();\n const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);\n return {\n counter: view.getUint32(0, true),\n deleted: buf[4] !== 0,\n bytes: new Uint8Array(buf.subarray(HEADER_BYTES)),\n };\n } finally {\n await handle.close();\n }\n }\n\n private async writeRow(\n path: string,\n counter: number,\n deleted: boolean,\n bytes: Uint8Array,\n ): Promise<void> {\n if (counter > COUNTER_MAX) {\n // 4 billion writes to one chunk — astronomically unreachable, but guard rather than wrap a u32\n // (which would re-issue an old token and break ABA-safety).\n throw new IntegrityError(`warm row counter overflow on ${path}`);\n }\n await mkdir(dirname(path), { recursive: true });\n const out = new Uint8Array(HEADER_BYTES + bytes.length);\n new DataView(out.buffer).setUint32(0, counter, true);\n out[4] = deleted ? 1 : 0;\n out.set(bytes, HEADER_BYTES);\n\n const tmp = `${path}.${randomUUID()}.tmp`;\n let handle;\n try {\n handle = await open(tmp, FS.O_CREAT | FS.O_EXCL | FS.O_WRONLY | O_NOFOLLOW);\n } catch (err) {\n throw mapFsError(err); // e.g. EMFILE under heavy concurrency — retryable\n }\n try {\n await handle.write(out);\n await handle.sync();\n } finally {\n await handle.close();\n }\n // Atomic replace (rows are mutable, unlike write-once Cold objects); rename replaces a symlink at\n // `path` rather than following it.\n await rename(tmp, path).catch(async (err) => {\n await unlink(tmp).catch(() => {});\n throw mapFsError(err);\n });\n await fsyncDir(dirname(path)); // make the directory-entry update durable (C13 parity with Cold)\n }\n\n /**\n * Serialize callbacks for a given row path so read-modify-write is atomic in-process. `prev.then(fn,\n * fn)` runs `fn` regardless of whether the predecessor fulfilled or rejected — a conflict on one\n * writer must not stall the row's chain.\n */\n private withRowLock<T>(key: string, fn: () => Promise<T>): Promise<T> {\n const prev = this.chain.get(key) ?? Promise.resolve();\n const result = prev.then(fn, fn);\n const tail = result.then(\n () => undefined,\n () => undefined,\n );\n this.chain.set(key, tail);\n void tail.then(() => {\n if (this.chain.get(key) === tail) this.chain.delete(key);\n });\n return result;\n }\n}\n","/**\n * `LocalFsRegistryDriver` — a zero-cloud, persistent {@link IRegistryDriver} (Phase 4c).\n *\n * One JSON file per segment at `<root>/<namespace>/registry/<segment>.reg`, holding `{ deleted, record }`.\n * OCC mirrors the Warm tier: the token is a monotonic counter (stringified), advanced on every mutation and\n * even across a `delete` (which **tombstones** rather than unlinks) so a deleted-then-recreated row never\n * re-issues an old token (ABA-safe). Every write is temp → fsync(file) → atomic rename → fsync(dir), and\n * read-modify-write is serialized per row in-process. Drivers do I/O; only `core/` is bound by determinism.\n */\nimport { constants as FS } from 'node:fs';\nimport { randomUUID } from 'node:crypto';\nimport { mkdir, open, readdir, rename, unlink } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { IntegrityError, ValidationError, WriteConflictError } from '@/core/errors';\nimport type {\n IRegistryDriver,\n NewRegistryRecord,\n RegCaps,\n RegistryPatch,\n RegistryRecord,\n SegmentRef,\n Token,\n} from '@/core/ports';\nimport {\n applyRegistryPatch,\n parseRegistryEnvelope,\n recordFromNew,\n registryCounterOf,\n serializeRegistryEnvelope,\n validateNewRegistryRecord,\n validateRegistryPatch,\n type RegistryEnvelope,\n} from '../_shared/registry';\nimport { registryDir, registryRowPath, parseRegistryRow } from './paths';\nimport { O_NOFOLLOW, fsyncDir, isCode, mapFsError } from './fs-util';\n\n/** Defensive cap on a single registry file read from storage, before allocation. */\nconst DEFAULT_MAX_ROW_BYTES = 1 * 1024 * 1024;\n\nexport interface LocalFsRegistryDriverOptions {\n /** Injected clock for `createdAt`/`updatedAt`; defaults to `Date.now`. */\n readonly now?: () => number;\n}\n\nexport class LocalFsRegistryDriver implements IRegistryDriver {\n /** Per-row promise chain — serializes read-modify-write so an in-process CAS never loses an update. */\n private readonly chain = new Map<string, Promise<unknown>>();\n private readonly now: () => number;\n\n constructor(\n private readonly root: string,\n options: LocalFsRegistryDriverOptions = {},\n ) {\n this.now = options.now ?? (() => Date.now());\n }\n\n capabilities(): RegCaps {\n return { strongRead: true };\n }\n\n async get(ref: SegmentRef): Promise<RegistryRecord | null> {\n const env = await this.readRow(registryRowPath(this.root, ref));\n return env && !env.deleted ? env.record : null;\n }\n\n async create(ref: SegmentRef, record: NewRegistryRecord): Promise<{ token: Token }> {\n validateNewRegistryRecord(record);\n const path = registryRowPath(this.root, ref);\n return this.withRowLock(path, async () => {\n const current = await this.readRow(path);\n if (current !== null && !current.deleted) {\n throw new WriteConflictError(`registry row already exists for segment ${ref.segment}`);\n }\n const counter = current ? registryCounterOf(current.record) + 1 : 0; // advance across a tombstone (ABA-safe)\n const token = String(counter);\n await this.writeRow(path, false, recordFromNew(ref, record, this.now(), token));\n return { token };\n });\n }\n\n async compareAndSwap(\n ref: SegmentRef,\n expected: Token,\n patch: RegistryPatch,\n ): Promise<{ token: Token }> {\n validateRegistryPatch(patch);\n const path = registryRowPath(this.root, ref);\n return this.withRowLock(path, async () => {\n const current = await this.readRow(path);\n if (current === null || current.deleted || current.record.token !== expected) {\n throw new WriteConflictError(`OCC token mismatch for registry row ${ref.segment}`);\n }\n const token = String(registryCounterOf(current.record) + 1);\n await this.writeRow(\n path,\n false,\n applyRegistryPatch(current.record, patch, this.now(), token),\n );\n return { token };\n });\n }\n\n async *list(namespace?: string): AsyncIterable<RegistryRecord> {\n for (const ns of await this.namespaceDirs(namespace)) {\n const dir = registryDir(this.root, ns);\n let names: string[];\n try {\n names = await readdir(dir);\n } catch (err) {\n if (isCode(err, 'ENOENT')) continue; // no registry rows in this namespace yet\n throw mapFsError(err);\n }\n for (const name of names) {\n const segment = parseRegistryRow(name);\n if (segment === null) continue;\n const env = await this.readRow(registryRowPath(this.root, { namespace: ns, segment }));\n if (env && !env.deleted) yield env.record;\n }\n }\n }\n\n async delete(ref: SegmentRef): Promise<void> {\n const path = registryRowPath(this.root, ref);\n return this.withRowLock(path, async () => {\n const current = await this.readRow(path);\n if (current === null || current.deleted) return; // idempotent\n // Tombstone (advance the counter) rather than unlink — keeps the token monotonic for ABA-safety.\n const token = String(registryCounterOf(current.record) + 1);\n await this.writeRow(path, true, { ...current.record, token, updatedAt: this.now() });\n });\n }\n\n /** Namespaces to scan: just the one requested, or every namespace dir under the root. */\n private async namespaceDirs(namespace: string | undefined): Promise<Array<string | undefined>> {\n if (namespace !== undefined) return [namespace];\n let entries: string[];\n try {\n entries = await readdir(this.root);\n } catch (err) {\n if (isCode(err, 'ENOENT')) return [];\n throw mapFsError(err);\n }\n // A namespace dir name IS the namespace; the `_default` sentinel dir maps back to \"no namespace\".\n return entries.map((e) => (e === '_default' ? undefined : e));\n }\n\n private async readRow(path: string): Promise<RegistryEnvelope | null> {\n let handle;\n try {\n handle = await open(path, FS.O_RDONLY | O_NOFOLLOW);\n } catch (err) {\n if (isCode(err, 'ENOENT') || isCode(err, 'ELOOP')) return null;\n throw mapFsError(err);\n }\n try {\n const { size } = await handle.stat();\n if (size > DEFAULT_MAX_ROW_BYTES) {\n throw new IntegrityError(`registry row ${size}B exceeds cap ${DEFAULT_MAX_ROW_BYTES}B`);\n }\n const text = (await handle.readFile()).toString('utf8');\n return parseRegistryEnvelope(text, path);\n } finally {\n await handle.close();\n }\n }\n\n private async writeRow(path: string, deleted: boolean, record: RegistryRecord): Promise<void> {\n await mkdir(dirname(path), { recursive: true });\n const out = Buffer.from(serializeRegistryEnvelope({ deleted, record }), 'utf8');\n // Cap on the write path too (the read path caps at the same size): never produce a row that would later\n // be unreadable. The governance fields are already capped by validate*, so this is a belt-and-braces guard.\n if (out.length > DEFAULT_MAX_ROW_BYTES) {\n throw new ValidationError(\n `registry row ${out.length}B exceeds cap ${DEFAULT_MAX_ROW_BYTES}B`,\n );\n }\n\n const tmp = `${path}.${randomUUID()}.tmp`;\n let handle;\n try {\n handle = await open(tmp, FS.O_CREAT | FS.O_EXCL | FS.O_WRONLY | O_NOFOLLOW);\n } catch (err) {\n throw mapFsError(err);\n }\n try {\n await handle.write(out);\n await handle.sync();\n } finally {\n await handle.close();\n }\n await rename(tmp, path).catch(async (err) => {\n await unlink(tmp).catch(() => {});\n throw mapFsError(err);\n });\n await fsyncDir(dirname(path));\n }\n\n /** Serialize callbacks for a row path so read-modify-write is atomic in-process (mirrors the Warm tier). */\n private withRowLock<T>(key: string, fn: () => Promise<T>): Promise<T> {\n const prev = this.chain.get(key) ?? Promise.resolve();\n const result = prev.then(fn, fn);\n const tail = result.then(\n () => undefined,\n () => undefined,\n );\n this.chain.set(key, tail);\n void tail.then(() => {\n if (this.chain.get(key) === tail) this.chain.delete(key);\n });\n return result;\n }\n}\n","/**\n * Concrete AES-256-GCM crypto (lives outside `core/`, which lint-bans `node:crypto`). Implements the injected\n * {@link Aead}/{@link IKeystore} seams from `core/crypto`: a `NodeAead` over `aes-256-gcm`, and an in-process\n * **BYOK** keystore that envelope-wraps a per-segment DEK under one or more operator-held KEKs.\n *\n * Default, dependency-free key management: you bring 32-byte KEK(s); we never call a cloud service. KMS/Vault\n * are future optional adapters against the same {@link IKeystore} interface. **The KEK is the\n * one secret to back up** — lose it and that segment's at-rest bytes are unrecoverable by design (re-seed the\n * segment from your source of truth); see the getting-started \"Encryption\" section.\n */\nimport { createCipheriv, createDecipheriv, randomBytes } from 'node:crypto';\nimport type { Aead, AeadSealed, IKeystore, WrappedDek } from '../core/crypto';\nimport { IntegrityError, KeyUnavailableError, ValidationError } from '../core/errors';\n\nconst KEY_BYTES = 32; // AES-256\nconst NONCE_BYTES = 12; // GCM standard nonce\nconst TAG_BYTES = 16; // GCM tag\n\n/** AES-256-GCM AEAD bound to one 32-byte key. A fresh CSPRNG 96-bit nonce per `seal`; `aad` is authenticated,\n * never stored. Nonce-reuse safety: the random-96-bit birthday bound is ~q²/2⁹⁷, negligible below ~2³² seals\n * under one key. A per-segment DEK is **reused across all generations** (compaction re-encrypts under it), so\n * seal count is cumulative over the segment's life — a segment approaching ~2³² lifetime chunk-seals should be\n * re-seeded (a fresh segment ⇒ fresh DEK). Far beyond any realistic workload; noted for completeness. */\nexport class NodeAead implements Aead {\n private readonly key: Buffer;\n\n constructor(key: Uint8Array) {\n if (key.length !== KEY_BYTES)\n throw new ValidationError(`AEAD key must be ${KEY_BYTES} bytes, got ${key.length}`);\n this.key = Buffer.from(key);\n }\n\n seal(plaintext: Uint8Array, aad: Uint8Array): AeadSealed {\n const nonce = randomBytes(NONCE_BYTES);\n const cipher = createCipheriv('aes-256-gcm', this.key, nonce);\n cipher.setAAD(aad);\n const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);\n return { nonce, ciphertext, tag: cipher.getAuthTag() };\n }\n\n open(sealed: AeadSealed, aad: Uint8Array): Uint8Array {\n if (sealed.nonce.length !== NONCE_BYTES || sealed.tag.length !== TAG_BYTES)\n throw new IntegrityError('AEAD nonce/tag have the wrong length');\n const decipher = createDecipheriv('aes-256-gcm', this.key, sealed.nonce);\n decipher.setAAD(aad);\n decipher.setAuthTag(Buffer.from(sealed.tag));\n try {\n return Buffer.concat([decipher.update(sealed.ciphertext), decipher.final()]);\n } catch {\n // Wrong key, tampered ciphertext/tag, or mismatched AAD — never leak which, never return plaintext.\n throw new IntegrityError(\n 'AEAD authentication failed (wrong key, tampered data, or wrong context)',\n );\n }\n }\n}\n\n/** Wrap/unwrap a DEK under a KEK with AES-256-GCM, binding the wrapping to its `keyId` via AAD so a wrapping\n * can't be relabelled to another KEK. Stored blob = nonce ‖ ciphertext ‖ tag, base64. */\nfunction wrapKey(dek: Uint8Array, kek: Uint8Array, keyId: string): string {\n const sealed = new NodeAead(kek).seal(dek, new TextEncoder().encode(keyId));\n return Buffer.concat([sealed.nonce, sealed.ciphertext, sealed.tag]).toString('base64');\n}\n\nfunction unwrapKey(wrapped: string, kek: Uint8Array, keyId: string): Uint8Array {\n const blob = Buffer.from(wrapped, 'base64');\n if (blob.length < NONCE_BYTES + TAG_BYTES)\n throw new IntegrityError('wrapped DEK is too short to be valid');\n const nonce = blob.subarray(0, NONCE_BYTES);\n const tag = blob.subarray(blob.length - TAG_BYTES);\n const ciphertext = blob.subarray(NONCE_BYTES, blob.length - TAG_BYTES);\n return new NodeAead(kek).open({ nonce, ciphertext, tag }, new TextEncoder().encode(keyId));\n}\n\n/**\n * Options for {@link InProcessKeystore}. `keys` maps a `keyId` → its 32-byte KEK; `activeKeyId` names the KEK\n * new DEKs are wrapped under; an optional `recoveryKeyId` additionally wraps each new DEK under a second\n * (e.g. offline) KEK, so losing the active KEK isn't fatal. Rotating the active KEK needs no data\n * re-encryption: add the new KEK, point `activeKeyId` at it, keep the old one to unwrap existing segments.\n */\nexport interface InProcessKeystoreOptions {\n readonly keys: Readonly<Record<string, Uint8Array>>;\n readonly activeKeyId: string;\n readonly recoveryKeyId?: string;\n}\n\n/**\n * Dependency-free BYOK keystore: envelope-wraps a fresh random per-segment DEK under the active (and optional\n * recovery) KEK using `node:crypto`. No external service. The raw DEK never leaves a returned {@link NodeAead}.\n */\nexport class InProcessKeystore implements IKeystore {\n private readonly keys: Map<string, Uint8Array>;\n private readonly activeKeyId: string;\n private readonly recoveryKeyId: string | undefined;\n\n constructor(options: InProcessKeystoreOptions) {\n const entries = Object.entries(options.keys);\n if (entries.length === 0) throw new ValidationError('keystore needs at least one KEK');\n for (const [id, k] of entries) {\n if (k.length !== KEY_BYTES)\n throw new ValidationError(`KEK \"${id}\" must be ${KEY_BYTES} bytes, got ${k.length}`);\n }\n if (!(options.activeKeyId in options.keys))\n throw new ValidationError(`activeKeyId \"${options.activeKeyId}\" is not in keys`);\n if (options.recoveryKeyId !== undefined && !(options.recoveryKeyId in options.keys))\n throw new ValidationError(`recoveryKeyId \"${options.recoveryKeyId}\" is not in keys`);\n this.keys = new Map(entries.map(([id, k]) => [id, Buffer.from(k)]));\n this.activeKeyId = options.activeKeyId;\n this.recoveryKeyId =\n options.recoveryKeyId === options.activeKeyId ? undefined : options.recoveryKeyId;\n }\n\n // async to satisfy the IKeystore seam (a KMS adapter awaits a network call here); the in-process path is\n // synchronous, but staying async keeps unwrap failures as rejections, matching a remote keystore.\n async createDek(): Promise<{ wrapped: WrappedDek[]; aead: Aead }> {\n const dek = randomBytes(KEY_BYTES);\n const ids = this.recoveryKeyId ? [this.activeKeyId, this.recoveryKeyId] : [this.activeKeyId];\n const wrapped = ids.map((keyId) => ({\n keyId,\n wrapped: wrapKey(dek, this.keys.get(keyId)!, keyId),\n }));\n return { wrapped, aead: new NodeAead(dek) };\n }\n\n // async for the same reason as createDek — a synchronous unwrap failure surfaces as a promise rejection.\n async openDek(wrapped: readonly WrappedDek[]): Promise<Aead> {\n // Try EVERY held wrapping, not just the first: a DEK is wrapped under both the active KEK and (if\n // configured) the offline recovery KEK precisely so a damaged/tampered active-KEK wrapping can be\n // recovered from the other. Returning on the first held keyId and letting a corrupt unwrap throw would\n // defeat that insurance — the recovery wrapping would never be attempted. So catch a failed unwrap and\n // fall through to the next held wrapping; only give up once none succeeds.\n let anyKekHeld = false;\n let lastUnwrapError: unknown;\n for (const w of wrapped) {\n const kek = this.keys.get(w.keyId);\n if (kek === undefined) continue;\n anyKekHeld = true;\n try {\n return new NodeAead(unwrapKey(w.wrapped, kek, w.keyId));\n } catch (err) {\n lastUnwrapError = err; // held KEK but this wrapping is corrupt/tampered — try the next one\n }\n }\n // A KEK WAS held but every held wrapping failed to unwrap → the wrapping(s) are corrupt/tampered, not\n // missing. Surface that integrity failure in its original type rather than masking it as \"no held KEK\".\n if (anyKekHeld) throw lastUnwrapError;\n const have = [...this.keys.keys()].join(', ') || '(none)';\n const need = wrapped.map((w) => w.keyId).join(', ') || '(none)';\n throw new KeyUnavailableError(\n `no held KEK can unwrap this DEK — have [${have}], wrappings reference [${need}]. ` +\n `Restore the missing KEK (or its recovery KEK), or rebuild the segment from source.`,\n );\n }\n}\n","/**\n * Crypto-shred erasure (Phase 4e).\n *\n * GDPR \"right to erasure\" on immutable/backed-up Cold storage: you can't delete a `.crbm` object from every\n * backup, but you can **delete its key**. `destroySegment` drops the segment's wrapped DEK(s) from the registry\n * (a CAS to a `destroyed` tombstone) — the encrypted Cold bytes are then permanently unreadable, everywhere,\n * forever — and physically deletes the segment's (cleartext) Warm rows. **Immediate + irreversible**, so it's\n * gated behind an explicit confirmation (name the exact segment/namespace). A `destroyed` segment reads as\n * empty (its DEK is gone). Only works on an **encrypted** segment; a cleartext segment has no key to shred.\n *\n * Note (scope): this shreds the Cold key + clears Warm rows present *now*. Preventing *new* writes to a\n * destroyed segment (a registry-checked write path) is a later hardening; the write path stays uncoupled today.\n */\nimport { type IAuditSink, NOOP_AUDIT, safeAudit } from './audit';\nimport { mapWithConcurrency } from './concurrency';\nimport { ValidationError, WriteConflictError, isWriteConflictError } from './errors';\nimport type { ChunkRef, IColdDriver, IRegistryDriver, IWarmDriver, SegmentRef } from './ports';\n\nexport interface EraseDeps {\n readonly registry: IRegistryDriver;\n readonly warm: IWarmDriver;\n}\n\nexport interface DestroyResult {\n readonly segment: string;\n readonly namespace?: string;\n /** True iff the segment is now a `destroyed` tombstone (incl. the idempotent already-destroyed case). */\n readonly destroyed: boolean;\n /**\n * True iff **this call** performed a genuine crypto-shred — an encrypted segment whose wrapped DEK(s) were\n * dropped, so its Cold bytes are now permanently unreadable. False for a cleartext tombstone (bytes remain\n * readable), for the idempotent already-destroyed case, and for an absent segment. This is what the\n * `segment.erase` audit event keys off — a cleartext \"erase\" is not an irreversible destruction.\n */\n readonly cryptoShredded: boolean;\n /**\n * Why this segment was not a fresh crypto-shred. `'absent'` (no registry row), `'already'` (already\n * destroyed), `'cleartext'` (no DEK to shred) — and from `eraseNamespace` only, where per-segment faults are\n * isolated so one failure cannot discard the ledger: `'contended'` (warm rows were rewritten during every\n * erase pass) or `` `failed: <message>` `` (any other fault).\n *\n * The last two come with `destroyed: false` and mean **the segment still holds data**. A namespace erase\n * returns them rather than throwing, so its entries have to be inspected — see {@link eraseNamespace}.\n */\n readonly reason?: string;\n /** Warm rows physically deleted as part of the erase. */\n readonly warmRowsDeleted: number;\n}\n\nconst MAX_CAS_ATTEMPTS = 8;\nconst MAX_WARM_PASSES = 4;\n/**\n * Deletes in flight at once, for both the Warm rows and the Cold generations.\n *\n * Serial was the first cut and it is the wrong shape for this path: erasure is a fan-out over *independent*\n * keys, so a segment with 400 warm chunks paid 400 sequential round-trips (~20 s at 50 ms) for work that has no\n * ordering between items. This is the same bound `engine.writeConcurrency` and `S3RegistryDriver`'s\n * `LIST_READ_CONCURRENCY` already apply to the same kind of fan-out; the ceiling matters because an unbounded\n * `Promise.all` over a large segment is a self-inflicted thundering herd against one table/bucket.\n *\n * Not configurable: this is an admin path called by a human or a nightly job, so a knob would be surface with no\n * caller. If a deployment ever needs it tuned, it becomes an option then.\n */\nconst ERASE_CONCURRENCY = 8;\n/**\n * Cold list-then-delete passes a drop will make before giving up and reporting the residual.\n *\n * Two is the honest floor and three is the working value: pass 1 clears what was there, pass 2 catches a\n * generation staged by a compaction that was already in flight when the tombstone landed, pass 3 covers a second\n * such worker. It terminates regardless — the tombstone hard-fences *starting* a new generation, so the supply of\n * late stagings is whatever was already running, and any residual is reported rather than silently dropped.\n */\nconst MAX_COLD_SWEEPS = 3;\n\n/**\n * Crypto-shred one segment. **Irreversible.** `confirmSegment` must equal `ref.segment` (a guard against an\n * accidental destroy — you must name the exact segment). A non-encrypted segment is rejected unless you opt in\n * via `allowCleartext` (there's no key to shred; its Cold bytes stay readable, only Warm is cleared).\n */\nexport async function destroySegment(\n ref: SegmentRef,\n deps: EraseDeps,\n options: { confirmSegment: string; allowCleartext?: boolean; audit?: IAuditSink },\n): Promise<DestroyResult> {\n if (options.confirmSegment !== ref.segment) {\n throw new ValidationError(\n `destroySegment: confirmSegment must equal the segment name \"${ref.segment}\" (guard against accidental crypto-shred)`,\n );\n }\n const result = await shredSegment(ref, deps, options.allowCleartext ?? false);\n // Audit only a genuine crypto-shred — not the idempotent already-destroyed/absent no-ops, and not a\n // cleartext tombstone (whose Cold bytes stay readable, so it is not an irreversible erasure).\n if (result.cryptoShredded) {\n safeAudit(options.audit ?? NOOP_AUDIT).onEvent({\n kind: 'segment.erase',\n namespace: ref.namespace,\n segment: ref.segment,\n });\n }\n return result;\n}\n\n/**\n * Crypto-shred every segment in a namespace. **Irreversible.** `confirmNamespace` must equal `namespace`.\n * Returns a per-segment result (skips cleartext segments unless `allowCleartext`).\n */\nexport async function eraseNamespace(\n namespace: string,\n deps: EraseDeps,\n options: { confirmNamespace: string; allowCleartext?: boolean; audit?: IAuditSink },\n): Promise<{ destroyed: DestroyResult[] }> {\n if (typeof namespace !== 'string' || namespace.length === 0) {\n throw new ValidationError('eraseNamespace: namespace must be a non-empty string');\n }\n if (options.confirmNamespace !== namespace) {\n throw new ValidationError(\n `eraseNamespace: confirmNamespace must equal the namespace \"${namespace}\" (guard against accidental erasure)`,\n );\n }\n const refs: SegmentRef[] = [];\n for await (const rec of deps.registry.list(namespace)) {\n refs.push({ namespace: rec.namespace, segment: rec.segment });\n }\n const audit = safeAudit(options.audit ?? NOOP_AUDIT);\n const destroyed: DestroyResult[] = [];\n let segmentsShredded = 0;\n for (const ref of refs) {\n // Per-segment faults stay isolated so one failure cannot discard the ledger, mirroring `eraseSubject`'s\n // entries (\"one failure never aborts the ledger\") and for the same reason: on an erasure command the\n // caller's load-bearing question is *which segments are now destroyed*, and an exception thrown from the\n // middle of the loop answers it for none of them while having already destroyed some.\n //\n // Every error is caught, not just contention — again matching `eraseSubject`, which records any thrown\n // fault as a ledger entry rather than deciding which faults deserve a record. A `KeyUnavailableError` on\n // segment 3 is exactly as important to report as a `WriteConflictError`, and just as segment-local.\n //\n // NOTE the caller's obligation, because this is quieter than a throw: entries must be INSPECTED.\n // `destroyed: false` with a `reason` is a segment that still holds data. The `namespace.erase` audit event\n // carries the honest `segmentsShredded` count, which will be lower than the segment count, so an audit\n // trail still shows the shortfall even if the return value is ignored.\n let result: DestroyResult;\n try {\n result = await shredSegment(ref, deps, options.allowCleartext ?? false);\n } catch (err) {\n result = {\n segment: ref.segment,\n namespace: ref.namespace,\n destroyed: false,\n cryptoShredded: false,\n reason: isWriteConflictError(err)\n ? 'contended'\n : `failed: ${err instanceof Error ? err.message : String(err)}`,\n // Deliberately 0, and not a partial count. `eraseWarm` may have deleted rows before it threw, but the\n // erase did not complete as a unit, so a partial figure on a failed entry would invite reading it as\n // progress toward a destruction that did not happen. The attestation that matters is `destroyed`.\n warmRowsDeleted: 0,\n };\n }\n destroyed.push(result);\n // A per-segment record for each genuine crypto-shred, so the trail can prove *which* segments were\n // destroyed (each carries the namespace) — not just that the command ran.\n if (result.cryptoShredded) {\n segmentsShredded += 1;\n audit.onEvent({ kind: 'segment.erase', namespace: ref.namespace, segment: ref.segment });\n }\n }\n // Plus one namespace-level record of the erasure command, carrying the honest count actually shredded\n // (may be 0 — e.g. an empty namespace, or all-cleartext without `allowCleartext`): the command ran, but\n // the count keeps the record from over-attesting a destruction that did not happen.\n audit.onEvent({ kind: 'namespace.erase', namespace, segmentsShredded });\n return { destroyed };\n}\n\n/**\n * Deps for {@link dropSegment}. Adds `cold`, because unlike a crypto-shred this one deletes the objects.\n */\nexport interface DropDeps extends EraseDeps {\n readonly cold: IColdDriver;\n}\n\nexport interface DropResult {\n readonly segment: string;\n readonly namespace?: string;\n /**\n * **True iff this segment is now empty as a result of this call — or already was.** This is the field a\n * retention job should branch on: `false` means the call found nothing to do and your ref is probably wrong.\n *\n * It is *not* simply \"a tombstone exists\", and that distinction is load-bearing. A **pure accumulator**\n * segment — one created by writing to it and never compacted, so it has no registry row and no Cold objects —\n * is retired by deleting its Warm rows alone, with no tombstone to write. That reports `dropped: true` with\n * `reason: 'warm-only'`, because the data really is gone. Reporting it as `false` (which it did until\n * `0.8.2`) made every successful retirement of an accumulator look like a failure.\n */\n readonly dropped: boolean;\n /** Warm rows physically deleted. */\n readonly warmRowsDeleted: number;\n /** Cold generations physically deleted, ascending. Empty on a dry run — see {@link DropResult.wouldDelete}. */\n readonly generationsDeleted: readonly number[];\n /**\n * Generations still present in Cold when the sweep gave up, ascending. **Empty is the normal outcome** — a\n * non-empty value means the storage was NOT fully reclaimed and the drop should be re-run.\n *\n * This field exists because its absence was a defect. `dropped: true` with a populated `generationsDeleted`\n * and no `reason` used to be returned even when a `.crbm` holding the **complete effective set** had just been\n * left in the bucket by a compaction that was already mid-flight (it stages from data it read before the\n * tombstone, so its commit fails on the voided lease but its object survives). For a cleartext segment those\n * bytes are readable — and nothing in the library reclaimed them, because `gcOrphanGenerations` only considers\n * generations *below* `currentGen` and `checkConsistency` skips destroyed segments. The result was\n * indistinguishable from a clean drop, so an operator got no signal to re-run. Now they do.\n */\n readonly generationsRemaining: readonly number[];\n /**\n * On a dry run, the generations that **would** be deleted. `undefined` on a real run.\n *\n * This exists because the confirmation guard the erasure calls use — naming the segment twice — protects a\n * hand-typed literal and nothing else. In the loop this operation is actually *for*\n * (`for (const day of expired) drop({segment: day}, {confirmSegment: day})`) the same variable appears twice\n * and the guard is pure ceremony. A dry run is the guard that still works when a machine is calling.\n *\n * It is a **snapshot**: a later real run can see a different set.\n */\n readonly wouldDelete?: readonly number[];\n /**\n * On a dry run, how many Warm rows would be deleted. `undefined` on a real run.\n *\n * Previewing only the Cold generations was a gap: Warm rows hold **cleartext** deltas, so for the automated\n * caller this preview exists for, \"how much unencrypted data is about to go\" is at least as load-bearing as\n * the object count.\n */\n readonly wouldDeleteWarmRows?: number;\n /**\n * On a dry run, whether the real drop would **also** crypto-shred (i.e. the segment is encrypted).\n * `undefined` on a real run. This is the one fact in the preview that is irreversible *everywhere*, backups\n * included — a dry run that did not surface it was previewing the recoverable half only.\n */\n readonly wouldCryptoShred?: boolean;\n /**\n * True iff the segment was encrypted and its wrapped DEK(s) were dropped as part of this call — so its bytes\n * are unreadable *everywhere*, backups included, not merely deleted from the bucket. Deleting an object does\n * not reach a noncurrent version, a replica, or a PITR snapshot; discarding the key does.\n */\n readonly cryptoShredded: boolean;\n /**\n * How the segment got to its current state. Absent on a fresh, ordinary drop (tombstone written, Cold swept).\n *\n * - `'warm-only'` — **a successful retirement.** No registry row and no Cold objects, so this was an accumulator\n * segment: its Warm rows were deleted and it now reads empty. Pairs with `dropped: true`.\n * - `'already'` — it was already a tombstone. Idempotent; pairs with `dropped: true`. Note a re-drop is **not**\n * a no-op — it also clears Warm rows that landed after the tombstone.\n * - `'absent'` — **nothing existed.** No registry row, no Cold objects, and no Warm rows to delete. Pairs with\n * `dropped: false`, and it is the one value worth alerting on: the usual cause is a mistyped name or an\n * omitted `namespace`, both of which address a *different* segment than you meant.\n *\n * Two things `'absent'` used to mean and no longer does: it was returned while the call deleted every Cold\n * generation it found with no tombstone written (a data-integrity bug, fixed in `0.8.0`), and it was returned\n * for a successfully retired accumulator segment (misleading, fixed in `0.8.2`).\n */\n readonly reason?: string;\n}\n\n/**\n * **Dispose of a segment: tombstone it, delete its Warm rows, and delete its Cold objects.** Irreversible.\n *\n * WHY THIS EXISTS, given {@link destroySegment} already erases. Because `destroySegment` answers a *compliance*\n * question and this one answers an *operational* question, and they are not the same:\n *\n * - `destroySegment` **crypto-shreds** — it discards the key so the bytes are unreadable everywhere including\n * immutable backups, which is the only erasure that survives WORM. But it **leaves the objects in the\n * bucket**, still billed, and it *requires* encryption because a cleartext segment has no key to discard.\n * - `dropSegment` **removes the storage**. It works on a cleartext segment, and on an encrypted one it *also*\n * drops the DEKs, so it is a strict superset there.\n *\n * Before this existed there was no supported way to delete a segment and stop paying for it, and the obvious\n * workaround — an object-store lifecycle rule on the key prefix — deletes the bytes while the registry still\n * points at them. That is exactly the `missing-cold-generation` state the DR runbook says not to serve traffic\n * on, and it surfaces *intermittently*, because a read consults the hot cache before Cold: cached chunks answer\n * correctly and evicted ones throw. The whole value of this function is that the ordering below cannot be got\n * wrong by a caller.\n *\n * **THE ORDER IS THE CONTRACT — Warm, then registry, then Cold.** Each step is placed against a specific way\n * the other orders break:\n *\n * 1. **Warm first.** A `destroyed` row makes Cold read as empty, but Warm is consulted *separately* and earlier\n * on the read path — so a tombstone with live Warm deltas still answers `true` for ids in those deltas.\n * (This is why {@link shredSegment} already orders it this way; the reasoning is inherited, not invented.)\n * **Necessary, but not sufficient** — see \"writes must have stopped\" below.\n * 2. **Registry second.** After the tombstone nothing resolves a generation for this segment, so no reader can\n * reach for bytes that are about to disappear.\n * 3. **Cold last, best-effort, and re-swept.** Once the pointer is a tombstone the segment resolves as empty, so\n * a failure part-way through leaves **orphaned bytes, not a wrong answer.** Orphans cost money and are cleaned\n * up by re-running; a torn pointer costs correctness and is not self-healing. Given the choice, leak bytes —\n * but say so: whatever survives the sweep is reported in {@link DropResult.generationsRemaining}.\n *\n * **Why step 3 sweeps more than once.** A compaction that was already mid-flight when the tombstone landed will\n * still finish *staging* a fresh generation, built from data it read beforehand — its commit then fails on the\n * lease the tombstone voided, but the object it wrote survives, and it holds the complete effective set including\n * the Warm deltas step 1 just deleted. A single list-then-delete misses it entirely. The re-sweep converges\n * because the tombstone *is* a hard fence on **starting** a new generation (compaction returns `destroyed`\n * before it does anything), so only already-in-flight stagings can appear and they are finite.\n *\n * **Writes must have stopped.** Nothing here prevents a *new* Warm write after step 1 (the write path is\n * deliberately uncoupled — see this module's header). For `destroySegment` that is a scope note; here it is\n * sharper, because a Warm row that lands after the tombstone is **immortal**: compaction refuses to fold or purge\n * a destroyed segment, so nothing ever reaps it, and a fresh reader will report the dropped segment as non-empty\n * *forever*. Step 1 therefore runs a second time after the tombstone, which converges for anything in flight at\n * drop time — but a writer that keeps writing will keep resurrecting the segment. Stop writes first, or re-run.\n *\n * **When \"reads as empty\" starts being true.** Not instantly, for a store that has already read this segment: a\n * resolved generation is cached and decoded chunks sit in the hot LRU, so an in-flight reader can answer from\n * cache for a window. A fresh store, or any reader that had not touched the segment, sees empty at once.\n *\n * That window is bounded by `coldGenTtlMs` (default 2 s) **only for a reader whose cold source has both a clock\n * and a registry and a positive TTL** — expiry needs all three. A source built without a clock, or with\n * `coldGenTtlMs: 0` (documented as \"pin forever\"), holds its resolved snapshot for its own lifetime; because a\n * hot-LRU hit never reaches Cold, such a reader can answer `true` for a dropped segment **indefinitely** and must\n * be restarted. This is the *same* caching that makes the delete-bytes-first ordering fail intermittently rather\n * than loudly — it cuts both ways.\n *\n * `confirmSegment` must equal `ref.segment`, matching `destroySegment`/`eraseNamespace`. For an automated\n * caller that guard is ceremony — use `dryRun` first, which reports what would go without touching anything.\n */\nexport async function dropSegment(\n ref: SegmentRef,\n deps: DropDeps,\n options: { confirmSegment: string; dryRun?: boolean; audit?: IAuditSink },\n): Promise<DropResult> {\n if (options.confirmSegment !== ref.segment) {\n throw new ValidationError(\n `dropSegment: confirmSegment must equal the segment name \"${ref.segment}\" (guard against accidental deletion)`,\n );\n }\n const base = { segment: ref.segment, namespace: ref.namespace };\n\n if (options.dryRun === true) {\n const record = await deps.registry.get(ref);\n const wouldDelete = await listGenerations(deps.cold, ref);\n return {\n ...base,\n dropped: false,\n warmRowsDeleted: 0,\n generationsDeleted: [],\n generationsRemaining: [],\n wouldDelete,\n wouldDeleteWarmRows: await countWarmRows(deps.warm, ref),\n wouldCryptoShred: record?.wrappedDeks !== undefined && record.wrappedDeks.length > 0,\n cryptoShredded: false,\n reason:\n record === null\n ? wouldDelete.length === 0\n ? 'absent'\n : undefined\n : record.status === 'destroyed'\n ? 'already'\n : undefined,\n };\n }\n\n // Steps 1 and 2, reused wholesale. `allowCleartext` is true because deleting objects does not need a key —\n // the encryption requirement belongs to crypto-shred, not to disposal.\n let shred = await shredSegment(ref, deps, true, 'dropSegment');\n\n // ── THE ABSENT CASE. ───────────────────────────────────────────────────────────────────────────────────────\n // `shredSegment` returns `absent` having written NOTHING when there is no registry row — and this function used\n // to go on and delete every Cold generation anyway. That skipped the one step that makes the ordering safe\n // while still running the destructive one, and it produced two measured disasters, both from ordinary\n // interleavings:\n //\n // - A drop landing between `bulkLoadCrbmGeneration`'s object write and its `publishGeneration` (minutes apart\n // on a large load) left `currentGen: 0`, `status: 'active'` and no object — precisely the\n // `missing-cold-generation` state this function exists to PREVENT. Reads threw; nothing self-healed it,\n // because `publishGeneration`'s destroyed-fence has no row to check on the create path.\n // - A drop during a compaction bootstrap (which had already pinned the Warm rows in memory) deleted those\n // rows, reported `absent`, and then watched the bootstrap write them back to Cold and `create` an ACTIVE\n // row. Full resurrection, with no tombstone anywhere.\n //\n // The fix is to claim the identity before deleting anything. A `destroyed` row is exactly the fence the three\n // writers already respect — `publishGeneration`, `bulkLoadCrbmGeneration` and `compactSegmentInner` all refuse\n // one — so creating it converts both disasters into \"the writer is refused and the bytes are collected\".\n //\n // Only when Cold actually holds something, though. A drop against a *genuinely* nonexistent segment (the\n // typo the facade docs warn about) must not leave a `destroyed` row behind: that is registry litter, and worse,\n // it would refuse a later legitimate load of that name forever. No row and no objects ⇒ nothing existed ⇒ say\n // `absent` and touch nothing, which is what that reason has always been documented to mean.\n if (shred.reason === 'absent') {\n const orphans = await listGenerations(deps.cold, ref);\n if (orphans.length === 0) {\n // Nothing in Cold and no registry row. Two very different situations reach here, and reporting them\n // identically was a defect — found by the first real consumer, whose whole workload lives in this shape.\n //\n // A **pure accumulator** segment (created by writing to it, never compacted, so it has no registry row and\n // no Cold objects — the documented and supported way to use this as a runtime set) has now had its Warm\n // rows deleted. Its data is gone: a fresh reader sees `count() === 0`. That is a successful retirement, and\n // it used to be reported as `dropped: false, reason: 'absent'` *with* a non-zero `warmRowsDeleted` — which\n // is self-contradictory, and which a retention cron written as `if (!res.dropped) alert()` would alarm on\n // every single time it worked.\n //\n // A **genuinely nonexistent** segment — the typo the facade docs warn about — deleted nothing, and that one\n // SHOULD alarm.\n //\n // So `dropped` now answers the question callers actually ask: *is this segment empty as a result of this\n // call (or already was)?* `reason` says which route got there. There is deliberately still no tombstone in\n // either case: a `destroyed` row for every retired accumulator would be registry litter, and for a typo'd\n // name it would refuse that name forever.\n const clearedWarmOnly = shred.warmRowsDeleted > 0;\n return {\n ...base,\n dropped: clearedWarmOnly,\n warmRowsDeleted: shred.warmRowsDeleted,\n generationsDeleted: [],\n generationsRemaining: [],\n cryptoShredded: false,\n reason: clearedWarmOnly ? 'warm-only' : 'absent',\n };\n }\n try {\n await deps.registry.create(ref, {\n // The max listed generation, so the row is consistent with what is on disk if anything reads it before\n // the sweep finishes. It is a tombstone, so no reader resolves through it either way.\n currentGen: orphans[orphans.length - 1]!,\n status: 'destroyed',\n });\n shred = { ...shred, destroyed: true, reason: undefined };\n } catch (err) {\n if (!isWriteConflictError(err)) throw err;\n // A row appeared between our `get` and our `create` — that is the racing writer we were trying to fence,\n // and it won. Fall back into the normal path, which now has a row to CAS into a tombstone.\n shred = await shredSegment(ref, deps, true, 'dropSegment');\n }\n }\n\n // Step 1, again. A Warm write that landed after the first pass would otherwise be IMMORTAL: compaction returns\n // `destroyed` before it can fold or purge it, so nothing in the system ever reaps it and a fresh reader reports\n // this \"dropped\" segment as non-empty forever. This second pass converges for anything in flight at drop time.\n // It runs after the tombstone deliberately — that ordering is safe here precisely because the tombstone is\n // already written, so there is no window in which a destroyed pointer coexists with live deltas we have not\n // tried to clear.\n const lateWarmRows = shred.destroyed ? await eraseWarmQuietly(deps.warm, ref) : 0;\n\n // `segment.erase` ONLY on a genuine crypto-shred — exactly the condition `destroySegment` uses, and\n // deliberately NOT `|| generationsDeleted.length > 0`.\n //\n // It read that way in the first draft, and it was wrong in a way that matters. Four documents — including\n // `docs/guide/dashboards.md`, which calls this event the compliance *receipt* — define `segment.erase` as\n // proof of an irreversible crypto-shred: bytes unreadable everywhere, backups included. Deleting an object is\n // a weaker guarantee, because a noncurrent version, a cross-region replica or a PITR snapshot still holds the\n // cleartext. Emitting one event for both would make a compliance dashboard **over-attest**, which is the one\n // failure an audit trail exists to prevent.\n //\n // The cleartext case is NOT silent — it emits `segment.dispose` after the sweep (below). That kind exists\n // precisely so this one does not have to lie: disposal is attested as disposal, shredding as shredding, and an\n // encrypted drop emits both because both genuinely happened.\n //\n // And it goes out BEFORE the Cold sweep, not after. A genuine crypto-shred is complete the moment\n // `shredSegment` returns — the DEK wrappings are gone and the bytes are unreadable everywhere. If the sweep\n // then throws (a Cold driver that cannot list), emitting afterwards would mean **no receipt for a destruction\n // that really happened** — the exact mirror of the over-attestation above, and just as wrong. Both directions\n // of a false audit trail are defects; only one of them was obvious.\n if (shred.cryptoShredded) {\n safeAudit(options.audit ?? NOOP_AUDIT).onEvent({\n kind: 'segment.erase',\n namespace: ref.namespace,\n segment: ref.segment,\n });\n }\n\n // Step 3, swept until Cold comes back empty. See \"Why step 3 sweeps more than once\" above: a compaction already\n // mid-flight when the tombstone landed still finishes *staging* a generation, so one list-then-delete can miss\n // an object holding the complete effective set. `mapWithConcurrency` returns results in *input* order, so each\n // pass contributes ascending generations and the concatenation stays ascending. Failures are swallowed per item\n // so the pool never aborts — one unreachable generation must not leave the rest orphaned too.\n const generationsDeleted: number[] = [];\n for (let pass = 0; pass < MAX_COLD_SWEEPS; pass++) {\n const present = await listGenerations(deps.cold, ref);\n if (present.length === 0) break;\n const outcomes = await mapWithConcurrency(present, ERASE_CONCURRENCY, async (generation) => {\n try {\n await deps.cold.delete({ ...ref, generation });\n return generation;\n } catch {\n // Leave it orphaned. The segment already reads as empty, so this is a billing problem, not a\n // correctness one, and re-running the drop collects whatever was missed.\n return null;\n }\n });\n let deletedThisPass = 0;\n for (const g of outcomes) {\n if (g !== null) {\n generationsDeleted.push(g);\n deletedThisPass += 1;\n }\n }\n if (deletedThisPass === 0) break; // nothing went — another pass will not help\n }\n // Enumerate once more rather than inferring the residual from the last pass, so the reported value is exactly\n // what is still in Cold whichever way the loop ended: empty, a delete that kept failing, or the pass budget\n // exhausted while a compaction kept staging. Inferring it would report `[]` in precisely the case that matters\n // — a final pass that deleted everything it saw, after which one more object appeared.\n const generationsRemaining = await listGenerations(deps.cold, ref);\n\n // `segment.dispose` attests the *storage reclamation*, which is the weaker but still compliance-relevant fact,\n // and it is emitted AFTER the sweep because unlike a crypto-shred it is not established until the sweep runs.\n // Only when a tombstone was actually written — an absent no-op disposed of nothing.\n if (shred.destroyed) {\n safeAudit(options.audit ?? NOOP_AUDIT).onEvent({\n kind: 'segment.dispose',\n namespace: ref.namespace,\n segment: ref.segment,\n generationsDeleted: generationsDeleted.length,\n });\n }\n\n return {\n ...base,\n dropped: shred.destroyed,\n warmRowsDeleted: shred.warmRowsDeleted + lateWarmRows,\n generationsDeleted,\n generationsRemaining,\n cryptoShredded: shred.cryptoShredded,\n reason: shred.reason,\n };\n}\n\n/**\n * Every generation currently present in Cold for a segment, ascending.\n *\n * No error handling on purpose: `IColdDriver.list` is mandatory (not optional in `ports.ts`), so a driver that\n * cannot list cannot exist, and one that *throws* from `list` should propagate. (An earlier version of this\n * comment claimed it \"tolerates a driver that cannot list\", describing a `try`/`catch` that was never written.)\n *\n * **Be precise about what a throw means at each call site**, because a previous version of this comment was not.\n * From the `dryRun` branch it is accurate that the call \"has established nothing\". From the real run it is NOT:\n * by then the tombstone is written and the Warm rows are gone, so the segment IS dropped and only the bytes\n * leaked. The throw is still the right behaviour — it is the signal to re-run, and a re-run takes the `'already'`\n * path and re-attempts the sweep — but a caller who logs \"drop failed\" is wrong about the segment's state. This is\n * also why the audit event is emitted *before* the sweep: an irreversible crypto-shred that really happened must\n * not go unrecorded because a later, weaker step threw.\n */\nasync function listGenerations(cold: IColdDriver, ref: SegmentRef): Promise<number[]> {\n const generations: number[] = [];\n for await (const key of cold.list(ref)) generations.push(key.generation);\n return generations.sort((a, b) => a - b);\n}\n\n/**\n * Count the Warm rows a drop would delete, for {@link DropResult.wouldDeleteWarmRows}. Read-only.\n */\nasync function countWarmRows(warm: IWarmDriver, ref: SegmentRef): Promise<number> {\n let n = 0;\n for await (const _row of warm.listChunks(ref)) {\n void _row;\n n += 1;\n }\n return n;\n}\n\n/**\n * {@link eraseWarm}, but a contention failure is reported as \"cleared nothing\" instead of thrown.\n *\n * Used only for the **second** Warm pass, after the tombstone. Throwing there would be wrong in both directions:\n * the drop has already succeeded at everything the caller asked for (tombstone written, original rows cleared),\n * and a throw would discard that truthful result *and* skip the Cold sweep, so contention from a writer that\n * refuses to stop would make the storage permanently unreclaimable. A row this pass cannot clear is a row a\n * subsequent drop will clear; the pass exists to converge, not to gate.\n */\nasync function eraseWarmQuietly(warm: IWarmDriver, ref: SegmentRef): Promise<number> {\n try {\n return await eraseWarm(warm, ref, 'dropSegment');\n } catch (err) {\n if (!isWriteConflictError(err)) throw err;\n return 0;\n }\n}\n\n/**\n * The shred itself: clear Warm rows, then CAS the registry row to a `destroyed` tombstone with no wrappings.\n *\n * `op` is only for error text — `destroySegment` and `dropSegment` both come through here, and a message naming\n * the wrong one is operator-facing text on the single path where the operator must act.\n */\nasync function shredSegment(\n ref: SegmentRef,\n deps: EraseDeps,\n allowCleartext: boolean,\n op: 'destroySegment' | 'dropSegment' = 'destroySegment',\n): Promise<DestroyResult> {\n const base = { segment: ref.segment, namespace: ref.namespace };\n // Hoisted, and accumulated across attempts. Declaring it inside the loop meant only the LAST attempt's tally\n // survived: one benign concurrent registry write (`findCompactable`'s change-guarded CAS, `bumpFailure`, a lease\n // acquisition) made attempt 1's CAS conflict, and attempt 2 re-listed an already-empty Warm set — so the call\n // reported `warmRowsDeleted: 0` having physically deleted every row. On a right-to-erasure record that is\n // under-attestation, which is the same class of defect as over-attesting, pointed the other way.\n let warmRowsDeleted = 0;\n for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {\n const record = await deps.registry.get(ref);\n if (record === null) {\n // No authoritative row → nothing to crypto-shred. Still clear any stray Warm rows.\n warmRowsDeleted += await eraseWarm(deps.warm, ref, op);\n return {\n ...base,\n destroyed: false,\n cryptoShredded: false,\n reason: 'absent',\n warmRowsDeleted,\n };\n }\n if (record.status === 'destroyed') {\n warmRowsDeleted += await eraseWarm(deps.warm, ref, op);\n return {\n ...base,\n destroyed: true,\n cryptoShredded: false,\n reason: 'already',\n warmRowsDeleted,\n };\n }\n const encrypted = record.wrappedDeks !== undefined && record.wrappedDeks.length > 0;\n if (!encrypted && !allowCleartext) {\n return {\n ...base,\n destroyed: false,\n cryptoShredded: false,\n reason: 'cleartext',\n warmRowsDeleted,\n };\n }\n // Clear Warm first (cleartext deltas), then flip the tombstone so a reader never sees a destroyed pointer\n // with live Warm data lingering.\n warmRowsDeleted += await eraseWarm(deps.warm, ref, op);\n try {\n await deps.registry.compareAndSwap(ref, record.token, {\n status: 'destroyed',\n wrappedDeks: undefined, // ← the crypto-shred: the only copy of the DEK wrappings is gone\n keyId: undefined,\n leaseOwner: undefined,\n leaseExpiresAt: undefined,\n });\n // A genuine crypto-shred only when there were wrappings to drop; a cleartext opt-in tombstone leaves the\n // Cold bytes readable, so it is not an irreversible destruction (and does not emit `segment.erase`).\n return { ...base, destroyed: true, cryptoShredded: encrypted, warmRowsDeleted };\n } catch (err) {\n if (!isWriteConflictError(err)) throw err;\n // A concurrent compaction/write advanced the row — re-read and shred again (it always converges).\n }\n }\n throw new WriteConflictError(`${op}: contention shredding \"${ref.segment}\" — retry`);\n}\n\n/**\n * Physically delete a segment's Warm rows (version-fenced per row; re-list on contention). Returns the count.\n *\n * **Throws rather than giving up quietly.** This used to run out of passes and `return deleted` with rows still\n * live, and the caller would go on to CAS the `destroyed` tombstone — so `destroySegment` could answer\n * `destroyed: true` on a segment whose Warm rows, which this module's header notes are CLEARTEXT, were still\n * readable. For a right-to-erasure command that is the worst available failure: it reports the one thing it did\n * not do, and `warmRowsDeleted` is a count of successes that cannot express \"and N remain\".\n *\n * Failing typed here is also what the rest of the codebase already does when a bounded retry runs out —\n * `shredSegment`'s own CAS loop below, and `S3RegistryDriver.delete`, which comments that it \"fails typed rather\n * than silently leaving the row live\". This function was the one deviation.\n *\n * It is safe to throw from here specifically because of the ordering at the call site: Warm is cleared BEFORE\n * the tombstone CAS, so an exception leaves the segment un-destroyed and retryable rather than marked destroyed\n * with data behind it.\n */\nasync function eraseWarm(\n warm: IWarmDriver,\n ref: SegmentRef,\n op: 'destroySegment' | 'dropSegment' = 'destroySegment',\n): Promise<number> {\n let deleted = 0;\n // Hoisted: the value after the loop is what decides whether the erase actually finished.\n let conflicts = 0;\n for (let pass = 0; pass < MAX_WARM_PASSES; pass++) {\n conflicts = 0;\n const rows: Array<{ chunkKey: number; token: string }> = [];\n for await (const row of warm.listChunks(ref))\n rows.push({ chunkKey: row.chunkKey, token: row.token });\n if (rows.length === 0) break; // nothing left — the only clean finish\n // A conflict is caught inside `fn` and reported as `false`, so a rewritten row never aborts the pool — it is\n // retried on the next pass. Any *other* error rejects, which propagates out of `eraseWarm` exactly as the\n // serial version did (see the throw-vs-swallow note above); the running `deleted` tally is then discarded\n // along with the result, which is why it is safe not to account for the in-flight deletes that still land.\n const erased = await mapWithConcurrency(\n rows,\n ERASE_CONCURRENCY,\n async ({ chunkKey, token }) => {\n const chunkRef: ChunkRef = { namespace: ref.namespace, segment: ref.segment, chunkKey };\n try {\n await warm.deleteConditional(chunkRef, token);\n return true;\n } catch (err) {\n if (!isWriteConflictError(err)) throw err;\n return false; // rewritten mid-erase — caught on the next pass\n }\n },\n );\n for (const ok of erased) if (ok) deleted += 1;\n conflicts = erased.length - erased.filter(Boolean).length;\n if (conflicts === 0) break;\n }\n if (conflicts > 0) {\n throw new WriteConflictError(\n `${op}: ${conflicts} warm row(s) of \"${ref.segment}\" were rewritten during every one of ` +\n `${MAX_WARM_PASSES} erase passes — the segment was NOT destroyed and its cleartext warm deltas are ` +\n `still readable. Stop writes to this segment and retry.`,\n );\n }\n return deleted;\n}\n","/**\n * Fail-safe cross-tier DR check (gap #11). The registry (`currentGen`, e.g. in\n * DynamoDB) and the immutable `.crbm` generations (e.g. in S3) back up and restore **independently**, so a\n * failover can recover the registry *ahead of* the object store — leaving `currentGen` pointing at a generation\n * whose `.crbm` isn't present yet. That's a torn restore: reads of the affected segment then throw. This scan\n * detects it up front (run it at startup after a restore) instead of discovering it on the first read.\n *\n * Read-only; bounded fan-out. `destroyed` (crypto-shredded) segments are skipped — their Cold is intentionally\n * gone/unreadable, not a torn restore. A segment whose Cold/registry can't be read this pass is recorded in\n * `errored` (never aborts the scan). Each segment is checked against its **authoritative live pointer** — one\n * strong `registry.get` per segment — never the enumeration snapshot from `registry.list`, which can be\n * eventually-consistent (an unindexed Scan) and lag a recent in-place pointer advance: trusting it would both\n * miss a torn *live* generation and cry torn on a generation the pointer has already advanced past (GC'd during\n * the scan). Residual: a full compaction+GC landing in the tiny per-segment get→list gap can still yield a\n * transient false positive — run the scan against a quiesced fleet (the documented restore procedure), or re-run\n * to confirm a reported tear.\n */\n\nimport { mapWithConcurrency } from './concurrency';\nimport { BudgetExceededError, ValidationError } from './errors';\nimport type { IColdDriver, IRegistryDriver, RegistryRecord, SegmentRef } from './ports';\n\n/** Default in-flight fan-out for the consistency scan — bounded, no thundering herd. */\n/**\n * Default ceiling on how many registry records one consistency check may hold resident: 250,000.\n *\n * **Named `maxScanSegments`, not `maxSegments`, on purpose.** Compaction already has a `maxSegments`\n * (`CR_COMPACT_MAX_SEGMENTS`) that caps how much work one cycle does and then *continues normally*. This one\n * caps how much a scan may hold and *refuses* past it. Same-sounding names with opposite behaviour at the\n * limit is a trap; pairing this with `maxWarmScanBytes` instead makes both read as what they are — ceilings on\n * a scan that fail closed.\n *\n * Generous — the compaction docs target 100K+ segment fleets — while still bounding a DR drill's memory to\n * something a modest operator box survives. Raisable, because a ceiling you cannot lift is a landmine.\n */\nexport const DEFAULT_MAX_SCAN_SEGMENTS = 250_000;\nconst DEFAULT_CHECK_CONCURRENCY = 8;\n\nexport interface ConsistencyIssue {\n readonly segment: string;\n readonly namespace?: string;\n /** The registry's `currentGen` for the segment — the generation whose `.crbm` is missing from Cold. */\n readonly currentGen: number;\n /** The only issue class today: `currentGen` references a Cold generation that is not present (torn restore). */\n readonly issue: 'missing-cold-generation';\n}\n\n/** A segment that could not be checked this pass (Cold/registry read fault) — not proof of a torn restore. */\nexport interface ConsistencyErrorEntry {\n readonly segment: string;\n readonly namespace?: string;\n /** The read error's message (never the raw error, so the report stays serializable/loggable). */\n readonly error: string;\n}\n\nexport interface ConsistencyReport {\n /** Registered segments scanned (a `destroyed` segment counts as scanned but is never an issue). */\n readonly checked: number;\n /** Segments whose `currentGen` `.crbm` is absent — recover the object store (or restore to a coherent point). */\n readonly inconsistent: ConsistencyIssue[];\n /**\n * Segments that couldn't be read this pass (a transient/partial object store during a restore is exactly when\n * this runs) — **triage these too**: an unread segment is neither proven-coherent nor proven-torn. Empty on a\n * clean pass.\n */\n readonly errored: ConsistencyErrorEntry[];\n}\n\n/** Collect the set of generations the object store currently lists for a segment. */\nasync function listGenerations(cold: IColdDriver, ref: SegmentRef): Promise<Set<number>> {\n const present = new Set<number>();\n for await (const key of cold.list(ref)) present.add(key.generation);\n return present;\n}\n\ntype Outcome =\n | { readonly kind: 'ok' }\n | { readonly kind: 'issue'; readonly issue: ConsistencyIssue }\n | { readonly kind: 'error'; readonly error: ConsistencyErrorEntry };\n\n/**\n * Verify every registered segment's `currentGen` `.crbm` actually exists in Cold. Enumerates the registry\n * (optionally one namespace) and, for each non-`destroyed` segment, checks the object store lists that\n * generation. Returns the torn segments in `inconsistent` (empty ⇒ coherent) and any unreadable segments in\n * `errored`.\n */\nexport async function runConsistencyCheck(\n deps: { readonly cold: IColdDriver; readonly registry: IRegistryDriver },\n options: { namespace?: string; concurrency?: number; maxScanSegments?: number } = {},\n): Promise<ConsistencyReport> {\n const concurrency = options.concurrency ?? DEFAULT_CHECK_CONCURRENCY;\n if (!Number.isInteger(concurrency) || concurrency < 1) {\n // Fail fast before the (possibly huge) registry scan, not after.\n throw new ValidationError(`concurrency must be a positive integer; got ${concurrency}`);\n }\n const maxScanSegments = options.maxScanSegments ?? DEFAULT_MAX_SCAN_SEGMENTS;\n if (!Number.isFinite(maxScanSegments) || maxScanSegments < 1) {\n throw new ValidationError(\n `maxScanSegments must be a finite number >= 1; got ${String(options.maxScanSegments)}`,\n );\n }\n // Bounded enumeration, matching the engine's read paths. The comment above already noted the scan is\n // \"possibly huge\" and then drained it into an array regardless: memory scaled with total fleet size, which\n // the caller had no way to cap. This is operator-invoked rather than request-reachable, so it is less exposed\n // than the GDPR paths that were fixed first — but \"an operator runs it\" is not a bound, and a DR drill against\n // a large fleet from a modest box is exactly when it would bite.\n const recs: RegistryRecord[] = [];\n for await (const rec of deps.registry.list(options.namespace)) {\n recs.push(rec);\n if (recs.length > maxScanSegments) {\n throw new BudgetExceededError(\n `checkConsistency would enumerate more than ${maxScanSegments} segments — the scan was abandoned there ` +\n `rather than completed. Narrow it with \\`namespace\\`, or raise \\`maxScanSegments\\` if the fleet really ` +\n `is that large and the memory is available.`,\n );\n }\n }\n const results = await mapWithConcurrency(recs, concurrency, async (rec): Promise<Outcome> => {\n if (rec.status === 'destroyed') return { kind: 'ok' }; // Cold intentionally gone — not a torn restore\n const ref: SegmentRef = { segment: rec.segment, namespace: rec.namespace };\n try {\n // Resolve the AUTHORITATIVE live pointer (strong read) — not the drained `rec.currentGen`, which the\n // enumeration may have read eventually-consistently and can lag the live pointer. `rec` is used only to\n // enumerate + skip destroyed segments.\n const live = await deps.registry.get(ref);\n if (!live || live.status === 'destroyed') return { kind: 'ok' }; // vanished/shredded — no live pointer\n const present = await listGenerations(deps.cold, ref);\n if (present.has(live.currentGen)) return { kind: 'ok' };\n return {\n kind: 'issue',\n issue: {\n segment: rec.segment,\n namespace: rec.namespace,\n currentGen: live.currentGen,\n issue: 'missing-cold-generation',\n },\n };\n } catch (error) {\n // Fault isolation: one unreadable segment (a partial/transient object store mid-restore) must not abort\n // the whole triage. Record it and keep scanning the rest.\n return {\n kind: 'error',\n error: {\n segment: rec.segment,\n namespace: rec.namespace,\n error: error instanceof Error ? error.message : String(error),\n },\n };\n }\n });\n const inconsistent: ConsistencyIssue[] = [];\n const errored: ConsistencyErrorEntry[] = [];\n for (const r of results) {\n if (r.kind === 'issue') inconsistent.push(r.issue);\n else if (r.kind === 'error') errored.push(r.error);\n }\n return { checked: recs.length, inconsistent, errored };\n}\n","/**\n * Retry decorators (Phase 4b).\n *\n * Transparent wrappers that add bounded, jittered retry of **transient** faults to any driver, using the one\n * shared `core/retry` primitive — so every backend (DynamoDB, S3, LocalFS, …) inherits the same, simulator-\n * replayable policy instead of each rolling its own. Pure composition over the port interfaces (no SDK, no\n * I/O of their own); the wrapped driver is responsible for *classifying* its transient faults (raising\n * {@link TransientError}); these decorators decide *whether and when* to retry.\n *\n * **Streaming methods split into two shapes**, and the difference is deliberate — a partially-consumed async\n * iterator cannot be resumed mid-stream (it would re-yield earlier items), so each method picks between\n * buffering and bounded memory:\n *\n * · `RetryingColdDriver.list` / `RetryingRegistryDriver.list` **buffer**, inside `withRetry`, so the whole\n * enumeration is retried by re-running it from the start. Both are discovery scans over a generation or\n * namespace listing, where the result set is small and whole-scan retry is worth the memory.\n * · `RetryingWarmDriver.listChunks` does **not** buffer. It retries only until the first row arrives and\n * then streams live, because buffering it defeated the engine's resident-memory bound outright — see the\n * measured account on the method itself. A mid-stream fault therefore propagates rather than being\n * retried, which is the documented trade there.\n *\n * Point methods are retried in place, with nothing to buffer.\n *\n * (This paragraph previously said streaming methods buffer, full stop. That described `listChunks` as it was\n * before the bound was fixed, and the stale wording had also been copied into the Postgres and MySQL warm\n * drivers — so three comments promised a mid-stream resilience that the hot read path does not have.)\n *\n * What is **not** retried here: {@link WriteConflictError} (OCC — the engine's read-modify-write loop owns\n * that; a blind replay would re-apply against a stale token), and every deterministic error\n * (`ValidationError`/`IntegrityError`/`NotFoundError`/…). Default classifier: {@link isTransient}.\n */\nimport type { Clock, Rng } from '../../core/determinism';\nimport { withRetry, isTransient, DEFAULT_RETRY_POLICY } from '../../core/retry';\nimport type { RetryPolicy } from '../../core/retry';\nimport type {\n ChunkRef,\n ColdCaps,\n ColdChunkSource,\n GenKey,\n IColdDriver,\n IRegistryDriver,\n IWarmDriver,\n NewRegistryRecord,\n NoRow,\n RegCaps,\n RegistryPatch,\n RegistryRecord,\n SegmentRef,\n SegmentSize,\n Token,\n WarmReadOptions,\n WarmRow,\n} from '../../core/ports';\nimport type { BlobSink } from '../../core/blob';\n\nexport interface RetryingOptions {\n readonly clock: Clock;\n readonly rng: Rng;\n /** Defaults to {@link DEFAULT_RETRY_POLICY}. */\n readonly policy?: RetryPolicy;\n /** Override which errors are retryable. Default: {@link isTransient} (any `TransientError`). */\n readonly isRetryable?: (err: unknown) => boolean;\n /** Observability hook fired before each backoff wait. */\n readonly onRetry?: (info: { attempt: number; delayMs: number; err: unknown }) => void;\n}\n\n/** Internal: resolve the options into the `core/retry` shape once, at construction. */\nfunction toRetry(opts: RetryingOptions): {\n policy: RetryPolicy;\n deps: {\n clock: Clock;\n rng: Rng;\n isRetryable: (e: unknown) => boolean;\n onRetry?: RetryingOptions['onRetry'];\n };\n} {\n return {\n policy: opts.policy ?? DEFAULT_RETRY_POLICY,\n deps: {\n clock: opts.clock,\n rng: opts.rng,\n isRetryable: opts.isRetryable ?? isTransient,\n onRetry: opts.onRetry,\n },\n };\n}\n\n/** Wrap a warm driver so its calls retry transient faults. OCC conflicts are deliberately not retried here. */\nexport class RetryingWarmDriver implements IWarmDriver {\n private readonly inner: IWarmDriver;\n private readonly policy: RetryPolicy;\n private readonly deps: ReturnType<typeof toRetry>['deps'];\n\n constructor(inner: IWarmDriver, opts: RetryingOptions) {\n this.inner = inner;\n const r = toRetry(opts);\n this.policy = r.policy;\n this.deps = r.deps;\n }\n\n get(ref: ChunkRef, opts?: WarmReadOptions): Promise<WarmRow | null> {\n return withRetry(() => this.inner.get(ref, opts), this.policy, this.deps);\n }\n\n putConditional(\n ref: ChunkRef,\n bytes: Uint8Array,\n expected: Token | NoRow,\n ): Promise<{ token: Token }> {\n return withRetry(() => this.inner.putConditional(ref, bytes, expected), this.policy, this.deps);\n }\n\n deleteConditional(ref: ChunkRef, expected: Token): Promise<void> {\n return withRetry(() => this.inner.deleteConditional(ref, expected), this.policy, this.deps);\n }\n\n /**\n * Stream the inner driver's rows, retrying only until the first one arrives.\n *\n * **This used to buffer the whole scan** — `for await (…) out.push(row)` inside `withRetry`, then\n * `yield* out` — which made the retry trivially safe and quietly defeated every bound above it. The engine's\n * `collectWarm` refuses *during* enumeration precisely so resident memory is `O(ceiling)` rather than\n * `O(segment)`; with the buffering wrapper in place (and it is wired by default) it saw its first row only\n * after the entire segment was already in memory. Measured on a 500-row segment under\n * `budget: { maxRequests: 3 }`: **500 rows materialised with the default wiring, 4 with `retry: false`**.\n * Both paths threw the same `BudgetExceededError`, which is why no test caught it — the error was never the\n * distinguishing observable, the row count was.\n *\n * **The trade this makes.** A mid-stream fault now propagates instead of being retried. It cannot be retried\n * honestly: rows have already been handed to the consumer, so restarting the iterator would re-yield them,\n * and the driver interface exposes no resumption token to continue from. Retry is kept where it pays —\n * establishing the scan, which is where transient connect/throttle failures actually land — and bounded\n * memory wins the conflict, because invariant 6 (\"bounded memory & cost, always\") is a hard invariant and\n * mid-scan retry is not. A caller who needs whole-scan retry can wrap the operation at their own level,\n * where re-reading from the start is safe.\n */\n async *listChunks(\n ref: SegmentRef,\n opts?: WarmReadOptions,\n ): AsyncIterable<{ chunkKey: number } & WarmRow> {\n // Each attempt builds a FRESH iterator, so a retried establishment cannot duplicate rows.\n const started = await withRetry(\n async () => {\n const iterator = this.inner.listChunks(ref, opts)[Symbol.asyncIterator]();\n const first = await iterator.next();\n return { iterator, first };\n },\n this.policy,\n this.deps,\n );\n if (started.first.done === true) return;\n // The `finally` is load-bearing, and this is the only generator in the codebase that needs one written by\n // hand. Everywhere else either drives the inner scan with `for await` — which closes it automatically on an\n // abrupt exit — or has nothing to close (Postgres/MySQL/DynamoDB page statelessly, so each page's client is\n // already back in the pool). This method drives the inner iterator manually, precisely so it does NOT buffer,\n // and that means abandonment has to be handled explicitly.\n //\n // Abandonment is not hypothetical here, it is the designed path: `engine.ts` throws `BudgetExceededError`\n // from INSIDE its `for await` over this method (\"the scan was abandoned there rather than completed\"). That\n // closes this generator at a `yield`, and without the `finally` the inner generator stays suspended forever\n // — holding an open Mongo cursor or Cassandra stream, since those two are the drivers that keep one across\n // yields. The leak therefore fired exactly when the memory ceiling was doing its job, which is the worst\n // possible time to also be leaking a connection.\n try {\n yield started.first.value;\n for (;;) {\n const next = await started.iterator.next();\n if (next.done === true) return;\n yield next.value;\n }\n } finally {\n await started.iterator.return?.();\n }\n }\n}\n\n/** Wrap a cold chunk source so its reads retry transient faults. */\nexport class RetryingColdChunkSource implements ColdChunkSource {\n private readonly inner: ColdChunkSource;\n private readonly policy: RetryPolicy;\n private readonly deps: ReturnType<typeof toRetry>['deps'];\n /** Present only when the inner source supports it — so capability detection stays honest. */\n readonly sizeOf?: (ref: SegmentRef) => Promise<SegmentSize | null>;\n readonly cardinalities?: (ref: SegmentRef) => Promise<ReadonlyMap<number, number> | null>;\n readonly currentGeneration?: (ref: SegmentRef) => Promise<number | null>;\n\n constructor(inner: ColdChunkSource, opts: RetryingOptions) {\n this.inner = inner;\n const r = toRetry(opts);\n this.policy = r.policy;\n this.deps = r.deps;\n const innerSizeOf = inner.sizeOf;\n if (innerSizeOf) {\n this.sizeOf = (ref) => withRetry(() => innerSizeOf.call(inner, ref), this.policy, this.deps);\n }\n const innerCardinalities = inner.cardinalities;\n if (innerCardinalities) {\n this.cardinalities = (ref) =>\n withRetry(() => innerCardinalities.call(inner, ref), this.policy, this.deps);\n }\n const innerCurrentGeneration = inner.currentGeneration;\n if (innerCurrentGeneration) {\n this.currentGeneration = (ref) =>\n withRetry(() => innerCurrentGeneration.call(inner, ref), this.policy, this.deps);\n }\n }\n\n getChunk(ref: ChunkRef): Promise<Uint8Array | null> {\n return withRetry(() => this.inner.getChunk(ref), this.policy, this.deps);\n }\n\n listChunkKeys(ref: SegmentRef): Promise<number[]> {\n return withRetry(() => this.inner.listChunkKeys(ref), this.policy, this.deps);\n }\n}\n\n/** Wrap a cold driver so its byte operations retry transient faults. */\nexport class RetryingColdDriver implements IColdDriver {\n private readonly inner: IColdDriver;\n private readonly policy: RetryPolicy;\n private readonly deps: ReturnType<typeof toRetry>['deps'];\n\n constructor(inner: IColdDriver, opts: RetryingOptions) {\n this.inner = inner;\n const r = toRetry(opts);\n this.policy = r.policy;\n this.deps = r.deps;\n }\n\n capabilities(): ColdCaps {\n return this.inner.capabilities(); // pure, local — no retry\n }\n\n putImmutable(\n key: GenKey,\n write: (sink: BlobSink) => Promise<void>,\n ): Promise<{ size: number; sha256: string }> {\n // Write-once + content-buffered: a retry re-runs `write` from scratch and re-issues the conditional put;\n // a phantom-success surfaces as WriteConflictError (not transient) and stops the retry. Safe to wrap.\n return withRetry(() => this.inner.putImmutable(key, write), this.policy, this.deps);\n }\n\n getRange(key: GenKey, offset: number, length: number): Promise<Uint8Array> {\n return withRetry(() => this.inner.getRange(key, offset, length), this.policy, this.deps);\n }\n\n getTail(key: GenKey, maxBytes: number): Promise<{ bytes: Uint8Array; size: number }> {\n return withRetry(() => this.inner.getTail(key, maxBytes), this.policy, this.deps);\n }\n\n delete(key: GenKey): Promise<void> {\n return withRetry(() => this.inner.delete(key), this.policy, this.deps);\n }\n\n async *list(ref: SegmentRef): AsyncIterable<GenKey> {\n const keys = await withRetry(\n async () => {\n const out: GenKey[] = [];\n for await (const k of this.inner.list(ref)) out.push(k);\n return out;\n },\n this.policy,\n this.deps,\n );\n yield* keys;\n }\n}\n\n/** Wrap a registry driver so its calls retry transient faults. CAS conflicts are not retried (caller-owned). */\nexport class RetryingRegistryDriver implements IRegistryDriver {\n private readonly inner: IRegistryDriver;\n private readonly policy: RetryPolicy;\n private readonly deps: ReturnType<typeof toRetry>['deps'];\n\n constructor(inner: IRegistryDriver, opts: RetryingOptions) {\n this.inner = inner;\n const r = toRetry(opts);\n this.policy = r.policy;\n this.deps = r.deps;\n }\n\n capabilities(): RegCaps {\n return this.inner.capabilities();\n }\n\n get(ref: SegmentRef): Promise<RegistryRecord | null> {\n return withRetry(() => this.inner.get(ref), this.policy, this.deps);\n }\n\n create(ref: SegmentRef, record: NewRegistryRecord): Promise<{ token: Token }> {\n return withRetry(() => this.inner.create(ref, record), this.policy, this.deps);\n }\n\n compareAndSwap(\n ref: SegmentRef,\n expected: Token,\n patch: RegistryPatch,\n ): Promise<{ token: Token }> {\n return withRetry(() => this.inner.compareAndSwap(ref, expected, patch), this.policy, this.deps);\n }\n\n async *list(namespace?: string): AsyncIterable<RegistryRecord> {\n const records = await withRetry(\n async () => {\n const out: RegistryRecord[] = [];\n for await (const r of this.inner.list(namespace)) out.push(r);\n return out;\n },\n this.policy,\n this.deps,\n );\n yield* records;\n }\n\n delete(ref: SegmentRef): Promise<void> {\n return withRetry(() => this.inner.delete(ref), this.policy, this.deps);\n }\n}\n"]}
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/core/bit-route.ts", "../src/core/budget.ts", "../src/core/keys.ts", "../src/core/metrics.ts", "../src/core/engine.ts", "../src/core/lru.ts", "../src/core/cost.ts", "../src/core/due-index.ts", "../src/core/registry-scan.ts", "../src/core/codec.ts", "../src/export/index.ts", "../src/core/discover.ts", "../src/drivers/memory.ts", "../src/core/blob.ts", "../src/drivers/localfs/storage.ts", "../src/drivers/localfs/paths.ts", "../src/drivers/localfs/fs-util.ts", "../src/drivers/localfs/registry.ts", "../src/drivers/backends.ts", "../src/core/audit.ts", "../src/core/cooperative.ts", "../src/core/crypto.ts", "../src/core/crbm/crc32c.ts", "../src/core/crbm/varint.ts", "../src/core/crbm/format.ts", "../src/core/crbm/reader.ts", "../src/core/crbm/writer.ts", "../src/core/crbm-storage-source.ts", "../src/core/pinned-storage-source.ts", "../src/core/generation-gc.ts", "../src/core/load.ts", "../src/core/rollback.ts", "../src/core/erase-id.ts", "../src/drivers/crypto.ts", "../src/core/erasure.ts", "../src/core/retention.ts", "../src/core/retention-sweep.ts", "../src/core/consistency.ts", "../src/core/retry.ts", "../src/drivers/retry/retrying-drivers.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * BitRouteSplitter \u2014 maps a 32-bit id to its chunk (top 16 bits) and remainder\n * (bottom 16 bits), per the data model.\n */\nimport { ValidationError } from './errors';\n\nexport const U32_MAX = 0xffff_ffff;\nexport const CHUNK_COUNT = 0x1_0000; // 65,536 possible chunk keys\nconst LOW_16 = 0xffff;\n\nexport interface BitRoute {\n /** Top 16 bits \u2014 the chunk key (0..65535). */\n readonly chunkKey: number;\n /** Bottom 16 bits \u2014 the value within the chunk (0..65535). */\n readonly remainder: number;\n}\n\n/** Split a u32 id into `{ chunkKey, remainder }`. Throws `ValidationError` for non-u32 input. */\nexport function splitId(id: number): BitRoute {\n if (!Number.isInteger(id) || id < 0 || id > U32_MAX) {\n throw new ValidationError(`id must be an integer in 0..${U32_MAX}; got ${id}`);\n }\n return { chunkKey: id >>> 16, remainder: id & LOW_16 };\n}\n\n/**\n * Recombine a chunk key + remainder back into the u32 id. Precondition: `chunkKey` is a validated\n * 16-bit value (tier-derived keys are validated upstream in the engine before reaching here, per\n * invariant 5); `remainder` is masked to 16 bits.\n */\n/**\n * Largest legal value inside a chunk payload. A chunk covers `CHUNK_COUNT` ids, so remainders run\n * `[0, CHUNK_COUNT - 1]`. Exported so the engine can assert it on untrusted tier bytes.\n */\nexport const MAX_REMAINDER = CHUNK_COUNT - 1;\n\nexport function joinId(chunkKey: number, remainder: number): number {\n return (((chunkKey & LOW_16) << 16) >>> 0) + (remainder & LOW_16);\n}\n", "/**\n * Per-op denial-of-wallet budget \u2014 hard invariant 6 (bounded memory and cost). A read/admin op is refused\n * **before it fans out** if its projected fan-out would exceed `maxRequests` \u2014 so one runaway\n * `count`/`iterate`/`intersect`/`subjectReport`/`eraseSubject` can't drive unbounded RCU/GET cost on a shared\n * backend. The check is O(1) (a single comparison against the already-known fan-out size), so the hot path is\n * untouched. Each request's payload is separately size-capped (the safe-deserialize ceiling), so bounding the\n * fan-out count transitively bounds bytes \u2014 the budget is intentionally count-based, not a second byte\n * accumulator that would add per-chunk work.\n *\n * **What the count is.** For the read ops it is the number of Storage **chunk fetches** (`count`/`iterate`: one per\n * effective chunk; `intersect`: surviving keys \u00D7 operands). For the admin scans it is the number of **segments\n * fanned out to** (`subjectReport`: one `has()` each; `eraseSubject`: one generation rewrite each) \u2014 i.e. it\n * bounds the *breadth* of the fan-out, not the request total of each segment's own rewrite. That's\n * the right lever for a runaway (a million-segment sweep); it is not a byte/request meter.\n */\n\nimport { BudgetExceededError, ValidationError } from './errors';\n\nexport interface Budget {\n /** Max units of fan-out (Storage chunk fetches, or segments scanned) one op may issue before it is refused. */\n readonly maxRequests: number;\n}\n\n/**\n * Default: **on but generous** \u2014 even a full single-segment scan (\u2264 65 536 chunks) or a large single-namespace\n * admin scan stays well under it; it exists to catch a true runaway (a million-segment scan, a pathological\n * intersection). Tune it down for tighter multi-tenant control, or set `budget: false` to disable.\n */\nexport const DEFAULT_BUDGET: Budget = { maxRequests: 1_000_000 };\n\n/** A store/per-op budget option: partial overrides, or `false` to disable entirely. */\nexport type BudgetOption = Partial<Budget> | false;\n\n/** Resolve a budget option against a fallback to a concrete `Budget`, or `null` when disabled. Validates. */\nexport function resolveBudget(opt: BudgetOption | undefined, fallback: Budget): Budget | null {\n if (opt === false) return null; // explicitly disabled\n const maxRequests = opt?.maxRequests ?? fallback.maxRequests;\n if (!Number.isInteger(maxRequests) || maxRequests < 1) {\n throw new ValidationError(`budget.maxRequests must be a positive integer; got ${maxRequests}`);\n }\n return { maxRequests };\n}\n\n/**\n * Resolve a **per-op** budget override against the store's own resolved budget (never the raw global default):\n * `undefined` inherits the store budget as-is (including a disabled `null`); a partial `{}` / omitted\n * `maxRequests` inherits the store's *tightening* (so a per-op passthrough of an absent config value can't\n * silently lift a tight tenant ceiling back to the generous default); `{ maxRequests }` replaces it; `false`\n * disables. Falls back to {@link DEFAULT_BUDGET} only when the store itself has no budget (disabled).\n */\nexport function resolvePerOpBudget(\n opt: BudgetOption | undefined,\n storeBudget: Budget | null,\n): Budget | null {\n if (opt === undefined) return storeBudget;\n return resolveBudget(opt, storeBudget ?? DEFAULT_BUDGET);\n}\n\n/**\n * Refuse an op whose projected fan-out exceeds the budget. **Call before fan-out**, with the exact fan-out size\n * the op is about to issue (Storage chunk fetches, or segments to scan). O(1). No-op when `budget` is `null`\n * (disabled).\n */\nexport function checkBudget(budget: Budget | null, projectedRequests: number, op: string): void {\n if (budget !== null && projectedRequests > budget.maxRequests) {\n throw new BudgetExceededError(\n `${op} would fan out to ${projectedRequests} units, over the per-op budget of ` +\n `${budget.maxRequests} \u2014 raise \\`budget.maxRequests\\`, override it per-op, or set \\`budget: false\\``,\n );\n }\n}\n\n/**\n * Drain an async iterable into an array, refusing **as soon as** the budget is exceeded.\n *\n * This exists because the obvious spelling is wrong in a way that is easy to miss:\n *\n * ```ts\n * for await (const rec of registry.list(ns)) recs.push(rec);\n * checkBudget(budget, recs.length, op); // \u2190 too late; the memory is already spent\n * ```\n *\n * That pattern bounds the **fan-out** but not the **enumeration**, so a tight budget refuses the work only\n * after paying for the list \u2014 which defeats the purpose. It was measured buffering 20,000 registry records\n * under `budget: { maxRequests: 2 }` before throwing. Draining incrementally bounds resident memory to\n * `O(budget)` instead of `O(fleet)`.\n *\n * **The error message is deliberately vaguer than `checkBudget`'s.** It reports \"more than N\" rather than an\n * exact total, because knowing the exact total requires finishing the scan \u2014 which is precisely the cost being\n * refused. An honest approximation beats an expensive exact number.\n *\n * A `null` budget (`budget: false`) means the caller has explicitly opted out of fan-out limits, so this\n * degrades to a plain drain.\n */\nexport async function collectWithinBudget<T>(\n source: AsyncIterable<T>,\n budget: Budget | null,\n op: string,\n): Promise<T[]> {\n const out: T[] = [];\n for await (const item of source) {\n out.push(item);\n // Checked INSIDE the loop, and `>` not `>=`, so the threshold matches `checkBudget` exactly: a budget of N\n // admits exactly N units and refuses the N+1'th.\n if (budget !== null && out.length > budget.maxRequests) {\n throw new BudgetExceededError(\n `${op} would fan out to more than ${budget.maxRequests} units, over the per-op budget \u2014 the scan was ` +\n `abandoned at that point rather than completed, so no exact total is available. Raise ` +\n `\\`budget.maxRequests\\`, override it per-op, or set \\`budget: false\\``,\n );\n }\n }\n return out;\n}\n", "/**\n * Canonical key encoding for a segment / chunk \u2014 one source of truth, used by both the storage\n * drivers and the cache (DRY). The encoding is collision-proof and injection-proof.\n *\n * **The name parts are encoded, and that is what makes the delimiters safe.** This module used to rest on the\n * name grammar instead: a space and `/` were characters a name could not contain, so neither could be injected\n * across a field. When the grammar was deleted \u2014 a name is any non-empty string now \u2014 that argument silently\n * became false, and two distinct segments could produce one key:\n *\n * ```\n * segmentKey({ segment: 's' }) \u2192 \"/ s\"\n * segmentKey({ namespace: '/', segment: 's' }) \u2192 \"/ s\" \u2190 the same key\n * segmentKey({ namespace: 'a', segment: 'b c' }) \u2192 \"a b c\"\n * segmentKey({ namespace: 'a b', segment: 'c' }) \u2192 \"a b c\" \u2190 the same key\n * ```\n *\n * These keys reach the reader LRU and the decoded-chunk cache, so a collision is one segment serving\n * another's data on the read path, on every backend \u2014 invariant 3, and a tenant-isolation break.\n *\n * `encodeNameForKey` escapes both delimiters (`/` \u2192 `%2F`, space \u2192 `%20`) along with control characters, so\n * the original argument holds again \u2014 but now as a property of the encoding rather than of a grammar that can\n * be relaxed out from under it. The absent-namespace sentinel keeps the same ours-vs-theirs asymmetry the\n * storage keys use: it is emitted literally while a caller's namespace is encoded, so a namespace actually\n * named `/` encodes to `%2F` and cannot impersonate it.\n *\n * These keys are in-memory and driver-internal, so encoding them moves nothing on disk.\n */\nimport { encodeNameForKey } from './name-codec';\nimport type { ChunkRef, SegmentRef } from './ports';\n\nconst FIELD = ' ';\nconst NO_NAMESPACE = '/';\n\nexport function segmentKey(ref: SegmentRef): string {\n const ns = ref.namespace === undefined ? NO_NAMESPACE : encodeNameForKey(ref.namespace);\n return `${ns}${FIELD}${encodeNameForKey(ref.segment)}`;\n}\n\nexport function segmentPrefix(ref: SegmentRef): string {\n return `${segmentKey(ref)}${FIELD}`;\n}\n\nexport function chunkRefKey(ref: ChunkRef): string {\n return `${segmentPrefix(ref)}${ref.chunkKey}`;\n}\n\n/**\n * CACHE-cache key for a chunk scoped to a specific **version** of the segment \u2014 {@link chunkRefKey} plus that\n * version (space-delimited, injection-proof exactly as above \u2014 the name parts are already encoded). A publish bumps the version, so it naturally\n * misses the cache instead of serving a stale superseded chunk, and the superseded entries age out under the\n * LRU ceiling (no active purge needed).\n *\n * `version` is whatever the Storage source reports as identifying the bytes a read will see \u2014 its\n * `currentVersion` where it has one, otherwise the bare generation number. **A generation number alone is not\n * an identity**: `nextGeneration` restarts at 0 once a registry row is purged and the bucket emptied, so a\n * retired-and-re-created name serves different data at the same `currentGen`, and a key built on the number\n * hands the new incarnation the old one's decoded chunks.\n */\nexport function chunkGenKey(ref: ChunkRef, version: string | number): string {\n return `${chunkRefKey(ref)}${FIELD}${version}`;\n}\n\n/**\n * Deterministic FNV-1a shard assignment for a segment key \u2014 dependency-free, stable across workers and\n * restarts. One definition, so every sharded fleet operation (today the retention sweep) agrees on it exactly:\n * two definitions that disagreed would make the union across workers neither disjoint nor complete.\n */\nexport function shardOf(key: string, totalShards: number): number {\n let h = 0x811c9dc5;\n for (let i = 0; i < key.length; i++) {\n h ^= key.charCodeAt(i);\n h = Math.imul(h, 0x0100_0193);\n }\n return (h >>> 0) % totalShards;\n}\n", "/**\n * Metrics seam \u2014 an injected sink the engine pushes typed events to, exactly like the `Clock`/driver seams\n * keep `core/` pure and storage-agnostic.\n *\n * Design: the library emits **neutral domain events** and stays vendor-agnostic \u2014 you (or a ~12-line\n * adapter) map them to OpenTelemetry / Datadog / a log line. The default is a **no-op**, and emission is\n * skipped entirely when no sink is wired (near-zero overhead, no telemetry dependency). Events carry **raw\n * observations** (bytes, counts, ms); turning those into billable units / dollars is the cost model's job,\n * which keeps rates pluggable.\n *\n * Two caveats for sink authors: `onEvent` runs **synchronously on the I/O path**, so keep it cheap and\n * non-blocking (offload batching/network to your own async queue); and `segment`/`namespace` are\n * caller-controlled strings that may be PII and are **unbounded-cardinality** \u2014 do not map them to\n * per-series metric labels unless they're known low-cardinality and PII-free. See the getting-started\n * \"Observability\" section.\n */\n\n/** The segment operations that emit an `op` latency event (timed with the injected clock, at the facade). */\nexport type MetricOpName = 'has' | 'count' | 'intersectInto' | 'unionInto' | 'andNotInto';\n\n/**\n * One observability event. A discriminated union on `kind` \u2014 new variants can be added over time without\n * breaking consumers (they switch on the kinds they care about). `namespace` is the segment's namespace\n * (absent \u21D2 the default namespace). Segment names are identifiers, never bitmap contents (threat model:\n * never log PII / bitmap bits).\n */\nexport type MetricEvent =\n | {\n readonly kind: 'storage.get';\n readonly namespace?: string;\n readonly segment: string;\n /** Bytes returned (0 if the chunk was absent \u2014 a GET still happened). */\n readonly bytes: number;\n /**\n * Elapsed wall time of the read \u2014 includes any transient-retry backoff on the storage call. From the\n * injected clock, clamped to \u2265 0 (0 under the no-wait test clock).\n */\n readonly ms: number;\n }\n | { readonly kind: 'cache'; readonly hit: boolean }\n | {\n readonly kind: 'retry';\n /** Infrastructure-fault backoff (throttling, 5xx, a dropped connection) \u2014 the one kind of retry the store does. */\n readonly reason: 'transient';\n /** 1-based number of the attempt about to be retried. */\n readonly attempt: number;\n readonly delayMs: number;\n }\n | {\n readonly kind: 'intersect';\n /**\n * Which chunk-aligned combine this was. **Optional for backward compatibility** \u2014 absent means\n * `'intersect'`, which is all this event reported before `union`/`andNot` existed.\n *\n * For `'union'` over its *include* operands alone, `skippedChunks` is 0 by construction \u2014 union reads\n * every chunk of every operand, so there is nothing to prune. It can still be non-zero when a union\n * carries `exclude` operands, because a suppression list may hold keys no include does and those are\n * legitimately never fetched. So: 0 is the expected shape for a plain union, not a guarantee.\n */\n readonly op?: 'intersect' | 'union' | 'andNot';\n /** Operand count, including any `exclude` (suppression) operands. */\n readonly operands: number;\n /**\n * Distinct chunk **keys** selected to fetch \u2014 for `'intersect'`, those present in every operand.\n *\n * **Keys, not requests.** The actual storage GETs are roughly `fetchedChunks \u00D7 operands`, plus one per\n * `exclude` that holds a given key, which is why this number is smaller than what the per-op budget\n * charges for the same call. The two are different units by design; if you are reconciling a bill, the\n * budget's accounting is the one that models requests.\n */\n readonly fetchedChunks: number;\n /**\n * **Distinct** chunk-keys pruned \u2014 never fetched (the chunk-skipping saving). Counts distinct keys,\n * not per-operand GETs, so it under-states the true GET saving when 3+ operands partially overlap.\n */\n readonly skippedChunks: number;\n }\n | { readonly kind: 'op'; readonly name: MetricOpName; readonly ms: number };\n\n/**\n * The sink you plug in. One method, synchronous, fire-and-forget. It must never throw back into the\n * caller \u2014 `CloudRoaring` wraps a user sink with {@link safeMetrics} so a buggy sink can't break I/O.\n */\nexport interface IMetricsSink {\n onEvent(event: MetricEvent): void;\n}\n\n/** The default sink: discards everything, zero overhead. Used whenever no sink is wired. */\nexport const NOOP_METRICS: IMetricsSink = {\n onEvent(): void {\n /* discard */\n },\n};\n\n/**\n * Wrap a sink so a throwing/buggy `onEvent` can never break the data path \u2014 observability is strictly\n * best-effort. `CloudRoaring` applies this to the user-supplied sink at construction.\n */\nexport function safeMetrics(sink: IMetricsSink): IMetricsSink {\n if (sink === NOOP_METRICS) return sink;\n return {\n onEvent(event: MetricEvent): void {\n try {\n sink.onEvent(event);\n } catch {\n /* swallow \u2014 a metrics sink must never break a read */\n }\n },\n };\n}\n\n/** Accumulated totals \u2014 the shape returned by {@link CountingMetricsSink.snapshot}. */\nexport interface MetricsSnapshot {\n readonly storage: { readonly gets: number; readonly bytes: number; readonly totalMs: number };\n readonly cache: { readonly hits: number; readonly misses: number };\n readonly retries: { readonly transient: number };\n readonly intersect: {\n readonly calls: number;\n readonly fetchedChunks: number;\n readonly skippedChunks: number;\n };\n readonly ops: Readonly<\n Record<MetricOpName, { readonly count: number; readonly totalMs: number }>\n >;\n}\n\nconst OP_NAMES: readonly MetricOpName[] = [\n 'has',\n 'count',\n 'intersectInto',\n 'unionInto',\n 'andNotInto',\n];\n\n/**\n * A ready-made sink that tallies events into a {@link MetricsSnapshot} \u2014 handy for tests, quick scripts,\n * and as the grounded-request-cost source behind `costReport()`. `snapshot()` returns an independent copy;\n * `reset()` zeroes the counters.\n */\nexport class CountingMetricsSink implements IMetricsSink {\n private storage = { gets: 0, bytes: 0, totalMs: 0 };\n private cache = { hits: 0, misses: 0 };\n private retries = { transient: 0 };\n private intersect = { calls: 0, fetchedChunks: 0, skippedChunks: 0 };\n private ops: Record<MetricOpName, { count: number; totalMs: number }> =\n CountingMetricsSink.zeroOps();\n\n private static zeroOps(): Record<MetricOpName, { count: number; totalMs: number }> {\n // null-proto so a type-violating event.name (e.g. '__proto__') can never reach Object.prototype\n const ops = Object.create(null) as Record<MetricOpName, { count: number; totalMs: number }>;\n for (const name of OP_NAMES) ops[name] = { count: 0, totalMs: 0 };\n return ops;\n }\n\n onEvent(event: MetricEvent): void {\n switch (event.kind) {\n case 'storage.get':\n this.storage.gets += 1;\n this.storage.bytes += event.bytes;\n this.storage.totalMs += event.ms;\n break;\n case 'cache':\n if (event.hit) this.cache.hits += 1;\n else this.cache.misses += 1;\n break;\n case 'retry':\n this.retries.transient += 1;\n break;\n case 'intersect':\n this.intersect.calls += 1;\n this.intersect.fetchedChunks += event.fetchedChunks;\n this.intersect.skippedChunks += event.skippedChunks;\n break;\n case 'op': {\n // A name outside `OP_NAMES` (a JS caller) is counted nowhere rather than crashing the sink.\n const op = this.ops[event.name] as { count: number; totalMs: number } | undefined;\n if (op === undefined) break;\n op.count += 1;\n op.totalMs += event.ms;\n break;\n }\n default: {\n const exhaustive: never = event;\n return exhaustive;\n }\n }\n }\n\n snapshot(): MetricsSnapshot {\n const ops = Object.create(null) as Record<MetricOpName, { count: number; totalMs: number }>;\n for (const name of OP_NAMES) ops[name] = { ...this.ops[name] };\n return {\n storage: { ...this.storage },\n cache: { ...this.cache },\n retries: { ...this.retries },\n intersect: { ...this.intersect },\n ops,\n };\n }\n\n reset(): void {\n this.storage = { gets: 0, bytes: 0, totalMs: 0 };\n this.cache = { hits: 0, misses: 0 };\n this.retries = { transient: 0 };\n this.intersect = { calls: 0, fetchedChunks: 0, skippedChunks: 0 };\n this.ops = CountingMetricsSink.zeroOps();\n }\n}\n", "/**\n * SegmentEngine \u2014 the read side of the loaded store: id routing, the chunk-skipping combines, and the cache\n * of decoded Storage chunks, over the {@link StorageChunkSource} port.\n *\n * **Read-only by design.** Every write in this library is a new immutable generation \u2014 `bulkLoadCrbmGeneration`,\n * the facade's `*Into` verbs, `eraseIdFromSegment` \u2014 published through the registry pointer. Nothing here mutates\n * stored bytes, so a read never merges tiers: one chunk read is one whole, checksum-verified, immutable chunk of\n * one generation. Storage-agnostic and time/random-free (the determinism seam): all I/O is via the injected\n * source; the cache carries its own `Clock`.\n */\nimport { splitId, joinId, CHUNK_COUNT, MAX_REMAINDER } from './bit-route';\nimport type { CodecBitmap, CodecInterface } from './codec';\nimport { checkBudget, DEFAULT_BUDGET, resolvePerOpBudget } from './budget';\nimport type { Budget, BudgetOption } from './budget';\nimport type { Clock } from './determinism';\nimport { IntegrityError, ValidationError } from './errors';\nimport { chunkGenKey, chunkRefKey, segmentPrefix } from './keys';\nimport type { BoundedLru } from './lru';\nimport { NOOP_METRICS, safeMetrics } from './metrics';\nimport type { IMetricsSink } from './metrics';\nimport type { ChunkRef, StorageChunkSource, SegmentRef, SegmentSize } from './ports';\n\nconst DEFAULT_MAX_BITMAP_BYTES = 1 << 20; // 1 MiB per bitmap \u2014 generous; real chunks are far smaller\n/** Max overlapping-chunk intersections in flight \u2014 bounds memory + concurrent reads (invariant 6). */\nconst DEFAULT_INTERSECT_CONCURRENCY = 8;\n\n/** A clock that always reads 0 \u2014 used when nothing is injected, so the `storage.get` latency metric reports 0 ms. */\nconst ZERO_CLOCK: Pick<Clock, 'now'> = { now: () => 0 };\n\nexport interface EngineDeps {\n readonly storage: StorageChunkSource;\n /** Optional cache of decoded (immutable) Storage chunks. */\n readonly cache?: BoundedLru<string, CodecBitmap>;\n readonly maxBitmapBytes?: number;\n /**\n * The bitmap codec \u2014 **required**. `core/` is codec-agnostic: it can have no default, because the concrete codec\n * lives in a *flavor* package that depends on core (a default here would invert that arrow). A flavor's facade\n * injects it \u2014 `@cloudbitmaps/roaring` passes `roaringCodec` \u2014 so applications never see this.\n */\n readonly codec: CodecInterface;\n /** Time source for the `storage.get` latency metric only; defaults to a clock that reads 0. */\n readonly clock?: Pick<Clock, 'now'>;\n /** Observability sink; defaults to a no-op. Assumed exception-safe (the facade wraps it). */\n readonly metrics?: IMetricsSink;\n /**\n * Per-op denial-of-wallet budget, already resolved by the facade: a {@link Budget} to enforce, or `null` to\n * disable. Undefined \u21D2 {@link DEFAULT_BUDGET} (a direct engine construction still gets the generous default).\n * Read ops refuse before fan-out if they'd exceed it.\n */\n readonly budget?: Budget | null;\n}\n\n/** Options common to the chunk-aligned combines. */\nexport interface CombineOptions {\n /** Max chunk keys resolved concurrently \u2014 bounds the Storage footprint. A positive integer. */\n readonly concurrency?: number;\n /** Override the store's per-op budget for this call (`false` lifts it). */\n readonly budget?: BudgetOption;\n /** Segments whose ids are subtracted from the result. */\n readonly exclude?: readonly SegmentRef[];\n /**\n * Allow an operand that names a segment which does not exist. Default `false` \u2014 a combine refuses one,\n * because a misspelled or mis-namespaced operand is indistinguishable from a correct one in the result.\n * Set `true` when you genuinely intend to combine against a name that may not have been created yet.\n */\n readonly allowAbsentOperands?: boolean;\n}\n\n/** One resolved operand of a chunk-aligned combine: its chunk-key set + pinned generation. */\ninterface Operand {\n readonly seg: SegmentRef;\n readonly keys: Set<number>;\n /** The cache-key component \u2014 a `currentVersion` string, a generation number, or absent. */\n readonly gen: string | number | null | undefined;\n}\n\nexport class SegmentEngine {\n private readonly storage: StorageChunkSource;\n private readonly cache: BoundedLru<string, CodecBitmap> | undefined;\n private readonly codec: CodecInterface;\n private readonly maxBitmapBytes: number;\n private readonly clock: Pick<Clock, 'now'>;\n private readonly metrics: IMetricsSink;\n private readonly metricsOn: boolean;\n /** Resolved per-op budget (null = disabled); undefined deps \u21D2 the generous default. */\n private readonly budget: Budget | null;\n\n constructor(deps: EngineDeps) {\n this.storage = deps.storage;\n this.cache = deps.cache;\n this.codec = deps.codec;\n this.maxBitmapBytes = deps.maxBitmapBytes ?? DEFAULT_MAX_BITMAP_BYTES;\n this.clock = deps.clock ?? ZERO_CLOCK;\n // undefined \u21D2 the generous default; null \u21D2 explicitly disabled (must not be re-defaulted by `??`).\n this.budget = deps.budget === undefined ? DEFAULT_BUDGET : deps.budget;\n // Wrap for defense-in-depth (idempotent for the no-op) so even a direct engine construction with a\n // throwing sink can't break the data path; `metricsOn` short-circuits all emission when unused.\n this.metrics = safeMetrics(deps.metrics ?? NOOP_METRICS);\n this.metricsOn = this.metrics !== NOOP_METRICS;\n }\n\n /** Membership: one chunk lookup \u2014 the cache, else one Storage fetch of that chunk. */\n async has(seg: SegmentRef, id: number): Promise<boolean> {\n const { chunkKey, remainder } = splitId(id);\n const chunk = await this.storageChunk({ ...seg, chunkKey }, await this.cacheVersion(seg));\n return chunk ? chunk.has(remainder) : false;\n }\n\n /**\n * Cardinality. When the Storage source can serve per-chunk cardinality from its `.crbm` index (the `.crbm`\n * source can), the count is summed from the index with **zero payload reads**. A source without that\n * capability (the in-memory source) falls back to fetching every chunk.\n */\n async count(seg: SegmentRef): Promise<number> {\n const cardinalities = this.storage.cardinalities ? await this.storage.cardinalities(seg) : null;\n if (cardinalities) {\n let total = 0;\n for (const [k, n] of cardinalities) {\n this.assertChunkKeyInRange(k);\n total += n;\n }\n return total;\n }\n const chunkKeys = await this.chunkKeys(seg);\n checkBudget(this.budget, chunkKeys.length, 'count'); // one storage fetch per chunk (before fan-out)\n const gen = await this.cacheVersion(seg); // after the shape read \u2014 see `combine`\n let total = 0;\n for (const chunkKey of chunkKeys) {\n total += (await this.storageChunk({ ...seg, chunkKey }, gen))?.size ?? 0;\n }\n return total;\n }\n\n /** Whether the Storage source can measure segment size (for grounded cost); false \u21D2 storage isn't grounded. */\n get supportsStorageSize(): boolean {\n return typeof this.storage.sizeOf === 'function';\n }\n\n /** Grounded Storage size of a segment's current generation (cost reporting), or null if it has no generation. */\n segmentSize(seg: SegmentRef): Promise<SegmentSize | null> {\n return this.storage.sizeOf ? this.storage.sizeOf(seg) : Promise.resolve(null);\n }\n\n /** Every id, ascending, one chunk at a time. */\n async *iterate(seg: SegmentRef): AsyncGenerator<number> {\n const chunkKeys = await this.chunkKeys(seg);\n checkBudget(this.budget, chunkKeys.length, 'iterate'); // one storage fetch per chunk (before fan-out)\n const gen = await this.cacheVersion(seg); // after the shape read \u2014 see `combine`\n for (const chunkKey of chunkKeys) {\n const chunk = await this.storageChunk({ ...seg, chunkKey }, gen);\n if (chunk === null) continue;\n // Read straight off the (possibly cached) instance: iteration does not mutate it.\n for (const remainder of chunk) yield joinId(chunkKey, remainder);\n }\n }\n\n /**\n * `segs[0] \u2229 segs[1] \u2229 \u2026`, minus every id in `options.exclude` \u2014 streamed ascending.\n *\n * The `exclude` operands are what make suppression **compose without materialising**. Applying suppression\n * afterwards (intersect into a temp segment, then subtract) writes an intermediate segment that nobody wants;\n * applying it here folds it into the same chunk-aligned pass. It is also cheaper than it looks: an exclude\n * operand is read **only at the keys that survived the intersection** \u2014 the cost is bounded by the\n * audience's surviving key count and **never scales with the size of the suppression list**. Subtracting a\n * 61,000-chunk global opt-out list costs at most one read per surviving key, not 61,000.\n *\n * ---\n *\n * Chunk-skipping intersection. Aligns each segment's chunk-key set (read from the `.crbm` index, no payload),\n * keeps only keys present in **all** operands (a key missing from any operand can't contribute \u2192 its Storage\n * chunks are never fetched \u2014 the core saving), then for each surviving key fetches the operands' chunks in\n * parallel and hands them to the codec for the AND, streaming results through a bounded in-flight window.\n *\n * **Memory:** the Storage payload footprint is bounded by the window (`concurrency \u00D7 operands \u00D7 chunk`), not by\n * segment size \u2014 that's the Lambda-friendly property.\n *\n * Generation-consistent within the call (normal case): each operand's current generation is resolved **once**\n * up front (before the fan-out) and threaded into every chunk read, so a concurrent load can't corrupt or tear\n * the result \u2014 every chunk read is a whole, checksum-verified, immutable generation. The edge a *long* call can\n * hit: if it straddles a mid-call `cache.genTtlMs` boundary and a load has published, an operand's not-yet-read\n * chunks may re-resolve forward to the newer generation (a generation hop within one long call) \u2014 the call\n * never crashes or returns a torn object, but may mix generations. A shorter call is unaffected **unless the\n * reader cache evicts an operand mid-call** (`maxOpenSegments`): the re-read re-resolves fresh (bypassing the\n * TTL), which can hop generations even sub-TTL \u2014 still whole/immutable per read, never torn.\n */\n intersect(segs: readonly SegmentRef[], options?: CombineOptions): AsyncGenerator<number> {\n return this.combine(segs, options?.exclude ?? [], 'all', 'intersect', options);\n }\n\n /**\n * `segs[0] \u222A segs[1] \u222A \u2026`, minus every id in `options.exclude` \u2014 streamed ascending.\n *\n * **Union is the one composite read with no chunk-skipping**, and that is a property of the operation rather\n * than of this implementation: an id in *any* operand belongs to the result, so every chunk of every operand\n * has to be read. `intersect` can prune a key absent from any operand; union cannot prune anything. It is\n * budgeted exactly like `intersect` so a wide union is refused rather than quietly billed.\n */\n union(segs: readonly SegmentRef[], options?: CombineOptions): AsyncGenerator<number> {\n return this.combine(segs, options?.exclude ?? [], 'any', 'union', options);\n }\n\n /**\n * `seg \\ (excludes[0] \u222A excludes[1] \u222A \u2026)` \u2014 streamed ascending. Suppression on its own.\n *\n * Reads every chunk of `seg` (any of them may survive) but each exclude **only where it overlaps `seg`**, so\n * the cost scales with the segment being filtered rather than with the size of the suppression list.\n */\n andNot(\n seg: SegmentRef,\n excludes: readonly SegmentRef[],\n options?: Omit<CombineOptions, 'exclude'>,\n ): AsyncGenerator<number> {\n return this.combine([seg], excludes, 'all', 'andNot', options);\n }\n\n private async *combine(\n segs: readonly SegmentRef[],\n excludeSegs: readonly SegmentRef[],\n mode: 'all' | 'any',\n op: 'intersect' | 'union' | 'andNot',\n options?: Omit<CombineOptions, 'exclude'>,\n ): AsyncGenerator<number> {\n // Validated HERE rather than in the public wrappers, deliberately. `combine` is an async generator, so a\n // throw surfaces when the caller first iterates \u2014 which is the behaviour `intersect` has always had, and\n // `await expect(collect(engine.intersect([]))).rejects` in the suite depends on it. Guarding in the\n // wrappers would make them throw synchronously instead, a silent breaking change for anyone whose\n // try/catch sits around the iteration. Delegating through `yield*` would restore it at the cost of a\n // microtask per id on the hottest streaming path, which is not a trade worth making for an error case.\n if (segs.length === 0) {\n throw new ValidationError(`${op} requires at least one segment`);\n }\n if (op === 'andNot' && excludeSegs.length === 0) {\n throw new ValidationError('andNot requires at least one segment to subtract');\n }\n const limit = options?.concurrency ?? DEFAULT_INTERSECT_CONCURRENCY;\n if (!Number.isInteger(limit) || limit < 1) {\n throw new ValidationError(\n `concurrency must be a positive integer; got ${options?.concurrency}`,\n );\n }\n // Per-op budget override (else the store budget); resolved before any I/O so a bad value fails fast. A\n // partial override inherits the store's tightening (not the generous default) \u2014 see resolvePerOpBudget.\n const budget = resolvePerOpBudget(options?.budget, this.budget);\n\n // \u2460 Index-map extraction: each operand's chunk-key set + its current generation, resolved ONCE here (not\n // per chunk) so the fan-out below adds no per-chunk generation re-resolve. Only metadata so far.\n //\n // Generation resolution ordering: resolve `gen` AFTER the shape read (`listChunkKeys`). A non-empty shape\n // read means the source resolved and cached a non-null snapshot, so `gen` cannot then come back null while\n // storage data is present, and `storageChunk` cannot skip every chunk on a stale null.\n //\n // Honest note on how much this ordering now buys, because the comment used to claim more than it can and a\n // future reader should not take an untested claim for a tested one. Against a `CrbmStorageChunkSource` \u2014 the\n // only source with a generation to resolve \u2014 both reads go through the same resolved-reader memo, so the\n // pathological state (`keys` non-empty, `gen` null) does not arise and swapping the two is observably\n // identical. The ordering is kept because it is the order that is correct for *any* source\n // satisfying the port \u2014 a custom source that resolves its shape and its generation independently can still\n // produce that state \u2014 not because a test can currently tell the difference.\n //\n // Within a call shorter than `cache.genTtlMs` the two share one snapshot, so the read is\n // generation-consistent \u2014 absent cache-pressure eviction (see `intersect`).\n const extract = async (seg: SegmentRef): Promise<Operand> => {\n const keys = await this.chunkKeys(seg);\n const gen = await this.cacheVersion(seg);\n return { seg, keys: new Set(keys), gen };\n };\n const [operands, excludes] = await Promise.all([\n Promise.all(segs.map(extract)),\n Promise.all(excludeSegs.map(extract)),\n ]);\n await this.refuseAbsentOperands([...operands, ...excludes], options?.allowAbsentOperands, op);\n\n // \u2461 Key alignment. Candidate keys come from the INCLUDE operands only \u2014 an exclude can subtract ids from a\n // chunk but can never introduce one, so a key no include holds cannot appear in the result however large\n // the suppression list is. That asymmetry is what makes suppression cheap here.\n //\n // 'all' (intersect / andNot): keys present in EVERY include. Start from the smallest set to minimize the\n // scan \u2014 a key missing from any operand cannot survive the AND.\n // 'any' (union): keys present in ANY include. No pruning is possible; see `union`'s note.\n const candidates: number[] = [];\n if (mode === 'all') {\n const pivot = operands.reduce((a, b) => (a.keys.size <= b.keys.size ? a : b));\n for (const k of pivot.keys) {\n if (operands.every((o) => o.keys.has(k))) candidates.push(k);\n }\n } else {\n const seen = new Set<number>();\n for (const o of operands) for (const k of o.keys) seen.add(k);\n for (const k of seen) candidates.push(k);\n }\n candidates.sort((a, b) => a - b); // defensive: `chunkKeys` already returns sorted; don't rely on it\n const common = candidates;\n\n // Denial-of-wallet budget (before the fan-out AND before we emit a \"work done\" metric): the heavy cost is\n // one storage fetch per surviving key per operand \u2014 refuse up front if that would exceed the budget. Placed\n // above the metric so a refused intersect doesn't report chunks it never fetched.\n //\n // Units are the chunk reads this will actually issue, counted per key: every include present at that key\n // (all of them under 'all'), plus only those excludes that hold the key. Counting excludes as always-present\n // would refuse work that costs nothing \u2014 the whole point of the asymmetry above. For a plain `intersect`\n // with no excludes this reduces to `common.length * operands.length`.\n let units = 0;\n for (const key of common) {\n for (const o of operands) if (mode === 'all' || o.keys.has(key)) units += 1;\n for (const e of excludes) if (e.keys.has(key)) units += 1;\n }\n checkBudget(budget, units, op);\n\n // Emit the chunk-skipping efficiency: `fetched` = shared keys we'll read, `skipped` = distinct keys\n // pruned across all operands (never fetched \u2014 the core saving). Bounded metadata work, no extra I/O.\n if (this.metricsOn) {\n const distinctKeys = new Set<number>();\n for (const o of operands) for (const k of o.keys) distinctKeys.add(k);\n for (const e of excludes) for (const k of e.keys) distinctKeys.add(k);\n // `fetchedChunks` counts **distinct chunk keys**, not per-operand reads \u2014 its long-standing documented\n // unit, asserted by the bench anchors and the metrics tests. Deliberately NOT changed to match the\n // budget's request count: they measure different things on purpose (keys vs billable requests). The\n // relationship is documented on the event instead.\n this.metrics.onEvent({\n kind: 'intersect',\n op,\n operands: segs.length + excludes.length,\n fetchedChunks: common.length,\n // Never negative: under 'any' every candidate key came from some operand, so `distinctKeys` is a\n // superset of `common`; excludes only ever add keys here.\n skippedChunks: distinctKeys.size - common.length,\n });\n }\n\n // \u2462\u2013\u2464 Surgical streaming AND through a bounded, order-preserving window: fetch+intersect at most\n // `limit` keys concurrently, yield each key's ids before priming far ahead (bounded Storage footprint).\n // Each task resolves to a value (never rejects) so an error on one key can't leave the other in-flight\n // promises unhandled \u2014 we surface it, in key order, when its slot is drained.\n type Slot = { key: number; result: CodecBitmap | null; error?: unknown };\n const startAt = (key: number): Promise<Slot> =>\n this.combineChunk(operands, excludes, mode, key).then(\n (result) => ({ key, result }),\n (error: unknown) => ({ key, result: null, error }),\n );\n\n const inFlight: Array<Promise<Slot>> = [];\n let next = 0;\n while (next < common.length && inFlight.length < limit) inFlight.push(startAt(common[next++]!));\n while (inFlight.length > 0) {\n const slot = await inFlight.shift()!; // FIFO over ascending keys \u21D2 ascending output\n if (next < common.length) inFlight.push(startAt(common[next++]!));\n if (slot.error !== undefined) throw slot.error;\n if (slot.result && !slot.result.isEmpty) {\n for (const remainder of slot.result) yield joinId(slot.key, remainder);\n }\n }\n }\n\n /**\n * The AND (or OR) of one chunk key across all operands, minus the excludes that hold it, or `null` if empty.\n * Operand chunks are fetched **in parallel** (the spec's parallel byte-range reads).\n *\n * The accumulator is a **clone** of the first operand's chunk, and that clone is load-bearing: every other\n * bitmap here is the cached, shared Storage instance and must never be mutated, or the cache is poisoned for\n * every later reader. The remaining operands and the excludes are only *read* by the in-place ops, so they are\n * used as-is \u2014 one clone per key, not one per operand.\n */\n private async combineChunk(\n operands: ReadonlyArray<Operand>,\n excludes: ReadonlyArray<Operand>,\n mode: 'all' | 'any',\n chunkKey: number,\n ): Promise<CodecBitmap | null> {\n // Under 'any' an include may simply not hold this key; skip it rather than fetching a certainly-empty\n // chunk. Under 'all' every include holds every candidate key by construction, so the filter is a no-op.\n const present = mode === 'all' ? operands : operands.filter((o) => o.keys.has(chunkKey));\n if (present.length === 0) return null;\n const chunks = await Promise.all(\n present.map((op) => this.storageChunk({ ...op.seg, chunkKey }, op.gen)),\n );\n // A key the index lists but the source cannot produce bytes for reads as empty \u2014 and under AND an empty\n // operand empties the result.\n if (mode === 'all' && chunks.some((c) => c === null)) return null;\n const first = chunks[0];\n const acc = first ? first.clone() : this.codec.empty();\n for (let i = 1; i < chunks.length; i++) {\n const other = chunks[i];\n if (other === null || other === undefined) continue; // 'any' only \u2014 'all' returned above\n if (mode === 'all') {\n acc.andInPlace(other);\n if (acc.isEmpty) return null; // once empty, the remaining operands can't revive it\n } else {\n acc.orInPlace(other);\n }\n }\n if (acc.isEmpty) return null;\n\n // Suppression, folded into the same pass. Only excludes that actually hold this key are fetched \u2014 this is\n // where a large global opt-out list stops being expensive. Fetched lazily rather than alongside the\n // includes above, because an AND that collapsed to empty means there is nothing left to suppress.\n const relevant = excludes.filter((e) => e.keys.has(chunkKey));\n if (relevant.length > 0) {\n const cuts = await Promise.all(\n relevant.map((e) => this.storageChunk({ ...e.seg, chunkKey }, e.gen)),\n );\n for (const cut of cuts) {\n if (cut === null) continue;\n acc.andNotInPlace(cut);\n if (acc.isEmpty) return null;\n }\n }\n return acc;\n }\n\n /** The segment's chunk keys, ascending \u2014 a shape read off the index, no payload. Keys are untrusted (invariant 5). */\n private async chunkKeys(seg: SegmentRef): Promise<number[]> {\n const keys = [...(await this.storage.listChunkKeys(seg))];\n for (const k of keys) this.assertChunkKeyInRange(k);\n return keys.sort((a, b) => a - b);\n }\n\n /**\n * Tier-derived keys are untrusted (invariant 5) \u2014 fail fast on a corrupt/out-of-range key rather than\n * letting it flow into the id-routing step and produce a bogus id.\n */\n private assertChunkKeyInRange(k: number): void {\n if (!Number.isInteger(k) || k < 0 || k >= CHUNK_COUNT) {\n throw new IntegrityError(`chunk key from a tier is out of range: ${k}`);\n }\n }\n\n /**\n * The other half of invariant 5: a chunk payload holds **remainders** \u2014 16-bit offsets within one chunk \u2014 so\n * every value must be `<= 0xffff`.\n *\n * Nothing upstream establishes that. The byte cap bounds *size*, and CRC/AEAD prove the bytes are the bytes\n * that were written \u2014 which anyone able to write the bucket satisfies trivially. A value `>= 65536` would then\n * reach the id-routing step, which masks it (`remainder & 0xffff`) and emits a **fabricated id belonging to a different\n * chunk's id space**: indistinguishable from real data, inflating `count()` and creating spurious `intersect`\n * matches.\n *\n * Costs one `maximum()` per chunk, not per id \u2014 `maximum` is optional on the codec seam precisely so a codec\n * that cannot answer in O(1) opts out instead of making the read path walk every value.\n */\n private assertChunkPayloadInRange(bitmap: CodecBitmap, chunkKey: number): void {\n const max = bitmap.maximum?.();\n if (max !== undefined && max > MAX_REMAINDER) {\n throw new IntegrityError(\n `chunk ${chunkKey} payload holds value ${max}, outside the 16-bit remainder range ` +\n `[0, ${MAX_REMAINDER}] \u2014 the stored object is corrupt or was not written by this codec`,\n );\n }\n }\n\n /**\n * Refuse a combine whose operand names a segment that was never created.\n *\n * A segment that resolves to nothing is ambiguous in a way that matters only here. Read it directly and\n * \"empty\" is the right answer either way. Pass it as an **operand** and the two states diverge: a\n * suppression list with nobody on it correctly suppresses nothing, while one whose namespace you omitted\n * *silently* suppresses nothing \u2014 and the result is not empty and obviously wrong, it is the full audience\n * and plausibly right. That direction is the dangerous one: the failure mode is mailing the people who\n * opted out.\n *\n * The asymmetry is why this is checked rather than left to the caller. A mistyped **include** collapses an\n * intersect to nothing, which you notice; a mistyped **exclude** removes a safeguard, which you do not. Both\n * are refused, because both are wiring errors and one rule is easier to trust than two.\n *\n * **Costs nothing on a normal combine.** `exists` is consulted only for an operand that resolved to zero\n * chunks \u2014 a segment with data is self-evidently registered \u2014 so the check is a registry read exactly when\n * a combine was about to do something suspicious, and no reads at all otherwise. A source that cannot answer\n * `exists` (it has no notion of registration) skips the check rather than guessing.\n */\n private async refuseAbsentOperands(\n resolved: readonly Operand[],\n allow: boolean | undefined,\n op: string,\n ): Promise<void> {\n if (allow === true || this.storage.exists === undefined) return;\n const empty = resolved.filter((o) => o.keys.size === 0);\n if (empty.length === 0) return;\n const checked = await Promise.all(\n empty.map(async (o) => ({ seg: o.seg, exists: await this.storage.exists!(o.seg) })),\n );\n const absent = checked.filter((c) => !c.exists).map((c) => c.seg);\n if (absent.length === 0) return;\n const named = absent\n .map((s) => (s.namespace === undefined ? `\"${s.segment}\"` : `\"${s.namespace}/${s.segment}\"`))\n .join(', ');\n throw new ValidationError(\n `${op}: operand ${named} names a segment that does not exist, so it would contribute nothing \u2014 ` +\n `an exclude would suppress no ids and an include would contribute none. Check the name and the ` +\n `namespace (a segment addressed without its \\`namespace\\` is a DIFFERENT segment). ` +\n `Pass \\`allowAbsentOperands: true\\` if you meant it.`,\n );\n }\n\n /**\n * Drop every piece of state this engine derived from `ref`, and tell the Storage source to do the same.\n *\n * The decoded-chunk cache is keyed by generation, which handles a *publish* (the new generation misses) but\n * not a *destruction*: a segment that was erased from, dropped, shredded or retired has no newer generation\n * whose key would miss, so its decoded chunks stay resident and keep answering. That is why the erasing\n * process itself could report `erased: true` and then still answer `true` for the same id, out of RAM, with\n * no storage read to intercept.\n *\n * Called by the destructive verbs on the facade. Synchronous and best-effort \u2014 forgetting cannot fail.\n */\n invalidate(ref: SegmentRef): void {\n const prefix = segmentPrefix(ref);\n this.cache?.deleteWhere((key) => key.startsWith(prefix));\n this.storage.invalidate?.(ref);\n }\n\n /** The segment's current generation, resolved once per op (`undefined` \u21D2 source can't report it). */\n private currentGen(seg: SegmentRef): Promise<number | null | undefined> {\n return this.storage.currentGeneration\n ? this.storage.currentGeneration(seg)\n : Promise.resolve(undefined);\n }\n\n /**\n * The cache-key component identifying **which bytes** this op will read: the source's `currentVersion` when\n * it has one, else the generation alone.\n *\n * The generation alone is not an identity. `nextGeneration` restarts at 0 once a row is purged and the\n * bucket emptied, so a retired-and-re-created name serves different data at the same `currentGen` \u2014 and a\n * decoded chunk cached under `(segment, chunk, 0)` is handed straight back to the new incarnation. That is an\n * erased id reappearing with no read to intercept it, which is why this is keyed on the version rather than\n * the number.\n */\n private async cacheVersion(seg: SegmentRef): Promise<string | number | null | undefined> {\n if (this.storage.currentVersion) return this.storage.currentVersion(seg);\n return this.currentGen(seg);\n }\n\n /**\n * Decode a Storage chunk. `gen` is the segment's current generation, resolved **once per op** by the caller (not\n * per chunk \u2014 that would put a registry re-resolve on every chunk of a count/intersect). The cache is\n * keyed by it, so a load that advances the generation misses the cache and re-reads the new bytes instead of\n * serving a stale decoded chunk (an erased id can't resurrect from a cached superseded chunk). `gen === null`\n * \u21D2 the source reports no current generation \u21D2 no storage bytes for any chunk, so skip the fetch entirely.\n * `gen === undefined` \u21D2 the source can't report a generation (pins one for its lifetime) \u21D2 the key stays\n * generation-free. Superseded-generation entries age out under the LRU ceiling \u2014 no active purge.\n *\n * The returned instance is **shared** (it may be the cached one): callers read it or clone it, never mutate it.\n */\n private async storageChunk(\n ref: ChunkRef,\n gen: string | number | null | undefined,\n ): Promise<CodecBitmap | null> {\n if (gen === null) return null;\n const cacheKey = gen === undefined ? chunkRefKey(ref) : chunkGenKey(ref, gen);\n if (this.cache) {\n const cached = this.cache.get(cacheKey);\n if (cached) {\n if (this.metricsOn) this.metrics.onEvent({ kind: 'cache', hit: true });\n return cached;\n }\n if (this.metricsOn) this.metrics.onEvent({ kind: 'cache', hit: false });\n }\n const startedAt = this.metricsOn ? this.clock.now() : 0;\n const bytes = await this.storage.getChunk(ref);\n if (this.metricsOn) {\n this.metrics.onEvent({\n kind: 'storage.get',\n namespace: ref.namespace,\n segment: ref.segment,\n bytes: bytes ? bytes.length : 0,\n ms: Math.max(0, this.clock.now() - startedAt),\n });\n }\n if (!bytes) return null;\n const bitmap = this.codec.safeDeserialize(bytes, this.maxBitmapBytes);\n this.assertChunkPayloadInRange(bitmap, ref.chunkKey);\n this.cache?.set(cacheKey, bitmap);\n return bitmap;\n }\n}\n", "/**\n * Bounded LRU cache with optional TTL \u2014 the cache tier's memory ceiling.\n *\n * Time comes from an injected `Clock` (never `Date.now()`) so the cache is deterministic\n * under simulation.\n *\n * The cache can be bounded by entry **count** (`maxEntries`, always) and, optionally, by an aggregate\n * **byte weight** (`maxBytes`). The byte bound exists for values whose footprint is large and uneven \u2014 the\n * storage reader cache, where one entry pins a fully-parsed `.crbm` index that can be ~6 MB for a wide segment\n * yet a few hundred bytes for a small one (a count-only bound lets 1024 wide indices blow a Lambda's\n * memory even though the count is \"in bounds\"). Weights arrive **after** insertion (a cached reader is a\n * pending promise; its size is known only once it resolves), so weight is reported via {@link setWeight} and\n * eviction re-runs then.\n */\nimport type { Clock } from './determinism';\nimport { ValidationError } from './errors';\n\nexport interface LruOptions {\n /** Hard ceiling on entries; the least-recently-used is evicted past it. */\n readonly maxEntries: number;\n /**\n * Optional aggregate byte ceiling across all entries' reported weights (see {@link BoundedLru.setWeight}).\n * When set, the least-recently-used entries are evicted until the total is within budget \u2014 in addition to\n * the `maxEntries` bound. Omit for a pure count-bounded cache (weights stay 0, no byte eviction).\n */\n readonly maxBytes?: number;\n /** Optional time-to-live in ms; an entry older than this is treated as absent. */\n readonly ttlMs?: number;\n /** Only `now()` is used (never `sleep`), so a count-only cache can pass a minimal time source. */\n readonly clock: Pick<Clock, 'now'>;\n}\n\ninterface Entry<V> {\n readonly value: V;\n readonly expiresAt: number; // Infinity when no TTL\n bytes: number; // reported weight (0 until setWeight); summed against maxBytes\n}\n\nexport class BoundedLru<K, V> {\n private readonly map = new Map<K, Entry<V>>();\n private readonly maxEntries: number;\n private readonly maxBytes: number | undefined;\n private readonly ttlMs: number | undefined;\n private readonly clock: Pick<Clock, 'now'>;\n private totalBytes = 0;\n\n constructor(options: LruOptions) {\n if (!Number.isInteger(options.maxEntries) || options.maxEntries < 1) {\n throw new ValidationError(`maxEntries must be a positive integer; got ${options.maxEntries}`);\n }\n if (\n options.maxBytes !== undefined &&\n (!(options.maxBytes > 0) || !Number.isFinite(options.maxBytes))\n ) {\n throw new ValidationError(\n `maxBytes must be a positive finite number; got ${options.maxBytes}`,\n );\n }\n if (options.ttlMs !== undefined && (!(options.ttlMs > 0) || !Number.isFinite(options.ttlMs))) {\n throw new ValidationError(`ttlMs must be a positive finite number; got ${options.ttlMs}`);\n }\n this.maxEntries = options.maxEntries;\n this.maxBytes = options.maxBytes;\n this.ttlMs = options.ttlMs;\n this.clock = options.clock;\n }\n\n get(key: K): V | undefined {\n const entry = this.map.get(key);\n if (entry === undefined) return undefined;\n if (entry.expiresAt <= this.clock.now()) {\n this.drop(key, entry);\n return undefined;\n }\n // Refresh recency: re-insert so it becomes most-recently-used.\n this.map.delete(key);\n this.map.set(key, entry);\n return entry.value;\n }\n\n /** Read a value **without** counting as an access (recency unchanged, no purge on expiry). */\n peek(key: K): V | undefined {\n return this.map.get(key)?.value;\n }\n\n set(key: K, value: V): void {\n const prev = this.map.get(key);\n if (prev !== undefined) this.totalBytes -= prev.bytes;\n this.map.delete(key);\n const expiresAt = this.ttlMs === undefined ? Infinity : this.clock.now() + this.ttlMs;\n this.map.set(key, { value, expiresAt, bytes: 0 });\n while (this.map.size > this.maxEntries) {\n const oldest = this.map.keys().next();\n if (oldest.done === true) break;\n this.dropKey(oldest.value);\n }\n this.evictToBudget(key);\n }\n\n /**\n * Report an entry's byte weight (typically once a cached promise resolves and its size is known). Updates\n * the running total and evicts the least-recently-used entries if the aggregate now exceeds `maxBytes`.\n * Recency is **not** changed. The `key` being weighted is protected from this eviction pass (we just\n * populated it) \u2014 so a single entry larger than the whole budget is kept rather than immediately dropped.\n */\n setWeight(key: K, bytes: number): void {\n if (!(bytes >= 0) || !Number.isFinite(bytes)) {\n // Guard the running total against a NaN/negative weight, which no removal path could ever restore.\n throw new ValidationError(`weight must be a non-negative finite number; got ${bytes}`);\n }\n const entry = this.map.get(key);\n if (entry === undefined) return;\n this.totalBytes += bytes - entry.bytes;\n entry.bytes = bytes;\n this.evictToBudget(key);\n }\n\n private evictToBudget(protectKey: K): void {\n if (this.maxBytes === undefined) return;\n while (this.totalBytes > this.maxBytes && this.map.size > 1) {\n const oldest = this.oldestExcept(protectKey);\n if (oldest === undefined) break; // only the protected key remains\n this.dropKey(oldest);\n }\n }\n\n /** The least-recently-used key that is not `protectKey`, or undefined if none other exists. */\n private oldestExcept(protectKey: K): K | undefined {\n for (const key of this.map.keys()) {\n if (key !== protectKey) return key;\n }\n return undefined;\n }\n\n private dropKey(key: K): void {\n const entry = this.map.get(key);\n if (entry !== undefined) this.drop(key, entry);\n }\n\n private drop(key: K, entry: Entry<V>): void {\n this.totalBytes -= entry.bytes;\n this.map.delete(key);\n }\n\n /** Membership test that does NOT count as an access (recency is unchanged). Purges if expired. */\n has(key: K): boolean {\n const entry = this.map.get(key);\n if (entry === undefined) return false;\n if (entry.expiresAt <= this.clock.now()) {\n this.drop(key, entry);\n return false;\n }\n return true;\n }\n\n delete(key: K): boolean {\n const entry = this.map.get(key);\n if (entry === undefined) return false;\n this.drop(key, entry);\n return true;\n }\n\n /**\n * Delete every entry whose key matches `pred`, returning how many went. Used to drop one segment's decoded\n * chunks when something destroys the generation they came from \u2014 a deletion the generation-keyed cache\n * cannot express on its own, because a *destroyed* segment has no newer generation whose key would miss.\n * Linear in the cache size; called on admin paths (erasure, drop, shred, retirement), never on a read.\n */\n deleteWhere(pred: (key: K) => boolean): number {\n let dropped = 0;\n // Snapshot the keys first: `drop` mutates the map, and deleting during its own iteration is fragile.\n for (const key of [...this.map.keys()]) {\n if (!pred(key)) continue;\n const entry = this.map.get(key);\n if (entry === undefined) continue;\n this.drop(key, entry);\n dropped += 1;\n }\n return dropped;\n }\n\n clear(): void {\n this.map.clear();\n this.totalBytes = 0;\n }\n\n /** Current entry count (may include not-yet-evicted expired entries). */\n get size(): number {\n return this.map.size;\n }\n\n /** Current aggregate reported weight (bytes) across all entries. */\n get weightBytes(): number {\n return this.totalBytes;\n }\n}\n", "/**\n * Cost model & estimator \u2014 pure, `core/`-safe (no I/O, time, or SDK). Turns the verified economics of the\n * loaded store into a first-class library API:\n *\n * - {@link estimateCost} \u2014 **planning** mode: pure what-if from segment sizes + a workload (sizing/sales).\n * - `segment.costReport()` (wired in the facade) \u2014 **grounded** mode: the segment's real size from the `.crbm`\n * index (free + exact, no payload reads) + a supplied workload for request rates. (Whole-store aggregation is\n * a later phase.)\n *\n * Guiding split: **formulas are the spec; rates are a pluggable {@link PricingProfile}.** The report always emits\n * a {@link CostReport.verdict} that includes the lose-zone \u2014 it never hides where an always-on cache (Redis)\n * wins.\n *\n * What the model covers, and states in `assumptions.notes`: object-store GETs for reads and intersections,\n * object-store PUTs for loads, and storage. Same-region egress is treated as free and internet egress is not\n * modeled; request cost is derived from the supplied workload rates (deriving it from live metrics counters is a\n * later refinement). There is no per-write term because the loaded store has no per-id write: data arrives as\n * generations, and a generation is a load.\n */\nimport { ValidationError } from './errors';\n\n/** Pluggable rate card. Rates differ by cloud/region/term and drift over time; the formulas don't. */\nexport interface PricingProfile {\n readonly name: string;\n readonly storage: {\n /** Object GET (per **million** requests). A ranged GET bills as a full GET. */\n readonly getPerMillion: number;\n /** Object PUT (per million) \u2014 what a load pays, per request. */\n readonly putPerMillion: number;\n readonly storagePerGiBMonth: number;\n };\n /** The always-on baseline to compare against (e.g. an ElastiCache HA cluster). */\n readonly redis: { readonly monthlyUSD: number };\n}\n\n/**\n * Default profile \u2014 **AWS us-east-1, on-demand**, mid-2026, from the fact-checked\n * published pricing rather than copied from a blog post. Override it for your region, cloud, or committed term.\n */\nexport const AWS_US_EAST_1_ONDEMAND: PricingProfile = {\n name: 'aws-us-east-1-ondemand',\n storage: { getPerMillion: 0.4, putPerMillion: 5.0, storagePerGiBMonth: 0.023 },\n redis: { monthlyUSD: 346 }, // ElastiCache HA: 1 primary + 2 replicas (cache.m7g.large); ~$115 single-node\n};\n\nexport const DEFAULT_PRICING: PricingProfile = AWS_US_EAST_1_ONDEMAND;\n\n/** Sustained access pattern. All rates default to 0; unspecified \u21D2 that op contributes nothing. */\nexport interface Workload {\n /** Point reads (`has`) per second. Each cache miss is one object GET. */\n readonly readsPerSec?: number;\n readonly intersectsPerSec?: number;\n /** CACHE-cache hit rate in `[0, 1]` \u2014 hits are free; only misses cost. Default 0. */\n readonly cacheHitRate?: number;\n /** Storage chunks fetched per intersection (the chunk-skipping survivors). Default 1. */\n readonly chunksPerIntersect?: number;\n /**\n * Generations published per month across the modeled data \u2014 the write side of a loaded store. Default **0**\n * \u21D2 loads are not modeled and the report *discloses* the omission rather than silently under-reporting.\n */\n readonly loadsPerMonth?: number;\n /**\n * PUT-class requests one load issues. Default **1** (a single-object PUT). A multipart load of `P` parts bills\n * `P + 2` (initiate, the parts, complete) \u2014 set it when you know your object sizes. Still small money: at\n * $5/million, a thousand 100-part loads a month is $0.51.\n */\n readonly requestsPerLoad?: number;\n}\n\n/** One (group of) segment(s) for planning. `count` = how many like this (default 1). */\nexport interface SegmentSizing {\n readonly sizeBytes?: number;\n readonly cardinality?: number;\n /** Number of segments with these characteristics. Default 1. */\n readonly count?: number;\n}\n\nexport interface EstimateInput {\n readonly segments: readonly SegmentSizing[];\n readonly workload?: Workload;\n readonly pricing?: PricingProfile;\n}\n\nexport interface CostReport {\n readonly monthlyUSD: {\n readonly byOp: {\n readonly reads: number;\n readonly intersects: number;\n readonly storage: number;\n /** Loads (object PUTs). 0 unless `loadsPerMonth` is set. */\n readonly loads: number;\n };\n readonly total: number;\n };\n /**\n * Sustained read rate at which the pay-per-use model's cost passes the flat Redis baseline (with every other\n * axis at 0), **evaluated at this report's `cacheHitRate`** \u2014 so a higher cache-hit rate raises it (cache hits\n * are free). `Infinity` means it never crosses (a 100% cache-hit rate). The published anchor (~329 reads/s) is\n * at `cacheHitRate: 0`.\n */\n readonly redisCrossover: { readonly readsPerSec: number };\n readonly verdict: 'win-big' | 'win' | 'lose-zone';\n readonly rationale: string;\n readonly assumptions: {\n readonly cacheHitRate: number;\n readonly pricingName: string;\n /** True when segment **sizes** were real (grounded `costReport`), false for a pure `estimateCost`. */\n readonly grounded: boolean;\n readonly notes: readonly string[];\n };\n}\n\nconst SECONDS_PER_MONTH = 730 * 3600; // 2,628,000 \u2014 the research's convention\nconst GIB = 1024 ** 3;\n\n/** Fail-fast at the boundary: reject non-finite / negative inputs rather than leak NaN into the report. */\nfunction requireFiniteNonNeg(n: number, field: string): number {\n if (!Number.isFinite(n) || n < 0) {\n throw new ValidationError(`${field} must be a finite number >= 0; got ${n}`);\n }\n return n;\n}\n\nfunction clamp01(n: number): number {\n return n < 0 ? 0 : n > 1 ? 1 : n;\n}\n\n/** Rough bytes for a segment when only cardinality is known: 2 B/value (array-container upper bound). */\nfunction sizingBytes(spec: SegmentSizing): number {\n if (spec.sizeBytes !== undefined) return requireFiniteNonNeg(spec.sizeBytes, 'segment.sizeBytes');\n if (spec.cardinality !== undefined) {\n return requireFiniteNonNeg(spec.cardinality, 'segment.cardinality') * 2;\n }\n return 0;\n}\n\n/** Core report builder shared by planning + grounded modes. `storageBytes` is total across all segments. */\nfunction buildReport(input: {\n readonly storageBytes: number;\n readonly workload: Workload;\n readonly pricing: PricingProfile;\n readonly grounded: boolean;\n readonly extraNotes?: readonly string[];\n}): CostReport {\n const { pricing, grounded } = input;\n const { storage, redis } = pricing;\n const S = SECONDS_PER_MONTH;\n\n // The pricing profile is a public, caller-supplied boundary input too \u2014 validate every rate that feeds\n // the report so a malformed profile fails fast rather than leaking NaN/Infinity dollars + a bogus verdict.\n requireFiniteNonNeg(storage.getPerMillion, 'pricing.storage.getPerMillion');\n requireFiniteNonNeg(storage.putPerMillion, 'pricing.storage.putPerMillion');\n requireFiniteNonNeg(storage.storagePerGiBMonth, 'pricing.storage.storagePerGiBMonth');\n requireFiniteNonNeg(redis.monthlyUSD, 'pricing.redis.monthlyUSD');\n\n const storageBytes = requireFiniteNonNeg(input.storageBytes, 'storageBytes');\n const cacheHitRate = clamp01(\n requireFiniteNonNeg(input.workload.cacheHitRate ?? 0, 'cacheHitRate'),\n );\n const readsPerSec = requireFiniteNonNeg(input.workload.readsPerSec ?? 0, 'readsPerSec');\n const intersectsPerSec = requireFiniteNonNeg(\n input.workload.intersectsPerSec ?? 0,\n 'intersectsPerSec',\n );\n const chunksPerIntersect = requireFiniteNonNeg(\n input.workload.chunksPerIntersect ?? 1,\n 'chunksPerIntersect',\n );\n const loadsPerMonth = requireFiniteNonNeg(input.workload.loadsPerMonth ?? 0, 'loadsPerMonth');\n const requestsPerLoad = requireFiniteNonNeg(\n input.workload.requestsPerLoad ?? 1,\n 'requestsPerLoad',\n );\n\n // Per-request unit costs (USD). Same-region egress is free; internet egress not modeled.\n const storageGetUSD = storage.getPerMillion / 1e6;\n const putUSD = storage.putPerMillion / 1e6;\n\n // Monthly volumes.\n const missFraction = 1 - cacheHitRate;\n const readMisses = readsPerSec * S * missFraction;\n const intersects = intersectsPerSec * S;\n\n const storageUSD = (storageBytes / GIB) * storage.storagePerGiBMonth;\n const readsUSD = readMisses * storageGetUSD;\n const intersectsUSD = intersects * chunksPerIntersect * storageGetUSD;\n const loadsUSD = loadsPerMonth * requestsPerLoad * putUSD;\n const total = readsUSD + intersectsUSD + storageUSD + loadsUSD;\n\n // Crossover: the sustained read rate (other axes 0) where request cost alone passes (redis \u2212 fixed storage),\n // evaluated at this report's cache posture (misses).\n const headroom = Math.max(0, redis.monthlyUSD - storageUSD);\n const readsCross =\n storageGetUSD > 0 && missFraction > 0\n ? headroom / (S * storageGetUSD * missFraction)\n : Infinity;\n\n const verdict: CostReport['verdict'] =\n total <= redis.monthlyUSD * 0.1 ? 'win-big' : total < redis.monthlyUSD ? 'win' : 'lose-zone';\n\n const dominant = Math.max(readsUSD, intersectsUSD, storageUSD, loadsUSD);\n let driver = 'storage';\n if (dominant === readsUSD && readsUSD > 0) driver = 'point reads (object GETs)';\n else if (dominant === intersectsUSD && intersectsUSD > 0) driver = 'intersection chunk fetches';\n else if (dominant === loadsUSD && loadsUSD > 0) driver = 'loads (object PUTs)';\n const rationale =\n verdict === 'lose-zone'\n ? `pay-per-use total $${total.toFixed(2)}/mo exceeds the $${redis.monthlyUSD}/mo flat baseline; dominated by ${driver}`\n : verdict === 'win-big'\n ? `$${total.toFixed(2)}/mo \u2014 \u226410% of the $${redis.monthlyUSD}/mo baseline; dominated by ${driver}`\n : `$${total.toFixed(2)}/mo, under the $${redis.monthlyUSD}/mo baseline; dominated by ${driver}`;\n\n const notes = [\n 'Same-region egress treated as free; internet egress is not modeled.',\n 'Request cost is from the supplied workload rates (live-metrics-derived request cost is a later phase).',\n loadsPerMonth > 0\n ? `Loads modeled: ${loadsPerMonth}/mo \u00D7 ${requestsPerLoad} PUT-class request(s) each.`\n : 'Loads are NOT modeled \u2014 set workload.loadsPerMonth (+ requestsPerLoad for multipart) to include them.',\n ...(input.extraNotes ?? []),\n ];\n\n return {\n monthlyUSD: {\n byOp: { reads: readsUSD, intersects: intersectsUSD, storage: storageUSD, loads: loadsUSD },\n total,\n },\n redisCrossover: { readsPerSec: readsCross },\n verdict,\n rationale,\n assumptions: { cacheHitRate, pricingName: pricing.name, grounded, notes },\n };\n}\n\n/**\n * **Planning** cost estimate \u2014 pure, no instance or live data needed (sizing, sales, what-if). Segment sizes\n * are taken as given (or roughly derived from cardinality); use the grounded `segment.costReport()` for\n * exact, real sizes. See {@link CostReport}.\n */\nexport function estimateCost(input: EstimateInput): CostReport {\n const pricing = input.pricing ?? DEFAULT_PRICING;\n const workload = input.workload ?? {};\n let storageBytes = 0;\n for (const spec of input.segments) {\n const count = Math.floor(requireFiniteNonNeg(spec.count ?? 1, 'segment.count'));\n storageBytes += sizingBytes(spec) * count;\n }\n return buildReport({ storageBytes, workload, pricing, grounded: false });\n}\n\n/**\n * **Grounded** report from a real segment byte total (from the `.crbm` index) + a supplied workload. Used by\n * `Segment.costReport()` in the facade. `grounded` defaults to true (the size is exact, not estimated); the\n * caller passes `grounded: false` + a note when the Storage source can't measure size.\n */\nexport function groundedReport(input: {\n readonly storageBytes: number;\n readonly grounded?: boolean;\n readonly workload?: Workload;\n readonly pricing?: PricingProfile;\n readonly extraNotes?: readonly string[];\n}): CostReport {\n return buildReport({\n storageBytes: input.storageBytes,\n workload: input.workload ?? {},\n pricing: input.pricing ?? DEFAULT_PRICING,\n grounded: input.grounded ?? true,\n extraNotes: input.extraNotes,\n });\n}\n", "/**\n * The **due index** \u2014 a time-bucketed set of the segments that carry an expiry, so a retention cycle costs what\n * is *expiring* rather than what the fleet *holds*.\n *\n * Without it, every sweep drains `registry.list()` and filters: `O(fleet)` reads every cycle, forever, even when\n * nothing expires. At 500 segments that is free; at 100,000 on a 15-minute cadence it is a standing bill for\n * finding nothing. Redis solves the same problem with a separate `expires` dict, and Elasticsearch ILM with a\n * scheduler; this is that structure, built out of registry rows so it needs **no driver change** and works on\n * every backend.\n *\n * ## Why a namespace per bucket\n *\n * `IRegistryDriver.list()` filters by **namespace and nothing else** \u2014 there is no cursor, no `startAfter`, no\n * key range. That single fact drives the whole design: the only way to read a *subset* of rows is to make the\n * subset a namespace. So the day a segment expires becomes the namespace, and listing one due day yields exactly\n * the segments due that day.\n *\n * ```\n * cbm.due.20356 \u2500\u25BA the segments whose expiry falls on day 20,356\n * cbm.due.20357 \u2500\u25BA \u2026 day 20,357\n * ```\n *\n * A day index rather than a formatted date, because `core/` reads no ambient time and formatting a date would\n * drag in a calendar (and a timezone question) for no benefit. `Math.floor(expiresAt / 86_400_000)` is total,\n * reversible and has no edge cases.\n *\n * ## The index is a FAST PATH, never the source of truth\n *\n * The segment's own registry row holds the policy; an index row is a pointer that may be stale, missing, or\n * left behind. That is deliberate, and it is what makes a second index safe here \u2014 the failure family this\n * project has hit fourteen times is *a check that cannot fire*, and the answer is that **nothing is only known\n * by the index**:\n *\n * - **A stale pointer cannot retire anything.** The sweep re-reads the live segment row before acting (it\n * already does this \u2014 the `policy-changed` skip), so an index row whose policy has since been cleared or\n * moved is a wasted read and nothing worse.\n * - **A missing pointer cannot lose data.** The full `registry.list()` scan still exists, demoted from the\n * primary path to a periodic **repair** pass. Anything the index never learned about \u2014 a segment written\n * before the index existed, or one whose name is too long to encode (see {@link canIndex}) \u2014 is retired by\n * that pass instead. Slower, never wrong.\n *\n * So the index can only make the sweep *cheaper*, never *wronger*, and both drift directions are bounded by\n * machinery that already exists.\n */\nimport { ValidationError } from './errors';\nimport { MAX_NAME_LENGTH, encodedNameLength } from './validate';\nimport type { RegistryRecord, SegmentRef } from './ports';\n\n/** Namespace prefix for due-index rows. */\nexport const DUE_NAMESPACE_PREFIX = 'cbm.due.';\n\n/** Bucket width. One day: small enough that a cycle reads little, coarse enough that the index stays tiny. */\nexport const DUE_BUCKET_MS = 86_400_000;\n\n/**\n * The name-length cap, and an index row encodes **both** of the original ref's parts into one name \u2014 so a ref\n * whose encoding would exceed it is simply not indexed (see {@link canIndex}).\n *\n * Re-exported from the validator rather than restated. The two were separate constants with the same value\n * until the validator started measuring the **encoded** length; `canIndex` went on counting raw characters and\n * began answering `true` for refs the registry then refused, turning a documented graceful degradation into a\n * guaranteed throw on the retention fast path.\n */\nexport { MAX_NAME_LENGTH };\n\n/** Which bucket an expiry falls in. Total and reversible; no calendar, no timezone, no ambient time. */\nexport function dueBucket(expiresAt: number): number {\n return Math.floor(expiresAt / DUE_BUCKET_MS);\n}\n\n/** The namespace holding one bucket's pointers. */\nexport function dueNamespace(bucket: number): string {\n return `${DUE_NAMESPACE_PREFIX}${bucket}`;\n}\n\n/** Is this record a due-index pointer rather than a segment? */\nexport function isDueIndexRow(record: Pick<RegistryRecord, 'namespace'>): boolean {\n return record.namespace !== undefined && record.namespace.startsWith(DUE_NAMESPACE_PREFIX);\n}\n\n/**\n * Encode a ref into one index-row name, unambiguously.\n *\n * `${namespaceLength}.${namespace}${segment}` \u2014 a decimal length, a dot, then the two parts concatenated. The\n * length prefix is what makes it reversible: every character the grammar allows (`.`, `-`, `_`, `:`, alphanumerics)\n * is legal *inside* a name, so no separator character could ever be unambiguous on its own. Reading the digits\n * up to the first dot tells the parser exactly where the namespace ends.\n */\nexport function encodeDueName(ref: SegmentRef): string {\n const ns = ref.namespace ?? '';\n return `${ns.length}.${ns}${ref.segment}`;\n}\n\n/**\n * Can this ref be indexed at all? False when the encoded name would exceed the grammar's 256-character cap \u2014\n * possible only for a ref whose namespace and segment are together near the limit.\n *\n * **Not indexable is not \"not retired\".** The repair scan still sees the segment's own row, so the consequence\n * is that it expires on the repair cadence instead of the fast one. Callers must not treat `false` as an error.\n */\nexport function canIndex(ref: SegmentRef): boolean {\n // Measured the way the registry will measure it. Counting raw characters here made this guard lie: a ref of\n // 80 `#`s in each part encodes to 483 and was reported indexable, then threw on the write.\n return encodedNameLength(encodeDueName(ref)) <= MAX_NAME_LENGTH;\n}\n\n/** The registry ref of the pointer for `ref` in `bucket`. Throws if the ref cannot be encoded \u2014 check first. */\nexport function dueIndexRef(bucket: number, ref: SegmentRef): SegmentRef {\n const segment = encodeDueName(ref);\n if (segment.length > MAX_NAME_LENGTH) {\n throw new ValidationError(\n `due index: ${JSON.stringify(ref)} encodes to ${segment.length} characters, over the ` +\n `${MAX_NAME_LENGTH}-character name limit \u2014 check canIndex() first; such a segment is retired by the ` +\n `repair scan instead`,\n );\n }\n return { namespace: dueNamespace(bucket), segment };\n}\n\n/**\n * Recover the original ref from an index row's name. `null` for anything we did not write \u2014 a foreign row in\n * the reserved namespace is ignored rather than acted upon.\n */\nexport function decodeDueName(name: string): SegmentRef | null {\n const dot = name.indexOf('.');\n if (dot <= 0) return null;\n const lengthPart = name.slice(0, dot);\n if (!/^(0|[1-9][0-9]*)$/.test(lengthPart)) return null;\n const nsLength = Number(lengthPart);\n const rest = name.slice(dot + 1);\n const namespace = rest.slice(0, nsLength);\n const segment = rest.slice(nsLength);\n // A pointer to a segment with no name is meaningless \u2014 and would round-trip to a ref the grammar rejects.\n // This also covers a length prefix larger than the remainder: the slice then consumes everything and leaves\n // the segment empty, so a separate overflow guard would be unreachable (it was, and was removed).\n if (segment.length === 0) return null;\n return namespace.length === 0 ? { segment } : { namespace, segment };\n}\n\n/**\n * Which buckets a cycle must read at `now`: everything from `since` up to and including the current one.\n *\n * Past buckets are included because a sweep that did not run \u2014 a scaled-to-zero worker, a failed deploy, a\n * paused schedule \u2014 must not leave its buckets stranded. `lookbackBuckets` bounds how far back a first run\n * reaches, so a long outage costs a bounded number of list calls per cycle rather than one per day since the\n * epoch; anything older is the repair scan's job.\n */\nexport function dueBucketsAt(now: number, lookbackBuckets: number): number[] {\n if (!Number.isSafeInteger(lookbackBuckets) || lookbackBuckets < 0) {\n throw new ValidationError(\n `due index: lookbackBuckets must be a non-negative integer; got ${lookbackBuckets}`,\n );\n }\n const current = dueBucket(now);\n const buckets: number[] = [];\n for (let b = current - lookbackBuckets; b <= current; b++) buckets.push(b);\n return buckets;\n}\n", "/**\n * The one bounded drain of `registry.list()`.\n *\n * Three call sites wanted this \u2014 `runConsistencyCheck`, `retireExpired`, and (still unbounded) `eraseNamespace` \u2014\n * and before this module there were two verbatim copies of the loop, two exported ceiling constants with the same\n * value and the same meaning, and two copies of the option validation. A fleet-wide enumeration is exactly the\n * place where \"it drifted between callers\" costs memory rather than tidiness, so it lives once.\n *\n * **Why drain at all rather than stream.** Every caller mutates rows as it goes (a CAS, a delete), and iterating a\n * live listing while doing so is driver-dependent \u2014 a paged LIST may or may not observe its own writes. A\n * snapshot also makes per-cycle counters and limits mean something. The cost is resident memory proportional to\n * the fleet, which is why the ceiling is not optional: at the default of 250,000 rows the snapshot is tens of MB,\n * comfortably more than the 128\u2013256 MB Lambda the guide suggests starting with, so it fails loudly instead.\n */\nimport { BudgetExceededError, ValidationError } from './errors';\nimport { isDueIndexRow } from './due-index';\nimport type { IRegistryDriver, RegistryRecord } from './ports';\n\n/**\n * Ceiling on registry records one fleet-wide scan holds resident. Raise it via the caller's `maxScanSegments` when\n * the fleet really is that large *and* the memory is there; narrow the scan with a `namespace` otherwise.\n */\nexport const DEFAULT_MAX_SCAN_SEGMENTS = 250_000;\n\n/** Fail fast on a bad ceiling BEFORE the (possibly huge) scan, not after. */\nexport function validateMaxScanSegments(value: number, op: string): void {\n if (!Number.isFinite(value) || value < 1) {\n throw new ValidationError(`${op}: maxScanSegments must be a finite number >= 1; got ${value}`);\n }\n}\n\n/**\n * Drain every registry record (optionally one namespace) into an array, refusing past `maxScanSegments`.\n *\n * The bound is checked **before** each push, so the array never exceeds the ceiling the caller agreed to \u2014 the\n * earlier form pushed first and then threw, which meant the very row that broke the budget was already resident,\n * and a caller sizing a container against `maxScanSegments` was off by one row at the worst possible moment.\n */\nexport async function drainRegistry(\n registry: IRegistryDriver,\n options: { namespace?: string; maxScanSegments: number; op: string },\n): Promise<RegistryRecord[]> {\n const { maxScanSegments, op } = options;\n validateMaxScanSegments(maxScanSegments, op);\n const rows: RegistryRecord[] = [];\n for await (const rec of registry.list(options.namespace)) {\n // A due-index pointer is bookkeeping, not a segment. It lives in a reserved namespace, so an unscoped fleet\n // scan would otherwise pay a strong `get` per pointer row in `checkConsistency`, hand it to a retention\n // sweep, and inflate every fleet-wide count. A caller that explicitly scopes to the reserved namespace\n // still sees them.\n if (options.namespace === undefined && isReservedRow(rec)) continue;\n if (rows.length >= maxScanSegments) {\n throw new BudgetExceededError(\n `${op} would enumerate more than ${maxScanSegments} segments \u2014 the scan was abandoned there rather than ` +\n `completed. Narrow it with \\`namespace\\`, or raise \\`maxScanSegments\\` if the fleet really is that large ` +\n `and the memory is available (a record is a few hundred bytes resident).`,\n );\n }\n rows.push(rec);\n }\n return rows;\n}\n\n/**\n * Is this record **bookkeeping** rather than a segment? Covers every reserved family \u2014 today the due-index\n * pointers. **Every unscoped fleet-wide enumeration must skip these**: the bounded drain,\n * the export/eject scan, and the all-namespaces GDPR paths.\n *\n * This is the ONE place a reserved family is declared, and a new one belongs here rather than at the call\n * sites. An earlier cut inlined the comparison per site and shipped with three missed \u2014 including\n * `subjectReport`, where the rows consumed an Art. 15 request's per-op budget. A filter you have to remember at\n * each site is a check that cannot fire.\n */\nexport function isReservedRow(record: Pick<RegistryRecord, 'namespace'>): boolean {\n return isDueIndexRow(record);\n}\n\n/**\n * Filter bookkeeping rows out of a registry listing **before** anything downstream pays for them. Needed where\n * the enumeration is consumed inside a budgeted collector rather than a plain loop: charging a GDPR Art. 15\n * request's per-op budget for pointer rows can refuse a subject report for a reason that has nothing to do with\n * the subject.\n */\nexport async function* excludingReservedRows(\n source: AsyncIterable<RegistryRecord>,\n): AsyncIterable<RegistryRecord> {\n for await (const record of source) {\n if (!isReservedRow(record)) yield record;\n }\n}\n", "/**\n * The **bitmap-codec seam**.\n *\n * `core/` is **codec-agnostic**: `SegmentEngine`, the erasure rewrite, and the `.crbm` read/write helpers only ever\n * construct and combine bitmaps through the {@link CodecInterface} factory + the {@link CodecBitmap} value type\n * defined here \u2014 never a concrete implementation. The flagship codec is roaring (`roaringCodec`, in\n * `@cloudbitmaps/roaring`), and another codec would plug in behind the same seam with zero engine or driver\n * changes. That is the seam's value even with one codec shipped: a plain-bitset flavor was measured and\n * **decided against** (above ~6% density a Roaring chunk already *is* an uncompressed bitset), so the seam is\n * what let that question be answered by measurement rather than by a rewrite.\n *\n * **Homogeneity contract:** a single store uses a single codec, so every {@link CodecBitmap} an operation sees\n * was produced by the same {@link CodecInterface}. The binary set ops ({@link CodecBitmap.orInPlace} etc.) may\n * therefore assume `other` is the same concrete type and are not required to interoperate across codecs.\n * (Corollary: a decoded-chunk cache is codec-specific \u2014 never share one `cache` across engines built with\n * different codecs, or a cached bitmap from codec A could reach codec B's in-place op. The `CloudRoaring` facade\n * mints the cache per store, so this cannot arise in normal use.)\n *\n * **Interface surface = exactly what the engine needs**, kept general enough for the known fast-follow codecs\n * (positional/rank-select access + raw-bitset interop that `@cloudbitmaps/bitset` will add live on that\n * package's own extended value type, not here \u2014 the engine never calls them). The one codec-linked concern\n * this seam intentionally leaves in the format layer is the `.crbm` **payload codec id**\n * (`PAYLOAD_CODEC_ROARING_PORTABLE` / `KNOWN_PAYLOAD_CODEC_IDS` in `crbm/format.ts`): it is stamped in the footer\n * and validated on read. That generalization is **done** as of 0.7.0 \u2014 the field was `roaringSerializationId`\n * and validated by equality against a single constant, which would have frozen a codec-specific name into the\n * format at `1.0`. It is now a registry the reader checks membership against, so a future codec is a one-line\n * registration rather than a major format version. Still deliberately outside this interface: a codec declares\n * its bytes, the seam does not.\n */\n\nimport { ValidationError } from './errors';\n\n/**\n * The value type a codec produces \u2014 a mutable set of `u32` with set algebra and portable (de)serialization.\n * This is the shape `SafeBitmap` already has; the engine holds these, caches them, and merges tiers with them.\n */\nexport interface CodecBitmap {\n /** Serialize with the codec's **stable, portable** format (never a frozen/unsafe variant). */\n serialize(): Uint8Array;\n add(value: number): void;\n addMany(values: Iterable<number>): void;\n remove(value: number): void;\n removeMany(values: Iterable<number>): void;\n has(value: number): boolean;\n /** Cardinality. */\n readonly size: number;\n readonly isEmpty: boolean;\n /** A deep copy \u2014 mutating the clone must not touch the original (the cache relies on this). */\n clone(): CodecBitmap;\n /** In-place union `this = this \u222A other`. `other` is from the same codec (see the homogeneity contract). */\n orInPlace(other: CodecBitmap): void;\n /** In-place difference `this = this \\ other`. */\n andNotInPlace(other: CodecBitmap): void;\n /** In-place intersection `this = this \u2229 other`. */\n andInPlace(other: CodecBitmap): void;\n /** Ascending iterator over the set values. */\n [Symbol.iterator](): IterableIterator<number>;\n toArray(): number[];\n /**\n * The largest value in the set, or `undefined` when empty.\n *\n * **Optional, and deliberately so.** The engine uses it for one thing: asserting that a payload it is about\n * to interpret **as a chunk** holds only 16-bit remainders (see {@link assertChunkPayload}). A codec that\n * cannot answer this in better than O(n) should simply omit it \u2014 the engine then skips the check rather\n * than walking every value on the read path, which is the one thing this must never cost.\n *\n * Roaring answers it in O(1) from its container index, so the flagship codec implements it.\n */\n maximum?(): number | undefined;\n /**\n * Re-encode for size, in place, immediately before a **storage** write. Representation only \u2014 this must never\n * change membership, and `serialize()` afterwards must decode back to exactly the same set.\n *\n * **Optional, like {@link maximum}.** A codec whose encoding has no size decision to make (a plain bitset has\n * one representation and nothing to choose) simply omits it, and the engine skips the call.\n *\n * WHY THIS EXISTS. Roaring picks per container between an array, a bitset and a RUN \u2014 but the run choice is\n * not automatic in any implementation: it is a `runOptimize()` pass you have to ask for, and nothing here was\n * asking. So two of the three container types were ever used, and run-shaped data paid list or bitmap prices\n * for a run. Measured on the shipped codec: a contiguous 1,000,000-id range serialized to 128.1 KiB where\n * run-encoding needs **0.2 KiB** (570\u00D7), and a 2,000-run shape 536.5 KiB against **8.5 KiB** (63\u00D7). Sparse\n * data is unchanged, because there are no runs to find \u2014 the pass is not a gamble.\n *\n * WHY ONLY AT WRITE TIME. This is called where a whole immutable generation is written, so its cost amortizes\n * over a write that is already serializing and checksumming every chunk \u2014 and a generation is read many times\n * after. It is deliberately NOT called on the read path (a clone made for a combine is transient): the hot path\n * must not pay for a win that only the stored bytes collect, per KISS/YAGNI.\n */\n optimize?(): void;\n}\n\n/**\n * A pluggable bitmap codec \u2014 the factory the codec-agnostic engine constructs {@link CodecBitmap}s through.\n * Implementations **must** size-cap before handing untrusted bytes to any native decoder and use a safe\n * (never a trusting/frozen) deserializer \u2014 hard invariant 5.\n */\nexport interface CodecInterface {\n /** An empty set. */\n empty(): CodecBitmap;\n /** A set seeded from an iterable of `u32` values. */\n fromValues(values: Iterable<number>): CodecBitmap;\n /**\n * Size-cap (`bytes.length <= maxBytes`) then portable-deserialize. Throws `IntegrityError` when the input\n * exceeds the cap or fails to decode \u2014 the native decoder is never handed unbounded or unsafe-format input.\n */\n safeDeserialize(bytes: Uint8Array, maxBytes: number): CodecBitmap;\n}\n\n/**\n * Resolve a codec that a **public core entry point** was given, failing fast when it is missing.\n *\n * Why these entry points take `codec?` rather than a required field: `bulkLoadCrbmGeneration` /\n * `eraseIdFromSegment` / `runExport` are call-compatible public API, and core cannot supply a default (the concrete\n * codec lives in a *flavor* package that depends on core \u2014 a default here would invert that arrow). A **flavor**\n * package binds the codec for its users (`@cloudbitmaps/roaring` re-exports codec-bound wrappers), so an\n * application never reaches this throw; only someone calling `@cloudbitmaps/core` directly \u2014 i.e. a flavor or\n * driver author \u2014 can, and for them the typed error names exactly what to pass.\n */\nexport function requireCodec(codec: CodecInterface | undefined, api: string): CodecInterface {\n if (codec === undefined) {\n throw new ValidationError(\n `${api} needs a bitmap codec: pass \\`codec\\` (e.g. \\`roaringCodec\\` from @cloudbitmaps/roaring). ` +\n `@cloudbitmaps/core is codec-agnostic and has no default \u2014 install a flavor package, whose ` +\n `equivalents bind the codec for you.`,\n );\n }\n return codec;\n}\n", "/**\n * Segment **export (\"eject\")** \u2014 dump every registered segment's current *effective* set to a portable file,\n * using only public read APIs, so your data is readable **without CloudRoaring** (a first-class exit path;\n * see the README \"Your data stays yours\" section).\n *\n * Two formats:\n * - `'roaring'` (default) \u2014 one **portable RoaringBitmap32** per segment (the cross-language CRoaring format,\n * loadable by any roaring library in Java/Go/Python/Rust/C++/\u2026). Compact; builds one bitmap in memory per\n * segment.\n * - `'ndjson'` \u2014 newline-delimited ids, streamed (constant memory, any segment size); zero dependencies to read.\n *\n * The engine is **storage-agnostic and I/O-free**: it enumerates via an {@link IRegistryDriver}, reads each\n * segment's current generation via a store's `segment(...).iterate()`, and writes bytes through an injected\n * {@link ExportSink} \u2014 so it never imports `node:fs` (the `export-segments` CLI supplies a filesystem sink; a\n * test supplies an in-memory one; you could supply an S3 uploader). Crypto-shredded (`destroyed`) segments are\n * skipped (their bytes are unrecoverable); an encrypted segment is decrypted transparently **iff** the store was\n * wired with its keystore \u2014 so the export is **cleartext**, and protecting it is on you.\n *\n * **Enumeration** = the registry's known set. Every loaded segment has a registry row (the publish writes it),\n * so the registry is complete by construction; a segment loaded without a registry is not exportable here \u2014 wire\n * the registry the store was loaded with.\n *\n * **Per-segment fault isolation:** a segment that can't be read (a corrupt storage object, or an encrypted segment\n * when the store has no keystore) is recorded in the manifest's {@link ExportManifest.failed} list and the export\n * **continues** \u2014 one bad segment never blocks the rest. Its partial output is aborted, so a truncated file never\n * masquerades as complete. Therefore \"a manifest exists\" means *the run finished*, not that every segment\n * succeeded \u2014 check `failed` (the CLI also exits non-zero when it's non-empty).\n */\nimport { isReservedRow } from '../core/registry-scan';\nimport type { CodecInterface } from '../core/codec';\nimport { requireCodec } from '../core/codec';\nimport type { IRegistryDriver, SegmentRef } from '../core/ports';\nimport { validateSegmentRef } from '../core/validate';\n\n/** Output format for {@link runExport} / `CloudRoaring.exportSegments`. */\nexport type ExportFormat = 'roaring' | 'ndjson';\n\n/** A writer for one segment's output \u2014 inject a filesystem file, an S3 upload, stdout, or a test buffer. */\nexport interface ExportWriter {\n /** Append bytes (called one or more times; for `ndjson`, batched line chunks; for `roaring`, once). */\n write(bytes: Uint8Array): Promise<void> | void;\n /** **Commit** the output \u2014 called once, only on success (all bytes written). Finalize/flush/rename here. */\n close(): Promise<void> | void;\n /**\n * **Discard** a partial output \u2014 called instead of `close()` if a fault occurs mid-segment, so a truncated file\n * never masquerades as complete (e.g. delete the temp file). Optional; sinks with nothing to undo can omit it.\n */\n abort?(): Promise<void> | void;\n}\n\n/** A destination the export writes each segment to. `ext` is `.roaring` or `.ndjson`. */\nexport interface ExportSink {\n open(ref: SegmentRef, ext: string): Promise<ExportWriter> | ExportWriter;\n}\n\nexport interface ExportOptions {\n /** Output format; defaults to `'roaring'`. */\n readonly format?: ExportFormat;\n /**\n * Bitmap codec used to build the exported bitmap for the `'roaring'` format. Optional in the\n * type so this stays call-compatible public API; a **flavor** package binds it (see `requireCodec`). Not needed\n * for `'ndjson'`, which streams plain ids.\n */\n readonly codec?: CodecInterface;\n /** Scope the export to one namespace; omit to export every registered segment. */\n readonly namespace?: string;\n /** `ndjson` flush threshold in ~bytes (ids are ASCII, so \u2248 chars); defaults to 64 KiB. */\n readonly ndjsonBatchBytes?: number;\n}\n\n/** Per-segment result recorded in the {@link ExportManifest}. */\nexport interface ExportedSegment {\n readonly segment: string;\n readonly namespace?: string;\n /** Ids written (the segment's effective cardinality at export time). */\n readonly count: number;\n /** Bytes written to the sink for this segment. */\n readonly bytes: number;\n}\n\n/**\n * A segment that could **not** be exported \u2014 recorded rather than aborting the whole run (fault isolation), so a\n * single corrupt/undecryptable segment never blocks the rest of the dump.\n */\nexport interface ExportFailure {\n readonly segment: string;\n readonly namespace?: string;\n /** Why it failed (an error message) \u2014 e.g. a corrupt storage object, or an encrypted segment with no keystore. */\n readonly error: string;\n}\n\n/** What {@link runExport} produced \u2014 a self-describing summary the CLI persists as `manifest.json`. */\nexport interface ExportManifest {\n /** Schema version of this manifest shape (currently `1`) \u2014 insurance for evolving the format post-1.0. */\n readonly version: number;\n readonly format: ExportFormat;\n readonly totalSegments: number;\n readonly totalIds: number;\n readonly segments: readonly ExportedSegment[];\n /**\n * Segments that could not be read (empty when everything succeeded). Its presence in the manifest is the point:\n * \"a manifest exists\" \u21D2 the run finished, **not** that every segment succeeded \u2014 always check this list.\n */\n readonly failed: readonly ExportFailure[];\n}\n\n/** The minimal read surface the export needs from a store \u2014 a `CloudRoaring` satisfies this structurally. */\nexport interface SegmentReader {\n segment(name: string, options?: { namespace?: string }): { iterate(): AsyncIterable<number> };\n}\n\nconst DEFAULT_NDJSON_BATCH_BYTES = 64 * 1024;\n\nconst errMessage = (err: unknown): string => (err instanceof Error ? err.message : String(err));\n\n/**\n * Export every registered segment's current generation through `sink`. Enumerates via `registry`, reads via\n * `reader` (the store). Returns a manifest. `CloudRoaring.exportSegments` is the\n * public entry \u2014 it calls this with its own store + registry (so enumeration and the read path provably share one\n * registry).\n *\n * **Fault isolation:** a per-segment read/write fault aborts that segment's partial (so a truncated file never\n * looks complete), records it in `failed`, and the run continues \u2014 one bad segment never blocks the rest. A\n * `close()` fault is likewise recorded (never triggering `abort()` \u2014 they're mutually exclusive).\n *\n * Re-running overwrites the segments it re-exports but does **not** prune files for segments that have since\n * disappeared \u2014 export to a fresh directory for a clean dump. For a *current* image, run against a\n * freshly-constructed store: a store's storage source re-resolves each segment's generation on a short TTL (or pins\n * it for its lifetime when built without a clock or registry), so a long-lived store may export a view one load\n * behind.\n */\nexport async function runExport(\n reader: SegmentReader,\n registry: IRegistryDriver,\n sink: ExportSink,\n options: ExportOptions = {},\n): Promise<ExportManifest> {\n const format = options.format ?? 'roaring';\n const ext = format === 'roaring' ? '.roaring' : '.ndjson';\n const batchCap = options.ndjsonBatchBytes ?? DEFAULT_NDJSON_BATCH_BYTES;\n const segments: ExportedSegment[] = [];\n const failed: ExportFailure[] = [];\n let totalIds = 0;\n\n const exportRef = async (ref: SegmentRef): Promise<void> => {\n let writer: ExportWriter | undefined;\n let count = 0;\n let bytes = 0;\n try {\n validateSegmentRef(ref); // defense-in-depth: registry rows are untrusted bytes here\n const ids = reader.segment(ref.segment, { namespace: ref.namespace }).iterate();\n writer = await sink.open(ref, ext);\n if (format === 'roaring') {\n const bm = requireCodec(options.codec, \"runExport({ format: 'roaring' })\").empty();\n for await (const id of ids) {\n bm.add(id);\n count += 1;\n }\n const out = bm.serialize(); // portable RoaringBitmap32 \u2014 the cross-language CRoaring format\n await writer.write(out);\n bytes = out.length;\n } else {\n let buf = '';\n for await (const id of ids) {\n buf += `${id}\\n`;\n count += 1;\n if (buf.length >= batchCap) {\n const b = Buffer.from(buf, 'utf8');\n await writer.write(b);\n bytes += b.length;\n buf = '';\n }\n }\n if (buf.length > 0) {\n const b = Buffer.from(buf, 'utf8');\n await writer.write(b);\n bytes += b.length;\n }\n }\n } catch (err) {\n // Read/write fault: discard the partial (best-effort, so a failing cleanup can't mask the real fault),\n // record it, and move on \u2014 one bad segment never blocks the rest.\n if (writer !== undefined) {\n try {\n await writer.abort?.();\n } catch {\n /* best-effort cleanup */\n }\n }\n failed.push({ segment: ref.segment, namespace: ref.namespace, error: errMessage(err) });\n return;\n }\n // Commit outside the write try: a `close()` failure must NOT also trigger `abort()` (they're mutually\n // exclusive \u2014 abort on a write fault, close on success \u2014 so a custom sink never double-finalizes). A close\n // fault is still isolated: recorded, not thrown.\n try {\n await writer.close();\n } catch (err) {\n failed.push({ segment: ref.segment, namespace: ref.namespace, error: errMessage(err) });\n return;\n }\n segments.push({ segment: ref.segment, namespace: ref.namespace, count, bytes });\n totalIds += count;\n };\n\n for await (const rec of registry.list(options.namespace)) {\n // A coordination row is not a segment: an unscoped eject would otherwise write one empty file per partition\n // into the portability dump \u2014 the artifact whose whole value is being a faithful copy of the user's data.\n if (options.namespace === undefined && isReservedRow(rec)) continue;\n if (rec.status === 'destroyed') continue; // crypto-shredded \u2192 bytes unrecoverable; nothing to export\n await exportRef({ segment: rec.segment, namespace: rec.namespace });\n }\n return { version: 1, format, totalSegments: segments.length, totalIds, segments, failed };\n}\n", "/**\n * `segmentExists` and `listSegments` \u2014 ask the registry what is there.\n *\n * The registry has always known which segments exist; it is what `checkConsistency`, the retention sweep and\n * `exportSegments` each enumerate. It was simply never exposed, so a user asking \"do I already have this?\" had\n * to infer it: `count()` returns `0` for a segment that was never loaded AND for one loaded with no ids, and\n * `generations()` costs a bucket listing to answer a question the pointer alone settles.\n *\n * Inferring it is the expensive kind of wrong. The alternative a user reaches for is keeping their own list of\n * segment names alongside the store \u2014 a second source of truth, updated by hand, drifting from the first the\n * moment a load fails halfway. The registry is already the list; these two functions read it.\n */\nimport type { IRegistryDriver, RegistryRecord, SegmentRef } from './ports';\nimport { excludingReservedRows } from './registry-scan';\nimport { validateSegmentRef } from './validate';\n\n/** One segment the registry knows about. */\nexport interface SegmentInfo extends SegmentRef {\n /**\n * The generation the **pointer names** \u2014 not what a read would resolve. On a `destroyed` tombstone this is\n * still a number while reads answer empty, so read it together with {@link SegmentInfo.status} rather than\n * alone. `null` means the row exists with no Storage generation yet.\n */\n readonly currentGen: number | null;\n /**\n * `destroyed` is a tombstone: the row stays so sweeps can still find it, and the generations are gone \u2014 on an\n * encrypted segment the DEK wrappings went with them, which is what makes the bytes unrecoverable rather than\n * merely deleted.\n */\n readonly status: RegistryRecord['status'];\n}\n\n/**\n * Whether this segment's pointer resolves a generation \u2014 the question behind \"does it already exist?\".\n *\n * One registry point read, on every backend. Deliberately narrower than \"is there a row\": it is **false** for a\n * row that exists with `currentGen: null` (a retention policy recorded ahead of the first load) and for a\n * `destroyed` tombstone, because a read answers empty in both. The predicate mirrors generation resolution\n * clause for clause, which is what keeps the two from disagreeing.\n *\n * It is NOT the same question as `count() > 0`. A segment loaded with no ids exists and counts zero \u2014 the\n * distinction between \"never loaded\" and \"loaded, and genuinely empty\" is the one `count()` cannot make and\n * the main reason this function is worth having.\n *\n * Two states answer `true` where a read still gives you nothing, and neither is this call's job to detect: a\n * **torn restore** (`missing-storage-generation` \u2014 a live pointer whose object was deleted) makes reads *throw*\n * `NotFoundError` rather than answer empty, and `runConsistencyCheck` is the call that looks for it; and a\n * handle carrying an expired `expiresAt` reads as empty by a rule that lives on the handle, not on the row.\n *\n * Not a lock. A segment can be created or dropped between this call and whatever you do next; if the answer\n * has to hold, use the fences that exist for it \u2014 `load`'s guard, or `expectFrom`/`expectToken` on a publish.\n */\nexport async function segmentExists(ref: SegmentRef, registry: IRegistryDriver): Promise<boolean> {\n validateSegmentRef(ref);\n const record = await registry.get(ref);\n return record !== null && record.status !== 'destroyed' && record.currentGen !== null;\n}\n\n/**\n * Every segment the registry holds, streamed \u2014 optionally scoped to one namespace.\n *\n * **This is an admin/discovery call, not a request-path one.** It is the registry's own enumeration \u2014 a paged\n * LIST over the `registry/` prefix \u2014 so cost grows with the fleet, not with what you are looking for. The\n * fleet-wide sweeps that *drain* it bound it (`maxScanSegments`); this one streams, so the bound is yours.\n *\n * **Scoping to a namespace narrows the LIST prefix**, so it really is the difference between reading one\n * tenant and reading all of them.\n *\n * Streams, so a large fleet need not be held at once, and stopping the iteration stops the scan \u2014 **with one\n * exception that matters**: a driver that buffers its enumeration defeats both properties, and\n * `RetryingRegistryDriver` does exactly that (it must, to retry a `list` as a unit). Wrapped in it, the whole\n * scan is paid for and resident before the first row reaches you. On the four native drivers the guarantee\n * holds; on S3 the granularity is a page, so one LIST page and its in-flight row reads complete regardless.\n *\n * Yields `destroyed` tombstones, and rows whose `currentGen` is `null`, because hiding either would make this\n * disagree with the registry it reports on \u2014 a filtered enumeration that looks complete is how a retention\n * sweep ends up permanently skipping rows nobody can see. Filter on `status`/`currentGen` yourself, or use\n * {@link segmentExists} for the \"does the pointer resolve\" question. Internal bookkeeping rows are the one\n * exclusion, and only on an unscoped scan: they are not segments, and a caller naming their namespace still\n * sees them.\n */\nexport async function* listSegments(\n registry: IRegistryDriver,\n options: { namespace?: string } = {},\n): AsyncIterable<SegmentInfo> {\n // Validated here rather than only at the facade: this is a public export of `@cloudbitmaps/core`, and its\n // sibling `segmentExists` validates. Without it a typo'd or externally-supplied tenant id reads as \"this\n // tenant has no segments\" \u2014 an empty result is the most dangerous possible answer to a malformed question.\n if (options.namespace !== undefined)\n validateSegmentRef({ segment: 'x', namespace: options.namespace });\n const raw = registry.list(options.namespace);\n const source = options.namespace === undefined ? excludingReservedRows(raw) : raw;\n for await (const record of source) {\n yield {\n ...(record.namespace === undefined ? {} : { namespace: record.namespace }),\n segment: record.segment,\n currentGen: record.currentGen,\n status: record.status,\n };\n }\n}\n", "/**\n * In-memory drivers \u2014 the reference backing for tests and quick experiments.\n * They store **serialized bytes + an OCC token** (not live objects), so the engine's\n * safe-deserialize / size-cap paths and the registry's OCC paths are genuinely exercised.\n *\n * Not in `core/` (this is a driver), so it may hold concrete state.\n */\nimport { createHash } from 'node:crypto';\nimport { BufferSink } from '../core/blob';\nimport type { BlobSink } from '../core/blob';\nimport { NotFoundError, ValidationError, WriteConflictError } from '../core/errors';\nimport { chunkRefKey, segmentKey, segmentPrefix } from '../core/keys';\nimport { validateChunkRef, validateSegmentRef } from '../core/validate';\nimport type {\n ChunkRef,\n StorageCaps,\n StorageChunkSource,\n GenKey,\n IStorageDriver,\n IRegistryDriver,\n NewRegistryRecord,\n RegCaps,\n RegistryPatch,\n RegistryRecord,\n SegmentRef,\n SegmentSize,\n Token,\n} from '../core/ports';\nimport {\n applyRegistryPatch,\n recordFromNew,\n validateNewRegistryRecord,\n validateRegistryPatch,\n} from './_shared/registry';\n\nexport class MemoryStorageChunkSource implements StorageChunkSource {\n private readonly chunks = new Map<string, Uint8Array>();\n\n async getChunk(ref: ChunkRef): Promise<Uint8Array | null> {\n validateChunkRef(ref);\n return this.chunks.get(chunkRefKey(ref)) ?? null;\n }\n\n async listChunkKeys(ref: SegmentRef): Promise<number[]> {\n validateSegmentRef(ref);\n const prefix = segmentPrefix(ref);\n const keys: number[] = [];\n for (const key of this.chunks.keys()) {\n if (key.startsWith(prefix)) keys.push(Number(key.slice(prefix.length)));\n }\n return keys;\n }\n\n async sizeOf(ref: SegmentRef): Promise<SegmentSize | null> {\n validateSegmentRef(ref);\n const prefix = segmentPrefix(ref);\n let sizeBytes = 0;\n let found = false;\n for (const [key, bytes] of this.chunks) {\n if (!key.startsWith(prefix)) continue;\n found = true;\n sizeBytes += bytes.length;\n }\n return found ? { sizeBytes } : null;\n }\n\n /** Test/seed helper \u2014 populate immutable Storage bytes for a chunk directly (bypassing the `.crbm` format). */\n seed(ref: ChunkRef, bytes: Uint8Array): void {\n validateChunkRef(ref); // keep seed symmetric with the validated read path\n this.chunks.set(chunkRefKey(ref), bytes);\n }\n}\n\nexport interface MemoryRegistryDriverOptions {\n /** Injected clock for `createdAt`/`updatedAt`; defaults to `Date.now` (drivers may use ambient time). */\n readonly now?: () => number;\n}\n\n/**\n * In-memory {@link IRegistryDriver} \u2014 one record per segment under OCC. The token is a single global,\n * monotonic, never-reused counter (so a record recreated after `delete` always gets a strictly-greater\n * token \u2192 ABA-safe even though `delete` removes the row physically).\n */\nexport class MemoryRegistryDriver implements IRegistryDriver {\n private readonly rows = new Map<string, RegistryRecord>();\n private readonly now: () => number;\n private seq = 0;\n\n constructor(options: MemoryRegistryDriverOptions = {}) {\n this.now = options.now ?? (() => Date.now());\n }\n\n private nextToken(): Token {\n this.seq += 1;\n return String(this.seq);\n }\n\n capabilities(): RegCaps {\n return { strongRead: true };\n }\n\n async get(ref: SegmentRef): Promise<RegistryRecord | null> {\n validateSegmentRef(ref);\n const row = this.rows.get(segmentKey(ref));\n return row ? structuredClone(row) : null; // clone out: callers can't mutate stored (nested) state\n }\n\n async create(ref: SegmentRef, record: NewRegistryRecord): Promise<{ token: Token }> {\n validateSegmentRef(ref);\n validateNewRegistryRecord(record);\n const key = segmentKey(ref);\n if (this.rows.has(key)) {\n throw new WriteConflictError(`registry row already exists for segment ${ref.segment}`);\n }\n const token = this.nextToken();\n // clone in: the caller's (nested) retention/residency can't alias stored state (value semantics, parity\n // with the serialize-based persistent drivers).\n this.rows.set(key, structuredClone(recordFromNew(ref, record, this.now(), token)));\n return { token };\n }\n\n async compareAndSwap(\n ref: SegmentRef,\n expected: Token,\n patch: RegistryPatch,\n ): Promise<{ token: Token }> {\n validateSegmentRef(ref);\n validateRegistryPatch(patch);\n const key = segmentKey(ref);\n const existing = this.rows.get(key);\n if (!existing || existing.token !== expected) {\n throw new WriteConflictError(`OCC token mismatch for registry row ${ref.segment}`);\n }\n const token = this.nextToken();\n this.rows.set(key, structuredClone(applyRegistryPatch(existing, patch, this.now(), token)));\n return { token };\n }\n\n async *list(namespace?: string): AsyncIterable<RegistryRecord> {\n for (const row of this.rows.values()) {\n if (namespace === undefined || row.namespace === namespace) yield structuredClone(row);\n }\n }\n\n async delete(ref: SegmentRef): Promise<void> {\n validateSegmentRef(ref);\n this.rows.delete(segmentKey(ref)); // idempotent; token uniqueness is global so a recreate is ABA-safe\n }\n}\n\n/**\n * In-memory {@link IStorageDriver} \u2014 write-once immutable generation objects as opaque bytes. A \"dumb byte\n * mover\" (understands neither roaring nor `.crbm`), so it's a faithful storage backend for tests and a zero-setup\n * local storage tier. Mirrors the LocalFs/S3 contract (write-once, range/tail reads).\n */\nexport class MemoryStorageDriver implements IStorageDriver {\n private readonly objects = new Map<string, Uint8Array>();\n\n capabilities(): StorageCaps {\n return { rangeRead: true, maxObjectBytes: Number.MAX_SAFE_INTEGER, conditionalPut: true };\n }\n\n async putImmutable(\n key: GenKey,\n write: (sink: BlobSink) => Promise<void>,\n ): Promise<{ size: number; sha256: string }> {\n const k = genObjectKey(key); // validates ref + generation\n const sink = new BufferSink();\n await write(sink);\n const body = sink.bytes();\n if (this.objects.has(k)) {\n throw new WriteConflictError(\n `generation already exists (write-once): ${key.segment}.${key.generation}`,\n );\n }\n this.objects.set(k, body);\n return { size: body.length, sha256: createHash('sha256').update(body).digest('hex') };\n }\n\n async getRange(key: GenKey, offset: number, length: number): Promise<Uint8Array> {\n if (!Number.isInteger(offset) || !Number.isInteger(length) || offset < 0 || length < 0) {\n throw new ValidationError(`invalid range offset=${offset} length=${length}`);\n }\n const body = this.require(key);\n if (offset + length > body.length) {\n throw new ValidationError(\n `range [${offset}, ${offset + length}) out of bounds for ${body.length}B`,\n );\n }\n return body.slice(offset, offset + length);\n }\n\n async getTail(key: GenKey, maxBytes: number): Promise<{ bytes: Uint8Array; size: number }> {\n const body = this.require(key);\n const take = Math.min(Math.max(maxBytes, 0), body.length);\n return { bytes: body.slice(body.length - take), size: body.length };\n }\n\n async delete(key: GenKey): Promise<void> {\n this.objects.delete(genObjectKey(key)); // idempotent\n }\n\n async *list(ref: SegmentRef): AsyncIterable<GenKey> {\n validateSegmentRef(ref);\n const prefix = `${segmentKey(ref)} `;\n for (const k of this.objects.keys()) {\n if (k.startsWith(prefix)) {\n yield {\n namespace: ref.namespace,\n segment: ref.segment,\n generation: Number(k.slice(prefix.length)),\n };\n }\n }\n }\n\n private require(key: GenKey): Uint8Array {\n const body = this.objects.get(genObjectKey(key));\n if (body === undefined) {\n throw new NotFoundError(`no such generation: ${key.segment}.${key.generation}`);\n }\n return body;\n }\n}\n\n/** Collision-proof object key for a generation: `<segmentKey> <generation>` (the name parts are encoded, so a space cannot appear inside one). */\nfunction genObjectKey(key: GenKey): string {\n validateSegmentRef(key);\n if (!Number.isInteger(key.generation) || key.generation < 0) {\n throw new ValidationError(`generation must be a non-negative integer; got ${key.generation}`);\n }\n return `${segmentKey(key)} ${key.generation}`;\n}\n", "/**\n * The byte-IO seam the `.crbm` codec reads/writes through.\n *\n * Deliberately tiny and driver-independent: a `BlobSink` is a streaming append target (the writer needs\n * no random access), a `BlobReader` supports the speculative tail read + bounded range reads. An\n * `IStorageDriver` adapts a `GenKey` to these; the in-memory impls below let the format be\n * golden-tested and let the in-memory storage tier hold a real `.crbm` with no filesystem.\n */\nimport { ValidationError } from './errors';\n\n/** Streaming append target for a single object being written. */\nexport interface BlobSink {\n write(bytes: Uint8Array): Promise<void>;\n}\n\n/**\n * Random/tail read access to a single finished object. The total size comes back from `getTail` (the\n * codec's entry point), so there's no separate `size()` \u2014 keeping the seam minimal for driver authors.\n */\nexport interface BlobReader {\n /** Exactly `length` bytes starting at `offset`. Out-of-range is a `ValidationError`, never a short read. */\n getRange(offset: number, length: number): Promise<Uint8Array>;\n /** The last `min(maxBytes, size)` bytes plus the total size \u2014 the one-GET footer+index path. */\n getTail(maxBytes: number): Promise<{ bytes: Uint8Array; size: number }>;\n}\n\n/** In-memory `BlobSink` that accumulates written bytes; `bytes()` returns the concatenation. */\nexport class BufferSink implements BlobSink {\n private readonly chunks: Uint8Array[] = [];\n private length = 0;\n\n write(bytes: Uint8Array): Promise<void> {\n // Copy: callers may reuse their buffer after write() resolves.\n this.chunks.push(bytes.slice());\n this.length += bytes.length;\n return Promise.resolve();\n }\n\n bytes(): Uint8Array {\n const out = new Uint8Array(this.length);\n let offset = 0;\n for (const chunk of this.chunks) {\n out.set(chunk, offset);\n offset += chunk.length;\n }\n return out;\n }\n}\n\n/** In-memory `BlobReader` over a fixed byte buffer. */\nexport class BufferReader implements BlobReader {\n constructor(private readonly buffer: Uint8Array) {}\n\n getRange(offset: number, length: number): Promise<Uint8Array> {\n if (\n !Number.isInteger(offset) ||\n !Number.isInteger(length) ||\n offset < 0 ||\n length < 0 ||\n offset + length > this.buffer.length\n ) {\n throw new ValidationError(\n `range [${offset}, ${offset + length}) out of bounds for ${this.buffer.length}-byte blob`,\n );\n }\n return Promise.resolve(this.buffer.subarray(offset, offset + length));\n }\n\n getTail(maxBytes: number): Promise<{ bytes: Uint8Array; size: number }> {\n const size = this.buffer.length;\n const take = Math.min(Math.max(maxBytes, 0), size);\n return Promise.resolve({ bytes: this.buffer.subarray(size - take), size });\n }\n}\n", "/**\n * `LocalFsStorageDriver` \u2014 a zero-cloud {@link IStorageDriver} backed by the local filesystem.\n *\n * Generations are write-once immutable files. A new object is streamed to a temp file (with its content\n * hashed in-flight), `fsync`-ed, then published with an atomic `link` that fails if the destination\n * already exists \u2014 so a generation can never be silently overwritten (hard invariant 2), and a crash\n * leaves only an orphan temp file, never a torn object. Drivers do filesystem I/O and may use `node:crypto`; only `core/`\n * is bound by the determinism lint.\n */\nimport { constants as FS } from 'node:fs';\nimport { createHash, randomUUID } from 'node:crypto';\nimport { link, mkdir, open, readdir, unlink } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { NotFoundError, ValidationError, WriteConflictError } from '@/core/errors';\nimport type { BlobSink } from '@/core/blob';\nimport type { StorageCaps, GenKey, IStorageDriver, SegmentRef } from '@/core/ports';\nimport { storageObjectPath, parseGeneration, segmentsDir } from './paths';\nimport { O_NOFOLLOW, fsyncDir, isCode, mapFsError } from './fs-util';\n\nexport class LocalFsStorageDriver implements IStorageDriver {\n constructor(private readonly root: string) {}\n\n capabilities(): StorageCaps {\n return { rangeRead: true, maxObjectBytes: Number.MAX_SAFE_INTEGER, conditionalPut: false };\n }\n\n async putImmutable(\n key: GenKey,\n write: (sink: BlobSink) => Promise<void>,\n ): Promise<{ size: number; sha256: string }> {\n const finalPath = storageObjectPath(this.root, key);\n await mkdir(dirname(finalPath), { recursive: true });\n\n const tmpPath = `${finalPath}.${randomUUID()}.tmp`;\n // 'wx' = O_CREAT|O_EXCL|O_WRONLY; add O_NOFOLLOW so a pre-planted symlink can't redirect the write.\n const handle = await open(tmpPath, FS.O_CREAT | FS.O_EXCL | FS.O_WRONLY | O_NOFOLLOW);\n const hash = createHash('sha256');\n let size = 0;\n const sink: BlobSink = {\n async write(bytes) {\n await handle.write(bytes);\n hash.update(bytes);\n size += bytes.length;\n },\n };\n\n try {\n await write(sink);\n await handle.sync();\n } catch (err) {\n await handle.close().catch(() => {});\n await unlink(tmpPath).catch(() => {});\n throw mapFsError(err);\n }\n await handle.close();\n\n // Atomic write-once publish: link fails with EEXIST if the generation already exists.\n try {\n await link(tmpPath, finalPath);\n } catch (err) {\n await unlink(tmpPath).catch(() => {});\n if (isCode(err, 'EEXIST')) {\n // A generation is write-once; a collision is a concurrency/state condition, not bad input.\n // Identify it by the logical key only \u2014 never leak the absolute filesystem path.\n throw new WriteConflictError(\n `generation already exists (write-once): ${key.segment}.${key.generation}`,\n );\n }\n throw mapFsError(err);\n }\n await unlink(tmpPath).catch(() => {});\n await fsyncDir(dirname(finalPath));\n return { size, sha256: hash.digest('hex') };\n }\n\n async getRange(key: GenKey, offset: number, length: number): Promise<Uint8Array> {\n if (!Number.isInteger(offset) || !Number.isInteger(length) || offset < 0 || length < 0) {\n throw new ValidationError(`invalid range offset=${offset} length=${length}`);\n }\n const handle = await this.openRead(key);\n try {\n const { size } = await handle.stat();\n if (offset + length > size) {\n throw new ValidationError(\n `range [${offset}, ${offset + length}) out of bounds for ${size}B`,\n );\n }\n const buf = Buffer.alloc(length);\n if (length > 0) await handle.read(buf, 0, length, offset);\n return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);\n } finally {\n await handle.close();\n }\n }\n\n async getTail(key: GenKey, maxBytes: number): Promise<{ bytes: Uint8Array; size: number }> {\n const handle = await this.openRead(key);\n try {\n const { size } = await handle.stat();\n const take = Math.min(Math.max(maxBytes, 0), size);\n const buf = Buffer.alloc(take);\n if (take > 0) await handle.read(buf, 0, take, size - take);\n return { bytes: new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength), size };\n } finally {\n await handle.close();\n }\n }\n\n async delete(key: GenKey): Promise<void> {\n // Idempotent: deleting an absent generation is a no-op (GC may race / retry).\n await unlink(storageObjectPath(this.root, key)).catch((err) => {\n if (!isCode(err, 'ENOENT')) throw mapFsError(err);\n });\n }\n\n async *list(ref: SegmentRef): AsyncIterable<GenKey> {\n const dir = segmentsDir(this.root, ref);\n let names: string[];\n try {\n names = await readdir(dir);\n } catch (err) {\n if (isCode(err, 'ENOENT')) return; // no generations yet\n throw mapFsError(err);\n }\n for (const name of names) {\n const generation = parseGeneration(ref.segment, name);\n if (generation !== null) {\n yield { namespace: ref.namespace, segment: ref.segment, generation };\n }\n }\n }\n\n private async openRead(key: GenKey): Promise<Awaited<ReturnType<typeof open>>> {\n try {\n return await open(storageObjectPath(this.root, key), FS.O_RDONLY | O_NOFOLLOW);\n } catch (err) {\n if (isCode(err, 'ENOENT')) {\n throw new NotFoundError(`no such generation: ${key.segment}.${key.generation}`);\n }\n // A symlink at the object path is rejected (ELOOP) \u2014 treat as not-found, don't follow it.\n if (isCode(err, 'ELOOP')) {\n throw new NotFoundError(\n `generation path is a symlink, refusing: ${key.segment}.${key.generation}`,\n );\n }\n throw mapFsError(err);\n }\n }\n}\n", "/**\n * Logical-ref \u2192 filesystem-path mapping for the LocalFs drivers.\n *\n * Names are re-validated here at the driver boundary \u2014 defense in depth, because a driver can be\n * constructed and driven directly rather than through the engine that would otherwise have validated for\n * it, and a path built from an unvalidated name is a traversal or injection. The default\n * (absent) namespace maps to `_default`, which cannot collide with a real namespace because a\n * caller's `_default` encodes to `%5Fdefault` while this sentinel is emitted literally.\n */\nimport { join } from 'node:path';\nimport { ValidationError } from '@/core/errors';\nimport { validateSegmentRef } from '@/core/validate';\nimport type { GenKey, SegmentRef } from '@/core/ports';\nimport {\n DEFAULT_NAMESPACE,\n decodeNameFromPath,\n encodeNameForPath,\n namespacePathPart,\n} from '../_shared/keys';\n\n/** Directory holding all of a namespace's segment objects. */\nexport function segmentsDir(root: string, ref: SegmentRef): string {\n validateSegmentRef(ref);\n return join(root, namespacePathPart(ref.namespace), 'segments');\n}\n\n/** Absolute path of one `.crbm` generation object. */\nexport function storageObjectPath(root: string, key: GenKey): string {\n validateSegmentRef(key);\n if (!Number.isInteger(key.generation) || key.generation < 0) {\n throw new ValidationError(`generation must be a non-negative integer; got ${key.generation}`);\n }\n return join(segmentsDir(root, key), storageObjectFilename(key.segment, key.generation));\n}\n\n/** Filename pattern for a segment's generations: `<segment>.<gen>.crbm`. */\nexport function storageObjectFilename(segment: string, generation: number): string {\n return `${encodeNameForPath(segment)}.${generation}.crbm`;\n}\n\n/** Parse a generation number out of a `<segment>.<gen>.crbm` filename, or `null` if it doesn't match. */\nexport function parseGeneration(segment: string, filename: string): number | null {\n const prefix = `${encodeNameForPath(segment)}.`;\n const suffix = '.crbm';\n if (!filename.startsWith(prefix) || !filename.endsWith(suffix)) return null;\n const middle = filename.slice(prefix.length, filename.length - suffix.length);\n // Canonical decimal only: no leading zeros (so `s.07.crbm` can't alias `s.7.crbm`), and within\n // safe-integer range. The writer only ever emits the canonical form.\n if (!/^(0|[1-9]\\d*)$/.test(middle)) return null;\n const gen = Number(middle);\n return Number.isSafeInteger(gen) ? gen : null;\n}\n\nconst REGISTRY_SUFFIX = '.reg';\n\n/** Directory holding a namespace's registry rows (one file per segment). */\nexport function registryDir(root: string, namespace: string | undefined): string {\n // Validated like every sibling builder here. It is the caller-facing entry for a namespace-scoped\n // `list()`, so without this a namespace of `../..` reaches `readdir` outside the storage root \u2014 no content\n // escapes (iteration aborts before yielding) but it answers \"does this directory exist?\", and the whole\n // point of re-validating at the driver boundary is that a driver driven directly must be safe on its own.\n if (namespace !== undefined) validateSegmentRef({ segment: 'x', namespace });\n return join(root, namespacePathPart(namespace), 'registry');\n}\n\n/** Absolute path of one segment's registry row file: `<ns>/registry/<segment>.reg`. */\nexport function registryRowPath(root: string, ref: SegmentRef): string {\n validateSegmentRef(ref);\n return join(\n registryDir(root, ref.namespace),\n `${encodeNameForPath(ref.segment)}${REGISTRY_SUFFIX}`,\n );\n}\n\n/**\n * Parse a segment name out of a `<segment>.reg` filename, or `null` if it doesn't match \u2014 including any\n * file whose stem isn't a valid segment name. A strict parser means a stray or planted `.reg` file makes\n * `list()` *skip* it, never abort the whole enumeration on a boundary throw.\n */\nexport function parseRegistryRow(filename: string): string | null {\n if (!filename.endsWith(REGISTRY_SUFFIX)) return null;\n const stem = filename.slice(0, filename.length - REGISTRY_SUFFIX.length);\n const segment = decodeNameFromPath(stem);\n // The encoding must ROUND-TRIP, not merely decode. POSIX will happily hold a literal `dedup:foo.reg`\n // alongside the driver's own `dedup%3Afoo.reg`; both decode to `dedup:foo`, and reporting that name twice\n // would hand `list()` a segment whose row path resolves to only one of them. The driver never writes the\n // literal form, so anything that does not re-encode to exactly this filename was not written by us.\n if (encodeNameForPath(segment) !== stem) return null;\n try {\n validateSegmentRef({ segment });\n } catch {\n return null;\n }\n return segment;\n}\n\n/**\n * Parse a namespace out of a directory name under the storage root, or `null` if it was not written by us.\n *\n * The inverse of the `namespacePathPart(ns)` that {@link segmentsDir} and {@link registryDir}\n * write. A fleet-wide scan enumerates these directories, so getting it wrong does not fail one segment \u2014 it\n * aborts the whole enumeration, taking the consistency check, the retention sweep and subject erasure with it.\n *\n * Like {@link parseRegistryRow} this requires the encoding to **round-trip**, so a planted literal `tenant:acme`\n * directory sitting next to the driver's own `tenant%3Aacme` is skipped rather than reported as a namespace\n * whose rows then resolve to the other directory. `_default` maps back to \"no namespace\".\n */\nexport function parseNamespaceDir(entry: string): { namespace: string | undefined } | null {\n if (entry === DEFAULT_NAMESPACE) return { namespace: undefined };\n const namespace = decodeNameFromPath(entry);\n if (encodeNameForPath(namespace) !== entry) return null;\n try {\n validateSegmentRef({ segment: 'x', namespace });\n } catch {\n return null;\n }\n return { namespace };\n}\n", "/**\n * Shared filesystem helpers for the LocalFs drivers (storage and registry) \u2014 one source\n * of truth for error-code matching, the symlink-refusal flag, and directory durability.\n */\nimport { constants as FS } from 'node:fs';\nimport { open } from 'node:fs/promises';\nimport { TransientError } from '@/core/errors';\n\ninterface NodeError extends Error {\n code?: string;\n}\n\n/** True when `err` is a Node system error with the given `code` (e.g. `'ENOENT'`, `'EEXIST'`). */\nexport const isCode = (err: unknown, code: string): boolean =>\n err instanceof Error && (err as NodeError).code === code;\n\n/**\n * Filesystem error codes that are transient \u2014 a retry after a brief backoff often succeeds: the resource is\n * busy (`EBUSY`), the OS asked us to retry (`EAGAIN`), or we hit the open-file-descriptor ceiling\n * (`EMFILE`/`ENFILE`, common under heavy concurrency once earlier handles close). A networked FS may also\n * surface `ETIMEDOUT`.\n */\nconst TRANSIENT_FS_CODES = new Set(['EBUSY', 'EAGAIN', 'EMFILE', 'ENFILE', 'ETIMEDOUT']);\n\nexport const isFsTransient = (err: unknown): boolean =>\n err instanceof Error && TRANSIENT_FS_CODES.has((err as NodeError).code ?? '');\n\n/**\n * Reclassify a transient filesystem fault as a retryable {@link TransientError} (so the retry decorator can\n * ride it out); everything else \u2014 including the driver's own typed errors \u2014 propagates unchanged.\n */\nexport const mapFsError = (err: unknown): unknown =>\n isFsTransient(err)\n ? new TransientError(`transient filesystem fault: ${(err as NodeError).code}`, { cause: err })\n : err;\n\n/**\n * `O_NOFOLLOW` where the platform supports it (absent on Windows \u2192 0). OR it into an `open` flag set so a\n * symlink **at the final path component** is refused rather than followed outside the storage root.\n * Containment of symlinked *directory* components assumes the root itself is not attacker-writable.\n */\nexport const O_NOFOLLOW = FS.O_NOFOLLOW ?? 0;\n\n/**\n * Best-effort parent-directory fsync, so a just-published `rename`/`link` survives a crash. Without it the\n * directory entry can still be in the page cache when power goes: the generation's bytes are durable and\n * the name pointing at them is not, which is the one way a published generation can come back missing.\n */\nexport async function fsyncDir(dir: string): Promise<void> {\n try {\n const handle = await open(dir, 'r');\n try {\n await handle.sync();\n } finally {\n await handle.close();\n }\n } catch {\n // Some platforms reject directory fsync; durability of the entry is then best-effort.\n }\n}\n", "/**\n * `LocalFsRegistryDriver` \u2014 a zero-cloud, persistent {@link IRegistryDriver}.\n *\n * One JSON file per segment at `<root>/<namespace>/registry/<segment>.reg`, holding `{ deleted, record }`.\n * OCC: the token is a monotonic counter (stringified), advanced on every mutation and\n * even across a `delete` (which **tombstones** rather than unlinks) so a deleted-then-recreated row never\n * re-issues an old token (ABA-safe). Every write is temp \u2192 fsync(file) \u2192 atomic rename \u2192 fsync(dir), and\n * read-modify-write is serialized per row in-process. Drivers do I/O; only `core/` is bound by determinism.\n */\nimport { constants as FS } from 'node:fs';\nimport { randomUUID } from 'node:crypto';\nimport { mkdir, open, readdir, rename, unlink } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { IntegrityError, ValidationError, WriteConflictError } from '@/core/errors';\nimport type {\n IRegistryDriver,\n NewRegistryRecord,\n RegCaps,\n RegistryPatch,\n RegistryRecord,\n SegmentRef,\n Token,\n} from '@/core/ports';\nimport {\n applyRegistryPatch,\n parseRegistryEnvelope,\n recordFromNew,\n registryCounterOf,\n serializeRegistryEnvelope,\n validateNewRegistryRecord,\n validateRegistryPatch,\n type RegistryEnvelope,\n} from '../_shared/registry';\nimport { registryDir, registryRowPath, parseNamespaceDir, parseRegistryRow } from './paths';\nimport { O_NOFOLLOW, fsyncDir, isCode, mapFsError } from './fs-util';\n\n/** Defensive cap on a single registry file read from storage, before allocation. */\nconst DEFAULT_MAX_ROW_BYTES = 1 * 1024 * 1024;\n\nexport interface LocalFsRegistryDriverOptions {\n /** Injected clock for `createdAt`/`updatedAt`; defaults to `Date.now`. */\n readonly now?: () => number;\n}\n\nexport class LocalFsRegistryDriver implements IRegistryDriver {\n /** Per-row promise chain \u2014 serializes read-modify-write so an in-process CAS never loses an update. */\n private readonly chain = new Map<string, Promise<unknown>>();\n private readonly now: () => number;\n\n constructor(\n private readonly root: string,\n options: LocalFsRegistryDriverOptions = {},\n ) {\n this.now = options.now ?? (() => Date.now());\n }\n\n capabilities(): RegCaps {\n return { strongRead: true };\n }\n\n async get(ref: SegmentRef): Promise<RegistryRecord | null> {\n const env = await this.readRow(registryRowPath(this.root, ref));\n return env && !env.deleted ? env.record : null;\n }\n\n async create(ref: SegmentRef, record: NewRegistryRecord): Promise<{ token: Token }> {\n validateNewRegistryRecord(record);\n const path = registryRowPath(this.root, ref);\n return this.withRowLock(path, async () => {\n const current = await this.readRow(path);\n if (current !== null && !current.deleted) {\n throw new WriteConflictError(`registry row already exists for segment ${ref.segment}`);\n }\n const counter = current ? registryCounterOf(current.record) + 1 : 0; // advance across a tombstone (ABA-safe)\n const token = String(counter);\n await this.writeRow(path, false, recordFromNew(ref, record, this.now(), token));\n return { token };\n });\n }\n\n async compareAndSwap(\n ref: SegmentRef,\n expected: Token,\n patch: RegistryPatch,\n ): Promise<{ token: Token }> {\n validateRegistryPatch(patch);\n const path = registryRowPath(this.root, ref);\n return this.withRowLock(path, async () => {\n const current = await this.readRow(path);\n if (current === null || current.deleted || current.record.token !== expected) {\n throw new WriteConflictError(`OCC token mismatch for registry row ${ref.segment}`);\n }\n const token = String(registryCounterOf(current.record) + 1);\n await this.writeRow(\n path,\n false,\n applyRegistryPatch(current.record, patch, this.now(), token),\n );\n return { token };\n });\n }\n\n async *list(namespace?: string): AsyncIterable<RegistryRecord> {\n for (const ns of await this.namespaceDirs(namespace)) {\n const dir = registryDir(this.root, ns);\n let names: string[];\n try {\n names = await readdir(dir);\n } catch (err) {\n if (isCode(err, 'ENOENT')) continue; // no registry rows in this namespace yet\n throw mapFsError(err);\n }\n for (const name of names) {\n const segment = parseRegistryRow(name);\n if (segment === null) continue;\n const env = await this.readRow(registryRowPath(this.root, { namespace: ns, segment }));\n if (env && !env.deleted) yield env.record;\n }\n }\n }\n\n async delete(ref: SegmentRef): Promise<void> {\n const path = registryRowPath(this.root, ref);\n return this.withRowLock(path, async () => {\n const current = await this.readRow(path);\n if (current === null || current.deleted) return; // idempotent\n // Tombstone (advance the counter) rather than unlink \u2014 keeps the token monotonic for ABA-safety.\n const token = String(registryCounterOf(current.record) + 1);\n await this.writeRow(path, true, { ...current.record, token, updatedAt: this.now() });\n });\n }\n\n /** Namespaces to scan: just the one requested, or every namespace dir under the root. */\n private async namespaceDirs(namespace: string | undefined): Promise<Array<string | undefined>> {\n if (namespace !== undefined) return [namespace];\n let entries: string[];\n try {\n entries = await readdir(this.root);\n } catch (err) {\n if (isCode(err, 'ENOENT')) return [];\n throw mapFsError(err);\n }\n // A namespace dir name is the namespace ENCODED for a path, so it has to be parsed back rather than used\n // as-is \u2014 `tenant:acme` lives in `tenant%3Aacme`, and `%` only ever appears in an escape we wrote, so an un-decoded directory name fails the round-trip check. Anything that does\n // not parse is skipped, never thrown on: this enumeration is fleet-wide, so one unrecognised directory\n // must not take the consistency check, the retention sweep and subject erasure down with it.\n const namespaces: Array<string | undefined> = [];\n for (const entry of entries) {\n const parsed = parseNamespaceDir(entry);\n if (parsed !== null) namespaces.push(parsed.namespace);\n }\n return namespaces;\n }\n\n private async readRow(path: string): Promise<RegistryEnvelope | null> {\n let handle;\n try {\n handle = await open(path, FS.O_RDONLY | O_NOFOLLOW);\n } catch (err) {\n if (isCode(err, 'ENOENT') || isCode(err, 'ELOOP')) return null;\n throw mapFsError(err);\n }\n try {\n const { size } = await handle.stat();\n if (size > DEFAULT_MAX_ROW_BYTES) {\n throw new IntegrityError(`registry row ${size}B exceeds cap ${DEFAULT_MAX_ROW_BYTES}B`);\n }\n const text = (await handle.readFile()).toString('utf8');\n return parseRegistryEnvelope(text, path);\n } finally {\n await handle.close();\n }\n }\n\n private async writeRow(path: string, deleted: boolean, record: RegistryRecord): Promise<void> {\n await mkdir(dirname(path), { recursive: true });\n const out = Buffer.from(serializeRegistryEnvelope({ deleted, record }), 'utf8');\n // Cap on the write path too (the read path caps at the same size): never produce a row that would later\n // be unreadable. The governance fields are already capped by validate*, so this is a belt-and-braces guard.\n if (out.length > DEFAULT_MAX_ROW_BYTES) {\n throw new ValidationError(\n `registry row ${out.length}B exceeds cap ${DEFAULT_MAX_ROW_BYTES}B`,\n );\n }\n\n const tmp = `${path}.${randomUUID()}.tmp`;\n let handle;\n try {\n handle = await open(tmp, FS.O_CREAT | FS.O_EXCL | FS.O_WRONLY | O_NOFOLLOW);\n } catch (err) {\n throw mapFsError(err);\n }\n try {\n await handle.write(out);\n await handle.sync();\n } finally {\n await handle.close();\n }\n await rename(tmp, path).catch(async (err) => {\n await unlink(tmp).catch(() => {});\n throw mapFsError(err);\n });\n await fsyncDir(dirname(path));\n }\n\n /** Serialize callbacks for a row path so read-modify-write is atomic in-process. */\n private withRowLock<T>(key: string, fn: () => Promise<T>): Promise<T> {\n const prev = this.chain.get(key) ?? Promise.resolve();\n const result = prev.then(fn, fn);\n const tail = result.then(\n () => undefined,\n () => undefined,\n );\n this.chain.set(key, tail);\n void tail.then(() => {\n if (this.chain.get(key) === tail) this.chain.delete(key);\n });\n return result;\n }\n}\n", "/**\n * The two SDK-free backends, each as one object: `MemoryStorage` and `LocalFsStorage`.\n *\n * These live in the main entry because neither needs a cloud SDK \u2014 there is nothing to keep out of the\n * install, and it keeps the first five minutes to a single import. Their cloud siblings (`S3Storage`,\n * `GcsStorage`, `AzureBlobStorage`) ship in `@cloudbitmaps/s3`, `/gcs` and `/azure-blob` for the opposite\n * reason: each carries an SDK nobody should install for a service they do not use.\n *\n * Each one exists to state a location **once**. See {@link StorageBackend} for why that is worth a class.\n */\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { ValidationError } from '@/core/errors';\nimport { brandAsBackend, STORAGE_BACKEND } from '@/core/ports';\nimport type { StorageBackend } from '@/core/ports';\nimport { MemoryRegistryDriver, MemoryStorageDriver } from './memory';\nimport { LocalFsStorageDriver } from './localfs/storage';\nimport { LocalFsRegistryDriver } from './localfs/registry';\n\nexport interface MemoryStorageOptions {\n /** Injected clock for the registry's `createdAt`/`updatedAt`; defaults to `Date.now`. */\n readonly now?: () => number;\n}\n\n/**\n * An in-process backend \u2014 nothing to install, nothing to clean up, and it disappears with the process.\n *\n * This is the one to reach for in tests and in the first five minutes. It is **not** a cache in front of\n * anything: it is the whole store, held in RAM, so a restart is a data loss.\n */\nexport class MemoryStorage implements StorageBackend {\n /** Cross-bundle brand, stamped non-enumerably in the constructor so a spread cannot carry it. */\n declare readonly [STORAGE_BACKEND]: true;\n readonly storage: MemoryStorageDriver;\n readonly registry: MemoryRegistryDriver;\n\n constructor(options: MemoryStorageOptions = {}) {\n this.storage = new MemoryStorageDriver();\n this.registry = new MemoryRegistryDriver(options.now === undefined ? {} : { now: options.now });\n brandAsBackend(this);\n }\n}\n\nexport interface LocalFsStorageOptions {\n /** Injected clock for the registry's `createdAt`/`updatedAt`; defaults to `Date.now`. */\n readonly now?: () => number;\n}\n\n/**\n * A local-filesystem backend rooted at one directory: generations under `<root>/storage`, pointers under\n * `<root>/registry`.\n *\n * The layout is stated here rather than by the caller, which is the point \u2014 the two halves used to be two\n * paths a caller wrote out separately, and nothing stopped them naming different roots. It is also the layout\n * the `export-segments` CLI expects, so a store built this way can be ejected without being told where to look.\n *\n * **It refuses a store written before the tier was renamed**, because the alternative is much worse than an\n * error. Such a store keeps its generations in `<root>/cold`, where this class does not look, so the registry\n * half resolves a pointer the storage half cannot satisfy \u2014 and the store reports\n * `missing-storage-generation`, which is the signature of a **torn restore**. The runbook's remedies for that\n * include rolling `currentGen` back, which is destructive and would be applied to a store that was never\n * damaged. One `existsSync` at wiring time is a cheap price for not sending someone down that path.\n */\nexport class LocalFsStorage implements StorageBackend {\n /** Cross-bundle brand, stamped non-enumerably in the constructor so a spread cannot carry it. */\n declare readonly [STORAGE_BACKEND]: true;\n readonly storage: LocalFsStorageDriver;\n readonly registry: LocalFsRegistryDriver;\n\n constructor(\n readonly root: string,\n options: LocalFsStorageOptions = {},\n ) {\n if (!existsSync(join(root, 'storage')) && existsSync(join(root, 'cold'))) {\n throw new ValidationError(\n `${root} holds a \"cold/\" directory but no \"storage/\" \u2014 this store was written before the tier was ` +\n `renamed. Rename it (\\`mv ${root}/cold ${root}/storage\\`) and re-run; the objects inside are ` +\n `unchanged. Do NOT treat the \"missing-storage-generation\" you would otherwise see as a torn ` +\n `restore \u2014 the data is intact, it is the path that moved.`,\n );\n }\n this.storage = new LocalFsStorageDriver(join(root, 'storage'));\n this.registry = new LocalFsRegistryDriver(\n join(root, 'registry'),\n options.now === undefined ? {} : { now: options.now },\n );\n brandAsBackend(this);\n }\n}\n", "/**\n * Audit sink \u2014 an injected, no-op-by-default seam for **security/compliance** events, distinct\n * from the metrics sink (5a). Different audience (an audit log / SIEM, not a dashboard), different retention,\n * and only the compliance-relevant *state changes* \u2014 never routine reads/writes (that's the metrics sink).\n * It doubles as the GDPR Art. 30 \"record of processing\" surface: publishes, rewrites, and erasures.\n *\n * Like `Clock`/`Rng`/`IMetricsSink`, it's injected (into the operations that emit \u2014 bulk-load, the `*Into`\n * verbs, the erasure rewrite, crypto-shred, disposal and the retention sweep) and wrapped exception-safe, so a\n * buggy sink can never break the operation it observes.\n * Events are vendor-neutral and carry no timestamp/actor \u2014 the sink runs synchronously at the event, so it\n * stamps its own time / attaches the caller identity (keeps `core/` free of ambient time). As with metrics,\n * `segment`/`namespace` are caller-controlled strings that may be PII \u2014 treat them accordingly when routing.\n *\n * Not (yet) emitted: **KEK rotation** \u2014 rotation here is operator-side keystore reconfiguration (key-id-tagged\n * wrappings, no data re-encryption), so there is no library call to hook. A future `rewrapSegment()` op would\n * add a `kek.rotate` variant; until then, audit key changes at your keystore-config layer.\n */\n\n/** A security/compliance-relevant state change. Vendor-neutral; the sink adds its own timestamp/actor. */\nexport type AuditEvent =\n | {\n /** A new immutable Storage generation *became the segment's current generation* (via bulk-load publish). */\n readonly kind: 'segment.publish';\n readonly namespace?: string;\n readonly segment: string;\n readonly generation: number;\n }\n | {\n /**\n * A segment's pointer was moved **backwards**, to a generation still in the bucket.\n *\n * The only non-forward-only pointer move in the library, and the only one no automatic path can perform \u2014\n * a human decided the current generation was wrong and named the one they wanted. Every other pointer move\n * can be reconstructed from \"a load happened\"; this one is someone overriding the ordering rule the rest of\n * the system relies on, which is precisely what an incident review or an Art. 30 record wants to find.\n *\n * `fromGeneration` is `null` when the segment had a row but no current generation.\n */\n readonly kind: 'segment.rollback';\n readonly namespace?: string;\n readonly segment: string;\n readonly fromGeneration: number | null;\n readonly generation: number;\n }\n | {\n /**\n * A load was **refused** \u2014 the generation was written, failed a guard, and was deleted again rather than\n * published. The security-relevant fact is that a replacement the caller asked for did NOT happen, which a\n * downstream system reconciling \"the segment should now contain X\" needs as much as it needs the publish.\n *\n * `reason` is `'empty'` (an empty result over a non-empty segment, with no `allowEmpty`),\n * `'min-cardinality'`, `'min-retained'`, or `'superseded'` (another writer published a higher generation\n * first). `cardinality` is what the refused generation would have contained.\n */\n readonly kind: 'segment.load-refused';\n readonly namespace?: string;\n readonly segment: string;\n readonly generation: number;\n readonly reason: 'empty' | 'min-cardinality' | 'min-retained' | 'superseded';\n readonly cardinality: number;\n }\n | {\n /**\n * A generation was **rewritten**: a new generation derived from `fromGeneration` became current in its\n * place. Today the one emitter is `eraseIdFromSegment` (a subject erasure clearing one id), and the event is\n * emitted at the publish \u2014 before the superseded generation is collected \u2014 so the record exists the moment\n * the generation without the id is authoritative. A `segment.publish` is NOT also emitted for a rewrite: a\n * rewrite derives its content from the segment itself, a publish brings content in from outside.\n */\n readonly kind: 'segment.rewrite';\n readonly namespace?: string;\n readonly segment: string;\n readonly fromGeneration: number;\n readonly generation: number;\n }\n | {\n /**\n * A segment was **crypto-shredded** \u2014 its wrapped DEK(s) are gone, so its at-rest Storage bytes are now\n * permanently unreadable. Emitted only for a genuine key shred, never for a cleartext tombstone (which\n * leaves the Storage bytes readable) or an idempotent re-run.\n */\n readonly kind: 'segment.erase';\n readonly namespace?: string;\n readonly segment: string;\n }\n | {\n /**\n * A segment was **disposed of** \u2014 tombstoned and its storage reclaimed (its Storage generations deleted) by\n * `dropSegment`, *without* a key shred.\n *\n * Deliberately a separate kind from {@link AuditEvent} `segment.erase`, and the distinction is the point.\n * `segment.erase` attests that bytes are unreadable **everywhere, backups included** \u2014 the only claim that\n * survives WORM. Deleting an object is strictly weaker: a noncurrent version, a cross-region replica or a\n * PITR snapshot can still hold the cleartext. Emitting one kind for both would make a compliance dashboard\n * over-attest, so a cleartext drop gets this instead.\n *\n * An **encrypted** segment dropped via `dropSegment` emits **both** \u2014 `segment.erase` for the key shred and\n * this for the storage reclamation \u2014 because both things genuinely happened.\n *\n * `generationsDeleted` is how many Storage generations went. It can be 0 (a segment whose bytes were already\n * gone), and it does not promise the storage is now fully reclaimed: check `DropResult.generationsRemaining`\n * for that.\n */\n readonly kind: 'segment.dispose';\n readonly namespace?: string;\n readonly segment: string;\n readonly generationsDeleted: number;\n }\n | {\n /** A namespace erasure was executed. `segmentsShredded` is the count actually crypto-shredded (may be 0). */\n readonly kind: 'namespace.erase';\n readonly namespace: string;\n readonly segmentsShredded: number;\n };\n\n/** The `kind` discriminant of an {@link AuditEvent}. */\nexport type AuditEventKind = AuditEvent['kind'];\n\n/** Sink for {@link AuditEvent}s. Injected via the lifecycle options; omit it and nothing is recorded. */\nexport interface IAuditSink {\n onEvent(event: AuditEvent): void;\n}\n\n/** The default sink: records nothing. */\nexport const NOOP_AUDIT: IAuditSink = {\n onEvent(): void {\n /* discard */\n },\n};\n\n/**\n * Wrap a sink so a throwing/buggy `onEvent` can never break the lifecycle operation it observes \u2014 audit is\n * strictly observation. Returns {@link NOOP_AUDIT} unchanged (so the no-op case skips even the try/catch alloc).\n */\nexport function safeAudit(sink: IAuditSink): IAuditSink {\n if (sink === NOOP_AUDIT) return sink;\n return {\n onEvent(event: AuditEvent): void {\n try {\n sink.onEvent(event);\n } catch {\n /* swallow \u2014 an audit sink must never break the operation it observes */\n }\n },\n };\n}\n\n/** A ready-made sink that records events into an in-memory list \u2014 handy for tests + simple audit trails. */\nexport class RecordingAuditSink implements IAuditSink {\n private readonly recorded: AuditEvent[] = [];\n\n onEvent(event: AuditEvent): void {\n this.recorded.push(event);\n }\n\n /** An independent copy of the recorded events, in emission order. */\n snapshot(): AuditEvent[] {\n return this.recorded.map((e) => ({ ...e }));\n }\n\n reset(): void {\n this.recorded.length = 0;\n }\n}\n", "/**\n * Cooperative yielding for the long CPU-bound loops.\n *\n * Everything this library does on the hot read path is small. Bulk-load is the exception: it is the one place\n * where a single call legitimately occupies the CPU for hundreds of milliseconds, and Node has exactly one thread\n * to occupy. Measured on a 1M-id load, 62,455 chunks: **442 ms wall, and 450 ms during which the event loop did\n * not turn at all**. Wire that to a request handler and every other in-flight request on the instance \u2014 health\n * checks included \u2014 waits out the whole load.\n *\n * The fix is not to make the work asynchronous. That was measured too, and it is a 7x *regression*: handing each\n * chunk's insert to the threadpool costs ~9 \u00B5s of dispatch against ~1.5 \u00B5s of actual work once ids are spread\n * across ~62,000 chunks (636 ms versus 92 ms). The work is genuinely CPU-bound and genuinely small per chunk;\n * the only thing wrong with it is that it never stops to let anyone else go. So the fix is to keep the work\n * synchronous and periodically hand the loop back.\n *\n * TWO TRAPS, both of which make a plausible implementation measure as no change at all:\n *\n * 1. **`await Promise.resolve()` \u2014 and equally `Clock.sleep(0)` \u2014 do nothing.** Both resolve on a microtask, and\n * the microtask queue drains to empty before the event loop advances a single phase. A loop awaiting them\n * yields to other *microtasks* and to nothing else; no pending I/O callback runs. Measured: 555 ms of\n * starvation against a 568 ms unyielded baseline **on the synthetic yield-primitive benchmark below** \u2014\n * a different, smaller workload than the 442 ms end-to-end load above, which is why the two baselines\n * differ. The yield must be a **macrotask** \u2014 hence\n * `Clock.yieldNow`, backed by `setImmediate` in production wiring.\n * 2. **Yielding per unit of work costs more than the work.** The yield has to be periodic, and `everyN` has to be\n * large enough that its cost disappears into the batch it interrupts.\n *\n * At `everyN = 1024` over that same synthetic workload the trade is close to free: 569 ms wall against a 568 ms\n * baseline, with the worst event-loop gap down from 568 ms to 13.8 ms.\n *\n * **Three experiments, three sets of numbers \u2014 do not mix them.** (a) The end-to-end 1M-id bulk load:\n * 442 ms wall / 450 ms blocked before, 256 ms / 19 ms after. (b) This synthetic yield-primitive comparison:\n * 568 ms / 568 ms unyielded, 569 ms / 13.8 ms with `setImmediate`. (c) A per-chunk insert microbenchmark:\n * 92 ms sync versus 636 ms via the threadpool. Quoting a baseline from one against a result from another is\n * how this file previously published a 92 ms operation with 819 ms of starvation inside it.\n */\n/**\n * The only part of a `Clock` that yielding actually needs.\n *\n * Deliberately looser than `Clock` so a write path can opt in with whatever it has: a bulk load or a rewrite\n * yields when its caller supplies a clock that can, and simply runs unbroken when handed nothing (or a bare\n * `{ now }`). Requiring a full `Clock` would make every out-of-process caller wire one just to write a\n * generation.\n */\nexport interface Yielder {\n yieldNow?(): Promise<void>;\n sleep?(ms: number): Promise<void>;\n}\n\n/**\n * How many units of work pass between yields. Sized so the yield is unmeasurable against the batch it interrupts\n * (~60 yields across a 1M-id load) while still capping any single blocking stretch in the low tens of ms.\n */\nexport const YIELD_EVERY = 1024;\n\n/**\n * Build a periodic yield.\n *\n * Call the returned function **once per unit of work**. It returns `null` on the vast majority of calls \u2014 nothing\n * to await, nothing allocated \u2014 and a promise only on the `everyN`th, so the caller pays for a yield only when\n * one actually happens:\n *\n * ```ts\n * const tick = yieldEvery(clock);\n * for (const item of millions) {\n * work(item);\n * const pause = tick();\n * if (pause !== null) await pause;\n * }\n * ```\n *\n * The two-line shape is deliberate. `await tick()` would read better and would force a microtask turn on every\n * single iteration \u2014 an unconditional cost on the very loop this exists to keep fast.\n *\n * With no `clock` the result always returns `null`: the loop runs exactly as it did before this existed, so\n * adding a yield point to a code path can never change behaviour for a caller who did not opt in. `core/` cannot\n * supply a clock itself \u2014 it is timer-free by lint, which is the whole reason scheduling goes through the seam \u2014\n * so `@cloudbitmaps/roaring` pre-binds a real one and flavor users get this with no wiring at all.\n */\nexport function yieldEvery(\n clock: Yielder | undefined,\n everyN: number = YIELD_EVERY,\n): () => Promise<void> | null {\n if (clock === undefined) return () => null;\n // Resolved once here rather than re-tested every yield.\n //\n // A clock predating `yieldNow` falls back to `sleep(1)`, which yields on a *timer-backed* clock at ~1 ms of\n // dead wall-clock apiece (measured: +10% on the load above). It does NOT yield on a clock whose `sleep`\n // ignores its argument and resolves on a microtask \u2014 `InstantClock` and `SimClock` both do, deliberately.\n // Those are non-production wirings where yielding is meaningless, and both now say so by implementing\n // `yieldNow` as an explicit no-op rather than arriving here by accident.\n const sleep = clock.sleep;\n const pause =\n clock.yieldNow !== undefined\n ? (): Promise<void> => clock.yieldNow!()\n : sleep !== undefined\n ? (): Promise<void> => sleep.call(clock, 1)\n : undefined;\n if (pause === undefined) return () => null; // a clock that can neither yield nor sleep: nothing to do\n let n = 0;\n return () => {\n if (++n < everyN) return null;\n n = 0;\n return pause();\n };\n}\n", "/**\n * Encryption seams \u2014 the **pure** interfaces `core/` depends on so the codec can encrypt/decrypt without\n * importing `node:crypto` (lint-banned here, like `Clock`/`Rng`/drivers). Concrete AES-256-GCM lives outside\n * `core/` (`src/drivers/crypto.ts`) and is injected. The envelope scheme: a per-segment DEK wrapped under an\n * operator-held KEK, so discarding the DEK crypto-shreds the segment. Per-chunk AEAD over the `.crbm` payloads + index; a per-segment **DEK** wrapped (envelope\n * encryption) under one or more **KEK**s by an {@link IKeystore}; the wrapped DEK(s) live in the registry, so\n * crypto-shred = delete them.\n */\n\n/** One AEAD result: a fresh per-message nonce, the ciphertext, and the authentication tag. */\nexport interface AeadSealed {\n readonly nonce: Uint8Array;\n readonly ciphertext: Uint8Array;\n readonly tag: Uint8Array;\n}\n\n/**\n * Authenticated encryption bound to a single key (a segment's DEK). `aad` (associated data) is authenticated\n * but not encrypted \u2014 the codec passes each chunk's `(namespace, segment, generation, chunkKey)` identity\n * (the library derives it; an `Aead` implementation receives it), so a chunk's ciphertext can't be silently\n * relocated to another segment/generation/chunk or\n * the index, even by someone who can rewrite Storage objects. The seam is symmetric and self-framing-agnostic:\n * the caller decides where the nonce/tag go (inline with a chunk, or in the footer for the index).\n */\nexport interface Aead {\n /** Encrypt `plaintext`, authenticating `aad`. Returns a fresh nonce + ciphertext + tag. */\n seal(plaintext: Uint8Array, aad: Uint8Array): AeadSealed;\n /**\n * Decrypt + verify. Throws {@link IntegrityError} on **any** mismatch (wrong key, tampered ciphertext/tag,\n * or `aad` that doesn't match what was sealed) \u2014 never returns wrong-but-plausible plaintext.\n */\n open(sealed: AeadSealed, aad: Uint8Array): Uint8Array;\n}\n\n/**\n * A DEK wrapped under one KEK. A segment stores a **list** of these (one per KEK it was wrapped under \u2014 e.g.\n * an active KEK plus an offline recovery KEK), so losing one KEK isn't fatal and KEK rotation needs no\n * data re-encryption. `keyId` names which KEK; `wrapped` is the opaque wrapped-key blob (base64). Carries no\n * plaintext key material \u2014 safe to store in the registry next to the (encrypted) data.\n */\nexport interface WrappedDek {\n readonly keyId: string;\n readonly wrapped: string;\n}\n\n/**\n * Envelope key management \u2014 the injected seam between the codec and however the operator holds key material\n * (in-process BYOK by default; KMS/Vault as optional adapters later). Async so a remote keystore (KMS) fits\n * the same interface. Never exposes raw key bytes to `core/`: it returns an {@link Aead} bound to the DEK.\n */\nexport interface IKeystore {\n /**\n * Mint a fresh per-segment DEK, wrapped under the active KEK (and any recovery KEK). Returns the wrapping(s)\n * to persist in the registry plus an {@link Aead} to encrypt this segment's chunks with.\n */\n createDek(): Promise<{ wrapped: WrappedDek[]; aead: Aead }>;\n /**\n * Reconstruct the {@link Aead} from a segment's stored wrappings by unwrapping with any KEK currently held.\n * Throws {@link KeyUnavailableError} if it holds none of the referenced KEKs (lost key, or a shredded\n * segment whose wrappings were deleted).\n */\n openDek(wrapped: readonly WrappedDek[]): Promise<Aead>;\n}\n\n/**\n * What the encrypting codec needs: the {@link Aead} for this segment's DEK plus a way to build the AAD for a\n * given scope (`'index'` or a chunkKey). Built per (segment, generation) by the storage-source bridge so the\n * codec itself stays segment-agnostic.\n */\nexport interface CrbmCrypto {\n readonly aead: Aead;\n aadFor(scope: number | 'index'): Uint8Array;\n}\n\nconst AAD_VERSION = 1;\nconst SCOPE_CHUNK = 0;\nconst SCOPE_INDEX = 1;\n\n/**\n * Build the AEAD associated-data binding a chunk (or the index) to its exact location:\n * `v1 \u2016 len(namespace) \u2016 namespace \u2016 len(segment) \u2016 segment \u2016 generation \u2016 scope \u2016 chunkKey`. Length-prefixed\n * so distinct `(namespace, segment)` pairs can never collide. Pure (no crypto) \u2014 just the authenticated label.\n */\nexport function aadFor(\n ref: { readonly namespace?: string; readonly segment: string },\n generation: number,\n scope: number | 'index',\n): Uint8Array {\n const enc = new TextEncoder();\n const ns = enc.encode(ref.namespace ?? '');\n const seg = enc.encode(ref.segment);\n const out = new Uint8Array(1 + 2 + ns.length + 2 + seg.length + 8 + 1 + 4);\n const view = new DataView(out.buffer);\n let o = 0;\n out[o] = AAD_VERSION;\n o += 1;\n view.setUint16(o, ns.length, true);\n o += 2;\n out.set(ns, o);\n o += ns.length;\n view.setUint16(o, seg.length, true);\n o += 2;\n out.set(seg, o);\n o += seg.length;\n view.setBigUint64(o, BigInt(generation), true);\n o += 8;\n out[o] = scope === 'index' ? SCOPE_INDEX : SCOPE_CHUNK;\n o += 1;\n view.setUint32(o, scope === 'index' ? 0 : scope, true);\n return out;\n}\n", "/**\n * CRC32C (Castagnoli, polynomial 0x1EDC6F41) \u2014 the pre-deserialize integrity screen for `.crbm`\n * payloads, index, and footer.\n *\n * Pure TypeScript, table-driven: `core/` may not import `crypto`/`node:crypto` (the determinism lint\n * enforces it), and a from-scratch implementation is what the cross-language golden corpus will be pinned\n * against. CRC32C (not CRC32) is the locked choice \u2014 it matches the hardware-accelerated checksum used\n * by SSE/iSCSI/Btrfs, and it is the algorithm the `.crbm` format locks in.\n */\n\n/** Reflected CRC32C lookup table (256 entries), built once from the reflected polynomial. */\n/**\n * Slicing-by-8 tables. `TABLES[0]` is the classic byte-at-a-time table; each subsequent table is the previous\n * one advanced by another byte position, which is what lets the loop below consume 8 bytes per iteration\n * instead of one.\n */\nconst TABLES = ((): Uint32Array[] => {\n const POLY = 0x82f63b78; // bit-reflected 0x1EDC6F41\n const t0 = new Uint32Array(256);\n for (let n = 0; n < 256; n++) {\n let c = n;\n for (let k = 0; k < 8; k++) c = c & 1 ? POLY ^ (c >>> 1) : c >>> 1;\n t0[n] = c >>> 0;\n }\n const tables = [t0];\n for (let k = 1; k < 8; k++) {\n const prev = tables[k - 1] as Uint32Array;\n const next = new Uint32Array(256);\n for (let n = 0; n < 256; n++) {\n const v = prev[n] as number;\n next[n] = ((v >>> 8) ^ (t0[v & 0xff] as number)) >>> 0;\n }\n tables.push(next);\n }\n return tables;\n})();\nconst T0 = TABLES[0] as Uint32Array;\nconst T1 = TABLES[1] as Uint32Array;\nconst T2 = TABLES[2] as Uint32Array;\nconst T3 = TABLES[3] as Uint32Array;\nconst T4 = TABLES[4] as Uint32Array;\nconst T5 = TABLES[5] as Uint32Array;\nconst T6 = TABLES[6] as Uint32Array;\nconst T7 = TABLES[7] as Uint32Array;\n\nexport function crc32c(bytes: Uint8Array, seed = 0): number {\n let crc = (seed ^ 0xffffffff) >>> 0;\n let i = 0;\n // Eight bytes per iteration. Identical output to the byte-at-a-time form \u2014 this is the standard\n // slicing-by-8 arrangement of the same polynomial, not a different checksum \u2014 but it amortises the table\n // lookups and the loop overhead across eight bytes. That matters because this runs over the whole `.crbm`\n // index on every reader open, where the byte-at-a-time version measured ~3.3 ms/MiB and up to ~27 ms for a\n // maximally-sized index, all of it a synchronous stall on Node's only thread.\n const n8 = bytes.length - (bytes.length % 8);\n for (; i < n8; i += 8) {\n crc ^=\n (bytes[i] as number) |\n ((bytes[i + 1] as number) << 8) |\n ((bytes[i + 2] as number) << 16) |\n ((bytes[i + 3] as number) << 24);\n crc =\n ((T7[crc & 0xff] as number) ^\n (T6[(crc >>> 8) & 0xff] as number) ^\n (T5[(crc >>> 16) & 0xff] as number) ^\n (T4[(crc >>> 24) & 0xff] as number) ^\n (T3[bytes[i + 4] as number] as number) ^\n (T2[bytes[i + 5] as number] as number) ^\n (T1[bytes[i + 6] as number] as number) ^\n (T0[bytes[i + 7] as number] as number)) >>>\n 0;\n }\n // Tail: whatever did not divide by 8, byte-at-a-time.\n for (; i < bytes.length; i++) {\n crc = ((T0[(crc ^ (bytes[i] as number)) & 0xff] as number) ^ (crc >>> 8)) >>> 0;\n }\n return (crc ^ 0xffffffff) >>> 0;\n}\n", "/**\n * LEB128 unsigned varint codec for the `.crbm` chunk index.\n *\n * The index is delta+varint encoded so a full 16-bit span stays ~400\u2013650 KB instead of ~900 KB of\n * fixed triplets. All index varint values are small (chunk-key deltas \u2264 65535,\n * cardinalities \u2264 65536, payload lengths bounded by a size cap) \u2014 well within 32 bits \u2014 so this codec\n * accepts unsigned integers in `[0, 0xffffffff]` and rejects anything wider as a programming error.\n */\nimport { IntegrityError } from '../errors';\n\nconst U32_CEIL = 0x1_0000_0000; // 2^32\n\n/** Append the LEB128 encoding of a u32 `value` to `out`. */\nexport function writeVarint(out: number[], value: number): void {\n if (!Number.isInteger(value) || value < 0 || value >= U32_CEIL) {\n throw new RangeError(`varint value must be a u32; got ${value}`);\n }\n let v = value;\n while (v > 0x7f) {\n out.push((v & 0x7f) | 0x80);\n v >>>= 7;\n }\n out.push(v);\n}\n\nexport interface VarintRead {\n readonly value: number;\n /** Offset just past the bytes consumed. */\n readonly next: number;\n}\n\n/**\n * Decode a LEB128 varint from `bytes` starting at `offset`. Throws `IntegrityError` on a truncated or\n * over-long (> 5-byte / > u32) encoding \u2014 the bytes are untrusted, so a malformed index must fail\n * cleanly, never loop or overflow.\n */\nexport function readVarint(bytes: Uint8Array, offset: number): VarintRead {\n let result = 0;\n let shift = 0;\n let pos = offset;\n for (let i = 0; i < 5; i++) {\n if (pos >= bytes.length) {\n throw new IntegrityError('varint truncated past end of buffer');\n }\n const byte = bytes[pos]!;\n pos += 1;\n // The 5th byte may contribute at most 4 bits (32 total); reject wider.\n if (i === 4 && byte > 0x0f) {\n throw new IntegrityError('varint exceeds u32 range');\n }\n result += (byte & 0x7f) * 2 ** shift;\n if ((byte & 0x80) === 0) {\n return { value: result, next: pos };\n }\n shift += 7;\n }\n throw new IntegrityError('varint exceeds u32 range');\n}\n", "/**\n * Frozen `.crbm` v1.0 layout constants.\n *\n * These byte widths/offsets are pinned by the golden corpus and must never change for v1 \u2014\n * a new layout is a new format version. All multi-byte integers are little-endian (v1 fixes LE).\n */\n\n/** 4-byte magic at both file ends: \"CRBM\". */\nexport const MAGIC = Uint8Array.of(0x43, 0x52, 0x42, 0x4d);\n\nexport const VERSION_MAJOR = 1;\nexport const VERSION_MINOR = 0;\n\n/** Front preamble: magic(4) + version_major(1) + version_minor(1) + reserved(2). */\nexport const PREAMBLE_BYTES = 8;\n\n/** Payloads begin immediately after the preamble. */\nexport const PAYLOAD_START = PREAMBLE_BYTES;\n\n/** Fixed footer size (v1.0). */\nexport const FOOTER_BYTES = 104;\n\n/** Byte offsets of each field within the 104-byte footer. */\nexport const FOOTER = {\n indexOffset: 0, // u64\n indexLength: 8, // u64\n indexCrc32c: 16, // u32\n flags: 20, // u32\n payloadCodecId: 24, // u16 \u2014 was `roaringSerializationId`; same offset, same width, wider meaning\n elementWidth: 26, // u8\n containerCodec: 27, // u8\n versionMajor: 28, // u8\n versionMinor: 29, // u8\n reserved2: 30, // u16\n generation: 32, // u64\n indexNonce: 40, // 12 B\n indexTag: 52, // 16 B\n keyId: 68, // 16 B\n chunkCount: 84, // u32\n totalCardinality: 88, // u64\n footerCrc32c: 96, // u32 \u2014 covers footer bytes [0, 96)\n endMagic: 100, // char[4]\n} as const;\n\n/** Footer bytes covered by `footer_crc32c` (everything before the CRC field). */\nexport const FOOTER_CRC_COVERAGE = FOOTER.footerCrc32c; // 96\n\n/** `flags` bit positions. */\nexport const FLAG_ENCRYPTED = 1 << 0;\nexport const FLAG_INDEX_COMPRESSED = 1 << 1; // reserved\nexport const FLAG_LITTLE_ENDIAN = 1 << 2; // =1 in v1\n\n/** Flag bits a v1 reader understands; any bit outside this mask is an unsupported feature. */\nexport const KNOWN_FLAGS = FLAG_ENCRYPTED | FLAG_LITTLE_ENDIAN;\n\n/**\n * Default element width: 32-bit ids (the u32 member space). `64` is the *reserved* escape above the\n * ~4.29 B-ids/segment u32 ceiling; a v1 (32-bit) reader must **reject** a 64-bit generation rather than feed\n * it to the 32-bit deserializer (which would mis-count fleet-wide). A future 64-bit generation is therefore a\n * **major**-version bump (auto-rejected by old readers), never a silent minor one \u2014 see\n * {@link CrbmReader.open} validates this.\n */\nexport const ELEMENT_WIDTH_32 = 32;\n\n/**\n * **Which codec produced the chunk payloads.** Recorded in the footer, validated on read.\n *\n * `.crbm` is a shared container: the index, the CRC32Cs, the AEAD framing and the generation model are all\n * codec-independent, and **only the chunk payload bytes belong to a flavor** (hence *Chunked Remote BitMap* \u2014\n * see the `.crbm` format section of the API reference). This field is what lets one container hold either, the same way ZIP tags each member\n * with a compression method.\n *\n * **Why this is not named `roaringSerializationId` any more.** It was, and the name was a trap waiting for the\n * `1.0` format freeze. A second codec is genuinely expected \u2014 `soaring` is a planned Roaring *variant*, so its\n * serialized bytes are unlikely to be roaring-portable, and it lands *after* `1.0`. A field frozen under a\n * codec-specific name cannot be reinterpreted later without a major format version, so generalizing it is a\n * one-line change now and an expensive one after the freeze. The byte layout is untouched: same offset (24),\n * same width (u16), same golden corpus.\n *\n * **Ids are permanent once published.** Add to {@link KNOWN_PAYLOAD_CODEC_IDS} when a codec ships; never\n * reuse or renumber. Ids are deliberately *not* pre-allocated for codecs that do not exist \u2014 a reserved number\n * for an unbuilt codec is a guess about a format nobody has designed.\n */\nexport const PAYLOAD_CODEC_ROARING_PORTABLE = 1;\n\n/**\n * Every payload codec id this reader can decode.\n *\n * The reader validates membership rather than equality with a single constant. That is the whole point of the\n * generalization: an unknown id is rejected with a typed error naming it, so an old reader meeting a\n * future-codec generation **fails closed** \u2014 the correct direction, and the reason a store built on one codec\n * can never silently misread another's bytes as its own. (The homogeneity contract means one store is one\n * codec, so meeting a foreign generation implies misconfiguration, and a loud rejection is exactly what you\n * want there.)\n */\nexport const KNOWN_PAYLOAD_CODEC_IDS: ReadonlySet<number> = new Set([\n PAYLOAD_CODEC_ROARING_PORTABLE,\n]);\n\n/**\n * The only container codec v1 defines: `0` = none (payloads are stored as the portable roaring serialization\n * with no extra container-level transform). A non-zero codec is a future format feature; a v1 reader rejects\n * it ({@link UnsupportedError}) rather than mis-decode. Stamped by the writer, validated by the reader.\n */\nexport const CONTAINER_CODEC_NONE = 0;\n\n/**\n * Default speculative-tail-read size. The spec's worst-case index (a full 16-bit span) is ~400\u2013650 KB,\n * so 256 KB collapses the read to a single GET for the vast majority of real (sparse/medium) segments;\n * only near-full-span segments take the documented second GET.\n */\nexport const DEFAULT_TAIL_BYTES = 256 * 1024;\n\n/**\n * Hard cap on the index region a reader will fetch/parse from one (untrusted) object. The index is read\n * whole on the cheap `open()`/`count()` path, so it must be bounded before allocation \u2014 generously\n * above the ~650 KB full-span worst case, well below a denial-of-wallet allocation.\n */\nexport const DEFAULT_MAX_INDEX_BYTES = 8 * 1024 * 1024;\n\n/** Hard cap on a single chunk payload, defending the native deserializer against oversized input. */\nexport const DEFAULT_MAX_PAYLOAD_BYTES = 16 * 1024 * 1024;\n\n/** A chunk's cardinality is in `[1, 65536]` (empty chunks are never written). */\nexport const MAX_CHUNK_CARDINALITY = 0x1_0000;\n\n/** Fixed width of a per-chunk CRC32C field in the index (high-entropy \u2192 not varint). */\nexport const CRC32C_BYTES = 4;\n\n/**\n * v1 AEAD framing sizes (AES-256-GCM), fixed by the format exactly like the roaring serialization id \u2014 a\n * different cipher is a new format version. An encrypted chunk payload is stored as `nonce \u2016 ciphertext \u2016 tag`;\n * the encrypted **index**'s nonce/tag live in the footer's reserved `indexNonce`/`indexTag` slots. Matches\n * {@link FOOTER.indexNonce} (12 B) and {@link FOOTER.indexTag} (16 B).\n */\nexport const AEAD_NONCE_BYTES = 12;\nexport const AEAD_TAG_BYTES = 16;\n", "/**\n * `CrbmReader` \u2014 speculative-tail-read reader for one `.crbm` generation.\n *\n * `open()` fetches the object's tail in **one GET** (footer + usually the whole index), verifies the\n * footer/index CRCs, and parses the delta+varint index into a map. `getChunk()` then range-GETs a single\n * payload and verifies its CRC32C **before** any native deserialize \u2014 every byte from storage is\n * untrusted.\n *\n * **Encryption.** When the footer's `FLAG_ENCRYPTED` is set, a {@link CrbmCrypto} must be supplied:\n * the index is AES-256-GCM-decrypted (nonce/tag from the footer) and each chunk payload is decrypted after its\n * on-disk CRC passes. The footer's `chunkCount`/`totalCardinality` are zero on an encrypted object (metadata is\n * hidden), so both are derived from the decrypted index; AEAD authentication (incl. the per-location AAD)\n * replaces the cleartext-count cross-check.\n */\nimport { IntegrityError, UnsupportedError, ValidationError } from '../errors';\nimport type { BlobReader } from '../blob';\nimport type { CrbmCrypto } from '../crypto';\nimport { crc32c } from './crc32c';\nimport { readVarint } from './varint';\nimport {\n AEAD_NONCE_BYTES,\n AEAD_TAG_BYTES,\n CONTAINER_CODEC_NONE,\n CRC32C_BYTES,\n DEFAULT_MAX_INDEX_BYTES,\n DEFAULT_MAX_PAYLOAD_BYTES,\n DEFAULT_TAIL_BYTES,\n ELEMENT_WIDTH_32,\n FLAG_ENCRYPTED,\n FLAG_LITTLE_ENDIAN,\n FOOTER,\n FOOTER_BYTES,\n FOOTER_CRC_COVERAGE,\n KNOWN_FLAGS,\n MAGIC,\n MAX_CHUNK_CARDINALITY,\n PAYLOAD_START,\n PREAMBLE_BYTES,\n KNOWN_PAYLOAD_CODEC_IDS,\n PAYLOAD_CODEC_ROARING_PORTABLE,\n VERSION_MAJOR,\n} from './format';\n\nexport interface CrbmIndexEntry {\n readonly chunkKey: number;\n readonly offset: number;\n readonly length: number;\n readonly cardinality: number;\n readonly crc32c: number;\n}\n\n/**\n * Estimated retained JS heap for one parsed index entry, used to weight the reader-cache byte bound\n * ({@link CrbmReader.retainedIndexBytes}). In V8 an entry costs: a `Map` slot (~48\u201364 B: two pointer slots +\n * hash chaining), the {@link CrbmIndexEntry} object (~40\u201356 B: header + 5 fields, where `offset`/`crc32c`\n * routinely exceed the 2\u00B3\u00B9 SMI range and box as heap doubles, +16 B each), and one `orderedKeys` array slot\n * (~8 B) \u2014 realistically ~130\u2013160 B. Rounded UP to 160 so the bound **over-counts** (a configured N-byte\n * ceiling pins \u2264 N of real heap, never more), keeping the aggregate memory guarantee on the safe side. A\n * stable upper proxy, not an exact figure.\n */\nconst RETAINED_BYTES_PER_INDEX_ENTRY = 160;\n\nexport interface CrbmReaderOptions {\n /** Speculative tail size in bytes (default 256 KB; clamped up to at least the footer size). */\n readonly tailBytes?: number;\n /** Hard cap on a single chunk payload length (default 16 MB). */\n readonly maxPayloadBytes?: number;\n /** Hard cap on the whole index region fetched/parsed from one object (default 8 MB). */\n readonly maxIndexBytes?: number;\n /** Decryption context for an encrypted object (its DEK's AEAD + AAD builder). Required iff `FLAG_ENCRYPTED`. */\n readonly crypto?: CrbmCrypto;\n /**\n * Opaque marker for the *incarnation of the name* this object belongs to \u2014 the caller's own identity for the\n * registry row it resolved. The reader never interprets it; it carries it so a caller holding an open reader\n * can tell \"the same generation of the same segment\" from \"the same generation NUMBER of a segment that was\n * deleted and re-created\", which the number alone cannot express.\n */\n readonly lineage?: unknown;\n}\n\nfunction magicMatches(bytes: Uint8Array, offset: number): boolean {\n return (\n bytes[offset] === MAGIC[0] &&\n bytes[offset + 1] === MAGIC[1] &&\n bytes[offset + 2] === MAGIC[2] &&\n bytes[offset + 3] === MAGIC[3]\n );\n}\n\n/** Read a u64 footer field, rejecting values past JS safe-integer range (precision would be lost). */\nfunction readU64(view: DataView, offset: number, field: string): number {\n const big = view.getBigUint64(offset, true);\n if (big > BigInt(Number.MAX_SAFE_INTEGER)) {\n throw new IntegrityError(`.crbm ${field} ${big} exceeds safe-integer range`);\n }\n return Number(big);\n}\n\nexport class CrbmReader {\n private constructor(\n private readonly blob: BlobReader,\n private readonly objectSize: number,\n readonly generation: number,\n /** See {@link CrbmReaderOptions.lineage} \u2014 carried, never interpreted. */\n readonly lineage: unknown,\n readonly totalCardinality: number,\n private readonly entries: Map<number, CrbmIndexEntry>,\n private readonly orderedKeys: number[],\n /** True when `open()` satisfied the index from the tail GET alone (no second range read). */\n readonly servedFromTail: boolean,\n /** Set iff the object is encrypted \u2014 used to decrypt each chunk payload in {@link getChunk}. */\n private readonly crypto: CrbmCrypto | undefined,\n ) {}\n\n /** Total object bytes (from the one-GET tail read) \u2014 for grounded storage cost. */\n get sizeBytes(): number {\n return this.objectSize;\n }\n\n /**\n * Estimated retained JS heap of this reader's parsed index \u2014 the weight the storage reader cache bounds on\n * (a wide segment's parsed index, not its payloads, dominates the reader's footprint). `entries.size` scales with the number\n * of resident chunks (\u2264 65536), so this is `entries.size \u00D7 {@link RETAINED_BYTES_PER_INDEX_ENTRY}`.\n */\n get retainedIndexBytes(): number {\n return this.entries.size * RETAINED_BYTES_PER_INDEX_ENTRY;\n }\n\n /** Per-chunk cardinality (`chunkKey \u2192 count`) from the parsed index \u2014 no payload reads. */\n cardinalities(): Map<number, number> {\n const out = new Map<number, number>();\n for (const [chunkKey, entry] of this.entries) out.set(chunkKey, entry.cardinality);\n return out;\n }\n\n static async open(blob: BlobReader, options: CrbmReaderOptions = {}): Promise<CrbmReader> {\n // Always fetch at least a footer's worth, regardless of a smaller caller request.\n const tailBytes = Math.max(options.tailBytes ?? DEFAULT_TAIL_BYTES, FOOTER_BYTES);\n const maxPayloadBytes = options.maxPayloadBytes ?? DEFAULT_MAX_PAYLOAD_BYTES;\n const maxIndexBytes = options.maxIndexBytes ?? DEFAULT_MAX_INDEX_BYTES;\n const { bytes: tail, size } = await blob.getTail(tailBytes);\n\n if (size < PREAMBLE_BYTES + FOOTER_BYTES || tail.length < FOOTER_BYTES) {\n throw new IntegrityError(`.crbm too small: ${size}B`);\n }\n\n // --- Footer (last 104 bytes of the tail) ---\n const footer = tail.subarray(tail.length - FOOTER_BYTES);\n if (!magicMatches(footer, FOOTER.endMagic)) {\n throw new IntegrityError('.crbm end magic mismatch');\n }\n const fview = new DataView(footer.buffer, footer.byteOffset, footer.byteLength);\n const storedFooterCrc = fview.getUint32(FOOTER.footerCrc32c, true);\n if (crc32c(footer.subarray(0, FOOTER_CRC_COVERAGE)) !== storedFooterCrc) {\n throw new IntegrityError('.crbm footer CRC mismatch');\n }\n const versionMajor = footer[FOOTER.versionMajor]!;\n if (versionMajor !== VERSION_MAJOR) {\n throw new UnsupportedError(`.crbm major version ${versionMajor} not supported`);\n }\n const flags = fview.getUint32(FOOTER.flags, true);\n const encrypted = (flags & FLAG_ENCRYPTED) !== 0;\n if (encrypted && options.crypto === undefined) {\n throw new ValidationError('.crbm is encrypted but no decryption key (crypto) was provided');\n }\n if ((flags & FLAG_LITTLE_ENDIAN) === 0) {\n throw new UnsupportedError('.crbm big-endian layout not supported (v1 is little-endian)');\n }\n if ((flags & ~KNOWN_FLAGS) !== 0) {\n throw new UnsupportedError(`.crbm has unknown flag bits set: 0x${flags.toString(16)}`);\n }\n\n // Payload-decoding contract: the\n // reader must decode with the *same* element width, roaring serialization, and container codec the writer\n // stamped \u2014 a mismatch means the payloads are a format this v1 (32-bit, portable, uncompressed) reader can't\n // safely deserialize, so reject up front rather than feed them to the 32-bit deserializer and mis-count\n // fleet-wide. A 64-bit generation is the reserved >4.29 B-ids/segment escape and is a **major**-version bump\n // (auto-rejected here), never a silent minor one. All three fields are inside FOOTER_CRC_COVERAGE (verified).\n const elementWidth = footer[FOOTER.elementWidth]!;\n if (elementWidth !== ELEMENT_WIDTH_32) {\n throw new UnsupportedError(\n `.crbm element_width ${elementWidth} not supported (v1 reads 32-bit ids; 64-bit is a future major version)`,\n );\n }\n // Membership, not equality: the field says which codec wrote the payloads, and this reader accepts every\n // id it can actually decode. An unknown one fails closed rather than being handed to a decoder that would\n // misread it \u2014 see KNOWN_PAYLOAD_CODEC_IDS for why that direction is the safe one.\n const payloadCodecId = fview.getUint16(FOOTER.payloadCodecId, true);\n if (!KNOWN_PAYLOAD_CODEC_IDS.has(payloadCodecId)) {\n throw new UnsupportedError(\n `.crbm payload_codec_id ${payloadCodecId} not supported by this build ` +\n `(known: ${[...KNOWN_PAYLOAD_CODEC_IDS].join(', ')}; ` +\n `${PAYLOAD_CODEC_ROARING_PORTABLE}=roaring portable). A generation written by a different codec ` +\n `is rejected rather than decoded \u2014 a store uses one codec throughout.`,\n );\n }\n const containerCodec = footer[FOOTER.containerCodec]!;\n if (containerCodec !== CONTAINER_CODEC_NONE) {\n throw new UnsupportedError(\n `.crbm container_codec ${containerCodec} not supported (v1 defines only ${CONTAINER_CODEC_NONE}=none)`,\n );\n }\n\n const indexOffset = readU64(fview, FOOTER.indexOffset, 'index_offset');\n const indexLength = readU64(fview, FOOTER.indexLength, 'index_length');\n const indexCrc = fview.getUint32(FOOTER.indexCrc32c, true);\n const chunkCount = fview.getUint32(FOOTER.chunkCount, true);\n const totalCardinality = readU64(fview, FOOTER.totalCardinality, 'total_cardinality');\n const generation = readU64(fview, FOOTER.generation, 'generation');\n\n // Bounds + size cap on the index region before trusting/fetching it.\n if (indexOffset < PAYLOAD_START || indexOffset + indexLength > size - FOOTER_BYTES) {\n throw new IntegrityError(\n `.crbm index region [${indexOffset}, +${indexLength}) out of bounds`,\n );\n }\n if (indexLength > maxIndexBytes) {\n throw new IntegrityError(`.crbm index ${indexLength}B exceeds cap ${maxIndexBytes}B`);\n }\n\n // Validate the front preamble too, but only when this GET already covers it (no extra request).\n const tailCoversFrom = size - tail.length;\n if (tailCoversFrom === 0) {\n if (!magicMatches(tail, 0) || tail[4] !== versionMajor) {\n throw new IntegrityError('.crbm preamble magic/version mismatch with footer');\n }\n }\n\n // --- Index: already in the tail, or one more GET ---\n let indexBytes: Uint8Array;\n let servedFromTail: boolean;\n if (indexOffset >= tailCoversFrom) {\n const start = indexOffset - tailCoversFrom;\n indexBytes = tail.subarray(start, start + indexLength);\n servedFromTail = true;\n } else {\n indexBytes = await blob.getRange(indexOffset, indexLength);\n servedFromTail = false;\n }\n if (crc32c(indexBytes) !== indexCrc) {\n throw new IntegrityError('.crbm index CRC mismatch');\n }\n\n // Decrypt the index (nonce/tag from the footer) before parsing; AAD binds it to this (segment, generation).\n // A wrong key / tampered index / wrong context fails here as an IntegrityError \u2014 never a wrong parse.\n const indexForParse = encrypted\n ? options.crypto!.aead.open(\n {\n nonce: footer.subarray(FOOTER.indexNonce, FOOTER.indexNonce + AEAD_NONCE_BYTES),\n ciphertext: indexBytes,\n tag: footer.subarray(FOOTER.indexTag, FOOTER.indexTag + AEAD_TAG_BYTES),\n },\n options.crypto!.aadFor('index'),\n )\n : indexBytes;\n\n const { entries, orderedKeys, cardinalitySum } = parseIndex(\n indexForParse,\n size,\n maxPayloadBytes,\n );\n if (encrypted) {\n // Footer count/cardinality are zeroed on an encrypted object; the decrypted index is authoritative (and\n // already AEAD-authenticated, AAD-bound to this object), so derive the total from it.\n if (chunkCount !== 0 || totalCardinality !== 0) {\n throw new IntegrityError(\n '.crbm encrypted footer must zero chunk_count + total_cardinality',\n );\n }\n } else {\n // Cleartext: the footer total + count must match the index \u2014 don't trust the footer blindly.\n if (entries.size !== chunkCount) {\n throw new IntegrityError(\n `.crbm chunk_count ${chunkCount} != ${entries.size} index entries`,\n );\n }\n if (cardinalitySum !== totalCardinality) {\n throw new IntegrityError(\n `.crbm total_cardinality ${totalCardinality} != \u03A3 index cardinality ${cardinalitySum}`,\n );\n }\n }\n\n return new CrbmReader(\n blob,\n size,\n generation,\n options.lineage,\n cardinalitySum,\n entries,\n orderedKeys,\n servedFromTail,\n options.crypto,\n );\n }\n\n /** Chunk keys present in this generation, ascending. */\n chunkKeys(): number[] {\n return this.orderedKeys.slice();\n }\n\n /** Segment cardinality from the footer (no payload reads) \u2014 the cheap `count()` path. */\n count(): number {\n return this.totalCardinality;\n }\n\n has(chunkKey: number): boolean {\n return this.entries.has(chunkKey);\n }\n\n /**\n * Range-GET one chunk's payload, verifying its CRC32C before returning. Returns `null` if the chunk is\n * absent. Throws `IntegrityError` on a CRC mismatch (the bytes must never reach the native\n * deserializer). The returned buffer is a **read-only view** owned by the reader/driver \u2014 callers must\n * not mutate it.\n */\n async getChunk(chunkKey: number): Promise<Uint8Array | null> {\n const e = this.entries.get(chunkKey);\n if (e === undefined) return null;\n // Re-validate bounds at read time (defense in depth \u2014 a buggy caller or future mutable index path).\n if (e.offset < PAYLOAD_START || e.offset + e.length > this.objectSize - FOOTER_BYTES) {\n throw new IntegrityError(`chunk ${chunkKey} payload out of bounds`);\n }\n const bytes = await this.blob.getRange(e.offset, e.length);\n if (crc32c(bytes) !== e.crc32c) {\n throw new IntegrityError(`chunk ${chunkKey} payload CRC mismatch`);\n }\n if (this.crypto === undefined) return bytes;\n // Encrypted: on-disk frame is nonce \u2016 ciphertext \u2016 tag. Decrypt (AAD-bound to this chunkKey) after the CRC\n // passes \u2014 a wrong key / tamper / relocated chunk fails as an IntegrityError, never a wrong payload.\n if (bytes.length < AEAD_NONCE_BYTES + AEAD_TAG_BYTES) {\n throw new IntegrityError(`chunk ${chunkKey} encrypted payload too short`);\n }\n return this.crypto.aead.open(\n {\n nonce: bytes.subarray(0, AEAD_NONCE_BYTES),\n ciphertext: bytes.subarray(AEAD_NONCE_BYTES, bytes.length - AEAD_TAG_BYTES),\n tag: bytes.subarray(bytes.length - AEAD_TAG_BYTES),\n },\n this.crypto.aadFor(chunkKey),\n );\n }\n}\n\n// Exported for the coverage-guided fuzz harness, which fuzzes the hand-written index parser\n// directly on raw bytes \u2014 bypassing the CRC wall that mutational fuzzing can't cross. NOT part of the public\n// API surface (`src/index.ts`); reached only via `src/testing/fuzz-support.ts` \u2192 the gitignored `fuzz/build/`.\nexport function parseIndex(\n indexBytes: Uint8Array,\n objectSize: number,\n maxPayloadBytes: number,\n): { entries: Map<number, CrbmIndexEntry>; orderedKeys: number[]; cardinalitySum: number } {\n const entries = new Map<number, CrbmIndexEntry>();\n const orderedKeys: number[] = [];\n let pos = 0;\n let prevKey = 0;\n let prevEnd = PAYLOAD_START;\n let cardinalitySum = 0;\n\n // Parse entries until the index region is exactly consumed (chunk_count is hidden on encrypted objects, so\n // the byte length is the bound \u2014 readVarint throws on any overrun, so a malformed index fails cleanly).\n for (let i = 0; pos < indexBytes.length; i++) {\n const keyDelta = readVarint(indexBytes, pos);\n const offDelta = readVarint(indexBytes, keyDelta.next);\n const len = readVarint(indexBytes, offDelta.next);\n const card = readVarint(indexBytes, len.next);\n pos = card.next;\n if (pos + CRC32C_BYTES > indexBytes.length) {\n throw new IntegrityError('.crbm index truncated (missing payload CRC)');\n }\n const crc =\n (indexBytes[pos]! |\n (indexBytes[pos + 1]! << 8) |\n (indexBytes[pos + 2]! << 16) |\n (indexBytes[pos + 3]! << 24)) >>>\n 0;\n pos += CRC32C_BYTES;\n\n const chunkKey = prevKey + keyDelta.value;\n const offset = prevEnd + offDelta.value;\n // Unsigned deltas mean keys can only stay flat or rise; a 0 delta after the first is a duplicate.\n if (i > 0 && keyDelta.value === 0) {\n throw new IntegrityError(`.crbm index has a duplicate chunkKey ${chunkKey}`);\n }\n if (chunkKey > 0xffff) throw new IntegrityError(`.crbm chunkKey ${chunkKey} out of range`);\n if (len.value === 0 || len.value > maxPayloadBytes) {\n throw new IntegrityError(`.crbm chunk ${chunkKey} length ${len.value} invalid`);\n }\n if (card.value < 1 || card.value > MAX_CHUNK_CARDINALITY) {\n throw new IntegrityError(`.crbm chunk ${chunkKey} cardinality ${card.value} invalid`);\n }\n if (offset < PAYLOAD_START || offset + len.value > objectSize - FOOTER_BYTES) {\n throw new IntegrityError(`.crbm chunk ${chunkKey} payload out of bounds`);\n }\n\n entries.set(chunkKey, {\n chunkKey,\n offset,\n length: len.value,\n cardinality: card.value,\n crc32c: crc,\n });\n orderedKeys.push(chunkKey);\n cardinalitySum += card.value;\n prevKey = chunkKey;\n prevEnd = offset + len.value;\n }\n // The loop ends only when pos === indexBytes.length exactly (each entry consumes a whole record; a partial\n // trailing record makes readVarint or the CRC bound throw), so there are never unconsumed trailing bytes.\n return { entries, orderedKeys, cardinalitySum };\n}\n", "/**\n * `CrbmWriter` \u2014 streaming, constant-memory writer for one immutable `.crbm` generation.\n *\n * Chunks are appended in **ascending chunkKey order**; the writer holds only the small index in memory\n * (offsets aren't known until payloads are written \u2014 which is exactly why the index is a footer).\n *\n * **Encryption (opt-in via `crypto`).** When a {@link CrbmCrypto} is supplied, each chunk payload is\n * AES-256-GCM-sealed (`nonce \u2016 ciphertext \u2016 tag`, AAD = its chunkKey) and the whole index is sealed too (its\n * nonce/tag go in the footer). The footer then sets `FLAG_ENCRYPTED` and **zeroes `chunkCount` +\n * `totalCardinality`** so a leaked object reveals neither how many chunks nor how many ids it holds \u2014 the\n * reader derives both from the decrypted index. The per-chunk CRC covers the *encrypted* on-disk bytes.\n */\nimport { ValidationError } from '../errors';\nimport type { CrbmCrypto } from '../crypto';\nimport { crc32c } from './crc32c';\nimport { writeVarint } from './varint';\nimport type { BlobSink } from '../blob';\nimport {\n CONTAINER_CODEC_NONE,\n ELEMENT_WIDTH_32,\n FLAG_ENCRYPTED,\n FLAG_LITTLE_ENDIAN,\n FOOTER,\n FOOTER_BYTES,\n FOOTER_CRC_COVERAGE,\n MAGIC,\n MAX_CHUNK_CARDINALITY,\n PAYLOAD_START,\n PREAMBLE_BYTES,\n PAYLOAD_CODEC_ROARING_PORTABLE,\n VERSION_MAJOR,\n VERSION_MINOR,\n} from './format';\n\nexport interface CrbmWriterOptions {\n /** Self-describing generation number (also encoded in the object key). */\n readonly generation: number;\n /**\n * Which codec produced the chunk payloads. Defaults to {@link PAYLOAD_CODEC_ROARING_PORTABLE}.\n *\n * Renamed from `roaringSerializationId` in 0.7.0 \u2014 same footer field, same offset and width, generalized\n * because `.crbm` is a shared container and a second codec is expected before the format freezes.\n */\n readonly payloadCodecId?: number;\n readonly elementWidth?: number;\n /** When set, payloads + index are AES-256-GCM-encrypted, bound to `(segment, generation, scope)` via AAD. */\n readonly crypto?: CrbmCrypto;\n}\n\ninterface IndexEntry {\n readonly chunkKey: number;\n readonly offset: number;\n readonly length: number;\n readonly cardinality: number;\n readonly crc32c: number;\n}\n\nexport class CrbmWriter {\n private readonly entries: IndexEntry[] = [];\n private offset = PAYLOAD_START;\n private lastKey = -1;\n private totalCardinality = 0;\n private preambleWritten = false;\n private finished = false;\n\n constructor(\n private readonly sink: BlobSink,\n private readonly options: CrbmWriterOptions,\n ) {\n if (!Number.isInteger(options.generation) || options.generation < 0) {\n throw new ValidationError(\n `generation must be a non-negative integer; got ${options.generation}`,\n );\n }\n }\n\n /**\n * Append one chunk's payload (the roaring-serialized bytes) with its cardinality. `chunkKey` must be\n * strictly greater than the previous one (ascending, no duplicates); `cardinality` is `[1, 65536]`.\n */\n async addChunk(chunkKey: number, payload: Uint8Array, cardinality: number): Promise<void> {\n if (this.finished) throw new ValidationError('CrbmWriter already finished');\n if (!Number.isInteger(chunkKey) || chunkKey < 0 || chunkKey > 0xffff) {\n throw new ValidationError(`chunkKey must be a u16; got ${chunkKey}`);\n }\n if (chunkKey <= this.lastKey) {\n throw new ValidationError(\n `chunkKey ${chunkKey} not strictly ascending (last ${this.lastKey})`,\n );\n }\n if (!Number.isInteger(cardinality) || cardinality < 1 || cardinality > MAX_CHUNK_CARDINALITY) {\n throw new ValidationError(\n `cardinality must be in [1, ${MAX_CHUNK_CARDINALITY}]; got ${cardinality}`,\n );\n }\n if (payload.length === 0) throw new ValidationError('chunk payload must be non-empty');\n\n await this.ensurePreamble();\n // Encrypt (if configured) to the on-disk bytes; the CRC + index length cover what actually lands on disk.\n const stored = this.options.crypto ? this.sealChunk(chunkKey, payload) : payload;\n await this.sink.write(stored);\n this.entries.push({\n chunkKey,\n offset: this.offset,\n length: stored.length,\n cardinality,\n crc32c: crc32c(stored),\n });\n this.offset += stored.length;\n this.totalCardinality += cardinality;\n this.lastKey = chunkKey;\n }\n\n /** Seal one chunk payload into the on-disk frame `nonce \u2016 ciphertext \u2016 tag`, bound to its chunkKey. */\n private sealChunk(chunkKey: number, payload: Uint8Array): Uint8Array {\n const crypto = this.options.crypto!;\n const sealed = crypto.aead.seal(payload, crypto.aadFor(chunkKey));\n const out = new Uint8Array(sealed.nonce.length + sealed.ciphertext.length + sealed.tag.length);\n out.set(sealed.nonce, 0);\n out.set(sealed.ciphertext, sealed.nonce.length);\n out.set(sealed.tag, sealed.nonce.length + sealed.ciphertext.length);\n return out;\n }\n\n /** Write the index region + the fixed footer. After this the object is complete and immutable. */\n async finish(): Promise<void> {\n if (this.finished) throw new ValidationError('CrbmWriter already finished');\n await this.ensurePreamble();\n\n const indexPlain = this.encodeIndex();\n // Encrypt the index too (its nonce/tag go in the footer); a leaked object then reveals no chunk metadata.\n let indexRegion = indexPlain;\n let indexNonce: Uint8Array | undefined;\n let indexTag: Uint8Array | undefined;\n if (this.options.crypto !== undefined) {\n const sealed = this.options.crypto.aead.seal(indexPlain, this.options.crypto.aadFor('index'));\n indexRegion = sealed.ciphertext;\n indexNonce = sealed.nonce;\n indexTag = sealed.tag;\n }\n const indexOffset = this.offset;\n await this.sink.write(indexRegion);\n this.offset += indexRegion.length;\n\n const footer = this.buildFooter(indexOffset, indexRegion, indexNonce, indexTag);\n await this.sink.write(footer);\n this.finished = true;\n }\n\n private async ensurePreamble(): Promise<void> {\n if (this.preambleWritten) return;\n const preamble = new Uint8Array(PREAMBLE_BYTES);\n preamble.set(MAGIC, 0);\n preamble[4] = VERSION_MAJOR;\n preamble[5] = VERSION_MINOR;\n // bytes 6-7 reserved = 0\n await this.sink.write(preamble);\n this.preambleWritten = true;\n }\n\n private encodeIndex(): Uint8Array {\n const out: number[] = [];\n let prevKey = 0;\n let prevEnd = PAYLOAD_START;\n for (const e of this.entries) {\n writeVarint(out, e.chunkKey - prevKey);\n writeVarint(out, e.offset - prevEnd);\n writeVarint(out, e.length);\n writeVarint(out, e.cardinality);\n // crc32c is high-entropy \u2192 fixed 4-byte LE, not varint.\n out.push(\n e.crc32c & 0xff,\n (e.crc32c >>> 8) & 0xff,\n (e.crc32c >>> 16) & 0xff,\n (e.crc32c >>> 24) & 0xff,\n );\n prevKey = e.chunkKey;\n prevEnd = e.offset + e.length;\n }\n return Uint8Array.from(out);\n }\n\n private buildFooter(\n indexOffset: number,\n indexRegion: Uint8Array,\n indexNonce: Uint8Array | undefined,\n indexTag: Uint8Array | undefined,\n ): Uint8Array {\n const encrypted = this.options.crypto !== undefined;\n const footer = new Uint8Array(FOOTER_BYTES);\n const view = new DataView(footer.buffer);\n view.setBigUint64(FOOTER.indexOffset, BigInt(indexOffset), true);\n view.setBigUint64(FOOTER.indexLength, BigInt(indexRegion.length), true);\n view.setUint32(FOOTER.indexCrc32c, crc32c(indexRegion), true);\n view.setUint32(FOOTER.flags, FLAG_LITTLE_ENDIAN | (encrypted ? FLAG_ENCRYPTED : 0), true);\n view.setUint16(\n FOOTER.payloadCodecId,\n this.options.payloadCodecId ?? PAYLOAD_CODEC_ROARING_PORTABLE,\n true,\n );\n footer[FOOTER.elementWidth] = this.options.elementWidth ?? ELEMENT_WIDTH_32;\n footer[FOOTER.containerCodec] = CONTAINER_CODEC_NONE;\n footer[FOOTER.versionMajor] = VERSION_MAJOR;\n footer[FOOTER.versionMinor] = VERSION_MINOR;\n // When encrypted, the index's AEAD nonce/tag live in these reserved slots; key_id stays zero (the wrapped\n // DEKs live in the registry, not the object). Unencrypted: all crypto fields stay zero.\n if (indexNonce !== undefined) footer.set(indexNonce, FOOTER.indexNonce);\n if (indexTag !== undefined) footer.set(indexTag, FOOTER.indexTag);\n view.setBigUint64(FOOTER.generation, BigInt(this.options.generation), true);\n // Hide chunk count + cardinality on an encrypted object (a leak reveals neither); the reader derives both\n // from the decrypted index. Cleartext objects keep them for the O(1) count()/validation path.\n view.setUint32(FOOTER.chunkCount, encrypted ? 0 : this.entries.length, true);\n view.setBigUint64(FOOTER.totalCardinality, BigInt(encrypted ? 0 : this.totalCardinality), true);\n view.setUint32(FOOTER.footerCrc32c, crc32c(footer.subarray(0, FOOTER_CRC_COVERAGE)), true);\n footer.set(MAGIC, FOOTER.endMagic);\n return footer;\n }\n}\n", "/**\n * Bridges the `.crbm` archive format to the engine's Storage seam.\n *\n * `CrbmStorageChunkSource` implements the {@link StorageChunkSource} the engine reads through, over an\n * {@link IStorageDriver}: it resolves a segment's current generation, opens its {@link CrbmReader} once, and serves\n * per-chunk payloads. `writeCrbmGeneration` / `writeCrbmGenerationStream` are the write primitives (a generation\n * built from bitmaps, in memory or streamed), `bulkLoadCrbmGeneration` is the load path over them, and\n * `publishGeneration` is the forward-only pointer advance every write ends with.\n */\nimport { type IAuditSink, NOOP_AUDIT, safeAudit } from './audit';\nimport {\n IntegrityError,\n CapabilityError,\n KeyUnavailableError,\n ValidationError,\n WriteConflictError,\n isNotFoundError,\n isWriteConflictError,\n} from './errors';\nimport type { BlobReader } from './blob';\nimport { yieldEvery } from './cooperative';\nimport type { Yielder } from './cooperative';\nimport type { Clock } from './determinism';\nimport { BoundedLru } from './lru';\nimport { splitId } from './bit-route';\nimport { segmentKey } from './keys';\nimport { aadFor } from './crypto';\nimport type { CrbmCrypto, IKeystore, WrappedDek } from './crypto';\nimport { validateChunkRef, validateSegmentRef } from './validate';\nimport type {\n ChunkRef,\n StorageChunkSource,\n GenKey,\n IStorageDriver,\n IRegistryDriver,\n SegmentRef,\n SegmentSize,\n Token,\n} from './ports';\nimport { CrbmReader } from './crbm/reader';\nimport type { CrbmReaderOptions } from './crbm/reader';\nimport { CrbmWriter } from './crbm/writer';\nimport type { CodecBitmap, CodecInterface } from './codec';\nimport { requireCodec } from './codec';\n\nexport interface CrbmStorageChunkSourceOptions extends CrbmReaderOptions {\n /**\n * Optional {@link IRegistryDriver}. When provided, the current generation is resolved via the registry's\n * authoritative `currentGen` (one cheap strong read) instead of a `list` scan of every generation \u2014 the\n * retirement of that scan. When absent, the source falls back to the `list`-scan (so the\n * in-memory / simple setups keep working with no registry). The resolved generation is cached and\n * **re-resolved on a short TTL** ({@link currentGenTtlMs}, needs a {@link clock}) so a long-lived source\n * observes a load's new generation within the TTL instead of pinning one generation forever.\n */\n readonly registry?: IRegistryDriver;\n /**\n * Optional {@link IKeystore} for reading **encrypted** segments. When a segment's registry record\n * carries wrapped DEK(s), the source unwraps the DEK via this keystore and decrypts each chunk/index. Reading\n * an encrypted segment without a keystore throws {@link KeyUnavailableError}; cleartext segments ignore it.\n * Requires a `registry` (that's where the wrapped DEKs live).\n */\n readonly keystore?: IKeystore;\n /**\n * Enforce that every segment read is encrypted. When true, resolving a **cleartext** segment (no\n * wrapped DEKs) throws {@link KeyUnavailableError} \u2014 a guard against silently reading a segment that should\n * have been encrypted. Off by default (encryption is opt-in).\n */\n readonly requireEncryption?: boolean;\n /**\n * Time source for the current-generation TTL refresh \u2014 the determinism seam; `core/` never reads\n * ambient time. Refresh needs **both** a clock and a `registry`; without either the source **pins** the\n * first-resolved generation for its lifetime (the behaviour before the registry was wired in). The `CloudRoaring` facade passes its\n * clock automatically, so wiring a `registry` is enough to get live cross-generation invalidation.\n */\n readonly clock?: Pick<Clock, 'now'>;\n /**\n * How long (ms) a resolved `currentGen` is trusted before the next read re-resolves it (default 2000) \u2014 the\n * bound on read staleness after a load publishes: a reader may serve the prior generation for up to this long,\n * then converges. Lazy (checked on read \u2014 no timer); \u2264 one cheap registry read per segment per window, and a\n * new {@link CrbmReader} is opened only when the generation actually changed. `0` (or no clock) \u21D2 pin forever.\n */\n readonly currentGenTtlMs?: number;\n /**\n * Hard ceiling on how many segments' readers (each holding a fully-parsed `.crbm` index) are cached at once\n * (default 1024) \u2014 a memory bound for a long-running server. Past it, the least-recently-used\n * segment's reader is evicted; the next read of an evicted segment re-opens it (one cheap tail GET, since\n * generations are immutable). Raise it for a big cache working set of small segments.\n */\n readonly maxOpenSegments?: number;\n /**\n * Aggregate byte ceiling on the parsed `.crbm` indices resident in the reader cache (default 64 MiB) \u2014 the\n * **second half of that memory bound**. `maxOpenSegments` alone bounds by *count*, but a wide/dense segment's\n * parsed index can be several MB, so 1024 wide indices could pin ~GBs and blow a small heap (e.g. a 128 MB\n * Lambda) while the count is nominally \"in bounds\". This caps the summed {@link CrbmReader.retainedIndexBytes}\n * across cached readers; the least-recently-used reader is evicted once the total would exceed it \u2014 whichever\n * of the count/byte bounds binds first. Lower it for memory-tight deployments with wide segments; a single\n * segment whose index alone exceeds the budget is still cached (it can't be shrunk) but nothing else alongside.\n */\n readonly maxOpenIndexBytes?: number;\n}\n\n/** Adapt one `(driver, key)` pair to the codec's `BlobReader` seam. */\nfunction storageBlobReader(driver: IStorageDriver, key: GenKey): BlobReader {\n return {\n getRange(offset, length) {\n return driver.getRange(key, offset, length);\n },\n getTail(maxBytes) {\n return driver.getTail(key, maxBytes);\n },\n };\n}\n\n/** The generation target `resolveTarget` produces: which generation is current + its DEK wrappings (if encrypted). */\n/**\n * A resolved read target. `lineage` is the registry row's OCC token \u2014 the identity that survives a delete,\n * because `IRegistryDriver.delete` tombstones rather than unlinks (\"a later `create` still gets a fresh,\n * greater token\"). It is what separates two *incarnations* of one name, which a generation number cannot:\n * `nextGeneration` restarts at 0 once the row is purged and the bucket emptied, so a retired-and-re-created\n * segment presents different data at the same `currentGen`. Undefined for a registry-less source, which has no\n * row and therefore no incarnation to confuse.\n */\ntype Target = { generation: number; lineage?: Token; wrappedDeks?: readonly WrappedDek[] };\n\n/** A memoized per-segment reader plus the time it was installed, for the current-generation TTL refresh. */\ninterface Snapshot {\n readonly reader: Promise<CrbmReader | null>;\n readonly installedAtMs: number;\n}\n\n/** Default TTL (ms) for re-resolving a segment's `currentGen` \u2014 the bound on post-publish read staleness. */\nconst DEFAULT_CURRENT_GEN_TTL_MS = 2000;\n/**\n * How many buffered remainders bulk-load holds before flushing them into their chunk bitmaps. Bounds the\n * transient JS-side buffer to **~28 MB measured** irrespective of input size, while keeping batches large\n * enough that the per-id JS\u2194native crossing is amortised away.\n */\nconst BULK_FLUSH_IDS = 1 << 20;\n/**\n * Ids between ingest-loop yields. 16x coarser than the per-chunk cadence because the per-id work is ~40 ns\n * (a `splitId` and an array push) against ~1.3 \u00B5s per chunk \u2014 matching cadences would put the yield cost on the\n * wrong side of the work it interrupts. Sized against the *slowest* ingest, an in-memory async generator at\n * ~220 ns/id, so the resulting stretch stays a few ms there and well under 1 ms on a plain array.\n */\nconst YIELD_EVERY_IDS = 1 << 14;\n\n/** Default ceiling on cached segment readers (each holds a parsed `.crbm` index) \u2014 the steady-state count bound. */\nconst DEFAULT_MAX_OPEN_SEGMENTS = 1024;\n\n/** Default aggregate ceiling (bytes) on resident parsed indices in the reader cache \u2014 the steady-state byte bound. */\nconst DEFAULT_MAX_OPEN_INDEX_BYTES = 64 * 1024 * 1024;\n\nexport class CrbmStorageChunkSource implements StorageChunkSource {\n /**\n * One resolved reader per segment, re-resolved on a short TTL ({@link CrbmStorageChunkSourceOptions.currentGenTtlMs},\n * needs a clock). Within the TTL a segment's Storage bytes are treated as an immutable snapshot; when the TTL\n * elapses the next read cheaply re-resolves `currentGen` and, only if it advanced (a load published),\n * opens the new generation \u2014 so a long-lived source observes new generations within the TTL rather than\n * pinning one forever. The engine pairs this with a **generation-keyed** cache so a bump never\n * serves a stale decoded chunk. Without a clock or a registry the source pins the first generation for its\n * lifetime (the behaviour before the registry was wired in). A segment with no generation yet is not memoized, so it's re-checked until\n * one exists. **Bounded** by a {@link BoundedLru} ({@link CrbmStorageChunkSourceOptions.maxOpenSegments}, default\n * 1024): past the ceiling the least-recently-used segment's reader (and its parsed index) is evicted \u2014 the\n * steady-state memory bound; re-opening an evicted segment is one cheap tail GET.\n */\n private readonly snapshots: BoundedLru<string, Snapshot>;\n private readonly registry: IRegistryDriver | undefined;\n private readonly keystore: IKeystore | undefined;\n private readonly requireEncryption: boolean;\n private readonly readerOptions: CrbmReaderOptions;\n private readonly clock: Pick<Clock, 'now'> | undefined;\n private readonly currentGenTtlMs: number;\n\n constructor(\n private readonly driver: IStorageDriver,\n options: CrbmStorageChunkSourceOptions = {},\n ) {\n if (!driver.capabilities().rangeRead) {\n throw new CapabilityError('Storage driver must support range reads (rangeRead)');\n }\n const {\n registry,\n keystore,\n requireEncryption,\n clock,\n currentGenTtlMs,\n maxOpenSegments,\n maxOpenIndexBytes,\n ...readerOptions\n } = options;\n if (keystore !== undefined && registry === undefined) {\n throw new CapabilityError(\n 'a keystore needs a storage backend \u2014 that is where the wrapped DEKs live. A bare IStorageDriver has no registry to hold them',\n );\n }\n if (requireEncryption === true && registry === undefined) {\n // Without a registry the source can't see wrapped DEKs or `destroyed` tombstones (it list-scans storage),\n // so encryption can't be enforced or even observed here \u2014 fail fast rather than mislead.\n throw new CapabilityError('requireEncryption needs a registry');\n }\n this.registry = registry;\n this.keystore = keystore;\n this.requireEncryption = requireEncryption ?? false;\n this.readerOptions = readerOptions;\n this.clock = clock;\n this.currentGenTtlMs = currentGenTtlMs ?? DEFAULT_CURRENT_GEN_TTL_MS;\n // Bound the reader cache by BOTH count and aggregate parsed-index bytes. No TTL on the LRU itself \u2014\n // the currentGen TTL is handled separately via each snapshot's `installedAtMs`; these ceilings only bound how\n // many segment readers/indices stay resident. Each reader's byte weight is reported once it resolves (below).\n // The cache never compares against wall-clock, so a zero clock is fine when none is injected.\n this.snapshots = new BoundedLru<string, Snapshot>({\n maxEntries: maxOpenSegments ?? DEFAULT_MAX_OPEN_SEGMENTS,\n maxBytes: maxOpenIndexBytes ?? DEFAULT_MAX_OPEN_INDEX_BYTES,\n clock: clock ?? { now: () => 0 },\n });\n }\n\n /** The current resolved reader for a segment, refreshing on the TTL. Cheap within the TTL window. */\n private resolvedReader(ref: SegmentRef): Promise<CrbmReader | null> {\n const key = segmentKey(ref);\n const existing = this.snapshots.get(key);\n if (existing === undefined) return this.install(key, this.resolveLatest(ref)).reader;\n if (!this.expired(existing.installedAtMs)) return existing.reader;\n // Expired: install the in-flight refresh **synchronously** (before any await) so concurrent readers in this\n // window coalesce onto the one re-resolve \u2014 \u2264 one registry read + at most one reopen per segment per window\n // (no boundary thundering-herd). computeRefreshedReader reuses the prior reader unless the generation moved.\n return this.install(key, this.computeRefreshedReader(ref, existing)).reader;\n }\n\n /** TTL elapsed: cheaply re-resolve `currentGen`; reopen only if it actually changed, else reuse the prior reader. */\n private async computeRefreshedReader(\n ref: SegmentRef,\n existing: Snapshot,\n ): Promise<CrbmReader | null> {\n const current = await existing.reader.catch(() => null);\n let target: Target | null | undefined;\n try {\n target = await this.resolveTarget(ref);\n } catch {\n target = undefined; // transient resolve fault\n }\n // Transient resolve fault: keep serving the prior reader if it's alive; if it's dead (null/failed open),\n // reopen rather than re-arm a dead snapshot (else the segment reads empty for a whole TTL window).\n if (target === undefined) return current ?? this.resolveLatest(ref);\n if (target === null) return null; // segment gone / destroyed\n // Reuse only when BOTH the generation and the row match. Comparing the number alone treated a\n // retired-and-re-created name as unchanged \u2014 `nextGeneration` restarts at 0, so incarnation 2's generation 0\n // is indistinguishable from the reader already open \u2014 and the snapshot was never refreshed, so the store\n // kept serving a deleted segment's ids. A token that moved for an unrelated row write costs one reopen.\n if (\n current !== null &&\n target.generation === current.generation &&\n target.lineage === current.lineage\n ) {\n return current; // unchanged \u2014 reuse\n }\n return this.openForTarget(ref, target); // advanced / appeared / prior open was dead \u2014 reopen fresh\n }\n\n /**\n * Memoize a reader-promise as the segment's snapshot at `now()`, forgetting it later if it resolves to\n * null / throws (identity-guarded, so a stale cleanup never clobbers a fresher snapshot). Installing the\n * (pending) promise **synchronously** is what lets concurrent callers coalesce onto one in-flight resolve.\n */\n private install(key: string, reader: Promise<CrbmReader | null>): Snapshot {\n const snap: Snapshot = { reader, installedAtMs: this.now() };\n this.snapshots.set(key, snap);\n const forgetIfStale = (): void => {\n if (this.snapshots.get(key) === snap) this.snapshots.delete(key);\n };\n reader.then((r) => {\n if (r === null) {\n forgetIfStale();\n return;\n }\n // Report the parsed index's footprint so the cache can bound aggregate resident bytes. Identity-\n // guarded via `peek` (no recency change) so a since-replaced snapshot doesn't mis-weight the fresh entry.\n if (this.snapshots.peek(key) === snap) this.snapshots.setWeight(key, r.retainedIndexBytes);\n }, forgetIfStale);\n return snap;\n }\n\n private now(): number {\n return this.clock ? this.clock.now() : 0;\n }\n\n private expired(installedAtMs: number): boolean {\n // Refresh needs a clock (the TTL) AND a registry (the *cheap* `currentGen` read the design assumes \u2014\n // without one, re-resolution is a full storage `list`-scan, and a registry-less setup is single-process\n // local, not the shared bucket that separate loaders publish into). Otherwise: pin for the lifetime.\n return (\n this.clock !== undefined &&\n this.registry !== undefined &&\n this.currentGenTtlMs > 0 &&\n this.clock.now() - installedAtMs >= this.currentGenTtlMs\n );\n }\n\n /**\n * The segment's current generation number \u2014 the engine keys its chunk cache by this so a generation bump\n * is observed instead of serving a stale decoded chunk. Served from the (TTL-refreshed)\n * snapshot, so no extra backend read within the TTL window. `null` if the segment has no committed generation.\n *\n * Heals a swept generation exactly like {@link withFreshSnapshot} \u2014 the engine calls this **once per op**,\n * before any chunk fetch, so an unhealed miss here fails the whole operation rather than one chunk. It is\n * spelled out rather than delegated because this is the hottest call in the library: once per operand of\n * every `has`/`count`/`iterate`/`intersect`, and almost always served from the cached snapshot with no\n * backend call at all. Routing it through the generic helper cost ~115 ns/op on that path (a second async\n * frame, a per-call closure, and an `await` on a plain number) for a race that fires only during a\n * concurrent sweep. One retry, then propagate \u2014 same contract, same eviction rule.\n */\n async currentGeneration(ref: SegmentRef): Promise<number | null> {\n const pending = this.resolvedReader(ref);\n try {\n return (await pending)?.generation ?? null;\n } catch (err) {\n if (!isNotFoundError(err)) throw err;\n this.dropStale(segmentKey(ref), pending);\n return (await this.resolvedReader(ref))?.generation ?? null; // a second miss propagates\n }\n }\n\n /**\n * Forget everything derived from `ref`: the resolved snapshot and the open reader behind it (and with the\n * reader, the DEK it unwrapped at open time). The next read resolves `currentGen` from the registry again.\n *\n * Needed because the TTL refresh only ever answers \"has the pointer moved?\", and every *destructive* verb \u2014\n * an erasure that deletes the generation holding the bit, a `dropSegment`, a crypto-shred, a retirement \u2014\n * leaves the pointer's answer unchanged from this source's point of view while making the snapshot wrong.\n * Until this is called the source keeps serving that snapshot with no backend read at all, so nothing on the\n * storage side can close the window; with `cache.genTtlMs: 0` or no clock it never closes.\n */\n invalidate(ref: SegmentRef): void {\n const key = segmentKey(ref);\n this.snapshots.delete(key);\n // \u2026and every PINNED reader of the same segment, which is memoized under `<key>@<generation>`. Dropping\n // only the live entry left a pinned handle reading a crypto-shredded segment: the pin is exactly the\n // reader that does not re-resolve on its own, so it is the one that most needs to be told.\n const pinnedPrefix = `${key}@`;\n this.snapshots.deleteWhere((k) => k.startsWith(pinnedPrefix));\n }\n\n /**\n * Whether the segment is a registered name at all. With a registry that is exactly \"a row exists\" \u2014 including\n * a row with no generation yet (minted by `setRetention` before the first load) and a `destroyed` tombstone,\n * both of which are names somebody deliberately created. Without a registry there is no registration to\n * consult, so the honest answer is whether the bucket holds any generation of it.\n *\n * Deliberately NOT served from the snapshot memo: the memo resolves to `null` for both states this exists to\n * tell apart.\n */\n /**\n * `<generation>` for a registry-less source (no row, so no incarnation to confuse), or\n * `<generation>:<row token>` with one. The token moves on every row write, so an unrelated write (a\n * `setRetention`) costs the segment's decoded chunks once \u2014 bounded, and on an admin path. Exactness in the\n * direction that matters: two incarnations can never share a version string.\n */\n async currentVersion(ref: SegmentRef): Promise<string | null> {\n const reader = await this.resolvedReader(ref);\n if (reader === null) return null;\n return reader.lineage === undefined\n ? String(reader.generation)\n : `${reader.generation}:${String(reader.lineage)}`;\n }\n\n /**\n * Resolve the segment **once** and report what a pin should hold: the generation, and the version that\n * identifies those exact bytes. `null` when the segment resolves to no generation \u2014 there is nothing to pin,\n * and a caller must treat that as \"this handle reads empty\", not \"pinning is unsupported here\".\n */\n async pinGeneration(ref: SegmentRef): Promise<{ generation: number; version: string } | null> {\n // Resolved FRESH, not through the snapshot memo. \"The generation current right now\" is the whole promise\n // of a pin, and the memo is allowed to be up to `cache.genTtlMs` behind \u2014 or, on a store with no clock,\n // arbitrarily far behind, since it never refreshes at all. Pinning through it made every pin on such a\n // store return the first generation that store had ever read.\n const target = await this.resolveTarget(ref);\n if (target === null) return null;\n const version =\n target.lineage === undefined\n ? String(target.generation)\n : `${target.generation}:${String(target.lineage)}`;\n return { generation: target.generation, version };\n }\n\n /**\n * A reader for one **specific** generation, memoized in the same bounded LRU as the live snapshots under a\n * generation-qualified key.\n *\n * Sharing the LRU is the point, not an implementation detail. A pinned reader held in a private field is\n * outside the memory ceiling the library advertises \u2014 measured at 10.34 MiB per live pin, 32 pins holding\n * 111.7 MiB against an 8 MiB configured bound. A pinned *generation number* has no such problem: the\n * generation is immutable, so eviction is harmless and re-opening at the same number reproduces the same\n * bytes. It also removes a memoized-rejection bug by construction \u2014 `install` forgets a promise that rejects,\n * where a hand-rolled `this.reader ??= open()` cached the rejection for the life of the handle and made a pin\n * the one read path with no resilience.\n *\n * **`status` is re-checked here**, on every open rather than once at pin time. A pin taken before a\n * crypto-shred must not keep unwrapping a DEK the shred destroyed; a destroyed segment resolves no generation\n * for anyone, pinned or not.\n */\n private async readerAt(ref: SegmentRef, generation: number): Promise<CrbmReader | null> {\n const key = `${segmentKey(ref)}@${generation}`;\n const existing = this.snapshots.get(key);\n if (existing !== undefined) return existing.reader;\n return this.install(key, this.openAt(ref, generation)).reader;\n }\n\n private async openAt(ref: SegmentRef, generation: number): Promise<CrbmReader | null> {\n let lineage: Token | undefined;\n if (this.registry !== undefined) {\n const record = await this.registry.get(ref);\n // Re-checked at open, not captured at pin: a shred between the two must be observed. A row that has gone\n // takes its key material with it, so there is nothing left to read under any generation.\n if (record === null || record.status === 'destroyed') return null;\n lineage = record.token;\n }\n return this.openForTarget(ref, { generation, lineage, wrappedDeks: await this.deksFor(ref) });\n }\n\n /** The row's current key wrappings, for opening a pinned generation. */\n private async deksFor(ref: SegmentRef): Promise<readonly WrappedDek[] | undefined> {\n if (this.registry === undefined) return undefined;\n return (await this.registry.get(ref))?.wrappedDeks;\n }\n\n /** Read one chunk of a specific generation \u2014 the pinned read path. */\n async getChunkAt(ref: ChunkRef, generation: number): Promise<Uint8Array | null> {\n validateSegmentRef(ref);\n const reader = await this.readerAt(ref, generation);\n return reader === null ? null : reader.getChunk(ref.chunkKey);\n }\n\n /** Chunk keys of a specific generation \u2014 the pinned shape read. */\n async listChunkKeysAt(ref: SegmentRef, generation: number): Promise<number[]> {\n validateSegmentRef(ref);\n const reader = await this.readerAt(ref, generation);\n return reader === null ? [] : reader.chunkKeys();\n }\n\n /** Per-chunk cardinalities of a specific generation \u2014 powers a pinned `count()` with no payload reads. */\n async cardinalitiesAt(\n ref: SegmentRef,\n generation: number,\n ): Promise<ReadonlyMap<number, number> | null> {\n validateSegmentRef(ref);\n const reader = await this.readerAt(ref, generation);\n return reader === null ? null : reader.cardinalities();\n }\n\n /** Grounded size of a specific generation. */\n async sizeOfAt(ref: SegmentRef, generation: number): Promise<SegmentSize | null> {\n validateSegmentRef(ref);\n const reader = await this.readerAt(ref, generation);\n return reader === null ? null : { sizeBytes: reader.sizeBytes };\n }\n\n async exists(ref: SegmentRef): Promise<boolean> {\n if (this.registry !== undefined) return (await this.registry.get(ref)) !== null;\n for await (const key of this.driver.list(ref)) {\n void key;\n return true;\n }\n return false;\n }\n\n /**\n * Evict a snapshot we just failed to read from \u2014 matched by its reader *promise*, so a concurrent call's\n * fresher snapshot is never clobbered. The identity guard is the whole point: `install` replaces the entry\n * wholesale, so comparing anything else would drop a good snapshot on the floor.\n */\n private dropStale(key: string, pending: Promise<CrbmReader | null>): void {\n const cur = this.snapshots.get(key);\n if (cur !== undefined && cur.reader === pending) this.snapshots.delete(key);\n }\n\n private async resolveLatest(ref: SegmentRef): Promise<CrbmReader | null> {\n const target = await this.resolveTarget(ref);\n if (target === null) return null;\n return this.openForTarget(ref, target);\n }\n\n /** Open a {@link CrbmReader} for an already-resolved generation target (decrypting if the segment is encrypted). */\n private async openForTarget(ref: SegmentRef, target: Target): Promise<CrbmReader | null> {\n const genKey: GenKey = {\n namespace: ref.namespace,\n segment: ref.segment,\n generation: target.generation,\n };\n const crypto = await this.cryptoForRead(ref, target.generation, target.wrappedDeks);\n return CrbmReader.open(storageBlobReader(this.driver, genKey), {\n ...this.readerOptions,\n crypto,\n lineage: target.lineage,\n });\n }\n\n /**\n * The current generation + its DEK wrappings: the registry's authoritative record (one strong read), or a\n * `list` scan for the max generation when there's no registry (a registry-less source can only read cleartext\n * \u2014 there's nowhere a wrapped DEK could live).\n */\n private async resolveTarget(ref: SegmentRef): Promise<Target | null> {\n if (this.registry !== undefined) {\n const record = await this.registry.get(ref);\n if (record === null) return null;\n // A crypto-shredded segment reads as empty \u2014 its DEK is gone, so its Storage bytes are unrecoverable.\n if (record.status === 'destroyed') return null;\n // A row with no Storage generation yet (minted by `setSegmentRetention` ahead of the first load, so admin tools\n // can see the segment) resolves exactly like a segment with NO row: every read answers empty. Returning\n // `null` here rather than a generation is the whole reason such a row is safe to create \u2014 the alternative,\n // pointing at a generation that does not exist, is the `missing-storage-generation` state.\n if (record.currentGen === null) return null;\n return {\n generation: record.currentGen,\n lineage: record.token,\n wrappedDeks: record.wrappedDeks,\n };\n }\n let maxGen = -1;\n for await (const key of this.driver.list(ref)) {\n if (key.generation > maxGen) maxGen = key.generation;\n }\n return maxGen < 0 ? null : { generation: maxGen };\n }\n\n /** Build the per-generation decryption context for an encrypted segment (undefined for cleartext). */\n private async cryptoForRead(\n ref: SegmentRef,\n generation: number,\n wrappedDeks: readonly WrappedDek[] | undefined,\n ): Promise<CrbmCrypto | undefined> {\n if (wrappedDeks === undefined || wrappedDeks.length === 0) {\n if (this.requireEncryption) {\n throw new KeyUnavailableError(\n `requireEncryption: segment \"${ref.segment}\" is cleartext but encryption is required`,\n );\n }\n return undefined; // cleartext segment\n }\n if (this.keystore === undefined) {\n throw new KeyUnavailableError(\n `segment \"${ref.segment}\" is encrypted but this CrbmStorageChunkSource has no keystore`,\n );\n }\n const aead = await this.keystore.openDek(wrappedDeks);\n return { aead, aadFor: (scope) => aadFor(ref, generation, scope) };\n }\n\n async getChunk(ref: ChunkRef): Promise<Uint8Array | null> {\n validateChunkRef(ref);\n return this.withFreshSnapshot(ref, (reader) => reader.getChunk(ref.chunkKey), null);\n }\n\n async listChunkKeys(ref: SegmentRef): Promise<number[]> {\n validateSegmentRef(ref);\n return this.withFreshSnapshot(ref, (reader) => reader.chunkKeys(), []);\n }\n\n async sizeOf(ref: SegmentRef): Promise<SegmentSize | null> {\n validateSegmentRef(ref);\n return this.withFreshSnapshot<SegmentSize | null>(\n ref,\n (reader) => ({ sizeBytes: reader.sizeBytes }),\n null,\n );\n }\n\n async cardinalities(ref: SegmentRef): Promise<ReadonlyMap<number, number> | null> {\n validateSegmentRef(ref);\n return this.withFreshSnapshot<ReadonlyMap<number, number> | null>(\n ref,\n (reader) => reader.cardinalities(),\n null,\n );\n }\n\n /**\n * Run `read` against the pinned snapshot, healing the torn-read window generation GC can open: if the\n * generation we resolved was superseded *and* swept (the grace window elapsed), the Storage driver throws\n * {@link NotFoundError}. Surfacing that as a query failure would turn a benign, recoverable race into a\n * caller-visible error, so instead we drop the stale snapshot,\n * re-resolve `currentGen`, and retry once \u2014 the read then serves the newer (committed, immutable) generation,\n * a monotonic move forward \u2014 within one incarnation of the row. A name that was retired and re-created is a\n * different segment and can resolve to a LOWER generation, which is why the snapshot carries the row's token\n * as its lineage rather than trusting the generation number (invariant 1).\n *\n * **Resolution and open are inside the retry, not before it.** Resolving `currentGen` and opening that\n * generation's object are two backend round trips with a gap between them, so the object can be swept after\n * the registry named it and before its tail is read \u2014 and that miss surfaces from awaiting the snapshot, not\n * from `read`. Awaiting outside the retry left the *first* attempt unhealed on the one path GC actually\n * races: `keep: 0`, which every id erasure passes, sweeps microseconds after the publish.\n *\n * A *second* NotFound is pathological (GC outrunning resolution) and propagates rather than fabricating an\n * absent answer \u2014 never return a wrong result. `ifGone` is returned when the segment has no committed\n * generation to serve: storage is empty, or the row was dropped or crypto-shredded, in which case reading empty\n * is the documented outcome rather than a failure.\n *\n * **Bounded to exactly two resolve-and-open round trips.** That is a cost contract, not a detail: the retry\n * now re-reads the *registry*, so an unbounded one would hammer the shared, throttle-prone resource in a\n * tight loop on a segment whose pointer names an object that is permanently absent \u2014 and an N-way\n * `intersect` would do it N times. Gated in `tests/core/storage-source-heal-open.test.ts` by counting calls.\n */\n private async withFreshSnapshot<T>(\n ref: SegmentRef,\n read: (reader: CrbmReader) => T | Promise<T>,\n ifGone: T,\n ): Promise<T> {\n for (let attempt = 0; attempt < 2; attempt++) {\n const pending = this.resolvedReader(ref);\n try {\n const reader = await pending;\n if (reader === null) return ifGone;\n return await read(reader);\n } catch (err) {\n // Only a vanished pinned generation is recoverable here, and only on the first try; anything else\n // (corruption, a real second miss) propagates / falls through.\n if (!isNotFoundError(err) || attempt === 1) throw err;\n this.dropStale(segmentKey(ref), pending); // lazily: the happy path never needs the key\n }\n }\n return ifGone;\n }\n}\n\n/**\n * Write one immutable generation from in-memory bitmaps (the seed / bulk-load primitive). Chunks are\n * sorted ascending and empty bitmaps skipped (empty chunks are never stored). Returns the driver's\n * `{ size, sha256 }` for the written object. Pass `options.crypto` to AES-256-GCM-encrypt the generation\n * (built from the segment's DEK, with associated data bound to `(segment, generation)`).\n */\nexport function writeCrbmGeneration(\n driver: IStorageDriver,\n key: GenKey,\n chunks: Iterable<{ chunkKey: number; bitmap: CodecBitmap }>,\n options: { crypto?: CrbmCrypto; clock?: Yielder } = {},\n): Promise<{ size: number; sha256: string }> {\n const sorted = [...chunks].sort((a, b) => a.chunkKey - b.chunkKey);\n // The single longest blocking stretch in a bulk load: serialize + CRC32C + frame, once per chunk, ~62,000\n // times. `await writer.addChunk(...)` looks like it yields and does not \u2014 the sink buffers in memory, so the\n // promise is already resolved and awaiting it is a microtask. See {@link yieldEvery}.\n const tick = yieldEvery(options.clock);\n return driver.putImmutable(key, async (sink) => {\n const writer = new CrbmWriter(sink, { generation: key.generation, crypto: options.crypto });\n for (const { chunkKey, bitmap } of sorted) {\n if (bitmap.isEmpty) continue;\n // Run-encode before serializing. Storage generations are immutable and read many times, so the one-off cost\n // here buys every later read a smaller fetch \u2014 see CodecBitmap.optimize for the measured factors.\n bitmap.optimize?.();\n await writer.addChunk(chunkKey, bitmap.serialize(), bitmap.size);\n const pause = tick();\n if (pause !== null) await pause;\n }\n await writer.finish();\n });\n}\n\n/** What {@link writeCrbmGenerationStream} wrote: the driver's `{ size, sha256 }` + a tally of the generation. */\nexport interface StreamWriteResult {\n readonly size: number;\n readonly sha256: string;\n /** Non-empty chunk keys written, in ascending order (for the post-write verify, since the stream is consumed). */\n readonly chunkKeys: number[];\n /** Total ids written. */\n readonly cardinality: number;\n}\n\n/**\n * Streaming variant of {@link writeCrbmGeneration} for a **constant-memory** rewrite (the erasure rewrite, a\n * sorted load): consumes an **already-ascending** async stream of `{ chunkKey, bitmap }`, feeding each to the\n * codec and freeing it, instead of materializing the whole generation. Paired with a streaming storage sink (S3\n * multipart / LocalFs temp file), peak memory is ~one chunk + one part. Returns a tally so the caller can verify\n * the re-opened object without re-iterating the (now-consumed) stream. Input **must** be ascending by `chunkKey`\n * \u2014 the codec rejects an out-of-order chunk; empty bitmaps are skipped.\n */\nexport async function writeCrbmGenerationStream(\n driver: IStorageDriver,\n key: GenKey,\n chunks: AsyncIterable<{ chunkKey: number; bitmap: CodecBitmap }>,\n options: { crypto?: CrbmCrypto; clock?: Yielder } = {},\n): Promise<StreamWriteResult> {\n const chunkKeys: number[] = [];\n let cardinality = 0;\n // A rewrite runs this over a whole segment. The `for await` is not itself a yield \u2014 a stream backed by\n // already-resident chunks resolves on a microtask \u2014 so it needs the same periodic macrotask as the\n // non-streaming writer above.\n const tick = yieldEvery(options.clock);\n const { size, sha256 } = await driver.putImmutable(key, async (sink) => {\n const writer = new CrbmWriter(sink, { generation: key.generation, crypto: options.crypto });\n for await (const { chunkKey, bitmap } of chunks) {\n if (bitmap.isEmpty) continue;\n bitmap.optimize?.(); // same storage-write rationale as the non-streaming writer above\n await writer.addChunk(chunkKey, bitmap.serialize(), bitmap.size);\n chunkKeys.push(chunkKey);\n cardinality += bitmap.size;\n const pause = tick();\n if (pause !== null) await pause;\n }\n await writer.finish();\n });\n return { size, sha256, chunkKeys, cardinality };\n}\n\n/**\n * Point a segment's registry `currentGen` at `key.generation` \u2014 the publish step that makes a freshly-written\n * generation the authoritative latest (so registry-aware readers see it). **Forward-only and idempotent:**\n * if the registry has no row it creates one; if it's already at/ahead of `key.generation` it's a no-op (an\n * out-of-order/duplicate publish never regresses the pointer); otherwise it advances via compare-and-swap,\n * retrying a few times under contention. Separated from the Storage write so callers can publish atomically\n * after the immutable object is durable (write-then-publish).\n *\n * **Throws** rather than returning, in two cases, because each would otherwise create a state no reader can\n * recover from: a `destroyed` (crypto-shredded) row, where advancing the pointer would name an object encrypted\n * under a shredded key; and an advance carrying **new** `wrappedDeks`, which would either strand that key or make\n * the row advertise encryption over cleartext generations. Contention that never clears throws\n * {@link WriteConflictError} after the retries.\n *\n * **`expectFrom` turns forward-only into read-modify-write.** Forward-only is the right rule for a writer whose\n * content does not depend on what was current \u2014 a load computes its ids upstream, so publishing over a newer\n * generation loses nothing the loader knew about. It is the WRONG rule for a writer that *derived* its content\n * from a particular generation: the erasure rewrite streams generation `from` and clears one bit, so publishing\n * it over a newer generation silently discards whatever that generation added. Passing `expectFrom` makes the\n * publish land only while the pointer is still exactly there, and return `false` otherwise, so the caller can\n * report `superseded` and re-derive. The compare-and-swap itself carries the token read in the same iteration,\n * so the check and the write see the same row.\n *\n * **`expectToken` fences the LINEAGE, and a derived writer needs both.** A generation number identifies a\n * generation only within one incarnation of a name: `nextGeneration` restarts at `0` once the row is purged and\n * the bucket empty, so a name that is retired and re-created has a *different* segment wearing the *same*\n * `currentGen`. `expectFrom` alone matched it \u2014 and an erasure rewrite then published one incarnation's content\n * over another's, deleted the live objects with its `keep: 0` collection, and returned `erased: true`. The row's\n * OCC token is the identity that survives this: {@link IRegistryDriver.delete} tombstones rather than unlinks,\n * so \"a later `create` still gets a fresh, greater token\" and no token is ever reused across incarnations.\n *\n * Pass the token read alongside `expectFrom` and the publish lands only on the same row it was derived from.\n * The check is deliberately **conservative**: the token also changes on writes that are not supersessions at\n * all (a `setRetention`, a due-index reindex), so such a write makes a derived publish report `superseded` and\n * the caller re-derive. That costs a re-run on a rare, unrelated write; the alternative costs a segment.\n */\nexport async function publishGeneration(\n registry: IRegistryDriver,\n key: GenKey,\n options: {\n wrappedDeks?: readonly WrappedDek[];\n expectFrom?: number;\n expectToken?: Token;\n /**\n * Publish only while the segment still has **no registry row**.\n *\n * The fence for a caller whose decision rests on the row being ABSENT. `expectFrom` and `expectToken`\n * cannot express it: both compare against a value read from a row, so when there was no row there is\n * nothing to compare and both are simply omitted \u2014 leaving the publish a bare forward-only advance that\n * happily lands over whatever appeared in the meantime.\n *\n * That gap was a silent wipe, not a theoretical one. A guarded load into a segment that did not exist yet\n * read \"no row\", so its empty/`minRetained` bounds had nothing to judge and passed vacuously; a\n * concurrent writer then created the row and published a thousand ids; and the guarded load published an\n * EMPTY generation over them, reporting `published: true` with no reason. Reproduced through both\n * `loadSegment` and the `*Into` verbs, which hit it far more often because materialising into a\n * destination that does not exist yet is the ordinary first run of a pipeline.\n */\n expectAbsent?: boolean;\n } = {},\n): Promise<boolean> {\n for (let attempt = 0; attempt < 5; attempt++) {\n const record = await registry.get(key);\n try {\n if (options.expectFrom !== undefined && record?.currentGen !== options.expectFrom) {\n // The pointer is no longer where the caller derived its content from \u2014 including the cases where the row\n // has vanished or has no generation at all. Not an error: the caller re-reads and re-derives.\n return false;\n }\n if (options.expectAbsent === true && record !== null) {\n // A row appeared since the caller looked. Whatever it decided from \"this segment does not exist\" no\n // longer holds \u2014 most importantly \"there is nothing here to overwrite\".\n return false;\n }\n if (options.expectToken !== undefined && record?.token !== options.expectToken) {\n // Same pointer VALUE, different row. Either the row was written since (harmless, and we re-derive\n // anyway) or the name was retired and re-created, in which case `currentGen` matching means nothing:\n // it is a different segment that restarted its generation counter at the same number.\n return false;\n }\n if (record === null) {\n // First publish for the segment \u2014 carry the wrapped DEK(s) so encrypted reads can resolve the key.\n await registry.create(key, {\n currentGen: key.generation,\n wrappedDeks: options.wrappedDeks,\n });\n } else if (record.status === 'destroyed') {\n // Closes the window between a writer's own destroyed-check and its publish.\n //\n // `bulkLoadCrbmGeneration` reads the registry record once, refuses if it is already destroyed, and then\n // spends a KMS call plus a whole object write before getting here \u2014 seconds to minutes on a large load.\n // A `destroySegment` landing inside that window used to be invisible to this function: it compares only\n // `currentGen`, so it would advance the pointer on a destroyed record, leaving an object encrypted with\n // the DEK that destroy had just shredded \u2014 permanently unreadable, still paid for, and attached to a\n // segment the registry says was erased.\n //\n // Checking here rather than at the caller is what makes it a fence instead of a second guess: this\n // record was re-read moments ago inside the retry loop, so the check and the CAS that follows it see the\n // same state. `erasure.ts` notes that coupling the write path to destruction was left as \"a later\n // hardening\" \u2014 for the publish step, this is it.\n throw new ValidationError(\n `segment \"${key.segment}\" was destroyed (crypto-shredded) while generation ${key.generation} was ` +\n `being written \u2014 refusing to publish it; the written object is unreadable. Use a new segment.`,\n );\n } else if (record.currentGen === null) {\n // The row exists with no Storage generation yet (a retention policy recorded ahead of the first load). There\n // is no pointer to regress past, so this publish advances it \u2014 and carries the wrapped\n // DEK(s) exactly like a first publish onto no row, since no generation is encrypted under the row's\n // current wrappings (there is no generation at all).\n //\n // `wrappedDeks` is spread in ONLY when there is something to store. A registry patch clears an optional\n // field by *mentioning* it (`'wrappedDeks' in patch`), so passing `wrappedDeks: undefined` unconditionally\n // would wipe key material off the row whenever a cleartext generation is published onto it \u2014 a divergence\n // from the branch below, which never touches the field.\n await registry.compareAndSwap(key, record.token, {\n currentGen: key.generation,\n ...(options.wrappedDeks === undefined ? {} : { wrappedDeks: options.wrappedDeks }),\n });\n } else if (record.currentGen > key.generation) {\n return false; // a newer generation is already current \u2014 forward-only, never regress\n } else if (record.currentGen === key.generation) {\n return true; // already exactly current (an idempotent re-publish) \u2014 nothing to advance\n } else {\n // Advancing over an existing generation. `wrappedDeks` is deliberately NOT carried here, and a caller\n // that supplies it is refused rather than served.\n //\n // Reaching this branch with a freshly minted DEK means an encrypted generation is being published onto a\n // lineage whose current generation the row already describes \u2014 i.e. onto a segment whose existing\n // generations are cleartext. Both ways of resolving that silently are damaging: dropping the wrapping\n // (what this branch used to do) advances the pointer to an object encrypted under a key that exists\n // nowhere, so the data is unrecoverable the moment the call returns; carrying it makes the row advertise\n // encryption over a lineage that still holds readable cleartext objects, which is what makes\n // `destroySegment` emit `segment.erase` \u2014 \"unreadable everywhere, backups included\" \u2014 over plaintext.\n // Two independent reviews reproduced the first one from two different entry points (a re-load with a\n // keystore newly wired, and an `*Into` on a keystore-wired store whose destination was cleartext), and\n // it needed no race. So the state is refused before the pointer moves; the object stays an orphan.\n if (options.wrappedDeks !== undefined && options.wrappedDeks.length > 0) {\n throw new ValidationError(\n `publishGeneration: refusing to publish generation ${key.generation} of \"${key.segment}\" with new ` +\n `key material onto a segment that already has generation ${record.currentGen} \u2014 its existing ` +\n `generations are not encrypted under this key. Encrypt a new segment and load into that instead.`,\n );\n }\n await registry.compareAndSwap(key, record.token, { currentGen: key.generation });\n }\n return true; // created or advanced the pointer to key.generation \u2192 it is now current\n } catch (err) {\n if (isWriteConflictError(err)) continue; // lost the race \u2014 re-read and retry\n throw err;\n }\n }\n // Exhausted: only possible if competing writers kept advancing currentGen \u2014 which likely already satisfies\n // the forward-only goal. Confirm before reporting failure, so a lost-every-race-but-already-current case\n // isn't a spurious error. Whether *this* generation is the current one decides the returned flag.\n const final = await registry.get(key);\n // `currentGen === null` after exhausting the retries is a genuine failure, not an already-current case: nothing\n // is published, so it falls through to the conflict below rather than being read as \"a newer gen won\".\n if (final !== null && final.currentGen !== null && final.currentGen >= key.generation)\n return final.currentGen === key.generation;\n throw new WriteConflictError(\n `publishGeneration: contention setting currentGen for ${key.segment}`,\n );\n}\n\n/** What a bulk-load wrote \u2014 the driver's `{ size, sha256 }` plus a summary of the built generation. */\nexport interface BulkLoadResult {\n /** Bytes written to the Storage object. */\n readonly size: number;\n /** The driver's content hash of the object. */\n readonly sha256: string;\n /** Distinct non-empty chunks written (\u2264 65536). */\n readonly chunkCount: number;\n /**\n * The DEK freshly minted for this generation, wrapped \u2014 present only when the segment is encrypted AND this\n * call minted one (an existing segment reuses its key, which is already on the row).\n *\n * Returned so a caller that deliberately does **not** pass `registry` here \u2014 writing now and publishing later,\n * which is how a load applies a guard while the old generation is still authoritative \u2014 can carry the key onto\n * its own `publishGeneration`. Without it that publish stores no DEK and the generation it makes current is\n * unreadable: the bytes are encrypted with a key nothing recorded.\n */\n readonly wrappedDeks?: readonly WrappedDek[];\n /** Total distinct ids in the generation (post-dedup). */\n readonly cardinality: number;\n /**\n * Whether this generation is now the segment's **current** one \u2014 `undefined` when no `registry` was wired, so\n * there is no pointer and no publish step to report on.\n *\n * `false` means the object is durable but a **concurrent writer published a higher generation first**, so this\n * one is an orphan that no reader will ever resolve. The write succeeded and the *load* did not: whatever this\n * call was asked to make the segment contain, the segment does not contain. That is not a detail a caller can\n * be left to infer \u2014 a `*Into` materialisation used to report the generation it wrote as \"the destination's\n * new current generation\" on exactly this path, which is a plain untruth \u2014 so the flag is on the result and the\n * verbs that promise a published generation check it.\n */\n readonly becameCurrent?: boolean;\n}\n\n/**\n * **Bulk-load** a whole immutable generation from a flat id source \u2014 the batch \"seed/rebuild\" entry point.\n * Unlike {@link writeCrbmGeneration} (which takes pre-grouped bitmaps), this\n * consumes an arbitrary, **unsorted** stream of u32 ids (sync or async) and routes each into its chunk's\n * Roaring bitmap as it goes. The input is consumed lazily and ids dedup on insert, so memory is bounded by\n * the **built generation** \u2014 the in-memory Roaring representation of the *distinct* set (\u2264 one bitmap per\n * non-empty chunk) \u2014 not by the input length: you can stream a billion duplicate-heavy ids and hold only the\n * distinct result. Note this is `O(distinct set)`, **not** window-bounded like {@link SegmentEngine.intersect}:\n * bulk-load holds the whole generation in RAM, which suits batch seed/rebuild jobs but not an\n * unbounded-cardinality stream (a segment larger than RAM needs external-merge / pre-sorted input \u2014 later phase).\n *\n * Each id must be an integer in `[0, 2\u00B3\u00B2)` ({@link splitId} throws {@link ValidationError} otherwise) \u2014 the\n * source is consumed lazily, so a bad id aborts mid-stream without writing a partial object (the driver\n * commits only after the callback resolves). An empty source writes a valid empty generation.\n *\n * Writes a fresh full snapshot of a segment. The caller picks the generation number in `key` \u2014 `nextGeneration`\n * computes the right one from the registry and the bucket \u2014 and re-using an existing generation throws\n * {@link WriteConflictError} (write-once). Without a registry a `StorageChunkSource` serves the **highest**\n * generation present, so a too-high number silently shadows real data; with one, `publishGeneration` decides.\n */\nexport async function bulkLoadCrbmGeneration(\n driver: IStorageDriver,\n key: GenKey,\n ids: Iterable<number> | AsyncIterable<number>,\n options: {\n registry?: IRegistryDriver;\n keystore?: IKeystore;\n requireEncryption?: boolean;\n audit?: IAuditSink;\n /** Bitmap codec. Optional in the type; a **flavor** package binds it ({@link requireCodec}). */\n codec?: CodecInterface;\n /**\n * Injected clock. Supplying one makes bulk-load **cooperative**: it yields the event loop periodically so a\n * long load does not stall everything else on the process. Without it the load still completes, just\n * without yielding \u2014 which is the pre-existing behaviour, kept so this is purely additive.\n *\n * `@cloudbitmaps/roaring` supplies a real clock by default, so flavor users get cooperative behaviour with\n * no wiring. `core/` cannot default it: it is timer-free by lint, which is exactly why waiting goes through\n * this seam rather than `setTimeout`.\n */\n clock?: Clock;\n /**\n * Write the object but do **not** advance the pointer (default: publish when a `registry` is wired).\n *\n * For a caller that has to inspect what it wrote before deciding whether it should become current \u2014 a\n * guarded {@link loadSegment} is the one in-tree case \u2014 because the check is only meaningful while the old\n * generation is still authoritative. The `registry` is still required for an encrypted segment and still\n * consulted: it is where an existing segment's DEK lives, and reusing that key is not optional. The wrapped\n * DEK comes back on the result so the deferred publish can store it.\n *\n * A caller that defers the publish owns what it wrote: an unpublished object sits ABOVE `currentGen`, where\n * generation collection deliberately never looks, so nothing else will ever reclaim it.\n */\n publish?: boolean;\n } = {},\n): Promise<BulkLoadResult> {\n if (options.keystore === undefined && options.requireEncryption === true) {\n throw new ValidationError('requireEncryption: bulk-load needs a keystore to write encrypted');\n }\n const codec = requireCodec(options.codec, 'bulkLoadCrbmGeneration');\n const byChunk = new Map<number, CodecBitmap>();\n // Batched per chunk, not one native `add()` per id.\n //\n // The obvious loop \u2014 `bitmap.add(remainder)` for every id \u2014 crosses the JS\u2194native boundary once per id, and\n // measured **1,679 ms for 1M ids** with no yield point anywhere in it. Since this is a synchronous stretch on\n // Node's only thread, a caller who wires it to a request handler stalls every other request on that instance\n // for over a second (measured separately: a 0.7 ms health check took 275 ms).\n //\n // Buffering the remainders and inserting them per chunk in one `fromValues`/`addMany` call amortises that\n // boundary crossing across the whole batch.\n //\n // WHY THE BUFFER IS CAPPED. Bucketing *everything* first and inserting once per chunk at the end is faster\n // still, but it holds every remainder as a JS number before any bitmap compression happens \u2014 and with up to\n // 65,536 chunks in play that is unbounded in exactly the way this library refuses to be. So the buffer is\n // flushed whenever the total pending count crosses `BULK_FLUSH_IDS`, bounding the extra memory regardless of\n // input size or key distribution while still getting the batching win. That bound is **~28 MB measured** at\n // 1M staged ids across ~65,000 chunks \u2014 not the ~8 MB a naive 8-bytes-per-number estimate gives, because the\n // cost is dominated by per-array and Map overhead across tens of thousands of small arrays.\n const pendingByChunk = new Map<number, number[]>();\n let pending = 0;\n // Yield periodically, NOT per chunk \u2014 see {@link yieldEvery} for why per-unit async is a 7x regression here.\n const tickChunk = yieldEvery(options.clock);\n const tickId = yieldEvery(options.clock, YIELD_EVERY_IDS);\n // Yield every N chunks, NOT per chunk. Measured: handing each chunk's insert to the threadpool\n // (`fromArrayAsync`) costs ~9 \u00B5s of dispatch against ~1.5 \u00B5s of actual work once ids are spread across\n // ~61,000 chunks \u2014 636 ms versus 92 ms, a 7x regression that would have undone the per-chunk batching this\n // function already does. Keeping the inserts synchronous and interrupting them periodically gets the\n // starvation fix without the cost \u2014 measured on the per-chunk insert microbenchmark: 88 ms wall against a\n // 92 ms unyielded baseline. The whole-load end-to-end figures are a DIFFERENT experiment and live in\n // `cooperative.ts`; an earlier version of this comment spliced the two, pairing a 92 ms operation with\n // 819 ms of starvation, which is impossible on its face.\n //\n // The yield must be a REAL macrotask. `await Promise.resolve()` is a microtask and never lets I/O run, which\n // is the trap that makes naive \"just await something\" fixes measure as no change at all.\n const flushPending = async (): Promise<void> => {\n for (const [chunkKey, rems] of pendingByChunk) {\n if (rems.length === 0) continue;\n const existingBitmap = byChunk.get(chunkKey);\n if (existingBitmap === undefined) byChunk.set(chunkKey, codec.fromValues(rems));\n else existingBitmap.addMany(rems);\n rems.length = 0;\n const pause = tickChunk();\n if (pause !== null) await pause;\n }\n pending = 0;\n };\n /** Bucket one id. Returns true when the pending buffer is full and must be flushed. */\n const ingest = (id: number): boolean => {\n const { chunkKey, remainder } = splitId(id); // validates the u32 range\n let bucket = pendingByChunk.get(chunkKey);\n if (bucket === undefined) {\n bucket = [];\n pendingByChunk.set(chunkKey, bucket);\n }\n bucket.push(remainder);\n return ++pending >= BULK_FLUSH_IDS;\n };\n // The two ingest loops are deliberately NOT collapsed into one `for await` over a normalising wrapper.\n //\n // That is the tidier code and it was measured at **20x** the cost: routing a sync source through an async\n // generator forces a microtask per id, and over 1M ids that is 224 ms against 11 ms for a plain `for..of` \u2014\n // 55% of a whole bulk load spent on iteration protocol rather than on work. Since an array, a Set and a\n // generator are what callers actually hand this function most of the time, the sync path is the common one.\n //\n // Note that `for await` yields nothing to the event loop either way: a microtask per id still drains before\n // the loop turns a phase. Both paths therefore need the same explicit yield.\n if (Symbol.asyncIterator in ids) {\n for await (const id of ids as AsyncIterable<number>) {\n if (ingest(id)) await flushPending();\n const pause = tickId();\n if (pause !== null) await pause;\n }\n } else {\n for (const id of ids as Iterable<number>) {\n if (ingest(id)) await flushPending();\n const pause = tickId();\n if (pause !== null) await pause;\n }\n }\n await flushPending();\n\n let cardinality = 0;\n const chunks: Array<{ chunkKey: number; bitmap: CodecBitmap }> = [];\n for (const [chunkKey, bitmap] of byChunk) {\n // Every chunk in the map received at least one id, so no bitmap here is empty.\n cardinality += bitmap.size; // a native call per chunk \u2014 5 ms across 62,000 of them, so it yields too\n chunks.push({ chunkKey, bitmap });\n const pause = tickChunk();\n if (pause !== null) await pause;\n }\n\n if (options.keystore !== undefined && options.registry === undefined) {\n throw new ValidationError('bulk-load encryption requires a registry to store the wrapped DEK');\n }\n // Read the segment's record once (when a registry is wired): to refuse writing to a crypto-shredded segment\n // (which would create unreadable/unreachable bytes), and to reuse its DEK if it's encrypted.\n const existing = options.registry !== undefined ? await options.registry.get(key) : null;\n if (existing?.status === 'destroyed') {\n throw new ValidationError(\n `segment \"${key.segment}\" is destroyed (crypto-shredded) \u2014 refusing to write; use a new segment`,\n );\n }\n\n // An encrypted row with no keystore is a lost key, not a cleartext segment \u2014 the same fail-fast the erasure\n // rewrite does. Without it this wrote a CLEARTEXT generation onto a row that still advertises `wrappedDeks`, and the\n // damage is not just a confusing state: `destroySegment` keys `cryptoShredded` off the *presence* of wrappings,\n // so shredding that segment emits `segment.erase` \u2014 the audit event defined as \"these bytes are unreadable\n // everywhere, backups included\" \u2014 over bytes that are plaintext and stay readable from any copy. An audit trail\n // that over-attests is the one failure it exists to prevent, so this refuses to create the state.\n if (\n existing?.wrappedDeks !== undefined &&\n existing.wrappedDeks.length > 0 &&\n options.keystore === undefined\n ) {\n throw new KeyUnavailableError(\n `segment \"${key.segment}\" is encrypted but this bulk-load has no keystore \u2014 refusing to write a cleartext ` +\n `generation onto an encrypted segment. Pass the keystore holding its DEK.`,\n );\n }\n\n // Encryption (opt-in): reuse the segment's existing DEK, or mint a fresh one on its FIRST generation.\n //\n // The segment's own posture decides, not the presence of a keystore. A keystore is wired on the store, so it is\n // in scope for every segment that store touches \u2014 including ones deliberately left cleartext \u2014 and minting on\n // that basis alone is what made \"load it again with a keystore wired\" destroy the data: the minted wrapping has\n // nowhere to live on a row whose pointer is already set (see `publishGeneration`'s advance branch), so the\n // generation ends up encrypted under a key that exists in no persistent store. `requireEncryption` is the way\n // to *demand* encryption, and on an already-cleartext lineage it fails fast rather than silently downgrading.\n let crypto: CrbmCrypto | undefined;\n let newWrapped: readonly WrappedDek[] | undefined;\n if (options.keystore !== undefined) {\n if (existing?.wrappedDeks !== undefined && existing.wrappedDeks.length > 0) {\n const aead = await options.keystore.openDek(existing.wrappedDeks); // reuse the segment's DEK\n crypto = { aead, aadFor: (scope) => aadFor(key, key.generation, scope) };\n } else if (existing !== null && existing.currentGen !== null) {\n // An existing lineage with no key material on the row: the segment is cleartext, and one segment cannot be\n // half-encrypted \u2014 a reader pinned to a superseded generation would find bytes its key cannot open, and a\n // later `destroySegment` would attest that shredding one DEK made every copy unreadable while the older\n // cleartext objects stay readable from any of them.\n if (options.requireEncryption === true) {\n throw new ValidationError(\n `requireEncryption: segment \"${key.segment}\" already has generation ${existing.currentGen} in ` +\n `cleartext, so this load cannot be encrypted \u2014 encryption is chosen when a segment is first ` +\n `loaded. Load into a new segment with the keystore wired, then drop this one.`,\n );\n }\n // Otherwise the segment stays what it is: cleartext.\n } else {\n const minted = await options.keystore.createDek();\n newWrapped = minted.wrapped;\n crypto = { aead: minted.aead, aadFor: (scope) => aadFor(key, key.generation, scope) };\n }\n }\n\n const { size, sha256 } = await writeCrbmGeneration(driver, key, chunks, {\n crypto,\n clock: options.clock,\n });\n // Publish only after the immutable object is durable (write-then-publish): a registry-aware reader should\n // never point at a generation that isn't fully written. A freshly minted DEK is stored on this publish.\n if (options.registry !== undefined && options.publish !== false) {\n const becameCurrent = await publishGeneration(options.registry, key, {\n wrappedDeks: newWrapped,\n });\n // Audit the publish only when this generation actually *became* the current one \u2014 not when a\n // forward-only publish no-oped because a newer generation was already current (the event's contract is\n // \"became the segment's current generation\"). Needs a registry to have a \"current generation\" at all.\n if (becameCurrent) {\n safeAudit(options.audit ?? NOOP_AUDIT).onEvent({\n kind: 'segment.publish',\n namespace: key.namespace,\n segment: key.segment,\n generation: key.generation,\n });\n }\n return {\n size,\n sha256,\n chunkCount: chunks.length,\n cardinality,\n becameCurrent,\n wrappedDeks: newWrapped,\n };\n }\n return { size, sha256, chunkCount: chunks.length, cardinality, wrappedDeks: newWrapped };\n}\n\n/**\n * Open a {@link CrbmReader} on one generation over the storage driver's range/tail reads (decrypting if `crypto`).\n * The reader the write paths use to re-read what they wrote, and the erasure rewrite uses to stream the old\n * generation; the engine's read path goes through {@link CrbmStorageChunkSource} instead, which caches these.\n */\nexport function openGenerationReader(\n storage: IStorageDriver,\n key: GenKey,\n crypto: CrbmCrypto | undefined,\n options: Omit<CrbmReaderOptions, 'crypto'> = {},\n): Promise<CrbmReader> {\n return CrbmReader.open(storageBlobReader(storage, key), { ...options, crypto });\n}\n\n/**\n * Re-open a freshly written generation and assert it round-trips exactly what was streamed into it: the same\n * per-chunk key set *and* the same total cardinality (on top of the codec's own per-chunk CRC + footer checks).\n * `expected` is the streaming writer's tally (the stream is consumed, so it can't be re-iterated) \u2014 the key-set\n * comparison catches a dropped/extra chunk that a cardinality-only check could miss when two errors cancel out.\n * Throws {@link IntegrityError}: the object is on disk but must not be published.\n */\nexport async function verifyGeneration(\n storage: IStorageDriver,\n key: GenKey,\n expected: { readonly chunkKeys: readonly number[]; readonly cardinality: number },\n crypto: CrbmCrypto | undefined,\n): Promise<void> {\n const expectedKeys = [...expected.chunkKeys].sort((a, b) => a - b);\n const reader = await openGenerationReader(storage, key, crypto);\n const actualKeys = [...reader.chunkKeys()].sort((a, b) => a - b);\n const keysMatch =\n actualKeys.length === expectedKeys.length && actualKeys.every((k, i) => k === expectedKeys[i]);\n if (!keysMatch) {\n throw new IntegrityError(\n `verify failed for ${key.segment}.${key.generation}: chunk-key set mismatch (${actualKeys.length} vs ${expectedKeys.length})`,\n );\n }\n if (reader.count() !== expected.cardinality) {\n throw new IntegrityError(\n `verify failed for ${key.segment}.${key.generation}: cardinality ${reader.count()} != ${expected.cardinality}`,\n );\n }\n}\n", "/**\n * A {@link StorageChunkSource} view that holds **one** segment at **one** generation, and passes everything else\n * through to the live source.\n *\n * A pin exists so a long job describes a single instant. An ordinary handle re-resolves on `cache.genTtlMs`, so a\n * publish part-way through an export, a send or a reconciliation means the second half of the job describes a\n * different instant than the first \u2014 and nothing in the result says so.\n *\n * **A pin is a generation NUMBER, not a captured reader.** The number is immutable, so the reader behind it can\n * live in the shared bounded LRU and be evicted freely: re-opening at the same number reproduces the same\n * bytes. Holding the reader instead put every live pin outside the library's memory ceiling.\n *\n * **Other segments are not pinned, and that is the contract, not an omission.** `snap.intersect([other])` reads\n * `snap` at its pinned generation and `other` at whatever is current. Pinning the whole query means pinning\n * each segment. The alternative shapes are both worse: refusing the combine outright makes a pin useless to the\n * export and reconciliation jobs it exists for, and silently pinning the operands would quietly change what\n * `other` means to a caller who did not ask.\n *\n * What this must never do is the inverse \u2014 read a pinned handle's segment **live** because the call was made\n * on some other handle. That is why the routing is by segment identity here rather than by which object the\n * caller happened to start from.\n */\nimport type { ChunkRef, StorageChunkSource, SegmentRef, SegmentSize } from './ports';\nimport type { CrbmStorageChunkSource } from './crbm-storage-source';\nimport { segmentKey } from './keys';\n\n/** What a pin holds for one segment: the generation, and the version identifying those exact bytes. */\nexport interface PinnedAt {\n readonly generation: number | null;\n readonly version: string | null;\n}\n\nexport class PinnedStorageChunkSource implements StorageChunkSource {\n constructor(\n private readonly inner: CrbmStorageChunkSource,\n /**\n * The pinned segments, keyed by {@link segmentKey}. A **set** rather than one entry because a combine may\n * involve several pinned handles, and each must be read at its own pin \u2014 including when the call was made\n * on a different handle. Reading a pinned handle live because the caller started elsewhere is the silent\n * wrong answer this exists to prevent.\n */\n private readonly pins: ReadonlyMap<string, PinnedAt>,\n ) {}\n\n /**\n * The pin for this segment, or `undefined` if it is not pinned here.\n *\n * A pin whose `generation` is `null` is a segment that had none when it was pinned: that handle reads empty\n * for its lifetime, which is exactly what an unpinned read of it does. That is **not** the same as \"this\n * source cannot pin\" \u2014 a source that genuinely cannot is a capability gap and fails fast at `pin()`.\n */\n private pinFor(ref: SegmentRef): PinnedAt | undefined {\n return this.pins.get(segmentKey(ref));\n }\n\n getChunk(ref: ChunkRef): Promise<Uint8Array | null> {\n const pin = this.pinFor(ref);\n if (pin === undefined) return this.inner.getChunk(ref);\n return pin.generation === null\n ? Promise.resolve(null)\n : this.inner.getChunkAt(ref, pin.generation);\n }\n\n listChunkKeys(ref: SegmentRef): Promise<number[]> {\n const pin = this.pinFor(ref);\n if (pin === undefined) return this.inner.listChunkKeys(ref);\n return pin.generation === null\n ? Promise.resolve([])\n : this.inner.listChunkKeysAt(ref, pin.generation);\n }\n\n sizeOf(ref: SegmentRef): Promise<SegmentSize | null> {\n const pin = this.pinFor(ref);\n if (pin === undefined) return this.inner.sizeOf(ref);\n return pin.generation === null\n ? Promise.resolve(null)\n : this.inner.sizeOfAt(ref, pin.generation);\n }\n\n cardinalities(ref: SegmentRef): Promise<ReadonlyMap<number, number> | null> {\n const pin = this.pinFor(ref);\n if (pin === undefined) return this.inner.cardinalities(ref);\n return pin.generation === null\n ? Promise.resolve(null)\n : this.inner.cardinalitiesAt(ref, pin.generation);\n }\n\n currentGeneration(ref: SegmentRef): Promise<number | null> {\n const pin = this.pinFor(ref);\n return pin === undefined ? this.inner.currentGeneration(ref) : Promise.resolve(pin.generation);\n }\n\n /**\n * A pinned segment reports the version captured when it was pinned, so its decoded chunks are cached under a\n * key that cannot collide with the live generation's. That is what lets a pinned handle share the store's\n * chunk cache safely; sharing it on a generation-only key was how a pinned read could resurrect an id that\n * `eraseIdFromSegment` had reported physically gone.\n */\n currentVersion(ref: SegmentRef): Promise<string | null> {\n const pin = this.pinFor(ref);\n return pin === undefined ? this.inner.currentVersion(ref) : Promise.resolve(pin.version);\n }\n\n exists(ref: SegmentRef): Promise<boolean> {\n return this.inner.exists(ref);\n }\n\n invalidate(ref: SegmentRef): void {\n this.inner.invalidate(ref);\n }\n}\n", "/**\n * Generation bookkeeping for the loaded store: which generation a writer should take next, and which\n * superseded generations may be collected.\n *\n * Storage generations are write-once, generation-keyed objects (`<segment>.<gen>.crbm`) behind one registry pointer\n * (`currentGen`). Every write path in the library \u2014 a bulk load, an `*Into` materialisation, a subject-erasure\n * rewrite \u2014 writes a **new** object and then advances the pointer, forward-only for a load and fenced on its\n * source generation for the rewrite (see invariant 1). That leaves the superseded object\n * in the bucket, still billed, so something has to collect it: {@link gcOrphanGenerations}. Pure orchestration\n * over the driver ports \u2014 no I/O, time or randomness of its own.\n */\nimport { WriteConflictError } from './errors';\nimport type { IStorageDriver, IRegistryDriver, SegmentRef } from './ports';\n\n/** The two ports generation bookkeeping needs: the objects, and the pointer that says which one is current. */\nexport interface GenerationDeps {\n readonly storage: IStorageDriver;\n readonly registry: IRegistryDriver;\n}\n\n/**\n * The generation number a writer should use for the segment's **next** object: one above the highest generation\n * the registry points at *or* that is present in Storage \u2014 whichever is higher.\n *\n * Both are consulted because they can disagree. A load that wrote its object and crashed before publishing leaves\n * an object *above* `currentGen`; a writer that consulted only the pointer would pick that same number and hit the\n * write-once conflict on every retry. Skipping past it costs one `list` and keeps the retry trivial \u2014 the crashed\n * object is an orphan {@link gcOrphanGenerations} collects once the pointer moves on. Reusing such an object\n * instead of skipping it (verify-and-publish) is `load()`'s job, not a numbering helper's.\n *\n * A segment with no row and no objects starts at 0. An admin/write-path helper, never on the read path.\n */\nexport async function nextGeneration(ref: SegmentRef, deps: GenerationDeps): Promise<number> {\n const record = await deps.registry.get(ref);\n let highest = record?.currentGen ?? -1;\n for await (const key of deps.storage.list(ref)) {\n if (key.generation > highest) highest = key.generation;\n }\n return highest + 1;\n}\n\n/**\n * Garbage-collect superseded Storage generations for a segment: everything strictly below `currentGen`, keeping\n * the most recent `keep` of them as a grace window, so a read still fetching from a just-superseded\n * generation need not re-resolve mid-call (**invariant 4**). It is a window, not a lock: a read whose\n * generation is swept anyway re-resolves and retries once rather than failing (see `withFreshSnapshot`), so\n * `keep` trades storage for round trips. Generations \u2265 `currentGen` are never touched. Returns the generations\n * deleted.\n *\n * **Except on a `destroyed` segment, where EVERY generation is garbage** and the grace window is meaningless.\n * A tombstoned segment resolves no generation for any reader, pinned or not \u2014 a pin cannot be taken on one, and\n * a pin taken while it was still active re-checks the status on every open \u2014 and nothing else in the library\n * would ever collect them, so without this those objects are billed forever.\n *\n * **Throws {@link WriteConflictError} if the segment changed underneath the pass** \u2014 not to be confused with\n * the empty array it still returns when there was genuinely nothing to collect (no row at all, or no pointer\n * yet), which is why an empty array is not a receipt. The row is read before the listing and acted on after it, so a name that was purged and\n * re-created in that window is a *different* segment wearing the same name, and its live object must not be\n * collected on the strength of the old row. Refusing is safe \u2014 the objects are not going anywhere and the next\n * pass reads a consistent row \u2014 but it has to be **distinguishable** from \"there was nothing to collect\", which\n * an empty array is not: `eraseIdFromSegment` reads the returned list as the physical half of its erasure\n * receipt, and would otherwise report `erased: true` over bytes still in the bucket. Re-run it.\n *\n * That state is reachable in practice: a `dropSegment` whose Storage sweep threw part-way, or a load that was\n * already writing its object when the tombstone landed and finished the write afterwards. `dropSegment` re-sweeps\n * and reports whatever it could not reclaim in `generationsRemaining`, but a drop that was never re-run leaves a\n * residual, and this is what eventually collects it from the retention sweep.\n *\n * `keep: 0` is how a subject-erasure rewrite makes a bit **physically** gone on return: the generation that held\n * it is collected the moment the rewrite is current. A reader pinned to it re-resolves on its next read.\n */\nexport async function gcOrphanGenerations(\n ref: SegmentRef,\n deps: GenerationDeps,\n options: { keep?: number } = {},\n): Promise<number[]> {\n const keep = Math.max(0, options.keep ?? 1);\n const record = await deps.registry.get(ref);\n if (record === null) return []; // no authoritative pointer \u2192 don't delete anything\n const current = record.currentGen;\n // A set, not an array: a listing that spans a purge-and-recreate can yield the same generation number\n // twice (the objects are re-created under the numbers just swept), and the grace window below keeps the\n // newest `keep` ENTRIES \u2014 so a duplicate would silently consume a keep slot and evict a live generation.\n const seen = new Set<number>();\n for await (const key of deps.storage.list(ref)) seen.add(key.generation);\n const gens = [...seen];\n // Everything above was read BEFORE the listing and is acted on after it, and the listing is paginated \u2014\n // seconds wide on a real object store. So re-read the row and reconcile, because BOTH branches can otherwise\n // delete an object the live pointer names, which is the forbidden `missing-storage-generation` state.\n //\n // A purged row refuses outright, on either branch: purged-and-idle is indistinguishable from\n // purged-and-being-recreated, and the top of this function already declines to act without an authoritative\n // pointer.\n const after = await deps.registry.get(ref);\n if (after === null)\n throw new WriteConflictError(`registry row for segment ${ref.segment} was purged mid-pass`);\n\n // On a tombstone, require the *same* row. A token is never reused (ABA-safe), so an unchanged one proves the\n // segment was not purged and re-created underneath this pass \u2014 which matters here because this branch deletes\n // every object it enumerated, `currentGen` included, so a re-created segment would lose the generation its\n // new pointer names.\n if (record.status === 'destroyed' && after.token !== record.token) {\n throw new WriteConflictError(\n `segment ${ref.segment} changed incarnation while its generations were being listed`,\n );\n }\n\n // On the ordinary branch, take the LOWER of the two pointers. Within one incarnation the pointer only moves\n // forward, so a publish landing mid-listing leaves the cutoff exactly where it was and routine GC still\n // collects \u2014 refusing on any token change would make GC useless on a busy segment. But the pointer is only\n // monotonic *within* an incarnation: `nextGeneration` restarts at 0 once a row is purged and the bucket\n // emptied, so a name that was retired and re-created wears a LOWER `currentGen` than the one read before the\n // listing \u2014 and `rollbackSegment` lets an operator lower it deliberately \u2014 so `g < current` would then select\n // a live object. `Math.min` is what makes a\n // regressed pointer narrow the cutoff instead of widening it.\n const cutoff =\n current === null || after.currentGen === null ? null : Math.min(current, after.currentGen);\n\n /**\n * Re-prove that everything still queued for deletion is still collectable. Two different questions, because\n * the two branches delete under different licences:\n *\n * - a **tombstone** deletes at and above `currentGen`, so it needs incarnation IDENTITY \u2014 the same row,\n * by token;\n * - the **ordinary** branch deletes strictly below `cutoff`, so it needs only that the live pointer has not\n * fallen below `cutoff`. A forward publish moves it up and changes nothing, which is what keeps routine\n * collection working on a busy segment; only a purge-and-recreate can move it down.\n */\n const stillCollectable = async (): Promise<void> => {\n const still = await deps.registry.get(ref);\n if (still === null) {\n throw new WriteConflictError(`registry row for segment ${ref.segment} was purged mid-pass`);\n }\n const ok =\n record.status === 'destroyed'\n ? still.token === after.token\n : cutoff === null || (still.currentGen !== null && still.currentGen >= cutoff);\n if (!ok) {\n throw new WriteConflictError(\n `segment ${ref.segment} changed incarnation while its generations were being collected`,\n );\n }\n };\n\n const toDelete =\n record.status === 'destroyed'\n ? gens.sort((a, b) => a - b) // all of it: no reader can resolve a generation of a tombstoned segment\n : cutoff === null\n ? // No Storage pointer yet, so \"below current\" selects nothing and there is nothing safe to infer: an object\n // here is either a load about to publish or an orphan we cannot tell apart from it. Deleting would race\n // that publish into a dangling pointer. It is collected once a pointer exists.\n []\n : // Delete generations below the cutoff, except the newest `keep` of them (the grace window).\n gens\n .filter((g) => g < cutoff)\n .sort((a, b) => b - a) // newest-first\n .slice(keep);\n // The re-read above proves the segment was intact at ONE instant; the deletes below are one round trip each,\n // so the exposure is the whole loop, not that instant. The ordinary branch deletes newest-first, which puts a\n // restarted incarnation's generation 0 LAST \u2014 the worst ordering.\n //\n // Re-proved before EVERY delete, the first included. An earlier version skipped the first on the grounds that\n // the re-read above had just covered it, which held only while the pointer could not fall: the window between\n // the re-read and the first delete was one where the pointer could only rise, and a rising pointer only makes\n // more things collectable. `rollbackSegment` removed that premise \u2014 an operator can now move the pointer\n // *down*, onto a generation this pass has already queued \u2014 and reproduced exactly that: a rollback landing in\n // that window left the pass deleting the live generation before its second iteration noticed anything.\n //\n // Cost is one registry read per object actually deleted, on a path that is already one round trip per object\n // and is never on the read path.\n for (const generation of toDelete) {\n await stillCollectable();\n await deps.storage.delete({ namespace: ref.namespace, segment: ref.segment, generation });\n }\n return toDelete;\n}\n", "/**\n * `loadSegment` \u2014 the loaded store's primary write path, as one call.\n *\n * A load is always the same four steps: take the next generation number, write one immutable object, move the\n * pointer, collect what the move superseded. Done by hand they are `nextGeneration` + `bulkLoadCrbmGeneration` +\n * `publishGeneration` + `gcOrphanGenerations`, and the step people leave out is the last one \u2014 so stores that\n * compose it themselves accumulate superseded generations they keep paying for. Composing it here is the point.\n *\n * The other reason it is one call is the **guard**. A load REPLACES a segment: whatever the stream contains is\n * what the segment contains afterwards. That makes an upstream query returning fewer rows than usual \u2014 or none \u2014\n * a silent, successful-looking wipe, and nothing downstream can tell it from a legitimate shrink. The guard is\n * the place to say what a plausible result looks like, and it has to sit **between the write and the publish**,\n * because that is the only moment where the new content is known and the old one is still authoritative.\n *\n * Refusing therefore has to clean up after itself. The object is already durable at that point, and it sits\n * ABOVE `currentGen`, where generation collection deliberately never looks (it deletes strictly below the\n * pointer). Nothing else would ever reclaim it, so a refused load deletes its own object before returning.\n */\nimport { type IAuditSink, NOOP_AUDIT, safeAudit } from './audit';\nimport type { CodecInterface } from './codec';\nimport {\n bulkLoadCrbmGeneration,\n openGenerationReader,\n publishGeneration,\n} from './crbm-storage-source';\nimport type { Clock } from './determinism';\nimport { aadFor } from './crypto';\nimport type { CrbmCrypto, IKeystore } from './crypto';\nimport {\n KeyUnavailableError,\n ValidationError,\n isNotFoundError,\n isWriteConflictError,\n} from './errors';\nimport { gcOrphanGenerations, nextGeneration } from './generation-gc';\nimport type { IStorageDriver, IRegistryDriver, RegistryRecord, SegmentRef, Token } from './ports';\nimport { validateSegmentRef } from './validate';\n\n/** What {@link loadSegment} needs: the objects, the pointer, the codec, and key material if encrypted. */\nexport interface LoadDeps {\n readonly storage: IStorageDriver;\n readonly registry: IRegistryDriver;\n readonly codec?: CodecInterface;\n readonly keystore?: IKeystore;\n readonly requireEncryption?: boolean;\n readonly clock?: Clock;\n}\n\n/**\n * What a plausible result looks like, so an implausible one is refused instead of published.\n *\n * Both bounds are compared against the **current** generation's cardinality, read from the `.crbm` index rather\n * than its payload \u2014 one object-header read, and only when a bound is actually set.\n */\nexport interface LoadGuard {\n /** Refuse a generation with fewer than this many ids. Use for \"this segment is never legitimately tiny\". */\n readonly minCardinality?: number;\n /**\n * Refuse a generation that retains less than this fraction of the current one \u2014 `0.5` means \"at least half the\n * ids must survive\". A *growing* load is never refused by this bound, and neither is the first load of a\n * segment, which has nothing to shrink from.\n *\n * Phrased as a floor rather than a ceiling on the loss so that `0` means the same thing here as it does on\n * `minCardinality` above: **no bound**. The inverse spelling (`maxShrink`) would make `0` mean \"refuse any\n * shrink at all\" \u2014 maximally strict \u2014 sitting in the same object literal as a field where `0` is maximally\n * permissive, which is where an inversion would eventually be written and not noticed.\n */\n readonly minRetained?: number;\n}\n\nexport interface LoadOptions {\n /**\n * Publish an empty generation over a non-empty one. Off by default: an empty result is far more often an\n * upstream failure than an intent, and the failure is indistinguishable from success once it lands.\n */\n readonly allowEmpty?: boolean;\n readonly guard?: LoadGuard;\n /**\n * Generations to keep below the new pointer as a grace window (default 1). Keep at least one: a read that is\n * still fetching chunks from the just-superseded generation would otherwise have it deleted out from under it\n * and pay a re-resolve. A wider window costs storage and buys nothing a pinned read would not do better.\n */\n readonly keep?: number;\n readonly audit?: IAuditSink;\n}\n\n/** Why a load did not become current. */\nexport type LoadRefusal =\n | 'empty'\n | 'min-cardinality'\n | 'min-retained'\n /** Another writer published a higher generation first. The object was written, then removed. */\n | 'superseded';\n\nexport interface LoadResult {\n /** The generation written. Present even when refused \u2014 it is what was deleted again. */\n readonly generation: number;\n /** Whether this generation is now the segment's current one. */\n readonly published: boolean;\n /** Set only when `published` is false. */\n readonly reason?: LoadRefusal;\n readonly size: number;\n readonly sha256: string;\n readonly chunkCount: number;\n /** Distinct ids in the generation that was written, post-dedup. */\n readonly cardinality: number;\n /**\n * What the segment held when the guard judged it \u2014 `null` when there was no current generation, or when no\n * bound needed it. Returned because an alert on `reason: 'min-retained'` is useless without it: \"refused\" is a\n * page, \"refused: 4 \u2192 1\" is a diagnosis, and re-reading the segment to find out costs a round trip and races\n * whatever happens next.\n */\n readonly cardinalityBefore: number | null;\n /** The superseded generations collected after publishing. Empty when nothing was published. */\n readonly collected: readonly number[];\n}\n\n/**\n * Cardinality of the segment's current generation, read from the `.crbm` index rather than its payload.\n * `null` when there is no current generation to compare against.\n *\n * The crypto is derived **here** rather than taken from the caller, and that is not a convenience. AAD is bound\n * to a specific generation, so a `CrbmCrypto` passed in from outside would have to be pre-bound to whichever\n * generation turns out to be current \u2014 which only this function learns, by reading the row. A caller cannot\n * satisfy that seam even in principle, so offering it would be offering a parameter nobody can fill correctly.\n */\nasync function currentCardinality(\n ref: SegmentRef,\n deps: LoadDeps,\n record: RegistryRecord | null,\n): Promise<number | null> {\n if (record === null || record.currentGen === null || record.status === 'destroyed') return null;\n const generation = record.currentGen;\n let crypto: CrbmCrypto | undefined;\n const wrapped = record.wrappedDeks;\n if (wrapped !== undefined && wrapped.length > 0) {\n if (deps.keystore === undefined) {\n throw new KeyUnavailableError(\n `segment \"${ref.segment}\" is encrypted but load was given no keystore`,\n );\n }\n const aead = await deps.keystore.openDek(wrapped);\n crypto = { aead, aadFor: (scope) => aadFor(ref, generation, scope) };\n }\n let reader;\n try {\n reader = await openGenerationReader(deps.storage, { ...ref, generation }, crypto);\n } catch (err) {\n // The row names a generation whose OBJECT is gone \u2014 the `missing-storage-generation` state a consistency\n // check reports, produced by a partial `dropSegment`, a bucket lifecycle rule, or a restore that brought\n // the registry back without the bucket.\n //\n // `null`, not a throw. The guard exists to protect ids that are still there, and these are already gone:\n // refusing to write would leave the segment unreadable AND unrepairable, which is the opposite of what a\n // guard is for. Writing over it is precisely the repair, and it is what this path did before the guard\n // reached it. A caller who wants to be told instead can run `checkConsistency()`, whose job that is.\n if (!isNotFoundError(err)) throw err;\n return null;\n }\n let total = 0;\n for (const n of reader.cardinalities().values()) total += n;\n return total;\n}\n\n/**\n * Replace a segment's contents with `ids`, as one immutable generation, and make it current.\n *\n * Returns what was written and whether it became current. A refusal is **not** an exception: `published: false`\n * with a `reason` is a normal outcome a caller branches on, in the same shape as a successful load, because the\n * interesting cases (a guard tripped, a racing writer won) are operational facts rather than faults.\n */\nexport async function loadSegment(\n ref: SegmentRef,\n ids: Iterable<number> | AsyncIterable<number>,\n deps: LoadDeps,\n options: LoadOptions = {},\n): Promise<LoadResult> {\n validateSegmentRef(ref);\n const keep = options.keep ?? 1;\n if (!Number.isInteger(keep) || keep < 0) {\n throw new ValidationError(`keep must be a non-negative integer; got ${String(keep)}`);\n }\n const guard = options.guard;\n if (guard?.minCardinality !== undefined) {\n const m = guard.minCardinality;\n if (!Number.isInteger(m) || m < 0) {\n throw new ValidationError(\n `guard.minCardinality must be a non-negative integer; got ${String(m)}`,\n );\n }\n }\n if (guard?.minRetained !== undefined) {\n const s = guard.minRetained;\n if (!Number.isFinite(s) || s < 0 || s > 1) {\n throw new ValidationError(`guard.minRetained must be a fraction in 0..1; got ${String(s)}`);\n }\n }\n const audit = safeAudit(options.audit ?? NOOP_AUDIT);\n\n // One row read, used for three things: the guard's \"before\", the incarnation this call is acting on, and the\n // pointer it derived its decision from.\n const row = await deps.registry.get(ref);\n const fromToken: Token | undefined = row?.token;\n const fromGeneration = row?.currentGen ?? undefined;\n\n // Read the \"before\" cardinality ONLY when a bound needs it. The empty guard needs to know whether the current\n // generation is non-empty; `minRetained` needs its size. `minCardinality` compares against the new generation\n // alone, so it costs nothing extra.\n const needsBefore = guard?.minRetained !== undefined || options.allowEmpty !== true;\n const before = needsBefore ? await currentCardinality(ref, deps, row) : null;\n\n const generation = await nextGeneration(ref, deps);\n const key = { namespace: ref.namespace, segment: ref.segment, generation };\n\n // `publish: false`, deliberately: the guard has to run while the old generation is still authoritative, so the\n // pointer moves below rather than here. The registry is still passed \u2014 it is where an existing encrypted\n // segment's DEK lives, and reusing that key is not optional \u2014 and the freshly minted one comes back on the\n // result so the deferred publish can store it.\n let written;\n try {\n written = await bulkLoadCrbmGeneration(deps.storage, key, ids, {\n registry: deps.registry,\n publish: false,\n keystore: deps.keystore,\n requireEncryption: deps.requireEncryption,\n codec: deps.codec,\n clock: deps.clock,\n });\n } catch (err) {\n // Another loader took this generation number first \u2014 write-once refused the second put. That is a lost race,\n // and `LoadRefusal` documents a lost race as `'superseded'`; letting a `WriteConflictError` escape here would\n // make a caller who branches on `published` (as the doc-comment tells them to) miss the one outcome they were\n // told to expect. Nothing was written, so there is nothing to clean up.\n if (!isWriteConflictError(err)) throw err;\n return {\n generation,\n published: false,\n reason: 'superseded',\n size: 0,\n sha256: '',\n chunkCount: 0,\n cardinality: 0,\n cardinalityBefore: before,\n collected: [],\n };\n }\n\n const refuse = async (reason: LoadRefusal): Promise<LoadResult> => {\n // The object is durable and sits above `currentGen`, where collection never looks. Nothing else would ever\n // reclaim it, so the refusal reclaims it here \u2014 but ONLY while this is still the same segment.\n //\n // A generation number identifies a generation within one incarnation of a row, and nothing more (invariant\n // 1). If the row was purged and the name re-created while this load was in flight, `nextGeneration` restarts\n // from 0 and the number this call is holding can name the NEW incarnation's live object. Deleting it would\n // put an active row over a missing generation \u2014 the forbidden `missing-storage-generation` state, produced by\n // the one code path whose whole purpose is to prevent data loss. Leaving an orphan behind is strictly the\n // better failure: it costs storage until something collects it, rather than costing a live segment.\n const now = await deps.registry.get(ref);\n if (now === null || now.token === fromToken) await deps.storage.delete(key);\n audit.onEvent({\n kind: 'segment.load-refused',\n segment: ref.segment,\n namespace: ref.namespace,\n generation,\n reason,\n cardinality: written.cardinality,\n });\n // Constructed field by field, never spread from the write result. That result now carries `wrappedDeks` \u2014\n // wrapped key material \u2014 and a spread would put it on a public, JSON-serialisable object that a load job\n // will reasonably `logger.info({ result })`. Declared shapes are not a filter at runtime.\n return {\n generation,\n published: false,\n reason,\n size: written.size,\n sha256: written.sha256,\n chunkCount: written.chunkCount,\n cardinality: written.cardinality,\n cardinalityBefore: before,\n collected: [],\n };\n };\n\n if (written.cardinality === 0 && options.allowEmpty !== true && (before ?? 0) > 0) {\n return refuse('empty');\n }\n if (guard?.minCardinality !== undefined && written.cardinality < guard.minCardinality) {\n return refuse('min-cardinality');\n }\n if (guard?.minRetained !== undefined && before !== null) {\n if (written.cardinality < before * guard.minRetained) return refuse('min-retained');\n }\n\n // Fence the publish on the row the guard judged.\n //\n // Forward-only is right for an UNGUARDED load: its ids come from upstream, so losing a race costs nothing that\n // the winner did not also bring. A guarded load is a different animal \u2014 it derived its decision from a\n // particular generation's cardinality, which makes it exactly the writer invariant 1 says must publish with\n // `expectFrom`. Without that, anything published between the \"before\" read and this publish voids the guard's\n // premise while the guard still reports success: reproduced, two loaders on a fresh segment let an EMPTY\n // generation land over a thousand ids, under default options, because `before` was read as \"no row\".\n //\n // `expectToken` goes on regardless. It is incarnation identity rather than a derivation fence, it costs\n // nothing legitimate \u2014 a token only changes when the row does \u2014 and it is what stops this call publishing\n // into a segment that merely reuses the name it started with.\n const published = await publishGeneration(deps.registry, key, {\n wrappedDeks: written.wrappedDeks,\n ...(fromToken === undefined ? {} : { expectToken: fromToken }),\n ...(needsBefore && fromGeneration !== undefined ? { expectFrom: fromGeneration } : {}),\n // The third case, and the one the two fences above structurally cannot cover: the guard judged a segment\n // that had NO ROW. Both `expectFrom` and `expectToken` compare against a value read from a row, so with no\n // row both are omitted and the publish becomes a bare forward-only advance \u2014 which lands over anything\n // that appeared in between. `before` was `null`, so the empty and `minRetained` bounds had nothing to\n // judge and passed vacuously. Verified: an empty generation published over a thousand ids that a\n // concurrent writer had created meanwhile, reporting success. A guarded write therefore has to fence on\n // the ABSENCE it relied on, exactly as it fences on the pointer it relied on.\n ...(needsBefore && row === null ? { expectAbsent: true } : {}),\n });\n if (!published) return refuse('superseded');\n\n audit.onEvent({\n kind: 'segment.publish',\n segment: ref.segment,\n namespace: ref.namespace,\n generation,\n });\n\n const collected = await gcOrphanGenerations(ref, deps, { keep });\n return {\n generation,\n published: true,\n size: written.size,\n sha256: written.sha256,\n chunkCount: written.chunkCount,\n cardinality: written.cardinality,\n cardinalityBefore: before,\n collected,\n };\n}\n", "/**\n * `listGenerations` and `rollbackSegment` \u2014 see what a segment has been, and put it back.\n *\n * Immutable generations mean the previous version of a segment is usually still sitting in the bucket: a load\n * that replaced it did not overwrite anything, it wrote a new object and moved a pointer. So recovering from a\n * bad load is, in principle, moving the pointer back \u2014 and until now there was no way to do it, because every\n * write path in the library is deliberately **forward-only** and refuses a regression.\n *\n * That refusal is right for a *writer*: a load whose ids came from upstream loses nothing by being out-raced, and\n * letting it regress the pointer would let a slow loader silently undo a fast one. It is wrong for an *operator*,\n * who has looked at the segment, decided the current generation is wrong, and knows which one they want. So\n * rollback is the one call that moves the pointer backwards, and it is deliberately not reachable from any\n * automatic path \u2014 no sweep, no retry, no reconciliation calls it.\n *\n * It is audited for the same reason. Every other pointer move can be reconstructed from \"a load happened\"; this\n * one is a human overriding the ordering rule the rest of the system relies on, which is exactly the event an\n * Art. 30 record or an incident review wants to find.\n */\nimport { type IAuditSink, NOOP_AUDIT, safeAudit } from './audit';\nimport { NotFoundError, ValidationError } from './errors';\nimport type { IStorageDriver, IRegistryDriver, SegmentRef } from './ports';\nimport { validateSegmentRef } from './validate';\n\n/** What the generation helpers need: the objects, and the pointer that says which one is current. */\nexport interface GenerationListDeps {\n readonly storage: IStorageDriver;\n readonly registry: IRegistryDriver;\n}\n\n/** One generation present in the bucket. */\nexport interface GenerationEntry {\n readonly generation: number;\n /** Whether the registry pointer currently names this generation. */\n readonly current: boolean;\n}\n\n/**\n * Every generation still present for a segment, ascending, with the current one marked.\n *\n * This is what the bucket holds, not what the segment has ever been: generation collection deletes superseded\n * objects, so the list is the grace window plus whatever has not been collected yet. It is the set a\n * {@link rollbackSegment} can choose from, which is the reason to look at it.\n *\n * One `list` call. It does not open the objects, so it costs nothing per generation and tells you nothing about\n * their contents \u2014 read the sizes through the store's own report if you need them.\n */\nexport async function listGenerations(\n ref: SegmentRef,\n deps: GenerationListDeps,\n): Promise<GenerationEntry[]> {\n validateSegmentRef(ref);\n const record = await deps.registry.get(ref);\n const current = record?.currentGen ?? null;\n const seen = new Set<number>();\n for await (const key of deps.storage.list(ref)) seen.add(key.generation);\n return [...seen]\n .sort((a, b) => a - b)\n .map((generation) => ({ generation, current: generation === current }));\n}\n\nexport interface RollbackResult {\n /** The generation the pointer named before the rollback. `null` when the segment had no current generation. */\n readonly fromGeneration: number | null;\n /** The generation the pointer names now. */\n readonly generation: number;\n}\n\n/**\n * Move a segment's pointer **back** to a generation that is still in the bucket.\n *\n * The only non-forward-only publish in the library, and the only one an operator has to ask for by name. It\n * refuses rather than guesses:\n *\n * - a generation whose object is **not in the bucket** \u2014 collected, or never written \u2014 is refused with\n * `NotFoundError` rather than pointed at, because a pointer naming a missing object is the one state the whole\n * design exists to avoid;\n * - a **crypto-shredded** segment is refused: every generation of it is unreadable, so a rollback would produce a\n * segment that resolves and then fails;\n * - rolling to the generation **already current** is a no-op that reports itself, not an error.\n *\n * What it does **not** do is delete anything. The generations above the new pointer stay in the bucket, which is\n * what makes the rollback reversible \u2014 roll forward again by naming one of them. They are also then *above*\n * `currentGen`, where generation collection never looks, so they will sit there until a later load raises the\n * pointer past them or they are deleted deliberately. That is a deliberate trade: an operator who has just\n * undone a bad load should not have the evidence collected out from under them.\n */\nexport async function rollbackSegment(\n ref: SegmentRef,\n toGeneration: number,\n deps: GenerationListDeps,\n options: { audit?: IAuditSink; allowForward?: boolean } = {},\n): Promise<RollbackResult> {\n validateSegmentRef(ref);\n if (!Number.isInteger(toGeneration) || toGeneration < 0) {\n throw new ValidationError(\n `rollback: generation must be a non-negative integer; got ${String(toGeneration)}`,\n );\n }\n\n const record = await deps.registry.get(ref);\n if (record === null) {\n throw new NotFoundError(`rollback: no registry row for segment \"${ref.segment}\"`);\n }\n if (record.status === 'destroyed') {\n throw new ValidationError(\n `rollback: segment \"${ref.segment}\" is destroyed (crypto-shredded) \u2014 every generation of it is unreadable`,\n );\n }\n if (record.currentGen === toGeneration) {\n return { fromGeneration: record.currentGen, generation: toGeneration };\n }\n\n // A first look, for the affordance rather than the safety: an operator who named a collected generation needs\n // to be told what IS available, and that is much nicer to produce before anything has moved.\n const present = new Set<number>();\n for await (const key of deps.storage.list(ref)) present.add(key.generation);\n if (!present.has(toGeneration)) {\n const available = [...present].sort((a, b) => a - b);\n throw new NotFoundError(\n `rollback: generation ${toGeneration} of \"${ref.segment}\" is not in the bucket` +\n (available.length === 0\n ? ' (no generations remain)'\n : ` \u2014 present: ${available.join(', ')}`),\n );\n }\n if (\n record.currentGen !== null &&\n toGeneration > record.currentGen &&\n options.allowForward !== true\n ) {\n // Above the pointer is not \"a later version of this segment\". It is where objects live that were never\n // authoritative: a load that wrote its object and died before publishing, and a guard-refused load whose\n // cleanup was skipped because the row had changed. Rolling onto one of those makes current the very\n // generation a guard refused \u2014 an empty one, typically. The legitimate above-pointer case is undoing a\n // rollback, which is what the opt-in is for.\n throw new ValidationError(\n `rollback: generation ${toGeneration} of \"${ref.segment}\" is above the current pointer ` +\n `(${record.currentGen}) \u2014 it may never have been published. Pass { allowForward: true } if you are ` +\n `undoing an earlier rollback.`,\n );\n }\n\n // Fenced on the row this decision was made against. A rollback is the most derived write there is \u2014 an\n // operator looked at a particular state and chose \u2014 so publishing it into a row that has moved since would\n // undo whatever moved it, which is the opposite of what they asked for.\n const { token } = await deps.registry.compareAndSwap(ref, record.token, {\n currentGen: toGeneration,\n });\n\n // THE check, and it has to be here rather than above. The target is by construction at or below the old\n // pointer, which is precisely generation collection's range \u2014 and a collector never writes the row, so the\n // token fence above cannot see it coming. A listing taken before the swap therefore proves nothing: the object\n // can be collected between that listing and this swap, leaving the pointer naming a missing object.\n //\n // Once the swap lands, the target is safe \u2014 collection only ever takes what is strictly below `currentGen`,\n // and the target now IS `currentGen`. So the ordering is: move first, then verify, and put the pointer back if\n // the object went. Re-pointing can itself be raced, which is why it is fenced on the token the swap returned\n // and why failing to undo is reported rather than swallowed.\n let stillThere = false;\n for await (const key of deps.storage.list(ref)) {\n if (key.generation === toGeneration) {\n stillThere = true;\n break;\n }\n }\n if (!stillThere) {\n let undone = false;\n try {\n await deps.registry.compareAndSwap(ref, token, { currentGen: record.currentGen });\n undone = true;\n } catch {\n /* the row moved again; the throw below says the pointer was left where it is */\n }\n throw new NotFoundError(\n `rollback: generation ${toGeneration} of \"${ref.segment}\" was collected while the pointer was moving` +\n (undone\n ? ' \u2014 the pointer was put back'\n : `, and the pointer could NOT be put back: it still names ${toGeneration}. Re-run a rollback to a ` +\n 'generation that exists, or restore the object.'),\n );\n }\n\n safeAudit(options.audit ?? NOOP_AUDIT).onEvent({\n kind: 'segment.rollback',\n segment: ref.segment,\n namespace: ref.namespace,\n fromGeneration: record.currentGen,\n generation: toGeneration,\n });\n\n return { fromGeneration: record.currentGen, generation: toGeneration };\n}\n", "/**\n * Subject erasure on a loaded segment (GDPR Art. 17): remove **one id** from a segment by rewriting its current\n * generation without that id.\n *\n * There is no per-id delete on an immutable object, and there is no mutable tier to hold a tombstone, so erasure\n * is what every other write in this library is: a new generation. The current generation is streamed chunk by\n * chunk through the ascending writer \u2014 every chunk copied through, the one chunk holding the id re-encoded with\n * that bit cleared \u2014 then published fenced on the generation it streamed, and that generation is collected immediately\n * (`keep: 0`), so the bit is **physically gone from the bucket when this returns**. Constant memory: one chunk in\n * flight, never the whole segment.\n *\n * What it does NOT reach: backups, replicas and noncurrent object versions hold the old object until their own\n * lifecycle removes it. For an at-rest guarantee that survives those, use encryption plus crypto-shred\n * (`destroySegment`), which is per segment \u2014 a per-id shred is infeasible because one DEK covers the whole segment.\n *\n * Concurrency. This is a **read-modify-write**, not a plain forward-only publish, and that distinction is where\n * its correctness lives: the new generation is `from` minus one bit, so it is a valid successor to `from` and to\n * nothing else. The publish is therefore fenced on `from` **and on the row it was read from**\n * (`publishGeneration`'s `expectFrom` + `expectToken`) and lands only while the pointer is still exactly there,\n * on that same row. Both halves are needed: a generation number identifies a generation only within one\n * incarnation of a name, and a name that is retired and re-created restarts at `0`, so the number alone matched\n * a different segment entirely. Anything else \u2014 a load that published in the meantime, or another\n * erasure that got there first \u2014 is reported as `reason: 'superseded'`, `erased: false`, and the caller re-runs\n * against the new generation. A writer that claims the same generation *number* first surfaces as a\n * `WriteConflictError` (write-once).\n *\n * The same answer covers the read half, and for the same reason. An erasure collects with `keep: 0`, which takes\n * every generation below its new pointer \u2014 so a racing erasure can delete the generation this call is streaming,\n * and (once it is below the winner's pointer) the object this call just wrote. All three exposed round trips (the\n * reader open, any chunk of the whole-segment rewrite, the verify) therefore report a *reason* rather than a bare\n * `NotFoundError`, which was the same event wearing an unactionable face: through `eraseSubject` it became a note\n * the facade documents as ambiguous about which side of the publish it landed on, telling an operator to triage\n * where the truth was to re-run.\n *\n * Which reason comes from **re-reading the row**, not from assuming a supersession: a moved pointer is\n * `'superseded'`, a tombstoned row `'destroyed'`, a purged row `'absent'`, a row with no pointer\n * `'no-generation'`. A pointer still on `from` means the object it names is genuinely gone \u2014 the forbidden\n * `missing-storage-generation` state \u2014 and that throws, because no re-run fixes it. That `NotFoundError` is the only\n * signal of that state, so a faulting re-read rethrows it rather than replacing it with a transient-looking\n * registry error.\n *\n * **No orphan is left behind by a refused rewrite**, and it is worth saying why, because nothing else collects\n * above the pointer: `putImmutable` commits atomically, so a rewrite whose stream throws leaves no object at all;\n * and if the write did complete, the winner's generation is necessarily higher, which puts ours below its pointer\n * where its `keep: 0` takes it. The two orderings are mutually exclusive.\n *\n * Without that fence the failure was silent and severe, and both halves were reproduced: `nextGeneration` picks a\n * number above everything in the bucket, so a forward-only publish here always won \u2014 discarding a concurrent\n * load's whole set, and letting two concurrent erasures each return `erased: true` while the second one's\n * generation put the first one's id back and collected the generation that had evidenced its removal. A false\n * Art. 17 receipt is the worst output this module can produce.\n *\n * Readers pinned to the collected generation re-resolve on their next read; that is the documented cost of\n * physical deletion on return. **Do not re-load the id while erasing it**: a load that lands after this rewrite\n * carries whatever its source held, and the library cannot know that source was meant to exclude the id.\n */\nimport { type IAuditSink, NOOP_AUDIT, safeAudit } from './audit';\nimport { MAX_REMAINDER, splitId } from './bit-route';\nimport type { CodecBitmap, CodecInterface } from './codec';\nimport { requireCodec } from './codec';\nimport type { Yielder } from './cooperative';\nimport {\n openGenerationReader,\n publishGeneration,\n verifyGeneration,\n writeCrbmGenerationStream,\n} from './crbm-storage-source';\nimport type { CrbmReader } from './crbm/reader';\nimport { aadFor } from './crypto';\nimport type { Aead, CrbmCrypto, IKeystore } from './crypto';\nimport {\n IntegrityError,\n KeyUnavailableError,\n ValidationError,\n WriteConflictError,\n isNotFoundError,\n} from './errors';\nimport { gcOrphanGenerations, nextGeneration } from './generation-gc';\nimport type { GenKey, IStorageDriver, IRegistryDriver, RegistryRecord, SegmentRef } from './ports';\nimport { validateSegmentRef } from './validate';\n\nconst DEFAULT_MAX_BITMAP_BYTES = 1 << 20;\n\n/** What {@link eraseIdFromSegment} needs: the objects, the pointer, the codec, and the key material if encrypted. */\nexport interface EraseIdDeps {\n readonly storage: IStorageDriver;\n readonly registry: IRegistryDriver;\n /**\n * Bitmap codec \u2014 the rewrite decodes and re-encodes every chunk through it. Optional in the type so this stays\n * call-compatible public API; a **flavor** package binds it (see {@link requireCodec}).\n */\n readonly codec?: CodecInterface;\n /**\n * Keystore for an **encrypted** segment: its registry record carries wrapped DEK(s), and the rewrite reuses\n * that DEK \u2014 unwrapping it to decrypt the old generation and encrypt the new one under a `(segment, generation)`\n * -bound AAD. Rewriting an encrypted segment without a keystore throws {@link KeyUnavailableError}.\n */\n readonly keystore?: IKeystore;\n /** When true, refuse to rewrite a **cleartext** segment (the same guard the read path and bulk-load offer). */\n readonly requireEncryption?: boolean;\n /** Supplying a clock that can yield makes the rewrite cooperative \u2014 see `bulkLoadCrbmGeneration`. */\n readonly clock?: Yielder;\n /** Per-chunk decode ceiling (invariant 5); defaults to 1 MiB. */\n readonly maxBitmapBytes?: number;\n}\n\nexport interface EraseIdResult {\n readonly segment: string;\n readonly namespace?: string;\n /**\n * True iff the id **was** a member and a generation without it is now the segment's current generation \u2014 and\n * the generation that held it has been deleted (see `collected`). This is the field an erasure ledger records.\n */\n readonly erased: boolean;\n /**\n * Why nothing was rewritten, when `erased` is false. `'absent'` (no registry row), `'destroyed'` (a crypto-shred\n * tombstone \u2014 already unreadable), `'no-generation'` (a row with no Storage data yet), `'not-member'` (the id is not\n * in the current generation \u2014 the common case across a fleet scan), or `'superseded'`.\n *\n * **`'superseded'` means this call did not erase the id, not that the id is still there.** Another writer \u2014 a\n * load, or another erasure \u2014 moved the pointer off the generation this rewrite was derived from, so the\n * rewrite is not a valid successor to what is now current. Re-run against the new generation: if the id is\n * still present it is erased then; if the racing writer was another erasure of the *same* id, the re-run\n * reports `'not-member'` because it is already gone. Either way the re-run settles it, which is why it is the\n * documented action for this reason and for no other.\n *\n * The first four reasons are also returned when the row changes *underneath* a rewrite already in flight,\n * not only when it is read up front \u2014 a concurrent `dropSegment` gives `'destroyed'`, a retention sweep that\n * purges the row gives `'absent'`. A caller branching on `reason` never has to care which it was.\n */\n readonly reason?: 'absent' | 'destroyed' | 'no-generation' | 'not-member' | 'superseded';\n /** The generation the id was found in (present whenever it was read). */\n readonly fromGeneration?: number;\n /** The generation written without the id (present whenever one was written, even if `superseded`). */\n readonly generation?: number;\n /**\n * Generations deleted after the publish \u2014 normally `[fromGeneration]`, plus any older orphans. Empty when nothing\n * was rewritten. **It is what THIS call deleted, not the proof that the id is gone** \u2014 those differ: a\n * concurrent collector can take the generation holding the id first, and then `erased: true` is returned with\n * `collected` empty, because the claim is about the bucket rather than about who emptied it. Treat a\n * non-empty `collected` as evidence and an empty one as \"someone else got there\", never as a failure.\n *\n * A call that cannot establish the claim **throws** rather than report `erased: true` over bytes that are\n * still there. Three ways that happens: a Storage `delete` fault, a collection pass that could not prove the\n * segment was still the same one (`WriteConflictError`, which an ordinary retirement landing mid-call is\n * enough to cause), and the same refusal on the collect-only path below, where nothing was published at all.\n *\n * **Re-run it**, and read what the re-run says rather than assuming it finished the job. The pointer has\n * moved, so the re-run looks for the id in the *superseded* generations as well as the current one, and there\n * are three outcomes:\n *\n * - `erased: true` naming the superseded generation it found the id in and collected \u2014 the ordinary case,\n * and the one that gives you the receipt the failed call could not;\n * - `'not-member'` \u2014 a racing collector took that generation first. The bit is gone, but **no run reports a\n * receipt for it**, so keep the failed call's error alongside your ledger if you need the audit trail;\n * - `'absent'` \u2014 the segment's registry row is gone, so it is no longer a segment at all and\n * `store.eraseSubject` will not even scan it. Anything left in the bucket is an **orphan**: find it with\n * `checkConsistency()` and collect it with `gcOrphanGenerations`.\n */\n readonly collected: readonly number[];\n}\n\n/**\n * Remove `id` from `ref` by rewriting its current generation without it. See the module note for the contract.\n *\n * Emits one `segment.rewrite` audit event at the publish (before the superseded generation is collected), so the\n * compliance record exists the moment the generation without the id is authoritative.\n */\n/**\n * The receipt check. `erased: true` is a claim that the generation holding the id is **gone from the bucket**,\n * so verify exactly that, rather than trusting the collector's return value.\n *\n * A collection pass can decline for reasons that are not faults: the row was re-created underneath it (it\n * throws), or the row was already gone when it started (it returns an empty list, the same value it returns\n * when there was genuinely nothing to collect). Both are reachable in the window between this rewrite's publish\n * and its collect \u2014 a retirement only has to land in between \u2014 and neither may become a clean Art. 17 receipt.\n *\n * But the converse is just as important: a holder missing from `collected` does **not** mean it survived. A\n * concurrent collector \u2014 `gcOrphanGenerations(ref, deps, { keep: 0 })` is the call this library tells operators\n * to run \u2014 may simply have taken it first. That is not a failure of this call, it is the outcome this call\n * wanted, and the same reasoning is applied a few lines up when a superseded generation disappears mid-scan.\n * So on a miss, look: if the object is gone, the claim is true no matter who made it true.\n */\nasync function assertCollected(\n ref: SegmentRef,\n holder: number,\n collected: readonly number[],\n storage: IStorageDriver,\n): Promise<void> {\n if (collected.includes(holder)) return;\n for await (const key of storage.list(ref)) {\n if (key.generation !== holder) continue;\n throw new WriteConflictError(\n `erasure of segment ${ref.segment} could not remove generation ${holder} \u2014 the one holding the id \u2014 which is still in the bucket; re-run`,\n );\n }\n}\n\nexport async function eraseIdFromSegment(\n ref: SegmentRef,\n id: number,\n deps: EraseIdDeps,\n options: { audit?: IAuditSink } = {},\n): Promise<EraseIdResult> {\n validateSegmentRef(ref);\n const { chunkKey, remainder } = splitId(id); // validates the u32 range\n const codec = requireCodec(deps.codec, 'eraseIdFromSegment');\n const maxBytes = deps.maxBitmapBytes ?? DEFAULT_MAX_BITMAP_BYTES;\n const base = { segment: ref.segment, namespace: ref.namespace };\n\n const record = await deps.registry.get(ref);\n if (record === null) return { ...base, erased: false, reason: 'absent', collected: [] };\n if (record.status === 'destroyed')\n return { ...base, erased: false, reason: 'destroyed', collected: [] };\n if (record.currentGen === null)\n return { ...base, erased: false, reason: 'no-generation', collected: [] };\n const from = record.currentGen;\n /**\n * The row this rewrite derives its content from, not just the number it points at. `nextGeneration` restarts\n * at `0` once a row is purged and the bucket emptied, so a retired-and-re-created name presents a *different*\n * segment at the *same* `currentGen` \u2014 which `expectFrom` alone matched, republishing one incarnation's\n * content over another's and reporting `erased: true`. The token is never reused across incarnations.\n */\n const fromToken = record.token;\n\n // The segment's DEK, reused across generations. Resolved before any object I/O so a slow keystore/KMS call\n // sits outside the read-write window; an encrypted row with no keystore is a lost key, not a cleartext segment.\n let aead: Aead | undefined;\n if (record.wrappedDeks !== undefined && record.wrappedDeks.length > 0) {\n if (deps.keystore === undefined) {\n throw new KeyUnavailableError(\n `segment \"${ref.segment}\" is encrypted but eraseIdFromSegment has no keystore`,\n );\n }\n aead = await deps.keystore.openDek(record.wrappedDeks);\n } else if (deps.requireEncryption === true) {\n throw new ValidationError(`requireEncryption: segment \"${ref.segment}\" is cleartext`);\n }\n // The AAD binds each chunk/index to (segment, generation), so reading gen g and writing gen g' use distinct\n // contexts over the same DEK.\n const cryptoAt = (generation: number): CrbmCrypto | undefined =>\n aead === undefined ? undefined : { aead, aadFor: (scope) => aadFor(ref, generation, scope) };\n\n const fromKey: GenKey = { ...base, generation: from };\n const refused = (\n reason: 'superseded' | 'absent' | 'no-generation' | 'destroyed',\n generation?: number,\n ): EraseIdResult => ({\n ...base,\n erased: false,\n reason,\n fromGeneration: from,\n generation,\n collected: [],\n });\n\n /**\n * What the row says about the premise this call was working from \u2014 `null` when the premise still holds\n * (the pointer is exactly `from`, so nothing raced us), otherwise the reason to report.\n *\n * Each state gets the answer this function already gives when it reads that state *up front*, so a caller\n * branching on `reason` never has to care at which point in the call it was discovered: a tombstoned row is\n * `'destroyed'` (a concurrent `dropSegment` leaves `currentGen` where it was, so testing the pointer alone\n * would miss it and report an error for a segment the operator deliberately dropped), a vanished row is\n * `'absent'` (the retention sweep purged a tombstone while we worked), a row with no pointer is\n * `'no-generation'`, and a pointer that moved is `'superseded'`.\n */\n const rowVerdict = (\n row: RegistryRecord | null,\n ): 'superseded' | 'absent' | 'no-generation' | 'destroyed' | null => {\n if (row === null) return 'absent';\n if (row.status === 'destroyed') return 'destroyed';\n if (row.currentGen === null) return 'no-generation';\n // A different row is a different lineage even at the same pointer value \u2014 see `fromToken`.\n return row.currentGen === from && row.token === fromToken ? null : 'superseded';\n };\n\n /**\n * Read `from`, write its successor, and verify it \u2014 the read-modify-write whose premise is that the pointer is\n * still at `from`. Returns a staged generation, or the result to report if the premise stopped holding.\n *\n * **Every object this phase touches can be deleted underneath it, by a concurrent call of this very\n * function.** An erasure collects with `keep: 0`, which takes every generation below its new pointer \u2014 so a\n * racing erasure deletes `from` while we are still streaming it, and deletes *the object we just wrote* too,\n * since ours is below its pointer and can never become current. There are three separate round trips exposed:\n * the reader open, every chunk of the rewrite (a whole-segment read \u2014 by far the longest window), and the\n * verify.\n *\n * The documented answer to that race is `reason: 'superseded'` \u2014 *this call did not erase it; re-run against\n * the new generation* \u2014 and it is what the publish already reports when its `expectFrom` fence fails. A bare\n * `NotFoundError` instead is the same event wearing a different, unactionable face; through `eraseSubject` it\n * becomes a note the facade documents as ambiguous about which side of the publish it landed on, so an\n * Art. 17 operator is told *triage this* where the truth is *re-run*.\n *\n * **A `NotFoundError` is translated only after re-reading the row, and the row decides which answer.** The\n * pointer still at exactly `from` means the object it names is genuinely absent \u2014 the forbidden\n * `missing-storage-generation` state a failed publish leaves behind \u2014 and that **throws**, because it is an\n * integrity problem rather than a race and no re-run fixes it. A pointer that moved is `'superseded'`. The\n * other two states are not supersessions and are not reported as one: the row **gone** (the retention sweep\n * purged a tombstone while we worked) is `'absent'`, and a row whose `currentGen` is `null` is\n * `'no-generation'` \u2014 the same answers this function gives when it reads either state up front, so a caller\n * branching on `reason` never has to special-case where in the call it was discovered.\n *\n * `generation` is set only once the object is **durable**. Reporting it from `nextGeneration` was wrong in a\n * way worth naming: if the row is gone by then, `nextGeneration` finds no row and no objects and restarts at\n * `0`, so the ledger read `fromGeneration: 0 \u2192 generation: 0` \u2014 the generation that *held* the bit named as\n * the one written *without* it, for an object that was never written.\n */\n /**\n * The id is not in the current generation \u2014 which is **not** the same as not being in the bucket.\n *\n * A re-seed that simply stops including someone leaves their bit in the generation it dropped them from, and\n * the documented post-load call (`gcOrphanGenerations` with its default `keep: 1`) *retains* exactly that\n * generation as the reader grace window. So the ordinary lifecycle of a rotating audience leaves an\n * ex-member's bit sitting in a retained object \u2014 and the rewrite never looked there, returned `'not-member'`,\n * and `eraseSubject` filtered the segment out of the ledger entirely. A clean Art. 17 receipt over bytes\n * still in the bucket, for the one population most likely to be asking: people who already left.\n *\n * So look. If a superseded generation holds the bit, the only remedy is to delete those generations \u2014\n * they cannot be rewritten, because a rewrite of a non-current generation would regress the pointer \u2014 and\n * that is exactly what `keep: 0` does. Deleting them is safe for the same reason it is safe on the rewrite\n * path: everything below `currentGen` is permanently unreachable, so no reader can be denied an answer it\n * could otherwise have had. It costs the segment its grace window, which is proportionate: only a segment\n * that genuinely held the subject pays it.\n *\n * **The cost is paid only where it is owed.** The cheap filter comes first: one `list`, and if the segment\n * has no superseded generations at all \u2014 true of any store that collects with `keep: 0`, and of a segment\n * loaded once \u2014 nothing else is read. Then per superseded generation, the index is opened and the chunk is\n * fetched only if the index says that chunk exists. `eraseSubject` fans this out across every registered\n * segment, so the filter is what keeps a fleet-wide subject scan from doubling its reads on segments that\n * never held the id.\n */\n const notInCurrent = async (): Promise<EraseIdResult> => {\n // EVERY other generation in the bucket, not just the ones below the pointer.\n //\n // The bound used to be `< from`, on the reasoning that an object above the pointer is permanently\n // unreachable: forward-only publishing refuses to regress, so nothing up there could ever become current\n // again. `rollbackSegment` ended that \u2014 an operator can move the pointer back onto any generation still in\n // the bucket, which makes above-pointer objects reachable data. Reproduced with no race at all: roll back,\n // then erase, and the erasure reported `'not-member'` \u2014 filtered out of the subject ledger entirely, a clean\n // Art. 17 receipt \u2014 while the subject's bit sat in a generation one rollback away from being served again.\n const superseded: number[] = [];\n for await (const key of deps.storage.list(ref)) {\n if (key.generation !== from) superseded.push(key.generation);\n }\n if (superseded.length === 0) {\n return { ...base, erased: false, reason: 'not-member', fromGeneration: from, collected: [] };\n }\n superseded.sort((a, b) => b - a); // newest first: the likeliest holder of a just-dropped id\n for (const generation of superseded) {\n let held = false;\n try {\n const reader = await openGenerationReader(\n deps.storage,\n { ...base, generation },\n cryptoAt(generation),\n );\n const bytes = await reader.getChunk(chunkKey);\n if (bytes !== null) held = codec.safeDeserialize(bytes, maxBytes).has(remainder);\n } catch (err) {\n // A superseded generation swept by a concurrent collector is not a failure of this call \u2014 it is the\n // outcome this call wanted. Anything else is a real fault and must not be swallowed into a clean\n // receipt.\n if (!isNotFoundError(err)) throw err;\n continue;\n }\n if (!held) continue;\n // Found. Take every generation below the pointer; the current one keeps the id out by not having it.\n const collected = await gcOrphanGenerations(ref, deps, { keep: 0 });\n // A holder ABOVE the pointer is not in that range, so it has to go explicitly. This is the one place the\n // library deletes an above-pointer object, and it costs `rollbackSegment` a target \u2014 deliberately. A\n // rollback point that still contains data we were required to erase is not a rollback point; keeping it\n // would mean the erasure is undoable by an ordinary operator action, which is not erasure.\n const alsoCollected = [...collected];\n if (from !== null && generation > from) {\n await deps.storage.delete({ namespace: ref.namespace, segment: ref.segment, generation });\n alsoCollected.push(generation);\n }\n await assertCollected(ref, generation, alsoCollected, deps.storage);\n return { ...base, erased: true, fromGeneration: generation, collected: alsoCollected };\n }\n return { ...base, erased: false, reason: 'not-member', fromGeneration: from, collected: [] };\n };\n\n const stage = async (): Promise<EraseIdResult | { generation: number; key: GenKey }> => {\n /** Set only once the object exists in the bucket \u2014 see the note above. */\n let written: number | undefined;\n try {\n const reader = await openGenerationReader(deps.storage, fromKey, cryptoAt(from));\n const bytes = await reader.getChunk(chunkKey);\n if (bytes === null) return notInCurrent();\n const target = codec.safeDeserialize(bytes, maxBytes);\n assertRemaindersInRange(target, chunkKey); // invariant 5, on the chunk we are about to re-encode\n if (!target.has(remainder)) return notInCurrent();\n target.remove(remainder);\n\n const generation = await nextGeneration(ref, deps);\n const key: GenKey = { ...base, generation };\n const tally = await writeCrbmGenerationStream(\n deps.storage,\n key,\n rewrite(reader, chunkKey, target, codec, maxBytes),\n { crypto: cryptoAt(generation), clock: deps.clock },\n );\n written = generation; // `putImmutable` commits atomically, so the object exists exactly now\n // Re-check the pointer before spending the verification read. The fence below is what makes the publish\n // correct; this only saves a round trip on the common race, which the catch reports either way.\n const beforeVerify = await deps.registry.get(ref);\n const early = rowVerdict(beforeVerify);\n if (early !== null) return refused(early, written);\n await verifyGeneration(deps.storage, key, tally, cryptoAt(generation));\n return { generation, key };\n } catch (err) {\n if (!isNotFoundError(err)) throw err;\n // The row decides which answer this is \u2014 but only if it can be read. A re-read that faults must not\n // replace the `NotFoundError`: that error is the ONLY signal of the integrity state below, and swapping\n // it for a transient-looking registry fault loses the one thing an operator needs to see.\n let now: RegistryRecord | null;\n try {\n now = await deps.registry.get(ref);\n } catch {\n throw err;\n }\n const verdict = rowVerdict(now);\n if (verdict !== null) return refused(verdict, written);\n throw err; // the pointer still names the missing object: genuinely absent, not a race\n }\n };\n\n const staged = await stage();\n if ('erased' in staged) return staged;\n const { generation, key } = staged;\n\n // Read-modify-write, not merely forward-only, and the distinction is the whole correctness of this function.\n //\n // The new generation's content is `from` minus one bit, so it is only a valid successor to `from`. Publishing\n // it forward-only would land it over ANY newer generation, because `nextGeneration` deliberately picks a number\n // above everything in the bucket \u2014 including an object a concurrent writer just published. Two ways that went\n // wrong, both reproduced: a load that published between our read and our publish had its whole set discarded\n // and its object collected; and two concurrent erasures each returned `erased: true` with a `segment.rewrite`\n // event while the second one's generation put the FIRST one's id back, deleting the generation that had\n // evidenced its removal. A false Art. 17 receipt is the worst output this module can produce.\n //\n // `expectFrom` makes the publish land only while the pointer is still exactly `from`. The predecessor\n // (the removed `compactSegment`) had the same fence as an explicit re-read; it was lost in the move to\n // `nextGeneration`.\n //\n // Reported, not thrown \u2014 the caller re-runs against the new generation, which may or may not still hold the id.\n const published = await publishGeneration(deps.registry, key, {\n expectFrom: from,\n expectToken: fromToken,\n });\n if (!published) {\n return {\n ...base,\n erased: false,\n reason: 'superseded',\n fromGeneration: from,\n generation,\n collected: [],\n };\n }\n safeAudit(options.audit ?? NOOP_AUDIT).onEvent({\n kind: 'segment.rewrite',\n namespace: ref.namespace,\n segment: ref.segment,\n fromGeneration: from,\n generation,\n });\n // `keep: 0`: the whole point is that the generation holding the bit does not survive this call. Every\n // generation below the new pointer is safe to take, and provably so now that the publish is fenced on `from`:\n // the CAS succeeded while the pointer was still at `from`, so nothing in `(from, generation)` had been\n // published before us, and the pointer only moves forward WITHIN THIS INCARNATION \u2014 so none of them can ever\n // become current either. They are permanently unreachable, which is exactly what makes deleting them the\n // strongest form of the \"physically gone on return\" claim rather than a risk to a load that is still in\n // flight. Across incarnations the pointer CAN regress (invariant 1), which is why the collector re-proves the\n // row rather than trusting the one this call read, and why the receipt is checked below rather than assumed.\n const collected = await gcOrphanGenerations(ref, deps, { keep: 0 });\n await assertCollected(ref, from, collected, deps.storage);\n return { ...base, erased: true, fromGeneration: from, generation, collected };\n}\n\n/**\n * The new generation's chunks, ascending: every chunk of the old generation decoded and passed through, except\n * `chunkKey`, which is replaced by `replacement` (already missing the id). Decoding rather than copying bytes is\n * deliberate \u2014 it puts every chunk through the **safe** deserializer and the size cap on the one path that\n * rewrites a whole segment, so a chunk that is not decodable, or is larger than the cap, stops the rewrite\n * instead of being copied forward \u2014 and the writer skips a chunk the removal emptied. One chunk is live at a\n * time.\n *\n * Both halves of **invariant 5** apply, including the remainder range: a chunk of a 16-bit-keyed segment cannot\n * hold a value above `MAX_REMAINDER`, and one that does was not written by this codec. Carrying it forward would\n * re-encode pre-existing corruption into a brand-new object and then report `erased: true` over a segment that\n * still cannot be read \u2014 so the rewrite stops instead, naming the chunk. An `IntegrityError` here says \"this\n * segment is corrupt\", which is what the operator needs to know; a successful-looking erasure says nothing. The\n * check is one `maximum()` call per chunk against a bitmap this function has already decoded, so honouring the\n * invariant costs nothing measurable on a path that is re-encoding every chunk anyway.\n */\nasync function* rewrite(\n reader: CrbmReader,\n chunkKey: number,\n replacement: CodecBitmap,\n codec: CodecInterface,\n maxBytes: number,\n): AsyncGenerator<{ chunkKey: number; bitmap: CodecBitmap }> {\n const keys = [...reader.chunkKeys()].sort((a, b) => a - b);\n for (const k of keys) {\n if (k === chunkKey) {\n yield { chunkKey: k, bitmap: replacement };\n continue;\n }\n const bytes = await reader.getChunk(k);\n if (bytes === null) continue; // listed but absent: nothing to carry forward\n const bitmap = codec.safeDeserialize(bytes, maxBytes);\n assertRemaindersInRange(bitmap, k);\n yield { chunkKey: k, bitmap };\n }\n}\n\n/**\n * Invariant 5's range half, for one decoded chunk: every value in a chunk is a 16-bit remainder, so a value above\n * `MAX_REMAINDER` means the object was not written by this codec. `maximum()` is optional on the codec seam (a\n * codec with no size decision to make may omit it); when it is absent the check is skipped rather than faked.\n */\nfunction assertRemaindersInRange(bitmap: CodecBitmap, chunkKey: number): void {\n const max = bitmap.maximum?.();\n if (max !== undefined && max > MAX_REMAINDER) {\n throw new IntegrityError(\n `chunk ${chunkKey} payload holds value ${max}, outside the 16-bit remainder range [0, ${MAX_REMAINDER}] \u2014 ` +\n `the stored object is corrupt or was not written by this codec; refusing to carry it into a new generation`,\n );\n }\n}\n", "/**\n * Concrete AES-256-GCM crypto (lives outside `core/`, which lint-bans `node:crypto`). Implements the injected\n * {@link Aead}/{@link IKeystore} seams from `core/crypto`: a `NodeAead` over `aes-256-gcm`, and an in-process\n * **BYOK** keystore that envelope-wraps a per-segment DEK under one or more operator-held KEKs.\n *\n * Default, dependency-free key management: you bring 32-byte KEK(s); we never call a cloud service. KMS/Vault\n * are future optional adapters against the same {@link IKeystore} interface. **The KEK is the\n * one secret to back up** \u2014 lose it and that segment's at-rest bytes are unrecoverable by design (re-seed the\n * segment from your source of truth); see the getting-started \"Encryption\" section.\n */\nimport { createCipheriv, createDecipheriv, randomBytes } from 'node:crypto';\nimport type { Aead, AeadSealed, IKeystore, WrappedDek } from '../core/crypto';\nimport { IntegrityError, KeyUnavailableError, ValidationError } from '../core/errors';\n\nconst KEY_BYTES = 32; // AES-256\nconst NONCE_BYTES = 12; // GCM standard nonce\nconst TAG_BYTES = 16; // GCM tag\n\n/** AES-256-GCM AEAD bound to one 32-byte key. A fresh CSPRNG 96-bit nonce per `seal`; `aad` is authenticated,\n * never stored. Nonce-reuse safety: the random-96-bit birthday bound is ~q\u00B2/2\u2079\u2077, negligible below ~2\u00B3\u00B2 seals\n * under one key. A per-segment DEK is **reused across all generations** (every load and rewrite encrypts under it), so\n * seal count is cumulative over the segment's life \u2014 a segment approaching ~2\u00B3\u00B2 lifetime chunk-seals should be\n * re-seeded (a fresh segment \u21D2 fresh DEK). Far beyond any realistic workload; noted for completeness. */\nexport class NodeAead implements Aead {\n private readonly key: Buffer;\n\n constructor(key: Uint8Array) {\n if (key.length !== KEY_BYTES)\n throw new ValidationError(`AEAD key must be ${KEY_BYTES} bytes, got ${key.length}`);\n this.key = Buffer.from(key);\n }\n\n seal(plaintext: Uint8Array, aad: Uint8Array): AeadSealed {\n const nonce = randomBytes(NONCE_BYTES);\n const cipher = createCipheriv('aes-256-gcm', this.key, nonce);\n cipher.setAAD(aad);\n const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);\n return { nonce, ciphertext, tag: cipher.getAuthTag() };\n }\n\n open(sealed: AeadSealed, aad: Uint8Array): Uint8Array {\n if (sealed.nonce.length !== NONCE_BYTES || sealed.tag.length !== TAG_BYTES)\n throw new IntegrityError('AEAD nonce/tag have the wrong length');\n const decipher = createDecipheriv('aes-256-gcm', this.key, sealed.nonce);\n decipher.setAAD(aad);\n decipher.setAuthTag(Buffer.from(sealed.tag));\n try {\n return Buffer.concat([decipher.update(sealed.ciphertext), decipher.final()]);\n } catch {\n // Wrong key, tampered ciphertext/tag, or mismatched AAD \u2014 never leak which, never return plaintext.\n throw new IntegrityError(\n 'AEAD authentication failed (wrong key, tampered data, or wrong context)',\n );\n }\n }\n}\n\n/** Wrap/unwrap a DEK under a KEK with AES-256-GCM, binding the wrapping to its `keyId` via AAD so a wrapping\n * can't be relabelled to another KEK. Stored blob = nonce \u2016 ciphertext \u2016 tag, base64. */\nfunction wrapKey(dek: Uint8Array, kek: Uint8Array, keyId: string): string {\n const sealed = new NodeAead(kek).seal(dek, new TextEncoder().encode(keyId));\n return Buffer.concat([sealed.nonce, sealed.ciphertext, sealed.tag]).toString('base64');\n}\n\nfunction unwrapKey(wrapped: string, kek: Uint8Array, keyId: string): Uint8Array {\n const blob = Buffer.from(wrapped, 'base64');\n if (blob.length < NONCE_BYTES + TAG_BYTES)\n throw new IntegrityError('wrapped DEK is too short to be valid');\n const nonce = blob.subarray(0, NONCE_BYTES);\n const tag = blob.subarray(blob.length - TAG_BYTES);\n const ciphertext = blob.subarray(NONCE_BYTES, blob.length - TAG_BYTES);\n return new NodeAead(kek).open({ nonce, ciphertext, tag }, new TextEncoder().encode(keyId));\n}\n\n/**\n * Options for {@link InProcessKeystore}. `keys` maps a `keyId` \u2192 its 32-byte KEK; `activeKeyId` names the KEK\n * new DEKs are wrapped under; an optional `recoveryKeyId` additionally wraps each new DEK under a second\n * (e.g. offline) KEK, so losing the active KEK isn't fatal. Rotating the active KEK needs no data\n * re-encryption: add the new KEK, point `activeKeyId` at it, keep the old one to unwrap existing segments.\n */\nexport interface InProcessKeystoreOptions {\n readonly keys: Readonly<Record<string, Uint8Array>>;\n readonly activeKeyId: string;\n readonly recoveryKeyId?: string;\n}\n\n/**\n * Dependency-free BYOK keystore: envelope-wraps a fresh random per-segment DEK under the active (and optional\n * recovery) KEK using `node:crypto`. No external service. The raw DEK never leaves a returned {@link NodeAead}.\n */\nexport class InProcessKeystore implements IKeystore {\n private readonly keys: Map<string, Uint8Array>;\n private readonly activeKeyId: string;\n private readonly recoveryKeyId: string | undefined;\n\n constructor(options: InProcessKeystoreOptions) {\n const entries = Object.entries(options.keys);\n if (entries.length === 0) throw new ValidationError('keystore needs at least one KEK');\n for (const [id, k] of entries) {\n if (k.length !== KEY_BYTES)\n throw new ValidationError(`KEK \"${id}\" must be ${KEY_BYTES} bytes, got ${k.length}`);\n }\n if (!(options.activeKeyId in options.keys))\n throw new ValidationError(`activeKeyId \"${options.activeKeyId}\" is not in keys`);\n if (options.recoveryKeyId !== undefined && !(options.recoveryKeyId in options.keys))\n throw new ValidationError(`recoveryKeyId \"${options.recoveryKeyId}\" is not in keys`);\n this.keys = new Map(entries.map(([id, k]) => [id, Buffer.from(k)]));\n this.activeKeyId = options.activeKeyId;\n this.recoveryKeyId =\n options.recoveryKeyId === options.activeKeyId ? undefined : options.recoveryKeyId;\n }\n\n // async to satisfy the IKeystore seam (a KMS adapter awaits a network call here); the in-process path is\n // synchronous, but staying async keeps unwrap failures as rejections, matching a remote keystore.\n async createDek(): Promise<{ wrapped: WrappedDek[]; aead: Aead }> {\n const dek = randomBytes(KEY_BYTES);\n const ids = this.recoveryKeyId ? [this.activeKeyId, this.recoveryKeyId] : [this.activeKeyId];\n const wrapped = ids.map((keyId) => ({\n keyId,\n wrapped: wrapKey(dek, this.keys.get(keyId)!, keyId),\n }));\n return { wrapped, aead: new NodeAead(dek) };\n }\n\n // async for the same reason as createDek \u2014 a synchronous unwrap failure surfaces as a promise rejection.\n async openDek(wrapped: readonly WrappedDek[]): Promise<Aead> {\n // Try EVERY held wrapping, not just the first: a DEK is wrapped under both the active KEK and (if\n // configured) the offline recovery KEK precisely so a damaged/tampered active-KEK wrapping can be\n // recovered from the other. Returning on the first held keyId and letting a corrupt unwrap throw would\n // defeat that insurance \u2014 the recovery wrapping would never be attempted. So catch a failed unwrap and\n // fall through to the next held wrapping; only give up once none succeeds.\n let anyKekHeld = false;\n let lastUnwrapError: unknown;\n for (const w of wrapped) {\n const kek = this.keys.get(w.keyId);\n if (kek === undefined) continue;\n anyKekHeld = true;\n try {\n return new NodeAead(unwrapKey(w.wrapped, kek, w.keyId));\n } catch (err) {\n lastUnwrapError = err; // held KEK but this wrapping is corrupt/tampered \u2014 try the next one\n }\n }\n // A KEK WAS held but every held wrapping failed to unwrap \u2192 the wrapping(s) are corrupt/tampered, not\n // missing. Surface that integrity failure in its original type rather than masking it as \"no held KEK\".\n if (anyKekHeld) throw lastUnwrapError;\n const have = [...this.keys.keys()].join(', ') || '(none)';\n const need = wrapped.map((w) => w.keyId).join(', ') || '(none)';\n throw new KeyUnavailableError(\n `no held KEK can unwrap this DEK \u2014 have [${have}], wrappings reference [${need}]. ` +\n `Restore the missing KEK (or its recovery KEK), or rebuild the segment from source.`,\n );\n }\n}\n", "/**\n * Whole-segment erasure: crypto-shred (`destroySegment`, `eraseNamespace`) and disposal (`dropSegment`).\n *\n * GDPR \"right to erasure\" on immutable, backed-up storage: you can't delete a `.crbm` object from every\n * backup, but you can **delete its key**. `destroySegment` drops the segment's wrapped DEK(s) from the registry\n * (a CAS to a `destroyed` tombstone) \u2014 the encrypted Storage bytes are then permanently unreadable, everywhere,\n * forever. **Immediate + irreversible**, so it's gated behind an explicit confirmation (name the exact\n * segment/namespace). A `destroyed` segment reads as empty (its DEK is gone). Only works on an **encrypted**\n * segment; a cleartext segment has no key to shred.\n *\n * The tombstone is also the fence every writer respects: `publishGeneration` and `bulkLoadCrbmGeneration` refuse\n * a `destroyed` row, so a load racing an erasure cannot resurrect the segment. A single id's erasure is a different\n * operation \u2014 `eraseIdFromSegment` rewrites the generation without it.\n */\nimport { type IAuditSink, NOOP_AUDIT, safeAudit } from './audit';\nimport { mapWithConcurrency } from './concurrency';\nimport { ValidationError, WriteConflictError, isWriteConflictError } from './errors';\nimport type { IStorageDriver, IRegistryDriver, SegmentRef } from './ports';\n\nexport interface EraseDeps {\n readonly registry: IRegistryDriver;\n}\n\nexport interface DestroyResult {\n readonly segment: string;\n readonly namespace?: string;\n /** True iff the segment is now a `destroyed` tombstone (incl. the idempotent already-destroyed case). */\n readonly destroyed: boolean;\n /**\n * True iff **this call** performed a genuine crypto-shred \u2014 an encrypted segment whose wrapped DEK(s) were\n * dropped, so its Storage bytes are now permanently unreadable. False for a cleartext tombstone (bytes remain\n * readable), for the idempotent already-destroyed case, and for an absent segment. This is what the\n * `segment.erase` audit event keys off \u2014 a cleartext \"erase\" is not an irreversible destruction.\n */\n readonly cryptoShredded: boolean;\n /**\n * Why this segment was not a fresh crypto-shred. `'absent'` (no registry row), `'already'` (already\n * destroyed), `'cleartext'` (no DEK to shred) \u2014 and from `eraseNamespace` only, where per-segment faults are\n * isolated so one failure cannot discard the ledger: `'contended'` (the row was rewritten during every CAS\n * attempt) or `` `failed: <message>` `` (any other fault).\n *\n * The last two come with `destroyed: false` and mean **the segment still holds data**. A namespace erase\n * returns them rather than throwing, so its entries have to be inspected \u2014 see {@link eraseNamespace}.\n */\n readonly reason?: string;\n}\n\nconst MAX_CAS_ATTEMPTS = 8;\n/**\n * Storage deletes in flight at once. Erasure is a fan-out over *independent* keys, so serial would pay one\n * round-trip per generation for work that has no ordering between items; unbounded would be a self-inflicted\n * thundering herd against one bucket. Not configurable: an admin path called by a human or a nightly job.\n */\nconst ERASE_CONCURRENCY = 8;\n/**\n * Storage list-then-delete passes a drop will make before giving up and reporting the residual.\n *\n * Two is the honest floor and three is the working value: pass 1 clears what was there, pass 2 catches an object\n * a load was still writing when the tombstone landed (its publish is then refused, but the object write\n * completes), pass 3 covers a second such writer. It terminates regardless \u2014 the tombstone hard-fences\n * *publishing* a new generation, so the supply of late objects is whatever was already mid-write, and any\n * residual is reported rather than silently dropped.\n */\nconst MAX_STORAGE_SWEEPS = 3;\n\n/**\n * Crypto-shred one segment. **Irreversible.** `confirmSegment` must equal `ref.segment` (a guard against an\n * accidental destroy \u2014 you must name the exact segment). A non-encrypted segment is rejected unless you opt in\n * via `allowCleartext` (there's no key to shred; its Storage bytes stay readable \u2014 the tombstone only stops the\n * segment resolving).\n */\nexport async function destroySegment(\n ref: SegmentRef,\n deps: EraseDeps,\n options: { confirmSegment: string; allowCleartext?: boolean; audit?: IAuditSink },\n): Promise<DestroyResult> {\n if (options.confirmSegment !== ref.segment) {\n throw new ValidationError(\n `destroySegment: confirmSegment must equal the segment name \"${ref.segment}\" (guard against accidental crypto-shred)`,\n );\n }\n const result = await shredSegment(ref, deps, options.allowCleartext ?? false);\n // Audit only a genuine crypto-shred \u2014 not the idempotent already-destroyed/absent no-ops, and not a\n // cleartext tombstone (whose Storage bytes stay readable, so it is not an irreversible erasure).\n if (result.cryptoShredded) {\n safeAudit(options.audit ?? NOOP_AUDIT).onEvent({\n kind: 'segment.erase',\n namespace: ref.namespace,\n segment: ref.segment,\n });\n }\n return result;\n}\n\n/**\n * Crypto-shred every segment in a namespace. **Irreversible.** `confirmNamespace` must equal `namespace`.\n * Returns a per-segment result (skips cleartext segments unless `allowCleartext`).\n */\nexport async function eraseNamespace(\n namespace: string,\n deps: EraseDeps,\n options: { confirmNamespace: string; allowCleartext?: boolean; audit?: IAuditSink },\n): Promise<{ destroyed: DestroyResult[] }> {\n if (typeof namespace !== 'string' || namespace.length === 0) {\n throw new ValidationError('eraseNamespace: namespace must be a non-empty string');\n }\n if (options.confirmNamespace !== namespace) {\n throw new ValidationError(\n `eraseNamespace: confirmNamespace must equal the namespace \"${namespace}\" (guard against accidental erasure)`,\n );\n }\n const refs: SegmentRef[] = [];\n for await (const rec of deps.registry.list(namespace)) {\n refs.push({ namespace: rec.namespace, segment: rec.segment });\n }\n const audit = safeAudit(options.audit ?? NOOP_AUDIT);\n const destroyed: DestroyResult[] = [];\n let segmentsShredded = 0;\n for (const ref of refs) {\n // Per-segment faults stay isolated so one failure cannot discard the ledger, mirroring `eraseSubject`'s\n // entries (\"one failure never aborts the ledger\") and for the same reason: on an erasure command the\n // caller's load-bearing question is *which segments are now destroyed*, and an exception thrown from the\n // middle of the loop answers it for none of them while having already destroyed some.\n //\n // Every error is caught, not just contention \u2014 again matching `eraseSubject`, which records any thrown\n // fault as a ledger entry rather than deciding which faults deserve a record. A `KeyUnavailableError` on\n // segment 3 is exactly as important to report as a `WriteConflictError`, and just as segment-local.\n //\n // NOTE the caller's obligation, because this is quieter than a throw: entries must be INSPECTED.\n // `destroyed: false` with a `reason` is a segment that still holds data. The `namespace.erase` audit event\n // carries the honest `segmentsShredded` count, which will be lower than the segment count, so an audit\n // trail still shows the shortfall even if the return value is ignored.\n let result: DestroyResult;\n try {\n result = await shredSegment(ref, deps, options.allowCleartext ?? false);\n } catch (err) {\n result = {\n segment: ref.segment,\n namespace: ref.namespace,\n destroyed: false,\n cryptoShredded: false,\n reason: isWriteConflictError(err)\n ? 'contended'\n : `failed: ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n destroyed.push(result);\n // A per-segment record for each genuine crypto-shred, so the trail can prove *which* segments were\n // destroyed (each carries the namespace) \u2014 not just that the command ran.\n if (result.cryptoShredded) {\n segmentsShredded += 1;\n audit.onEvent({ kind: 'segment.erase', namespace: ref.namespace, segment: ref.segment });\n }\n }\n // Plus one namespace-level record of the erasure command, carrying the honest count actually shredded\n // (may be 0 \u2014 e.g. an empty namespace, or all-cleartext without `allowCleartext`): the command ran, but\n // the count keeps the record from over-attesting a destruction that did not happen.\n audit.onEvent({ kind: 'namespace.erase', namespace, segmentsShredded });\n return { destroyed };\n}\n\n/**\n * Deps for {@link dropSegment}. Adds `storage`, because unlike a crypto-shred this one deletes the objects.\n */\nexport interface DropDeps extends EraseDeps {\n readonly storage: IStorageDriver;\n}\n\nexport interface DropResult {\n readonly segment: string;\n readonly namespace?: string;\n /**\n * **True iff this segment is now empty as a result of this call \u2014 or already was.** This is the field a\n * retention job should branch on: `false` means the call found nothing to do and your ref is probably wrong.\n */\n readonly dropped: boolean;\n /** Storage generations physically deleted, ascending. Empty on a dry run \u2014 see {@link DropResult.wouldDelete}. */\n readonly generationsDeleted: readonly number[];\n /**\n * Generations still present in Storage when the sweep gave up, ascending. **Empty is the normal outcome** \u2014 a\n * non-empty value means the storage was NOT fully reclaimed and the drop should be re-run.\n *\n * This field exists because its absence was a defect. A drop used to return `dropped: true` with a populated\n * `generationsDeleted` and no `reason` even when an object holding the **complete set** had just been left in\n * the bucket by a writer that was already mid-write when the tombstone landed (its publish is refused, but the\n * object survives). For a cleartext segment those bytes are readable \u2014 and `gcOrphanGenerations` only collects\n * a destroyed segment's generations when something runs it. The result was indistinguishable from a clean\n * drop, so an operator got no signal to re-run. Now they do.\n */\n readonly generationsRemaining: readonly number[];\n /**\n * On a dry run, the generations that **would** be deleted. `undefined` on a real run.\n *\n * This exists because the confirmation guard the erasure calls use \u2014 naming the segment twice \u2014 protects a\n * hand-typed literal and nothing else. In the loop this operation is actually *for*\n * (`for (const day of expired) drop({segment: day}, {confirmSegment: day})`) the same variable appears twice\n * and the guard is pure ceremony. A dry run is the guard that still works when a machine is calling.\n *\n * It is a **snapshot**: a later real run can see a different set.\n */\n readonly wouldDelete?: readonly number[];\n /**\n * On a dry run, whether the real drop would **also** crypto-shred (i.e. the segment is encrypted).\n * `undefined` on a real run. This is the one fact in the preview that is irreversible *everywhere*, backups\n * included \u2014 a dry run that did not surface it was previewing the recoverable half only.\n */\n readonly wouldCryptoShred?: boolean;\n /**\n * True iff the segment was encrypted and its wrapped DEK(s) were dropped as part of this call \u2014 so its bytes\n * are unreadable *everywhere*, backups included, not merely deleted from the bucket. Deleting an object does\n * not reach a noncurrent version, a replica, or a PITR snapshot; discarding the key does.\n */\n readonly cryptoShredded: boolean;\n /**\n * How the segment got to its current state. Absent on a fresh, ordinary drop (tombstone written, Storage swept).\n *\n * - `'already'` \u2014 it was already a tombstone. Idempotent; pairs with `dropped: true`. A re-drop is **not** a\n * no-op \u2014 it re-sweeps Storage, so it is how a residual in `generationsRemaining` is collected.\n * - `'absent'` \u2014 **nothing existed.** No registry row and no Storage objects. Pairs with `dropped: false`, and it\n * is the one value worth alerting on: the usual cause is a mistyped name or an omitted `namespace`, both of\n * which address a *different* segment than you meant.\n */\n readonly reason?: string;\n}\n\n/**\n * **Dispose of a segment: tombstone it, then delete its Storage objects.** Irreversible.\n *\n * WHY THIS EXISTS, given {@link destroySegment} already erases. Because `destroySegment` answers a *compliance*\n * question and this one answers an *operational* question, and they are not the same:\n *\n * - `destroySegment` **crypto-shreds** \u2014 it discards the key so the bytes are unreadable everywhere including\n * immutable backups, which is the only erasure that survives WORM. But it **leaves the objects in the\n * bucket**, still billed, and it *requires* encryption because a cleartext segment has no key to discard.\n * - `dropSegment` **removes the storage**. It works on a cleartext segment, and on an encrypted one it *also*\n * drops the DEKs, so it is a strict superset there.\n *\n * Before this existed there was no supported way to delete a segment and stop paying for it, and the obvious\n * workaround \u2014 an object-store lifecycle rule on the key prefix \u2014 deletes the bytes while the registry still\n * points at them. That is exactly the `missing-storage-generation` state the DR runbook says not to serve traffic\n * on, and it surfaces *intermittently*, because a read consults the cache before Storage: cached chunks answer\n * correctly and evicted ones throw. The whole value of this function is that the ordering below cannot be got\n * wrong by a caller.\n *\n * **THE ORDER IS THE CONTRACT \u2014 registry first, then Storage.**\n *\n * 1. **Registry first.** After the tombstone nothing resolves a generation for this segment, so no reader can\n * reach for bytes that are about to disappear, and no writer can publish onto it (`publishGeneration` and\n * `bulkLoadCrbmGeneration` refuse a `destroyed` row).\n * 2. **Storage second, best-effort, and re-swept.** Once the pointer is a tombstone the segment resolves as empty,\n * so a failure part-way through leaves **orphaned bytes, not a wrong answer.** Orphans cost money and are\n * cleaned up by re-running; a torn pointer costs correctness and is not self-healing. Given the choice, leak\n * bytes \u2014 but say so: whatever survives the sweep is reported in {@link DropResult.generationsRemaining}.\n *\n * **Why step 2 sweeps more than once.** A load that was already writing its object when the tombstone landed\n * still finishes the write \u2014 its publish is then refused, but the object survives, and it holds the complete\n * set. A single list-then-delete misses it entirely. The re-sweep converges because the tombstone *is* a hard\n * fence on **publishing**, so only already-in-flight writes can appear and they are finite.\n *\n * **When \"reads as empty\" starts being true.** Not instantly, for a store that has already read this segment: a\n * resolved generation is cached and decoded chunks sit in the cache, so an in-flight reader can answer from\n * cache for a window. A fresh store, or any reader that had not touched the segment, sees empty at once.\n *\n * That window is bounded by `cache.genTtlMs` (default 2 s) **only for a reader whose storage source has both a clock\n * and a registry and a positive TTL** \u2014 expiry needs all three. A source built without a clock, or with\n * `cache.genTtlMs: 0` (documented as \"pin forever\"), holds its resolved snapshot for its own lifetime; because a\n * cache-LRU hit never reaches Storage, such a reader can answer `true` for a dropped segment **indefinitely** and must\n * be restarted. This is the *same* caching that makes the delete-bytes-first ordering fail intermittently rather\n * than loudly \u2014 it cuts both ways.\n *\n * `confirmSegment` must equal `ref.segment`, matching `destroySegment`/`eraseNamespace`. For an automated\n * caller that guard is ceremony \u2014 use `dryRun` first, which reports what would go without touching anything.\n */\nexport async function dropSegment(\n ref: SegmentRef,\n deps: DropDeps,\n options: { confirmSegment: string; dryRun?: boolean; audit?: IAuditSink },\n): Promise<DropResult> {\n if (options.confirmSegment !== ref.segment) {\n throw new ValidationError(\n `dropSegment: confirmSegment must equal the segment name \"${ref.segment}\" (guard against accidental deletion)`,\n );\n }\n const base = { segment: ref.segment, namespace: ref.namespace };\n\n if (options.dryRun === true) {\n const record = await deps.registry.get(ref);\n const wouldDelete = await listGenerations(deps.storage, ref);\n return {\n ...base,\n dropped: false,\n generationsDeleted: [],\n generationsRemaining: [],\n wouldDelete,\n wouldCryptoShred: record?.wrappedDeks !== undefined && record.wrappedDeks.length > 0,\n cryptoShredded: false,\n reason:\n record === null\n ? wouldDelete.length === 0\n ? 'absent'\n : undefined\n : record.status === 'destroyed'\n ? 'already'\n : undefined,\n };\n }\n\n // Step 1, reused wholesale. `allowCleartext` is true because deleting objects does not need a key \u2014 the\n // encryption requirement belongs to crypto-shred, not to disposal.\n let shred = await shredSegment(ref, deps, true, 'dropSegment');\n\n // \u2500\u2500 THE ABSENT CASE. \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // `shredSegment` returns `absent` having written NOTHING when there is no registry row \u2014 and this function used\n // to go on and delete every Storage generation anyway. That skipped the one step that makes the ordering safe\n // while still running the destructive one: a drop landing between a load's object write and its publish\n // (minutes apart on a large load) left a published pointer with no object behind it \u2014 precisely the\n // `missing-storage-generation` state this function exists to PREVENT.\n //\n // The fix is to claim the identity before deleting anything. A `destroyed` row is exactly the fence the\n // writers already respect \u2014 `publishGeneration` and `bulkLoadCrbmGeneration` both refuse one \u2014 so creating it\n // converts the race into \"the writer is refused and the bytes are collected\".\n //\n // Only when Storage actually holds something, though. A drop against a *genuinely* nonexistent segment (the\n // typo the facade docs warn about) must not leave a `destroyed` row behind: that is registry litter, and worse,\n // it would refuse a later legitimate load of that name forever. No row and no objects \u21D2 nothing existed \u21D2 say\n // `absent` and touch nothing, which is what that reason has always been documented to mean.\n if (shred.reason === 'absent') {\n const orphans = await listGenerations(deps.storage, ref);\n if (orphans.length === 0) {\n return {\n ...base,\n dropped: false,\n generationsDeleted: [],\n generationsRemaining: [],\n cryptoShredded: false,\n reason: 'absent',\n };\n }\n try {\n await deps.registry.create(ref, {\n // The max listed generation, so the row is consistent with what is on disk if anything reads it before\n // the sweep finishes. It is a tombstone, so no reader resolves through it either way.\n currentGen: orphans[orphans.length - 1]!,\n status: 'destroyed',\n });\n shred = { ...shred, destroyed: true, reason: undefined };\n } catch (err) {\n if (!isWriteConflictError(err)) throw err;\n // A row appeared between our `get` and our `create` \u2014 that is the racing writer we were trying to fence,\n // and it won. Fall back into the normal path, which now has a row to CAS into a tombstone.\n shred = await shredSegment(ref, deps, true, 'dropSegment');\n }\n }\n\n // `segment.erase` ONLY on a genuine crypto-shred \u2014 exactly the condition `destroySegment` uses, and\n // deliberately NOT `|| generationsDeleted.length > 0`.\n //\n // It read that way in the first draft, and it was wrong in a way that matters. Four documents \u2014 including\n // `docs/guide/dashboards.md`, which calls this event the compliance *receipt* \u2014 define `segment.erase` as\n // proof of an irreversible crypto-shred: bytes unreadable everywhere, backups included. Deleting an object is\n // a weaker guarantee, because a noncurrent version, a cross-region replica or a PITR snapshot still holds the\n // cleartext. Emitting one event for both would make a compliance dashboard **over-attest**, which is the one\n // failure an audit trail exists to prevent.\n //\n // The cleartext case is NOT silent \u2014 it emits `segment.dispose` after the sweep (below). That kind exists\n // precisely so this one does not have to lie: disposal is attested as disposal, shredding as shredding, and an\n // encrypted drop emits both because both genuinely happened.\n //\n // And it goes out BEFORE the Storage sweep, not after. A genuine crypto-shred is complete the moment\n // `shredSegment` returns \u2014 the DEK wrappings are gone and the bytes are unreadable everywhere. If the sweep\n // then throws (a Storage driver that cannot list), emitting afterwards would mean **no receipt for a destruction\n // that really happened** \u2014 the exact mirror of the over-attestation above, and just as wrong. Both directions\n // of a false audit trail are defects; only one of them was obvious.\n if (shred.cryptoShredded) {\n safeAudit(options.audit ?? NOOP_AUDIT).onEvent({\n kind: 'segment.erase',\n namespace: ref.namespace,\n segment: ref.segment,\n });\n }\n\n // Step 2, swept until Storage comes back empty. See \"Why step 2 sweeps more than once\" above. `mapWithConcurrency`\n // returns results in *input* order, so each pass contributes ascending generations and the concatenation stays\n // ascending. Failures are swallowed per item so the pool never aborts \u2014 one unreachable generation must not\n // leave the rest orphaned too.\n const generationsDeleted: number[] = [];\n for (let pass = 0; pass < MAX_STORAGE_SWEEPS; pass++) {\n const present = await listGenerations(deps.storage, ref);\n if (present.length === 0) break;\n const outcomes = await mapWithConcurrency(present, ERASE_CONCURRENCY, async (generation) => {\n try {\n await deps.storage.delete({ ...ref, generation });\n return generation;\n } catch {\n // Leave it orphaned. The segment already reads as empty, so this is a billing problem, not a\n // correctness one, and re-running the drop collects whatever was missed.\n return null;\n }\n });\n let deletedThisPass = 0;\n for (const g of outcomes) {\n if (g !== null) {\n generationsDeleted.push(g);\n deletedThisPass += 1;\n }\n }\n if (deletedThisPass === 0) break; // nothing went \u2014 another pass will not help\n }\n // Enumerate once more rather than inferring the residual from the last pass, so the reported value is exactly\n // what is still in Storage whichever way the loop ended: empty, a delete that kept failing, or the pass budget\n // exhausted while a writer kept finishing. Inferring it would report `[]` in precisely the case that matters\n // \u2014 a final pass that deleted everything it saw, after which one more object appeared.\n const generationsRemaining = await listGenerations(deps.storage, ref);\n\n // `segment.dispose` attests the *storage reclamation*, which is the weaker but still compliance-relevant fact,\n // and it is emitted AFTER the sweep because unlike a crypto-shred it is not established until the sweep runs.\n // Only when a tombstone was actually written \u2014 an absent no-op disposed of nothing.\n if (shred.destroyed) {\n safeAudit(options.audit ?? NOOP_AUDIT).onEvent({\n kind: 'segment.dispose',\n namespace: ref.namespace,\n segment: ref.segment,\n generationsDeleted: generationsDeleted.length,\n });\n }\n\n return {\n ...base,\n dropped: shred.destroyed,\n generationsDeleted,\n generationsRemaining,\n cryptoShredded: shred.cryptoShredded,\n reason: shred.reason,\n };\n}\n\n/**\n * Every generation currently present in Storage for a segment, ascending.\n *\n * No error handling on purpose: `IStorageDriver.list` is mandatory (not optional in `ports.ts`), so a driver that\n * cannot list cannot exist, and one that *throws* from `list` should propagate.\n *\n * **Be precise about what a throw means at each call site.** From the `dryRun` branch it is accurate that the\n * call \"has established nothing\". From the real run it is NOT: by then the tombstone is written, so the segment\n * IS dropped and only the bytes leaked. The throw is still the right behaviour \u2014 it is the signal to re-run, and\n * a re-run takes the `'already'` path and re-attempts the sweep \u2014 but a caller who logs \"drop failed\" is wrong\n * about the segment's state. This is also why the audit event is emitted *before* the sweep: an irreversible\n * crypto-shred that really happened must not go unrecorded because a later, weaker step threw.\n */\nasync function listGenerations(storage: IStorageDriver, ref: SegmentRef): Promise<number[]> {\n const generations: number[] = [];\n for await (const key of storage.list(ref)) generations.push(key.generation);\n return generations.sort((a, b) => a - b);\n}\n\n/**\n * The shred itself: CAS the registry row to a `destroyed` tombstone with no wrappings.\n *\n * `op` is only for error text \u2014 `destroySegment` and `dropSegment` both come through here, and a message naming\n * the wrong one is operator-facing text on the single path where the operator must act.\n */\nasync function shredSegment(\n ref: SegmentRef,\n deps: EraseDeps,\n allowCleartext: boolean,\n op: 'destroySegment' | 'dropSegment' = 'destroySegment',\n): Promise<DestroyResult> {\n const base = { segment: ref.segment, namespace: ref.namespace };\n for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {\n const record = await deps.registry.get(ref);\n if (record === null) {\n // No authoritative row \u2192 nothing to crypto-shred.\n return { ...base, destroyed: false, cryptoShredded: false, reason: 'absent' };\n }\n if (record.status === 'destroyed') {\n return { ...base, destroyed: true, cryptoShredded: false, reason: 'already' };\n }\n const encrypted = record.wrappedDeks !== undefined && record.wrappedDeks.length > 0;\n if (!encrypted && !allowCleartext) {\n return { ...base, destroyed: false, cryptoShredded: false, reason: 'cleartext' };\n }\n try {\n await deps.registry.compareAndSwap(ref, record.token, {\n status: 'destroyed',\n wrappedDeks: undefined, // \u2190 the crypto-shred: the only copy of the DEK wrappings is gone\n keyId: undefined,\n });\n // A genuine crypto-shred only when there were wrappings to drop; a cleartext opt-in tombstone leaves the\n // Storage bytes readable, so it is not an irreversible destruction (and does not emit `segment.erase`).\n return { ...base, destroyed: true, cryptoShredded: encrypted };\n } catch (err) {\n if (!isWriteConflictError(err)) throw err;\n // A concurrent publish or policy write advanced the row \u2014 re-read and shred again (it always converges).\n }\n }\n throw new WriteConflictError(`${op}: contention shredding \"${ref.segment}\" \u2014 retry`);\n}\n", "/**\n * Segment retention policy \u2014 **when** a segment becomes eligible for retirement.\n *\n * This module only *records and reads the intent*. Nothing here deletes anything, and nothing here runs on a\n * timer: setting a policy is one registry write, and the sweep that acts on it (`retireExpired`) is a separate\n * call the operator schedules. That split is deliberate \u2014 see the \"who owns what\" note below.\n *\n * **The expiry is an absolute epoch-ms the writer sets, not a duration the library derives.** A relative TTL\n * anchored to anything the library knows would be wrong: every load republishes `currentGen` and touches\n * `updatedAt`, so a \"30 days since last write\" rule would keep a daily bucket alive forever precisely because\n * it keeps being reloaded. The caller who knows what the segment *means* computes the instant:\n *\n * ```ts\n * const DAY = 86_400_000;\n * await store.setRetention({ namespace: 'active-daily', segment: '2026-08-05' }, {\n * expiresAt: Date.now() + 30 * DAY,\n * });\n * ```\n *\n * **Who owns what.** The library owns the policy field, its validation, and the sweep that acts on it. **You own\n * the heartbeat** \u2014 an EventBridge rule, a Kubernetes CronJob, `cron`, a queue consumer, whatever already runs in\n * your deployment. There is no background thread here, and there will not be one: this library runs in a Lambda,\n * an edge isolate and a long-lived server alike, and a timer that only works in one of those is worse than none.\n *\n * **Storage.** The policy lives in the registry row's free-form `retention` metadata, which already round-trips\n * through every driver and is carried by `list()` \u2014 so a fleet-wide sweep reads it from the enumeration with no\n * per-segment `get()`. A segment that has no row yet (a policy recorded before the first load) gets one, with\n * `currentGen: null`: the row exists so the segment is *enumerable*, and it claims no Storage generation, so every\n * read answers empty until the first load publishes onto it.\n */\nimport { ValidationError, WriteConflictError, isWriteConflictError } from './errors';\nimport { canIndex, dueBucket, dueIndexRef } from './due-index';\nimport type { GovernanceMeta, IRegistryDriver, RegistryRecord, SegmentRef } from './ports';\n\n/** The key the policy is stored under inside the row's `retention` metadata. */\nconst EXPIRES_AT = 'expiresAt';\n\n/** How many times a policy write re-reads and retries under contention before reporting a conflict. */\nconst RETENTION_CAS_ATTEMPTS = 5;\n\n/**\n * The smallest accepted `expiresAt`: 2001-09-09, the point below which an epoch-**seconds** value would land.\n *\n * This is a deliberate guard against the single most damaging typo available here. `Date.now() / 1000 + 30 * 86400`\n * is a natural thing to write, and it produces a number ~1.8 billion \u2014 an instant in **1970**, which is to say\n * *already expired*. Without this check, that typo is not a validation error, it is a sweep that retires the\n * segment on its very next pass. Anything below this floor is far likelier to be seconds than a genuine intent to\n * expire a segment two decades ago, and the caller who really means \"retire it now\" can say so with `dropSegment`.\n */\nexport const MIN_EXPIRES_AT_MS = 1_000_000_000_000;\n\n/** A segment's retention policy: the instant it becomes eligible for retirement. */\nexport interface RetentionPolicy {\n /**\n * Absolute epoch-**milliseconds**. Once `now >= expiresAt`, a retention sweep may retire the segment \u2014 tombstone\n * it and delete its Storage generations. A value in the past is legal (backfilling a policy onto existing\n * buckets is a normal thing to do) and means \"eligible on the next sweep\".\n */\n readonly expiresAt: number;\n}\n\nexport interface RetentionDeps {\n readonly registry: IRegistryDriver;\n}\n\nexport interface SetRetentionResult {\n readonly segment: string;\n readonly namespace?: string;\n /** The policy now stored on the row. */\n readonly expiresAt: number;\n /**\n * True iff this call **minted the registry row** \u2014 a policy recorded before the segment's first load. The\n * segment is now enumerable by `registry.list()` and therefore by every fleet-wide operation; the row claims no\n * Storage generation (`currentGen: null`), so reads answer empty until the first load publishes onto it.\n */\n readonly createdRow: boolean;\n /**\n * True iff the **due-index pointer** for this policy was written, so a fast sweep will find this segment by\n * reading only its expiry day instead of scanning the fleet.\n *\n * `false` is a **degradation, not an error**, and the policy is committed either way: either the ref is too\n * long to encode into one index-row name, or the pointer write failed. The full-scan repair pass still sees\n * the segment's own row, so it is retired on the repair cadence rather than the fast one \u2014 slower, never\n * never. Alarm on a *sustained* run of `false`, not on one.\n */\n readonly indexed: boolean;\n}\n\n/** Fail-fast validation of a caller-supplied policy. Boundary check \u2014 untrusted-input posture. */\nfunction validateRetentionPolicy(policy: RetentionPolicy): void {\n const { expiresAt } = policy;\n if (typeof expiresAt !== 'number' || !Number.isInteger(expiresAt)) {\n throw new ValidationError(\n `retention.expiresAt must be an integer epoch-ms; got ${String(expiresAt)}`,\n );\n }\n if (expiresAt < MIN_EXPIRES_AT_MS) {\n throw new ValidationError(\n `retention.expiresAt (${expiresAt}) is before ${MIN_EXPIRES_AT_MS} \u2014 that is almost certainly epoch ` +\n `SECONDS rather than milliseconds, which would read as \"already expired\" and retire the segment on the ` +\n `next sweep. Use \\`Date.now() + days * 86_400_000\\`. To retire a segment now, call \\`dropSegment\\`.`,\n );\n }\n}\n\n/**\n * Read the policy off a registry row's `retention` metadata. Returns `null` when there is no policy, and\n * `'invalid'` when the key is present but unusable (wrong type, or below the epoch-seconds floor).\n *\n * The three-way answer exists so a fleet sweep can *report* a malformed policy instead of choosing between two\n * bad options: treating it as \"no policy\" hides an operator error on a segment someone believes is expiring, and\n * throwing aborts a ledger over one bad row. Nothing writes an invalid policy through\n * {@link setSegmentRetention} \u2014 hand-edited rows, an older/newer writer, or a restore are how it happens.\n */\nexport function readRetentionPolicy(\n meta: GovernanceMeta | undefined,\n): RetentionPolicy | null | 'invalid' {\n if (meta === undefined) return null;\n // Guard the CONTAINER before the `in` test, not just the value inside it. `in` dereferences its operand, so a\n // stored `retention` of `null` (or a string, a number, an array) threw an untyped `TypeError` from here \u2014 and a\n // fleet sweep calls this *outside* its per-segment `try`, so one malformed row aborted the whole sweep and the\n // healthy expired segment next to it was never retired. That is precisely the outcome the three-way answer\n // exists to prevent. Both registry boundaries now reject a non-object blob, so this is the third line of defence\n // rather than the only one \u2014 but it is the one that keeps a ledger alive.\n if (meta === null || typeof meta !== 'object' || Array.isArray(meta)) return 'invalid';\n if (!(EXPIRES_AT in meta)) return null;\n const raw = meta[EXPIRES_AT];\n if (typeof raw !== 'number' || !Number.isInteger(raw) || raw < MIN_EXPIRES_AT_MS)\n return 'invalid';\n return { expiresAt: raw };\n}\n\n/** The stored policy for one segment, or `null` if it has none (and `'invalid'` for a malformed one). */\nexport async function getSegmentRetention(\n ref: SegmentRef,\n deps: RetentionDeps,\n): Promise<RetentionPolicy | null | 'invalid'> {\n const record = await deps.registry.get(ref);\n if (record === null || record.status === 'destroyed') return null;\n return readRetentionPolicy(record.retention);\n}\n\n/**\n * Record when a segment becomes eligible for retirement, creating its registry row if it has none.\n *\n * Idempotent and safe to re-run: writing the same instant twice is a no-op in effect. Other keys already in the\n * row's `retention` metadata are preserved \u2014 this owns one key, not the whole object.\n *\n * Refuses a `destroyed` segment: a tombstone has nothing left to retire, and putting a policy on one would make\n * a sweep repeatedly \"retire\" bytes that are already gone.\n */\n/** The expiry currently recorded on a row, if any \u2014 the input to deciding which old pointer to remove. */\nfunction readExpiresAt(record: { retention?: GovernanceMeta } | null): number | undefined {\n const parsed = record === null ? null : readRetentionPolicy(record.retention);\n return parsed === null || parsed === 'invalid' ? undefined : parsed.expiresAt;\n}\n\n/**\n * Move the due-index pointer to match a policy change: add the new bucket's pointer, drop the old one.\n *\n * **Best-effort by construction, and that is the design rather than a shortcut.** The policy is already\n * committed when this runs, and the index is a fast path that nothing depends on for correctness \u2014 a pointer\n * that fails to appear costs a repair-cadence delay, and one that fails to disappear costs a single wasted read\n * when its bucket comes due (the sweep re-reads the live row and skips). So a failure here must never turn a\n * successful policy write into a thrown error; it is reported through `indexed` instead.\n *\n * Order matters the other way round from intuition: the **new pointer is written first**. Interrupted between\n * the two writes, the segment is then reachable from both buckets \u2014 a duplicate the sweep handles by re-reading\n * \u2014 whereas the reverse order would leave a window in which it is reachable from neither.\n */\nasync function reindex(\n ref: SegmentRef,\n deps: RetentionDeps,\n expiresAt: number | undefined,\n previousExpiresAt: number | undefined,\n): Promise<boolean> {\n // Not independently observable: `dueIndexRef` would throw for the same refs and the catch below would swallow\n // it to the same `indexed: false`. Kept because relying on a thrown ValidationError for ordinary control flow\n // reads as an accident, and because it keeps a programming condition out of a try block whose catch exists for\n // I/O failures. No mutation kills it, and that is a property of the equivalence, not of the tests.\n if (!canIndex(ref)) return false;\n const nextBucket = expiresAt === undefined ? undefined : dueBucket(expiresAt);\n const oldBucket = previousExpiresAt === undefined ? undefined : dueBucket(previousExpiresAt);\n let indexed = expiresAt === undefined;\n if (nextBucket !== undefined) {\n try {\n await deps.registry.create(dueIndexRef(nextBucket, ref), { currentGen: null });\n indexed = true;\n } catch (err) {\n // Already there \u2014 the pointer is idempotent, and a second policy write in the same day is the common case.\n if (isWriteConflictError(err)) indexed = true;\n }\n }\n if (oldBucket !== undefined && oldBucket !== nextBucket) {\n try {\n await deps.registry.delete(dueIndexRef(oldBucket, ref));\n } catch {\n // A pointer left behind is read once, when its bucket comes due, and skipped. Nothing to recover.\n }\n }\n return indexed;\n}\n\nexport async function setSegmentRetention(\n ref: SegmentRef,\n deps: RetentionDeps,\n policy: RetentionPolicy,\n): Promise<SetRetentionResult> {\n validateRetentionPolicy(policy);\n const base = { segment: ref.segment, namespace: ref.namespace };\n /** The bucket this segment was already in, if any \u2014 its pointer has to be removed when the expiry moves. */\n let previousExpiresAt: number | undefined;\n for (let attempt = 0; attempt < RETENTION_CAS_ATTEMPTS; attempt += 1) {\n const record = await deps.registry.get(ref);\n try {\n previousExpiresAt = readExpiresAt(record);\n if (record === null) {\n // A policy ahead of the first load. `currentGen: null` is what makes this safe: the row exists purely so\n // the segment is enumerable, and it claims no Storage generation, so generation resolution takes the same\n // path it takes for a segment with no row at all \u2014 and the first publish advances it.\n await deps.registry.create(ref, {\n currentGen: null,\n retention: { [EXPIRES_AT]: policy.expiresAt },\n });\n return {\n ...base,\n expiresAt: policy.expiresAt,\n createdRow: true,\n indexed: await reindex(ref, deps, policy.expiresAt, undefined),\n };\n }\n assertNotDestroyed(record, ref);\n await deps.registry.compareAndSwap(ref, record.token, {\n retention: { ...record.retention, [EXPIRES_AT]: policy.expiresAt },\n });\n return {\n ...base,\n expiresAt: policy.expiresAt,\n createdRow: false,\n indexed: await reindex(ref, deps, policy.expiresAt, previousExpiresAt),\n };\n } catch (err) {\n if (!isWriteConflictError(err)) throw err;\n // Lost the race (a load's publish, another policy write) \u2014 re-read and retry.\n }\n }\n throw new WriteConflictError(\n `setRetention: contention writing the retention policy for segment \"${ref.segment}\"`,\n );\n}\n\n/**\n * Remove a segment's expiry so no sweep will retire it. Returns whether a policy was actually removed (`false`\n * for a segment with no row, or one that had no policy) \u2014 a separate verb from setting one, because \"cancel the\n * expiry\" and \"expire at time T\" are different intents and a magic sentinel value for the first is how a typo\n * becomes a deletion.\n *\n * Other `retention` keys are left in place; if removing the expiry empties the metadata, the field is cleared.\n */\nexport async function clearSegmentRetention(\n ref: SegmentRef,\n deps: RetentionDeps,\n): Promise<boolean> {\n for (let attempt = 0; attempt < RETENTION_CAS_ATTEMPTS; attempt += 1) {\n const record = await deps.registry.get(ref);\n if (record === null) return false; // nothing to clear \u2014 and creating a row to say so would be litter\n if (record.status === 'destroyed') return false; // terminal; a tombstone has no expiry to cancel\n if (record.retention === undefined || !(EXPIRES_AT in record.retention)) return false;\n const rest = { ...record.retention };\n delete rest[EXPIRES_AT];\n try {\n // `retention: undefined` CLEARS the field (a patch clears by mentioning), which is what an emptied policy\n // object should become \u2014 a row carrying `{}` reads as \"has retention metadata\" to anything inspecting it.\n await deps.registry.compareAndSwap(ref, record.token, {\n retention: Object.keys(rest).length === 0 ? undefined : rest,\n });\n await reindex(ref, deps, undefined, readExpiresAt(record));\n return true;\n } catch (err) {\n if (!isWriteConflictError(err)) throw err;\n }\n }\n throw new WriteConflictError(\n `clearRetention: contention clearing the retention policy for segment \"${ref.segment}\"`,\n );\n}\n\nfunction assertNotDestroyed(record: RegistryRecord, ref: SegmentRef): void {\n if (record.status === 'destroyed') {\n throw new ValidationError(\n `segment \"${ref.segment}\" is destroyed (crypto-shredded) \u2014 refusing to set a retention policy on a ` +\n `tombstone; there is nothing left to retire. Use a new segment.`,\n );\n }\n}\n", "/**\n * The retention **sweep** \u2014 the thing that acts on the policies `setSegmentRetention` records.\n *\n * `retireExpired` enumerates the registry, selects the segments whose `expiresAt` has passed, and retires each\n * one through {@link dropSegment}. It deliberately **delegates rather than reimplements**: the registry \u2192 Storage\n * ordering, the re-sweep for an object a load was still writing, and the `generationsRemaining` report are all\n * load-bearing and already live there. A sweep that open-coded the deletions would be a second\n * implementation of the most dangerous ordering in the library.\n *\n * **This is a call, not a daemon.** Nothing here schedules itself. You run it from whatever heartbeat your\n * deployment already has \u2014 an EventBridge rule, a Kubernetes CronJob, a queue consumer, the job that runs your\n * loads \u2014 and the library stays a library: it has to behave identically in a Lambda, an edge isolate and a\n * long-lived server, and a timer that only works in one of those is worse than none.\n *\n * Three properties make it safe to point at a fleet:\n *\n * - **`dryRun` at the sweep level.** `dropSegment`'s `confirmSegment` guard is vacuous in a loop (it is the same\n * variable twice), so the meaningful preview is here: it reports what it *would* retire, per segment, and\n * touches nothing.\n * - **A per-cycle `limit`.** Clock skew, a bad backfill, or a namespace-wide policy mistake should cost one\n * bounded batch, not the fleet. When the limit bites, the result says so (`limited: true`) rather than looking\n * like a completed sweep.\n * - **A ledger, never an exception.** A per-segment fault is recorded and the sweep continues \u2014 the caller's\n * load-bearing question is *which* segments were retired, and a throw from the middle of the loop answers it\n * for none of them while having already retired some. Same posture as `eraseNamespace`.\n *\n * It also **purges the tombstones its own retirements leave behind**. A retired segment that had a registry row\n * gets a `destroyed` row, and one dead row per retired daily bucket \u2014 or per retired dedup wave \u2014 is exactly the\n * registry litter `dropSegment` already refuses to create for a row-less accumulator. Purging is narrow on\n * purpose: only a tombstone that still carries an **expired retention policy** (so it is attributably ours, never\n * a GDPR crypto-shred), only after a grace period, and only once Storage is provably empty for it \u2014\n * because deleting the row is what makes the name reusable and takes the segment out of reach of\n * `gcOrphanGenerations`.\n */\nimport { type IAuditSink } from './audit';\nimport { BudgetExceededError, ValidationError, isWriteConflictError } from './errors';\nimport { gcOrphanGenerations } from './generation-gc';\nimport { drainRegistry } from './registry-scan';\nimport { dropSegment } from './erasure';\nimport type { DropDeps, DropResult } from './erasure';\nimport { MIN_EXPIRES_AT_MS, readRetentionPolicy } from './retention';\nimport { DEFAULT_MAX_SCAN_SEGMENTS } from './registry-scan';\nimport {\n canIndex,\n decodeDueName,\n dueBucket,\n dueBucketsAt,\n dueIndexRef,\n dueNamespace,\n} from './due-index';\nimport { segmentKey, shardOf } from './keys';\nimport type { IRegistryDriver, RegistryRecord } from './ports';\nimport type { GovernanceMeta, IStorageDriver, SegmentRef } from './ports';\n\n/** Default cap on retirements per sweep \u2014 a bounded batch, so a policy mistake costs one batch, not the fleet. */\nexport const DEFAULT_RETIRE_LIMIT = 100;\n\n/**\n * Default delay before a retirement's own tombstone row is purged: 24 h.\n *\n * The row is a fence \u2014 while it exists, `publishGeneration` and `bulkLoadCrbmGeneration` refuse the segment, so\n * a load that was mid-write when the drop landed cannot resurrect it. That window is\n * seconds to minutes in practice; a day of margin costs one tiny row and removes any need to reason about it.\n */\nexport const DEFAULT_TOMBSTONE_GRACE_MS = 86_400_000;\n\nexport interface RetireExpiredOptions {\n /** Scope the sweep to one namespace. Omit to sweep every namespace the registry knows. */\n readonly namespace?: string;\n /**\n * The instant to compare policies against (epoch-ms). Required here because `core/` takes its time from the\n * caller, never from the platform \u2014 `store.retireExpired()` fills it in from the store's clock.\n */\n readonly now: number;\n /** Maximum segments to retire in this cycle (default 100). */\n readonly limit?: number;\n /** Report what would be retired and change nothing. */\n readonly dryRun?: boolean;\n /** Forwarded to each `dropSegment`, so every retirement lands in the audit trail as `segment.dispose`. */\n readonly audit?: IAuditSink;\n /** Ceiling on rows enumerated (default 250,000); exceeding it throws. */\n readonly maxScanSegments?: number;\n /**\n * **Where the candidates come from.**\n *\n * - `'fleet'` (default) \u2014 drain `registry.list()` and filter. Cost tracks the **fleet**, every cycle, even\n * when nothing expires. Complete by construction: it cannot miss a policy.\n * - `'index'` \u2014 read only the due buckets of the due index. Cost tracks **what is\n * expiring**. Each candidate's live row is still re-read before anything is decided, so a stale pointer\n * costs one read and retires nothing.\n *\n * **`'index'` is not a drop-in replacement for `'fleet'`; it is the fast half of a pair.** A policy written\n * before the index existed, or one whose pointer write failed (`indexed: false`), has no pointer \u2014 so a\n * deployment that *only* ever runs `'index'` will never retire those. Run `'fleet'` periodically as the\n * repair pass. The default stays `'fleet'` so that upgrading changes nothing about what gets retired.\n */\n readonly scan?: 'fleet' | 'index';\n /**\n * **The shards this worker owns**, with {@link totalShards}. Without them every replica sweeps the whole\n * fleet and contends over the same segments. A stable hash of the segment key, so a worker owns the same slice\n * across restarts.\n */\n readonly shards?: readonly number[];\n /** Total shards the fleet is split into. Required with {@link shards}; ignored without it. */\n readonly totalShards?: number;\n /**\n * How many **past** buckets an `'index'` scan reads besides the current one (default 7, one per day).\n * A sweep that did not run \u2014 scaled to zero, a failed deploy, a paused\n * schedule \u2014 leaves its buckets behind, and this is how far back a later cycle reaches for them. Bounded so a\n * long outage costs a bounded number of list calls per cycle rather than one per day since the epoch;\n * anything older is the `'fleet'` repair pass's job.\n */\n readonly lookbackBuckets?: number;\n /**\n * Whether to delete the tombstone rows this sweep's own past retirements left (default `true`). Set `false` to\n * keep every tombstone forever \u2014 the right choice if something outside this library treats the presence of a\n * `destroyed` row as an attestation.\n *\n * Two knobs rather than one `number | 'never'`, deliberately: `0` would have had to mean \"purge immediately\"\n * here while `cache.genTtlMs: 0` in this same library means \"pin forever\", and one option whose zero is the\n * opposite of another's is a reading hazard for whoever tunes both.\n */\n readonly purgeTombstones?: boolean;\n /** How long a retirement's tombstone must age before this sweep deletes it (default 24 h). */\n readonly tombstoneGraceMs?: number;\n}\n\n/** What happened to one segment in a sweep. */\nexport type RetireEntry =\n | {\n readonly segment: string;\n readonly namespace?: string;\n /** Retired: `result` is `dropSegment`'s full report \u2014 **check `generationsRemaining`**. */\n readonly action: 'retired';\n readonly expiresAt: number;\n readonly result: DropResult;\n /**\n * Present when the retirement **completed the destructive part and then faulted** \u2014 the tombstone is written\n * and the segment reads empty, but something after that (the Storage sweep) threw. The storage may not be fully\n * reclaimed; re-run. Reported as `retired` rather than `skipped` because the segment really is retired, and\n * saying otherwise is the one thing a caller cannot recover from.\n */\n readonly fault?: `failed: ${string}`;\n }\n | {\n readonly segment: string;\n readonly namespace?: string;\n /** `dryRun` only \u2014 what a real sweep would have retired, with `dropSegment`'s own preview attached. */\n readonly action: 'would-retire';\n readonly expiresAt: number;\n readonly result: DropResult;\n }\n | {\n readonly segment: string;\n readonly namespace?: string;\n /** A tombstone row from an earlier retirement was deleted (or would be, under `dryRun`). */\n readonly action: 'purged-tombstone' | 'would-purge-tombstone';\n }\n | {\n readonly segment: string;\n readonly namespace?: string;\n readonly action: 'skipped';\n /**\n * `'invalid-policy'` \u2014 the row has an `expiresAt` that is not usable (hand-edited, or restored from another\n * schema). Reported rather than ignored: reading as \"never expires\" on a segment someone believes is\n * expiring is the silence that costs a retention commitment.\n * `'limit'` \u2014 eligible, but this cycle's `limit` was already spent. Re-run to continue.\n * `'tombstone-not-empty'` \u2014 a tombstone whose Storage generations are not gone even after a GC\n * attempt, so its row is kept: the row is what keeps the segment reachable by `gcOrphanGenerations` and\n * refused by every writer. Several causes, all self-healing: the storage really could not be reclaimed,\n * the collection *declined* because the row changed underneath it (`WriteConflictError`, which this\n * sweep swallows deliberately), or this was a `dryRun`, which reports the reason without attempting the\n * collection at all. Except under `dryRun` the next cycle retries.\n * `'policy-changed'` \u2014 the live row no longer says \"expired\" (a `clearRetention`, a new `expiresAt`, or\n * someone else's drop landed between the enumeration and this segment's turn). Not an error: the sweep\n * re-reads before every deletion precisely so cancelling an expiry works on a sweep already in flight.\n * `` `failed: \u2026` `` \u2014 any fault, isolated to this segment. A fault that happened *after* the tombstone\n * landed is reported as `retired` with a `fault` instead, because that segment IS retired.\n */\n readonly reason:\n 'invalid-policy' | 'limit' | 'tombstone-not-empty' | 'policy-changed' | `failed: ${string}`;\n };\n\nexport interface RetireExpiredResult {\n /** Registry rows enumerated. */\n readonly scanned: number;\n /** Rows whose policy said \"expired\" \u2014 including any the `limit` deferred. */\n readonly eligible: number;\n /**\n * Segments **actually retired**. Zero under `dryRun` \u2014 see `wouldRetire`. Kept honest because this is the field\n * most likely to end up on a dashboard, and the CLI emits it: a counter that means \"deleted\" in one mode and\n * \"would delete\" in another produces phantom deletions on any graph that does not also join on `dryRun`.\n */\n readonly retired: number;\n /** Segments a real sweep **would** have retired. Only ever non-zero under `dryRun`. */\n readonly wouldRetire: number;\n /** Tombstone rows actually deleted. Zero under `dryRun`; the `would-purge-tombstone` entries carry the preview. */\n readonly tombstonesPurged: number;\n /** True when `limit` cut the cycle short \u2014 **more segments are still eligible**. Re-run. */\n readonly limited: boolean;\n readonly dryRun: boolean;\n /** Per-segment ledger. Inspect it: a `skipped` or failed entry is a segment that still holds data. */\n readonly entries: readonly RetireEntry[];\n}\n\n/**\n * Retire every segment whose retention policy has expired, and clean up the tombstones earlier sweeps left.\n *\n * Returns a ledger; **never throws for a per-segment fault** (those become entries). It does throw for a bad\n * argument, and for a fleet larger than `maxScanSegments` \u2014 a scan that cannot be held in memory is a fail-loud\n * condition, not a partial result to be mistaken for a complete sweep.\n */\n/**\n * How many past buckets an index scan reads besides the current one. A week: long enough that a weekend outage\n * or a paused schedule recovers on its own, short enough that a cycle is eight list calls rather than hundreds.\n */\nexport const DEFAULT_LOOKBACK_BUCKETS = 7;\n\n/**\n * Candidates from the due index: read the buckets that are due, resolve each pointer, and **re-read the live\n * row**.\n *\n * That re-read is the load-bearing line. The index is a fast path and the segment's own row is the truth, so a\n * pointer whose policy has since been cleared, moved, or destroyed must cost one read and change nothing \u2014 the\n * ordinary eligibility check downstream then skips it, using exactly the same logic the fleet scan uses. There\n * is no second decision path to keep in step, which is the property that makes a second index safe here.\n *\n * A pointer we cannot decode, or one whose segment no longer exists, is skipped rather than repaired: this\n * function decides nothing irreversible, and cleaning up is the sweep's job once a retirement actually happens.\n */\nasync function rowsFromDueIndex(\n registry: IRegistryDriver,\n options: { now: number; lookbackBuckets: number; namespace?: string; maxScanSegments: number },\n): Promise<RegistryRecord[]> {\n const rows: RegistryRecord[] = [];\n const seen = new Set<string>();\n for (const bucket of dueBucketsAt(options.now, options.lookbackBuckets)) {\n for await (const pointer of registry.list(dueNamespace(bucket))) {\n const ref = decodeDueName(pointer.segment);\n if (ref === null) continue; // a foreign row in the reserved namespace \u2014 ignored, never acted on\n if (options.namespace !== undefined && ref.namespace !== options.namespace) continue;\n // A segment can appear in two buckets at once: `reindex` writes the new pointer before deleting the old,\n // so an interruption leaves both. De-duplicate here rather than retiring twice and reporting a phantom.\n const key = `${ref.namespace ?? ''}\\u0000${ref.segment}`;\n if (seen.has(key)) continue;\n seen.add(key);\n if (rows.length >= options.maxScanSegments) {\n throw new BudgetExceededError(\n `retireExpired: the due index yielded more than ${options.maxScanSegments} segments \u2014 the scan was ` +\n `abandoned there rather than completed. Raise \\`maxScanSegments\\`, narrow with \\`namespace\\`, or ` +\n `reduce \\`lookbackBuckets\\`.`,\n );\n }\n const live = await registry.get(ref);\n if (live === null) continue; // the segment is gone; the pointer is litter a later retirement will clear\n rows.push(live);\n }\n }\n return rows;\n}\n\n/**\n * Best-effort removal of a retired segment's due-index pointer. A failure here leaves litter that costs one\n * read when its bucket next comes due and is then skipped (the segment is gone, so the live re-read yields\n * `null`) \u2014 never a wrong retirement, so it must not turn a successful retirement into a fault.\n */\nasync function forgetDuePointer(\n registry: IRegistryDriver,\n ref: SegmentRef,\n expiresAt: number,\n): Promise<void> {\n if (!canIndex(ref)) return;\n try {\n await registry.delete(dueIndexRef(dueBucket(expiresAt), ref));\n } catch {\n // See above: litter, not a fault.\n }\n}\n\nexport async function retireExpired(\n deps: DropDeps,\n options: RetireExpiredOptions,\n): Promise<RetireExpiredResult> {\n const now = options.now;\n if (!Number.isFinite(now)) {\n throw new ValidationError(\n `retireExpired: \\`now\\` must be a finite epoch-ms; got ${String(now)}`,\n );\n }\n // A floor on `now` for the same reason `expiresAt` has one, and in the direction that actually destroys data: a\n // clock returning seconds makes every policy in the fleet look expired. (Too *small* a `now` is harmless \u2014\n // nothing expires \u2014 but a sweep against a pre-2001 instant cannot legitimately expire anything anyway, so\n // refusing it costs nothing and catches the units mistake.)\n if (now < MIN_EXPIRES_AT_MS) {\n throw new ValidationError(\n `retireExpired: \\`now\\` (${now}) is before ${MIN_EXPIRES_AT_MS} \u2014 that is almost certainly epoch SECONDS ` +\n `rather than milliseconds. A sweep with a wrong-units clock treats every policy as expired.`,\n );\n }\n const limit = options.limit ?? DEFAULT_RETIRE_LIMIT;\n if (!Number.isInteger(limit) || limit < 1) {\n throw new ValidationError(`retireExpired: \\`limit\\` must be a positive integer; got ${limit}`);\n }\n const purgeTombstones = options.purgeTombstones ?? true;\n const grace = options.tombstoneGraceMs ?? DEFAULT_TOMBSTONE_GRACE_MS;\n if (!Number.isFinite(grace) || grace < 0) {\n throw new ValidationError(\n `retireExpired: \\`tombstoneGraceMs\\` must be a non-negative finite number; got ${String(grace)}`,\n );\n }\n const maxScanSegments = options.maxScanSegments ?? DEFAULT_MAX_SCAN_SEGMENTS;\n if (!Number.isFinite(maxScanSegments) || maxScanSegments < 1) {\n throw new ValidationError(\n `retireExpired: \\`maxScanSegments\\` must be a finite number >= 1; got ${String(maxScanSegments)}`,\n );\n }\n const dryRun = options.dryRun === true;\n\n // Drain the enumeration first, bounded. The sweep mutates rows as it goes (a tombstone CAS, a row delete), and\n // iterating a live listing while doing so is driver-dependent \u2014 a Scan may or may not observe its own writes.\n // Draining makes the candidate set a snapshot; the retire path then RE-READS each row before acting on it,\n // because deciding an irreversible deletion from a minutes-old copy is not the same as enumerating from one.\n const scan = options.scan ?? 'fleet';\n const rows =\n scan === 'index'\n ? await rowsFromDueIndex(deps.registry, {\n now,\n lookbackBuckets: options.lookbackBuckets ?? DEFAULT_LOOKBACK_BUCKETS,\n namespace: options.namespace,\n maxScanSegments,\n })\n : await drainRegistry(deps.registry, {\n namespace: options.namespace,\n maxScanSegments,\n op: 'retireExpired',\n });\n\n const shards = options.shards;\n const totalShards = options.totalShards ?? 0;\n const mine =\n shards === undefined || totalShards <= 1\n ? rows\n : rows.filter((r) => shards.includes(shardOf(segmentKey(r), totalShards)));\n\n const entries: RetireEntry[] = [];\n let eligible = 0;\n let retired = 0;\n let wouldRetire = 0;\n let tombstonesPurged = 0;\n let limited = false;\n // The budget is charged on ATTEMPT, not on success, and that distinction is the whole guard. `dropSegment`\n // writes the tombstone BEFORE sweeping Storage, so a fault in the Storage phase is a segment that is\n // already retired \u2014 counting only successes meant a partial storage outage marched through the entire fleet with\n // the cap never engaging, reporting `retired: 0, limited: false` (a \"completed sweep that retired nothing\") while\n // every segment in the namespace was tombstoned. Reproduced by two independent reviews.\n let attempted = 0;\n\n for (const rec of mine) {\n const ref: SegmentRef = { namespace: rec.namespace, segment: rec.segment };\n const base = { segment: rec.segment, namespace: rec.namespace };\n const policy = readRetentionPolicy(rec.retention);\n\n if (rec.status === 'destroyed') {\n if (!purgeTombstones) continue;\n // Attribution is a POSITIVE MARKER the sweep writes on its own retirements, never an inference from\n // \"destroyed + an expired policy\". That inference was wrong and the consequence was serious: `shredSegment`\n // never touches `retention`, so the ordinary ordering \u2014 set a 30-day policy, then a GDPR request arrives\n // mid-window and you `destroySegment` \u2014 leaves a **crypto-shred** tombstone carrying an expired policy.\n // Deleting that row destroys the local attestation for a right-to-erasure execution and un-fences the name\n // for every writer. Two reviews reproduced it. A marker cannot be forged by that ordering.\n const retiredAt = retirementStamp(rec.retention);\n if (retiredAt === null) continue; // not ours \u2014 a GDPR tombstone, or one from a manual drop\n if (now - retiredAt < grace) continue; // inside the fence window; not ledger noise\n if (attempted >= limit) {\n limited = true;\n break;\n }\n attempted += 1;\n try {\n if (!(await isFullyReclaimed(deps, ref))) {\n // Self-heal rather than report-and-wait: `gcOrphanGenerations` takes EVERY generation of a destroyed\n // row, and nothing else will ever call it for this segment (no load publishes onto a tombstone, and the\n // erasure rewrite refuses one). Without this the row is stuck forever, the\n // objects are billed forever, and the sweep pays two list calls per cycle to say so again. Measured.\n if (!dryRun) await gcOrphanGenerations(ref, deps).catch(() => undefined);\n if (!(await isFullyReclaimed(deps, ref))) {\n entries.push({ ...base, action: 'skipped', reason: 'tombstone-not-empty' });\n continue;\n }\n }\n if (!dryRun) await deps.registry.delete(ref);\n if (!dryRun) tombstonesPurged += 1;\n entries.push({\n ...base,\n action: dryRun ? 'would-purge-tombstone' : 'purged-tombstone',\n });\n } catch (err) {\n entries.push({ ...base, action: 'skipped', reason: failureReason(err) });\n }\n continue;\n }\n\n if (policy === null) continue; // no policy \u2014 this segment is not the sweep's business\n if (policy === 'invalid') {\n entries.push({ ...base, action: 'skipped', reason: 'invalid-policy' });\n continue;\n }\n if (policy.expiresAt > now) continue; // not yet\n eligible += 1;\n if (attempted >= limit) {\n // Stop SCANNING, not just stop acting. Pushing a `limit` entry per deferred row made the ledger scale with\n // the fleet rather than with the batch \u2014 250,000 rows behind a bad backfill is ~15 MB of entries the caller\n // did not ask for, and the CLI then serialised all of them into one stdout line. They are not information:\n // the next run picks them up, which is what `limited` says.\n limited = true;\n break;\n }\n\n try {\n // Re-read the AUTHORITATIVE row before deleting anything. The enumeration is a snapshot, and on a large\n // fleet the gap between drawing it and reaching this segment is the whole sweep \u2014 minutes. Cancelling an\n // expiry is exactly the operator's recovery action for the bad-backfill case `limit` exists to survive, and\n // it did not work if a sweep was already running: the segment was retired from the stale copy. One strong\n // read per *eligible* segment, so the fleet enumeration stays a single `list()`. (`consistency.ts` takes the\n // same care for a read-only check; an irreversible deletion deserves at least as much.)\n const live = await deps.registry.get(ref);\n const livePolicy = live === null ? null : readRetentionPolicy(live.retention);\n if (\n live === null ||\n live.status === 'destroyed' ||\n livePolicy === null ||\n livePolicy === 'invalid' ||\n livePolicy.expiresAt > now\n ) {\n entries.push({ ...base, action: 'skipped', reason: 'policy-changed' });\n continue;\n }\n\n attempted += 1;\n // `confirmSegment` is satisfied structurally here \u2014 in a loop the guard is the same value twice, which is\n // why `dryRun` is the real preview. The dry run goes through `dropSegment` too, so the preview reports the\n // generations a real sweep would delete rather than a guess.\n const result = await dropSegment(ref, deps, {\n confirmSegment: rec.segment,\n dryRun,\n audit: options.audit,\n });\n if (dryRun) {\n wouldRetire += 1;\n entries.push({ ...base, action: 'would-retire', expiresAt: livePolicy.expiresAt, result });\n continue;\n }\n if (!result.dropped) {\n // `dropped: false` means the call found nothing to do, and the documented cause is a ref that does not\n // address what the caller meant. Counting that as a retirement is how a sweep addressing the wrong segment\n // reports success \u2014 so it is a ledger entry instead, carrying the reason `dropSegment` gave.\n //\n // Unreachable in practice now that the live re-read above proves the row exists (the only `dropped: false`\n // path needs no row at all), except through the microsecond in which someone else deletes it. Kept, and\n // labelled rather than claimed as covered: the invariant is \"never count a no-op as a retirement\", and it\n // must hold if either that re-read or `dropSegment`'s reporting ever changes.\n entries.push({\n ...base,\n action: 'skipped',\n reason: `failed: drop reported ${result.reason}`,\n });\n continue;\n }\n retired += 1;\n entries.push({ ...base, action: 'retired', expiresAt: livePolicy.expiresAt, result });\n // The pointer has done its job. Dropping it keeps a bucket from accumulating rows that every subsequent\n // lookback re-reads forever \u2014 the index would otherwise grow monotonically and slowly undo its own\n // purpose. Best-effort and unconditional on `scan`: a fleet sweep retires index-pointed segments too, and\n // leaving their pointers behind would make a later index scan re-read segments that no longer exist.\n await forgetDuePointer(deps.registry, ref, livePolicy.expiresAt);\n if (result.generationsDeleted.length === 0 && result.generationsRemaining.length === 0) {\n // The segment really held nothing, so `dropSegment` has just written a tombstone for a name that was\n // empty. Left in place that row FENCES the name against every writer \u2014 and `setRetention` will mint a\n // row for any name, including a typo'd one, so this is reachable from a single mistake. Nothing\n // existed, so there is nothing a delete could resurrect: remove the row instead of bricking the name.\n //\n // **Both halves of the predicate are load-bearing.** `generationsDeleted: []` alone does NOT mean the\n // segment was empty \u2014 it is equally what a segment whose every `storage.delete` threw produces, because\n // `dropSegment`'s sweep loop stops once a pass deletes nothing. Purging the row on that reading left\n // the expired objects readable and billed, and then unreachable by everything that could have\n // collected them: `gcOrphanGenerations` returns `[]` with no row to compare against, the next sweep\n // never sees the name again (no row to enumerate), and `dropSegment` takes its `'absent'` path. The\n // data that was contractually supposed to expire stayed, silently, forever. `generationsRemaining` is\n // the honest question and `dropSegment` computes it one field over for exactly this reason.\n //\n // When something DOES remain, falling through is the right move rather than a special case: the row\n // keeps its tombstone, so reads stay refused, and the tombstone-purge pass above re-sweeps it with\n // `gcOrphanGenerations` (which takes every generation of a destroyed row) and purges the row once it is\n // genuinely empty. The residual is visible in this entry's `result.generationsRemaining` meanwhile.\n await deps.registry.delete(ref).catch(() => undefined);\n continue;\n }\n // Stamp the tombstone as OURS, so a later sweep may purge the row (see the attribution note above). A\n // failure here only means the row is never auto-purged \u2014 never data loss \u2014 so it is best-effort.\n await stampRetirement(deps.registry, ref, now).catch(() => undefined);\n } catch (err) {\n // A fault AFTER the tombstone landed is a segment that IS retired, and reporting it as skipped told the\n // caller the opposite of the truth (\"a skipped entry is a segment that still holds data\"). One cheap read\n // settles which side of the tombstone we failed on.\n const after = await deps.registry.get(ref).catch(() => null);\n if (after?.status === 'destroyed') {\n // Stamp it here too. Without this a retirement that faulted after the tombstone landed is a row no later\n // sweep can attribute to itself, so it is never auto-purged \u2014 exactly the litter the purge exists to\n // prevent, and reachable from any transient Storage fault.\n await stampRetirement(deps.registry, ref, now).catch(() => undefined);\n retired += 1;\n entries.push({\n ...base,\n action: 'retired',\n expiresAt: policy.expiresAt,\n result: {\n ...base,\n dropped: true,\n generationsDeleted: [],\n generationsRemaining: [],\n cryptoShredded: false,\n reason: undefined,\n },\n fault: failureReason(err),\n });\n continue;\n }\n entries.push({ ...base, action: 'skipped', reason: failureReason(err) });\n }\n }\n\n return {\n scanned: mine.length,\n eligible,\n retired,\n wouldRetire,\n tombstonesPurged,\n limited,\n dryRun,\n entries,\n };\n}\n\n/** The key the sweep stamps on its own tombstones, so a purge is attributable rather than inferred. */\nconst RETIRED_AT = 'retiredBySweepAt';\n\n/** Read the sweep's own retirement stamp off a row, or `null` if this tombstone is not one of ours. */\nfunction retirementStamp(meta: GovernanceMeta | undefined): number | null {\n if (meta === undefined || meta === null || typeof meta !== 'object' || Array.isArray(meta)) {\n return null;\n }\n const raw = (meta as Record<string, unknown>)[RETIRED_AT];\n return typeof raw === 'number' && Number.isInteger(raw) && raw >= MIN_EXPIRES_AT_MS ? raw : null;\n}\n\n/**\n * Mark a freshly written tombstone as this sweep's own work, preserving whatever else the row's `retention`\n * metadata carried. Retried a couple of times on contention, then given up on: an unstamped tombstone is simply\n * never auto-purged, which is the safe direction.\n */\nasync function stampRetirement(\n registry: DropDeps['registry'],\n ref: SegmentRef,\n now: number,\n): Promise<void> {\n for (let attempt = 0; attempt < 3; attempt += 1) {\n const rec = await registry.get(ref);\n if (rec === null || rec.status !== 'destroyed') return; // nothing to stamp\n try {\n await registry.compareAndSwap(ref, rec.token, {\n retention: { ...rec.retention, [RETIRED_AT]: now },\n });\n return;\n } catch (err) {\n if (!isWriteConflictError(err)) throw err;\n }\n }\n}\n\n/**\n * Whether a tombstoned segment's storage is provably gone \u2014 no Storage generations.\n *\n * The check is about what deleting the row would break rather than about tidiness: `gcOrphanGenerations` reads\n * the registry row to decide what to collect and returns empty when there is none, so deleting the row while\n * objects remain strands them permanently \u2014 billed forever, reachable by nothing. (An object a load was still\n * writing when the tombstone landed is exactly how they get there, which is why `dropSegment` reports\n * `generationsRemaining` at all.)\n *\n * Leaving the tombstone in place is self-healing: this sweep collects the orphan generations itself\n * (`gcOrphanGenerations` takes *every* generation of a destroyed row), and the next cycle purges the row.\n */\nasync function isFullyReclaimed(\n deps: { readonly storage: IStorageDriver },\n ref: SegmentRef,\n): Promise<boolean> {\n for await (const key of deps.storage.list(ref)) {\n void key;\n return false;\n }\n return true;\n}\n\nfunction failureReason(err: unknown): `failed: ${string}` {\n if (isWriteConflictError(err)) return 'failed: contended';\n return `failed: ${err instanceof Error ? err.message : String(err)}`;\n}\n", "/**\n * Fail-safe cross-store disaster-recovery check. The registry (`currentGen`) and the immutable `.crbm`\n * generations can be restored **independently**, so a failover can recover the registry *ahead of* the storage\n * objects \u2014 leaving `currentGen` pointing at a generation whose `.crbm` isn't present yet. That is likelier\n * than it sounds even now that both usually live in one bucket: a restore scoped to a prefix, or replayed\n * per-object from a version history, recovers the two prefixes at different points. That's a torn restore: reads of the affected segment then throw. This scan\n * detects it up front (run it at startup after a restore) instead of discovering it on the first read.\n *\n * Read-only; bounded fan-out. `destroyed` (crypto-shredded) segments are skipped \u2014 their Storage is intentionally\n * gone/unreadable, not a torn restore. A segment whose Storage/registry can't be read this pass is recorded in\n * `errored` (never aborts the scan). Each segment is checked against its **authoritative live pointer** \u2014 one\n * strong `registry.get` per segment \u2014 never the enumeration snapshot from `registry.list`, which can be\n * eventually-consistent (an unindexed Scan) and lag a recent in-place pointer advance: trusting it would both\n * miss a torn *live* generation and cry torn on a generation the pointer has already advanced past (GC'd during\n * the scan). Residual: a load's publish plus a GC landing in the tiny per-segment get\u2192list gap can still yield a\n * transient false positive \u2014 run the scan against a quiesced fleet (the documented restore procedure), or re-run\n * to confirm a reported tear.\n */\n\nimport { mapWithConcurrency } from './concurrency';\nimport { ValidationError } from './errors';\nimport { DEFAULT_MAX_SCAN_SEGMENTS, drainRegistry } from './registry-scan';\nimport type { IStorageDriver, IRegistryDriver, SegmentRef } from './ports';\n\n/** Default in-flight fan-out for the consistency scan \u2014 bounded, no thundering herd. */\n/**\n * Default ceiling on how many registry records one consistency check may hold resident: 250,000.\n *\n * **Named `maxScanSegments`, not `maxSegments`, on purpose.** A `maxSegments`-style option caps how much work\n * one cycle does and then *continues normally* (the retention sweep's `limit` is that shape). This one caps how\n * much a scan may hold and *refuses* past it. Same-sounding names with opposite behaviour at the limit is a\n * trap; the name says what it is \u2014 a ceiling on a scan that fails closed.\n *\n * Generous \u2014 fleets of 100K+ segments are the design target \u2014 while still bounding a DR drill's memory to\n * something a modest operator box survives. Raisable, because a ceiling you cannot lift is a landmine.\n */\n// Re-exported from its original home because this module is where the ceiling is documented; the value and the\n// loop that enforces it live in `registry-scan.ts`, shared with the retention sweep. This is an INTERNAL\n// re-export: the name left `@cloudbitmaps/core`'s main entry in 0.10.0 along with the other two defaults, and\n// `MIGRATING.md` tells callers to pass their own `maxScanSegments` rather than read ours.\nexport { DEFAULT_MAX_SCAN_SEGMENTS } from './registry-scan';\nconst DEFAULT_CHECK_CONCURRENCY = 8;\n\nexport interface ConsistencyIssue {\n readonly segment: string;\n readonly namespace?: string;\n /** The registry's `currentGen` for the segment \u2014 the generation whose `.crbm` is missing from Storage. */\n readonly currentGen: number;\n /** The only issue class today: `currentGen` references a Storage generation that is not present (torn restore). */\n readonly issue: 'missing-storage-generation';\n}\n\n/** A segment that could not be checked this pass (Storage/registry read fault) \u2014 not proof of a torn restore. */\nexport interface ConsistencyErrorEntry {\n readonly segment: string;\n readonly namespace?: string;\n /** The read error's message (never the raw error, so the report stays serializable/loggable). */\n readonly error: string;\n}\n\nexport interface ConsistencyReport {\n /** Registered segments scanned (a `destroyed` segment counts as scanned but is never an issue). */\n readonly checked: number;\n /** Segments whose `currentGen` `.crbm` is absent \u2014 recover the object store (or restore to a coherent point). */\n readonly inconsistent: ConsistencyIssue[];\n /**\n * Segments that couldn't be read this pass (a transient/partial object store during a restore is exactly when\n * this runs) \u2014 **triage these too**: an unread segment is neither proven-coherent nor proven-torn. Empty on a\n * clean pass.\n */\n readonly errored: ConsistencyErrorEntry[];\n}\n\n/** Collect the set of generations the object store currently lists for a segment. */\nasync function generationsPresent(storage: IStorageDriver, ref: SegmentRef): Promise<Set<number>> {\n const present = new Set<number>();\n for await (const key of storage.list(ref)) present.add(key.generation);\n return present;\n}\n\ntype Outcome =\n | { readonly kind: 'ok' }\n | { readonly kind: 'issue'; readonly issue: ConsistencyIssue }\n | { readonly kind: 'error'; readonly error: ConsistencyErrorEntry };\n\n/**\n * Verify every registered segment's `currentGen` `.crbm` actually exists in Storage. Enumerates the registry\n * (optionally one namespace) and, for each non-`destroyed` segment, checks the object store lists that\n * generation. Returns the torn segments in `inconsistent` (empty \u21D2 coherent) and any unreadable segments in\n * `errored`.\n */\nexport async function runConsistencyCheck(\n deps: { readonly storage: IStorageDriver; readonly registry: IRegistryDriver },\n options: { namespace?: string; concurrency?: number; maxScanSegments?: number } = {},\n): Promise<ConsistencyReport> {\n const concurrency = options.concurrency ?? DEFAULT_CHECK_CONCURRENCY;\n if (!Number.isInteger(concurrency) || concurrency < 1) {\n // Fail fast before the (possibly huge) registry scan, not after.\n throw new ValidationError(`concurrency must be a positive integer; got ${concurrency}`);\n }\n const maxScanSegments = options.maxScanSegments ?? DEFAULT_MAX_SCAN_SEGMENTS;\n // Bounded enumeration, shared with the retention sweep \u2014 see `registry-scan.ts` for why a fleet-wide scan is\n // drained rather than streamed, and why the ceiling is not optional. This used to be an inline copy of that loop.\n const recs = await drainRegistry(deps.registry, {\n namespace: options.namespace,\n maxScanSegments,\n op: 'checkConsistency',\n });\n const results = await mapWithConcurrency(recs, concurrency, async (rec): Promise<Outcome> => {\n if (rec.status === 'destroyed') return { kind: 'ok' }; // Storage intentionally gone \u2014 not a torn restore\n const ref: SegmentRef = { segment: rec.segment, namespace: rec.namespace };\n try {\n // Resolve the AUTHORITATIVE live pointer (strong read) \u2014 not the drained `rec.currentGen`, which the\n // enumeration may have read eventually-consistently and can lag the live pointer. `rec` is used only to\n // enumerate + skip destroyed segments.\n const live = await deps.registry.get(ref);\n if (!live || live.status === 'destroyed') return { kind: 'ok' }; // vanished/shredded \u2014 no live pointer\n // A row with no Storage generation is *deliberately* Storage-less \u2014 a retention policy recorded before the first\n // load, given a row so the segment is enumerable at all. There is no generation that ought to exist, so nothing can be missing. Reporting it\n // would make `missing-storage-generation` fire on the healthy steady state of every such segment, which is the\n // opposite of what a DR triage needs: the one real signal drowned in expected noise.\n if (live.currentGen === null) return { kind: 'ok' };\n const present = await generationsPresent(deps.storage, ref);\n if (present.has(live.currentGen)) return { kind: 'ok' };\n return {\n kind: 'issue',\n issue: {\n segment: rec.segment,\n namespace: rec.namespace,\n currentGen: live.currentGen,\n issue: 'missing-storage-generation',\n },\n };\n } catch (error) {\n // Fault isolation: one unreadable segment (a partial/transient object store mid-restore) must not abort\n // the whole triage. Record it and keep scanning the rest.\n return {\n kind: 'error',\n error: {\n segment: rec.segment,\n namespace: rec.namespace,\n error: error instanceof Error ? error.message : String(error),\n },\n };\n }\n });\n const inconsistent: ConsistencyIssue[] = [];\n const errored: ConsistencyErrorEntry[] = [];\n for (const r of results) {\n if (r.kind === 'issue') inconsistent.push(r.issue);\n else if (r.kind === 'error') errored.push(r.error);\n }\n return { checked: recs.length, inconsistent, errored };\n}\n", "/**\n * `withRetry` \u2014 the one retry/backoff primitive.\n *\n * A pure, storage-agnostic helper: it knows nothing about HTTP, AWS, or any SDK. It retries an operation\n * while the operation keeps failing with a **retryable** error (by default {@link TransientError}), waiting\n * a bounded, jittered, exponentially-growing delay between attempts. Time and randomness are **injected**\n * (the determinism seam) \u2014 production wires a `setTimeout`-backed clock + a real RNG; the\n * tests wire virtual ones \u2014 so a backoff schedule is replayable from a seed and unit tests run with no\n * real sleeping.\n *\n * It deliberately does **not** retry deterministic failures ({@link WriteConflictError},\n * {@link ValidationError}, {@link IntegrityError}, {@link NotFoundError}, \u2026): retrying those either can't\n * help or would be incorrect. A pointer conflict is retried by a *separate* loop inside\n * `publishGeneration`, because each attempt must re-read the row and re-decide \u2014 a blind replay of the same\n * compare-and-swap would either fail again on a stale token or, worse, advance a pointer whose state has\n * changed underneath it. A write-once object collision is never replayed at all: the generation number is\n * taken, so the caller has to pick a new one.\n */\nimport type { Clock, Rng } from './determinism';\nimport { isTransientError, ValidationError } from './errors';\n\nexport interface RetryPolicy {\n /** Total attempts including the first (so `maxAttempts: 4` = 1 try + 3 retries). Must be \u2265 1. */\n readonly maxAttempts: number;\n /** Delay before the first retry, in ms. Grows by `backoffFactor` each subsequent retry. */\n readonly baseDelayMs: number;\n /** Upper bound on a single (pre-jitter) delay, in ms \u2014 caps the exponential growth. */\n readonly maxDelayMs: number;\n /** Exponential growth factor between retries (e.g. 2 \u21D2 base, 2\u00B7base, 4\u00B7base, \u2026). */\n readonly backoffFactor: number;\n /**\n * `'full'` \u21D2 the actual wait is uniform in `[0, computed]` (AWS-recommended full jitter: decorrelates\n * concurrent retriers so they don't reconverge into a thundering herd). `'none'` \u21D2 wait exactly `computed`.\n */\n readonly jitter: 'full' | 'none';\n}\n\n/**\n * Conservative defaults: 4 attempts, 50ms \u2192 100 \u2192 200 (\u00D72), capped at 2s, full jitter. Tuned for a cloud\n * backend's brief throttle/5xx blip \u2014 enough to ride out a transient fault without turning a hard outage\n * into a long hang. Override per store/driver if your latency budget differs.\n */\nexport const DEFAULT_RETRY_POLICY: RetryPolicy = {\n maxAttempts: 4,\n baseDelayMs: 50,\n maxDelayMs: 2_000,\n backoffFactor: 2,\n jitter: 'full',\n};\n\nexport interface RetryDeps {\n readonly clock: Clock;\n readonly rng: Rng;\n /** Override which errors are retryable. Default: any {@link TransientError} (incl. `TimeoutError`). */\n readonly isRetryable?: (err: unknown) => boolean;\n /** Optional hook (observability) fired before each backoff wait. `attempt` is 1-based (the one that failed). */\n readonly onRetry?: (info: { attempt: number; delayMs: number; err: unknown }) => void;\n}\n\n/**\n * Backoff delay (ms) for the retry that follows a given 1-based attempt, before jitter is applied. Exposed\n * for tests. `attempt` 1 \u21D2 `baseDelayMs`, 2 \u21D2 `base\u00B7factor`, \u2026 capped at `maxDelayMs`.\n */\nexport function backoffDelayMs(policy: RetryPolicy, attempt: number): number {\n const raw = policy.baseDelayMs * policy.backoffFactor ** (attempt - 1);\n return Math.min(policy.maxDelayMs, raw);\n}\n\n/** Apply the policy's jitter to a computed delay using the injected RNG. */\nexport function applyJitter(policy: RetryPolicy, delayMs: number, rng: Rng): number {\n if (policy.jitter === 'none') return delayMs;\n return rng.next() * delayMs; // full jitter: uniform in [0, delayMs)\n}\n\n/**\n * Run `op`, retrying transient failures per `policy`. Resolves with `op`'s result, or rejects with the last\n * error once attempts are exhausted (or immediately for a non-retryable error). The thrown error is always\n * the *operation's* error \u2014 never a wrapper \u2014 so callers keep their typed-error branching.\n */\nexport async function withRetry<T>(\n op: () => Promise<T>,\n policy: RetryPolicy,\n deps: RetryDeps,\n): Promise<T> {\n const retryable = deps.isRetryable ?? isTransientError;\n // `Math.max(1, x)` guards 0 and negatives but NOT NaN \u2014 `Math.max(1, NaN)` is NaN, and `1 <= NaN` is false,\n // so the loop below would never execute: `op()` never called, and the function rejects with the literal\n // `undefined` from `lastErr`. Every write would silently no-op without touching the backend, and callers\n // would catch a non-Error. Reachable from ordinary wiring \u2014 `maxAttempts: Number(process.env.X)` with the\n // var unset is NaN. Fail loudly instead, and floor it so a fractional value can't sleep on a final attempt\n // that never happens.\n if (!Number.isFinite(policy.maxAttempts) || policy.maxAttempts < 1) {\n throw new ValidationError(\n `retry.maxAttempts must be a finite number >= 1 (got ${String(policy.maxAttempts)})`,\n );\n }\n const attempts = Math.floor(policy.maxAttempts);\n let lastErr: unknown;\n for (let attempt = 1; attempt <= attempts; attempt++) {\n try {\n return await op();\n } catch (err) {\n lastErr = err;\n if (attempt >= attempts || !retryable(err)) throw err;\n const delayMs = applyJitter(policy, backoffDelayMs(policy, attempt), deps.rng);\n deps.onRetry?.({ attempt, delayMs, err });\n await deps.clock.sleep(delayMs);\n }\n }\n // Unreachable: the loop either returns or throws. Satisfies the type checker.\n throw lastErr;\n}\n", "/**\n * Retry decorators.\n *\n * Transparent wrappers that add bounded, jittered retry of **transient** faults to any driver, using the one\n * shared `core/retry` primitive \u2014 so every backend (S3, GCS, Azure Blob, LocalFS, \u2026) inherits the same\n * policy instead of each rolling its own. Pure composition over the port interfaces (no SDK, no I/O of their\n * own); the wrapped driver is responsible for *classifying* its transient faults (raising {@link TransientError});\n * these decorators decide *whether and when* to retry.\n *\n * **Streaming methods buffer**, deliberately: a partially-consumed async iterator cannot be resumed mid-stream\n * (it would re-yield earlier items), so `RetryingStorageDriver.list` and `RetryingRegistryDriver.list` collect the\n * whole enumeration inside `withRetry` and re-run it from the start on a fault. Both are discovery scans over a\n * generation or namespace listing, where the result set is small and whole-scan retry is worth the memory.\n *\n * Point methods are retried in place, with nothing to buffer.\n *\n * What is **not** retried here: {@link WriteConflictError} (OCC \u2014 the publish loop owns that; a blind replay\n * would re-apply against a stale token), and every deterministic error\n * (`ValidationError`/`IntegrityError`/`NotFoundError`/\u2026). Default classifier: {@link isTransientError}.\n */\nimport type { Clock, Rng } from '../../core/determinism';\nimport { withRetry, DEFAULT_RETRY_POLICY } from '../../core/retry';\nimport { isTransientError } from '../../core/errors';\nimport type { RetryPolicy } from '../../core/retry';\nimport type {\n ChunkRef,\n StorageCaps,\n StorageChunkSource,\n GenKey,\n IStorageDriver,\n IRegistryDriver,\n NewRegistryRecord,\n RegCaps,\n RegistryPatch,\n RegistryRecord,\n SegmentRef,\n SegmentSize,\n Token,\n} from '../../core/ports';\nimport type { BlobSink } from '../../core/blob';\n\nexport interface RetryingOptions {\n readonly clock: Clock;\n readonly rng: Rng;\n /** Defaults to {@link DEFAULT_RETRY_POLICY}. */\n readonly policy?: RetryPolicy;\n /** Override which errors are retryable. Default: {@link isTransientError} (any `TransientError`). */\n readonly isRetryable?: (err: unknown) => boolean;\n /** Observability hook fired before each backoff wait. */\n readonly onRetry?: (info: { attempt: number; delayMs: number; err: unknown }) => void;\n}\n\n/** Internal: resolve the options into the `core/retry` shape once, at construction. */\nfunction toRetry(opts: RetryingOptions): {\n policy: RetryPolicy;\n deps: {\n clock: Clock;\n rng: Rng;\n isRetryable: (e: unknown) => boolean;\n onRetry?: RetryingOptions['onRetry'];\n };\n} {\n return {\n policy: opts.policy ?? DEFAULT_RETRY_POLICY,\n deps: {\n clock: opts.clock,\n rng: opts.rng,\n isRetryable: opts.isRetryable ?? isTransientError,\n onRetry: opts.onRetry,\n },\n };\n}\n\n/** Wrap a storage chunk source so its reads retry transient faults. */\nexport class RetryingStorageChunkSource implements StorageChunkSource {\n private readonly inner: StorageChunkSource;\n private readonly policy: RetryPolicy;\n private readonly deps: ReturnType<typeof toRetry>['deps'];\n /** Present only when the inner source supports it \u2014 so capability detection stays honest. */\n readonly sizeOf?: (ref: SegmentRef) => Promise<SegmentSize | null>;\n readonly cardinalities?: (ref: SegmentRef) => Promise<ReadonlyMap<number, number> | null>;\n readonly currentGeneration?: (ref: SegmentRef) => Promise<number | null>;\n readonly invalidate?: (ref: SegmentRef) => void;\n readonly exists?: (ref: SegmentRef) => Promise<boolean>;\n readonly currentVersion?: (ref: SegmentRef) => Promise<string | null>;\n\n constructor(inner: StorageChunkSource, opts: RetryingOptions) {\n this.inner = inner;\n const r = toRetry(opts);\n this.policy = r.policy;\n this.deps = r.deps;\n const innerSizeOf = inner.sizeOf;\n if (innerSizeOf) {\n this.sizeOf = (ref) => withRetry(() => innerSizeOf.call(inner, ref), this.policy, this.deps);\n }\n const innerCardinalities = inner.cardinalities;\n if (innerCardinalities) {\n this.cardinalities = (ref) =>\n withRetry(() => innerCardinalities.call(inner, ref), this.policy, this.deps);\n }\n const innerCurrentGeneration = inner.currentGeneration;\n if (innerCurrentGeneration) {\n this.currentGeneration = (ref) =>\n withRetry(() => innerCurrentGeneration.call(inner, ref), this.policy, this.deps);\n }\n // Forwarded, NOT retried: it is synchronous and cannot fail, and dropping memoized state has no transient\n // mode to back off from. Forgetting to forward it would be silent \u2014 the wrapper would satisfy the port\n // while the invalidation stopped one layer short of the source that holds the snapshot and the DEK.\n const innerInvalidate = inner.invalidate;\n if (innerInvalidate) {\n this.invalidate = (ref) => {\n innerInvalidate.call(inner, ref);\n };\n }\n // Retried, unlike `invalidate`: this one reads the registry, so it has a transient mode to back off from.\n const innerExists = inner.exists;\n if (innerExists) {\n this.exists = (ref) => withRetry(() => innerExists.call(inner, ref), this.policy, this.deps);\n }\n const innerCurrentVersion = inner.currentVersion;\n if (innerCurrentVersion) {\n this.currentVersion = (ref) =>\n withRetry(() => innerCurrentVersion.call(inner, ref), this.policy, this.deps);\n }\n }\n\n getChunk(ref: ChunkRef): Promise<Uint8Array | null> {\n return withRetry(() => this.inner.getChunk(ref), this.policy, this.deps);\n }\n\n listChunkKeys(ref: SegmentRef): Promise<number[]> {\n return withRetry(() => this.inner.listChunkKeys(ref), this.policy, this.deps);\n }\n}\n\n/** Wrap a storage driver so its byte operations retry transient faults. */\nexport class RetryingStorageDriver implements IStorageDriver {\n private readonly inner: IStorageDriver;\n private readonly policy: RetryPolicy;\n private readonly deps: ReturnType<typeof toRetry>['deps'];\n\n constructor(inner: IStorageDriver, opts: RetryingOptions) {\n this.inner = inner;\n const r = toRetry(opts);\n this.policy = r.policy;\n this.deps = r.deps;\n }\n\n capabilities(): StorageCaps {\n return this.inner.capabilities(); // pure, local \u2014 no retry\n }\n\n putImmutable(\n key: GenKey,\n write: (sink: BlobSink) => Promise<void>,\n ): Promise<{ size: number; sha256: string }> {\n // Write-once + content-buffered: a retry re-runs `write` from scratch and re-issues the conditional put;\n // a phantom-success surfaces as WriteConflictError (not transient) and stops the retry. Safe to wrap.\n return withRetry(() => this.inner.putImmutable(key, write), this.policy, this.deps);\n }\n\n getRange(key: GenKey, offset: number, length: number): Promise<Uint8Array> {\n return withRetry(() => this.inner.getRange(key, offset, length), this.policy, this.deps);\n }\n\n getTail(key: GenKey, maxBytes: number): Promise<{ bytes: Uint8Array; size: number }> {\n return withRetry(() => this.inner.getTail(key, maxBytes), this.policy, this.deps);\n }\n\n delete(key: GenKey): Promise<void> {\n return withRetry(() => this.inner.delete(key), this.policy, this.deps);\n }\n\n async *list(ref: SegmentRef): AsyncIterable<GenKey> {\n const keys = await withRetry(\n async () => {\n const out: GenKey[] = [];\n for await (const k of this.inner.list(ref)) out.push(k);\n return out;\n },\n this.policy,\n this.deps,\n );\n yield* keys;\n }\n}\n\n/** Wrap a registry driver so its calls retry transient faults. CAS conflicts are not retried (caller-owned). */\nexport class RetryingRegistryDriver implements IRegistryDriver {\n private readonly inner: IRegistryDriver;\n private readonly policy: RetryPolicy;\n private readonly deps: ReturnType<typeof toRetry>['deps'];\n\n constructor(inner: IRegistryDriver, opts: RetryingOptions) {\n this.inner = inner;\n const r = toRetry(opts);\n this.policy = r.policy;\n this.deps = r.deps;\n }\n\n capabilities(): RegCaps {\n return this.inner.capabilities();\n }\n\n get(ref: SegmentRef): Promise<RegistryRecord | null> {\n return withRetry(() => this.inner.get(ref), this.policy, this.deps);\n }\n\n create(ref: SegmentRef, record: NewRegistryRecord): Promise<{ token: Token }> {\n return withRetry(() => this.inner.create(ref, record), this.policy, this.deps);\n }\n\n compareAndSwap(\n ref: SegmentRef,\n expected: Token,\n patch: RegistryPatch,\n ): Promise<{ token: Token }> {\n return withRetry(() => this.inner.compareAndSwap(ref, expected, patch), this.policy, this.deps);\n }\n\n async *list(namespace?: string): AsyncIterable<RegistryRecord> {\n const records = await withRetry(\n async () => {\n const out: RegistryRecord[] = [];\n for await (const r of this.inner.list(namespace)) out.push(r);\n return out;\n },\n this.policy,\n this.deps,\n );\n yield* records;\n }\n\n delete(ref: SegmentRef): Promise<void> {\n return withRetry(() => this.inner.delete(ref), this.policy, this.deps);\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["total", "FS", "createHash", "open", "open", "FS", "createHash", "FS", "randomUUID", "mkdir", "open", "readdir", "unlink", "dirname", "readdir", "open", "FS", "mkdir", "dirname", "randomUUID", "unlink", "join", "join", "DEFAULT_MAX_BITMAP_BYTES", "generation", "key", "collected", "listGenerations"]
|
|
7
|
+
}
|