@lunora/do 1.0.0-alpha.61 → 1.0.0-alpha.63

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/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { SchemaLike, DatabaseWriterLike, CdcChange, FilterClause, ExportRow, MigrationDirection, ReactiveCache, ReactiveCacheOptions, ShardSocketLike, LifecycleDispatchInfo, MigrationRunResult, TableIndexInfo, ColumnMeta, AdvisoryFinding, AdvisorProcedure, RlsPoliciesResult, MaskPoliciesResult, StorageRulesResult, StudioFeaturesResult, FlagsResult, SubscriptionIdentity, QueuesResult, WorkflowsResult, ImportShardResult, ShardRankPageResult, SubscriptionQuery, ShapeSubscriptionQuery, MutationDelta, KeyRange, ResolvedShape, ShapeRow, TtlSweepSpec, TransactionLimits, TransactionHeadroomTracker, IndexKeyEntry, SqlExec } from '@lunora/shard-engine';
1
+ import { SchemaLike, DatabaseWriterLike, CdcChange, FilterClause, ExportRow, MigrationDirection, ReactiveCache, ReactiveCacheOptions, ShardSocketLike, TransactionHeadroomTracker, LifecycleDispatchInfo, MigrationRunResult, TableIndexInfo, ColumnMeta, AdvisoryFinding, AdvisorProcedure, RlsPoliciesResult, MaskPoliciesResult, StorageRulesResult, StudioFeaturesResult, FlagsResult, SubscriptionIdentity, QueuesResult, WorkflowsResult, ImportShardResult, ShardRankPageResult, SubscriptionQuery, ShapeSubscriptionQuery, MutationDelta, KeyRange, ResolvedShape, ShapeRow, TtlSweepSpec, TransactionLimits, IndexKeyEntry, SqlExec } from '@lunora/shard-engine';
2
2
  export { ADMIN_FUNCTIONS, ADMIN_FUNCTION_PREFIX, AGGREGATE_SQL_FUNCTION, type AdvisorProcedure, type AdvisorProceduresResult, type AdvisoriesResult, type AdvisoryFinding, type AggregateIndexDefinitionLike, type AggregateOp, type AggregateOptions, type AggregateResult, type AggregateTally, type ApplyOnDeleteOptions, type AuditEntry, type AuditLogResult, type BroadcastDelta, CDC_LOG_TABLE, type CacheEntry, type CapturedMailRow, type CdcChange, type Clock, type ColumnMeta, type ColumnMetaLike, ConflictError, type CountArgs, CountRlsUnsupportedError, type CtxDbOptions, DATA_MIGRATION_STATE_TABLE, DEFAULT_MAX_RELATION_KEYS, type DataMigrationDocument, type DataMigrationLike, type DataMigrationTransform, type DatabaseWriterLike, type DependencyTracker, type DeployInfo, type ExportRow, type ExportShardAdminArgs, type ExportShardArgs, type ExternalSourceDiffResult, type ExternalSourceLike, FLAGS_FUNCTION_PREFIX, type FacetColumnOptions, type FacetColumnResult, type FacetValue, type FieldOperators, type FlagEvaluation, type FlagsResult, type FunctionCallStat, type FunctionStatsResult, GEO_DEFAULT_PRECISION, type GeoBoundingBox, type GeoFilterBuilderLike, type GeoIndexDefinitionLike, type GeoPoint, type GroupByEntry, type GroupByOptions, type IdGenerator, type ImportError, type ImportShardAdminArgs, type ImportShardArgs, type ImportShardResult, type IncrementalMaterializeResult, type IndexDefinitionLike, type IndexKeyEntry, type IndexRangeBuilderLike, type KeyRange, MAIL_RETENTION, MAIL_TABLE, MAX_SQL_ROWS, type MaskColumnMetadata, type MaskPoliciesResult, type MaterializeResult, type MigrationDirection, type MigrationRunResult, type MigrationStatus, type MigrationStatusRow, type MutationDelta, type NestedWith, NotFoundError, NotUniqueError, type OnDeleteActionLike, type OrderByInput, type OrderKey, type PaginationOptions, type PitrBookmarkResult, type PitrRestoreArgs, type PitrRestoreResult, type PitrStorage, type QueryArgs, type QueryPage, type QueueMetadata, type QueuesResult, RANK_TIEBREAK, RELATION_FUNCTION_PREFIX, RLS_UNWRAP_SYMBOL, type RankDirection, type RankIndexDefinitionLike, type RankOptions, type RankPage, type RankPageOptions, type RankPageRow, type RankPageRowKey, type RankResult, type RankSortKeyLike, ReactiveCache, type ReactiveCacheOptions, type ReadHook, type ReadTablePageOptions, type RecordMailInput, type RelationDefinitionLike, type RenderedSql, type ResolveRelationPredicatesOptions, type ResolveWithOptions, type RestrictableQueryOptions, type RlsPoliciesResult, type RlsPolicyMetadata, RlsRequiredError, type RlsRoleMetadata, type RpcRequest, type RunDataMigrationOptions, type RunTriggersOptions, SCAN_DEP, type SchedulableWorkflowReferenceLike, type ScheduledFunctionDoc, type SchedulerLike, type SchemaLike, type SearchFilterBuilderLike, type SearchIndexDefinitionLike, type SelectMatchingIdsOptions, type ServerDefaultContextLike, type SettingEntry, type SettingKind, type SettingsResult, type ShapeSubscriptionQuery, type ShardRankPageResult, type SocketAttachment, type SortDirection, type SourceClientLike, type SourceCursorLike, type SourceRefresh, type SqlConsoleResult, type SqlCursor, type SqlEngine, type SqlExec, type StorageRuleMetadata, type StorageRulesResult, type StudioFeaturesResult, type SubscriptionEnvelope, type SubscriptionQuery, type SystemDatabaseReader, type SystemDoc, type SystemQuery, type SystemReaderOptions, type SystemReaderSchedulerLike, type SystemReaderStorageLike, type SystemTableName, type TableColumnsResult, type TableDefinitionLike, type TableIndexInfo, type TableIndexesResult, type TableInfo, type TablePage, type TableReaderLike, type TablesColumnsResult, type TransactionHeadroomTracker, type TransactionSqlLike, type TriggerContextLike, type TriggerDefinitionLike, type TriggerEventLike, type TriggerOpLike, type TriggerTimingLike, type TtlSweepSpec, type ValidatorLike, type WhereInput, type WhereSqlStrategy, type WithInput, type WorkflowMetadata, type WorkflowsResult, type WriteEvent, type WriteHook, aggregateSqlFunction, aggregateTableName, applyCdcChanges, applyOnDelete, applySelect, armRestore, assertFlatPredicate, assertReadonly, assertShapeShardable, assertValidClientId, backfillAggregateIndexes, backfillRankIndexes, backfillSearchIndexes, boundingBoxCenter, boundingBoxGeohashes, buildSeekWhere, clearCapturedMail, coerceAggregateNumber, compileWhereSql, containsRelationPredicate, coveringGeohashes, createDependencyTracker, createReadFootprint, createShardCtxDb, createSystemReader, decodeCursor, depKey, diffExternalSource, encodeAggregateKey, encodeCursor, encodeGeohash, encodePartitionKey, ensureMailTable, exportShardRows, exportShardTable, facetColumn, fanOutScalarCounts, foldAggregateTally, guardWriter, hasTrigger, haversineMeters, importShardRows, isRelationPredicate, isSoftDeleted, isSourceDue, liftSourceId, listTables, matchesRankStaticWhere, matchesStaticWhere, materializeExternalRows, materializeExternalRowsIncremental, mergeWhere, normalizeCountArgument, normalizeIdStructurally, normalizeOrderKeys, parseExportShardArgs, parseImportShardArgs, planAggregateLookup, pointInBoundingBox, pullExternalSourceIncrementalTick, pullExternalSourceTick, rankTableName, reactiveCacheKey, readAggregateValue, readBookmark, readCapturedMail, readCdcChanges, readExternalSourceBaseline, readMigrationStatus, readTablePage, recordCapturedMail, renderSql, resolveRankPartition, resolveRelationPredicates, resolveWith, runDataMigration, runExternalSourceTick, runReadonlySql, runRowValidators, runShardMigrations, runTriggers, selectExpiredIds, selectExportTables, selectIndexForAggregate, selectIndexForCount, selectIndexForGroupBy, selectMatchingIds, softDeleteScope, sortColumnName, stableStringify, stableWireKey, subscriptionListDeltas, throwingScheduler, trimCdcChanges, validateImportRow } from '@lunora/shard-engine';
