@legioncodeinc/honeycomb 0.1.6 → 0.1.7

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/daemon/index.js CHANGED
@@ -7369,7 +7369,7 @@ var require_dist = __commonJS({
7369
7369
  // dist/src/shared/constants.js
7370
7370
  var DAEMON_PORT = 3850;
7371
7371
  var DAEMON_HOST = "127.0.0.1";
7372
- var HONEYCOMB_VERSION = true ? "0.1.6" : "0.0.0-dev";
7372
+ var HONEYCOMB_VERSION = true ? "0.1.7" : "0.0.0-dev";
7373
7373
 
7374
7374
  // node_modules/zod/v4/classic/external.js
7375
7375
  var external_exports = {};
@@ -26904,6 +26904,36 @@ function appendOnlyInsert(client, target, scope, row) {
26904
26904
  const sql = buildInsert(target.table, row);
26905
26905
  return withHeal(client, target, scope, () => client.query(sql, scope));
26906
26906
  }
26907
+ function buildInsertMany(table, rows) {
26908
+ if (rows.length === 0) {
26909
+ throw new Error("buildInsertMany: at least one row is required");
26910
+ }
26911
+ const tbl = sqlIdent(table);
26912
+ const first = rows[0];
26913
+ const colNames = first.map(([name]) => name);
26914
+ for (const row of rows)
26915
+ assertSameColumns(colNames, row);
26916
+ const cols = colNames.map((name) => sqlIdent(name)).join(", ");
26917
+ const vals = rows.map((row) => `(${row.map(([, v]) => renderValue(v)).join(", ")})`).join(", ");
26918
+ return `INSERT INTO "${tbl}" (${cols}) VALUES ${vals}`;
26919
+ }
26920
+ function assertSameColumns(expected, row) {
26921
+ if (row.length !== expected.length) {
26922
+ throw new Error(`buildInsertMany: row column count ${row.length} != expected ${expected.length}`);
26923
+ }
26924
+ for (let i = 0; i < expected.length; i++) {
26925
+ const actual = row[i][0];
26926
+ if (actual !== expected[i]) {
26927
+ throw new Error(`buildInsertMany: row column "${actual}" != expected "${expected[i]}" at index ${i}`);
26928
+ }
26929
+ }
26930
+ }
26931
+ function appendOnlyInsertMany(client, target, scope, rows, opts) {
26932
+ if (rows.length === 0)
26933
+ return Promise.resolve(ok([], 0));
26934
+ const sql = buildInsertMany(target.table, rows);
26935
+ return withHeal(client, target, scope, () => client.query(sql, scope, opts));
26936
+ }
26907
26937
  async function readLatestVersion(client, target, scope, keyColumn, keyValue, selectColumns = "*") {
26908
26938
  const tbl = sqlIdent(target.table);
26909
26939
  const key = sqlIdent(keyColumn);
@@ -26988,6 +27018,8 @@ function resolveConfig(config2, ownerFallback) {
26988
27018
  var RESOLVE_POLLS = 8;
26989
27019
  var DISCOVER_POLLS = 8;
26990
27020
  var LEASE_CANDIDATE_TRIES = 8;
27021
+ var SOURCE_LEASE = "poll-lease";
27022
+ var SOURCE_REAPER = "poll-reaper";
26991
27023
  function defaultClock2() {
26992
27024
  return {
26993
27025
  now: () => Date.now(),
@@ -27164,7 +27196,7 @@ var DeepLakeJobQueueService = class {
27164
27196
  ]);
27165
27197
  if (!wrote)
27166
27198
  return null;
27167
- const current = await this.resolveCurrent(candidate.id);
27199
+ const current = await this.resolveCurrent(candidate.id, SOURCE_LEASE);
27168
27200
  if (current !== null && current.leaseOwner === owner && current.status === JOB_LEASED) {
27169
27201
  return {
27170
27202
  id: candidate.id,
@@ -27189,7 +27221,7 @@ var DeepLakeJobQueueService = class {
27189
27221
  */
27190
27222
  async selectLeasable(exclude, kinds) {
27191
27223
  const nowIso10 = this.nowIso();
27192
- const states = await this.discoverIds();
27224
+ const states = await this.discoverIds(SOURCE_LEASE);
27193
27225
  const leasable = states.filter((s) => !exclude.has(s.id) && (kinds === void 0 || kinds.includes(s.type)) && (s.status === JOB_QUEUED || s.status === JOB_FAILED) && s.nextRunAt !== "" && s.nextRunAt <= nowIso10);
27194
27226
  if (leasable.length === 0)
27195
27227
  return null;
@@ -27204,12 +27236,12 @@ var DeepLakeJobQueueService = class {
27204
27236
  * growing. Then resolves each id's current state via {@link resolveCurrent}. The
27205
27237
  * `__ensure__` sentinel row (see {@link ensureTable}) is filtered out.
27206
27238
  */
27207
- async discoverIds() {
27239
+ async discoverIds(source) {
27208
27240
  const ids = /* @__PURE__ */ new Set();
27209
27241
  let lastSize = -1;
27210
27242
  for (let poll = 0; poll < DISCOVER_POLLS; poll++) {
27211
27243
  const sql = `SELECT DISTINCT ${sqlIdent("id")} FROM "${this.tbl()}"`;
27212
- const res = await this.storage.query(sql, this.scope);
27244
+ const res = await this.storage.query(sql, this.scope, source !== void 0 ? { source } : {});
27213
27245
  if (isOk(res)) {
27214
27246
  for (const row of res.rows) {
27215
27247
  const id = rowText(row, "id");
@@ -27223,7 +27255,7 @@ var DeepLakeJobQueueService = class {
27223
27255
  }
27224
27256
  const states = [];
27225
27257
  for (const id of ids) {
27226
- const state = await this.resolveCurrent(id);
27258
+ const state = await this.resolveCurrent(id, source);
27227
27259
  if (state !== null)
27228
27260
  states.push(state);
27229
27261
  }
@@ -27239,11 +27271,11 @@ var DeepLakeJobQueueService = class {
27239
27271
  * when the id has no row at all. Short-circuits once a max-version row is seen
27240
27272
  * twice (the fake is decisive on the first read).
27241
27273
  */
27242
- async resolveCurrent(id) {
27274
+ async resolveCurrent(id, source) {
27243
27275
  let best = null;
27244
27276
  let seenBestTwice = false;
27245
27277
  for (let poll = 0; poll < RESOLVE_POLLS; poll++) {
27246
- const row = await this.latestById(id);
27278
+ const row = await this.latestById(id, source);
27247
27279
  if (row !== null) {
27248
27280
  const state = toJobState(row);
27249
27281
  if (best === null || state.version > best.version) {
@@ -27259,10 +27291,10 @@ var DeepLakeJobQueueService = class {
27259
27291
  return best;
27260
27292
  }
27261
27293
  /** One highest-version by-id read of the full job row, or `null` when absent. */
27262
- async latestById(id) {
27294
+ async latestById(id, source) {
27263
27295
  const cols = STATE_COLUMNS.map((c) => sqlIdent(c)).join(", ");
27264
27296
  const sql = `SELECT ${cols} FROM "${this.tbl()}" WHERE ${sqlIdent("id")} = ${sLiteral(id)} ORDER BY ${sqlIdent("version")} DESC LIMIT 1`;
27265
- const res = await this.storage.query(sql, this.scope);
27297
+ const res = await this.storage.query(sql, this.scope, source !== void 0 ? { source } : {});
27266
27298
  if (isOk(res) && res.rows.length > 0)
27267
27299
  return res.rows[0];
27268
27300
  return null;
@@ -27362,7 +27394,7 @@ var DeepLakeJobQueueService = class {
27362
27394
  */
27363
27395
  async reapExpiredLeases() {
27364
27396
  const nowIso10 = this.nowIso();
27365
- const states = await this.discoverIds();
27397
+ const states = await this.discoverIds(SOURCE_REAPER);
27366
27398
  const expired = states.filter((s) => s.status === JOB_LEASED && s.leaseExpiresAt !== "" && s.leaseExpiresAt <= nowIso10);
27367
27399
  if (expired.length === 0)
27368
27400
  return 0;
@@ -28464,7 +28496,7 @@ function buildAllowedProperties(input) {
28464
28496
  }
28465
28497
  var systemTelemetryClock = () => (/* @__PURE__ */ new Date()).toISOString();
28466
28498
  var DEFAULT_EMIT_TIMEOUT_MS = 2e3;
28467
- var HONEYCOMB_VERSION2 = true ? "0.1.6" : "0.0.0-dev";
28499
+ var HONEYCOMB_VERSION2 = true ? "0.1.7" : "0.0.0-dev";
28468
28500
  async function emitTelemetry(event, opts, deps = {}) {
28469
28501
  const env = deps.env ?? process.env;
28470
28502
  const key = deps.posthogKey ?? POSTHOG_KEY;
@@ -31094,15 +31126,204 @@ function parseCaptureRequest(body) {
31094
31126
  return { ok: false, error: issues };
31095
31127
  }
31096
31128
 
31129
+ // dist/src/daemon/runtime/capture/capture-buffer.js
31130
+ var realBufferClock = {
31131
+ now: () => Date.now(),
31132
+ setTimer: (fn, ms) => {
31133
+ const t = setTimeout(fn, ms);
31134
+ if (typeof t === "object" && t !== null && "unref" in t && typeof t.unref === "function")
31135
+ t.unref();
31136
+ return t;
31137
+ },
31138
+ clearTimer: (handle) => clearTimeout(handle)
31139
+ };
31140
+ var DEFAULT_MAX_EVENTS = 25;
31141
+ var DEFAULT_WINDOW_MS = 1e3;
31142
+ var CaptureBuffer = class {
31143
+ maxEvents;
31144
+ windowMs;
31145
+ clock;
31146
+ flushFn;
31147
+ /** The current window's buffered items. */
31148
+ items = [];
31149
+ /** The pending time-flush timer, or null when the window is empty. */
31150
+ timer = null;
31151
+ /** The in-flight flush, so a second trigger awaits it rather than racing it. */
31152
+ inFlight = Promise.resolve();
31153
+ /** Set on `close()` so a late `add` after shutdown is rejected, not silently buffered-then-lost. */
31154
+ closed = false;
31155
+ constructor(flushFn, config2 = {}, clock = realBufferClock) {
31156
+ this.flushFn = flushFn;
31157
+ this.maxEvents = Math.max(1, config2.maxEvents ?? DEFAULT_MAX_EVENTS);
31158
+ this.windowMs = Math.max(1, config2.windowMs ?? DEFAULT_WINDOW_MS);
31159
+ this.clock = clock;
31160
+ }
31161
+ /** Number of items currently buffered (for assertions / diagnostics). */
31162
+ get size() {
31163
+ return this.items.length;
31164
+ }
31165
+ /**
31166
+ * Buffer one item. Starts the time window on the first item of an empty buffer,
31167
+ * and triggers an immediate flush when the size cap is reached. Returns a promise
31168
+ * that resolves when THIS item has been flushed (either by the size cap it just
31169
+ * tripped, or by a later time/force flush), so a caller that needs the durable
31170
+ * write before responding can await it; a caller that wants fire-and-forget
31171
+ * batching simply does not await.
31172
+ */
31173
+ add(item) {
31174
+ if (this.closed) {
31175
+ return Promise.reject(new Error("CaptureBuffer.add after close"));
31176
+ }
31177
+ this.items.push(item);
31178
+ if (this.items.length === 1)
31179
+ this.startTimer();
31180
+ if (this.items.length >= this.maxEvents)
31181
+ return this.flushNow();
31182
+ return this.inFlight;
31183
+ }
31184
+ /**
31185
+ * Force a flush of the current window NOW (window close / shutdown drain). Cancels
31186
+ * the pending timer, swaps out the buffered batch, and appends it as one multi-row
31187
+ * write. Awaits any in-flight flush first so two flushes never overlap. A no-op
31188
+ * (resolved) when the buffer is empty.
31189
+ */
31190
+ flushNow() {
31191
+ this.cancelTimer();
31192
+ if (this.items.length === 0)
31193
+ return this.inFlight;
31194
+ const batch = this.items;
31195
+ this.items = [];
31196
+ this.inFlight = this.inFlight.then(() => this.flushFn(batch));
31197
+ return this.inFlight;
31198
+ }
31199
+ /**
31200
+ * Drain + close (graceful shutdown, AC-5 / AC-62c.1.2). Flushes the remaining
31201
+ * window so nothing buffered is lost on a clean stop, then marks the buffer closed
31202
+ * so a late `add` is rejected rather than buffered into a buffer that will never
31203
+ * flush again. Idempotent.
31204
+ */
31205
+ async close() {
31206
+ if (this.closed) {
31207
+ await this.inFlight;
31208
+ return;
31209
+ }
31210
+ const drained = this.flushNow();
31211
+ this.closed = true;
31212
+ await drained;
31213
+ }
31214
+ /** Start the time-flush timer for the current window (called on the first buffered item). */
31215
+ startTimer() {
31216
+ this.cancelTimer();
31217
+ this.timer = this.clock.setTimer(() => {
31218
+ this.timer = null;
31219
+ void this.flushNow();
31220
+ }, this.windowMs);
31221
+ }
31222
+ /** Cancel + clear the pending time-flush timer, if any. */
31223
+ cancelTimer() {
31224
+ if (this.timer !== null) {
31225
+ this.clock.clearTimer(this.timer);
31226
+ this.timer = null;
31227
+ }
31228
+ }
31229
+ };
31230
+
31231
+ // dist/src/daemon/runtime/capture/capture-config.js
31232
+ var DEFAULT_CAPTURE_WINDOW_MS = 1e3;
31233
+ var DEFAULT_CAPTURE_MAX_EVENTS = 25;
31234
+ var DEFAULT_CAPTURE_ENVELOPE_BUDGET_BYTES = 16384;
31235
+ var BoolFlag = external_exports.preprocess((raw2) => {
31236
+ if (typeof raw2 === "boolean")
31237
+ return raw2;
31238
+ return raw2 === "true" || raw2 === "1";
31239
+ }, external_exports.boolean());
31240
+ function ClampedInt(def, min = 0) {
31241
+ return external_exports.preprocess((raw2) => {
31242
+ const n = typeof raw2 === "number" ? raw2 : Number(raw2);
31243
+ if (!Number.isFinite(n))
31244
+ return def;
31245
+ return Math.max(min, Math.trunc(n));
31246
+ }, external_exports.number().int());
31247
+ }
31248
+ var CaptureConfigSchema = external_exports.object({
31249
+ /** Master switch for write batching; DEFAULT-ON (L-X1). Off ⇒ one INSERT per event. */
31250
+ batch: BoolFlag.default(true),
31251
+ /** Time-flush window in ms (AC-5). */
31252
+ windowMs: ClampedInt(DEFAULT_CAPTURE_WINDOW_MS, 1).default(DEFAULT_CAPTURE_WINDOW_MS),
31253
+ /** Size-flush cap in events (AC-5). */
31254
+ maxEvents: ClampedInt(DEFAULT_CAPTURE_MAX_EVENTS, 1).default(DEFAULT_CAPTURE_MAX_EVENTS),
31255
+ /** Per-field tool-I/O byte budget; `0` disables trimming (full envelope, pre-062c). */
31256
+ envelopeBudgetBytes: ClampedInt(DEFAULT_CAPTURE_ENVELOPE_BUDGET_BYTES, 0).default(DEFAULT_CAPTURE_ENVELOPE_BUDGET_BYTES)
31257
+ });
31258
+ var CAPTURE_ENV_KEYS = {
31259
+ batch: "HONEYCOMB_CAPTURE_BATCH",
31260
+ windowMs: "HONEYCOMB_CAPTURE_WINDOW_MS",
31261
+ maxEvents: "HONEYCOMB_CAPTURE_MAX_EVENTS",
31262
+ envelopeBudgetBytes: "HONEYCOMB_CAPTURE_ENVELOPE_BUDGET_BYTES"
31263
+ };
31264
+ function resolveCaptureConfig(env = process.env) {
31265
+ const parsed = CaptureConfigSchema.safeParse({
31266
+ batch: env[CAPTURE_ENV_KEYS.batch],
31267
+ windowMs: env[CAPTURE_ENV_KEYS.windowMs],
31268
+ maxEvents: env[CAPTURE_ENV_KEYS.maxEvents],
31269
+ envelopeBudgetBytes: env[CAPTURE_ENV_KEYS.envelopeBudgetBytes]
31270
+ });
31271
+ return parsed.success ? parsed.data : CaptureConfigSchema.parse({});
31272
+ }
31273
+
31274
+ // dist/src/daemon/runtime/capture/budgeted-stringify.js
31275
+ var DEFAULT_ENVELOPE_BUDGET_BYTES = 16384;
31276
+ function truncationMarker(originalBytes) {
31277
+ return `\u2026[truncated ${originalBytes} bytes]`;
31278
+ }
31279
+ function byteLength(value) {
31280
+ return Buffer.byteLength(value, "utf8");
31281
+ }
31282
+ function capToolField(value, budgetBytes) {
31283
+ if (value === void 0)
31284
+ return void 0;
31285
+ let serialized;
31286
+ try {
31287
+ serialized = JSON.stringify(value);
31288
+ } catch {
31289
+ return void 0;
31290
+ }
31291
+ if (serialized === void 0)
31292
+ return void 0;
31293
+ if (byteLength(serialized) <= budgetBytes)
31294
+ return value;
31295
+ return truncationMarker(byteLength(serialized));
31296
+ }
31297
+ function trimEvent(event, budgetBytes) {
31298
+ if (event.kind !== "tool_call")
31299
+ return event;
31300
+ const cappedInput = capToolField(event.input, budgetBytes);
31301
+ const cappedResponse = capToolField(event.response, budgetBytes);
31302
+ if (cappedInput === event.input && cappedResponse === event.response)
31303
+ return event;
31304
+ return {
31305
+ kind: "tool_call",
31306
+ tool: event.tool,
31307
+ ...cappedInput !== void 0 ? { input: cappedInput } : {},
31308
+ ...cappedResponse !== void 0 ? { response: cappedResponse } : {}
31309
+ };
31310
+ }
31311
+ function budgetedStringify(event, metadata, budgetBytes = DEFAULT_ENVELOPE_BUDGET_BYTES) {
31312
+ const trimmedEvent = trimEvent(event, budgetBytes);
31313
+ return JSON.stringify({ event: trimmedEvent, metadata });
31314
+ }
31315
+
31097
31316
  // dist/src/daemon/runtime/capture/capture-handler.js
31098
31317
  var HOOKS_GROUP = "/api/hooks";
31318
+ var CAPTURE_WRITE_SOURCE = "capture-write";
31099
31319
  var CAPTURE_PATH = "/capture";
31100
31320
  var CONVERSATION_PATH = "/conversation";
31101
31321
  function createCaptureHandler(deps) {
31102
31322
  const counters = deps.counters ?? new TurnCounters(deps.counterConfig);
31103
31323
  const embed = deps.embed ?? noopEmbedAttachment;
31104
31324
  const now = deps.now ?? (() => Date.now());
31105
- const handler = new CaptureRouteHandler(deps, counters, embed, now);
31325
+ const config2 = deps.captureConfig ?? resolveCaptureConfig();
31326
+ const handler = new CaptureRouteHandler(deps, counters, embed, now, config2);
31106
31327
  return {
31107
31328
  register(daemon) {
31108
31329
  const group = daemon.group(HOOKS_GROUP);
@@ -31112,7 +31333,8 @@ function createCaptureHandler(deps) {
31112
31333
  group.post(CAPTURE_PATH, (c) => handler.handleCapture(c));
31113
31334
  group.get(CONVERSATION_PATH, (c) => handler.handleConversation(c));
31114
31335
  },
31115
- counters
31336
+ counters,
31337
+ flush: () => handler.flush()
31116
31338
  };
31117
31339
  }
31118
31340
  var CaptureRouteHandler = class {
@@ -31120,11 +31342,19 @@ var CaptureRouteHandler = class {
31120
31342
  counters;
31121
31343
  embed;
31122
31344
  now;
31123
- constructor(deps, counters, embed, now) {
31345
+ config;
31346
+ /**
31347
+ * PRD-062c (L-C1): the capture write buffer. NULL when batching is off — the handler
31348
+ * then does one append-only INSERT per event (the pre-062c path). Lazily created on the
31349
+ * first buffered write so a flag-off handler allocates nothing.
31350
+ */
31351
+ buffer = null;
31352
+ constructor(deps, counters, embed, now, config2) {
31124
31353
  this.deps = deps;
31125
31354
  this.counters = counters;
31126
31355
  this.embed = embed;
31127
31356
  this.now = now;
31357
+ this.config = config2;
31128
31358
  }
31129
31359
  /**
31130
31360
  * POST /api/hooks/capture (FR-1..5, FR-7..9 / a-AC-1..5).
@@ -31153,10 +31383,16 @@ var CaptureRouteHandler = class {
31153
31383
  const nowIso10 = new Date(this.now()).toISOString();
31154
31384
  const projectId = this.resolveCaptureProjectId(metadata);
31155
31385
  const row = this.buildRow(id, event, metadata, nowIso10, projectId);
31156
- const result = await appendOnlyInsert(this.deps.storage, this.deps.sessionsTarget, scope, row);
31157
- if (!isOk(result)) {
31158
- this.deps.logger?.event("capture.insert.failed", { id, kind: result.kind });
31159
- return c.json({ error: "capture_failed", reason: "could not write the session row" }, 502);
31386
+ if (this.config.batch) {
31387
+ this.bufferRow(id, row, scope);
31388
+ } else {
31389
+ const result = await appendOnlyInsertMany(this.deps.storage, this.deps.sessionsTarget, scope, [row], {
31390
+ source: CAPTURE_WRITE_SOURCE
31391
+ });
31392
+ if (!isOk(result)) {
31393
+ this.deps.logger?.event("capture.insert.failed", { id, kind: result.kind });
31394
+ return c.json({ error: "capture_failed", reason: "could not write the session row" }, 502);
31395
+ }
31160
31396
  }
31161
31397
  const cues = this.bumpCounters(metadata);
31162
31398
  await this.enqueueCues(cues);
@@ -31189,6 +31425,67 @@ var CaptureRouteHandler = class {
31189
31425
  }
31190
31426
  return c.json({ path: path4.trim(), rows: result.rows });
31191
31427
  }
31428
+ /**
31429
+ * Buffer one built row for batched flushing (PRD-062c L-C1). Lazily creates the
31430
+ * buffer on first use (a flag-off handler never allocates one). The per-item flush
31431
+ * promise the buffer returns is observed fire-and-forget: a flush failure is logged
31432
+ * here (never swallowed) but does NOT fail the captured turn — the row is committed
31433
+ * to the in-memory window, which the buffer GUARANTEES to flush (window / size /
31434
+ * shutdown). This is the documented trade: worst-case loss is one window on a hard
31435
+ * crash (see {@link CaptureBuffer}); a graceful stop drains the buffer.
31436
+ */
31437
+ bufferRow(id, row, scope) {
31438
+ const buffer = this.ensureBuffer();
31439
+ void buffer.add({ row, scope }).catch((err) => {
31440
+ this.deps.logger?.event("capture.flush.failed", {
31441
+ id,
31442
+ reason: err instanceof Error ? err.message : String(err)
31443
+ });
31444
+ });
31445
+ }
31446
+ /** Lazily build the capture write buffer from the resolved config + the flush callback. */
31447
+ ensureBuffer() {
31448
+ if (this.buffer === null) {
31449
+ const cfg = { maxEvents: this.config.maxEvents, windowMs: this.config.windowMs };
31450
+ this.buffer = this.deps.bufferClock !== void 0 ? new CaptureBuffer((batch) => this.flushBatch(batch), cfg, this.deps.bufferClock) : new CaptureBuffer((batch) => this.flushBatch(batch), cfg);
31451
+ }
31452
+ return this.buffer;
31453
+ }
31454
+ /**
31455
+ * Flush a buffered batch as multi-row append(s) (PRD-062c L-C1 / AC-5). Rows that
31456
+ * share a tenancy scope are grouped and written with ONE `appendOnlyInsertMany`, so N
31457
+ * within-window same-scope events become ONE DeepLake write (AC-62c.1.1). Different
31458
+ * scopes (the rare cross-tenant interleave within a window) each get their own append —
31459
+ * a multi-row INSERT cannot span partitions. Every append threads the `capture-write`
31460
+ * 062a meter source. A failed append rejects so the awaiter ({@link bufferRow}) logs it.
31461
+ */
31462
+ async flushBatch(batch) {
31463
+ for (const [scope, rows] of groupRowsByScope(batch)) {
31464
+ const result = await appendOnlyInsertMany(this.deps.storage, this.deps.sessionsTarget, scope, rows, {
31465
+ source: CAPTURE_WRITE_SOURCE
31466
+ });
31467
+ if (!isOk(result)) {
31468
+ this.deps.logger?.event("capture.batch_insert.failed", { count: rows.length, kind: result.kind });
31469
+ throw new Error(`capture batch append failed: ${result.kind}`);
31470
+ }
31471
+ }
31472
+ }
31473
+ /**
31474
+ * Force-flush + close the buffer on shutdown (PRD-062c AC-5 / AC-62c.1.2). Drains the
31475
+ * remaining window so nothing buffered is lost on a clean stop. A no-op when batching is
31476
+ * off (no buffer). Never throws — a flush failure on shutdown is logged, not surfaced.
31477
+ */
31478
+ async flush() {
31479
+ if (this.buffer === null)
31480
+ return;
31481
+ try {
31482
+ await this.buffer.close();
31483
+ } catch (err) {
31484
+ this.deps.logger?.event("capture.flush.failed", {
31485
+ reason: err instanceof Error ? err.message : String(err)
31486
+ });
31487
+ }
31488
+ }
31192
31489
  /**
31193
31490
  * Build the single `sessions` row's ordered column values (FR-4 / FR-5).
31194
31491
  *
@@ -31205,7 +31502,7 @@ var CaptureRouteHandler = class {
31205
31502
  * org/workspace scope the partition.
31206
31503
  */
31207
31504
  buildRow(id, event, meta3, nowIso10, projectId) {
31208
- const message = JSON.stringify({ event, metadata: meta3 });
31505
+ const message = this.config.envelopeBudgetBytes > 0 ? budgetedStringify(event, meta3, this.config.envelopeBudgetBytes) : JSON.stringify({ event, metadata: meta3 });
31209
31506
  return [
31210
31507
  ["id", val.str(id)],
31211
31508
  ["path", val.str(meta3.path)],
@@ -31365,6 +31662,21 @@ function embedTextFor(event) {
31365
31662
  return [event.tool, serialize(event.input), serialize(event.response)].filter((s) => s.length > 0).join("\n");
31366
31663
  }
31367
31664
  }
31665
+ function groupRowsByScope(batch) {
31666
+ const byKey = /* @__PURE__ */ new Map();
31667
+ for (const item of batch) {
31668
+ const key = JSON.stringify([item.scope.org, item.scope.workspace ?? ""]);
31669
+ const bucket = byKey.get(key);
31670
+ if (bucket === void 0)
31671
+ byKey.set(key, { scope: item.scope, rows: [item.row] });
31672
+ else
31673
+ bucket.rows.push(item.row);
31674
+ }
31675
+ const out = /* @__PURE__ */ new Map();
31676
+ for (const { scope, rows } of byKey.values())
31677
+ out.set(scope, rows);
31678
+ return out;
31679
+ }
31368
31680
  function serialize(value) {
31369
31681
  if (value === void 0 || value === null)
31370
31682
  return "";
@@ -31389,7 +31701,9 @@ function attachHooksHandlers(daemon, options) {
31389
31701
  ...options.enqueuePipelineEntry !== void 0 ? { enqueuePipelineEntry: options.enqueuePipelineEntry } : {},
31390
31702
  ...options.firstRunGate !== void 0 ? { firstRunGate: options.firstRunGate } : {},
31391
31703
  ...options.projectsDir !== void 0 ? { projectsDir: options.projectsDir } : {},
31392
- ...options.logger !== void 0 ? { logger: options.logger } : {}
31704
+ ...options.logger !== void 0 ? { logger: options.logger } : {},
31705
+ ...options.captureConfig !== void 0 ? { captureConfig: options.captureConfig } : {},
31706
+ ...options.bufferClock !== void 0 ? { bufferClock: options.bufferClock } : {}
31393
31707
  });
31394
31708
  handler.register(daemon);
31395
31709
  const group = daemon.group(HOOKS_GROUP);
@@ -32426,9 +32740,9 @@ async function loadGrammar(language, tsx) {
32426
32740
  const base = GRAMMAR_WASM[language];
32427
32741
  const wasm = language === "typescript" && tsx ? "tree-sitter-tsx" : base;
32428
32742
  const key = wasm;
32429
- const cached2 = grammarCache.get(key);
32430
- if (cached2)
32431
- return cached2;
32743
+ const cached3 = grammarCache.get(key);
32744
+ if (cached3)
32745
+ return cached3;
32432
32746
  const promise2 = (async () => {
32433
32747
  const Parser = await parserModule();
32434
32748
  return Parser.Language.load(`${grammarDir()}${wasm}.wasm`);
@@ -35401,13 +35715,13 @@ function mountDashboardApi(daemon, options) {
35401
35715
  }
35402
35716
  var INSTALLED_ASSETS_TTL_MS = 5e3;
35403
35717
  function createInventoryCache() {
35404
- let cached2;
35718
+ let cached3;
35405
35719
  return async () => {
35406
35720
  const now = Date.now();
35407
- if (cached2 !== void 0 && now - cached2.at < INSTALLED_ASSETS_TTL_MS)
35408
- return cached2.value;
35721
+ if (cached3 !== void 0 && now - cached3.at < INSTALLED_ASSETS_TTL_MS)
35722
+ return cached3.value;
35409
35723
  const value = await scanInstalledAssets();
35410
- cached2 = { value, at: now };
35724
+ cached3 = { value, at: now };
35411
35725
  return value;
35412
35726
  };
35413
35727
  }
@@ -36162,7 +36476,17 @@ var StorageConfigSchema = external_exports.object({
36162
36476
  /** Per-statement timeout, clamped non-negative. */
36163
36477
  queryTimeoutMs: QueryTimeoutMs.default(DEFAULT_QUERY_TIMEOUT_MS),
36164
36478
  /** SQL tracing gate (FR-6). Evaluated at call time, see client.ts. */
36165
- traceSql: external_exports.boolean().default(false)
36479
+ traceSql: external_exports.boolean().default(false),
36480
+ /**
36481
+ * Query-meter persistence gate (PRD-062a). RESERVED, NOT YET IMPLEMENTED. The
36482
+ * query meter's default posture is in-memory + structured-log only and adds
36483
+ * ZERO DeepLake queries; persisting per-source counts to the existing
36484
+ * `telemetry_counters` tenant group is a later, separate concern and would add
36485
+ * write cost, so it is gated behind this flag. Today the flag is parsed and
36486
+ * carried but nothing reads it for behavior — wiring persistence is out of
36487
+ * scope for this sub-PRD (it must not make the meter itself a write-cost driver).
36488
+ */
36489
+ queryMeterPersist: external_exports.boolean().default(false)
36166
36490
  });
36167
36491
  var StorageConfigError = class extends Error {
36168
36492
  issues;
@@ -36181,7 +36505,8 @@ function envCredentialProvider(env = process.env) {
36181
36505
  org: env.HONEYCOMB_DEEPLAKE_ORG,
36182
36506
  workspace: env.HONEYCOMB_DEEPLAKE_WORKSPACE,
36183
36507
  queryTimeoutMs: env.HONEYCOMB_QUERY_TIMEOUT_MS,
36184
- traceSql: env.HONEYCOMB_TRACE_SQL === "1" || env.HONEYCOMB_TRACE_SQL === "true"
36508
+ traceSql: env.HONEYCOMB_TRACE_SQL === "1" || env.HONEYCOMB_TRACE_SQL === "true",
36509
+ queryMeterPersist: env.HONEYCOMB_QUERY_METER_PERSIST === "1" || env.HONEYCOMB_QUERY_METER_PERSIST === "true"
36185
36510
  };
36186
36511
  }
36187
36512
  };
@@ -36233,7 +36558,8 @@ function defaultCredentialProvider(options = {}) {
36233
36558
  orgName: fromFile.orgName,
36234
36559
  // Tuning knobs are env-only (the file carries none).
36235
36560
  queryTimeoutMs: fromEnv.queryTimeoutMs,
36236
- traceSql: fromEnv.traceSql
36561
+ traceSql: fromEnv.traceSql,
36562
+ queryMeterPersist: fromEnv.queryMeterPersist
36237
36563
  };
36238
36564
  }
36239
36565
  };
@@ -37583,12 +37909,12 @@ function mountSetupMigrate(daemon, options = {}) {
37583
37909
  // dist/src/daemon/runtime/pollinating/config.js
37584
37910
  var DEFAULT_TOKEN_THRESHOLD = 1e5;
37585
37911
  var DEFAULT_MAX_INPUT_TOKENS = 128e3;
37586
- var BoolFlag = external_exports.preprocess((raw2) => {
37912
+ var BoolFlag2 = external_exports.preprocess((raw2) => {
37587
37913
  if (typeof raw2 === "boolean")
37588
37914
  return raw2;
37589
37915
  return raw2 === "true" || raw2 === "1";
37590
37916
  }, external_exports.boolean());
37591
- function ClampedInt(def, min = 1) {
37917
+ function ClampedInt2(def, min = 1) {
37592
37918
  return external_exports.preprocess((raw2) => {
37593
37919
  const n = typeof raw2 === "number" ? raw2 : Number(raw2);
37594
37920
  if (!Number.isFinite(n))
@@ -37598,13 +37924,13 @@ function ClampedInt(def, min = 1) {
37598
37924
  }
37599
37925
  var PollinatingConfigSchema = external_exports.object({
37600
37926
  /** Master switch; off → counter still grows but no job is queued (FR-7 / a-AC-4). */
37601
- enabled: BoolFlag.default(false),
37927
+ enabled: BoolFlag2.default(false),
37602
37928
  /** Tokens-since-last-pass that queues a pass; reset SUBTRACTS this (FR-3 / FR-5). */
37603
- tokenThreshold: ClampedInt(DEFAULT_TOKEN_THRESHOLD).default(DEFAULT_TOKEN_THRESHOLD),
37929
+ tokenThreshold: ClampedInt2(DEFAULT_TOKEN_THRESHOLD).default(DEFAULT_TOKEN_THRESHOLD),
37604
37930
  /** Input-token budget a pass's payload must fit under (D-2 / 009c). */
37605
- maxInputTokens: ClampedInt(DEFAULT_MAX_INPUT_TOKENS).default(DEFAULT_MAX_INPUT_TOKENS),
37931
+ maxInputTokens: ClampedInt2(DEFAULT_MAX_INPUT_TOKENS).default(DEFAULT_MAX_INPUT_TOKENS),
37606
37932
  /** First run with no prior pass enters compaction, not incremental (D-4 / c-AC-1). */
37607
- backfillOnFirstRun: BoolFlag.default(true)
37933
+ backfillOnFirstRun: BoolFlag2.default(true)
37608
37934
  });
37609
37935
  var PollinatingConfigError = class extends Error {
37610
37936
  issues;
@@ -38632,7 +38958,7 @@ var DEFAULT_KEEP_LATEST_N = 5;
38632
38958
  var DEFAULT_WINDOW_DAYS = 30;
38633
38959
  var DEFAULT_TIMESTAMP_COLUMN = "updated_at";
38634
38960
  var DEFAULT_VERSION_COLUMN = "version";
38635
- function ClampedInt2(def, min) {
38961
+ function ClampedInt3(def, min) {
38636
38962
  return external_exports.preprocess((raw2) => {
38637
38963
  const n = typeof raw2 === "number" ? raw2 : Number(raw2);
38638
38964
  if (!Number.isFinite(n))
@@ -38649,9 +38975,9 @@ function IdentColumn(def) {
38649
38975
  }
38650
38976
  var CompactionRetentionSchema = external_exports.object({
38651
38977
  /** Keep the most-recent N versions below the highest (D-1). Clamp `>= 1`. */
38652
- keepLatestN: ClampedInt2(DEFAULT_KEEP_LATEST_N, 1).default(DEFAULT_KEEP_LATEST_N),
38978
+ keepLatestN: ClampedInt3(DEFAULT_KEEP_LATEST_N, 1).default(DEFAULT_KEEP_LATEST_N),
38653
38979
  /** Keep any version newer than now − windowDays (D-1). Clamp `>= 0` (0 = off). */
38654
- windowDays: ClampedInt2(DEFAULT_WINDOW_DAYS, 0).default(DEFAULT_WINDOW_DAYS),
38980
+ windowDays: ClampedInt3(DEFAULT_WINDOW_DAYS, 0).default(DEFAULT_WINDOW_DAYS),
38655
38981
  /** The timestamp column the window is measured on. Default `updated_at`. */
38656
38982
  timestampColumn: IdentColumn(DEFAULT_TIMESTAMP_COLUMN).default(DEFAULT_TIMESTAMP_COLUMN),
38657
38983
  /** The version column. Default `version` (mirrors `appendVersionBumped`). */
@@ -40382,12 +40708,12 @@ var DEFAULT_REHEARSAL_BOOST = 1.1;
40382
40708
  var DEFAULT_REHEARSAL_WINDOW_MS = 7 * 24 * 60 * 60 * 1e3;
40383
40709
  var DEFAULT_MIN_INJECTION_SCORE = 0.6;
40384
40710
  var RERANKER_STRATEGIES = Object.freeze(["embedding-cosine", "llm", "none"]);
40385
- var BoolFlag2 = external_exports.preprocess((raw2) => {
40711
+ var BoolFlag3 = external_exports.preprocess((raw2) => {
40386
40712
  if (typeof raw2 === "boolean")
40387
40713
  return raw2;
40388
40714
  return raw2 === "true" || raw2 === "1";
40389
40715
  }, external_exports.boolean());
40390
- function ClampedInt3(def, min = 0) {
40716
+ function ClampedInt4(def, min = 0) {
40391
40717
  return external_exports.preprocess((raw2) => {
40392
40718
  const n = typeof raw2 === "number" ? raw2 : Number(raw2);
40393
40719
  if (!Number.isFinite(n))
@@ -40423,29 +40749,29 @@ function OptionalClampedHalfLifeDays(min) {
40423
40749
  }
40424
40750
  var TraversalConfigSchema = external_exports.object({
40425
40751
  /** Max aspects per focal entity. */
40426
- aspectsPerEntity: ClampedInt3(DEFAULT_TRAVERSAL_ASPECTS_PER_ENTITY, 1).default(DEFAULT_TRAVERSAL_ASPECTS_PER_ENTITY),
40752
+ aspectsPerEntity: ClampedInt4(DEFAULT_TRAVERSAL_ASPECTS_PER_ENTITY, 1).default(DEFAULT_TRAVERSAL_ASPECTS_PER_ENTITY),
40427
40753
  /** Max attributes per aspect. */
40428
- attrsPerAspect: ClampedInt3(DEFAULT_TRAVERSAL_ATTRS_PER_ASPECT, 1).default(DEFAULT_TRAVERSAL_ATTRS_PER_ASPECT),
40754
+ attrsPerAspect: ClampedInt4(DEFAULT_TRAVERSAL_ATTRS_PER_ASPECT, 1).default(DEFAULT_TRAVERSAL_ATTRS_PER_ASPECT),
40429
40755
  /** Max branching factor per node. */
40430
- branching: ClampedInt3(DEFAULT_TRAVERSAL_BRANCHING, 1).default(DEFAULT_TRAVERSAL_BRANCHING),
40756
+ branching: ClampedInt4(DEFAULT_TRAVERSAL_BRANCHING, 1).default(DEFAULT_TRAVERSAL_BRANCHING),
40431
40757
  /** Hard cap on total IDs the walk may collect. */
40432
- totalIds: ClampedInt3(DEFAULT_TRAVERSAL_TOTAL_IDS, 1).default(DEFAULT_TRAVERSAL_TOTAL_IDS),
40758
+ totalIds: ClampedInt4(DEFAULT_TRAVERSAL_TOTAL_IDS, 1).default(DEFAULT_TRAVERSAL_TOTAL_IDS),
40433
40759
  /** Minimum edge strength×confidence to follow an edge. */
40434
40760
  minEdgeWeight: ClampedFloat(DEFAULT_TRAVERSAL_MIN_EDGE_WEIGHT).default(DEFAULT_TRAVERSAL_MIN_EDGE_WEIGHT),
40435
40761
  /** Hard traversal timeout in ms. */
40436
- timeoutMs: ClampedInt3(DEFAULT_TRAVERSAL_TIMEOUT_MS, 1).default(DEFAULT_TRAVERSAL_TIMEOUT_MS)
40762
+ timeoutMs: ClampedInt4(DEFAULT_TRAVERSAL_TIMEOUT_MS, 1).default(DEFAULT_TRAVERSAL_TIMEOUT_MS)
40437
40763
  });
40438
40764
  var RerankerConfigSchema = external_exports.object({
40439
40765
  /** The reranker strategy (D-4). */
40440
40766
  strategy: external_exports.enum(RERANKER_STRATEGIES).default(DEFAULT_RERANKER),
40441
40767
  /** Reranker timeout in ms; on timeout keep the original order (d-AC-2 / b-AC-2). */
40442
- timeoutMs: ClampedInt3(DEFAULT_RERANKER_TIMEOUT_MS, 1).default(DEFAULT_RERANKER_TIMEOUT_MS),
40768
+ timeoutMs: ClampedInt4(DEFAULT_RERANKER_TIMEOUT_MS, 1).default(DEFAULT_RERANKER_TIMEOUT_MS),
40443
40769
  /** Rerank window N: how many fused top-N candidates to re-score (PRD-047b). */
40444
- window: ClampedInt3(DEFAULT_RERANKER_WINDOW, 1).default(DEFAULT_RERANKER_WINDOW)
40770
+ window: ClampedInt4(DEFAULT_RERANKER_WINDOW, 1).default(DEFAULT_RERANKER_WINDOW)
40445
40771
  });
40446
40772
  var DedupConfigSchema = external_exports.object({
40447
40773
  /** Whether semantic near-duplicate dedup runs; ON by default (PRD-047c / c-AC-3). */
40448
- enabled: BoolFlag2.default(DEFAULT_DEDUP_ENABLED),
40774
+ enabled: BoolFlag3.default(DEFAULT_DEDUP_ENABLED),
40449
40775
  /** The cosine-similarity collapse threshold in `[0,1]` (PRD-047c / c-AC-1). */
40450
40776
  similarityThreshold: ClampedFloat(DEFAULT_DEDUP_SIMILARITY_THRESHOLD).default(DEFAULT_DEDUP_SIMILARITY_THRESHOLD)
40451
40777
  });
@@ -40484,21 +40810,21 @@ var DampeningConfigSchema = external_exports.object({
40484
40810
  /** Bounded rehearsal boost for a recently-accessed memory. Ceiling 4. */
40485
40811
  rehearsalBoost: ClampedFloat(DEFAULT_REHEARSAL_BOOST, 4).default(DEFAULT_REHEARSAL_BOOST),
40486
40812
  /** "Recent" window for the rehearsal boost in ms (7d). */
40487
- rehearsalWindowMs: ClampedInt3(DEFAULT_REHEARSAL_WINDOW_MS, 1).default(DEFAULT_REHEARSAL_WINDOW_MS)
40813
+ rehearsalWindowMs: ClampedInt4(DEFAULT_REHEARSAL_WINDOW_MS, 1).default(DEFAULT_REHEARSAL_WINDOW_MS)
40488
40814
  });
40489
40815
  var RecallConfigSchema = external_exports.object({
40490
40816
  /** Over-fetch multiplier for scoped vector recalls (D-1 / a-AC-2 / FR-5). */
40491
- overFetchMultiplier: ClampedInt3(DEFAULT_OVER_FETCH_MULTIPLIER, 1).default(DEFAULT_OVER_FETCH_MULTIPLIER),
40817
+ overFetchMultiplier: ClampedInt4(DEFAULT_OVER_FETCH_MULTIPLIER, 1).default(DEFAULT_OVER_FETCH_MULTIPLIER),
40492
40818
  /** Base per-channel candidate limit (FTS/vector base, pre over-fetch). */
40493
- channelLimit: ClampedInt3(DEFAULT_CHANNEL_LIMIT, 1).default(DEFAULT_CHANNEL_LIMIT),
40819
+ channelLimit: ClampedInt4(DEFAULT_CHANNEL_LIMIT, 1).default(DEFAULT_CHANNEL_LIMIT),
40494
40820
  /** Hint cap so a memory can't ride in on hints alone (D-2 / a-AC-4 / FR-7). */
40495
- hintCap: ClampedInt3(DEFAULT_HINT_CAP, 0).default(DEFAULT_HINT_CAP),
40821
+ hintCap: ClampedInt4(DEFAULT_HINT_CAP, 0).default(DEFAULT_HINT_CAP),
40496
40822
  /** Keyword expansion for the LEXICAL path only; OFF by default (D-2 / FR-2). */
40497
- keywordExpansion: BoolFlag2.default(false),
40823
+ keywordExpansion: BoolFlag3.default(false),
40498
40824
  /** Minimum calibrated injection score (D-6 / e-AC-1); per-agent tunable. */
40499
40825
  minInjectionScore: ClampedFloat(DEFAULT_MIN_INJECTION_SCORE).default(DEFAULT_MIN_INJECTION_SCORE),
40500
40826
  /** Master graph switch for the traversal channel/phase (007b). */
40501
- graphEnabled: BoolFlag2.default(false),
40827
+ graphEnabled: BoolFlag3.default(false),
40502
40828
  /** D-3 traversal budgets (007b). */
40503
40829
  traversal: TraversalConfigSchema.default(() => TraversalConfigSchema.parse({})),
40504
40830
  /** D-4 reranker config (007d). */
@@ -40581,6 +40907,129 @@ function resolveRecallConfig(provider = envRecallConfigProvider()) {
40581
40907
  return parsed.data;
40582
40908
  }
40583
40909
 
40910
+ // dist/src/daemon/runtime/memories/bounded-pool.js
40911
+ var Semaphore = class {
40912
+ /** The maximum permits (in-flight tasks) allowed at once. Always `>= 1`. */
40913
+ max;
40914
+ /** Permits currently held (tasks running). Never exceeds {@link max}. */
40915
+ held = 0;
40916
+ /** FIFO queue of waiters parked because all permits were held at acquire time. */
40917
+ waiters = [];
40918
+ constructor(max) {
40919
+ this.max = Number.isFinite(max) && max >= 1 ? Math.trunc(max) : 1;
40920
+ }
40921
+ /** Permits currently held (the live in-flight count). Test-observable for the cap assertion. */
40922
+ get inFlight() {
40923
+ return this.held;
40924
+ }
40925
+ /** Number of tasks parked waiting for a permit (test-observable). */
40926
+ get waiting() {
40927
+ return this.waiters.length;
40928
+ }
40929
+ /**
40930
+ * Acquire one permit. Resolves immediately when a permit is free; otherwise parks
40931
+ * FIFO and resolves when {@link release} hands a permit forward. Each acquire MUST
40932
+ * be paired with exactly one {@link release} (use {@link run} to guarantee it).
40933
+ */
40934
+ acquire() {
40935
+ if (this.held < this.max) {
40936
+ this.held += 1;
40937
+ return Promise.resolve();
40938
+ }
40939
+ return new Promise((resolve6) => {
40940
+ this.waiters.push(() => {
40941
+ this.held += 1;
40942
+ resolve6();
40943
+ });
40944
+ });
40945
+ }
40946
+ /**
40947
+ * Release one permit. If a waiter is parked, hand the permit STRAIGHT to it (the
40948
+ * held count stays balanced — the waiter's resolver re-increments), otherwise drop
40949
+ * the held count. Releasing with no permit held is a no-op (defensive — a double
40950
+ * release never drives the count negative).
40951
+ */
40952
+ release() {
40953
+ const next = this.waiters.shift();
40954
+ if (next !== void 0) {
40955
+ this.held -= 1;
40956
+ next();
40957
+ return;
40958
+ }
40959
+ if (this.held > 0)
40960
+ this.held -= 1;
40961
+ }
40962
+ /**
40963
+ * Run `fn` under one permit: acquire, run, and ALWAYS release (even when `fn`
40964
+ * throws/rejects), then re-throw the original error. The safe wrapper — a task
40965
+ * that throws never leaks a permit and wedges the pool.
40966
+ */
40967
+ async run(fn) {
40968
+ await this.acquire();
40969
+ try {
40970
+ return await fn();
40971
+ } finally {
40972
+ this.release();
40973
+ }
40974
+ }
40975
+ };
40976
+
40977
+ // dist/src/daemon/runtime/memories/amplification-config.js
40978
+ var DEFAULT_FANOUT_BATCH = true;
40979
+ var DEFAULT_RECALL_MAX_CONCURRENCY = 6;
40980
+ var MIN_RECALL_MAX_CONCURRENCY = 1;
40981
+ var OnByDefaultFlag = external_exports.preprocess((raw2) => {
40982
+ if (typeof raw2 === "boolean")
40983
+ return raw2;
40984
+ if (raw2 === void 0 || raw2 === null || raw2 === "")
40985
+ return true;
40986
+ return !(raw2 === "false" || raw2 === "0");
40987
+ }, external_exports.boolean());
40988
+ var ConcurrencyKnob = external_exports.preprocess((raw2) => {
40989
+ const n = typeof raw2 === "number" ? raw2 : Number(raw2);
40990
+ if (!Number.isFinite(n))
40991
+ return DEFAULT_RECALL_MAX_CONCURRENCY;
40992
+ return Math.max(MIN_RECALL_MAX_CONCURRENCY, Math.trunc(n));
40993
+ }, external_exports.number().int());
40994
+ var AmplificationConfigSchema = external_exports.object({
40995
+ /** `HONEYCOMB_FANOUT_BATCH` — batched fan-out enqueue; ON by default (AC-62d.1.1 / AC-9). */
40996
+ fanoutBatch: OnByDefaultFlag.default(DEFAULT_FANOUT_BATCH),
40997
+ /** `HONEYCOMB_RECALL_MAX_CONCURRENCY` — in-flight DeepLake-query ceiling; 6 by default (AC-62d.2.1). */
40998
+ recallMaxConcurrency: ConcurrencyKnob.default(DEFAULT_RECALL_MAX_CONCURRENCY)
40999
+ });
41000
+ var AmplificationConfigError = class extends Error {
41001
+ issues;
41002
+ constructor(issues) {
41003
+ super(`Invalid amplification config: ${issues.join("; ")}`);
41004
+ this.name = "AmplificationConfigError";
41005
+ this.issues = issues;
41006
+ }
41007
+ };
41008
+ function envAmplificationConfigProvider(env = process.env) {
41009
+ return {
41010
+ read() {
41011
+ return {
41012
+ fanoutBatch: env.HONEYCOMB_FANOUT_BATCH,
41013
+ recallMaxConcurrency: env.HONEYCOMB_RECALL_MAX_CONCURRENCY
41014
+ };
41015
+ }
41016
+ };
41017
+ }
41018
+ function resolveAmplificationConfig(provider = envAmplificationConfigProvider()) {
41019
+ const parsed = AmplificationConfigSchema.safeParse(provider.read());
41020
+ if (!parsed.success) {
41021
+ const issues = parsed.error.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`);
41022
+ throw new AmplificationConfigError(issues);
41023
+ }
41024
+ return parsed.data;
41025
+ }
41026
+ var cached2;
41027
+ function amplificationConfig() {
41028
+ if (cached2 === void 0)
41029
+ cached2 = resolveAmplificationConfig();
41030
+ return cached2;
41031
+ }
41032
+
40584
41033
  // dist/src/daemon/runtime/memories/activation.js
40585
41034
  var DEFAULT_ACTR_DECAY = 0.5;
40586
41035
  var DEFAULT_ACTR_A_MIN = 0.05;
@@ -40695,6 +41144,15 @@ function deserializeModel(blob) {
40695
41144
  }
40696
41145
 
40697
41146
  // dist/src/daemon/runtime/memories/recall.js
41147
+ var SOURCE_RECALL_ARM = "recall-arm";
41148
+ var sharedRecallPool;
41149
+ function resolveRecallPool(deps) {
41150
+ if (deps.recallPool !== void 0)
41151
+ return deps.recallPool;
41152
+ if (sharedRecallPool === void 0)
41153
+ sharedRecallPool = new Semaphore(amplificationConfig().recallMaxConcurrency);
41154
+ return sharedRecallPool;
41155
+ }
40698
41156
  var DEFAULT_RECALL_LIMIT = 20;
40699
41157
  var MAX_RECALL_LIMIT = 200;
40700
41158
  var RRF_K = 60;
@@ -40826,7 +41284,8 @@ function projectConjunctFor(request) {
40826
41284
  });
40827
41285
  }
40828
41286
  async function runArm(sql, request, deps) {
40829
- const result = await deps.storage.query(sql, request.scope);
41287
+ const pool = resolveRecallPool(deps);
41288
+ const result = await pool.run(() => deps.storage.query(sql, request.scope, { source: SOURCE_RECALL_ARM }));
40830
41289
  return isOk(result) ? result.rows : [];
40831
41290
  }
40832
41291
  var SEMANTIC_ARMS = [
@@ -40866,7 +41325,8 @@ async function runSemanticArm(spec, queryVector, request, deps, limit) {
40866
41325
  const projectClause = projectConjunctFor(request);
40867
41326
  let scored;
40868
41327
  try {
40869
- const recall = await vectorSearch(deps.storage, request.scope, {
41328
+ const pool = resolveRecallPool(deps);
41329
+ const recall = await pool.run(() => vectorSearch(deps.storage, request.scope, {
40870
41330
  table: spec.table,
40871
41331
  idColumn: spec.idColumn,
40872
41332
  embeddingColumn: spec.embeddingColumn,
@@ -40874,7 +41334,7 @@ async function runSemanticArm(spec, queryVector, request, deps, limit) {
40874
41334
  scope: {},
40875
41335
  limit,
40876
41336
  ...projectClause !== "" ? { extraClause: projectClause } : {}
40877
- });
41337
+ }));
40878
41338
  scored = recall.ids;
40879
41339
  } catch {
40880
41340
  return [];
@@ -41911,12 +42371,12 @@ var DEFAULT_DEAD_JOB_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
41911
42371
  var DEFAULT_HISTORY_RETENTION_MS = 90 * 24 * 60 * 60 * 1e3;
41912
42372
  var DEFAULT_TOMBSTONE_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
41913
42373
  var EXTRACTION_PROVIDER_NONE = "none";
41914
- var BoolFlag3 = external_exports.preprocess((raw2) => {
42374
+ var BoolFlag4 = external_exports.preprocess((raw2) => {
41915
42375
  if (typeof raw2 === "boolean")
41916
42376
  return raw2;
41917
42377
  return raw2 === "true" || raw2 === "1";
41918
42378
  }, external_exports.boolean());
41919
- function ClampedInt4(def, min = 1) {
42379
+ function ClampedInt5(def, min = 1) {
41920
42380
  return external_exports.preprocess((raw2) => {
41921
42381
  const n = typeof raw2 === "number" ? raw2 : Number(raw2);
41922
42382
  if (!Number.isFinite(n))
@@ -41932,49 +42392,49 @@ var Confidence = external_exports.preprocess((raw2) => {
41932
42392
  }, external_exports.number());
41933
42393
  var AutonomousConfigSchema = external_exports.object({
41934
42394
  /** Master switch for retention/autonomous mutation; off → retention does not run (006e e-AC-4). */
41935
- enabled: BoolFlag3.default(false),
42395
+ enabled: BoolFlag4.default(false),
41936
42396
  /** Halt switch: set → no further purges even when enabled (006e e-AC-5). */
41937
- frozen: BoolFlag3.default(false),
42397
+ frozen: BoolFlag4.default(false),
41938
42398
  /** Gate for UPDATE/DELETE proposals being applied (006c c-AC-3 / D-7). */
41939
- allowUpdateDelete: BoolFlag3.default(false)
42399
+ allowUpdateDelete: BoolFlag4.default(false)
41940
42400
  });
41941
42401
  var GraphConfigSchema = external_exports.object({
41942
42402
  /** Master graph switch; off → no graph rows written (006d d-AC-4). */
41943
- enabled: BoolFlag3.default(false),
42403
+ enabled: BoolFlag4.default(false),
41944
42404
  /** Whether extraction-derived triples are persisted to the graph (006d d-AC-4). */
41945
- extractionWritesEnabled: BoolFlag3.default(false)
42405
+ extractionWritesEnabled: BoolFlag4.default(false)
41946
42406
  });
41947
42407
  var ExtractionConfigSchema = external_exports.object({
41948
42408
  /** Input char cap before the model call (a-AC-2 / FR-6). */
41949
- inputCharCap: ClampedInt4(DEFAULT_INPUT_CHAR_CAP).default(DEFAULT_INPUT_CHAR_CAP),
42409
+ inputCharCap: ClampedInt5(DEFAULT_INPUT_CHAR_CAP).default(DEFAULT_INPUT_CHAR_CAP),
41950
42410
  /** Max facts kept (a-AC-3 / FR-7). */
41951
- maxFacts: ClampedInt4(DEFAULT_MAX_FACTS).default(DEFAULT_MAX_FACTS),
42411
+ maxFacts: ClampedInt5(DEFAULT_MAX_FACTS).default(DEFAULT_MAX_FACTS),
41952
42412
  /** Max entity triples kept (a-AC-3 / FR-7). */
41953
- maxEntities: ClampedInt4(DEFAULT_MAX_ENTITIES).default(DEFAULT_MAX_ENTITIES),
42413
+ maxEntities: ClampedInt5(DEFAULT_MAX_ENTITIES).default(DEFAULT_MAX_ENTITIES),
41954
42414
  /** Per-fact content length cap (a-AC-3 / FR-7). */
41955
- maxFactChars: ClampedInt4(DEFAULT_MAX_FACT_CHARS).default(DEFAULT_MAX_FACT_CHARS)
42415
+ maxFactChars: ClampedInt5(DEFAULT_MAX_FACT_CHARS).default(DEFAULT_MAX_FACT_CHARS)
41956
42416
  });
41957
42417
  var RetentionConfigSchema = external_exports.object({
41958
42418
  /** Per-run row batch cap (e-AC-1 / e-AC-6). */
41959
- batchLimit: ClampedInt4(DEFAULT_RETENTION_BATCH_LIMIT).default(DEFAULT_RETENTION_BATCH_LIMIT),
42419
+ batchLimit: ClampedInt5(DEFAULT_RETENTION_BATCH_LIMIT).default(DEFAULT_RETENTION_BATCH_LIMIT),
41960
42420
  /** Completed-jobs window in ms. */
41961
- completedJobMs: ClampedInt4(DEFAULT_COMPLETED_JOB_RETENTION_MS).default(DEFAULT_COMPLETED_JOB_RETENTION_MS),
42421
+ completedJobMs: ClampedInt5(DEFAULT_COMPLETED_JOB_RETENTION_MS).default(DEFAULT_COMPLETED_JOB_RETENTION_MS),
41962
42422
  /** Dead-jobs window in ms. */
41963
- deadJobMs: ClampedInt4(DEFAULT_DEAD_JOB_RETENTION_MS).default(DEFAULT_DEAD_JOB_RETENTION_MS),
42423
+ deadJobMs: ClampedInt5(DEFAULT_DEAD_JOB_RETENTION_MS).default(DEFAULT_DEAD_JOB_RETENTION_MS),
41964
42424
  /** History window in ms. */
41965
- historyMs: ClampedInt4(DEFAULT_HISTORY_RETENTION_MS).default(DEFAULT_HISTORY_RETENTION_MS),
42425
+ historyMs: ClampedInt5(DEFAULT_HISTORY_RETENTION_MS).default(DEFAULT_HISTORY_RETENTION_MS),
41966
42426
  /** Tombstone window in ms. */
41967
- tombstoneMs: ClampedInt4(DEFAULT_TOMBSTONE_RETENTION_MS).default(DEFAULT_TOMBSTONE_RETENTION_MS)
42427
+ tombstoneMs: ClampedInt5(DEFAULT_TOMBSTONE_RETENTION_MS).default(DEFAULT_TOMBSTONE_RETENTION_MS)
41968
42428
  });
41969
42429
  var PipelineConfigSchema = external_exports.object({
41970
42430
  /** Master switch; off → no stage runs (a-AC-5 / FR-9). */
41971
- enabled: BoolFlag3.default(false),
42431
+ enabled: BoolFlag4.default(false),
41972
42432
  /** Router-selection token; `'none'` disables extraction (a-AC-5 / FR-9). */
41973
42433
  extractionProvider: external_exports.string().trim().min(1).default(EXTRACTION_PROVIDER_NONE),
41974
42434
  /** Shadow mode: proposals logged, no memory written (006c c-AC-4). */
41975
- shadowMode: BoolFlag3.default(false),
42435
+ shadowMode: BoolFlag4.default(false),
41976
42436
  /** Frozen: nothing written even if shadow off; supersedes shadow (006c c-AC-5). */
41977
- mutationsFrozen: BoolFlag3.default(false),
42437
+ mutationsFrozen: BoolFlag4.default(false),
41978
42438
  /** ADD confidence gate (D-1 / 006c c-AC-1). */
41979
42439
  minFactConfidenceForWrite: Confidence.default(DEFAULT_MIN_FACT_CONFIDENCE),
41980
42440
  /** Autonomous brakes (retention + UPDATE/DELETE). */
@@ -42125,6 +42585,7 @@ function normalizeProposalKeys(candidate) {
42125
42585
  // dist/src/daemon/runtime/pipeline/controlled-writes.js
42126
42586
  var silentLogger4 = { event() {
42127
42587
  } };
42588
+ var CONTROLLED_WRITE_BATCH_KEY = "proposals";
42128
42589
  var MEMORIES_VERSION_COLUMN = Object.freeze({
42129
42590
  name: "version",
42130
42591
  sql: "BIGINT NOT NULL DEFAULT 1"
@@ -42474,33 +42935,66 @@ var noopControlledWriteHandler = async (_job) => {
42474
42935
  function createControlledWriteHandler(deps) {
42475
42936
  if (deps === void 0)
42476
42937
  return noopControlledWriteHandler;
42938
+ const handlerDeps = deps;
42477
42939
  const logger = deps.logger ?? silentLogger4;
42478
42940
  return async (job) => {
42479
- const parsed = readControlledWriteInput(job.payload);
42480
- if (parsed === null) {
42481
- logger.event("controlled_write.unparseable_payload", { id: job.id });
42941
+ const batch = readBatchPayloads(job.payload);
42942
+ if (batch !== null) {
42943
+ for (const factPayload of batch) {
42944
+ const merged = { ...envelopeOf(job.payload), ...factPayload };
42945
+ const factJob = { ...job, payload: merged };
42946
+ await applyOneControlledWrite(factJob, handlerDeps, logger);
42947
+ }
42482
42948
  return;
42483
42949
  }
42484
- const input = {
42485
- ...parsed,
42486
- agentId: parsed.agentId ?? job.scope.agentId
42487
- };
42488
- const scope = { org: job.scope.org, workspace: job.scope.workspace };
42489
- const outcome = await applyControlledWrite(input, scope, deps);
42490
- if (deps.onOutcome) {
42491
- try {
42492
- await deps.onOutcome(job, outcome);
42493
- } catch (err) {
42494
- const reason = err instanceof Error ? err.message : String(err);
42495
- logger.event("controlled_write.fan_out_failed", {
42496
- id: job.id,
42497
- action: outcome.action,
42498
- memoryId: outcome.memoryId,
42499
- reason
42500
- });
42501
- }
42950
+ await applyOneControlledWrite(job, handlerDeps, logger);
42951
+ };
42952
+ }
42953
+ function envelopeOf(payload) {
42954
+ const out = {};
42955
+ for (const key of ["org", "workspace", "agent_id", "project_id"]) {
42956
+ if (typeof payload[key] === "string")
42957
+ out[key] = payload[key];
42958
+ }
42959
+ return out;
42960
+ }
42961
+ function readBatchPayloads(payload) {
42962
+ const raw2 = payload[CONTROLLED_WRITE_BATCH_KEY];
42963
+ if (!Array.isArray(raw2) || raw2.length === 0)
42964
+ return null;
42965
+ const out = [];
42966
+ for (const item of raw2) {
42967
+ if (item !== null && typeof item === "object" && !Array.isArray(item)) {
42968
+ out.push(item);
42502
42969
  }
42970
+ }
42971
+ return out.length > 0 ? out : null;
42972
+ }
42973
+ async function applyOneControlledWrite(job, deps, logger) {
42974
+ const parsed = readControlledWriteInput(job.payload);
42975
+ if (parsed === null) {
42976
+ logger.event("controlled_write.unparseable_payload", { id: job.id });
42977
+ return;
42978
+ }
42979
+ const input = {
42980
+ ...parsed,
42981
+ agentId: parsed.agentId ?? job.scope.agentId
42503
42982
  };
42983
+ const scope = { org: job.scope.org, workspace: job.scope.workspace };
42984
+ const outcome = await applyControlledWrite(input, scope, deps);
42985
+ if (deps.onOutcome) {
42986
+ try {
42987
+ await deps.onOutcome(job, outcome);
42988
+ } catch (err) {
42989
+ const reason = err instanceof Error ? err.message : String(err);
42990
+ logger.event("controlled_write.fan_out_failed", {
42991
+ id: job.id,
42992
+ action: outcome.action,
42993
+ memoryId: outcome.memoryId,
42994
+ reason
42995
+ });
42996
+ }
42997
+ }
42504
42998
  }
42505
42999
 
42506
43000
  // dist/src/daemon/runtime/memories/store.js
@@ -43609,7 +44103,7 @@ var DEFAULT_OPEN_CONFLICT_SUPPRESSION = DEFAULT_RHO;
43609
44103
  var DEFAULT_CONFLICT_AUTO_RESOLVE = false;
43610
44104
  var STALE_REF_POSTURES = Object.freeze(["observe", "execute"]);
43611
44105
  var DEFAULT_STALE_REF_POSTURE = "observe";
43612
- var BoolFlag4 = external_exports.preprocess((raw2) => {
44106
+ var BoolFlag5 = external_exports.preprocess((raw2) => {
43613
44107
  if (typeof raw2 === "boolean")
43614
44108
  return raw2;
43615
44109
  return raw2 === "true" || raw2 === "1";
@@ -43664,7 +44158,7 @@ var LifecycleConfigSchema = external_exports.object({
43664
44158
  /** Open-conflict suppression `ρ` (058b); `0` default (fully suppress, reversible), clamped into `[0,1]`. */
43665
44159
  openConflictSuppression: ClampedFloat2(DEFAULT_OPEN_CONFLICT_SUPPRESSION, 1).default(DEFAULT_OPEN_CONFLICT_SUPPRESSION),
43666
44160
  /** Conflict auto-resolve (058b); OFF by default (detect + queue only, human-in-the-loop). */
43667
- conflictAutoResolve: BoolFlag4.default(DEFAULT_CONFLICT_AUTO_RESOLVE),
44161
+ conflictAutoResolve: BoolFlag5.default(DEFAULT_CONFLICT_AUTO_RESOLVE),
43668
44162
  /** Stale-ref posture (058c); `observe` by default (`s = 0`, inert). */
43669
44163
  staleRefPosture: PostureFlag.default(DEFAULT_STALE_REF_POSTURE)
43670
44164
  });
@@ -46179,8 +46673,8 @@ function realDiscordProvider(cfg, transport) {
46179
46673
  }
46180
46674
  }
46181
46675
  async function* indexDesktopCache() {
46182
- const cached2 = await transport.readDesktopCache();
46183
- for (const m of cached2) {
46676
+ const cached3 = await transport.readDesktopCache();
46677
+ for (const m of cached3) {
46184
46678
  yield messageArtifact(cfg, m);
46185
46679
  }
46186
46680
  }
@@ -48972,6 +49466,216 @@ async function buildInferenceModelClient(deps) {
48972
49466
  return new RouterModelClient(router);
48973
49467
  }
48974
49468
 
49469
+ // dist/src/daemon/runtime/services/poll-backoff.js
49470
+ var DEFAULT_POLL_BACKOFF_FLOOR_MS = 1e3;
49471
+ var DEFAULT_POLL_BACKOFF_CEILING_MS = 3e4;
49472
+ var DEFAULT_POLL_BACKOFF_JITTER = 0.1;
49473
+ var BoolFlag6 = external_exports.preprocess((raw2) => {
49474
+ if (typeof raw2 === "boolean")
49475
+ return raw2;
49476
+ return raw2 === "true" || raw2 === "1";
49477
+ }, external_exports.boolean());
49478
+ function ClampedInt6(def, min = 1) {
49479
+ return external_exports.preprocess((raw2) => {
49480
+ const n = typeof raw2 === "number" ? raw2 : Number(raw2);
49481
+ if (!Number.isFinite(n))
49482
+ return def;
49483
+ return Math.max(min, Math.trunc(n));
49484
+ }, external_exports.number().int());
49485
+ }
49486
+ function ClampedFraction(def) {
49487
+ return external_exports.preprocess((raw2) => {
49488
+ const n = typeof raw2 === "number" ? raw2 : Number(raw2);
49489
+ if (!Number.isFinite(n))
49490
+ return def;
49491
+ return Math.min(1, Math.max(0, n));
49492
+ }, external_exports.number());
49493
+ }
49494
+ var PollBackoffConfigSchema = external_exports.object({
49495
+ /** Master switch; off → flat `floorMs`, the exact pre-PRD cadence (AC-9). */
49496
+ enabled: BoolFlag6.default(false),
49497
+ /** Fast floor the backoff starts at and resets to on any lease (AC-3). */
49498
+ floorMs: ClampedInt6(DEFAULT_POLL_BACKOFF_FLOOR_MS).default(DEFAULT_POLL_BACKOFF_FLOOR_MS),
49499
+ /** Ceiling the backoff doubles toward while the queue stays empty (AC-2). */
49500
+ ceilingMs: ClampedInt6(DEFAULT_POLL_BACKOFF_CEILING_MS).default(DEFAULT_POLL_BACKOFF_CEILING_MS),
49501
+ /** +/- jitter fraction of the current step, anti-thundering-herd. */
49502
+ jitter: ClampedFraction(DEFAULT_POLL_BACKOFF_JITTER).default(DEFAULT_POLL_BACKOFF_JITTER)
49503
+ });
49504
+ var PollBackoffConfigError = class extends Error {
49505
+ issues;
49506
+ constructor(issues) {
49507
+ super(`Invalid poll-backoff config: ${issues.join("; ")}`);
49508
+ this.name = "PollBackoffConfigError";
49509
+ this.issues = issues;
49510
+ }
49511
+ };
49512
+ function envPollBackoffConfigProvider(env = process.env) {
49513
+ return {
49514
+ read() {
49515
+ const raw2 = env.HONEYCOMB_POLL_BACKOFF_ENABLED;
49516
+ const enabled = raw2 === void 0 ? true : raw2;
49517
+ return {
49518
+ enabled,
49519
+ floorMs: env.HONEYCOMB_POLL_BACKOFF_FLOOR_MS,
49520
+ ceilingMs: env.HONEYCOMB_POLL_BACKOFF_CEILING_MS,
49521
+ jitter: env.HONEYCOMB_POLL_BACKOFF_JITTER
49522
+ };
49523
+ }
49524
+ };
49525
+ }
49526
+ function resolvePollBackoffConfig(provider = envPollBackoffConfigProvider()) {
49527
+ const parsed = PollBackoffConfigSchema.safeParse(provider.read());
49528
+ if (!parsed.success) {
49529
+ const issues = parsed.error.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`);
49530
+ throw new PollBackoffConfigError(issues);
49531
+ }
49532
+ const cfg = parsed.data;
49533
+ return cfg.ceilingMs < cfg.floorMs ? { ...cfg, ceilingMs: cfg.floorMs } : cfg;
49534
+ }
49535
+ var defaultJitterSource = () => Math.random() * 2 - 1;
49536
+ var PollBackoff = class {
49537
+ floorMs;
49538
+ ceilingMs;
49539
+ jitter;
49540
+ jitterSource;
49541
+ /** The current un-jittered step. Starts at the floor; doubles toward the ceiling. */
49542
+ stepMs;
49543
+ /**
49544
+ * @param config the resolved bounds + jitter fraction. The state machine is only
49545
+ * ever CONSTRUCTED when backoff is active; a loop with `config.enabled === false`
49546
+ * does not build one (it keeps its flat legacy interval), so this class need not
49547
+ * re-check the flag.
49548
+ * @param jitterSource injectable `[-1, 1]` source — a test pins it to 0 to assert
49549
+ * the exact geometric schedule; production uses the uniform random default.
49550
+ */
49551
+ constructor(config2, jitterSource = defaultJitterSource) {
49552
+ this.floorMs = config2.floorMs;
49553
+ this.ceilingMs = Math.max(config2.floorMs, config2.ceilingMs);
49554
+ this.jitter = config2.jitter;
49555
+ this.jitterSource = jitterSource;
49556
+ this.stepMs = this.floorMs;
49557
+ }
49558
+ /**
49559
+ * Step the delay toward the ceiling after an EMPTY lease (no job this tick):
49560
+ * double the current step, capped at the ceiling. Idempotent at the ceiling (a
49561
+ * fully-idle daemon stays there until a job arrives).
49562
+ */
49563
+ onEmptyLease() {
49564
+ this.stepMs = Math.min(this.stepMs * 2, this.ceilingMs);
49565
+ }
49566
+ /**
49567
+ * Reset the delay to the floor after a SUCCESSFUL lease (AC-3): the first real
49568
+ * job snaps the cadence back to fast so an active session is unchanged.
49569
+ */
49570
+ onLease() {
49571
+ this.stepMs = this.floorMs;
49572
+ }
49573
+ /** The current un-jittered step (for assertions on the geometric schedule). */
49574
+ currentStepMs() {
49575
+ return this.stepMs;
49576
+ }
49577
+ /**
49578
+ * The ms to wait before the next tick: the current step plus a bounded jitter.
49579
+ * The jitter is a fraction of the step (`jitter * step`), so it scales with the
49580
+ * step; the result is clamped to `[floorMs, ceilingMs]` so jitter never pushes
49581
+ * the cadence below the fast floor (which would defeat the cost cut) or above the
49582
+ * ceiling (which would blow the worst-case pickup-latency budget).
49583
+ */
49584
+ nextDelayMs() {
49585
+ const offset = this.jitterSource() * this.jitter * this.stepMs;
49586
+ const delayed = this.stepMs + offset;
49587
+ return Math.min(this.ceilingMs, Math.max(this.floorMs, Math.round(delayed)));
49588
+ }
49589
+ };
49590
+
49591
+ // dist/src/daemon/runtime/services/poll-loop.js
49592
+ var AdaptivePollLoop = class {
49593
+ tick;
49594
+ backoffEnabled;
49595
+ flatIntervalMs;
49596
+ timers;
49597
+ backoff;
49598
+ handle;
49599
+ stopped = false;
49600
+ /** Guards against overlapping ticks on the poll loop (the workers' `running` flag). */
49601
+ running = false;
49602
+ constructor(deps) {
49603
+ this.tick = deps.tick;
49604
+ this.backoffEnabled = deps.backoff.enabled;
49605
+ this.flatIntervalMs = deps.flatIntervalMs;
49606
+ this.timers = deps.timers;
49607
+ this.backoff = deps.backoff.enabled ? new PollBackoff(deps.backoff) : null;
49608
+ }
49609
+ start() {
49610
+ this.stopped = false;
49611
+ if (this.backoff === null) {
49612
+ this.handle = this.timers.setTimer(() => {
49613
+ this.fireGuarded(null);
49614
+ }, this.flatIntervalMs);
49615
+ return;
49616
+ }
49617
+ this.scheduleNext(this.backoff.nextDelayMs());
49618
+ }
49619
+ /** Arm the next one-shot tick (adaptive path only). */
49620
+ scheduleNext(ms) {
49621
+ if (this.stopped)
49622
+ return;
49623
+ this.handle = this.timers.setTimer(() => {
49624
+ this.fireGuarded(this.backoff);
49625
+ }, ms);
49626
+ }
49627
+ /**
49628
+ * One guarded tick. Skips if a previous run is still in flight (never overlap).
49629
+ * On the adaptive path, feeds the lease outcome to the state machine and re-arms
49630
+ * the next tick; on the flat path, the repeating interval re-fires on its own.
49631
+ */
49632
+ fireGuarded(backoff) {
49633
+ if (this.running)
49634
+ return;
49635
+ this.running = true;
49636
+ void this.tick().then((processed) => {
49637
+ if (backoff === null)
49638
+ return;
49639
+ if (processed)
49640
+ backoff.onLease();
49641
+ else
49642
+ backoff.onEmptyLease();
49643
+ }).finally(() => {
49644
+ this.running = false;
49645
+ if (backoff !== null)
49646
+ this.scheduleNext(backoff.nextDelayMs());
49647
+ });
49648
+ }
49649
+ stop() {
49650
+ this.stopped = true;
49651
+ if (this.handle !== void 0) {
49652
+ this.timers.clearTimer(this.handle);
49653
+ this.handle = void 0;
49654
+ }
49655
+ }
49656
+ };
49657
+ function createPollLoop(deps) {
49658
+ return new AdaptivePollLoop(deps);
49659
+ }
49660
+ function buildWorkerPollLoop(options) {
49661
+ const setTimer = options.setTimer ?? ((cb, ms) => {
49662
+ const t = setInterval(cb, ms);
49663
+ if (typeof t === "object" && t !== null && "unref" in t && typeof t.unref === "function")
49664
+ t.unref();
49665
+ return t;
49666
+ });
49667
+ const clearTimer = options.clearTimer ?? ((handle) => {
49668
+ if (handle !== void 0)
49669
+ clearInterval(handle);
49670
+ });
49671
+ return createPollLoop({
49672
+ tick: options.tick,
49673
+ backoff: options.backoff ?? PollBackoffConfigSchema.parse({}),
49674
+ flatIntervalMs: options.flatIntervalMs,
49675
+ timers: { setTimer, clearTimer }
49676
+ });
49677
+ }
49678
+
48975
49679
  // dist/src/daemon/runtime/pipeline/stage-worker.js
48976
49680
  var PIPELINE_JOB_KINDS = Object.freeze([
48977
49681
  "memory_extraction",
@@ -48999,33 +49703,42 @@ var PipelineStageWorker = class {
48999
49703
  queue;
49000
49704
  handlers;
49001
49705
  logger;
49706
+ /** Public for the lease coordinator's union (the kinds this participant owns). */
49002
49707
  leaseKinds;
49003
- pollIntervalMs;
49004
- setTimer;
49005
- clearTimer;
49006
- handle;
49007
- /** Guards against overlapping `runOnce` invocations on the poll loop. */
49008
- running = false;
49708
+ loop;
49009
49709
  constructor(deps) {
49010
49710
  this.queue = deps.queue;
49011
49711
  this.handlers = deps.handlers;
49012
49712
  this.logger = deps.logger;
49013
49713
  this.leaseKinds = deps.leaseKinds ?? PIPELINE_JOB_KINDS;
49014
- this.pollIntervalMs = deps.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS2;
49015
- this.setTimer = deps.setTimer ?? ((cb, ms) => setInterval(cb, ms));
49016
- this.clearTimer = deps.clearTimer ?? ((handle) => {
49017
- if (handle !== void 0)
49018
- clearInterval(handle);
49714
+ this.loop = buildWorkerPollLoop({
49715
+ tick: () => this.runOnce(),
49716
+ flatIntervalMs: deps.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS2,
49717
+ backoff: deps.backoff,
49718
+ setTimer: deps.setTimer,
49719
+ clearTimer: deps.clearTimer
49019
49720
  });
49020
49721
  }
49021
49722
  async runOnce() {
49022
49723
  const leased = await this.queue.lease(this.leaseKinds);
49023
49724
  if (leased === null)
49024
49725
  return false;
49726
+ await this.processLeased(leased);
49727
+ return true;
49728
+ }
49729
+ /**
49730
+ * PRD-062b (AC-4): process ONE already-leased pipeline job — route it by kind, run
49731
+ * the handler, and complete/fail it. Split out of {@link runOnce} so the single
49732
+ * combined lease coordinator can dispatch a job IT leased (over the union of kinds)
49733
+ * to this participant without a second lease. The standalone `runOnce` leases then
49734
+ * calls this; both paths share the identical route+run+complete/fail body, so kind
49735
+ * isolation and the no-swallowed-error contract hold whether consolidation is on or off.
49736
+ */
49737
+ async processLeased(leased) {
49025
49738
  if (!isPipelineJobKind(leased.kind)) {
49026
49739
  this.logger?.event("stage.unknown_kind", { id: leased.id, kind: leased.kind });
49027
49740
  await this.queue.fail(leased.id, `unknown pipeline job kind: ${leased.kind}`);
49028
- return true;
49741
+ return;
49029
49742
  }
49030
49743
  const job = toStageJob(leased, leased.kind);
49031
49744
  const handler = this.handlers[leased.kind];
@@ -49038,23 +49751,12 @@ var PipelineStageWorker = class {
49038
49751
  this.logger?.event("stage.failed", { id: job.id, kind: job.kind, attempt: job.attempt, reason });
49039
49752
  await this.queue.fail(job.id, reason);
49040
49753
  }
49041
- return true;
49042
49754
  }
49043
49755
  start() {
49044
- this.handle = this.setTimer(() => {
49045
- if (this.running)
49046
- return;
49047
- this.running = true;
49048
- void this.runOnce().finally(() => {
49049
- this.running = false;
49050
- });
49051
- }, this.pollIntervalMs);
49756
+ this.loop.start();
49052
49757
  }
49053
49758
  stop() {
49054
- if (this.handle !== void 0) {
49055
- this.clearTimer(this.handle);
49056
- this.handle = void 0;
49057
- }
49759
+ this.loop.stop();
49058
49760
  }
49059
49761
  };
49060
49762
  function createStageWorker(deps) {
@@ -49894,34 +50596,45 @@ function extractionFanOut(queue) {
49894
50596
  });
49895
50597
  };
49896
50598
  }
49897
- function decisionFanOut(queue) {
50599
+ function buildControlledWritePayload(decision, entities) {
50600
+ const proposal = {
50601
+ action: decision.proposal.action,
50602
+ confidence: decision.proposal.confidence,
50603
+ reason: decision.proposal.reason
50604
+ };
50605
+ if (decision.proposal.targetId !== void 0 && decision.proposal.targetId !== "") {
50606
+ proposal.target_id = decision.proposal.targetId;
50607
+ }
50608
+ const targetId = decision.proposal.targetId;
50609
+ const candidates = decision.candidates.filter((c) => c.id !== "" && c.id !== targetId && typeof c.content === "string" && c.content !== "").map((c) => ({ id: c.id, content: c.content }));
50610
+ return {
50611
+ proposal,
50612
+ content: decision.fact.content,
50613
+ normalized_content: decision.fact.content,
50614
+ fact_confidence: decision.fact.confidence,
50615
+ fact_type: decision.fact.type,
50616
+ entities: serializeEntities(entities),
50617
+ ...candidates.length > 0 ? { candidates } : {}
50618
+ };
50619
+ }
50620
+ function decisionFanOut(queue, config2 = amplificationConfig()) {
49898
50621
  return async (job, decisions) => {
49899
50622
  const entities = readForwardedEntities(job.payload);
49900
- for (const decision of decisions) {
49901
- if (decision.proposal.action === "none")
49902
- continue;
49903
- const proposal = {
49904
- action: decision.proposal.action,
49905
- confidence: decision.proposal.confidence,
49906
- reason: decision.proposal.reason
49907
- };
49908
- if (decision.proposal.targetId !== void 0 && decision.proposal.targetId !== "") {
49909
- proposal.target_id = decision.proposal.targetId;
49910
- }
49911
- const targetId = decision.proposal.targetId;
49912
- const candidates = decision.candidates.filter((c) => c.id !== "" && c.id !== targetId && typeof c.content === "string" && c.content !== "").map((c) => ({ id: c.id, content: c.content }));
50623
+ const envelope = scopeEnvelope(job.scope);
50624
+ const facts = decisions.filter((d) => d.proposal.action !== "none").map((d) => buildControlledWritePayload(d, entities));
50625
+ if (facts.length === 0)
50626
+ return;
50627
+ if (config2.fanoutBatch) {
49913
50628
  await queue.enqueue({
49914
50629
  kind: "memory_controlled_write",
49915
- payload: {
49916
- ...scopeEnvelope(job.scope),
49917
- proposal,
49918
- content: decision.fact.content,
49919
- normalized_content: decision.fact.content,
49920
- fact_confidence: decision.fact.confidence,
49921
- fact_type: decision.fact.type,
49922
- entities: serializeEntities(entities),
49923
- ...candidates.length > 0 ? { candidates } : {}
49924
- }
50630
+ payload: { ...envelope, [CONTROLLED_WRITE_BATCH_KEY]: facts }
50631
+ });
50632
+ return;
50633
+ }
50634
+ for (const fact of facts) {
50635
+ await queue.enqueue({
50636
+ kind: "memory_controlled_write",
50637
+ payload: { ...envelope, ...fact }
49925
50638
  });
49926
50639
  }
49927
50640
  };
@@ -50463,6 +51176,8 @@ function stateUpdaterFromTrigger(trigger) {
50463
51176
  };
50464
51177
  }
50465
51178
  var PollinatingJobWorkerImpl = class {
51179
+ /** Public for the lease coordinator's union — the single `pollinating` kind. */
51180
+ leaseKinds = LEASE_KINDS2;
50466
51181
  queue;
50467
51182
  storage;
50468
51183
  scope;
@@ -50472,12 +51187,7 @@ var PollinatingJobWorkerImpl = class {
50472
51187
  stateUpdater;
50473
51188
  logger;
50474
51189
  clock;
50475
- pollIntervalMs;
50476
- setTimer;
50477
- clearTimer;
50478
- handle;
50479
- /** Guards against overlapping `runOnce` invocations on the poll loop. */
50480
- running = false;
51190
+ loop;
50481
51191
  constructor(deps) {
50482
51192
  this.queue = deps.queue;
50483
51193
  this.storage = deps.storage;
@@ -50488,22 +51198,36 @@ var PollinatingJobWorkerImpl = class {
50488
51198
  this.stateUpdater = deps.stateUpdater ?? stateUpdaterFromTrigger(deps.trigger);
50489
51199
  this.logger = deps.logger;
50490
51200
  this.clock = deps.clock ?? { now: () => Date.now() };
50491
- this.pollIntervalMs = deps.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS3;
50492
- this.setTimer = deps.setTimer ?? ((cb, ms) => setInterval(cb, ms));
50493
- this.clearTimer = deps.clearTimer ?? ((handle) => {
50494
- if (handle !== void 0)
50495
- clearInterval(handle);
51201
+ this.loop = buildWorkerPollLoop({
51202
+ tick: () => this.runOnce(),
51203
+ flatIntervalMs: deps.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS3,
51204
+ backoff: deps.backoff,
51205
+ setTimer: deps.setTimer,
51206
+ clearTimer: deps.clearTimer
50496
51207
  });
50497
51208
  }
50498
51209
  async runOnce() {
50499
- const leased = await this.queue.lease(LEASE_KINDS2);
51210
+ const leased = await this.queue.lease(this.leaseKinds);
50500
51211
  if (leased === null)
50501
51212
  return false;
51213
+ await this.processLeased(leased);
51214
+ return true;
51215
+ }
51216
+ /**
51217
+ * PRD-062b (AC-4): process ONE already-leased `pollinating` job — parse it, select
51218
+ * the strategy, run the pass, and complete/fail it. Split out of {@link runOnce} so
51219
+ * the single combined lease coordinator can dispatch a job IT leased (over the
51220
+ * union of kinds) to this participant without a second lease. The standalone
51221
+ * `runOnce` leases then calls this; both share the identical parse+run+complete/fail
51222
+ * body, so kind isolation and the no-swallowed-error contract hold whether
51223
+ * consolidation is on or off.
51224
+ */
51225
+ async processLeased(leased) {
50502
51226
  const job = parsePollinatingJobPayload(leased.payload);
50503
51227
  if (job === null) {
50504
51228
  this.logger?.event("pollinating.worker.bad_payload", { id: leased.id });
50505
51229
  await this.queue.fail(leased.id, "malformed pollinating job payload");
50506
- return true;
51230
+ return;
50507
51231
  }
50508
51232
  try {
50509
51233
  const strategy = await this.selectStrategy(job);
@@ -50527,7 +51251,6 @@ var PollinatingJobWorkerImpl = class {
50527
51251
  this.logger?.event("pollinating.worker.failed", { id: leased.id, attempt: leased.attempt, reason });
50528
51252
  await this.queue.fail(leased.id, reason);
50529
51253
  }
50530
- return true;
50531
51254
  }
50532
51255
  /**
50533
51256
  * Select the payload strategy for a job by mode (D-4). Compaction when the payload
@@ -50555,26 +51278,105 @@ var PollinatingJobWorkerImpl = class {
50555
51278
  return shouldEnterCompaction(this.config, state.lastPassAt);
50556
51279
  }
50557
51280
  start() {
50558
- this.handle = this.setTimer(() => {
50559
- if (this.running)
50560
- return;
50561
- this.running = true;
50562
- void this.runOnce().finally(() => {
50563
- this.running = false;
50564
- });
50565
- }, this.pollIntervalMs);
51281
+ this.loop.start();
50566
51282
  }
50567
51283
  stop() {
50568
- if (this.handle !== void 0) {
50569
- this.clearTimer(this.handle);
50570
- this.handle = void 0;
50571
- }
51284
+ this.loop.stop();
50572
51285
  }
50573
51286
  };
50574
51287
  function createPollinatingWorker(deps) {
50575
51288
  return new PollinatingJobWorkerImpl(deps);
50576
51289
  }
50577
51290
 
51291
+ // dist/src/daemon/runtime/services/lease-coordinator.js
51292
+ var CombinedLeaseCoordinator = class {
51293
+ queue;
51294
+ participants;
51295
+ logger;
51296
+ unionKinds;
51297
+ /** `kind` → the participant that owns it (built once; one owner per kind). */
51298
+ routes;
51299
+ loop;
51300
+ constructor(deps) {
51301
+ this.queue = deps.queue;
51302
+ this.participants = deps.participants;
51303
+ this.logger = deps.logger;
51304
+ this.routes = /* @__PURE__ */ new Map();
51305
+ const union2 = [];
51306
+ for (const participant of deps.participants) {
51307
+ for (const kind of participant.leaseKinds) {
51308
+ if (this.routes.has(kind)) {
51309
+ this.logger?.event("lease.coordinator.duplicate_kind", { kind });
51310
+ continue;
51311
+ }
51312
+ this.routes.set(kind, participant);
51313
+ union2.push(kind);
51314
+ }
51315
+ }
51316
+ this.unionKinds = union2;
51317
+ const timers = deps.timers ?? {
51318
+ setTimer: (cb, ms) => {
51319
+ const t = setInterval(cb, ms);
51320
+ if (typeof t === "object" && t !== null && "unref" in t && typeof t.unref === "function")
51321
+ t.unref();
51322
+ return t;
51323
+ },
51324
+ clearTimer: (handle) => {
51325
+ if (handle !== void 0)
51326
+ clearInterval(handle);
51327
+ }
51328
+ };
51329
+ this.loop = createPollLoop({
51330
+ tick: () => this.runOnce(),
51331
+ backoff: deps.backoff,
51332
+ flatIntervalMs: deps.flatIntervalMs,
51333
+ timers
51334
+ });
51335
+ }
51336
+ async runOnce() {
51337
+ const leased = await this.queue.lease(this.unionKinds);
51338
+ if (leased === null)
51339
+ return false;
51340
+ const participant = this.routes.get(leased.kind);
51341
+ if (participant === void 0) {
51342
+ this.logger?.event("lease.coordinator.unknown_kind", { id: leased.id, kind: leased.kind });
51343
+ await this.queue.fail(leased.id, `no participant owns leased kind: ${leased.kind}`);
51344
+ return true;
51345
+ }
51346
+ await participant.processLeased(leased);
51347
+ return true;
51348
+ }
51349
+ start() {
51350
+ this.loop.start();
51351
+ }
51352
+ stop() {
51353
+ this.loop.stop();
51354
+ }
51355
+ };
51356
+ function createLeaseCoordinator(deps) {
51357
+ return new CombinedLeaseCoordinator(deps);
51358
+ }
51359
+ var BoolFlag7 = external_exports.preprocess((raw2) => {
51360
+ if (typeof raw2 === "boolean")
51361
+ return raw2;
51362
+ return raw2 === "true" || raw2 === "1";
51363
+ }, external_exports.boolean());
51364
+ var PollConsolidateConfigSchema = external_exports.object({
51365
+ /** Master switch; off → two independent lease passes, the pre-PRD path (AC-9). */
51366
+ enabled: BoolFlag7.default(false)
51367
+ });
51368
+ function envPollConsolidateConfigProvider(env = process.env) {
51369
+ return {
51370
+ read() {
51371
+ const raw2 = env.HONEYCOMB_POLL_CONSOLIDATE;
51372
+ return { enabled: raw2 === void 0 ? true : raw2 };
51373
+ }
51374
+ };
51375
+ }
51376
+ function resolvePollConsolidateConfig(provider = envPollConsolidateConfigProvider()) {
51377
+ return PollConsolidateConfigSchema.parse(provider.read());
51378
+ }
51379
+
50578
51380
  // dist/src/daemon/runtime/skillify/worker.js
50579
51381
  import { homedir as homedir24 } from "node:os";
50580
51382
  import { join as join31 } from "node:path";
@@ -50841,6 +51643,86 @@ function createSkillifyJobWorker(deps) {
50841
51643
  // dist/src/daemon/storage/client.js
50842
51644
  import { setTimeout as delay3 } from "node:timers/promises";
50843
51645
 
51646
+ // dist/src/daemon/storage/query-meter.js
51647
+ var QUERY_SOURCES = [
51648
+ "poll-lease",
51649
+ "poll-reaper",
51650
+ "capture-write",
51651
+ "fan-out-enqueue",
51652
+ "controlled-write",
51653
+ "recall-arm",
51654
+ "embedding",
51655
+ "other"
51656
+ ];
51657
+ var DEFAULT_QUERY_SOURCE = "other";
51658
+ var QueryMeter = class {
51659
+ /** `source` → {reads, writes}. Lazily populated on first hit per source. */
51660
+ counts = /* @__PURE__ */ new Map();
51661
+ /**
51662
+ * Record ONE metered operation against a `source`.
51663
+ *
51664
+ * @param source the attribution label. Callers that have not threaded a label
51665
+ * pass nothing and the operation is counted under {@link DEFAULT_QUERY_SOURCE}
51666
+ * (`"other"`), so it is visibly "unlabeled" rather than dropped.
51667
+ * @param isWrite `true` for a write statement (INSERT/UPDATE/DELETE/DDL),
51668
+ * `false` for a read (SELECT / read-only WITH). The storage client classifies
51669
+ * this from the statement shape so the split is consistent with the retry
51670
+ * layer's read/write tag, not guessed per call site.
51671
+ */
51672
+ record(source = DEFAULT_QUERY_SOURCE, isWrite = false) {
51673
+ const entry = this.counts.get(source) ?? { reads: 0, writes: 0 };
51674
+ if (isWrite)
51675
+ entry.writes += 1;
51676
+ else
51677
+ entry.reads += 1;
51678
+ this.counts.set(source, entry);
51679
+ }
51680
+ /**
51681
+ * Take an immutable snapshot of the current per-source counts and rollup
51682
+ * totals. Sources that have never been hit are omitted from `perSource` (a
51683
+ * zero-traffic source contributes nothing), but the entries that ARE present
51684
+ * are emitted in the canonical {@link QUERY_SOURCES} order for stable output.
51685
+ */
51686
+ snapshot() {
51687
+ const perSource = [];
51688
+ let totalReads = 0;
51689
+ let totalWrites = 0;
51690
+ for (const source of QUERY_SOURCES) {
51691
+ const entry = this.counts.get(source);
51692
+ if (entry === void 0)
51693
+ continue;
51694
+ perSource.push({ source, reads: entry.reads, writes: entry.writes });
51695
+ totalReads += entry.reads;
51696
+ totalWrites += entry.writes;
51697
+ }
51698
+ return { perSource, totalReads, totalWrites };
51699
+ }
51700
+ /**
51701
+ * Reset every counter to zero. Used by the idle-baseline harness to start a
51702
+ * clean measurement window, and available if a future caller flushes the meter
51703
+ * per period.
51704
+ */
51705
+ reset() {
51706
+ this.counts.clear();
51707
+ }
51708
+ /**
51709
+ * Render the current snapshot as a single structured log line for the periodic
51710
+ * diagnostic surface (AC-62a.1.3). The shape is `key=value` pairs so it greps
51711
+ * cleanly and parses without a schema:
51712
+ *
51713
+ * [query-meter] total_reads=42 total_writes=7 poll-lease=r:30/w:0 capture-write=r:0/w:5 other=r:12/w:2
51714
+ *
51715
+ * A meter with no traffic yet renders the header with zero totals and no
51716
+ * per-source segments, so an idle window is still an explicit, loggable fact.
51717
+ */
51718
+ formatLogLine() {
51719
+ const snap = this.snapshot();
51720
+ const segments = snap.perSource.map((e) => `${e.source}=r:${e.reads}/w:${e.writes}`);
51721
+ const header = `[query-meter] total_reads=${snap.totalReads} total_writes=${snap.totalWrites}`;
51722
+ return segments.length === 0 ? header : `${header} ${segments.join(" ")}`;
51723
+ }
51724
+ };
51725
+
50844
51726
  // dist/src/daemon/storage/transport.js
50845
51727
  var TransportError = class extends Error {
50846
51728
  kind;
@@ -51015,15 +51897,39 @@ var StorageClient = class {
51015
51897
  * the real timer; a test injects a no-op so the bounded backoff costs zero
51016
51898
  * wall-clock time and the retry count stays deterministic.
51017
51899
  */
51018
- constructor(transport, config2, sleep2 = realSleep2) {
51900
+ /** Per-source DeepLake query meter (PRD-062a). Always present; default mode is in-memory + log only. */
51901
+ meter;
51902
+ /**
51903
+ * @param sleep injectable backoff clock for the read-retry layer. Defaults to
51904
+ * the real timer; a test injects a no-op so the bounded backoff costs zero
51905
+ * wall-clock time and the retry count stays deterministic.
51906
+ * @param meter injectable query meter (PRD-062a). Defaults to a fresh in-memory
51907
+ * {@link QueryMeter}; the daemon may inject a shared one so diagnostics and a
51908
+ * later persistence path observe the SAME counts. The meter is a pure observer:
51909
+ * supplying it never changes any query's behavior or result.
51910
+ */
51911
+ constructor(transport, config2, sleep2 = realSleep2, meter = new QueryMeter()) {
51019
51912
  this.transport = transport;
51020
51913
  this.config = config2;
51021
51914
  this.sleep = sleep2;
51915
+ this.meter = meter;
51022
51916
  }
51023
51917
  /** The endpoint the client is bound to (for diagnostics; no secrets). */
51024
51918
  get endpoint() {
51025
51919
  return this.config.endpoint;
51026
51920
  }
51921
+ /**
51922
+ * Snapshot the per-source query counts (PRD-062a, AC-62a.1.3). The diagnostic
51923
+ * surface and the idle-baseline harness read the meter through here without
51924
+ * touching the live counter, so a snapshot is stable even as traffic continues.
51925
+ */
51926
+ meterSnapshot() {
51927
+ return this.meter.snapshot();
51928
+ }
51929
+ /** Render the current per-source counts as one structured log line (PRD-062a). */
51930
+ meterLogLine() {
51931
+ return this.meter.formatLogLine();
51932
+ }
51027
51933
  /**
51028
51934
  * Liveness check (a-AC-1): "connects" against the fake transport means a
51029
51935
  * trivial statement succeeds. Returns a typed result so a caller branches on
@@ -51056,7 +51962,9 @@ var StorageClient = class {
51056
51962
  * from the per-statement timeout: each attempt gets its own fresh timeout/abort.
51057
51963
  */
51058
51964
  async query(sql, scope, opts = {}) {
51059
- if (statementRetryability(sql) === "unsafe-write")
51965
+ const retryability = statementRetryability(sql);
51966
+ this.meter.record(opts.source, retryability !== "read");
51967
+ if (retryability === "unsafe-write")
51060
51968
  return this.attemptOnce(sql, scope, opts);
51061
51969
  let last;
51062
51970
  for (let attempt = 1; attempt <= RETRY_ATTEMPTS; attempt++) {
@@ -51141,7 +52049,7 @@ function createStorageClient(options = {}) {
51141
52049
  const provider = options.provider ?? defaultCredentialProvider();
51142
52050
  const config2 = resolveStorageConfig(provider);
51143
52051
  const transport = options.transport ?? new HttpDeepLakeTransport(config2.endpoint, config2.token);
51144
- return new StorageClient(transport, config2, options.sleep);
52052
+ return new StorageClient(transport, config2, options.sleep, options.meter);
51145
52053
  }
51146
52054
  function createLazyStorageClient(options = {}) {
51147
52055
  let built = null;
@@ -51291,7 +52199,7 @@ function authForMode(mode, storage, scope) {
51291
52199
  return { authenticator: composeAuthenticator(storage, scope), policy: defaultDenyPolicy };
51292
52200
  }
51293
52201
  function assembleSeams(daemon, storage, defaultScope, orgName, embed, healthDetail, workspaceDir, installedHarnesses, logStore, seams = defaultSeamFns, vault) {
51294
- seams.attachHooks(daemon, {
52202
+ const captureHandler = seams.attachHooks(daemon, {
51295
52203
  storage,
51296
52204
  queue: daemon.services.queue,
51297
52205
  embed,
@@ -51416,6 +52324,7 @@ function assembleSeams(daemon, storage, defaultScope, orgName, embed, healthDeta
51416
52324
  `);
51417
52325
  }
51418
52326
  }
52327
+ return captureHandler;
51419
52328
  }
51420
52329
  function resolveProductDataDeps(storage, defaultScope, queue, embed) {
51421
52330
  const baseDir = process.env.HONEYCOMB_WORKSPACE ?? process.cwd();
@@ -51502,7 +52411,7 @@ function coerceSettingBool(value) {
51502
52411
  return value === "true" || value === "1";
51503
52412
  return false;
51504
52413
  }
51505
- async function buildGatedPollinatingWorker(options, storage, scope, queue, vault) {
52414
+ async function buildGatedPollinatingWorker(options, storage, scope, queue, vault, backoff) {
51506
52415
  let config2;
51507
52416
  try {
51508
52417
  config2 = resolvePollinatingConfig(options.pollinatingConfigProvider);
@@ -51529,7 +52438,7 @@ async function buildGatedPollinatingWorker(options, storage, scope, queue, vault
51529
52438
  ...providerModelOverride !== void 0 ? { providerModelOverride } : {}
51530
52439
  });
51531
52440
  const trigger = createPollinatingTrigger({ storage, scope, config: config2, enqueuer: queue });
51532
- return createPollinatingWorker({ queue, storage, scope, config: config2, model, trigger });
52441
+ return createPollinatingWorker({ queue, storage, scope, config: config2, model, trigger, backoff });
51533
52442
  }
51534
52443
  function buildSummaryWorker(storage, scope, queue, embed) {
51535
52444
  return createSummaryJobWorker({ queue, storage, scope, embed: embed.client });
@@ -51550,7 +52459,7 @@ function makePipelineEntryEnqueuer(queue) {
51550
52459
  });
51551
52460
  };
51552
52461
  }
51553
- async function buildPipelineWorker(options, storage, scope, queue, embed) {
52462
+ async function buildPipelineWorker(options, storage, scope, queue, embed, backoff) {
51554
52463
  let config2;
51555
52464
  try {
51556
52465
  config2 = resolvePipelineConfig();
@@ -51580,7 +52489,7 @@ async function buildPipelineWorker(options, storage, scope, queue, embed) {
51580
52489
  graphPersist: { storage, scope: queryScope, config: config2 },
51581
52490
  retention: { storage, scope: queryScope, config: config2 }
51582
52491
  });
51583
- return createStageWorker({ queue, handlers });
52492
+ return createStageWorker({ queue, handlers, backoff });
51584
52493
  }
51585
52494
  function buildSkillifyWorker(storage, scope, queue) {
51586
52495
  return createSkillifyJobWorker({
@@ -51635,7 +52544,7 @@ function assembleDaemon(options = {}) {
51635
52544
  const embed = options.embed ?? createEmbedAttachment({ storage });
51636
52545
  const installedHarnesses = options.installedHarnesses ?? (options.harnessTargets !== void 0 && options.harnessTargets.length > 0 ? new Set(options.harnessTargets.map((t) => t.name)) : options.storage === void 0 ? detectInstalledHarnesses() : /* @__PURE__ */ new Set());
51637
52546
  const vault = options.vault ?? (options.storage === void 0 ? buildVaultStore() : void 0);
51638
- assembleSeams(daemon, storage, scope, daemonOrgName, embed, healthDetail, options.workspaceDir ?? process.cwd(), installedHarnesses, logStore, options.seams ?? defaultSeamFns, vault);
52547
+ const captureHandler = assembleSeams(daemon, storage, scope, daemonOrgName, embed, healthDetail, options.workspaceDir ?? process.cwd(), installedHarnesses, logStore, options.seams ?? defaultSeamFns, vault);
51639
52548
  if (vault !== void 0 && vault instanceof VaultStore) {
51640
52549
  try {
51641
52550
  mountSettingsApi(daemon, { store: vault });
@@ -51705,6 +52614,7 @@ function assembleDaemon(options = {}) {
51705
52614
  let pollinatingWorker = null;
51706
52615
  let summaryWorker = null;
51707
52616
  let pipelineWorker = null;
52617
+ let leaseCoordinator = null;
51708
52618
  let skillifyWorker = null;
51709
52619
  return {
51710
52620
  daemon,
@@ -51724,6 +52634,18 @@ function assembleDaemon(options = {}) {
51724
52634
  probeTimer.unref();
51725
52635
  }
51726
52636
  await daemon.startServices();
52637
+ let pollBackoff;
52638
+ try {
52639
+ pollBackoff = resolvePollBackoffConfig();
52640
+ } catch {
52641
+ pollBackoff = resolvePollBackoffConfig({ read: () => ({}) });
52642
+ }
52643
+ let consolidatePoll = false;
52644
+ try {
52645
+ consolidatePoll = resolvePollConsolidateConfig().enabled;
52646
+ } catch {
52647
+ consolidatePoll = false;
52648
+ }
51727
52649
  try {
51728
52650
  summaryWorker = buildSummaryWorker(storage, scope, daemon.services.queue, embed);
51729
52651
  summaryWorker.start();
@@ -51734,8 +52656,9 @@ function assembleDaemon(options = {}) {
51734
52656
  summaryWorker = null;
51735
52657
  }
51736
52658
  try {
51737
- pipelineWorker = await buildPipelineWorker(options, storage, scope, daemon.services.queue, embed);
51738
- pipelineWorker.start();
52659
+ pipelineWorker = await buildPipelineWorker(options, storage, scope, daemon.services.queue, embed, pollBackoff);
52660
+ if (!consolidatePoll)
52661
+ pipelineWorker.start();
51739
52662
  } catch (err) {
51740
52663
  const reason = err instanceof Error ? err.message : String(err);
51741
52664
  process.stderr.write(`honeycomb: memory-pipeline worker start failed (non-fatal): ${reason}
@@ -51765,16 +52688,41 @@ function assembleDaemon(options = {}) {
51765
52688
  }
51766
52689
  }
51767
52690
  try {
51768
- pollinatingWorker = await buildGatedPollinatingWorker(options, storage, scope, daemon.services.queue, vault);
51769
- pollinatingWorker?.start();
52691
+ pollinatingWorker = await buildGatedPollinatingWorker(options, storage, scope, daemon.services.queue, vault, pollBackoff);
52692
+ const pollinatingInjected = options.pollinatingWorker !== void 0;
52693
+ if (consolidatePoll && !pollinatingInjected) {
52694
+ const participants = [pipelineWorker, pollinatingWorker].filter((p) => p !== null);
52695
+ if (participants.length > 0) {
52696
+ leaseCoordinator = createLeaseCoordinator({
52697
+ queue: daemon.services.queue,
52698
+ participants,
52699
+ backoff: pollBackoff,
52700
+ flatIntervalMs: 1e3
52701
+ });
52702
+ leaseCoordinator.start();
52703
+ }
52704
+ } else {
52705
+ pollinatingWorker?.start();
52706
+ if (consolidatePoll && pollinatingInjected && pipelineWorker !== null) {
52707
+ pipelineWorker.start();
52708
+ }
52709
+ }
51770
52710
  } catch (err) {
51771
52711
  const reason = err instanceof Error ? err.message : String(err);
51772
52712
  process.stderr.write(`honeycomb: pollinating worker start failed (non-fatal): ${reason}
51773
52713
  `);
51774
52714
  pollinatingWorker = null;
52715
+ if (consolidatePoll && leaseCoordinator === null && pipelineWorker !== null) {
52716
+ pipelineWorker.start();
52717
+ }
51775
52718
  }
51776
52719
  },
51777
52720
  async shutdown() {
52721
+ await captureHandler.flush?.();
52722
+ if (leaseCoordinator !== null) {
52723
+ leaseCoordinator.stop();
52724
+ leaseCoordinator = null;
52725
+ }
51778
52726
  if (pollinatingWorker !== null) {
51779
52727
  pollinatingWorker.stop();
51780
52728
  pollinatingWorker = null;
@@ -51911,6 +52859,7 @@ export {
51911
52859
  DEFAULT_MAX_POLLS2 as DEFAULT_MAX_POLLS,
51912
52860
  DEFAULT_MAX_RETRIES,
51913
52861
  DEFAULT_OVERFETCH_MULTIPLIER,
52862
+ DEFAULT_QUERY_SOURCE,
51914
52863
  DEFAULT_QUERY_TIMEOUT_MS,
51915
52864
  DEFAULT_TIMESTAMP_COLUMN,
51916
52865
  DEFAULT_VERSION_COLUMN,
@@ -51935,6 +52884,8 @@ export {
51935
52884
  LEGACY_CREDENTIALS_DIR_NAME,
51936
52885
  LOCK_FILE_NAME,
51937
52886
  PID_FILE_NAME,
52887
+ QUERY_SOURCES,
52888
+ QueryMeter,
51938
52889
  ROLES,
51939
52890
  RuntimeConfigError,
51940
52891
  RuntimeConfigSchema,