memhtml 0.4.0 → 0.5.1

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.
@@ -8267,12 +8267,23 @@ const EmbeddingsLive = Layer.effect(Embeddings, Effect.gen(function* () {
8267
8267
  //#endregion
8268
8268
  //#region packages/llm/dist/models.js
8269
8269
  /**
8270
- * The three Claude 5 models the sleep phases run on, and the wire rules that differ
8271
- * between them. The set is Anthropic-only on purpose, because the four LLM phases need one
8272
- * call shape. A second vendor would add a second set of truncation and structured-output
8273
- * semantics that no phase asks for.
8270
+ * The models the sleep phases run on, and the wire rules that differ between them.
8271
+ *
8272
+ * Two providers, two call shapes, one decode. The Anthropic lane speaks the native
8273
+ * Messages body with a forced `emit` tool; the OpenAI lane speaks the chat-completions
8274
+ * body with `response_format: {type: "json_schema", strict: true}`. The OpenAI lane
8275
+ * exists for exactly one property the Anthropic lane cannot offer on Bedrock today:
8276
+ * constrained decoding, which makes an off-schema structured answer impossible at
8277
+ * generation time instead of repaired after (probed live 2026-08-22 — the Claude 5
8278
+ * models reject `strict` and `output_config.format` on every Bedrock surface, while
8279
+ * `global.openai.gpt-5.6-sol` honors strict JSON schema on InvokeModel). Both lanes
8280
+ * converge on the same response shape before `decodeToolInput`, so every phase and
8281
+ * every test sees one contract.
8282
+ */
8283
+ /**
8284
+ * Reasoning effort. The Anthropic lane passes it as `output_config.effort`, the OpenAI
8285
+ * lane as `reasoning_effort`; both accept all four values (sol probed live 2026-08-22).
8274
8286
  */
8275
- /** Reasoning effort, passed as `output_config.effort`. Accepted by all three models. */
8276
8287
  const Effort = Schema.Literals([
8277
8288
  "low",
8278
8289
  "medium",
@@ -8282,27 +8293,39 @@ const Effort = Schema.Literals([
8282
8293
  const ModelKey = Schema.Literals([
8283
8294
  "sonnet-5",
8284
8295
  "opus-5",
8285
- "fable-5"
8296
+ "fable-5",
8297
+ "gpt-5.6-sol"
8286
8298
  ]);
8287
8299
  /**
8288
8300
  * Bedrock ids use the `global.` inference profiles, which makes them reachable from a
8289
- * single region without provisioning per-region throughput.
8301
+ * single region without provisioning per-region throughput. The OpenAI models REQUIRE
8302
+ * the profile: the bare `openai.gpt-5.6-*` ids reject on-demand invocation outright
8303
+ * (probed live 2026-08-22).
8290
8304
  */
8291
8305
  const MODELS = [
8292
8306
  {
8293
8307
  key: "sonnet-5",
8294
8308
  label: "Claude Sonnet 5",
8295
- modelId: "global.anthropic.claude-sonnet-5"
8309
+ modelId: "global.anthropic.claude-sonnet-5",
8310
+ provider: "anthropic"
8296
8311
  },
8297
8312
  {
8298
8313
  key: "opus-5",
8299
8314
  label: "Claude Opus 5",
8300
- modelId: "global.anthropic.claude-opus-5"
8315
+ modelId: "global.anthropic.claude-opus-5",
8316
+ provider: "anthropic"
8301
8317
  },
8302
8318
  {
8303
8319
  key: "fable-5",
8304
8320
  label: "Claude Fable 5",
8305
- modelId: "global.anthropic.claude-fable-5"
8321
+ modelId: "global.anthropic.claude-fable-5",
8322
+ provider: "anthropic"
8323
+ },
8324
+ {
8325
+ key: "gpt-5.6-sol",
8326
+ label: "GPT-5.6 Sol",
8327
+ modelId: "global.openai.gpt-5.6-sol",
8328
+ provider: "openai"
8306
8329
  }
8307
8330
  ];
8308
8331
  const BY_KEY = new Map(MODELS.map((model) => [model.key, model]));
@@ -8317,12 +8340,13 @@ const modelByKey = (key) => {
8317
8340
  return found;
8318
8341
  };
8319
8342
  /**
8320
- * The `thinking` object per model. Opus 5 and Fable 5 take `{type: "adaptive"}` (Fable is
8321
- * adaptive-only). Sonnet 5 reasons unconditionally and takes NO thinking key. Sending one
8322
- * to Sonnet 5 raises a validation error instead of being ignored.
8343
+ * The `thinking` object per Anthropic model. Opus 5 and Fable 5 take `{type: "adaptive"}`
8344
+ * (Fable is adaptive-only). Sonnet 5 reasons unconditionally and takes NO thinking key.
8345
+ * Sending one to Sonnet 5 raises a validation error instead of being ignored. The OpenAI
8346
+ * lane never consults this: its reasoning dial is `reasoning_effort` alone.
8323
8347
  *
8324
- * Verified live 2026-08-02: all three accept this shape alongside a forced `tool_choice`,
8325
- * so structured output and adaptive thinking compose.
8348
+ * Verified live 2026-08-02: all three Claude models accept this shape alongside a forced
8349
+ * `tool_choice`, so structured output and adaptive thinking compose.
8326
8350
  */
8327
8351
  const thinkingFor = (key) => key === "opus-5" || key === "fable-5" ? { type: "adaptive" } : null;
8328
8352
 
@@ -8337,6 +8361,13 @@ const thinkingFor = (key) => key === "opus-5" || key === "fable-5" ? { type: "ad
8337
8361
  * default for an omitted field, and no accepted extra key. Downstream code cannot tell a
8338
8362
  * coerced object from a real one, and the phases that consume these objects archive and
8339
8363
  * rewrite files.
8364
+ *
8365
+ * ONE repair is the exception, because it recovers the payload the model meant rather than
8366
+ * inventing one: a top-level field the schema declares as an array or object sometimes
8367
+ * arrives double-encoded as a JSON STRING. That string is parsed once and the SAME strict
8368
+ * decode re-runs on the result, so nothing an off-schema answer carries can slip through —
8369
+ * a payload the repair cannot make satisfy the schema still fails with the original
8370
+ * violation. See {@link decodeToolInput}.
8340
8371
  */
8341
8372
  /** Cap on the raw payload carried on a violation, so a runaway response cannot bloat it. */
8342
8373
  const MAX_RAW = 800;
@@ -8371,6 +8402,50 @@ const preview = (payload) => {
8371
8402
  })();
8372
8403
  return rendered.length <= 800 ? rendered : `${rendered.slice(0, 800)}…`;
8373
8404
  };
8405
+ /** True when a property's derived JSON schema declares a container: an array, an object, or a
8406
+ * `$ref` (every hoisted definition is a struct). A string-typed property is NOT a container,
8407
+ * which is what keeps a field that legitimately holds JSON-looking text out of the repair. */
8408
+ const expectsContainer = (property) => {
8409
+ if (typeof property !== "object" || property === null) return false;
8410
+ const record = property;
8411
+ return typeof record.$ref === "string" || record.type === "array" || record.type === "object";
8412
+ };
8413
+ /**
8414
+ * Undo ONE level of JSON-string double-encoding on the top-level fields of a tool payload.
8415
+ *
8416
+ * The shape this repairs was observed on the wire: a field the schema declares as an array
8417
+ * arrives as `"{\"groups\":[…]}"` — the whole answer serialized as a string under its own
8418
+ * key — or as the array itself serialized. So a string sitting where the derived
8419
+ * `input_schema` declares a container is parsed once; when the parsed value is an object
8420
+ * carrying the SAME key, the value at that key is taken, otherwise the parsed value stands.
8421
+ *
8422
+ * Returns `undefined` when there is nothing to repair: no field qualified, or no parse
8423
+ * succeeded. The caller then reports the ORIGINAL violation, and a repaired payload still
8424
+ * re-runs the same strict decode, so this never widens what the schema accepts.
8425
+ */
8426
+ const unwrapDoubleEncoded = (schema, input) => {
8427
+ if (typeof input !== "object" || input === null || Array.isArray(input)) return void 0;
8428
+ const properties = toInputSchema(schema).properties;
8429
+ if (properties === void 0) return void 0;
8430
+ let repairedAField = false;
8431
+ const repaired = {};
8432
+ for (const [key, received] of Object.entries(input)) {
8433
+ repaired[key] = received;
8434
+ if (typeof received !== "string" || !expectsContainer(properties[key])) continue;
8435
+ const parsed = (() => {
8436
+ try {
8437
+ return { value: JSON.parse(received) };
8438
+ } catch {
8439
+ return;
8440
+ }
8441
+ })();
8442
+ if (parsed === void 0) continue;
8443
+ const wrapper = typeof parsed.value === "object" && parsed.value !== null && !Array.isArray(parsed.value) ? parsed.value : void 0;
8444
+ repaired[key] = wrapper !== void 0 && key in wrapper ? wrapper[key] : parsed.value;
8445
+ repairedAField = true;
8446
+ }
8447
+ return repairedAField ? repaired : void 0;
8448
+ };
8374
8449
  /**
8375
8450
  * Decode a forced-tool payload against its schema.
8376
8451
  *
@@ -8379,13 +8454,29 @@ const preview = (payload) => {
8379
8454
  * would let a model answer a schema next to the one it was given and have the extra field
8380
8455
  * vanish. croq's judge rules out the same drift by enumerating its allowed keys.
8381
8456
  *
8457
+ * One failure shape is repaired before the violation is constructed: a top-level container
8458
+ * field double-encoded as a JSON string ({@link unwrapDoubleEncoded}). The repaired payload
8459
+ * goes through the SAME strict decode, and a repair that still does not satisfy the schema
8460
+ * reports the original payload's violation, so the repair cannot mask a genuinely off-schema
8461
+ * answer.
8462
+ *
8382
8463
  * `undefined` input means the model produced no `emit` call at all. That is the same class
8383
8464
  * of failure as a malformed one, and the reason text names it so a caller can tell the two
8384
8465
  * apart in a log without a second error type.
8385
8466
  */
8386
8467
  const decodeToolInput = (schema, input) => input === void 0 ? Effect.fail(LlmContractViolation.make({ reason: "model returned no tool_use block for the forced tool" })) : Effect.gen(function* () {
8387
- const decoded = yield* Effect.result(Schema.decodeUnknownEffect(schema, { onExcessProperty: "error" })(input));
8388
- return Result.isSuccess(decoded) ? decoded.success : yield* Effect.fail(LlmContractViolation.make({ reason: `tool payload does not satisfy its schema: ${String(decoded.failure)} (raw: ${preview(input)})` }));
8468
+ const strictDecode = Schema.decodeUnknownEffect(schema, { onExcessProperty: "error" });
8469
+ const decoded = yield* Effect.result(strictDecode(input));
8470
+ if (Result.isSuccess(decoded)) return decoded.success;
8471
+ const repaired = unwrapDoubleEncoded(schema, input);
8472
+ if (repaired !== void 0) {
8473
+ const redecoded = yield* Effect.result(strictDecode(repaired));
8474
+ if (Result.isSuccess(redecoded)) {
8475
+ yield* Effect.logWarning("llm.structured repaired a double-encoded tool field before decoding");
8476
+ return redecoded.success;
8477
+ }
8478
+ }
8479
+ return yield* Effect.fail(LlmContractViolation.make({ reason: `tool payload does not satisfy its schema: ${String(decoded.failure)} (raw: ${preview(input)})` }));
8389
8480
  });
8390
8481
 
8391
8482
  //#endregion
@@ -8397,16 +8488,18 @@ const decodeToolInput = (schema, input) => input === void 0 ? Effect.fail(LlmCon
8397
8488
  */
8398
8489
  const clampTokens = (requested) => Math.min(requested ?? 16384, MAX_TOKENS_CEILING);
8399
8490
  /**
8400
- * Build the request body. The `tool` argument selects the lane. When it is absent the model
8401
- * answers in prose. When it is present, `tool_choice` forces the model into exactly one
8402
- * `emit` call, and that is the whole structured-output mechanism.
8491
+ * Build the request body in the model's own dialect. The `tool` argument selects the lane.
8492
+ * When it is absent the model answers in prose. When it is present the request constrains
8493
+ * the model to exactly one schema-shaped answer: a forced `emit` tool call on the
8494
+ * Anthropic dialect, a strict `json_schema` response format on the OpenAI one.
8403
8495
  *
8404
8496
  * `system` is omitted rather than sent empty, because an empty system block is a distinct
8405
8497
  * (and rejected) input from no system block at all. An omitted system also has nothing to cache, so
8406
8498
  * `cacheSystem` over an absent or empty system emits no `system` key at all instead of an empty
8407
8499
  * cached block.
8408
8500
  */
8409
- const buildInvokeBody = (key, prompt, options, tool) => {
8501
+ const buildInvokeBody = (key, prompt, options, tool) => modelByKey(key).provider === "openai" ? buildOpenAiBody(prompt, options, tool) : buildAnthropicBody(key, prompt, options, tool);
8502
+ const buildAnthropicBody = (key, prompt, options, tool) => {
8410
8503
  const body = {
8411
8504
  anthropic_version: ANTHROPIC_VERSION,
8412
8505
  max_tokens: clampTokens(options.maxTokens),
@@ -8437,6 +8530,51 @@ const buildInvokeBody = (key, prompt, options, tool) => {
8437
8530
  return JSON.stringify(body);
8438
8531
  };
8439
8532
  /**
8533
+ * The OpenAI chat-completions body (probed live 2026-08-22 against
8534
+ * `global.openai.gpt-5.6-sol` — every field here is one the probe exercised).
8535
+ *
8536
+ * Differences from the Anthropic dialect, each one deliberate:
8537
+ *
8538
+ * - The token budget is `max_completion_tokens` and it bounds reasoning and answer
8539
+ * together, so the same clamp applies. 128k accepted at the ceiling.
8540
+ * - Effort is `reasoning_effort`, taking the same four values.
8541
+ * - `system` rides as a leading `{role: "system"}` message; there is no `system` field.
8542
+ * `cacheSystem` has no OpenAI-side marker — Bedrock reports `cache_write_tokens` in
8543
+ * this dialect's usage without an opt-in field — so the flag is accepted and unused
8544
+ * rather than rejected, keeping the option surface identical across lanes.
8545
+ * - The structured mechanism is `response_format.json_schema` with `strict: true`, named
8546
+ * `emit` so logs read the same across providers. `description` becomes the schema's
8547
+ * own `description`, the closest surface this dialect has to a tool description.
8548
+ */
8549
+ const buildOpenAiBody = (prompt, options, tool) => {
8550
+ const messages = [];
8551
+ if (options.system !== void 0 && options.system.length > 0) messages.push({
8552
+ role: "system",
8553
+ content: options.system
8554
+ });
8555
+ messages.push({
8556
+ role: "user",
8557
+ content: prompt
8558
+ });
8559
+ const body = {
8560
+ max_completion_tokens: clampTokens(options.maxTokens),
8561
+ messages,
8562
+ reasoning_effort: options.effort
8563
+ };
8564
+ if (tool !== void 0) body.response_format = {
8565
+ type: "json_schema",
8566
+ json_schema: {
8567
+ name: STRUCTURED_TOOL_NAME,
8568
+ strict: true,
8569
+ schema: tool.description === void 0 ? tool.inputSchema : {
8570
+ description: tool.description,
8571
+ ...tool.inputSchema
8572
+ }
8573
+ }
8574
+ };
8575
+ return JSON.stringify(body);
8576
+ };
8577
+ /**
8440
8578
  * `stop_reason` values that mean the content is not a complete answer. Both become typed
8441
8579
  * failures. A response cut off at `max_tokens` may never have reached the point that made
8442
8580
  * it a judgment, and a refusal carries no judgment at all. Reading either as a finished
@@ -8445,6 +8583,55 @@ const buildInvokeBody = (key, prompt, options, tool) => {
8445
8583
  const INCOMPLETE_STOP_REASONS = /* @__PURE__ */ new Set(["max_tokens", "refusal"]);
8446
8584
  /** The parsed payload, read defensively, since every field on the wire is optional. */
8447
8585
  const asResponseBody = (payload) => payload ?? {};
8586
+ /**
8587
+ * Fold an OpenAI chat-completions payload into {@link InvokeResponseBody}, so one read
8588
+ * side serves both dialects.
8589
+ *
8590
+ * `finish_reason` maps onto the Anthropic vocabulary this module already gates on:
8591
+ * `length` is `max_tokens` and `content_filter` is `refusal`, both of which
8592
+ * {@link INCOMPLETE_STOP_REASONS} already refuses; everything else passes through as a
8593
+ * complete answer. `structured` says how the caller asked, which decides how the content
8594
+ * is presented: a structured request's content is the schema-constrained JSON, parsed
8595
+ * here and presented as the `emit` tool's input, and a prose request's content is a text
8596
+ * block. Content that fails to parse on the structured path yields NO tool block, which
8597
+ * downstream reports as the existing "no tool_use block" violation — the right class,
8598
+ * since constrained decoding makes that a broken response rather than an off-schema one.
8599
+ */
8600
+ const normalizeOpenAiResponse = (payload, structured) => {
8601
+ const body = payload ?? {};
8602
+ const choice = body.choices?.[0];
8603
+ const finish = choice?.finish_reason ?? null;
8604
+ const stopReason = finish === "length" ? "max_tokens" : finish === "content_filter" ? "refusal" : finish;
8605
+ const text = choice?.message?.content;
8606
+ const content = [];
8607
+ if (typeof text === "string" && text.length > 0) {
8608
+ if (structured) {
8609
+ const input = (() => {
8610
+ try {
8611
+ return { value: JSON.parse(text) };
8612
+ } catch {
8613
+ return;
8614
+ }
8615
+ })();
8616
+ if (input !== void 0) content.push({
8617
+ type: "tool_use",
8618
+ name: STRUCTURED_TOOL_NAME,
8619
+ input: input.value
8620
+ });
8621
+ } else content.push({
8622
+ type: "text",
8623
+ text
8624
+ });
8625
+ }
8626
+ return {
8627
+ stop_reason: stopReason,
8628
+ content,
8629
+ usage: {
8630
+ ...body.usage?.prompt_tokens === void 0 ? {} : { input_tokens: body.usage.prompt_tokens },
8631
+ ...body.usage?.completion_tokens === void 0 ? {} : { output_tokens: body.usage.completion_tokens }
8632
+ }
8633
+ };
8634
+ };
8448
8635
  /** The incomplete `stop_reason`, or null when the response ran to a natural end. */
8449
8636
  const incompleteReason = (parsed) => {
8450
8637
  const stop = parsed.stop_reason ?? null;
@@ -8483,7 +8670,7 @@ const makeModelClient = (client) => {
8483
8670
  description: tool.description
8484
8671
  }));
8485
8672
  const finished = yield* Effect.clockWith((clock) => clock.currentTimeMillis);
8486
- const parsed = asResponseBody(payload);
8673
+ const parsed = model.provider === "openai" ? normalizeOpenAiResponse(payload, tool !== void 0) : asResponseBody(payload);
8487
8674
  const incomplete = incompleteReason(parsed);
8488
8675
  if (incomplete !== null) return yield* Effect.fail(ModelUnavailable.make({
8489
8676
  modelId: model.modelId,
@@ -8834,17 +9021,42 @@ const keyMembers = (items, textOf, options) => {
8834
9021
  };
8835
9022
  };
8836
9023
  /**
9024
+ * The offered key a model's answer denotes, or `undefined` when it denotes none.
9025
+ *
9026
+ * A model shown `<member_m3>` answers `member_m3` at least as readily as `m3`: the wrapper tag is
9027
+ * the only place most batch prompts DISPLAY a key, so the label-prefixed form is the one the prompt
9028
+ * itself teaches (measured live 2026-08-23: `gpt-5.6-sol` answers the prefixed form on every call,
9029
+ * Claude Sonnet 5 on most). So a key that does not match directly is retried once with everything
9030
+ * up to its last `_` stripped, and only a suffix the batch actually offered resolves — `member_m9`
9031
+ * in a batch of three still denotes nothing, and a path or an invented name still drops. The
9032
+ * canonical form is returned so two spellings of one member collapse to one key everywhere a phase
9033
+ * keeps per-key state.
9034
+ */
9035
+ const offeredKeyFor = (batch, key) => {
9036
+ if (batch.itemForKey.has(key)) return key;
9037
+ const at = key.lastIndexOf("_");
9038
+ if (at === -1) return void 0;
9039
+ const suffix = key.slice(at + 1);
9040
+ return batch.itemForKey.has(suffix) ? suffix : void 0;
9041
+ };
9042
+ /**
8837
9043
  * Resolve the keys a model named back to items: unknown keys are dropped, repeats collapse.
8838
9044
  *
8839
9045
  * A key the batch never offered is a member the model invented, and every phase on this kernel turns
8840
9046
  * a named member into a write, so an unresolvable key must not reach that write. Dropping it leaves
8841
9047
  * the corresponding file untouched, which is the safe outcome for every one of the five phases.
9048
+ * Resolution goes through {@link offeredKeyFor}, so the label-prefixed spelling of an offered key
9049
+ * (`member_m3` for `m3`) resolves rather than reading as an invention.
8842
9050
  *
8843
9051
  * The result keeps the order the model named the keys in, and a key named twice appears once.
8844
- * De-duplication is on the KEY rather than on the resolved item, so the count a phase gates on
8845
- * ("at least two members absorbed") counts distinct offered members.
8846
- */
8847
- const resolveKeys = (batch, keys) => [...new Set(keys)].flatMap((key) => {
9052
+ * De-duplication is on the CANONICAL key rather than on the spelling or the resolved item, so `m1`
9053
+ * and `member_m1` in one answer count as one member, and the count a phase gates on ("at least two
9054
+ * members absorbed") counts distinct offered members.
9055
+ */
9056
+ const resolveKeys = (batch, keys) => [...new Set(keys.flatMap((key) => {
9057
+ const canonical = offeredKeyFor(batch, key);
9058
+ return canonical === void 0 ? [] : [canonical];
9059
+ }))].flatMap((key) => {
8848
9060
  const item = batch.itemForKey.get(key);
8849
9061
  return item === void 0 ? [] : [item];
8850
9062
  });
@@ -9341,7 +9553,16 @@ const datePlusDays = (date, days) => {
9341
9553
  //#endregion
9342
9554
  //#region packages/sleep/dist/env.js
9343
9555
  /**
9344
- * Model assignments per LLM phase: the cheap judge for classification, the strong one for synthesis.
9556
+ * Model assignments per LLM phase.
9557
+ *
9558
+ * Every structured phase names `gpt-5.6-sol`, and the reason is one wire property rather
9559
+ * than a model-quality judgment: its strict `json_schema` mode does constrained decoding
9560
+ * on Bedrock today, so an off-schema answer — including the double-encoded-string shape
9561
+ * that skipped 13 batches in one Claude-5 run (issue #53) — cannot be generated at all.
9562
+ * The Claude 5 models reject `strict` and `output_config.format` on every Bedrock surface
9563
+ * (probed live 2026-08-22), so with them the schema is a request the decode enforces
9564
+ * after the fact, and a violated batch is work lost. When Claude 5 structured outputs
9565
+ * land on Bedrock, re-deciding this map is a quality question again; today it is not.
9345
9566
  *
9346
9567
  * `trace-consolidation` names `opus-5` and does not thereby choose it. The consolidator is an eve
9347
9568
  * agent that pins its own model in `apps/consolidator/agent/agent.ts`, and this map cannot reach that
@@ -9350,33 +9571,13 @@ const datePlusDays = (date, days) => {
9350
9571
  * the Bedrock global endpoint, high reasoning effort, no cost ceiling.)
9351
9572
  */
9352
9573
  const DEFAULT_MODELS = {
9353
- /**
9354
- * `dedup-merge` names sonnet for the same reason the edge-typing judge does: the question is a
9355
- * classification over text the model is shown, not a synthesis it has to write. It partitions a
9356
- * component into "these are the same memory" groups, and every consequence of that answer — which
9357
- * file survives, whether the pair diverges, whether either path is already claimed — is decided by
9358
- * code afterwards. The strong model is spent where prose gets written.
9359
- */
9360
- "dedup-merge": "sonnet-5",
9361
- /**
9362
- * Sonnet, and one or two calls a night: the whole of one entity type's name list goes in one call.
9363
- * The question is a partition over short strings with their evidence inline, not a synthesis, so
9364
- * the strong model would buy nothing the deterministic floors around the answer do not already
9365
- * supply.
9366
- */
9367
- "entity-resolution": "sonnet-5",
9368
- "edge-typing": "sonnet-5",
9369
- "arc-synthesis": "opus-5",
9370
- compress: "sonnet-5",
9574
+ "dedup-merge": "gpt-5.6-sol",
9575
+ "entity-resolution": "gpt-5.6-sol",
9576
+ "edge-typing": "gpt-5.6-sol",
9577
+ "arc-synthesis": "gpt-5.6-sol",
9578
+ compress: "gpt-5.6-sol",
9371
9579
  "trace-consolidation": "opus-5",
9372
- /**
9373
- * Sonnet, for the same reason `dedup-merge` and the edge-typing judge name it: the question is an
9374
- * extraction over text the model is shown — which of these memories carries an open commitment,
9375
- * quote the sentence — and every consequence is decided afterwards by code. The sentence has to be
9376
- * VERBATIM, which is copying rather than composing, and the confidence floor plus the verbatim
9377
- * check are what a stronger model would otherwise be buying.
9378
- */
9379
- "task-detection": "sonnet-5"
9580
+ "task-detection": "gpt-5.6-sol"
9380
9581
  };
9381
9582
  /** The model a phase calls: the caller's override, else {@link DEFAULT_MODELS}, else sonnet. */
9382
9583
  const modelFor = (deps, phase) => deps.models?.[phase] ?? DEFAULT_MODELS[phase] ?? "sonnet-5";
@@ -10862,7 +11063,9 @@ const compress = (env) => Effect.gen(function* () {
10862
11063
  batches: batches.length,
10863
11064
  canonicals: 0,
10864
11065
  archived: 0,
10865
- skipped: 0
11066
+ skipped: 0,
11067
+ failed: 0,
11068
+ refused: 0
10866
11069
  };
10867
11070
  if (batches.length === 0) return emptyOutcome(counts);
10868
11071
  if (env.dryRun) return emptyOutcome(counts);
@@ -10870,7 +11073,16 @@ const compress = (env) => Effect.gen(function* () {
10870
11073
  let llmCalls = 0;
10871
11074
  let canonicals = 0;
10872
11075
  let archived = 0;
11076
+ /**
11077
+ * `skipped` stays the total, and `failed` + `refused` partition it. The two are different
11078
+ * diagnoses with different fixes — a failed call is the model or the wire (already logged by
11079
+ * `isolate`), a refusal is an answer the phase declined to act on (logged below) — and a night
11080
+ * reporting only their sum cannot say which one it had. 47 of 47 batches once skipped as
11081
+ * refusals with nothing on stderr, and the sum read as flaky calls.
11082
+ */
10873
11083
  let skipped = 0;
11084
+ let failed = 0;
11085
+ let refused = 0;
10874
11086
  let lastCommit = null;
10875
11087
  for (const batch of batches) {
10876
11088
  /** Opaque keys again, so `absorbedKeys` cannot name a path. */
@@ -10886,12 +11098,15 @@ const compress = (env) => Effect.gen(function* () {
10886
11098
  });
10887
11099
  if (synthesis === void 0) {
10888
11100
  skipped += 1;
11101
+ failed += 1;
10889
11102
  continue;
10890
11103
  }
10891
11104
  /** A key the batch never offered resolves to nothing, so a fold reaches only offered files. */
10892
11105
  const absorbed = resolveKeys(keyed, synthesis.absorbedKeys).map((entry) => entry.row.path);
10893
11106
  if (absorbed.length < 2 || synthesis.title.trim() === "" || synthesis.claim.trim() === "") {
10894
11107
  skipped += 1;
11108
+ refused += 1;
11109
+ yield* Effect.logWarning(`sleep.llm compress batch of ${batch.length} refused: the model absorbed ${absorbed.length} of ${synthesis.absorbedKeys.length} named keys` + (synthesis.absorbedKeys.length > 0 && absorbed.length === 0 ? ` (none of the named keys resolved: ${synthesis.absorbedKeys.slice(0, 3).join(", ")}${synthesis.absorbedKeys.length > 3 ? ", …" : ""})` : ""));
10895
11110
  continue;
10896
11111
  }
10897
11112
  /**
@@ -10904,6 +11119,8 @@ const compress = (env) => Effect.gen(function* () {
10904
11119
  const members = excludeSelfSupersede(canonicalPath, absorbed);
10905
11120
  if (members.length === 0) {
10906
11121
  skipped += 1;
11122
+ refused += 1;
11123
+ yield* Effect.logWarning(`sleep.llm compress batch of ${batch.length} refused: every absorbed member was the canonical itself`);
10907
11124
  continue;
10908
11125
  }
10909
11126
  /**
@@ -10918,6 +11135,8 @@ const compress = (env) => Effect.gen(function* () {
10918
11135
  }
10919
11136
  if (archivedPaths.length === 0) {
10920
11137
  skipped += 1;
11138
+ refused += 1;
11139
+ yield* Effect.logWarning(`sleep.llm compress batch of ${batch.length} refused: every member was already gone from the tree`);
10921
11140
  continue;
10922
11141
  }
10923
11142
  yield* writeFileBytes(env, canonicalPath, renderTemplate({
@@ -10936,7 +11155,9 @@ const compress = (env) => Effect.gen(function* () {
10936
11155
  ...counts,
10937
11156
  canonicals,
10938
11157
  archived,
10939
- skipped
11158
+ skipped,
11159
+ failed,
11160
+ refused
10940
11161
  });
10941
11162
  if (commitSha !== null) lastCommit = commitSha;
10942
11163
  }
@@ -10945,7 +11166,9 @@ const compress = (env) => Effect.gen(function* () {
10945
11166
  ...counts,
10946
11167
  canonicals,
10947
11168
  archived,
10948
- skipped
11169
+ skipped,
11170
+ failed,
11171
+ refused
10949
11172
  },
10950
11173
  commitSha: lastCommit,
10951
11174
  llmCalls
@@ -11856,7 +12079,9 @@ const dedupMerge = (env) => Effect.gen(function* () {
11856
12079
  candidates: oriented.length,
11857
12080
  components: 0,
11858
12081
  llmGroups: 0,
11859
- vetoed: oriented.length - decisions.length
12082
+ vetoed: oriented.length - decisions.length,
12083
+ skipped: 0,
12084
+ unresolved: 0
11860
12085
  },
11861
12086
  /**
11862
12087
  * Every mined pair on this arm cleared 0.92, so a vetoed one here is a near-certain duplicate
@@ -11927,6 +12152,12 @@ const dedupMerge = (env) => Effect.gen(function* () {
11927
12152
  let llmCalls = 0;
11928
12153
  let llmGroups = 0;
11929
12154
  let skipped = 0;
12155
+ /**
12156
+ * Model-named member keys that resolved to no offered member, dropped unacted. The drop is the
12157
+ * safe outcome and stays; the count makes a systematic naming pattern visible instead of reading
12158
+ * as a night in which the model proposed no merges (issue #58).
12159
+ */
12160
+ let unresolved = 0;
11930
12161
  /** Group-implied pairs, in batch then component then group order. */
11931
12162
  const groupPairs = [];
11932
12163
  /** Every path a surviving group claimed, so the mined arm cannot re-propose one. */
@@ -11966,11 +12197,17 @@ const dedupMerge = (env) => Effect.gen(function* () {
11966
12197
  skipped += 1;
11967
12198
  continue;
11968
12199
  }
12200
+ /** This batch's unresolvable keys, so the warning below can name the spellings that failed. */
12201
+ const unresolvedKeys = [];
11969
12202
  for (const group of partition.groups) {
12203
+ const dropped = group.memberKeys.filter((key) => offeredKeyFor(keyed, key) === void 0);
12204
+ unresolved += dropped.length;
12205
+ unresolvedKeys.push(...dropped);
11970
12206
  const members = resolveKeys(keyed, group.memberKeys);
11971
12207
  if (members.length < 2) continue;
11972
12208
  if (new Set(group.memberKeys.flatMap((key) => {
11973
- const id = componentOfKey.get(key);
12209
+ const canonical = offeredKeyFor(keyed, key);
12210
+ const id = canonical === void 0 ? void 0 : componentOfKey.get(canonical);
11974
12211
  return id === void 0 ? [] : [id];
11975
12212
  })).size !== 1) continue;
11976
12213
  /** The keeper is the OLDEST member: the lowest corpus offset, the same rule a pair uses. */
@@ -11996,6 +12233,7 @@ const dedupMerge = (env) => Effect.gen(function* () {
11996
12233
  }
11997
12234
  grouped.add(keeper.path);
11998
12235
  }
12236
+ if (unresolvedKeys.length > 0) yield* Effect.logWarning(`sleep.llm dedup batch of ${batch.length} components dropped ${unresolvedKeys.length} member keys naming no offered member (${unresolvedKeys.slice(0, 3).join(", ")}${unresolvedKeys.length > 3 ? ", …" : ""})`);
11999
12237
  }
12000
12238
  /**
12001
12239
  * Groups first, then the mined pairs above the DETERMINISTIC floor that no group claimed. The
@@ -12015,7 +12253,8 @@ const dedupMerge = (env) => Effect.gen(function* () {
12015
12253
  components: components.length,
12016
12254
  llmGroups,
12017
12255
  vetoed: proposed.length - decisions.length,
12018
- skipped
12256
+ skipped,
12257
+ unresolved
12019
12258
  },
12020
12259
  /**
12021
12260
  * On this arm a vetoed pair is one the MODEL grouped as the same memory, or one that cleared
@@ -12026,11 +12265,13 @@ const dedupMerge = (env) => Effect.gen(function* () {
12026
12265
  *
12027
12266
  * `judged` is false when a batch's call failed, because those components were never partitioned:
12028
12267
  * their pairs reach the veto only through the mined arm, so a night that lost a call cannot say
12029
- * whether a pair it did not see is still a candidate.
12268
+ * whether a pair it did not see is still a candidate. An unresolved member key is the same
12269
+ * hazard from the answer side — a group the phase could not fully map was not fully judged —
12270
+ * so it holds the sweep back the same way.
12030
12271
  */
12031
12272
  {
12032
12273
  vetoed: vetoedPairs(proposed),
12033
- judged: skipped === 0
12274
+ judged: skipped === 0 && unresolved === 0
12034
12275
  }
12035
12276
  ),
12036
12277
  llmCalls
@@ -12455,6 +12696,7 @@ const edgeTyping = (env) => Effect.gen(function* () {
12455
12696
  contradictions: 0,
12456
12697
  promoted: 0,
12457
12698
  skipped: 0,
12699
+ unresolved: 0,
12458
12700
  capped: 0,
12459
12701
  duplicates: 0,
12460
12702
  tasksMinted: 0,
@@ -12521,6 +12763,13 @@ const edgeTyping = (env) => Effect.gen(function* () {
12521
12763
  let capped = 0;
12522
12764
  /** Second-and-later verdicts naming a key their batch had already answered for. */
12523
12765
  let duplicates = 0;
12766
+ /**
12767
+ * Verdicts whose key resolved to no offered pair, so they were dropped unacted. Dropping is the
12768
+ * safe outcome and stays; the count is what makes a SYSTEMATIC pattern visible — a model naming
12769
+ * keys in a spelling the resolver refuses drops every verdict of every batch, and a night that
12770
+ * judged nothing looked identical to a night whose model answered nothing (issue #58).
12771
+ */
12772
+ let unresolved = 0;
12524
12773
  let llmCalls = 0;
12525
12774
  /**
12526
12775
  * Contradictions this night detected for the FIRST time, so below the promotion gate.
@@ -12561,18 +12810,27 @@ const edgeTyping = (env) => Effect.gen(function* () {
12561
12810
  * rather than silently swallowed, so a model doing this is visible in a night's report.
12562
12811
  */
12563
12812
  const answered = /* @__PURE__ */ new Set();
12813
+ /** This batch's dropped verdicts, so the warning below can name the spellings that failed. */
12814
+ const unresolvedKeys = [];
12564
12815
  for (const verdict of answer.verdicts) {
12565
12816
  /**
12566
12817
  * The key is resolved through the kernel, so an invented key yields no candidate and no
12567
- * write.
12818
+ * write. The CANONICAL key feeds the repeat guard, so `m1` and its label-prefixed spelling
12819
+ * `pair_m1` in one answer are one pair answered twice, not two pairs.
12568
12820
  */
12569
- const [candidate] = resolveKeys(keyed, [verdict.pairKey]);
12821
+ const pairKey = offeredKeyFor(keyed, verdict.pairKey);
12822
+ if (pairKey === void 0) {
12823
+ unresolved += 1;
12824
+ unresolvedKeys.push(verdict.pairKey);
12825
+ continue;
12826
+ }
12827
+ const [candidate] = resolveKeys(keyed, [pairKey]);
12570
12828
  if (candidate === void 0) continue;
12571
- if (answered.has(verdict.pairKey)) {
12829
+ if (answered.has(pairKey)) {
12572
12830
  duplicates += 1;
12573
12831
  continue;
12574
12832
  }
12575
- answered.add(verdict.pairKey);
12833
+ answered.add(pairKey);
12576
12834
  judged += 1;
12577
12835
  if (!assertsEdge(verdict)) continue;
12578
12836
  if (assertsContradiction(verdict)) {
@@ -12675,14 +12933,18 @@ const edgeTyping = (env) => Effect.gen(function* () {
12675
12933
  const [subject, object] = verdict.direction === "src_to_dst" ? [candidate.pair.src, candidate.pair.dst] : [candidate.pair.dst, candidate.pair.src];
12676
12934
  if (yield* stampFile(env, subject, [link(verdict.rel, hrefFor(object)), meta("memhtml-updated", env.at)])) typed += 1;
12677
12935
  }
12936
+ if (unresolvedKeys.length > 0) yield* Effect.logWarning(`sleep.llm edge-typing batch of ${batch.length} dropped ${unresolvedKeys.length} verdicts naming no offered pair (${unresolvedKeys.slice(0, 3).join(", ")}${unresolvedKeys.length > 3 ? ", …" : ""})`);
12678
12937
  }
12679
12938
  /**
12680
12939
  * The single-detection contradictions become tasks in the SAME commit as the promotions. The
12681
12940
  * sweep is gated on a night that judged its whole candidate set: `skipped` counts pairs whose
12682
12941
  * batch's call failed as well as pairs whose endpoint the tree no longer holds, and a pair the
12683
12942
  * model was never asked about must not read as a pair the model stopped contradicting.
12943
+ * `unresolved` is the same hazard from the answer side — a verdict the phase could not map to a
12944
+ * pair is a pair that was never judged, so its held-back contradiction must not close as "no
12945
+ * longer detected" over a misspelled key.
12684
12946
  */
12685
- const tasks = yield* mintContradictionTasks(env, deferred, skipped === 0);
12947
+ const tasks = yield* mintContradictionTasks(env, deferred, skipped === 0 && unresolved === 0);
12686
12948
  const counts = {
12687
12949
  candidates: candidates.length,
12688
12950
  judged,
@@ -12690,6 +12952,7 @@ const edgeTyping = (env) => Effect.gen(function* () {
12690
12952
  contradictions,
12691
12953
  promoted,
12692
12954
  skipped,
12955
+ unresolved,
12693
12956
  capped,
12694
12957
  duplicates,
12695
12958
  tasksMinted: tasks.minted,
@@ -13206,6 +13469,12 @@ const entityResolution = (env) => Effect.gen(function* () {
13206
13469
  /** Model calls that came back malformed. The sweep's precondition reads this; see below. */
13207
13470
  let callsFailed = 0;
13208
13471
  /**
13472
+ * Cluster member keys (or canonical keys) resolving to no offered member, dropped unacted. The
13473
+ * drop is the safe outcome and stays; the count makes a systematic naming pattern visible
13474
+ * instead of reading as a night in which the model proposed no merges (issue #58).
13475
+ */
13476
+ let unresolved = 0;
13477
+ /**
13209
13478
  * Every pair this night deferred to a human, as a value rather than only a count.
13210
13479
  *
13211
13480
  * This is issue #44's motivating case in one variable. The phase used to report
@@ -13317,6 +13586,8 @@ const entityResolution = (env) => Effect.gen(function* () {
13317
13586
  callsFailed += 1;
13318
13587
  continue;
13319
13588
  }
13589
+ /** This shard's unresolvable keys, so the warning below names the spellings that failed. */
13590
+ const unresolvedKeys = [];
13320
13591
  for (const cluster of clustering.clusters) {
13321
13592
  /**
13322
13593
  * A key the batch never offered resolves to nothing, so an invented member cannot become a
@@ -13324,6 +13595,9 @@ const entityResolution = (env) => Effect.gen(function* () {
13324
13595
  * canonical is outside it contradicts itself, and guessing which half was meant would be
13325
13596
  * the caller inventing a merge.
13326
13597
  */
13598
+ const droppedKeys = [...cluster.memberKeys, cluster.canonicalKey].filter((key) => offeredKeyFor(keyed, key) === void 0);
13599
+ unresolved += droppedKeys.length;
13600
+ unresolvedKeys.push(...droppedKeys);
13327
13601
  const memberNames = resolveKeys(keyed, cluster.memberKeys).map((centroid) => centroid.name);
13328
13602
  const [canonicalMember] = resolveKeys(keyed, [cluster.canonicalKey]);
13329
13603
  if (canonicalMember === void 0 || !memberNames.includes(canonicalMember.name)) continue;
@@ -13382,6 +13656,7 @@ const entityResolution = (env) => Effect.gen(function* () {
13382
13656
  });
13383
13657
  }
13384
13658
  }
13659
+ if (unresolvedKeys.length > 0) yield* Effect.logWarning(`sleep.llm entity-resolution ${entityType} batch of ${shard.length} dropped ${unresolvedKeys.length} cluster keys naming no offered member (${unresolvedKeys.slice(0, 3).join(", ")}${unresolvedKeys.length > 3 ? ", …" : ""})`);
13385
13660
  }
13386
13661
  }
13387
13662
  /**
@@ -13419,6 +13694,8 @@ const entityResolution = (env) => Effect.gen(function* () {
13419
13694
  aliasMerges,
13420
13695
  pendingCorroboration,
13421
13696
  reviewCandidates,
13697
+ callsFailed,
13698
+ unresolved,
13422
13699
  tasksMinted: 0,
13423
13700
  tasksFramed: 0,
13424
13701
  tasksDismissed: 0,
@@ -13444,7 +13721,12 @@ const entityResolution = (env) => Effect.gen(function* () {
13444
13721
  * 1. The old early return on `rewrites.size === 0` would have skipped exactly the night this
13445
13722
  * feature exists for: a night whose only outcome was deferrals is a night with no rewrites.
13446
13723
  */
13447
- const tasks = yield* mintReviewTasks(env, deferred, model !== void 0 && callsFailed === 0);
13724
+ /**
13725
+ * `unresolved === 0` joins the sweep gate for the reason `callsFailed === 0` is already in it: a
13726
+ * cluster key the phase could not map to a member is a name that was never judged, and sweeping
13727
+ * against a night that lost part of an answer closes reviews over a misspelling.
13728
+ */
13729
+ const tasks = yield* mintReviewTasks(env, deferred, model !== void 0 && callsFailed === 0 && unresolved === 0);
13448
13730
  let rewritten = 0;
13449
13731
  for (const [path, pairs] of [...rewrites.entries()].sort(([left], [right]) => left < right ? -1 : 1)) {
13450
13732
  const html = yield* readFileBytes(env, path);
@@ -14441,6 +14723,12 @@ const taskDetection = (env) => Effect.gen(function* () {
14441
14723
  let dismissed = 0;
14442
14724
  let skipped = 0;
14443
14725
  /**
14726
+ * Findings whose key resolved to no offered member, dropped unacted. The drop is the safe
14727
+ * outcome and stays; the count makes a systematic pattern visible, because a night whose every
14728
+ * finding named an unresolvable key otherwise reads as a night with no open work (issue #58).
14729
+ */
14730
+ let unresolved = 0;
14731
+ /**
14444
14732
  * Every key this night's scan SAW, whether or not it minted and whether or not it cleared the floor.
14445
14733
  * The sweep's input; see the `liveKeys.add` below for why the floor is not a filter here.
14446
14734
  */
@@ -14468,11 +14756,20 @@ const taskDetection = (env) => Effect.gen(function* () {
14468
14756
  * because it is called one key at a time here — a finding names one member.
14469
14757
  */
14470
14758
  const answered = /* @__PURE__ */ new Set();
14759
+ /** This batch's dropped findings, so the warning below can name the spellings that failed. */
14760
+ const unresolvedKeys = [];
14471
14761
  for (const finding of answer.findings) {
14472
- const [row] = resolveKeys(keyed, [finding.memberKey]);
14762
+ /** The CANONICAL key feeds the repeat guard, same as edge-typing's, and for the same reason. */
14763
+ const memberKey = offeredKeyFor(keyed, finding.memberKey);
14764
+ if (memberKey === void 0) {
14765
+ unresolved += 1;
14766
+ unresolvedKeys.push(finding.memberKey);
14767
+ continue;
14768
+ }
14769
+ const [row] = resolveKeys(keyed, [memberKey]);
14473
14770
  if (row === void 0) continue;
14474
- if (answered.has(finding.memberKey)) continue;
14475
- answered.add(finding.memberKey);
14771
+ if (answered.has(memberKey)) continue;
14772
+ answered.add(memberKey);
14476
14773
  findings += 1;
14477
14774
  /**
14478
14775
  * The key is the SOURCE PATH plus the normalized sentence, so the same commitment found again
@@ -14518,13 +14815,17 @@ const taskDetection = (env) => Effect.gen(function* () {
14518
14815
  else if (outcome === "framed") framed += 1;
14519
14816
  else if (outcome === "dismissed") dismissed += 1;
14520
14817
  }
14818
+ if (unresolvedKeys.length > 0) yield* Effect.logWarning(`sleep.llm task-detection batch of ${batch.length} dropped ${unresolvedKeys.length} findings naming no offered member (${unresolvedKeys.slice(0, 3).join(", ")}${unresolvedKeys.length > 3 ? ", …" : ""})`);
14521
14819
  }
14522
14820
  /**
14523
14821
  * The sweep, only from a full-strength scan. `skipped > 0` means at least one batch's memories
14524
14822
  * went unread, so a finding of theirs is missing from `liveKeys` because the phase could not look
14525
- * rather than because it is gone.
14823
+ * rather than because it is gone. `unresolved > 0` is the same hazard from the answer side: the
14824
+ * model reported a finding the phase could not map to a member, so its detection key was never
14825
+ * constructed, and sweeping against that would close a live task because the model misspelled a
14826
+ * key rather than because the finding vanished.
14526
14827
  */
14527
- const closed = skipped === 0 ? yield* closeVanishedDetections(env, TASK_DETECT_DETECTOR, liveKeys) : 0;
14828
+ const closed = skipped === 0 && unresolved === 0 ? yield* closeVanishedDetections(env, TASK_DETECT_DETECTOR, liveKeys) : 0;
14528
14829
  const counts = {
14529
14830
  candidates: candidates.length,
14530
14831
  batches: batches.length,
@@ -14536,7 +14837,8 @@ const taskDetection = (env) => Effect.gen(function* () {
14536
14837
  dismissed,
14537
14838
  closed,
14538
14839
  capped: budget.overflow,
14539
- skipped
14840
+ skipped,
14841
+ unresolved
14540
14842
  };
14541
14843
  /**
14542
14844
  * A refresh writes a `memhtml-updated` stamp, which is a staged file, so it commits — the queue's
@@ -14572,7 +14874,8 @@ const ZERO = {
14572
14874
  dismissed: 0,
14573
14875
  closed: 0,
14574
14876
  capped: 0,
14575
- skipped: 0
14877
+ skipped: 0,
14878
+ unresolved: 0
14576
14879
  };
14577
14880
 
14578
14881
  //#endregion
@@ -16685,4 +16988,4 @@ const latest = (left, right) => left === null ? right : right === null ? left :
16685
16988
 
16686
16989
  //#endregion
16687
16990
  export { STATE_DB_PATH as $, IndexRecorder as A, IndexGit as B, ModelClient as C, EmbeddingsLive as D, Embeddings as E, makeRetrieval as F, MIGRATIONS_DIR as G, sanitizeFtsQuery as H, reinforce as I, Store as J, STATE_MIGRATIONS_DIR as K, Indexer as L, persistScanned as M, readWatermark as N, EMBED_DIM as O, Retrieval as P, SLEEP_REPORTS_DIR as Q, makeIndexer as R, runDiscrimination as S, wrapAsData as T, DatabaseService as U, makeGitPort as V, makeDatabase as W, makeStore as X, expandRoot as Y, INDEX_DB_PATH as Z, meta as _, parseSidecar as a, makeGit as at, isSleepPhase as b, generateArtifacts as c, setMeta as ct, allPaths as d, fenceOpeningOf as dt, STATE_SIDECAR_PATH as et, danglingEdges as f, REINFORCE_SIGNALS as ft, link as g, hrefFor as h, makeSleep as i, Git as it, makeIndexRecorder as j, EMBED_WATERMARK as k, DETECTION_PREFIX as l, isValidDatetime as lt, applyHeadEdits as m, scanTraceRoot as n, initRepo as nt, renderSidecar as o, commitSubject as ot, publishRows as p, frameKeyOf as pt, STATE_SCHEMA as q, Sleep as r, readFileOrNull as rt, archivedFormOf as s, checkMemory as st, mergeTailExtract as t, attemptIo as tt, accessRows as u, closesFence as ut, unlink as v, ModelClientLive as w, discriminationGate as x, SLEEP_PHASES as y, readIndexState as z };
16688
- //# sourceMappingURL=dist-D73gfqLc.mjs.map
16991
+ //# sourceMappingURL=dist-DgKlozi6.mjs.map