3
3
  import { DatabaseInstrumentation, MetricHistoryOptions, LogEventInput, ContextLogLevel, TraceAnchor, ContextTracer, ContextFetch, ContextMetrics } from '@lunora/observability';
4
4
  import { DrizzleSqliteDODatabase } from 'drizzle-orm/durable-sqlite';
@@ -1131,6 +1131,13 @@ declare abstract class ShardDO {
1131
1131
  * RPC. In-memory only — they reset when the DO hibernates or restarts, which
1132
1132
  * is the right granularity for a "since this instance woke" health readout
1133
1133
  * (durable aggregation would be a separate, heavier feature).
1134
+ *
1135
+ * `subscriptionRefreshErrors` (DO-01) rides along the same lifetime/in-memory
1136
+ * shape: incremented, alongside a structured log, wherever a live-query
1137
+ * refresh or shape poke swallows a per-subscription/per-socket error so its
1138
+ * siblings can keep flushing (`refreshSubscriptions`, `pokeShapeSubscribers`
1139
+ * via `recordSubscriptionRefreshError`). It IS on the `getMetrics` wire
1140
+ * response (`collectMetrics`); a studio panel charting it is a follow-up.
1134
1141
  */
1135
1142
  private readonly metrics;
1136
1143
  /**
@@ -1208,6 +1215,16 @@ declare abstract class ShardDO {
1208
1215
  * call so a leaked tracker can never bleed into a sibling RPC.
1209
1216
  */
1210
1217
  private currentTracker;
1218
+ /**
1219
+ * In-flight range footprint (the `onReadRange` channel) for the
1220
+ * currently-executing cached query. Set by `runCachedQuery` alongside
1221
+ * `currentTracker` so `getCtxDbReadRangeHook` — and the range-marking half
1222
+ * of `getCtxDbReadHook` — can stamp it without threading it explicitly
1223
+ * through every generated handler signature. `ReactiveCache.run`'s ranges
1224
+ * thunk reads it lazily, AFTER the handler resolves, so it always sees the
1225
+ * footprint's final state. Cleared in the same `finally` as `currentTracker`.
1226
+ */
1227
+ private currentReadFootprint;
1211
1228
  /**
1212
1229
  * Tables the in-flight dispatch full-scanned (read via `SCAN_DEP`, no index
1213
1230
  * / point lookup). Allocated at the top of each `/rpc` dispatch and drained
@@ -1248,19 +1265,38 @@ declare abstract class ShardDO {
1248
1265
  */
1249
1266
  private currentRequestReadTables;
1250
1267
  /**
1251
- * Per-statement SQL samples collected during the current `/rpc` dispatch by
1252
- * the instrumented `sql` getter. Drained into the durable
1253
- * `__lunora_metrics_queries` table after the handler returns (same pattern as
1254
- * `currentScannedTables` / `currentIndexHits`). `undefined` when no dispatch
1255
- * is in flight; allocated fresh per dispatch so a previous request's samples
1256
- * never leak into the next one.
1257
- *
1258
- * Each entry is `[rawSql, durationMs, rowsRead, rowsWritten]`. DML rows
1259
- * written is always 0 here the ctx-db adapter doesn't expose a
1268
+ * Per-DISTINCT-statement SQL samples collected during the current `/rpc`
1269
+ * dispatch by the instrumented `sql` getter, keyed by the raw query text.
1270
+ * Drained into the durable `__lunora_metrics_queries` table after the
1271
+ * handler returns (same pattern as `currentScannedTables` /
1272
+ * `currentIndexHits`). `undefined` when no dispatch is in flight; allocated
1273
+ * fresh per dispatch so a previous request's samples never leak into the
1274
+ * next one.
1275
+ *
1276
+ * Keyed by the raw query string rather than a growing array: a handler
1277
+ * that queries in a loop reuses the SAME prepared-statement text on every
1278
+ * iteration (bind parameters travel separately via `...params`, never
1279
+ * inlined into `query`), so folding each call into its entry as it lands
1280
+ * collapses the loop to one entry — {@link ShardDO.flushStmtSamples} then
1281
+ * pays one upsert per DISTINCT statement instead of one per raw execution.
1282
+ * Bounded at {@link MAX_STMT_SAMPLES_PER_DISPATCH} distinct entries; past
1283
+ * that, a brand-new statement shape (ad-hoc SQL built per iteration) is
1284
+ * dropped and `currentStmtSamplesTruncated` is set — already-tracked
1285
+ * statements keep folding regardless.
1286
+ *
1287
+ * `rowsWritten` is always 0 here — the ctx-db adapter doesn't expose a
1260
1288
  * `changes()` count through the structural `SqlExec` surface, so we
1261
1289
  * attribute only SELECT result sizes as `rowsRead`.
1262
1290
  */
1263
1291
  private currentStmtSamples;
1292
+ /**
1293
+ * Set when `currentStmtSamples` hit {@link MAX_STMT_SAMPLES_PER_DISPATCH}
1294
+ * distinct statements and a brand-new shape was dropped this dispatch.
1295
+ * Folded onto the dispatch's wide event as `db.stmt_samples_truncated`
1296
+ * (mirrors `database-telemetry.ts`'s `db.spans_truncated`) so a truncated
1297
+ * leaderboard contribution reads as partial rather than complete.
1298
+ */
1299
+ private currentStmtSamplesTruncated;
1264
1300
  /** Whether the current dispatch's cached query was served from cache; `undefined` until `runCachedQuery` resolves one. */
1265
1301
  private currentRequestCacheHit;
1266
1302
  constructor(state: ShardDOState, env: unknown, options?: ShardDOOptions);
@@ -1315,8 +1351,22 @@ declare abstract class ShardDO {
1315
1351
  * this stays dormant there.
1316
1352
  */
1317
1353
  alarm(): Promise<void>;
1318
- /** Subclasses implement function dispatch. */
1319
- abstract handleRpc(functionPath: string, args: Record<string, unknown>): Promise<unknown>;
1354
+ /**
1355
+ * Subclasses implement function dispatch.
1356
+ *
1357
+ * `headroom` is an optional BY-VALUE override, mirroring
1358
+ * {@link ShardDO.deleteRowThroughWriter}'s pattern: the main `/rpc` dispatch
1359
+ * (`handleFetchCloudflare`) captures its freshly-minted tracker in a LOCAL and
1360
+ * passes it here explicitly, so the ctx this dispatch builds never depends on
1361
+ * `this.currentTransactionHeadroom` still holding the right value by the time
1362
+ * the (possibly `await`-interleaved) handler runs — a concurrent dispatch's
1363
+ * `finally` clearing that shared field could otherwise leave this one
1364
+ * unmetered mid-flight. Callers that dispatch through here without minting
1365
+ * their own tracker (`dispatchLifecycle`, `handleRunAs`) omit it and the
1366
+ * codegen subclass falls back to `this.transactionHeadroom()`, unchanged from
1367
+ * before this parameter existed.
1368
+ */
1369
+ abstract handleRpc(functionPath: string, args: Record<string, unknown>, headroom?: TransactionHeadroomTracker): Promise<unknown>;
1320
1370
  /**
1321
1371
  * The registered function paths to dispatch when a socket connects/disconnects.
1322
1372
  * Base default is empty; the codegen subclass overrides it to return the
@@ -1353,7 +1403,7 @@ declare abstract class ShardDO {
1353
1403
  protected runRelationFanoutRead(_functionPath: string, _args: Record<string, unknown>): Promise<unknown>;
1354
1404
  /**
1355
1405
  * Instrumented SQL handle. Wraps `state.storage.sql` so that every `exec`
1356
- * call during a user RPC dispatch is timed and its result size captured into
1406
+ * call during a user RPC dispatch is timed and its result size folded into
1357
1407
  * `currentStmtSamples`. The samples are flushed to the durable
1358
1408
  * `__lunora_metrics_queries` table after the handler returns (same lifecycle
1359
1409
  * as `currentScannedTables`/`currentIndexHits`).
@@ -1669,8 +1719,14 @@ declare abstract class ShardDO {
1669
1719
  * The base class can't build a writer without the user's `schema.ts`, so it
1670
1720
  * reports the table as unknown; the codegen-generated subclass overrides
1671
1721
  * this to call `writer.delete(id)` on a live `createShardCtxDb(...)` writer.
1722
+ *
1723
+ * `headroom` is an optional BY-VALUE override: {@link ShardDO.runShardBulkDelete}
1724
+ * (a normal `/rpc` dispatch) omits it, so the override falls back to
1725
+ * `this.transactionHeadroom()` — the per-dispatch meter every other write
1726
+ * already uses. {@link ShardDO.pollTtlSweeps} (an alarm work item, no dispatch
1727
+ * in flight) passes its own fresh tracker explicitly instead.
1672
1728
  */
1673
- protected deleteRowThroughWriter(_table: string, _id: string): Promise<void>;
1729
+ protected deleteRowThroughWriter(_table: string, _id: string, _headroom?: TransactionHeadroomTracker): Promise<void>;
1674
1730
  /**
1675
1731
  * Bulk-delete the rows of `table` matching the active `filters`/`search`
1676
1732
  * (or every row, for `clearTable`), bounded to {@link SHARD_BULK_DELETE_CAP}
@@ -2042,6 +2098,17 @@ declare abstract class ShardDO {
2042
2098
  * cadence, so freshly-written rows expire within a bounded window) while any
2043
2099
  * TTL table exists, or `undefined` when there are none — so a DO with no TTL
2044
2100
  * table never arms this tier.
2101
+ *
2102
+ * One {@link ShardDO.alarmHeadroom} tracker covers the WHOLE sweep pass (every
2103
+ * spec, every batch) — not per-row or per-spec — because the ceiling exists to
2104
+ * bound one alarm tick's total isolate cost, not any single table's. A
2105
+ * `TRANSACTION_LIMIT_EXCEEDED` mid-batch is "batch full", not a genuine
2106
+ * failure: `selectExpiredIds` never re-selects an already-deleted row, so
2107
+ * deletion IS the resumable checkpoint here — no separate cursor is needed.
2108
+ * The sweep stops immediately, logs a `warn` (not `recordShapeError`, which
2109
+ * would surface as a genuine failure), and returns `Date.now()` so the shared
2110
+ * alarm re-arms promptly via `nextPollAlarmTarget`'s existing due-now floor,
2111
+ * rather than waiting out the full `TTL_SWEEP_INTERVAL_MS` cadence.
2045
2112
  */
2046
2113
  protected pollTtlSweeps(): Promise<number | undefined>;
2047
2114
  /**
@@ -2084,6 +2151,24 @@ declare abstract class ShardDO {
2084
2151
  * with empty dep sets, so writes never invalidate them and stale
2085
2152
  * results stick around — the {@link ReactiveCache} class is contract-
2086
2153
  * neutral about who fills `deps`.
2154
+ *
2155
+ * Also allocates a fresh {@link ReadFootprint} alongside the tracker,
2156
+ * stored on `this.currentReadFootprint` so `getCtxDbReadRangeHook()` —
2157
+ * and the range-marking half of `getCtxDbReadHook()` — can stamp it. Its
2158
+ * `ranges()` is handed to `reactiveCache.run` as a LAZY 4th argument (a
2159
+ * thunk, evaluated only after `run()` resolves), the same deferral
2160
+ * `deps` already relies on: the footprint is only complete once the
2161
+ * handler has actually run. Subclasses that also want range-precise
2162
+ * invalidation should pass `getCtxDbReadRangeHook()` as `onReadRange` on
2163
+ * the same `createShardCtxDb(...)` call — mirroring `onRead` above. A
2164
+ * subclass that only wires `onRead` still works: `ranges()` degrades to
2165
+ * `undefined` and every read is treated as a whole-table dependency, per
2166
+ * `ReactiveCache.run`'s own default. When `onReadRange` IS wired, a table
2167
+ * `footprint.ranges()` could not narrow (any by-id/scan read, or a
2168
+ * provable range mixed with one) still falls back to a whole-table
2169
+ * `SCAN_DEP`, stamped after `run()` resolves — see the fallback in this
2170
+ * method's body. Only a table read EXCLUSIVELY through provable ranges
2171
+ * gets range-precise invalidation instead.
2087
2172
  */
2088
2173
  protected runCachedQuery<R>(functionPath: string, args: Record<string, unknown>, run: () => Promise<R>): Promise<R>;
2089
2174
  /**
@@ -2099,8 +2184,30 @@ declare abstract class ShardDO {
2099
2184
  * full-scan attribution — and unlike the tracker, it's collected even when
2100
2185
  * the reactive cache is off, since the causal signal is independent of
2101
2186
  * caching.
2187
+ *
2188
+ * It ALSO marks the table unnarrowable on {@link currentReadFootprint},
2189
+ * mirroring `executeSubscription`'s wiring (which hands a single
2190
+ * `ReadFootprint`'s `onRead`/`onReadRange` pair straight to `buildCtx`).
2191
+ * `ctx-db.ts`'s reader calls this `onRead` and `onReadRange` mutually
2192
+ * exclusively per read — a provable index slice fires ONLY `onReadRange`,
2193
+ * everything else (by-id, scan, an unprovable slice) fires ONLY this
2194
+ * `onRead` — so folding the footprint's `onRead` in here is exactly the
2195
+ * "read this table outside a range" signal {@link ReadFootprint.ranges}
2196
+ * needs to drop that table from the narrowed set.
2102
2197
  */
2103
2198
  protected getCtxDbReadHook(): (table: string, idOrScan?: string) => void;
2199
+ /**
2200
+ * Returns an `onReadRange` callback suitable to hand to
2201
+ * `createShardCtxDb`'s `onReadRange` option, alongside `getCtxDbReadHook()`
2202
+ * as `onRead` on the same call — the pairing `executeSubscription` already
2203
+ * uses via `ReadFootprint`. Stamps the in-flight footprint (set by
2204
+ * `runCachedQuery`) when one exists and is a no-op otherwise, so subclasses
2205
+ * can wire this hook unconditionally regardless of whether the cache is
2206
+ * enabled. Without this wiring `runCachedQuery`'s ranges thunk always
2207
+ * observes an empty footprint and every cached query degrades to the prior
2208
+ * whole-table dependency — safe, just not range-precise.
2209
+ */
2210
+ protected getCtxDbReadRangeHook(): (range: KeyRange) => void;
2104
2211
  /**
2105
2212
  * Read hook recording which declared indexes a query actually exercises.
2106
2213
  * Two destinations, both stamped here so a single hook serves the live and
@@ -2143,6 +2250,20 @@ declare abstract class ShardDO {
2143
2250
  * drain would take the refresh branch and lose its own ceiling entirely.
2144
2251
  */
2145
2252
  protected subscriptionHeadroom(): TransactionHeadroomTracker;
2253
+ /**
2254
+ * A fresh budget for one alarm-driven work item — one external-source
2255
+ * table's tick, or one TTL sweep pass.
2256
+ *
2257
+ * Alarm work runs with no client waiting and no `/rpc` dispatch in flight,
2258
+ * so `transactionHeadroom()`'s per-dispatch tracker is `undefined` there —
2259
+ * leaving external-source ingest and TTL sweeps completely unmetered, the
2260
+ * exact isolate-exhaustion class the meter exists to bound. Handed to the
2261
+ * writer BY VALUE, the same pattern as `subscriptionHeadroom()` and for the
2262
+ * same reason: an ambient instance-field flag would race a concurrently
2263
+ * in-flight `/rpc` dispatch, or a sibling alarm work item, clearing or
2264
+ * substituting the wrong tracker mid-flight.
2265
+ */
2266
+ protected alarmHeadroom(): TransactionHeadroomTracker;
2146
2267
  /**
2147
2268
  * Record that `table` was written during the current RPC. Wired into the
2148
2269
  * db adapter's `broadcast` callback by the generated subclass so that
@@ -2440,12 +2561,25 @@ declare abstract class ShardDO {
2440
2561
  * fields. `indexHits` is shaped exactly as the advisor's `AdvisorIndexHit`
2441
2562
  * (`{ table, index, reads }`), so the studio passes it straight to
2442
2563
  * `runLints({ ..., indexHits })` after summing the per-shard arrays.
2564
+ *
2565
+ * `subscriptionRefreshErrors` (DO-01) rides along the same way: an
2566
+ * in-memory-only lifetime count (no durable table, unlike `requests`/
2567
+ * `errors`), incremented by `recordSubscriptionRefreshError` whenever a live
2568
+ * query refresh or shape poke swallows a per-subscription error to protect
2569
+ * its siblings. The field is on the wire so it is queryable/testable now;
2570
+ * charting it in the studio's metrics panel is a follow-up.
2443
2571
  */
2444
2572
  private collectMetrics;
2445
2573
  /**
2446
2574
  * Fold one dispatch into the per-function counters keyed by `functionPath`,
2447
2575
  * creating the entry on first sight. `errorMessage` is supplied only when
2448
- * the handler threw, in which case the failure counters advance too.
2576
+ * the handler threw, in which case the failure counters advance too. The
2577
+ * caller is expected to have already redacted `errorMessage` (via
2578
+ * `redactArgs`, the same `standardRules` treatment the request-log sinks
2579
+ * use) — this method persists/caches it verbatim into BOTH the durable
2580
+ * `__lunora_metrics.last_error_message` column and the in-memory
2581
+ * `functionStats.lastErrorMessage` served by `getFunctionStats`, so an
2582
+ * un-redacted message reaching here leaks into the Studio.
2449
2583
  * `scannedTables` carries the tables the dispatch full-scanned (collected by
2450
2584
  * `getCtxDbReadHook`), which advance the causal scan attribution.
2451
2585
  * `indexHits` carries the declared indexes it exercised (collected by
@@ -2464,9 +2598,16 @@ declare abstract class ShardDO {
2464
2598
  */
2465
2599
  private recordFunctionCall;
2466
2600
  /**
2467
- * Flush per-statement SQL samples accumulated during the current dispatch
2468
- * into the durable `__lunora_metrics_queries` table. Called after
2469
- * `recordFunctionCall` on both the success and error paths.
2601
+ * Flush the per-DISTINCT-statement SQL samples accumulated during the
2602
+ * current dispatch into the durable `__lunora_metrics_queries` table.
2603
+ * Called after `recordFunctionCall` on both the success and error paths.
2604
+ *
2605
+ * Already folded by the instrumented `sql` getter (see
2606
+ * `currentStmtSamples`), so this pays exactly one `recordQueryMetric` call
2607
+ * — one accumulator upsert plus one bucket upsert — per distinct statement
2608
+ * the dispatch ran, however many times it actually ran. `count` carries the
2609
+ * real execution count through so the durable `exec_count`/`total_duration_ms`
2610
+ * still reflect every execution, not just one.
2470
2611
  *
2471
2612
  * Best-effort: a SQL failure (e.g. a test double without a usable `sql`
2472
2613
  * handle) must never fail the response, so every call is swallowed.
@@ -2492,8 +2633,8 @@ declare abstract class ShardDO {
2492
2633
  /**
2493
2634
  * Per-function coarse time-series served additively by the metrics RPC, so
2494
2635
  * the studio can chart call/error history. Reads the durable
2495
- * `__lunora_metrics_buckets` table; returns `[]` when persistence is
2496
- * unavailable so the response stays well-formed.
2636
+ * `__lunora_metrics_buckets` table; returns an empty, non-truncated result
2637
+ * when persistence is unavailable so the response stays well-formed.
2497
2638
  */
2498
2639
  private collectFunctionMetricBuckets;
2499
2640
  private maybeWarnRootSize;
@@ -2914,15 +3055,26 @@ declare abstract class ShardDO {
2914
3055
  * @returns the result and table-dependency set for a read op, or `null` for a write/migration op
2915
3056
  */
2916
3057
  private readAdminOp;
3058
+ /**
3059
+ * Shared shape behind `describeTables` and `listTablesIndexes`: read the
3060
+ * `tables` arg, run `lookup` (a cheap, synchronous, schema-sourced `this.*()`
3061
+ * hook) over each, and report the requested set as the read's table
3062
+ * dependency (or the {@link ADMIN_WILDCARD} sentinel when none were named).
3063
+ * Factored out so `readAdminTableSignal` states each batched RPC as one line
3064
+ * rather than duplicating the array-filter/fan-out shape per sibling.
3065
+ */
3066
+ private batchedTableLookup;
2917
3067
  /**
2918
3068
  * Resolve the table-scoped introspection reads whose payload is a single
2919
3069
  * `this.*()` lookup keyed by an optional `table` arg — `listTableIndexes`
2920
3070
  * (declared indexes), `describeTable` (declared columns) and `migrationStatus`
2921
- * (the migration ledger). The first two carry their `table` (or the
2922
- * {@link ADMIN_WILDCARD} sentinel when unscoped); `migrationStatus` is
2923
- * deployment-wide, so it always carries the wildcard. Returns `undefined` for
2924
- * any other path so {@link readAdminOp} falls through; folded into one helper
2925
- * to keep that dispatcher under its complexity budget.
3071
+ * (the migration ledger); plus their batched siblings `describeTables` and
3072
+ * `listTablesIndexes` (one RPC for N tables via {@link batchedTableLookup}).
3073
+ * The single-table pair carries its `table` (or the {@link ADMIN_WILDCARD}
3074
+ * sentinel when unscoped); `migrationStatus` is deployment-wide, so it always
3075
+ * carries the wildcard. Returns `undefined` for any other path so
3076
+ * {@link readAdminOp} falls through; folded into one helper to keep that
3077
+ * dispatcher under its complexity budget.
2926
3078
  * @returns the read result and its table-dependency set, or `undefined` when the path is not owned by this resolver
2927
3079
  */
2928
3080
  private readAdminTableSignal;
@@ -3220,6 +3372,32 @@ declare abstract class ShardDO {
3220
3372
  * high-fanout shards rather than bolt a second, semantically-divergent dedup
3221
3373
  * into this loop.
3222
3374
  */
3375
+ /**
3376
+ * Count and log a subscription-delivery error that its caller is about to
3377
+ * swallow (DO-01) — `refreshSubscriptions`' per-`(socket, sub)` catch and
3378
+ * `pokeShapeSubscribers`' per-socket catch both call this instead of a bare
3379
+ * `catch { continue; }`, so a live query or shape poke that throws
3380
+ * DETERMINISTICALLY on every flush is counted on `metrics.subscriptionRefreshErrors`
3381
+ * and shows up in the studio's Live Logs, rather than repeating silently for
3382
+ * the life of the socket. Factored out because both call sites need the
3383
+ * identical counter-then-best-effort-log shape, and duplicating it inline
3384
+ * pushed each closure over the file's cognitive-complexity budget.
3385
+ *
3386
+ * `lastTelemetrySink` (not a threaded `sink`) because both flush workers run
3387
+ * with no `ctx` — the same stand-in `flushTelemetry` uses.
3388
+ *
3389
+ * `error` is a caught INTERNAL failure surfaced from a background
3390
+ * refresh/poke pass, not a value a developer chose to log via `ctx.log` —
3391
+ * so `recordUserLog`'s "args are not redacted" contract (see its
3392
+ * docstring) does not apply here: a thrown value can carry an arbitrary
3393
+ * `cause`, stack, or custom own property (a handler can `throw
3394
+ * Object.assign(new Error(...), { row })`), and `args` rides raw into any
3395
+ * `sink.onLog` an operator has configured. Route it through the same
3396
+ * `toErrorBody` envelope every other error-crossing boundary in this file
3397
+ * uses (see `errorToResponse`, the shape-seed catches above) so only a
3398
+ * bounded `{ code, message }` — not the raw error — reaches the sink.
3399
+ */
3400
+ private recordSubscriptionRefreshError;
3223
3401
  private refreshSubscriptions;
3224
3402
  /**
3225
3403
  * Seed a freshly-registered subscription with its first value. Runs the
@@ -3309,9 +3487,10 @@ declare abstract class ShardDO {
3309
3487
  * the results into the poke parts to send and the per-shape memo advances. A
3310
3488
  * `.global()` shape (driven by the alarm poll loop, not this flush) and a shape
3311
3489
  * whose table didn't change are skipped; a shape whose resolve/diff throws is
3312
- * logged and skipped with its memo unadvanced so a later flush retries. Empty
3313
- * diffs advance unconditionally; part-bearing shapes advance only once the
3314
- * caller confirms the poke was delivered.
3490
+ * counted and logged via `recordSubscriptionRefreshError` (DO-01) and skipped
3491
+ * with its memo unadvanced so a later flush retries. Empty diffs advance
3492
+ * unconditionally; part-bearing shapes advance only once the caller confirms
3493
+ * the poke was delivered.
3315
3494
  */
3316
3495
  private collectShapePokeParts;
3317
3496
  /**
@@ -3404,6 +3583,16 @@ declare abstract class ShardDO {
3404
3583
  * default, since neither knows a more precise due time yet.
3405
3584
  */
3406
3585
  private scheduleGlobalPoll;
3586
+ /**
3587
+ * Delete one expired row through {@link ShardDO.deleteRowThroughWriter},
3588
+ * absorbing a `TRANSACTION_LIMIT_EXCEEDED` as "batch full" rather than
3589
+ * letting it propagate — split out of {@link ShardDO.pollTtlSweeps} to keep
3590
+ * that method's own complexity down. Returns `true` when the limit was hit
3591
+ * (the caller must stop the sweep pass) and logs a `warn` recording it; `false`
3592
+ * on an ordinary successful delete. Any OTHER thrown error still propagates —
3593
+ * only the meter's own signal is contained here.
3594
+ */
3595
+ private deleteExpiredTtlRow;
3407
3596
  /**
3408
3597
  * Record a contained shape-tier error (poll / poke / seed) into the DO's log
3409
3598
  * ring without aborting the rest of the pass. The shape pipeline is a
@@ -3478,6 +3667,14 @@ declare abstract class ShardDO {
3478
3667
  * persist its resume position and replay it as `sinceSeq` on reconnect
3479
3668
  * (Pillar 1b). Omitted on shards without CDC, keeping the wire byte-identical
3480
3669
  * to the pre-cursor format.
3670
+ *
3671
+ * `clientWatermark` is this socket's `socketClientWatermark(ws)` — read
3672
+ * ONCE by the caller and passed in, not recomputed here. A single
3673
+ * write-flush can call this method many times for the same socket (once
3674
+ * per affected subscription — see `refreshOne`), and the watermark
3675
+ * depends only on `ws`, never on `subId`/`outcome`, so recomputing it per
3676
+ * subscription was a redundant `SELECT … FROM __client_watermark` per
3677
+ * subscription per socket per flush.
3481
3678
  */
3482
3679
  private pushSubscriptionData;
3483
3680
  /**
@@ -3559,13 +3756,17 @@ declare abstract class ShardDO {
3559
3756
  * harness double) or a pre-CDC shard, so callers degrade to the no-CDC path.
3560
3757
  */
3561
3758
  private cdcEnabled;
3562
- /** Whether `ws` carries a credential whose expiry (stamped at upgrade) is now past. */
3759
+ /**
3760
+ * Whether `ws` carries a credential whose expiry (stamped at upgrade) is
3761
+ * now past. Delegates to the shared boundary check `@lunora/agent`'s
3762
+ * voice DO uses for the same decision, so the two DOs can never disagree
3763
+ * about it.
3764
+ */
3563
3765
  private isSocketExpired;
3564
3766
  /**
3565
- * Send the `TOKEN_EXPIRED` error frame and close the socket with code 4001 so
3566
- * the client distinguishes an expired-credential drop from an ordinary one
3567
- * and refreshes before reconnecting. Best-effort: a throw (socket already
3568
- * gone) is swallowed — this must never escape the hibernation handlers.
3767
+ * Drop an expired-credential socket via the shared `TOKEN_EXPIRED`/`4001`
3768
+ * helper `@lunora/agent`'s voice DO also calls, so both DOs send the
3769
+ * client-facing wire shape from one place.
3569
3770
  */
3570
3771
  private dropExpiredSocket;
3571
3772
  /**