@graphrefly/graphrefly 0.47.0 → 0.47.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.
Files changed (66) hide show
  1. package/dist/{chunk-CGHORL6G.js → chunk-7ADWWI2T.js} +2 -2
  2. package/dist/{chunk-TNX5ZGDJ.js → chunk-B4AKFXGE.js} +4 -4
  3. package/dist/{chunk-FW23JYNQ.js → chunk-CEVNQ74M.js} +2 -2
  4. package/dist/{chunk-JGFRAFDL.js → chunk-FVINAAKA.js} +3 -3
  5. package/dist/{chunk-22SG74BD.js → chunk-J5WFUEO4.js} +2 -2
  6. package/dist/{chunk-GWRNLJNW.js → chunk-K7PDZYQE.js} +4 -4
  7. package/dist/{chunk-Z6EGP5D7.js → chunk-LDCSZ72P.js} +2 -2
  8. package/dist/{chunk-EHRRQ4IC.js → chunk-MTTRCEJT.js} +2 -2
  9. package/dist/{chunk-Q3EYOCZB.js → chunk-NPRP3MCV.js} +111 -2
  10. package/dist/chunk-NPRP3MCV.js.map +1 -0
  11. package/dist/{chunk-JKTC747G.js → chunk-RGMTUZCL.js} +3 -3
  12. package/dist/{chunk-ZVXXDWIB.js → chunk-U225SKB4.js} +455 -25
  13. package/dist/chunk-U225SKB4.js.map +1 -0
  14. package/dist/{chunk-ZT4WMQW4.js → chunk-V4Y3TM7U.js} +5 -5
  15. package/dist/{chunk-5IMMNARC.js → chunk-YXCPV26R.js} +2 -2
  16. package/dist/index.cjs +1374 -840
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +2 -2
  19. package/dist/index.d.ts +2 -2
  20. package/dist/index.js +35 -13
  21. package/dist/index.js.map +1 -1
  22. package/dist/presets/ai/index.cjs.map +1 -1
  23. package/dist/presets/ai/index.js +6 -6
  24. package/dist/presets/harness/index.cjs.map +1 -1
  25. package/dist/presets/harness/index.js +9 -9
  26. package/dist/presets/index.cjs.map +1 -1
  27. package/dist/presets/index.js +13 -13
  28. package/dist/presets/inspect/index.cjs.map +1 -1
  29. package/dist/presets/inspect/index.js +4 -4
  30. package/dist/solutions/index.cjs.map +1 -1
  31. package/dist/solutions/index.js +10 -10
  32. package/dist/utils/ai/index.cjs.map +1 -1
  33. package/dist/utils/ai/index.js +5 -5
  34. package/dist/utils/index.cjs +931 -397
  35. package/dist/utils/index.cjs.map +1 -1
  36. package/dist/utils/index.d.cts +2 -2
  37. package/dist/utils/index.d.ts +2 -2
  38. package/dist/utils/index.js +28 -6
  39. package/dist/utils/inspect/index.cjs.map +1 -1
  40. package/dist/utils/inspect/index.js +2 -2
  41. package/dist/utils/memory/index.cjs +462 -37
  42. package/dist/utils/memory/index.cjs.map +1 -1
  43. package/dist/utils/memory/index.d.cts +591 -2
  44. package/dist/utils/memory/index.d.ts +591 -2
  45. package/dist/utils/memory/index.js +19 -1
  46. package/dist/utils/messaging/index.cjs +109 -0
  47. package/dist/utils/messaging/index.cjs.map +1 -1
  48. package/dist/utils/messaging/index.d.cts +115 -2
  49. package/dist/utils/messaging/index.d.ts +115 -2
  50. package/dist/utils/messaging/index.js +5 -1
  51. package/dist/utils/orchestration/index.cjs.map +1 -1
  52. package/dist/utils/orchestration/index.js +2 -2
  53. package/package.json +1 -1
  54. package/dist/chunk-Q3EYOCZB.js.map +0 -1
  55. package/dist/chunk-ZVXXDWIB.js.map +0 -1
  56. /package/dist/{chunk-CGHORL6G.js.map → chunk-7ADWWI2T.js.map} +0 -0
  57. /package/dist/{chunk-TNX5ZGDJ.js.map → chunk-B4AKFXGE.js.map} +0 -0
  58. /package/dist/{chunk-FW23JYNQ.js.map → chunk-CEVNQ74M.js.map} +0 -0
  59. /package/dist/{chunk-JGFRAFDL.js.map → chunk-FVINAAKA.js.map} +0 -0
  60. /package/dist/{chunk-22SG74BD.js.map → chunk-J5WFUEO4.js.map} +0 -0
  61. /package/dist/{chunk-GWRNLJNW.js.map → chunk-K7PDZYQE.js.map} +0 -0
  62. /package/dist/{chunk-Z6EGP5D7.js.map → chunk-LDCSZ72P.js.map} +0 -0
  63. /package/dist/{chunk-EHRRQ4IC.js.map → chunk-MTTRCEJT.js.map} +0 -0
  64. /package/dist/{chunk-JKTC747G.js.map → chunk-RGMTUZCL.js.map} +0 -0
  65. /package/dist/{chunk-ZT4WMQW4.js.map → chunk-V4Y3TM7U.js.map} +0 -0
  66. /package/dist/{chunk-5IMMNARC.js.map → chunk-YXCPV26R.js.map} +0 -0
@@ -4,8 +4,8 @@ import {
4
4
  humanInput,
5
5
  pipelineGraph,
6
6
  tracker
7
- } from "../../chunk-CGHORL6G.js";
8
- import "../../chunk-Q3EYOCZB.js";
7
+ } from "../../chunk-7ADWWI2T.js";
8
+ import "../../chunk-NPRP3MCV.js";
9
9
  import "../../chunk-FMPF42Q4.js";
10
10
  import "../../chunk-BXGZFGZ4.js";
11
11
  import "../../chunk-AZDQPQ3V.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphrefly/graphrefly",
3
- "version": "0.47.0",
3
+ "version": "0.47.1",
4
4
  "description": "Reactive harness layer for agent workflows. Describe automations in plain language, trace every decision, enforce policies, persist checkpoints. Zero dependencies.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/messaging/audit-records.ts","../src/utils/messaging/message.ts","../src/utils/messaging/index.ts"],"sourcesContent":["/**\n * Messaging audit-record schemas (DS-13.5.E, locked 2026-05-01 alt A).\n *\n * Per-site discriminated-union audit records for the four messaging mutation\n * sites that route through `mutate`:\n *\n * - {@link TopicPublishRecord} — `Topic.publish`\n * - {@link SubscriptionAckRecord} — `Subscription.ack`\n * - {@link SubscriptionPullAndAckRecord} — `Subscription.pullAndAck`\n * - {@link HubRemoveTopicRecord} — `Hub.removeTopic`\n *\n * **Opt-in usage.** None of the four mutation sites enable an audit log by\n * default — caller wires audit visibility by composing `mutate` with\n * an audit `ReactiveLogBundle<R>` of the matching record type and an\n * `onSuccess`/`onFailure` builder:\n *\n * ```ts\n * import { createAuditLog, mutate } from \"@graphrefly/graphrefly/extra\";\n * import {\n * type TopicPublishRecord,\n * topicPublishKeyOf,\n * } from \"@graphrefly/graphrefly/patterns/messaging\";\n *\n * const audit = createAuditLog<TopicPublishRecord>({ name: \"publishes\" });\n * const publish = mutate(\n * (item: MyMessage) => topic.publish(item),\n * {\n * frame: \"inline\",\n * log: audit,\n * onSuccessRecord: ([item], _r, m) => ({\n * t_ns: m.t_ns,\n * seq: m.seq,\n * kind: \"topic.publish\",\n * topicName: topic.name,\n * itemKey: keyOf(item),\n * }),\n * },\n * );\n * ```\n *\n * **Stability.** The `kind` discriminator strings are pre-1.0 stable;\n * renaming downstream breaks external auditors.\n *\n * **Composability.** All four records extend {@link BaseAuditRecord} so they\n * carry the cross-cutting `t_ns` / `seq?` / `handlerVersion?` fields stamped\n * by `mutate` (Audit 2 / Audit 5).\n *\n * **Per-record keyOf.** Each record exports a recommended `keyOf` for\n * keyed-storage adapters (Rule G.27-keyOf-recommended) — partition the audit\n * log by the most natural identity (`topicName::itemKey`,\n * `subscriptionId::cursor`, etc.).\n *\n * **Hub.addTopic deferred.** No `HubAddTopicRecord` ships now; the lazy\n * topic-creation site has no caller signal asking for an audit record.\n * Re-add when a consumer surfaces.\n *\n * @category patterns\n * @module patterns/messaging/audit-records\n */\n\nimport type { BaseAuditRecord } from \"../../base/mutation/index.js\";\n\n// ── Topic.publish ────────────────────────────────────────────────────────\n\n/**\n * Audit record for a single {@link TopicGraph.publish} call.\n *\n * - `topicName` — the topic the publish targeted.\n * - `itemKey` — caller-supplied identity for the published item (typically\n * the result of the topic's own `keyOf` derivation, when one exists).\n */\nexport interface TopicPublishRecord extends BaseAuditRecord {\n\treadonly kind: \"topic.publish\";\n\treadonly topicName: string;\n\treadonly itemKey: string;\n}\n\n/**\n * Recommended `keyOf` for {@link TopicPublishRecord} — formats as\n * `${topicName}::${itemKey}` for keyed-storage partitioning. Caller may\n * override per Rule G.27-keyOf-recommended.\n */\nexport const topicPublishKeyOf = (r: TopicPublishRecord): string => `${r.topicName}::${r.itemKey}`;\n\n// ── Subscription.ack ─────────────────────────────────────────────────────\n\n/**\n * Audit record for a single {@link SubscriptionGraph.ack} call.\n *\n * - `subscriptionId` — the subscription the ack advanced.\n * - `cursor` — the post-ack cursor position.\n */\nexport interface SubscriptionAckRecord extends BaseAuditRecord {\n\treadonly kind: \"subscription.ack\";\n\treadonly subscriptionId: string;\n\treadonly cursor: number;\n}\n\n/**\n * Recommended `keyOf` for {@link SubscriptionAckRecord} — formats as\n * `${subscriptionId}::${cursor}`.\n */\nexport const subscriptionAckKeyOf = (r: SubscriptionAckRecord): string =>\n\t`${r.subscriptionId}::${r.cursor}`;\n\n// ── Subscription.pullAndAck ──────────────────────────────────────────────\n\n/**\n * Audit record for a single {@link SubscriptionGraph.pullAndAck} call.\n *\n * - `subscriptionId` — the subscription the pullAndAck advanced.\n * - `cursor` — the post-pullAndAck cursor position.\n * - `itemCount` — number of items returned to the caller in this call.\n */\nexport interface SubscriptionPullAndAckRecord extends BaseAuditRecord {\n\treadonly kind: \"subscription.pullAndAck\";\n\treadonly subscriptionId: string;\n\treadonly cursor: number;\n\treadonly itemCount: number;\n}\n\n/**\n * Recommended `keyOf` for {@link SubscriptionPullAndAckRecord} — formats as\n * `${subscriptionId}::${cursor}` (identical shape to ack records so the\n * combined audit-log partitioning matches a per-cursor-frame view).\n */\nexport const subscriptionPullAndAckKeyOf = (r: SubscriptionPullAndAckRecord): string =>\n\t`${r.subscriptionId}::${r.cursor}`;\n\n// ── Hub.removeTopic ──────────────────────────────────────────────────────\n\n/**\n * Audit record for a single {@link MessagingHubGraph.removeTopic} call.\n *\n * - `topicName` — the topic that was unmounted from the hub.\n */\nexport interface HubRemoveTopicRecord extends BaseAuditRecord {\n\treadonly kind: \"hub.removeTopic\";\n\treadonly topicName: string;\n}\n\n/**\n * Recommended `keyOf` for {@link HubRemoveTopicRecord} — the topic name itself\n * is already the natural identity.\n */\nexport const hubRemoveTopicKeyOf = (r: HubRemoveTopicRecord): string => r.topicName;\n\n// ── Discriminated-union convenience ──────────────────────────────────────\n\n/**\n * Discriminated union over every messaging audit record. Useful for callers\n * that aggregate records from multiple sites into one log; switch on\n * `record.kind` to narrow.\n */\nexport type MessagingAuditRecord =\n\t| TopicPublishRecord\n\t| SubscriptionAckRecord\n\t| SubscriptionPullAndAckRecord\n\t| HubRemoveTopicRecord;\n","/**\n * Standard `TopicMessage<T>` envelope for hub topics + well-known topic name\n * constants (Phase 13.B; spec source: archive/docs/SESSION-human-llm-intervention-primitives.md\n * §6 + archive/docs/SESSION-multi-agent-gap-analysis.md §6 cross-cut).\n *\n * `TopicMessage<T>` is the **recommended** wrapper for cross-agent / cross-graph\n * topic payloads — it carries identity, schema, deadline, and correlation\n * metadata alongside the typed `payload`. It is NOT a required protocol\n * type; raw `topic<T>` continues to work for in-process payloads where the\n * envelope fields would be noise.\n *\n * Use the envelope when:\n * - Two or more graphs (or human + LLM consumers) communicate over a topic\n * and need a stable wire shape — `correlationId` is the join key, `schema`\n * gates payload validation, `expiresAt` enables TTL enforcement.\n * - A topic carries multiple payload kinds and consumers need to discriminate\n * without parsing structurally.\n *\n * The standard well-known topic constants below are **conventions** — string\n * literals callers can pass to `messagingHub().topic(NAME)` to get a\n * predictable lookup. The hub does not enforce any topic to actually exist;\n * topics are still lazy on first access.\n */\n\n// ---------------------------------------------------------------------------\n// JSON Schema — minimal local type\n// ---------------------------------------------------------------------------\n\n/**\n * Minimal JSON Schema shape, scoped to what `TopicMessage<T>` validates against.\n * Locked DS-13.B (2026-04-30): zero-dep posture, structural shape only — no\n * full validator shipped. Callers that want full validation supply their own\n * (e.g. `ajv`, `zod`, `valibot`) and read `Message.schema` as the rule\n * source. The shape covers the JSON-Schema-7 subset that hub-topic payload\n * descriptions actually need:\n * - `type` / `properties` / `required` / `additionalProperties` for objects.\n * - `items` for arrays.\n * - `enum` / `const` for value constraints.\n * - `$ref` / `definitions` for shared sub-schemas.\n *\n * If a concrete consumer needs a richer shape (oneOf, allOf, format, etc.),\n * extend this type — it's a structural contract, not a tagged union, so\n * additive fields don't break existing producers.\n */\nexport interface JsonSchema {\n\treadonly type?:\n\t\t| \"string\"\n\t\t| \"number\"\n\t\t| \"integer\"\n\t\t| \"boolean\"\n\t\t| \"object\"\n\t\t| \"array\"\n\t\t| \"null\"\n\t\t| readonly (\"string\" | \"number\" | \"integer\" | \"boolean\" | \"object\" | \"array\" | \"null\")[];\n\treadonly properties?: Readonly<Record<string, JsonSchema>>;\n\treadonly required?: readonly string[];\n\treadonly additionalProperties?: boolean | JsonSchema;\n\treadonly items?: JsonSchema | readonly JsonSchema[];\n\treadonly enum?: readonly unknown[];\n\treadonly const?: unknown;\n\treadonly $ref?: string;\n\treadonly definitions?: Readonly<Record<string, JsonSchema>>;\n\treadonly description?: string;\n\treadonly title?: string;\n}\n\n// ---------------------------------------------------------------------------\n// TopicMessage<T> envelope\n// ---------------------------------------------------------------------------\n\n/**\n * Recommended envelope for hub topic payloads. Carries identity, optional\n * schema reference, optional expiry, optional correlation, and the typed\n * payload itself.\n *\n * - `id` — globally-unique identifier for this message instance. Producers\n * mint it (UUID, ULID, hash, etc.); consumers use it for deduplication and\n * trace correlation. **Required.**\n * - `schema` — optional structural description of `payload`. Validators\n * (caller-supplied) read this to gate or shape consumption. Writers MAY\n * include the schema inline for self-describing topics, or omit when the\n * payload type is statically known to all consumers.\n * - `expiresAt` — ISO 8601 timestamp; consumers SHOULD drop / fallback past\n * this point. Substrate enforcement is via composition (`timeout(source,\n * ms)` + `fallback`), not a hub-level rule.\n * - `correlationId` — links related messages across topics (request /\n * response pairs, conversation threads, multi-agent handoffs). Producers\n * propagate it; consumers filter / group on it.\n * - `payload` — the typed body. Type parameter `T` is the consumer-agreed\n * shape; the envelope adds metadata around it without coupling consumers\n * to a concrete payload type.\n *\n * Reactive composition with the envelope:\n *\n * ```ts\n * const requests = hub.topic<TopicMessage<RequestBody>>(PROMPTS_TOPIC);\n * const responses = hub.topic<TopicMessage<ResponseBody>>(RESPONSES_TOPIC);\n *\n * // Filter responses to one correlation\n * const myResponse = derived([responses.latest], ([msg]) =>\n * msg?.correlationId === requestId ? [msg.payload] : [],\n * );\n * ```\n */\nexport interface TopicMessage<T> {\n\treadonly id: string;\n\treadonly schema?: JsonSchema;\n\treadonly expiresAt?: string;\n\treadonly correlationId?: string;\n\treadonly payload: T;\n}\n\n// ---------------------------------------------------------------------------\n// Standard topic name constants\n// ---------------------------------------------------------------------------\n\n/**\n * Well-known topic name for human / LLM prompts directed at the harness.\n * Example payload: `TopicMessage<{ prompt: string; context?: object }>`.\n *\n * Co-locked with {@link RESPONSES_TOPIC} per the human-LLM intervention\n * session §6 #4 (paired request / response convention).\n */\nexport const PROMPTS_TOPIC = \"prompts\";\n\n/**\n * Well-known topic name for responses to {@link PROMPTS_TOPIC} entries.\n * Producers pair the response to its prompt via `correlationId`. Example\n * payload: `TopicMessage<{ content: string; finishReason?: string }>`.\n */\nexport const RESPONSES_TOPIC = \"responses\";\n\n/**\n * Well-known topic name for out-of-band injections — runtime overrides /\n * hot-fixes / human nudges that bypass the normal request flow. Example\n * payload: `TopicMessage<{ kind: \"context-patch\" | \"policy-override\" | ...;\n * data: unknown }>`. Per-injection consumers decide how (and whether) to\n * apply.\n */\nexport const INJECTIONS_TOPIC = \"injections\";\n\n/**\n * Well-known topic name for items the harness deferred for later attention\n * (parked queue, follow-up tracker, \"I'll get back to this\"). Producer is\n * usually the harness itself; consumer is a tracker / dashboard / human.\n * Example payload: `TopicMessage<{ reason: string; original: unknown }>`.\n */\nexport const DEFERRED_TOPIC = \"deferred\";\n\n/**\n * Well-known topic name for spawn requests (Phase 13.I `spawnable()`\n * surface). Producer emits a `TopicMessage<SpawnRequest>` to request a child\n * agent / subgraph; consumer is the materializer that mints the slot.\n * Example payload: `TopicMessage<{ presetId: string; taskInput: unknown;\n * depth?: number }>`. `correlationId` links the spawn to its parent\n * conversation; `expiresAt` enforces TTL on long-lived requests.\n */\nexport const SPAWNS_TOPIC = \"spawns\";\n\n/**\n * DS-14.6.A D-B3 — well-known topic for the dynamic `actorPool()` shared\n * tagged-context pool. Actors publish `ContextEntry` here; per-actor views\n * render their own compressed slice.\n */\nexport const CONTEXT_TOPIC = \"context\";\n\n/**\n * DS-14.6.A D-B3 — well-known topic for the `actorPool()` shared todo list.\n * Any actor may `enqueueTodo`; actors pull assigned todos via their cursor.\n */\nexport const TODOS_TOPIC = \"todos\";\n\n/**\n * Tuple of all well-known topic constants — useful for \"register all\n * standard topics on a hub\" patterns and for compile-time exhaustiveness\n * checks.\n */\nexport const STANDARD_TOPICS = [\n\tPROMPTS_TOPIC,\n\tRESPONSES_TOPIC,\n\tINJECTIONS_TOPIC,\n\tDEFERRED_TOPIC,\n\tSPAWNS_TOPIC,\n\tCONTEXT_TOPIC,\n\tTODOS_TOPIC,\n] as const;\n\n/**\n * Union of all well-known topic name string literals.\n */\nexport type StandardTopic = (typeof STANDARD_TOPICS)[number];\n","/**\n * Messaging patterns (roadmap §4.2).\n *\n * Pulsar-inspired messaging primitives modeled as graph factories:\n * - `topic()` for append-only topic streams with a retained window.\n * - `subscription()` for cursor-based consumers.\n * - `topicBridge()` for autonomous topic-to-topic relay.\n * - `messagingHub()` for a lazy topic registry.\n *\n * Plus the Phase 13.B standard `Message<T>` envelope and well-known topic\n * name constants ({@link PROMPTS_TOPIC} / {@link RESPONSES_TOPIC} /\n * {@link INJECTIONS_TOPIC} / {@link DEFERRED_TOPIC} / {@link SPAWNS_TOPIC})\n * — recommended (not enforced) wire shape for cross-graph topic payloads.\n *\n * Job queue / job flow primitives live in `patterns/job-queue` — they are a\n * distinct domain that happens to share reactive-log / reactive-map\n * infrastructure with topics.\n */\n\nexport {\n\ttype HubRemoveTopicRecord,\n\thubRemoveTopicKeyOf,\n\ttype MessagingAuditRecord,\n\ttype SubscriptionAckRecord,\n\ttype SubscriptionPullAndAckRecord,\n\tsubscriptionAckKeyOf,\n\tsubscriptionPullAndAckKeyOf,\n\ttype TopicPublishRecord,\n\ttopicPublishKeyOf,\n} from \"./audit-records.js\";\nexport {\n\tCONTEXT_TOPIC,\n\tDEFERRED_TOPIC,\n\tINJECTIONS_TOPIC,\n\ttype JsonSchema,\n\tPROMPTS_TOPIC,\n\tRESPONSES_TOPIC,\n\tSPAWNS_TOPIC,\n\tSTANDARD_TOPICS,\n\ttype StandardTopic,\n\tTODOS_TOPIC,\n\ttype TopicMessage,\n} from \"./message.js\";\n\nimport { batch, COMPLETE, DATA, type Node, node } from \"@graphrefly/pure-ts/core\";\nimport { keepalive, reactiveLog } from \"@graphrefly/pure-ts/extra\";\nimport { Graph, type GraphOptions } from \"@graphrefly/pure-ts/graph\";\nimport { domainMeta } from \"../../base/meta/domain-meta.js\";\nimport { mutate } from \"../../base/mutation/index.js\";\n\nconst DEFAULT_MAX_PER_PUMP = 256;\n\nfunction requireNonNegativeInt(value: number, label: string): number {\n\tif (!Number.isFinite(value) || !Number.isInteger(value) || value < 0) {\n\t\tthrow new Error(`${label} must be a non-negative integer`);\n\t}\n\treturn value;\n}\n\nfunction messagingMeta(kind: string, extra?: Record<string, unknown>): Record<string, unknown> {\n\treturn domainMeta(\"messaging\", kind, extra);\n}\n\nexport type TopicOptions = {\n\tgraph?: GraphOptions;\n\t/** Bounded retention; default 1024 per cross-cutting policy (Audit 2/4). */\n\tretainedLimit?: number;\n};\n\nconst DEFAULT_TOPIC_RETAINED_LIMIT = 1024;\n\nexport class TopicGraph<T> extends Graph {\n\tprivate readonly _log;\n\tprivate readonly _publishImpl: (value: T) => void;\n\treadonly events: Node<readonly T[]>;\n\t/**\n\t * Most recently published value. Stays in the protocol SENTINEL state\n\t * (`cache === undefined`, no DATA emitted) until the first publish, then\n\t * tracks the latest entry. Spec §5.12 reserves `undefined` as the\n\t * \"never sent DATA\" sentinel — and `TopicGraph.publish(undefined)` is\n\t * rejected — so `cache === undefined` unambiguously signals \"empty topic\"\n\t * even when `T` itself includes `null` (i.e., `topic<number | null>`).\n\t *\n\t * **Within a reactive fn:** detect the empty-topic case via\n\t * `ctx.prevData[i] === undefined` for the dep slot holding `topic.latest`,\n\t * or check `latest.cache === undefined` outside reactive code. No\n\t * separate `hasLatest` companion needed — the SENTINEL is the answer.\n\t */\n\treadonly latest: Node<T>;\n\n\tconstructor(name: string, opts: TopicOptions = {}) {\n\t\tsuper(name, opts.graph);\n\t\tthis._log = reactiveLog<T>([], {\n\t\t\tname: \"events\",\n\t\t\tmaxSize: opts.retainedLimit ?? DEFAULT_TOPIC_RETAINED_LIMIT,\n\t\t});\n\t\tthis.events = this._log.entries;\n\t\tthis.add(this.events, { name: \"events\" });\n\t\t// `this.derived(\"latest\", [\"events\"], …)` is expressible after the\n\t\t// 2026-04-30 self-resolve fix in `Graph._resolveFromSegments` — a\n\t\t// single-segment path matching the graph's own name (e.g.\n\t\t// `topic(\"events\").resolve(\"events\")`) no longer collapses to empty\n\t\t// and falls through to local-node lookup. Replaces the prior\n\t\t// `node([events], …) + this.add(...)` workaround.\n\t\t//\n\t\t// SENTINEL on empty: returning `[]` here yields a RESOLVED-only wave\n\t\t// (no DATA), so `latest.cache` stays `undefined` until the first\n\t\t// publish. `TopicGraph.publish(undefined)` is rejected (line below),\n\t\t// so `undefined` cache is unambiguously \"empty topic\" even when `T`\n\t\t// itself includes `null`. Drops the prior `hasLatest` companion as\n\t\t// redundant.\n\t\tthis.latest = this.derived<T>(\n\t\t\t\"latest\",\n\t\t\t[\"events\"],\n\t\t\t(batchData, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst entries = data[0] as readonly T[];\n\t\t\t\treturn entries.length === 0 ? [] : [entries[entries.length - 1] as T];\n\t\t\t},\n\t\t\t{ meta: messagingMeta(\"topic_latest\") },\n\t\t);\n\t\tthis.addDisposer(keepalive(this.latest));\n\n\t\t// D1(a): on teardown, propagate COMPLETE on `events` so downstream\n\t\t// derived chains (including any externally-held SubscriptionGraph\n\t\t// sources) see the termination via their `terminalDeps` and can stop\n\t\t// serving stale caches. Tier-3 terminal per spec §2.2.\n\t\t//\n\t\t// EC16 (verified 2026-04-30): the COMPLETE-then-disposeAllViews order\n\t\t// is intentional. COMPLETE propagates SYNCHRONOUSLY through every\n\t\t// subscriber (cursor views, derived chains) so they self-unsubscribe\n\t\t// in their terminal handler before `disposeAllViews` runs. Swapping\n\t\t// the order would clear view caches before subscribers receive the\n\t\t// terminal — strictly worse. Reading `.cache` outside a reactive fn\n\t\t// across teardown is an anti-pattern (spec §5.12) and not a use case\n\t\t// this ordering needs to preserve.\n\t\tthis.addDisposer(() => {\n\t\t\tthis.events.down([[COMPLETE]]);\n\t\t});\n\t\t// P9: release any memoized tail/slice view keepalives held by the log.\n\t\t// TopicGraph itself doesn't call log.tail/slice, but plugins may have\n\t\t// attached views via `_log` — defensive (typical reactive subscribers\n\t\t// have already unsubscribed in their COMPLETE handler above).\n\t\tthis.addDisposer(() => this._log.disposeAllViews());\n\n\t\t// Tier 8 / COMPOSITION-GUIDE §35: route publish through `mutate`\n\t\t// for centralized freeze + re-throw semantics. No audit log surface\n\t\t// (per Tier 8 γ-0): the topic's `events` log already records every\n\t\t// successful publish, so a separate audit Node would be redundant.\n\t\t// `freeze: false` because topic payloads can be large and per-publish\n\t\t// cost matters on hot paths.\n\t\tthis._publishImpl = mutate<[T], void, never>(\n\t\t\t(value): void => {\n\t\t\t\tthis._log.append(value);\n\t\t\t},\n\t\t\t{ frame: \"inline\", freeze: false },\n\t\t);\n\t}\n\n\tpublish(value: T): void {\n\t\t// SENTINEL alignment (Wave B.1 Unit 11 lock): `undefined` is the\n\t\t// protocol-level \"never sent DATA\" sentinel — refusing it here\n\t\t// preserves `lastValue: Node<T | undefined>` semantics.\n\t\tif (value === undefined) {\n\t\t\tthrow new TypeError(\n\t\t\t\t`TopicGraph \"${this.name}\": publish(undefined) is not allowed (spec §5.12 SENTINEL).`,\n\t\t\t);\n\t\t}\n\t\tthis._publishImpl(value);\n\t}\n\n\t/**\n\t * Wire one or more append-log storage tiers (Audit 4). Each tier receives\n\t * appended events per wave; rollback honors the wave-as-transaction model.\n\t *\n\t * Named `attachEventStorage` (not `attachStorage`) to avoid colliding with\n\t * the inherited {@link Graph.attachSnapshotStorage} which takes the\n\t * paired `AttachSnapshotTierPair[]` shape (Phase 14.6) — distinct\n\t * concerns, distinct surfaces.\n\t *\n\t * @returns Disposer.\n\t */\n\tattachEventStorage(\n\t\ttiers: readonly import(\"@graphrefly/pure-ts/extra\").AppendLogStorageTier<T>[],\n\t): () => void {\n\t\treturn this._log.attachStorage(tiers);\n\t}\n\n\tretained(): readonly T[] {\n\t\treturn this.events.cache as readonly T[];\n\t}\n\n\t/** Internal log bundle — used by TopicBridgeGraph for `attach`. */\n\tget _logBundle() {\n\t\treturn this._log;\n\t}\n}\n\nexport type SubscriptionOptions = {\n\tgraph?: GraphOptions;\n\t/**\n\t * Starting cursor position.\n\t * @deprecated Use `from` instead.\n\t */\n\tcursor?: number;\n\t/**\n\t * Starting position for the subscription.\n\t * - `\"retained\"` (default) — cursor starts at 0; consumer sees all retained history.\n\t * - `\"now\"` — cursor starts at current topic length; consumer ignores history.\n\t * - `number` — explicit cursor position.\n\t */\n\tfrom?: \"now\" | \"retained\" | number;\n\t/**\n\t * When this signal node emits DATA, the subscription auto-advances cursor\n\t * to current `available.length`. Useful for \"ack everything when X happens\"\n\t * patterns. The reactive edge `advanceOn → cursor` is visible in `explain()`.\n\t */\n\tadvanceOn?: Node<unknown>;\n};\n\n/** Result of {@link SubscriptionGraph.pullAndAck}. */\nexport type PullAndAckResult<T> = {\n\titems: readonly T[];\n\tcursor: number;\n};\n\nexport class SubscriptionGraph<T> extends Graph {\n\treadonly cursor: Node<number>;\n\treadonly available: Node<readonly T[]>;\n\t/**\n\t * Reference to the upstream topic graph. Intentionally NOT mounted\n\t * under this subscription: a subscription is a VIEW over an\n\t * externally-owned topic. Double-mounting (e.g. hub-owned topic +\n\t * sub-mount here) would make either-side teardown leave the other\n\t * holding a dead reference. Node-level `derived([topicEvents], …)`\n\t * still wires the data dependency across graph boundaries. D1(e).\n\t */\n\treadonly topic: TopicGraph<T>;\n\n\tprivate _disposed = false;\n\tprivate readonly _ackImpl: (count: number | undefined) => number;\n\tprivate readonly _pullAndAckImpl: (limit: number | undefined) => PullAndAckResult<T>;\n\n\tconstructor(name: string, topicGraph: TopicGraph<T>, opts: SubscriptionOptions = {}) {\n\t\tsuper(name, opts.graph);\n\t\tthis.topic = topicGraph;\n\n\t\t// Resolve initial cursor from `from` option, falling back to legacy `cursor` option.\n\t\tlet initialCursor: number;\n\t\tif (opts.from !== undefined) {\n\t\t\tif (opts.from === \"retained\") {\n\t\t\t\tinitialCursor = 0;\n\t\t\t} else if (opts.from === \"now\") {\n\t\t\t\t// §28 sanctioned factory-time boundary read.\n\t\t\t\tinitialCursor = (topicGraph.events.cache as readonly T[]).length;\n\t\t\t} else {\n\t\t\t\tinitialCursor = requireNonNegativeInt(opts.from, \"subscription from\");\n\t\t\t}\n\t\t} else {\n\t\t\tinitialCursor = requireNonNegativeInt(opts.cursor ?? 0, \"subscription cursor\");\n\t\t}\n\n\t\tthis.cursor = this.state<number>(\"cursor\", initialCursor, {\n\t\t\tmeta: messagingMeta(\"subscription_cursor\"),\n\t\t});\n\n\t\t// B.1 Unit 12 lock: `available` depends directly on topic.events + cursor\n\t\t// via `view({ kind: \"fromCursor\" })`. No `source` passthrough node —\n\t\t// describe shows `topic::events → available` (cross-graph edge) and\n\t\t// `cursor → available` (local edge). One fewer node per subscription.\n\t\tthis.available = topicGraph._logBundle.view({ kind: \"fromCursor\", cursor: this.cursor });\n\t\tthis.add(this.available, { name: \"available\" });\n\t\tthis.addDisposer(keepalive(this.available));\n\n\t\t// Optional reactive auto-advance: when `advanceOn` emits a NEW DATA\n\t\t// (after construction), cursor advances by `available.length` atomically.\n\t\t// Edge visible in describe: advancePump depends on advanceOn.\n\t\t// `_advanceInitialized` guards against the initial push-on-subscribe fire\n\t\t// that would advance cursor before the user has a chance to read.\n\t\tif (opts.advanceOn !== undefined) {\n\t\t\tconst advanceOn = opts.advanceOn;\n\t\t\tlet advanceInitialized = false;\n\t\t\tconst advancePump = node<unknown>(\n\t\t\t\t[advanceOn],\n\t\t\t\t() => {\n\t\t\t\t\t// Skip the initial push-on-subscribe wave.\n\t\t\t\t\tif (!advanceInitialized) {\n\t\t\t\t\t\tadvanceInitialized = true;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (this._disposed) return;\n\t\t\t\t\tconst avail = this.available.cache as readonly T[];\n\t\t\t\t\tif (avail.length === 0) return;\n\t\t\t\t\tconst next = (this.cursor.cache as number) + avail.length;\n\t\t\t\t\tthis.cursor.emit(next);\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: \"advancePump\",\n\t\t\t\t\tdescribeKind: \"effect\",\n\t\t\t\t\tmeta: messagingMeta(\"subscription_advance_pump\"),\n\t\t\t\t},\n\t\t\t);\n\t\t\tthis.add(advancePump, { name: \"advancePump\" });\n\t\t\tthis.addDisposer(keepalive(advancePump));\n\t\t}\n\n\t\t// Tier 8 / COMPOSITION-GUIDE §35: route ack + pullAndAck through\n\t\t// `mutate` for centralized freeze + re-throw semantics. No audit\n\t\t// log surface (per Tier 8 γ-0): the cursor's own emission stream already\n\t\t// records every advance, so a separate audit Node would be redundant.\n\t\t// `freeze: false` because count/limit are simple numbers; freezing is\n\t\t// pointless overhead. Disposed-checks stay outside the wrapper so a\n\t\t// no-op call doesn't unnecessarily run the wrapper.\n\t\tthis._ackImpl = mutate<[number | undefined], number, never>(\n\t\t\t(count): number => {\n\t\t\t\tconst available = this.available.cache as readonly T[];\n\t\t\t\tconst requested =\n\t\t\t\t\tcount === undefined\n\t\t\t\t\t\t? available.length\n\t\t\t\t\t\t: requireNonNegativeInt(count, \"subscription ack count\");\n\t\t\t\tconst step = Math.min(requested, available.length);\n\t\t\t\tif (step <= 0) return this.cursor.cache as number;\n\t\t\t\tconst next = (this.cursor.cache as number) + step;\n\t\t\t\t// F8: use emit() so the pipeline auto-prefixes DIRTY, runs equals\n\t\t\t\t// substitution, and produces a proper two-phase wave (the raw\n\t\t\t\t// `down([[DATA, next]])` path bypassed those contracts).\n\t\t\t\tthis.cursor.emit(next);\n\t\t\t\treturn next;\n\t\t\t},\n\t\t\t{ frame: \"inline\", freeze: false },\n\t\t);\n\n\t\tthis._pullAndAckImpl = mutate<[number | undefined], PullAndAckResult<T>, never>(\n\t\t\t(limit): PullAndAckResult<T> => {\n\t\t\t\tconst available = this.available.cache as readonly T[];\n\t\t\t\tconst max =\n\t\t\t\t\tlimit === undefined\n\t\t\t\t\t\t? available.length\n\t\t\t\t\t\t: requireNonNegativeInt(limit, \"subscription pullAndAck limit\");\n\t\t\t\tconst items = available.slice(0, max);\n\t\t\t\tif (items.length === 0) return { items, cursor: this.cursor.cache as number };\n\t\t\t\tconst next = (this.cursor.cache as number) + items.length;\n\t\t\t\tthis.cursor.emit(next);\n\t\t\t\treturn { items, cursor: next };\n\t\t\t},\n\t\t\t{ frame: \"inline\", freeze: false },\n\t\t);\n\t}\n\n\tack(count?: number): number {\n\t\tif (this._disposed) return this.cursor.cache as number;\n\t\treturn this._ackImpl(count);\n\t}\n\n\tpull(limit?: number): readonly T[] {\n\t\tif (this._disposed) return [];\n\t\tconst available = this.available.cache as readonly T[];\n\t\tconst max =\n\t\t\tlimit === undefined\n\t\t\t\t? available.length\n\t\t\t\t: requireNonNegativeInt(limit, \"subscription pull limit\");\n\t\treturn available.slice(0, max);\n\t}\n\n\t/**\n\t * Atomic pull-and-acknowledge. Returns `{ items, cursor }` where `cursor`\n\t * is the new cursor position after advancing. Under single-threaded JS the\n\t * snapshot and advance are atomic; PY callers use a per-subscription Lock.\n\t *\n\t * Replaces `pull(limit, { ack: true })`.\n\t */\n\tpullAndAck(limit?: number): PullAndAckResult<T> {\n\t\tif (this._disposed) return { items: [], cursor: this.cursor.cache as number };\n\t\treturn this._pullAndAckImpl(limit);\n\t}\n\n\t/**\n\t * Release internal subscriptions and mark the subscription torn-down.\n\t * Subsequent `pull`, `pullAndAck`, `ack` return empty / current cursor.\n\t * Emits COMPLETE on `cursor` so derived consumers (e.g. `available`) see\n\t * the termination signal. Also drains `addDisposer` callbacks (including\n\t * the `keepalive(advancePump)` subscription) so no keepalive leak occurs.\n\t */\n\tdispose(): void {\n\t\tif (this._disposed) return;\n\t\tthis._disposed = true;\n\t\tthis.cursor.down([[COMPLETE]]);\n\t\t// m4: drain addDisposer callbacks to release the keepalive subscription.\n\t\tthis.destroy();\n\t}\n}\n\nexport type TopicBridgeOptions<TIn, TOut> = {\n\tgraph?: GraphOptions;\n\tcursor?: number;\n\tmaxPerPump?: number;\n\t/**\n\t * Optional transform/filter applied to each item before republishing.\n\t *\n\t * **At-most-once with silent drop:** when `map` returns `undefined`, the\n\t * input is consumed from the source cursor but NOT republished. Filtered\n\t * items are not retained for retry. If you need filter-with-retry\n\t * semantics, do the filtering in a downstream subscription on the bridged\n\t * output rather than in the `map` function.\n\t */\n\tmap?: (value: TIn) => TOut | undefined;\n};\n\nexport class TopicBridgeGraph<TIn, TOut = TIn> extends Graph {\n\tprivate readonly _sourceSub;\n\treadonly bridgedCount: Node<number>;\n\t/**\n\t * Emits each mapped batch as DATA — gives downstream observers a reactive\n\t * stream of bridged values. Also the link target for `target._log.attach`.\n\t */\n\treadonly output: Node<readonly TOut[]>;\n\n\tconstructor(\n\t\tname: string,\n\t\tsourceTopic: TopicGraph<TIn>,\n\t\ttargetTopic: TopicGraph<TOut>,\n\t\topts: TopicBridgeOptions<TIn, TOut> = {},\n\t) {\n\t\tsuper(name, opts.graph);\n\t\tthis._sourceSub = subscription<TIn>(`${name}-subscription`, sourceTopic, {\n\t\t\tcursor: opts.cursor,\n\t\t});\n\t\tthis.mount(\"subscription\", this._sourceSub);\n\n\t\tconst maxPerPump = Math.max(\n\t\t\t1,\n\t\t\trequireNonNegativeInt(opts.maxPerPump ?? DEFAULT_MAX_PER_PUMP, \"topic bridge maxPerPump\"),\n\t\t);\n\t\tconst mapValue = opts.map ?? ((value: TIn) => value as unknown as TOut);\n\n\t\t// Reactive output node: derives a mapped batch from `available`.\n\t\t// §24 compliant — output is a real derived edge, visible in describe.\n\t\t// Replaces imperative publish loop. Items where mapValue returns undefined\n\t\t// are filtered out (opt-out / filter).\n\t\tthis.output = node<readonly TOut[]>(\n\t\t\t[this._sourceSub.available],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst arr = data[0] as readonly TIn[];\n\t\t\t\tconst outBatch: TOut[] = [];\n\t\t\t\tconst take = Math.min(arr.length, maxPerPump);\n\t\t\t\tfor (let i = 0; i < take; i++) {\n\t\t\t\t\tconst mapped = mapValue(arr[i] as TIn);\n\t\t\t\t\tif (mapped !== undefined) outBatch.push(mapped);\n\t\t\t\t}\n\t\t\t\tactions.emit(outBatch);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"output\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: messagingMeta(\"topic_bridge_output\", { targetRef: targetTopic.name }),\n\t\t\t\tinitial: [],\n\t\t\t},\n\t\t);\n\t\tthis.add(this.output, { name: \"output\" });\n\t\tthis.addDisposer(keepalive(this.output));\n\n\t\t// bridgedCount: state node accumulating total bridged items.\n\t\t// Updated by ackPump after each batch — edge visible via ackPump dep on output.\n\t\tthis.bridgedCount = this.state<number>(\"bridgedCount\", 0, {\n\t\t\tmeta: messagingMeta(\"topic_bridge_count\"),\n\t\t});\n\t\tthis.addDisposer(keepalive(this.bridgedCount));\n\n\t\t// ackPump: effect that advances the subscription cursor and updates\n\t\t// bridgedCount after each batch. Runs after `output` settles.\n\t\t// Captures refs to `this.output`, `this._sourceSub`, `this.bridgedCount`\n\t\t// to avoid `this` inside the fn body.\n\t\tconst outputRef = this.output;\n\t\tconst subRef = this._sourceSub;\n\t\tconst countRef = this.bridgedCount;\n\t\tconst ackPump = this.effect(\n\t\t\t\"ackPump\",\n\t\t\t[\"output\"],\n\t\t\t() => {\n\t\t\t\tconst outBatch = outputRef.cache as readonly TOut[];\n\t\t\t\tif (outBatch.length === 0) return;\n\t\t\t\tconst availLen = (subRef.available.cache as readonly TIn[]).length;\n\t\t\t\tconst toAck = Math.min(availLen, maxPerPump);\n\t\t\t\tif (toAck > 0) {\n\t\t\t\t\tsubRef.ack(toAck);\n\t\t\t\t\tconst prev = (countRef.cache as number) ?? 0;\n\t\t\t\t\tcountRef.emit(prev + outBatch.length);\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\tmeta: messagingMeta(\"topic_bridge_ack_pump\"),\n\t\t\t},\n\t\t);\n\t\tthis.addDisposer(keepalive(ackPump));\n\n\t\t// Wire output into target topic's log reactively.\n\t\t// _attachArrayToLog subscribes to output and publishes each item to targetTopic.\n\t\t// Teardown: disposer runs before mount teardown.\n\t\tconst detach = _attachArrayToLog(this.output, targetTopic);\n\t\tthis.addDisposer(detach);\n\t}\n}\n\n/**\n * Attaches each element of an array-valued Node to a TopicGraph's log.\n * Every DATA emission on `source` appends all items in the array to `targetTopic`.\n * Returns a disposer.\n */\nfunction _attachArrayToLog<T>(source: Node<readonly T[]>, targetTopic: TopicGraph<T>): () => void {\n\treturn source.subscribe((msgs) => {\n\t\tfor (const m of msgs) {\n\t\t\tif (m[0] !== DATA) continue;\n\t\t\tconst arr = m[1] as readonly T[];\n\t\t\tif (arr.length === 0) continue;\n\t\t\tbatch(() => {\n\t\t\t\tfor (const v of arr) targetTopic.publish(v);\n\t\t\t});\n\t\t}\n\t});\n}\n\n// ── TopicRegistry ─────────────────────────────────────────────────────────\n\n/**\n * Private pure data structure managing a named set of {@link TopicGraph}\n * instances. Extracted from {@link MessagingHubGraph} for separation of\n * concerns (B.2 Unit 14 lock: D — split into TopicRegistry + facade).\n *\n * Reusable if other domain consumers (e.g. cqrs.eventLogs) want a shared\n * topic registry later.\n *\n * @internal\n */\nexport class TopicRegistry {\n\tprivate readonly _map = new Map<string, TopicGraph<unknown>>();\n\t/** Reactive monotonic version counter. Advances on topic create/remove. */\n\treadonly version: Node<number>;\n\n\tconstructor(versionNode: Node<number>) {\n\t\tthis.version = versionNode;\n\t}\n\n\tget size(): number {\n\t\treturn this._map.size;\n\t}\n\n\thas(name: string): boolean {\n\t\treturn this._map.has(name);\n\t}\n\n\tget<T>(name: string): TopicGraph<T> | undefined {\n\t\treturn this._map.get(name) as TopicGraph<T> | undefined;\n\t}\n\n\tset<T>(name: string, t: TopicGraph<T>): void {\n\t\tthis._map.set(name, t as TopicGraph<unknown>);\n\t}\n\n\tdelete(name: string): boolean {\n\t\treturn this._map.delete(name);\n\t}\n\n\tkeys(): IterableIterator<string> {\n\t\treturn this._map.keys();\n\t}\n}\n\n// ── MessagingHubGraph ─────────────────────────────────────────────────────\n\nexport type MessagingHubOptions = {\n\tgraph?: GraphOptions;\n\t/**\n\t * Default `TopicOptions` applied to every topic created via `topic(name)`\n\t * without explicit options. Per-call opts override. Default: `{}`\n\t * (unbounded retention per topic unless `retainedLimit` is set per call).\n\t */\n\tdefaultTopicOptions?: TopicOptions;\n};\n\n/**\n * Lazy Pulsar-inspired topic registry. Manages a named set of {@link TopicGraph}\n * instances with retention + cursor semantics. Topics are created on first\n * access; `removeTopic(name)` unmounts and tears down via {@link Graph.remove}.\n *\n * Internally delegates to {@link TopicRegistry} for topic map management\n * (B.2 Unit 14 lock: D facade split).\n *\n * **Relationship to `pubsub()` in `src/extra/pubsub.ts`:** `pubsub` is a\n * lightweight last-value state hub (no retention, no cursors). `MessagingHubGraph`\n * is the full messaging hub — retained message logs, cursor-based subscriptions,\n * and pattern-layer lifecycle management.\n *\n * @category patterns\n */\nexport class MessagingHubGraph extends Graph {\n\tprivate readonly _registry: TopicRegistry;\n\t/** Reactive monotonic version counter — advances on topic create/remove. */\n\treadonly version: Node<number>;\n\tprivate readonly _defaultTopicOptions: TopicOptions;\n\tprivate readonly _removeTopicImpl: (name: string) => void;\n\n\tconstructor(name: string, opts: MessagingHubOptions = {}) {\n\t\tsuper(name, opts.graph);\n\t\t// B.2 Unit 14 lock: promote _version → version: Node<number>.\n\t\tconst versionNode = this.state<number>(\"version\", 0, {\n\t\t\tmeta: messagingMeta(\"hub_version\"),\n\t\t});\n\t\tthis.version = versionNode;\n\t\tthis._registry = new TopicRegistry(versionNode);\n\t\t// P8: shallow-copy caller-provided defaults so post-construction\n\t\t// mutations by the caller don't leak into every future `topic()` call.\n\t\tthis._defaultTopicOptions = { ...(opts.defaultTopicOptions ?? {}) };\n\n\t\t// Tier 8 / COMPOSITION-GUIDE §35: route the registry-delete branch of\n\t\t// `removeTopic` through `mutate` for centralized re-throw\n\t\t// semantics. No audit log surface (per Tier 8 γ-0).\n\t\t// `freeze: false` because the only arg is a string name (freeze pointless).\n\t\t// **Closure-state caveat (γ-4):** the inner `try/finally` mutates\n\t\t// `_registry` (a `Map`) and emits the version bump. mutate has no\n\t\t// `batch()` frame, so reactive emissions are NOT rolled back on throw —\n\t\t// and even if it did, `Map.delete` on closure state is invisible to the\n\t\t// batch and can't be unwound. The pre-existing try/finally on\n\t\t// `Graph.remove` is what guarantees registry/version converge to a\n\t\t// consistent state when `remove()` throws; `mutate` adds nothing\n\t\t// to that contract beyond the re-throw.\n\t\tthis._removeTopicImpl = mutate<[string], void, never>(\n\t\t\t(topicName): void => {\n\t\t\t\ttry {\n\t\t\t\t\tthis.remove(topicName); // unmounts, drops edges, tears down\n\t\t\t\t} finally {\n\t\t\t\t\tthis._registry.delete(topicName);\n\t\t\t\t\tconst cur = (this.version.cache as number) ?? 0;\n\t\t\t\t\tthis.version.emit(cur + 1);\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ frame: \"inline\", freeze: false },\n\t\t);\n\t}\n\n\t/** Number of topics currently in the hub. */\n\tget size(): number {\n\t\treturn this._registry.size;\n\t}\n\n\t/** Checks topic existence without creating. */\n\thas(name: string): boolean {\n\t\treturn this._registry.has(name);\n\t}\n\n\t/** Iterator over topic names. */\n\ttopicNames(): IterableIterator<string> {\n\t\treturn this._registry.keys();\n\t}\n\n\t/**\n\t * Returns the {@link TopicGraph} for `name`, creating lazily on first call.\n\t * Subsequent calls with the same name return the same instance (options on\n\t * repeat calls are ignored — the topic is already configured).\n\t */\n\ttopic<T = unknown>(name: string, opts?: TopicOptions): TopicGraph<T> {\n\t\tlet t = this._registry.get<T>(name);\n\t\tif (t === undefined) {\n\t\t\tconst effective: TopicOptions = { ...this._defaultTopicOptions, ...(opts ?? {}) };\n\t\t\tt = new TopicGraph<T>(name, effective);\n\t\t\tthis._registry.set(name, t);\n\t\t\tthis.mount(name, t);\n\t\t\tconst cur = (this.version.cache as number) ?? 0;\n\t\t\tthis.version.emit(cur + 1);\n\t\t}\n\t\treturn t;\n\t}\n\n\t/**\n\t * Publishes a value to the topic, lazily creating it on first publish.\n\t *\n\t * **Late-subscriber caveat:** the topic is created lazily, so subscribers\n\t * that attach AFTER a publish only see the retained window (governed by\n\t * `retainedLimit` on `TopicOptions` / `defaultTopicOptions`). If\n\t * `retainedLimit === 0` is set explicitly, early publishes are\n\t * effectively dropped — prefer an unset `retainedLimit` (unbounded\n\t * retention) or subscribe before publishing when late-subscribers matter.\n\t */\n\tpublish<T = unknown>(name: string, value: T): void {\n\t\tthis.topic<T>(name).publish(value);\n\t}\n\n\t/**\n\t * Bulk publish — issues all publishes inside one outer batch. New topics\n\t * are created on demand. No-op if `entries` yields nothing.\n\t *\n\t * **Iterable consumption (F6):** `entries` is consumed once (single-pass)\n\t * INSIDE the batch frame. If the iterator throws mid-way, the batch is\n\t * discarded and NO publishes are visible to subscribers (all-or-nothing).\n\t * Pass an array or `Set` for multi-shot callers.\n\t */\n\tpublishMany(entries: Iterable<[string, unknown]>): void {\n\t\t// P2: iterate inside batch — no `[...entries]` materialization so large\n\t\t// / infinite iterables don't OOM, and iterator throws are contained.\n\t\tbatch(() => {\n\t\t\tfor (const [name, value] of entries) {\n\t\t\t\tthis.topic(name).publish(value);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Creates a {@link SubscriptionGraph} over a named topic. The topic is\n\t * lazily created if missing. Subscription lifecycle is owned by the caller —\n\t * the hub does NOT mount the subscription.\n\t *\n\t * @param subName - Local name for the subscription graph.\n\t * @param topicName - Hub topic to subscribe to.\n\t * @param opts - `SubscriptionOptions` (initial cursor, etc.).\n\t */\n\tsubscribe<T = unknown>(\n\t\tsubName: string,\n\t\ttopicName: string,\n\t\topts?: SubscriptionOptions,\n\t): SubscriptionGraph<T> {\n\t\tconst t = this.topic<T>(topicName);\n\t\treturn new SubscriptionGraph<T>(subName, t, opts);\n\t}\n\n\t/**\n\t * Unmounts and tears down the topic's graph. Returns `true` if the topic\n\t * existed. Subscribers receive `TEARDOWN` via {@link Graph.remove}.\n\t *\n\t * **Closure-state caveat:** the registry mutation (`_registry.delete`) and\n\t * version bump happen in a `try/finally`, so registry/version converge to\n\t * a consistent state even when {@link Graph.remove} throws. `mutate`\n\t * does not roll back this mutation on throw — `Map.delete` on closure\n\t * state is invisible to any batch frame. The pre-existing try/finally is\n\t * load-bearing for that invariant.\n\t */\n\tremoveTopic(name: string): boolean {\n\t\tif (!this._registry.has(name)) return false;\n\t\t// P1 / P3: Graph.remove first — if it throws, `_registry` must NOT still\n\t\t// hold the broken half-disposed topic (otherwise the next\n\t\t// `hub.topic(name)` returns the corrupted reference). The `try/finally`\n\t\t// inside `_removeTopicImpl`'s action body preserves that invariant.\n\t\tthis._removeTopicImpl(name);\n\t\treturn true;\n\t}\n}\n\n/**\n * Creates a Pulsar-inspired topic graph (append-only retained stream + latest value).\n */\nexport function topic<T>(name: string, opts?: TopicOptions): TopicGraph<T> {\n\treturn new TopicGraph<T>(name, opts);\n}\n\n/**\n * Creates a lazy Pulsar-inspired messaging hub. Topics are created on first access\n * via `hub.topic(name)`; `hub.publish(name, value)` shortcuts through the registry.\n *\n * @example\n * ```ts\n * import { messagingHub } from \"@graphrefly/graphrefly/patterns/messaging\";\n *\n * const hub = messagingHub(\"main\", { defaultTopicOptions: { retainedLimit: 256 } });\n * hub.publish(\"orders\", { id: 1 });\n * hub.publishMany([[\"shipments\", { id: 1 }], [\"orders\", { id: 2 }]]);\n * const sub = hub.subscribe(\"orders-worker\", \"orders\", { cursor: 0 });\n * ```\n */\nexport function messagingHub(name: string, opts?: MessagingHubOptions): MessagingHubGraph {\n\treturn new MessagingHubGraph(name, opts);\n}\n\n/**\n * Creates a cursor-based subscription graph over a topic.\n */\nexport function subscription<T>(\n\tname: string,\n\ttopicGraph: TopicGraph<T>,\n\topts?: SubscriptionOptions,\n): SubscriptionGraph<T> {\n\treturn new SubscriptionGraph<T>(name, topicGraph, opts);\n}\n\n/**\n * Creates an autonomous cursor-based topic relay graph.\n *\n * When `opts.map` is provided, items where `map` returns `undefined` are\n * consumed from the source cursor but NOT republished (at-most-once with\n * silent drop). For filter-with-retry semantics, apply the filter in a\n * downstream subscription on the bridge's `output` node instead.\n */\nexport function topicBridge<TIn, TOut = TIn>(\n\tname: string,\n\tsourceTopic: TopicGraph<TIn>,\n\ttargetTopic: TopicGraph<TOut>,\n\topts?: TopicBridgeOptions<TIn, TOut>,\n): TopicBridgeGraph<TIn, TOut> {\n\treturn new TopicBridgeGraph<TIn, TOut>(name, sourceTopic, targetTopic, opts);\n}\n"],"mappings":"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","names":["batch"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/memory/index.ts","../src/utils/memory/fact-store.ts"],"sourcesContent":["/**\n * Memory patterns (roadmap §4.3) — public-face Phase-4 primitives audited under\n * `archive/docs/SESSION-public-face-blocks-review.md` (Wave A, locked 2026-04-25).\n *\n * Three primitives (the pure `decay` helper was promoted to `extra/utils/decay.ts`\n * per Tier 2.2 and is no longer re-exported here; `lightCollection` was folded\n * into `collection({ranked:false})` per Tier 2.3 and is no longer a separate\n * factory):\n * - {@link collection} / {@link CollectionGraph} — keyed memory store with\n * optional decay-aware ranking. Pass `{ ranked: false }` for the previous\n * `lightCollection` shape (Map + LRU + audit, no scoring).\n * - {@link vectorIndex} / {@link VectorIndexGraph} — reactive vector store with\n * optional HNSW backend, retention, and reactive {@link VectorIndexGraph.searchNode}.\n * - {@link knowledgeGraph} / {@link KnowledgeGraph} — entities + typed edges with\n * symmetric adjacency indexes and reactive {@link KnowledgeGraph.relatedNode}.\n *\n * **No imperative reads.** Per the API-style policy locked 2026-04-25, public-face\n * primitives expose reactive reads only — `itemNode` / `hasNode` / `searchNode` /\n * `relatedNode`. One-shot snapshots use `node.cache` after `awaitSettled`, or\n * `firstValueFrom(node)`.\n *\n * **Audit logs.** Every imperative mutation (`upsert / remove / clear / link /\n * unlink / rescore / reindex`) is wrapped via {@link mutate} and appends a\n * typed record to a public `events` log on the bundle / graph.\n *\n * @module\n */\n\nimport { monotonicNs, type Node, NodeImpl, node, wallClockNs } from \"@graphrefly/pure-ts/core\";\nimport type { ReactiveLogBundle } from \"@graphrefly/pure-ts/extra\";\nimport { fromTimer, keepalive, reactiveMap } from \"@graphrefly/pure-ts/extra\";\nimport { Graph } from \"@graphrefly/pure-ts/graph\";\nimport { domainMeta } from \"../../base/meta/domain-meta.js\";\nimport {\n\ttype BaseAuditRecord,\n\tbumpCursor,\n\tcreateAuditLog,\n\tmutate,\n\tregisterCursor,\n} from \"../../base/mutation/index.js\";\nimport type { NodeOrValue } from \"../../base/resilience/_internal.js\";\nimport { decay } from \"../../base/utils/decay.js\";\n\n// ── Shared helpers ───────────────────────────────────────────────────────\n\nconst NS_PER_SEC = 1_000_000_000;\n\nfunction memoryMeta(kind: string, extra?: Record<string, unknown>): Record<string, unknown> {\n\treturn domainMeta(\"memory\", kind, extra);\n}\n\n/**\n * Coerce a value-or-Node argument into a `Node<T>`. Pass-through if already a\n * Node; otherwise wraps in `state(value, {name})`. Used by reactive read\n * factories (`itemNode` / `searchNode` / `relatedNode`) so callers can supply\n * a static value without manually creating a state node.\n *\n * Heuristic: anything that is a `NodeImpl` instance is a Node; everything else\n * is treated as a raw value to wrap.\n */\nfunction toNode<T>(v: T | Node<T>, name?: string): Node<T> {\n\tif (v instanceof NodeImpl) return v as Node<T>;\n\treturn node<T>([], { initial: v as T, ...(name ? { name } : undefined) });\n}\n\nfunction ageSeconds(now: number, lastNs: number): number {\n\treturn (now - lastNs) / NS_PER_SEC;\n}\n\n// `decay` was promoted to `extra/utils/decay.ts` per Tier 2.2 — it is no longer\n// re-exported from this module. Import from `@graphrefly/graphrefly/extra` (or\n// `../../extra/utils/decay.js` internally) instead.\n\n/**\n * Cosine similarity over `(a, b)`. When lengths differ, the shorter is\n * implicitly zero-padded to the longer length. Returns `0` if either vector\n * has zero norm. Public utility — used by {@link VectorIndexGraph.searchNode}\n * and exposed for downstream consumers (e.g. `patterns/ai/memory/`) that need\n * the same scoring at the boundary.\n *\n * **Numeric guards.** Returns `0` for non-finite results (overflow producing\n * `Infinity`/`NaN` from very-large vectors, or `NaN` propagating from any\n * `NaN`/`Infinity` component). Without this guard, downstream sort\n * comparators would order NaN-scored rows arbitrarily.\n *\n * **Depth.** This is a per-call computation; no internal caching. For very\n * large indexes (>10k) consider precomputing norms or using HNSW.\n *\n * @category memory\n */\nexport function cosineSimilarity(a: readonly number[], b: readonly number[]): number {\n\tconst n = Math.max(a.length, b.length);\n\tlet dot = 0;\n\tlet na = 0;\n\tlet nb = 0;\n\tfor (let i = 0; i < n; i += 1) {\n\t\tconst av = a[i] ?? 0;\n\t\tconst bv = b[i] ?? 0;\n\t\tdot += av * bv;\n\t\tna += av * av;\n\t\tnb += bv * bv;\n\t}\n\tif (na === 0 || nb === 0) return 0;\n\tconst score = dot / Math.sqrt(na * nb);\n\treturn Number.isFinite(score) ? score : 0;\n}\n\n/**\n * Equality predicate for {@link VectorIndexGraph.searchNode} results. Compares\n * `id` AND `score` AND `meta` reference per position so that score-only changes\n * (re-upsert with new vector keeping the same top-K order) propagate to\n * downstream subscribers. The previous id-only comparator silently dropped\n * those updates.\n */\nfunction searchResultsEqual<TMeta>(\n\ta: readonly VectorSearchResult<TMeta>[] | undefined,\n\tb: readonly VectorSearchResult<TMeta>[] | undefined,\n): boolean {\n\tif (a === b) return true;\n\tif (a == null || b == null) return false;\n\tif (a.length !== b.length) return false;\n\tfor (let i = 0; i < a.length; i += 1) {\n\t\tconst x = a[i]!;\n\t\tconst y = b[i]!;\n\t\tif (x.id !== y.id || x.score !== y.score || x.meta !== y.meta) return false;\n\t}\n\treturn true;\n}\n\n// ── Common types ─────────────────────────────────────────────────────────\n\n/** Public alias for the `Node | value` shape accepted by reactive read factories. */\nexport type { NodeOrValue } from \"../../base/resilience/_internal.js\";\n\n// ── Unit 2 (Tier 2.3 fold): collection (formerly lightCollection + collection)\n//\n// Pre-Tier-2.3 the module shipped `lightCollection` (no Graph, no ranking,\n// just LRU + audit) alongside `collection` (Graph-mounted with timer-driven\n// decay-aware ranking). Per the consolidation plan §1 Rule 4, the two are\n// folded into a single `collection({ranked: true|false})` factory: when\n// `ranked: false`, no `ranked` derived / refresh tick / scoring is wired.\n// `LightCollectionEntry` is gone — `CollectionEntry<T>` is the unified entry\n// shape (`baseScore` reads `0` in unranked mode).\n\nexport type CollectionEntry<T> = {\n\treadonly id: string;\n\treadonly value: T;\n\treadonly createdAtNs: number;\n\treadonly lastAccessNs: number;\n\treadonly baseScore: number;\n};\n\nexport type RankedCollectionEntry<T> = CollectionEntry<T> & {\n\treadonly score: number;\n};\n\nexport type CollectionScoreFn<T> = (value: T) => number;\n\nexport type CollectionOptions<T> = {\n\tmaxSize?: number;\n\t/**\n\t * Whether to expose a live decay-aware `ranked` node + `rescore` mutator.\n\t * Default `true`. Pass `false` to fold in the previous `lightCollection`\n\t * shape — entries are still keyed/audited/LRU-evicted, but the timer-driven\n\t * `ranked` + scoring machinery is skipped. `ranked` then resolves to a\n\t * static empty array Node and `rescore()` is a no-op (so callers writing\n\t * type-generic code don't need to special-case the unranked path).\n\t */\n\tranked?: boolean;\n\t/**\n\t * Produces a base score at insert/update time. Static fn or a reactive\n\t * `Node<(value: T) => number>` — when supplied as a Node, `ranked` re-derives\n\t * whenever the score fn changes, but `baseScore` on each entry is only\n\t * recomputed via {@link CollectionGraph.rescore}. Default `() => 1`.\n\t *\n\t * Ignored when `ranked: false` (entries record `baseScore: 0`).\n\t */\n\tscore?: CollectionScoreFn<T> | Node<CollectionScoreFn<T>>;\n\t/**\n\t * Exponential decay rate per second. `0` disables decay (default). When\n\t * positive, `ranked` becomes fully reactive on time via a `fromTimer` source\n\t * (cadence auto-derived from `decayRate` unless overridden via\n\t * `refreshIntervalMs`). Half-life: `ratePerSecond = Math.LN2 / halfLifeSeconds`.\n\t *\n\t * Ignored when `ranked: false`.\n\t */\n\tdecayRate?: number;\n\t/** Minimum score floor after decay. Default `0`. */\n\tminScore?: number;\n\t/**\n\t * Override for the `ranked` refresh tick cadence (milliseconds). When\n\t * unset and `decayRate > 0`, defaults to `1000 * Math.LN2 / (10 * decayRate)`\n\t * — roughly one tick per 10% of the half-life (~10% staleness budget).\n\t */\n\trefreshIntervalMs?: number;\n};\n\nexport interface CollectionAuditRecord extends BaseAuditRecord {\n\treadonly action: \"upsert\" | \"remove\" | \"clear\" | \"rescore\";\n\treadonly id?: string;\n}\n\nexport type CollectionGraph<T> = Graph & {\n\treadonly events: ReactiveLogBundle<CollectionAuditRecord>;\n\treadonly items: Node<ReadonlyMap<string, CollectionEntry<T>>>;\n\t/**\n\t * Live decay-aware ranking, sorted by score descending. When the\n\t * collection was constructed with `ranked: false`, this is a static\n\t * empty-array Node (kept for type uniformity).\n\t */\n\treadonly ranked: Node<readonly RankedCollectionEntry<T>[]>;\n\treadonly size: Node<number>;\n\tupsert: (id: string, value: T, opts?: { score?: number }) => void;\n\tremove: (id: string) => void;\n\tclear: () => void;\n\t/**\n\t * Recompute every entry's `baseScore` via the latest score fn. O(N). Useful\n\t * when a reactive `score` Node has emitted a new fn and the caller wants\n\t * existing entries re-scored without an explicit re-upsert.\n\t *\n\t * No-op (still records an audit entry) when constructed with\n\t * `ranked: false`.\n\t */\n\trescore: () => void;\n\titemNode: (id: NodeOrValue<string>) => Node<CollectionEntry<T> | undefined>;\n\t/** Reactive `true` once the entry exists; tracks upsert / remove. */\n\thasNode: (id: NodeOrValue<string>) => Node<boolean>;\n};\n\nfunction rankedEqual<T>(\n\ta: readonly RankedCollectionEntry<T>[] | undefined,\n\tb: readonly RankedCollectionEntry<T>[] | undefined,\n): boolean {\n\tif (a === b) return true;\n\tif (a == null || b == null) return false;\n\tif (a.length !== b.length) return false;\n\tfor (let i = 0; i < a.length; i += 1) {\n\t\tconst x = a[i]!;\n\t\tconst y = b[i]!;\n\t\t// Compare value reference too — if `upsert(id, newValue)` runs and\n\t\t// `score(newValue) === score(oldValue)` AND timestamps coincide\n\t\t// (rare on platforms where consecutive `monotonicNs()` calls in the\n\t\t// same microtask collide), the prior comparator suppressed the\n\t\t// emission and consumers reading `entry.value` saw stale data.\n\t\t// Value identity catches it cheaply (`value !== value` only on NaN\n\t\t// payloads, which behave correctly here).\n\t\tif (\n\t\t\tx.id !== y.id ||\n\t\t\tx.score !== y.score ||\n\t\t\tx.lastAccessNs !== y.lastAccessNs ||\n\t\t\tx.value !== y.value\n\t\t)\n\t\t\treturn false;\n\t}\n\treturn true;\n}\n\n/**\n * Scored memory store with live decay-aware ranking.\n *\n * Topology (mounted on the returned graph):\n * - `items` — `reactiveMap<id, CollectionEntry<T>>` (with `retention` configured\n * for score-based eviction when `maxSize` is set).\n * - `ranked` — `Node<readonly RankedCollectionEntry<T>[]>`, sorted by live\n * decayed score. **Lazy** — does NOT compute until subscribed (no internal\n * keepalive). Use `keepalive(coll.ranked)` for eager activation.\n * - `size` — `Node<number>`, count of entries.\n * - `_refreshTick` — `fromTimer`-driven `monotonicNs()` source, mounted only\n * when `decayRate > 0`. Drives `ranked`'s time-dependent re-derivation.\n * - `_seq` — sequence cursor for the audit log.\n * - `events` — bounded reactive log of every mutation.\n *\n * **Time as a reactive dep.** When `decayRate > 0`, `ranked`'s deps are\n * `[items, refreshTick]` — the tick payload IS `monotonicNs()`, so the fn is\n * pure of deps and dry-run-reproducible with a mocked clock.\n *\n * **Lazy timer.** With no subscriber to `ranked`, the timer source does not\n * fire — the activation chain is downstream-driven. To keep the timer warm\n * without consuming results, register `graph.addDisposer(keepalive(coll.ranked))`.\n *\n * **Eviction at write-time.** Score-based retention runs on every successful\n * `upsert / remove / clear` (it is mutation-driven, not tick-driven). The\n * retention scorer reads `monotonicNs()` to compute decayed scores at eviction\n * time — this is a deliberate impurity vs. `ReactiveMapRetention.score`'s\n * \"pure of `(key, value)`\" docstring: write-time is the right moment to evict\n * stale-by-decay entries.\n *\n * **No imperative reads.** Subscribe to `items` / `ranked` for live snapshots,\n * or use `itemNode(id)` for single-key reactive reads.\n *\n * **`rescore` ordering caveat.** `rescore()` reads `items.entries.cache`\n * (the post-emission snapshot) and writes via `setMany`. When called\n * stand-alone it sees the latest committed state. When wrapped inside a\n * user-level `batch(() => { coll.upsert(...); coll.rescore(); })`, the\n * `cache` snapshot reflects state BEFORE the batch — so a just-staged\n * upsert is invisible to the rescore scan. If you need rescore to include\n * the staged upsert, either call `rescore()` after the batch settles or\n * pass the new `baseScore` directly via `upsert(id, value, { score })`.\n *\n * **Audit no-op records.** Like `lightCollection`, mutations record audit\n * entries even when the impl was a no-op (e.g., `rescore()` on an empty\n * store). Intentional — the framework records attempts.\n *\n * @category memory\n */\nexport function collection<T>(name: string, opts: CollectionOptions<T> = {}): CollectionGraph<T> {\n\tconst maxSize = opts.maxSize;\n\tconst ranked = opts.ranked ?? true;\n\t// `decayRate` / `score` / `refreshIntervalMs` are no-ops when ranked is off\n\t// (they only feed the `ranked` derived). The audit + LRU paths still run.\n\tconst decayRate = ranked ? (opts.decayRate ?? 0) : 0;\n\tconst minScore = opts.minScore ?? 0;\n\tif (maxSize !== undefined && maxSize < 1) {\n\t\tthrow new RangeError(\"collection: maxSize must be >= 1\");\n\t}\n\n\t// Resolve score fn — supports static fn or reactive Node<fn>. When\n\t// `ranked: false` the score is constant `0` and `readScoreFn` is unused\n\t// (the upsert path takes the `_opts.score ?? readScoreFn()(value)` branch\n\t// only when ranking is requested).\n\tconst scoreFnDefault: CollectionScoreFn<T> = () => (ranked ? 1 : 0);\n\tconst scoreInput = opts.score ?? scoreFnDefault;\n\tconst scoreNode: Node<CollectionScoreFn<T>> | undefined =\n\t\tranked && scoreInput instanceof NodeImpl\n\t\t\t? (scoreInput as Node<CollectionScoreFn<T>>)\n\t\t\t: undefined;\n\tconst readScoreFn = (): CollectionScoreFn<T> => {\n\t\tif (scoreNode) return scoreNode.cache ?? scoreFnDefault;\n\t\treturn scoreInput as CollectionScoreFn<T>;\n\t};\n\n\tconst graph = new Graph(name);\n\n\t// Score-based retention scorer for `reactiveMap`. When unranked the base\n\t// score is `0`, so retention falls back to LRU-by-`lastAccessNs` (the\n\t// older the access, the lower the decayed score → first to evict).\n\tconst retentionScore = (_k: string, v: CollectionEntry<T>): number =>\n\t\tranked\n\t\t\t? decay(v.baseScore, ageSeconds(monotonicNs(), v.lastAccessNs), decayRate, minScore)\n\t\t\t: v.lastAccessNs;\n\n\tconst items = reactiveMap<string, CollectionEntry<T>>({\n\t\tname: \"items\",\n\t\t...(maxSize !== undefined ? { retention: { score: retentionScore, maxSize } } : {}),\n\t});\n\n\tgraph.add(items.entries, { name: \"items\" });\n\n\t// Refresh tick — only mounted when ranking + decay are configured. Tick\n\t// payload is `monotonicNs()`, so `rankedNode`'s fn is pure-of-deps and\n\t// dry-run-reproducible.\n\tlet refreshTick: Node<number> | undefined;\n\tif (ranked && decayRate > 0) {\n\t\tconst intervalMs = opts.refreshIntervalMs ?? Math.max(1, (1000 * Math.LN2) / (10 * decayRate));\n\t\tconst tickCounter = fromTimer(intervalMs, { period: intervalMs });\n\t\t// Map each tick to the wall-clock `monotonicNs` — the tick payload IS\n\t\t// the time stamp downstream consumers use. Reading the central clock\n\t\t// inside this fn is sanctioned: this derived's purpose is to publish\n\t\t// \"now\" reactively (cf. spec §5.11 — central timer), and downstream\n\t\t// `rankedNode` reads it from its dep array, never from the clock\n\t\t// directly.\n\t\t//\n\t\t// `initial: monotonicNs()` seeds the cache with construction-time\n\t\t// `now` so push-on-subscribe delivers DATA to `rankedNode` before the\n\t\t// first tick fires — without this, `rankedNode` would stall in pending\n\t\t// status until ~`refreshIntervalMs` after first activation, and a\n\t\t// caller reading `rankedNode.cache` immediately after `upsert` would\n\t\t// see `undefined`.\n\t\trefreshTick = node(\n\t\t\t[tickCounter],\n\t\t\t(_batchData, actions) => {\n\t\t\t\tactions.emit(monotonicNs());\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"refresh_tick_ns\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tinitial: monotonicNs(),\n\t\t\t\tmeta: memoryMeta(\"clock\"),\n\t\t\t},\n\t\t);\n\t\tgraph.add(refreshTick, { name: \"refresh_tick_ns\" });\n\t}\n\n\t// `rankedNode` derived — pure of (items, refreshTick?, scoreNode?). When\n\t// `ranked: false`, `rankedNode` is a static empty-array node so the\n\t// public type stays uniform without re-running the sort.\n\tlet rankedNode: Node<readonly RankedCollectionEntry<T>[]>;\n\tif (ranked) {\n\t\tconst rankedDeps: Node<unknown>[] = [items.entries];\n\t\tif (refreshTick) rankedDeps.push(refreshTick);\n\t\tif (scoreNode) rankedDeps.push(scoreNode);\n\t\trankedNode = node(\n\t\t\trankedDeps,\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst values = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst snapshot = values[0] as ReadonlyMap<string, CollectionEntry<T>> | undefined;\n\t\t\t\tlet now: number;\n\t\t\t\tif (refreshTick) {\n\t\t\t\t\tconst tickValue = values[1] as number | undefined;\n\t\t\t\t\tnow = typeof tickValue === \"number\" ? tickValue : monotonicNs();\n\t\t\t\t} else {\n\t\t\t\t\tnow = monotonicNs();\n\t\t\t\t}\n\t\t\t\tif (!snapshot || snapshot.size === 0) {\n\t\t\t\t\tactions.emit([] as readonly RankedCollectionEntry<T>[]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst out: RankedCollectionEntry<T>[] = [];\n\t\t\t\tfor (const entry of snapshot.values()) {\n\t\t\t\t\tout.push({\n\t\t\t\t\t\t...entry,\n\t\t\t\t\t\tscore: decay(entry.baseScore, ageSeconds(now, entry.lastAccessNs), decayRate, minScore),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tout.sort((a, b) => b.score - a.score || b.lastAccessNs - a.lastAccessNs);\n\t\t\t\tactions.emit(out as readonly RankedCollectionEntry<T>[]);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"ranked\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tequals: rankedEqual,\n\t\t\t\tmeta: memoryMeta(\"ranked\"),\n\t\t\t},\n\t\t) as Node<readonly RankedCollectionEntry<T>[]>;\n\t\tgraph.add(rankedNode, { name: \"ranked\" });\n\t} else {\n\t\trankedNode = node<readonly RankedCollectionEntry<T>[]>([], {\n\t\t\tinitial: [] as readonly RankedCollectionEntry<T>[],\n\t\t\tname: \"ranked\",\n\t\t\tdescribeKind: \"state\",\n\t\t\tmeta: memoryMeta(\"ranked_disabled\"),\n\t\t}) as Node<readonly RankedCollectionEntry<T>[]>;\n\t\tgraph.add(rankedNode, { name: \"ranked\" });\n\t}\n\n\tconst size = node(\n\t\t[items.entries],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst snapshot = data[0] as ReadonlyMap<string, CollectionEntry<T>> | undefined;\n\t\t\tactions.emit(((snapshot ?? new Map()) as ReadonlyMap<string, CollectionEntry<T>>).size);\n\t\t},\n\t\t{\n\t\t\tname: \"size\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tinitial: 0,\n\t\t\tmeta: memoryMeta(\"size\"),\n\t\t},\n\t);\n\tgraph.add(size, { name: \"size\" });\n\t// Keepalive only on `size` (cheap; pure of items). `ranked` is intentionally\n\t// lazy so the refresh timer doesn't fire when nothing consumes the ranking.\n\tgraph.addDisposer(keepalive(size));\n\n\t// Audit log + seq cursor.\n\tconst events = createAuditLog<CollectionAuditRecord>({\n\t\tname: \"events\",\n\t\tretainedLimit: 1024,\n\t\tgraph,\n\t});\n\tconst seqCursor = registerCursor(graph, \"seq\", 0);\n\n\tconst upsertImpl = (id: string, value: T, _opts?: { score?: number }): void => {\n\t\tconst now = monotonicNs();\n\t\tconst prev = items.get(id);\n\t\tconst baseScore = _opts?.score ?? readScoreFn()(value);\n\t\titems.set(id, {\n\t\t\tid,\n\t\t\tvalue,\n\t\t\tbaseScore,\n\t\t\tcreatedAtNs: prev?.createdAtNs ?? now,\n\t\t\tlastAccessNs: now,\n\t\t});\n\t};\n\tconst removeImpl = (id: string): void => {\n\t\tif (!items.has(id)) return;\n\t\titems.delete(id);\n\t};\n\tconst clearImpl = (): void => {\n\t\tif (items.size === 0) return;\n\t\titems.clear();\n\t};\n\tconst rescoreImpl = (): void => {\n\t\t// `ranked: false` short-circuit — there's no live `ranked` node to\n\t\t// re-derive and `baseScore` is held at its insertion-time value, so\n\t\t// rescore is a no-op. The audit record is still emitted so consumers\n\t\t// see the attempt.\n\t\tif (!ranked) return;\n\t\tconst fn = readScoreFn();\n\t\tconst snapshot = items.entries.cache as ReadonlyMap<string, CollectionEntry<T>> | undefined;\n\t\tif (!snapshot || snapshot.size === 0) return;\n\t\tconst updates: Array<[string, CollectionEntry<T>]> = [];\n\t\tfor (const entry of snapshot.values()) {\n\t\t\tupdates.push([entry.id, { ...entry, baseScore: fn(entry.value) }]);\n\t\t}\n\t\titems.setMany(updates);\n\t};\n\n\tconst upsert = mutate(upsertImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([id], _r, m) => ({ action: \"upsert\" as const, id, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\tconst remove = mutate(removeImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([id], _r, m) => ({ action: \"remove\" as const, id, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\tconst clear = mutate(clearImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: (_args, _r, m) => ({ action: \"clear\" as const, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\tconst rescore = mutate(rescoreImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: (_args, _r, m) => ({ action: \"rescore\" as const, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\n\tfunction itemNode(id: NodeOrValue<string>): Node<CollectionEntry<T> | undefined> {\n\t\tconst idN = toNode(id, \"id\");\n\t\treturn node(\n\t\t\t[items.entries, idN],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst map = data[0] as ReadonlyMap<string, CollectionEntry<T>> | undefined;\n\t\t\t\tconst key = data[1] as string;\n\t\t\t\tactions.emit(map?.get(key));\n\t\t\t},\n\t\t\t{\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: memoryMeta(\"collection_item\"),\n\t\t\t},\n\t\t);\n\t}\n\n\tfunction hasNode(id: NodeOrValue<string>): Node<boolean> {\n\t\tconst idN = toNode(id, \"id\");\n\t\treturn node(\n\t\t\t[items.entries, idN],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst map = data[0] as ReadonlyMap<string, CollectionEntry<T>> | undefined;\n\t\t\t\tconst key = data[1] as string;\n\t\t\t\tactions.emit(map?.has(key) ?? false);\n\t\t\t},\n\t\t\t{\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: memoryMeta(\"collection_has\"),\n\t\t\t},\n\t\t);\n\t}\n\n\tconst out = Object.assign(graph, {\n\t\tevents,\n\t\titems: items.entries,\n\t\tranked: rankedNode,\n\t\tsize,\n\t\tupsert,\n\t\tremove,\n\t\tclear,\n\t\trescore,\n\t\titemNode,\n\t\thasNode,\n\t}) as CollectionGraph<T>;\n\treturn out;\n}\n\n// ── Unit 4: vectorIndex ──────────────────────────────────────────────────\n\nexport type VectorBackend = \"flat\" | \"hnsw\";\n\nexport type VectorRecord<TMeta> = {\n\treadonly id: string;\n\treadonly vector: readonly number[];\n\treadonly meta?: TMeta;\n\t/** Wall-clock-monotonic timestamp at last upsert; used for the default LRU retention. */\n\treadonly upsertedAtNs: number;\n};\n\nexport type VectorSearchResult<TMeta> = {\n\treadonly id: string;\n\treadonly score: number;\n\treadonly meta?: TMeta;\n};\n\nexport type HnswAdapter<TMeta> = {\n\tupsert: (id: string, vector: readonly number[], meta?: TMeta) => void;\n\tremove: (id: string) => void;\n\tclear: () => void;\n\tsearch: (query: readonly number[], k: number) => ReadonlyArray<VectorSearchResult<TMeta>>;\n\t/** Optional adapter teardown. Called from `graph.destroy()` via `addDisposer`. */\n\tdispose?: () => void;\n};\n\nexport type VectorIndexOptions<TMeta> = {\n\tname?: string;\n\tbackend?: VectorBackend;\n\tdimension?: number;\n\t/**\n\t * Strict-dimension default. When `true` (default) AND `dimension` is unset,\n\t * mixed-length upserts throw `RangeError`. Set `false` to opt into the\n\t * lenient zero-padding behavior of {@link VectorIndexGraph.searchNode}.\n\t */\n\tstrictDimension?: boolean;\n\t/** Optional dependency seam for HNSW. */\n\thnswFactory?: () => HnswAdapter<TMeta>;\n\t/** Maximum live entries (LRU-by-upsert-time when set; user-overridable via `retentionScore`). */\n\tmaxSize?: number;\n\t/** Custom retention scorer. Higher score = kept. Defaults to `r => r.upsertedAtNs`. */\n\tretentionScore?: (record: VectorRecord<TMeta>) => number;\n};\n\nexport interface VectorIndexAuditRecord extends BaseAuditRecord {\n\treadonly action: \"upsert\" | \"remove\" | \"clear\" | \"reindex\" | \"evict\";\n\treadonly id?: string;\n}\n\nexport type VectorIndexGraph<TMeta> = Graph & {\n\treadonly backend: VectorBackend;\n\treadonly events: ReactiveLogBundle<VectorIndexAuditRecord>;\n\treadonly entries: Node<ReadonlyMap<string, VectorRecord<TMeta>>>;\n\tupsert: (id: string, vector: readonly number[], meta?: TMeta) => void;\n\tremove: (id: string) => void;\n\tclear: () => void;\n\t/** Re-push every live entry into the optional HNSW adapter. No-op for `flat`. */\n\treindex: () => void;\n\t/**\n\t * Reactive top-K search. Re-derives whenever entries / query / k change.\n\t * Lazy. Use `firstValueFrom(searchNode(...))` for one-shot reads.\n\t */\n\tsearchNode: (\n\t\tquery: Node<readonly number[]>,\n\t\tk?: NodeOrValue<number>,\n\t) => Node<readonly VectorSearchResult<TMeta>[]>;\n};\n\n/**\n * Reactive vector store with optional HNSW backend.\n *\n * **Storage on `reactiveMap`.** `entries` is a `reactiveMap<id, VectorRecord<TMeta>>`\n * with optional score-based retention (`maxSize` + LRU-by-`upsertedAtNs` by\n * default; user can supply a custom `retentionScore`). On retention eviction,\n * the HNSW adapter (if configured) is also notified via `adapter.remove(id)`.\n *\n * **Reactive search.** `searchNode(queryNode, k)` returns a `Node<readonly\n * VectorSearchResult<TMeta>[]>` that re-derives on entries / query / k change.\n * Lazy — only computes when subscribed. Imperative `search()` is intentionally\n * not exposed (no-imperative-reads policy). Use `firstValueFrom(searchNode(...))`\n * for one-shot reads.\n *\n * **Strict dimension.** Default `strictDimension: true` — if `dimension` is\n * unset and an upsert produces a vector of a different length than the first\n * upserted, throws `RangeError`. Pass `strictDimension: false` to opt into\n * the lenient zero-padding fallback (the previous default).\n *\n * **Adapter lifecycle.** When the HNSW adapter exposes a `dispose()` method,\n * it is bound to the graph's teardown via `addDisposer`. When retention\n * evicts an entry, `adapter.remove(id)` is invoked synchronously inside the\n * retention `onArchive` callback.\n *\n * **Cosine zero-pad.** The flat backend uses cosine similarity over the\n * pairwise max-length zero-pad. Mixing dimensions silently degrades scores\n * unless strict mode catches it at upsert time. For embedding-model vectors,\n * L2-normalize at the source — `vectorIndex` does not normalize.\n *\n * @category memory\n */\nexport function vectorIndex<TMeta>(opts: VectorIndexOptions<TMeta> = {}): VectorIndexGraph<TMeta> {\n\tconst backend = opts.backend ?? \"flat\";\n\tconst dimension = opts.dimension;\n\tconst strictDimension = opts.strictDimension ?? true;\n\tconst maxSize = opts.maxSize;\n\tconst userRetentionScore = opts.retentionScore;\n\n\tlet hnsw: HnswAdapter<TMeta> | undefined;\n\tif (backend === \"hnsw\") {\n\t\thnsw = opts.hnswFactory?.();\n\t\tif (!hnsw) {\n\t\t\tthrow new Error(\n\t\t\t\t'vectorIndex backend \"hnsw\" requires an optional dependency adapter; install your HNSW package and provide `hnswFactory`.',\n\t\t\t);\n\t\t}\n\t}\n\n\tconst graph = new Graph(opts.name ?? \"vector_index\");\n\n\t// Track an inferred dimension when the user didn't lock it but strict mode\n\t// is on — first upsert sets it; subsequent mismatches throw.\n\tlet inferredDimension: number | undefined;\n\tfunction assertDimension(vector: readonly number[]): void {\n\t\tif (dimension !== undefined) {\n\t\t\tif (vector.length !== dimension) {\n\t\t\t\tthrow new RangeError(\n\t\t\t\t\t`vector dimension mismatch: expected ${dimension}, got ${vector.length}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (!strictDimension) return;\n\t\tif (inferredDimension === undefined) {\n\t\t\tinferredDimension = vector.length;\n\t\t\treturn;\n\t\t}\n\t\tif (vector.length !== inferredDimension) {\n\t\t\tthrow new RangeError(\n\t\t\t\t`vector dimension mismatch: inferred ${inferredDimension} from first upsert, got ${vector.length}. ` +\n\t\t\t\t\t`Pass \\`strictDimension: false\\` to opt into zero-pad behavior, or set an explicit \\`dimension\\`.`,\n\t\t\t);\n\t\t}\n\t}\n\n\tconst baseRetentionScore = userRetentionScore ?? ((r: VectorRecord<TMeta>) => r.upsertedAtNs);\n\t// `clearInProgress` lets us short-circuit the per-entry `onArchive` →\n\t// `hnsw.remove(id)` cascade when the user calls `clearImpl()`. Retention\n\t// fires `onArchive` for every evicted entry; followed by an explicit\n\t// `hnsw.clear()` we'd double-touch the adapter. Inside `clearImpl` we\n\t// flip this flag, then call `hnsw.clear()` once at the end. (G fix.)\n\tlet clearInProgress = false;\n\n\t// `clearAuditPending` defers the per-entry `evict` audit emission when a\n\t// `clear()` is in flight — those evictions are reported as a single\n\t// `clear` action, not a flurry of `evict` records.\n\tconst events = createAuditLog<VectorIndexAuditRecord>({\n\t\tname: \"events\",\n\t\tretainedLimit: 1024,\n\t\tgraph,\n\t});\n\tconst seqCursor = registerCursor(graph, \"seq\", 0);\n\n\tconst entries = reactiveMap<string, VectorRecord<TMeta>>({\n\t\tname: \"entries\",\n\t\t...(maxSize !== undefined\n\t\t\t? {\n\t\t\t\t\tretention: {\n\t\t\t\t\t\tscore: (_k, v) => baseRetentionScore(v),\n\t\t\t\t\t\tmaxSize,\n\t\t\t\t\t\tonArchive: (key) => {\n\t\t\t\t\t\t\tif (clearInProgress) return;\n\t\t\t\t\t\t\tif (backend === \"hnsw\") hnsw!.remove(key);\n\t\t\t\t\t\t\t// E1: surface retention-driven evictions in the audit log\n\t\t\t\t\t\t\t// so replay consumers can reconstruct the live snapshot\n\t\t\t\t\t\t\t// from `events` alone. `seq` is bumped via the cursor;\n\t\t\t\t\t\t\t// the `t_ns` matches `wallClockNs()` for consistency\n\t\t\t\t\t\t\t// with `lightMutation`'s record stamping.\n\t\t\t\t\t\t\tevents.append({\n\t\t\t\t\t\t\t\taction: \"evict\" as const,\n\t\t\t\t\t\t\t\tid: key,\n\t\t\t\t\t\t\t\tt_ns: wallClockNs(),\n\t\t\t\t\t\t\t\tseq: bumpCursor(seqCursor),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t: {}),\n\t});\n\tgraph.add(entries.entries, { name: \"entries\" });\n\t// F1: keep `entries` warm so downstream consumers reading\n\t// `vectors.entries.cache` (e.g. `patterns/ai/memory/runRetrieval`) don't\n\t// rely on an external subscriber to activate the node. State nodes are\n\t// ROM and retain `.cache` regardless of subscribers — this `keepalive`\n\t// is defense-in-depth and matches the kg's adjacency keepalive pattern.\n\tgraph.addDisposer(keepalive(entries.entries));\n\n\t// HNSW dispose runs BEFORE state-node teardown via standard disposer\n\t// ordering (disposers drain first, then `[[TEARDOWN]]` propagates per\n\t// `Graph.destroy()`). This is the right ordering: free the adapter's\n\t// native resources before the reactive layer tears down.\n\tif (hnsw?.dispose) {\n\t\tconst disposeAdapter = hnsw.dispose.bind(hnsw);\n\t\tgraph.addDisposer(() => disposeAdapter());\n\t}\n\n\tconst upsertImpl = (id: string, vector: readonly number[], meta?: TMeta): void => {\n\t\tassertDimension(vector);\n\t\t// B1: mutate HNSW first so a throw aborts the reactive write. With\n\t\t// the prior order (entries.set then hnsw.upsert), an adapter throw\n\t\t// would leave entries holding a row HNSW didn't index. Now: HNSW\n\t\t// commits first; if it throws, entries is untouched and audit log\n\t\t// records the failure.\n\t\tif (backend === \"hnsw\") hnsw!.upsert(id, vector, meta);\n\t\t// Defensive copies: vector via `[...vector]`; meta via shallow spread\n\t\t// when it's a non-null object (Array.isArray covered first since arrays\n\t\t// are objects). Primitives, `null`, functions etc. pass through\n\t\t// unchanged. Documented depth limitation: nested objects in `meta` are\n\t\t// shared by reference.\n\t\tconst copiedMeta: TMeta | undefined = (() => {\n\t\t\tif (meta === undefined) return undefined;\n\t\t\tif (meta === null || typeof meta !== \"object\") return meta;\n\t\t\treturn Array.isArray(meta) ? ([...meta] as unknown as TMeta) : ({ ...meta } as TMeta);\n\t\t})();\n\t\tconst record: VectorRecord<TMeta> = {\n\t\t\tid,\n\t\t\tvector: [...vector],\n\t\t\t...(copiedMeta !== undefined ? { meta: copiedMeta } : {}),\n\t\t\tupsertedAtNs: monotonicNs(),\n\t\t};\n\t\tentries.set(id, record);\n\t};\n\tconst removeImpl = (id: string): void => {\n\t\tif (!entries.has(id)) return;\n\t\t// B1: HNSW first, then entries.\n\t\tif (backend === \"hnsw\") hnsw!.remove(id);\n\t\tentries.delete(id);\n\t};\n\tconst clearImpl = (): void => {\n\t\tif (entries.size === 0) return;\n\t\t// B1 + G: mark the clear-in-progress flag so retention `onArchive`\n\t\t// suppresses per-entry HNSW removes AND per-entry `evict` audit\n\t\t// records. Then call `entries.clear()` (drains the backend through\n\t\t// retention archival without side effects), and finally call\n\t\t// `hnsw.clear()` once. Reset `inferredDimension` so a fresh start\n\t\t// re-infers from the next upsert.\n\t\tclearInProgress = true;\n\t\ttry {\n\t\t\tentries.clear();\n\t\t\tif (backend === \"hnsw\") hnsw!.clear();\n\t\t} finally {\n\t\t\tclearInProgress = false;\n\t\t}\n\t\tinferredDimension = undefined;\n\t};\n\tconst reindexImpl = (): void => {\n\t\tif (backend !== \"hnsw\") return;\n\t\tconst snapshot = entries.entries.cache as ReadonlyMap<string, VectorRecord<TMeta>> | undefined;\n\t\tif (!snapshot) return;\n\t\thnsw!.clear();\n\t\tfor (const r of snapshot.values()) {\n\t\t\thnsw!.upsert(r.id, r.vector, r.meta);\n\t\t}\n\t};\n\n\t// `freeze: false` for `upsert` — deep-freezing a 768-dim vector is a\n\t// measurable hot-path tax, and the wrapper does its own defensive copy\n\t// (`vector: [...vector]`) before persisting. See §B.2 of the audit lock.\n\tconst upsert = mutate(upsertImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tfreeze: false,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([id], _r, m) => ({ action: \"upsert\" as const, id, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\tconst remove = mutate(removeImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([id], _r, m) => ({ action: \"remove\" as const, id, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\tconst clear = mutate(clearImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: (_args, _r, m) => ({ action: \"clear\" as const, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\tconst reindex = mutate(reindexImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: (_args, _r, m) => ({ action: \"reindex\" as const, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\n\tfunction searchNode(\n\t\tquery: Node<readonly number[]>,\n\t\tk: NodeOrValue<number> = 5,\n\t): Node<readonly VectorSearchResult<TMeta>[]> {\n\t\tconst kN = toNode<number>(k, \"k\");\n\t\treturn node(\n\t\t\t[entries.entries, query, kN],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst values = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst snapshot = values[0] as ReadonlyMap<string, VectorRecord<TMeta>> | undefined;\n\t\t\t\tconst q = values[1] as readonly number[] | undefined;\n\t\t\t\tconst kRaw = values[2] as number;\n\t\t\t\t// Auto-fix: `Math.max(0, Math.floor(k))` — `| 0` is a 32-bit\n\t\t\t\t// signed truncation that collapses Infinity to 0 and wraps\n\t\t\t\t// values > 2^31. Use a proper floor with a non-negative floor.\n\t\t\t\tconst kVal = Number.isFinite(kRaw) ? Math.max(0, Math.floor(kRaw)) : 0;\n\t\t\t\tif (!snapshot || snapshot.size === 0 || kVal <= 0) {\n\t\t\t\t\tactions.emit([] as readonly VectorSearchResult<TMeta>[]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// Auto-fix: defensive guard for unset / empty query — earlier\n\t\t\t\t// the fn would TypeError on `q.length` reading `undefined`,\n\t\t\t\t// or compute meaningless all-zero scores against an empty\n\t\t\t\t// vector. With strict-dimension OR an explicit `dimension`,\n\t\t\t\t// also reject mismatched-length queries (the imperative path\n\t\t\t\t// used to throw; reactive deriveds shouldn't throw, so\n\t\t\t\t// degrade to empty results).\n\t\t\t\tif (q == null || q.length === 0) {\n\t\t\t\t\tactions.emit([] as readonly VectorSearchResult<TMeta>[]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst expectedDim = dimension ?? (strictDimension ? inferredDimension : undefined);\n\t\t\t\tif (expectedDim !== undefined && q.length !== expectedDim) {\n\t\t\t\t\tactions.emit([] as readonly VectorSearchResult<TMeta>[]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (backend === \"hnsw\") {\n\t\t\t\t\t// Defensive copy of the adapter's return — HNSW libs\n\t\t\t\t\t// sometimes hand back internal buffers; downstream\n\t\t\t\t\t// subscribers must not be able to corrupt adapter state.\n\t\t\t\t\tconst adapterResults = hnsw!.search(q, kVal);\n\t\t\t\t\tactions.emit([...adapterResults] as readonly VectorSearchResult<TMeta>[]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst ranked = [...snapshot.values()]\n\t\t\t\t\t.map((row) => {\n\t\t\t\t\t\tconst result: VectorSearchResult<TMeta> = {\n\t\t\t\t\t\t\tid: row.id,\n\t\t\t\t\t\t\tscore: cosineSimilarity(q, row.vector),\n\t\t\t\t\t\t\t...(row.meta !== undefined ? { meta: row.meta } : {}),\n\t\t\t\t\t\t};\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t})\n\t\t\t\t\t.sort((a, b) => b.score - a.score)\n\t\t\t\t\t.slice(0, kVal);\n\t\t\t\tactions.emit(ranked as readonly VectorSearchResult<TMeta>[]);\n\t\t\t},\n\t\t\t{\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\t// A1: include `score` in equality. The previous id-only\n\t\t\t\t// comparator suppressed re-emissions when the same set of\n\t\t\t\t// IDs/order had different scores (re-upsert with new\n\t\t\t\t// vector; query change preserving ranking order).\n\t\t\t\tequals: (a, b) => searchResultsEqual(a, b),\n\t\t\t\tmeta: memoryMeta(\"vector_search\"),\n\t\t\t},\n\t\t) as Node<readonly VectorSearchResult<TMeta>[]>;\n\t}\n\n\tconst out = Object.assign(graph, {\n\t\tbackend,\n\t\tevents,\n\t\tentries: entries.entries,\n\t\tupsert,\n\t\tremove,\n\t\tclear,\n\t\treindex,\n\t\tsearchNode,\n\t}) as VectorIndexGraph<TMeta>;\n\treturn out;\n}\n\n// ── Unit 5: knowledgeGraph ───────────────────────────────────────────────\n\nexport type KnowledgeEdge<TRelation extends string = string> = {\n\treadonly from: string;\n\treadonly to: string;\n\treadonly relation: TRelation;\n\treadonly weight: number;\n};\n\nexport type KnowledgeGraphOptions = {\n\t/** Cap on entity count (LRU-by-upsert-time when set). */\n\tentitiesMaxSize?: number;\n\t/** Cap on edge count (LRU-by-upsert-time when set). */\n\tedgesMaxSize?: number;\n\t/**\n\t * Orphan-entity garbage collection. `\"keep\"` (default) leaves entities\n\t * untouched when their last edge is unlinked; `\"remove\"` deletes the\n\t * entity post-`unlink` if no edges reference it.\n\t */\n\torphanGC?: \"keep\" | \"remove\";\n};\n\nexport interface KnowledgeGraphAuditRecord extends BaseAuditRecord {\n\treadonly action: \"upsertEntity\" | \"removeEntity\" | \"link\" | \"unlink\" | \"orphanRemove\";\n\treadonly id?: string;\n\treadonly from?: string;\n\treadonly to?: string;\n\treadonly relation?: string;\n\t/** Edge weight at the time of the `link`. Omitted for non-edge actions. */\n\treadonly weight?: number;\n}\n\nexport type KnowledgeGraph<TEntity, TRelation extends string = string> = Graph & {\n\treadonly events: ReactiveLogBundle<KnowledgeGraphAuditRecord>;\n\treadonly entities: Node<ReadonlyMap<string, TEntity>>;\n\treadonly edges: Node<ReadonlyMap<string, KnowledgeEdge<TRelation>>>;\n\treadonly adjacencyOut: Node<ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>>;\n\treadonly adjacencyIn: Node<ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>>;\n\treadonly entityCount: Node<number>;\n\treadonly edgeCount: Node<number>;\n\tupsertEntity: (id: string, value: TEntity) => void;\n\tremoveEntity: (id: string) => void;\n\tlink: (from: string, to: string, relation: TRelation, weight?: number) => void;\n\tunlink: (from: string, to: string, relation?: TRelation) => void;\n\trelatedNode: (\n\t\tid: NodeOrValue<string>,\n\t\trelation?: NodeOrValue<TRelation>,\n\t) => Node<readonly KnowledgeEdge<TRelation>[]>;\n};\n\nconst TRIPLE_SEP = \"\u0000\";\nfunction tripleKey(from: string, to: string, relation: string): string {\n\treturn `${from}${TRIPLE_SEP}${to}${TRIPLE_SEP}${relation}`;\n}\n\nfunction buildAdjacency<TRelation extends string>(\n\tedges: ReadonlyMap<string, KnowledgeEdge<TRelation>> | undefined,\n\tside: \"from\" | \"to\",\n): ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]> {\n\tif (!edges || edges.size === 0) return new Map();\n\tconst buckets = new Map<string, KnowledgeEdge<TRelation>[]>();\n\tfor (const edge of edges.values()) {\n\t\tconst key = side === \"from\" ? edge.from : edge.to;\n\t\tlet bucket = buckets.get(key);\n\t\tif (!bucket) {\n\t\t\tbucket = [];\n\t\t\tbuckets.set(key, bucket);\n\t\t}\n\t\tbucket.push(edge);\n\t}\n\tconst out = new Map<string, readonly KnowledgeEdge<TRelation>[]>();\n\tfor (const [key, bucket] of buckets) out.set(key, Object.freeze(bucket));\n\treturn out;\n}\n\nfunction adjacencyEqual<TRelation extends string>(\n\ta: ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]> | undefined,\n\tb: ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]> | undefined,\n): boolean {\n\tif (a === b) return true;\n\tif (a == null || b == null) return false;\n\tif (a.size !== b.size) return false;\n\tfor (const [k, av] of a) {\n\t\tconst bv = b.get(k);\n\t\tif (!bv || av.length !== bv.length) return false;\n\t\tfor (let i = 0; i < av.length; i += 1) {\n\t\t\tconst ae = av[i]!;\n\t\t\tconst be = bv[i]!;\n\t\t\tif (\n\t\t\t\tae.from !== be.from ||\n\t\t\t\tae.to !== be.to ||\n\t\t\t\tae.relation !== be.relation ||\n\t\t\t\tae.weight !== be.weight\n\t\t\t)\n\t\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n\n/**\n * Reactive knowledge graph: entities + typed edges + symmetric adjacency.\n *\n * Topology (mounted on the returned graph):\n * - `entities` — `reactiveMap<id, TEntity>` (optional `entitiesMaxSize` LRU).\n * - `edges` — `reactiveMap<tripleKey, KnowledgeEdge<TRelation>>` keyed by\n * `${from}\u0000${to}\u0000${relation}` (optional `edgesMaxSize` LRU).\n * Entity IDs / relations must NOT contain `\u0000`.\n * - `adjacencyOut` — `Node<ReadonlyMap<from, readonly edge[]>>`. **Full O(E)\n * rebuild on every `link` / `unlink` mutation.** (Prior JSDoc claim of\n * \"O(E) build\" referred to a single rebuild — the per-mutation cost is\n * O(E), not O(1) amortized. For very large graphs with frequent edge\n * churn, consider batching via `reactiveMap.setMany`.)\n * - `adjacencyIn` — `Node<ReadonlyMap<to, readonly edge[]>>`. Same O(E) per\n * mutation rebuild characteristic.\n * - `entityCount` / `edgeCount` — observability deriveds.\n * - `events` — bounded reactive audit log.\n *\n * **`link()` semantics.** Calling `link(a, b, rel, w)` twice with different\n * weights replaces the weight on the existing edge (keyed by the triple).\n * `unlink` then `link` re-creates the edge (and bumps `lastUpsertNs` for\n * retention purposes).\n *\n * **Edge weight convention.** Higher weight = stronger relation. Default `1`.\n *\n * **Orphan GC.** `orphanGC: \"remove\"` deletes an entity from `entities` after\n * an `unlink` that empties its adjacency on both sides. Default `\"keep\"`.\n *\n * **No imperative reads.** Use `relatedNode(id, relation?)` for reactive reads.\n *\n * @category memory\n */\nexport function knowledgeGraph<TEntity, TRelation extends string = string>(\n\tname: string,\n\topts: KnowledgeGraphOptions = {},\n): KnowledgeGraph<TEntity, TRelation> {\n\tconst orphanGC = opts.orphanGC ?? \"keep\";\n\tif (opts.entitiesMaxSize !== undefined && opts.entitiesMaxSize < 1) {\n\t\tthrow new RangeError(\"knowledgeGraph: entitiesMaxSize must be >= 1\");\n\t}\n\tif (opts.edgesMaxSize !== undefined && opts.edgesMaxSize < 1) {\n\t\tthrow new RangeError(\"knowledgeGraph: edgesMaxSize must be >= 1\");\n\t}\n\n\tconst graph = new Graph(name);\n\n\tconst entitiesMap = reactiveMap<string, TEntity>({\n\t\tname: \"entities\",\n\t\t...(opts.entitiesMaxSize !== undefined ? { maxSize: opts.entitiesMaxSize } : {}),\n\t});\n\tconst edgesMap = reactiveMap<string, KnowledgeEdge<TRelation>>({\n\t\tname: \"edges\",\n\t\t...(opts.edgesMaxSize !== undefined ? { maxSize: opts.edgesMaxSize } : {}),\n\t});\n\tgraph.add(entitiesMap.entries, { name: \"entities\" });\n\tgraph.add(edgesMap.entries, { name: \"edges\" });\n\n\tconst adjacencyOut = node(\n\t\t[edgesMap.entries],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst snapshot = data[0] as ReadonlyMap<string, KnowledgeEdge<TRelation>> | undefined;\n\t\t\tactions.emit(buildAdjacency<TRelation>(snapshot, \"from\"));\n\t\t},\n\t\t{\n\t\t\tname: \"adjacencyOut\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tinitial: new Map() as ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>,\n\t\t\tequals: adjacencyEqual,\n\t\t\tmeta: memoryMeta(\"adjacency_out\"),\n\t\t},\n\t) as Node<ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>>;\n\tconst adjacencyIn = node(\n\t\t[edgesMap.entries],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst snapshot = data[0] as ReadonlyMap<string, KnowledgeEdge<TRelation>> | undefined;\n\t\t\tactions.emit(buildAdjacency<TRelation>(snapshot, \"to\"));\n\t\t},\n\t\t{\n\t\t\tname: \"adjacencyIn\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tinitial: new Map() as ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>,\n\t\t\tequals: adjacencyEqual,\n\t\t\tmeta: memoryMeta(\"adjacency_in\"),\n\t\t},\n\t) as Node<ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>>;\n\tgraph.add(adjacencyOut, { name: \"adjacencyOut\" });\n\tgraph.add(adjacencyIn, { name: \"adjacencyIn\" });\n\tgraph.addDisposer(keepalive(adjacencyOut));\n\tgraph.addDisposer(keepalive(adjacencyIn));\n\n\tconst entityCount = node(\n\t\t[entitiesMap.entries],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst m = data[0] as ReadonlyMap<string, TEntity> | undefined;\n\t\t\tactions.emit(((m ?? new Map()) as ReadonlyMap<string, TEntity>).size);\n\t\t},\n\t\t{ name: \"entityCount\", describeKind: \"derived\", initial: 0, meta: memoryMeta(\"entity_count\") },\n\t);\n\tconst edgeCount = node(\n\t\t[edgesMap.entries],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst m = data[0] as ReadonlyMap<string, KnowledgeEdge<TRelation>> | undefined;\n\t\t\tactions.emit(((m ?? new Map()) as ReadonlyMap<string, KnowledgeEdge<TRelation>>).size);\n\t\t},\n\t\t{ name: \"edgeCount\", describeKind: \"derived\", initial: 0, meta: memoryMeta(\"edge_count\") },\n\t);\n\tgraph.add(entityCount, { name: \"entityCount\" });\n\tgraph.add(edgeCount, { name: \"edgeCount\" });\n\tgraph.addDisposer(keepalive(entityCount));\n\tgraph.addDisposer(keepalive(edgeCount));\n\n\tconst events = createAuditLog<KnowledgeGraphAuditRecord>({\n\t\tname: \"events\",\n\t\tretainedLimit: 1024,\n\t\tgraph,\n\t});\n\tconst seqCursor = registerCursor(graph, \"seq\", 0);\n\n\t/**\n\t * O(1) orphan check via the kept-warm `adjacency*` deriveds. Reading\n\t * `adjacencyOut.cache` / `adjacencyIn.cache` is safe here because both\n\t * are activated via `addDisposer(keepalive(...))` at construction time\n\t * (a derived's RAM cache only persists with at least one subscriber, and\n\t * the keepalive registers exactly that). The previous implementation\n\t * scanned `edgesMap.entries.cache` post-`deleteMany`, which depended on\n\t * the (sync) snapshot-emit timing of `reactiveMap` — fragile. The\n\t * `adjacency*.cache` approach is both faster (O(1) vs O(E) per check)\n\t * and timing-robust because the reactiveMap snapshot has already\n\t * propagated through the derived chain by the time we read.\n\t */\n\tfunction entityHasReferences(id: string): boolean {\n\t\tconst out = adjacencyOut.cache as\n\t\t\t| ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>\n\t\t\t| undefined;\n\t\tconst inb = adjacencyIn.cache as\n\t\t\t| ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>\n\t\t\t| undefined;\n\t\tif ((out?.get(id)?.length ?? 0) > 0) return true;\n\t\tif ((inb?.get(id)?.length ?? 0) > 0) return true;\n\t\treturn false;\n\t}\n\n\t/**\n\t * Apply orphan GC to a list of candidate entity ids. Used by both\n\t * {@link unlinkImpl} (post-edge-removal) and {@link removeEntityImpl}\n\t * (post-cascade) so semantics are consistent. Each removed entity\n\t * records a separate `orphanRemove` audit entry with its own monotonic\n\t * `seq` value (D1 fix — the previous bare `events.append(...)` skipped\n\t * the cursor advance, leaving gaps in the audit replay sequence).\n\t */\n\tfunction applyOrphanGC(candidates: readonly string[]): void {\n\t\tif (orphanGC !== \"remove\") return;\n\t\tfor (const candidate of candidates) {\n\t\t\tif (!entitiesMap.has(candidate)) continue;\n\t\t\tif (entityHasReferences(candidate)) continue;\n\t\t\tentitiesMap.delete(candidate);\n\t\t\tevents.append({\n\t\t\t\taction: \"orphanRemove\" as const,\n\t\t\t\tid: candidate,\n\t\t\t\tt_ns: wallClockNs(),\n\t\t\t\tseq: bumpCursor(seqCursor),\n\t\t\t});\n\t\t}\n\t}\n\n\tconst upsertEntityImpl = (id: string, value: TEntity): void => {\n\t\tentitiesMap.set(id, value);\n\t};\n\tconst removeEntityImpl = (id: string): void => {\n\t\tconst snapshot = edgesMap.entries.cache as\n\t\t\t| ReadonlyMap<string, KnowledgeEdge<TRelation>>\n\t\t\t| undefined;\n\t\t// Collect both the edge-keys to drop AND the entity ids those edges\n\t\t// reference (other than `id` itself) — the latter become orphan-GC\n\t\t// candidates after the cascade. (C1 fix — the previous impl only\n\t\t// applied orphan GC inside `unlink`, so cascading entity removal\n\t\t// could leave dangling orphans.)\n\t\tconst cascadedNeighbors = new Set<string>();\n\t\tif (snapshot) {\n\t\t\tconst toDrop: string[] = [];\n\t\t\tfor (const [key, edge] of snapshot) {\n\t\t\t\tif (edge.from === id || edge.to === id) {\n\t\t\t\t\ttoDrop.push(key);\n\t\t\t\t\tif (edge.from !== id) cascadedNeighbors.add(edge.from);\n\t\t\t\t\tif (edge.to !== id) cascadedNeighbors.add(edge.to);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (toDrop.length > 0) edgesMap.deleteMany(toDrop);\n\t\t}\n\t\tif (entitiesMap.has(id)) entitiesMap.delete(id);\n\t\tapplyOrphanGC([...cascadedNeighbors]);\n\t};\n\tconst linkImpl = (from: string, to: string, relation: TRelation, weight = 1): void => {\n\t\tedgesMap.set(tripleKey(from, to, relation), { from, to, relation, weight });\n\t};\n\tconst unlinkImpl = (from: string, to: string, relation?: TRelation): void => {\n\t\tif (relation !== undefined) {\n\t\t\tedgesMap.delete(tripleKey(from, to, relation));\n\t\t} else {\n\t\t\tconst snapshot = edgesMap.entries.cache as\n\t\t\t\t| ReadonlyMap<string, KnowledgeEdge<TRelation>>\n\t\t\t\t| undefined;\n\t\t\tif (!snapshot) return;\n\t\t\tconst toDrop: string[] = [];\n\t\t\tfor (const [key, edge] of snapshot) {\n\t\t\t\tif (edge.from === from && edge.to === to) toDrop.push(key);\n\t\t\t}\n\t\t\tif (toDrop.length > 0) edgesMap.deleteMany(toDrop);\n\t\t}\n\t\tapplyOrphanGC([from, to]);\n\t};\n\n\tconst upsertEntity = mutate(upsertEntityImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([id], _r, m) => ({\n\t\t\taction: \"upsertEntity\" as const,\n\t\t\tid,\n\t\t\tt_ns: m.t_ns,\n\t\t\tseq: m.seq,\n\t\t}),\n\t});\n\tconst removeEntity = mutate(removeEntityImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([id], _r, m) => ({\n\t\t\taction: \"removeEntity\" as const,\n\t\t\tid,\n\t\t\tt_ns: m.t_ns,\n\t\t\tseq: m.seq,\n\t\t}),\n\t});\n\tconst link = mutate(linkImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([from, to, relation, weight], _r, m) => ({\n\t\t\taction: \"link\" as const,\n\t\t\tfrom,\n\t\t\tto,\n\t\t\trelation: relation as string,\n\t\t\tweight: weight ?? 1,\n\t\t\tt_ns: m.t_ns,\n\t\t\tseq: m.seq,\n\t\t}),\n\t});\n\tconst unlink = mutate(unlinkImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([from, to, relation], _r, m) => ({\n\t\t\taction: \"unlink\" as const,\n\t\t\tfrom,\n\t\t\tto,\n\t\t\t...(relation !== undefined ? { relation: relation as string } : {}),\n\t\t\tt_ns: m.t_ns,\n\t\t\tseq: m.seq,\n\t\t}),\n\t});\n\n\tfunction relatedNode(\n\t\tid: NodeOrValue<string>,\n\t\trelation?: NodeOrValue<TRelation>,\n\t): Node<readonly KnowledgeEdge<TRelation>[]> {\n\t\tconst idN = toNode(id, \"id\");\n\t\t// `relation` is OPTIONAL. We deliberately do NOT include it as a dep\n\t\t// when omitted — `state(undefined)` would be a SENTINEL and the\n\t\t// derived's first-run gate would never open. Callers pass a Node\n\t\t// when they want reactive filtering; pass a value to lock the\n\t\t// filter; omit to disable filtering.\n\t\tconst relN = relation !== undefined ? toNode(relation, \"relation\") : undefined;\n\t\tconst deps: Node<unknown>[] = relN\n\t\t\t? [adjacencyOut, adjacencyIn, idN, relN]\n\t\t\t: [adjacencyOut, adjacencyIn, idN];\n\t\treturn node(\n\t\t\tdeps,\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst values = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst out = values[0] as ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>;\n\t\t\t\tconst inb = values[1] as ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>;\n\t\t\t\tconst key = values[2] as string;\n\t\t\t\tconst rel = relN ? (values[3] as TRelation | undefined) : undefined;\n\t\t\t\tconst outE = out?.get(key) ?? [];\n\t\t\t\tconst inE = inb?.get(key) ?? [];\n\t\t\t\t// Concatenate, then dedupe by triple key (a self-loop would appear in both).\n\t\t\t\tconst seen = new Set<string>();\n\t\t\t\tconst acc: KnowledgeEdge<TRelation>[] = [];\n\t\t\t\tfor (const edge of outE) {\n\t\t\t\t\tconst k = tripleKey(edge.from, edge.to, edge.relation);\n\t\t\t\t\tif (seen.has(k)) continue;\n\t\t\t\t\tif (rel !== undefined && edge.relation !== rel) continue;\n\t\t\t\t\tseen.add(k);\n\t\t\t\t\tacc.push(edge);\n\t\t\t\t}\n\t\t\t\tfor (const edge of inE) {\n\t\t\t\t\tconst k = tripleKey(edge.from, edge.to, edge.relation);\n\t\t\t\t\tif (seen.has(k)) continue;\n\t\t\t\t\tif (rel !== undefined && edge.relation !== rel) continue;\n\t\t\t\t\tseen.add(k);\n\t\t\t\t\tacc.push(edge);\n\t\t\t\t}\n\t\t\t\tactions.emit(acc as readonly KnowledgeEdge<TRelation>[]);\n\t\t\t},\n\t\t\t{\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tequals: (a, b) => {\n\t\t\t\t\tconst av = a as readonly KnowledgeEdge<TRelation>[] | undefined;\n\t\t\t\t\tconst bv = b as readonly KnowledgeEdge<TRelation>[] | undefined;\n\t\t\t\t\tif (av === bv) return true;\n\t\t\t\t\tif (av == null || bv == null) return false;\n\t\t\t\t\tif (av.length !== bv.length) return false;\n\t\t\t\t\tfor (let i = 0; i < av.length; i += 1) {\n\t\t\t\t\t\tconst x = av[i]!;\n\t\t\t\t\t\tconst y = bv[i]!;\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tx.from !== y.from ||\n\t\t\t\t\t\t\tx.to !== y.to ||\n\t\t\t\t\t\t\tx.relation !== y.relation ||\n\t\t\t\t\t\t\tx.weight !== y.weight\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t},\n\t\t\t\tmeta: memoryMeta(\"related\"),\n\t\t\t},\n\t\t) as Node<readonly KnowledgeEdge<TRelation>[]>;\n\t}\n\n\tconst out = Object.assign(graph, {\n\t\tevents,\n\t\tentities: entitiesMap.entries,\n\t\tedges: edgesMap.entries,\n\t\tadjacencyOut,\n\t\tadjacencyIn,\n\t\tentityCount,\n\t\tedgeCount,\n\t\tupsertEntity,\n\t\tremoveEntity,\n\t\tlink,\n\t\tunlink,\n\t\trelatedNode,\n\t}) as KnowledgeGraph<TEntity, TRelation>;\n\treturn out;\n}\n\n// ── DS-14.7: reactiveFactStore (static-topology MEME L2/L3 substrate) ─────\n// Lives in its own file (`fact-store.ts`) — re-exported here so the\n// `utils/memory` barrel stays the single import surface alongside\n// collection / vectorIndex / knowledgeGraph.\nexport {\n\ttype AdmissionFilter,\n\ttype CascadeEvent,\n\ttype CascadeOverflow,\n\ttype CascadeReason,\n\ttype DecayPolicy,\n\ttype DependentsIndex,\n\ttype FactId,\n\ttype FactStore,\n\ttype FactStoreAuditRecord,\n\ttype MemoryAnswer,\n\ttype MemoryFragment,\n\ttype MemoryQuery,\n\ttype OutcomeSignal,\n\ttype ReactiveFactStoreConfig,\n\ttype ReactiveFactStoreGraph,\n\ttype ReviewRequest,\n\treactiveFactStore,\n\ttype ScoringPolicy,\n\ttype ShardKey,\n\ttype StoreReadHandle,\n} from \"./fact-store.js\";\n","/**\n * DS-14.7 — Reactive Fact Store / Live Knowledge Graph (locked 2026-05-13).\n *\n * Static-topology agent-memory substrate that satisfies MEME L2 (cascade\n * invalidation) and L3 (obsolescence reasoning) plus Hassabis's\n * filter/consolidate/continual-learning frame, **without** materializing one\n * reactive node per fact. ~12 fixed operator nodes never grow regardless of how\n * many facts the store holds; facts live as columnar DATA inside an indexed\n * `state<FactStore>` (optionally sharded), and cascade is implemented as\n * bounded recursive message emission. Termination rests on a per-root\n * semantic contract — a fact only drives the cascade when it transitions to\n * obsolete (`validTo` set), and each obsolete root emits its cascade exactly\n * once across all waves — plus an empty-array fixpoint short-circuit. The\n * cascade is modeled as DATA arrays (NOT INVALIDATE messages), so spec §1.4's\n * idempotent-within-a-wave INVALIDATE guarantee does NOT govern this loop;\n * convergence is the per-root contract, not a spec §1.4 diamond-merge.\n *\n * Canonical design: `archive/docs/SESSION-DS-14.7-reactive-fact-store.md`\n * (9Q walk complete; Q9-open items 1–9 all resolved).\n *\n * Locked decisions baked in here:\n * - `cascadeMaxIterations` default **8**; overflow emits a per-batch summary\n * `{ droppedCount, sample, rootFactId }` to `cascadeOverflow` (Q9-open-4).\n * The overflow `sample` is capped at `OVERFLOW_SAMPLE_SIZE` (8),\n * independent of `cascadeMaxIterations`.\n * - `shardBy` default hash-mod **4**; caller override; `dependentsIndex`\n * unsharded for v1 (Q9-open-1).\n * - `MemoryFragment` adds `embedding? / parent_fragment_id? / provenance?`\n * (Q9-open-3).\n * - `dependentsIndex` updates synchronous + atomic with `factStore` commit\n * (Q9-open-2).\n * - Scoring contract `(fragment, storeReadHandle) => number` — read-only\n * handle, no mutation exposure (Q9-open-5).\n * - Consolidator emits to a dedicated `consolidated` topic that the pattern\n * default-wires back to `ingest`; caller can intercept (Q9-open-6).\n * - Query surface = structured `MemoryQuery` via the `query` topic (default);\n * function-shaped is caller-side `derived` over `factStore` (Q9-open-7).\n * - Bi-temporal is pattern-layer only — no DS-14 envelope shape change\n * (Q9-open-9); `simpleFactStore()` deferred to v1.1 (Q9-open-8 — NOT built).\n *\n * **Cascade cycle visibility.** `cascadeProcessor` stays synchronous (preserves\n * spec §1.4 batch-dedupe — LLM-driven dependency extraction lives UPSTREAM of\n * the cascade topic, never inside the recursion). Every cascade message carries\n * a `causalReason` field and the cycle nodes are tagged `meta.cycle:\"cascade\"`\n * so `describe()` / `explain()` surface the otherwise-invisible\n * `dependentsIndex` fn-body lookup.\n *\n * @module\n */\n\nimport { type Node, node, wallClockNs } from \"@graphrefly/pure-ts/core\";\nimport type { ReactiveLogBundle } from \"@graphrefly/pure-ts/extra\";\nimport { keepalive, reactiveLog } from \"@graphrefly/pure-ts/extra\";\nimport { Graph } from \"@graphrefly/pure-ts/graph\";\nimport { domainMeta } from \"../../base/meta/domain-meta.js\";\nimport {\n\ttype BaseAuditRecord,\n\tbumpCursor,\n\tcreateAuditLog,\n\tregisterCursor,\n} from \"../../base/mutation/index.js\";\n\n// ── Public types ─────────────────────────────────────────────────────────\n\n/** Stable identity for a stored fact. */\nexport type FactId = string;\n\n/** Shard partition key (string | number — any hashable scalar). */\nexport type ShardKey = string | number;\n\n/**\n * A single stored memory fact. Pattern convention only — NOT a spec primitive\n * and NOT a DS-14 envelope field (bi-temporal stays pattern-layer per\n * Q9-open-9). Each field is a reactive lever (see design PART 2.3):\n * `validTo` set → cascade fires; `confidence < θ` → review; `sources` →\n * `dependentsIndex` edges feeding cascade.\n */\nexport interface MemoryFragment<T> {\n\treadonly id: FactId;\n\treadonly payload: T;\n\t/** Transaction time (when learned). `bigint` ns (e.g. `BigInt(monotonicNs())`). */\n\treadonly t_ns: bigint;\n\t/** Valid-time start. `undefined` = unbounded past. */\n\treadonly validFrom?: bigint;\n\t/** Valid-time end. Setting this is the MEME L3 obsolescence lever. */\n\treadonly validTo?: bigint;\n\t/** Confidence 0..1. Dropping below the review threshold emits a review. */\n\treadonly confidence: number;\n\treadonly tags: readonly string[];\n\t/** Dependency edges — fact IDs this fact is derived from / depends on. */\n\treadonly sources: readonly FactId[];\n\t/** Optional dense embedding (recipes use it for retrieval). */\n\treadonly embedding?: readonly number[];\n\t/** Version-chain pointer — consolidator emits successor fragments. */\n\treadonly parent_fragment_id?: FactId;\n\t/** Free-form provenance string for audit. */\n\treadonly provenance?: string;\n}\n\n/**\n * Columnar in-memory store. Held as DATA inside a `state<FactStore<T>>` node\n * (one per shard). `byId` is the authoritative map; the typed companions are\n * kept for the recipe layer (`bitemporal-query`, `influence-analysis`) — v1\n * stores fragments directly and lazily projects columns on demand.\n */\nexport interface FactStore<T> {\n\treadonly byId: ReadonlyMap<FactId, MemoryFragment<T>>;\n}\n\n/** Reverse dependency index: fact → IDs that depend on it. Unsharded (v1). */\nexport type DependentsIndex = ReadonlyMap<FactId, readonly FactId[]>;\n\n/** Read-only projection passed to scoring policies (no mutation surface). */\nexport interface StoreReadHandle<T> {\n\tget(id: FactId): MemoryFragment<T> | undefined;\n\thas(id: FactId): boolean;\n\treadonly size: number;\n\tvalues(): IterableIterator<MemoryFragment<T>>;\n}\n\nexport type ScoringPolicy<T> = (fragment: MemoryFragment<T>, store: StoreReadHandle<T>) => number;\nexport type DecayPolicy = (confidence: number, ageNs: bigint) => number;\nexport type AdmissionFilter<T> = (fragment: MemoryFragment<T>) => boolean;\n\n/** Outcome / RL signal — write-back lever for continual learning. */\nexport interface OutcomeSignal {\n\treadonly factId: FactId;\n\treadonly reward: number;\n}\n\n/** Structured query (Q9-open-7 default surface). Serializable + inspectable. */\nexport interface MemoryQuery {\n\t/** Match any of these tags (OR). Omit for no tag filter. */\n\treadonly tags?: readonly string[];\n\t/** Bi-temporal \"as of\" — only facts valid at this instant. */\n\treadonly asOf?: bigint;\n\t/** Minimum confidence (inclusive). */\n\treadonly minConfidence?: number;\n\t/** Cap results (sorted by confidence desc, then t_ns desc). */\n\treadonly limit?: number;\n}\n\nexport interface MemoryAnswer<T> {\n\treadonly query: MemoryQuery;\n\treadonly results: readonly MemoryFragment<T>[];\n}\n\nexport type CascadeReason = \"cascade\" | \"obsolete\" | \"manual\";\n\n/** A single cascade invalidation message flowing through the cascade cycle. */\nexport interface CascadeEvent {\n\treadonly factId: FactId;\n\treadonly rootFactId: FactId;\n\treadonly reason: CascadeReason;\n\t/**\n\t * The triggering root fact's own `validTo`. Cascade-invalidated dependents\n\t * inherit this (NOT a fresh wall-clock read), so the store is a\n\t * deterministic rebuildable projection: replaying the same ingest stream\n\t * yields byte-identical `validTo` on cascade-invalidated fragments. Each\n\t * dependent inherits the `validTo` of the *nearest obsolete fact that\n\t * drove its invalidation*: in a pure chain A→B→C where only A is\n\t * explicitly obsoleted, B and C both inherit A's `validTo` (B has no own\n\t * `validTo`, so when B becomes a cascade root the detector reads\n\t * `B.validTo` === A's value). If an intermediate B is itself explicitly\n\t * obsoleted with its *own* `validTo`, B's dependents inherit B's value,\n\t * not A's — \"stale from when its driving source was invalidated.\"\n\t * Deterministic either way. Always defined: only obsolete facts\n\t * (`validTo` set) drive the cascade as roots.\n\t */\n\treadonly rootValidTo: bigint;\n\t/** Cascade recursion depth (1 = first wave). Bounded by `cascadeMaxIterations`. */\n\treadonly iteration: number;\n\t/**\n\t * Human-readable causal chain — makes the `dependentsIndex` fn-body lookup\n\t * visible in `explain()` output even though it is not a topology edge\n\t * (design Q3 / COMPOSITION-GUIDE §24 mitigation).\n\t */\n\treadonly causalReason: string;\n}\n\n/** Per-batch overflow summary (Q9-open-4 — never per-message). */\nexport interface CascadeOverflow {\n\treadonly droppedCount: number;\n\treadonly sample: readonly FactId[];\n\treadonly rootFactId: FactId;\n}\n\nexport interface ReviewRequest {\n\treadonly factId: FactId;\n\treadonly confidence: number;\n\treadonly threshold: number;\n}\n\nexport interface FactStoreAuditRecord extends BaseAuditRecord {\n\treadonly action: \"ingest\" | \"invalidate\" | \"outcome\" | \"consolidate\" | \"overflow\";\n\treadonly id?: FactId;\n\treadonly reason?: CascadeReason;\n}\n\nexport interface ReactiveFactStoreConfig<T> {\n\t// ① Function hooks (no reactive policy needed).\n\treadonly extractDependencies: (f: MemoryFragment<T>) => readonly FactId[];\n\t/** Shard partition fn. Default: FNV-1a hash of `id` mod `shardCount`. */\n\treadonly shardBy?: (f: MemoryFragment<T>) => ShardKey;\n\t/** Shard count for the default hash-mod sharder. Default 4 (§3.2). */\n\treadonly shardCount?: number;\n\n\t// ② Node<Policy> hooks (reactive — policy itself can evolve).\n\treadonly scoring?: Node<ScoringPolicy<T>>;\n\treadonly decay?: Node<DecayPolicy>;\n\treadonly admissionFilter?: Node<AdmissionFilter<T>>;\n\n\t// ③ Topic inputs (caller wires upstream sources).\n\treadonly ingest: Node<MemoryFragment<T>>;\n\treadonly outcome?: Node<OutcomeSignal>;\n\treadonly query?: Node<MemoryQuery>;\n\t/**\n\t * Consolidator trigger — a reactive timer/cron Node (e.g. `fromCron(...)`).\n\t * When supplied, the `consolidated` node maps each tick to summarized\n\t * fragments emitted on the `consolidated` topic and default-wired back to\n\t * the internal ingest path.\n\t */\n\treadonly consolidateTrigger?: Node<unknown>;\n\t/**\n\t * Consolidation summarizer. Reads a store snapshot, returns successor\n\t * fragments (typically with `parent_fragment_id` set). Default: no-op\n\t * (emits nothing) so the cron tick is observable without forcing a policy.\n\t */\n\treadonly consolidate?: (store: StoreReadHandle<T>) => readonly MemoryFragment<T>[];\n\n\t// Invariants.\n\t/** Cascade recursion cap (§3.1). Default 8. */\n\treadonly cascadeMaxIterations?: number;\n\t/** Confidence below which a {@link ReviewRequest} is emitted. Default 0.3. */\n\treadonly reviewThreshold?: number;\n\n\t// Persistence.\n\t/**\n\t * Record every committed fragment (post-admission-filter, with full\n\t * payload) into a replayable {@link ReactiveFactStoreGraph.ingestLog}.\n\t * Default `false` (the log retains every fragment in memory — opt in only\n\t * when you intend to persist + replay).\n\t *\n\t * Enables the canonical **rebuildable-projection** recipe: the store is a\n\t * deterministic projection of its ingest stream (cascade `validTo` is\n\t * derived from the triggering root, not wall-clock; consolidator successors\n\t * are re-derived from replayed state, not logged — the projection is still\n\t * deterministic), so persisting the ingest log and replaying it on restart\n\t * reconstructs a byte-identical store. Pair with the BigInt-safe codec\n\t * ({@link MemoryFragment} carries `bigint` time fields). The tier MUST be\n\t * `mode:\"append\"` (the default) — `attachStorage` ships per-wave deltas, so\n\t * an `\"overwrite\"` tier would truncate the log (and `attachStorage` now\n\t * throws on one).\n\t *\n\t * **First run — persist:**\n\t * ```ts\n\t * import { reactiveFactStore } from \"@graphrefly/graphrefly\";\n\t * import { appendLogStorage, bigintJsonCodecFor } from \"@graphrefly/pure-ts/extra\";\n\t *\n\t * const tier = appendLogStorage(backend, {\n\t * name: \"facts-ingest\",\n\t * codec: bigintJsonCodecFor<readonly MemoryFragment<Doc>[]>(),\n\t * });\n\t * const mem = reactiveFactStore<Doc>({ ingest, extractDependencies, recordIngest: true });\n\t * mem.ingestLog!.attachStorage([tier]); // forwards every committed fragment\n\t * ```\n\t *\n\t * **Restart — replay (rebuild the projection):** read the persisted entries\n\t * and feed them through `config.ingest`. Replay is just the reactive input —\n\t * there is no imperative restore primitive.\n\t * ```ts\n\t * const { entries } = await tier.loadEntries!();\n\t * const mem = reactiveFactStore<Doc>({ ingest, extractDependencies });\n\t * for (const f of entries) ingest.emit(f); // identical store rebuilt\n\t * ```\n\t *\n\t * **Do NOT do both at once.** On restart, either replay through `ingest`\n\t * (above) **or** rely on `attachStorage`'s auto-restore — never both:\n\t * `attachStorage` restores the persisted entries into a fresh `ingestLog`,\n\t * and a manual replay loop would then re-append + re-persist them (doubling\n\t * the durable log every restart). If you want continued persistence on the\n\t * rebuilt store, set `recordIngest:true` and call `attachStorage([tier])`\n\t * **after** the replay loop completes (the log already holds the replayed\n\t * fragments, so `attachStorage` ships no spurious deltas).\n\t *\n\t * **Memory:** the in-memory log is unbounded (every committed fragment is\n\t * retained for the store's lifetime). For a long-lived high-volume store,\n\t * `ingestLog.trimHead(n)` after a confirmed `tier.flush()` bounds it (the\n\t * durable tier remains the full record).\n\t */\n\treadonly recordIngest?: boolean;\n}\n\nexport interface ReactiveFactStoreGraph<T> extends Graph {\n\t// ④ Topic outputs (caller subscribes for custom processing).\n\t/** Per-shard `state<FactStore<T>>` nodes (length = shard count). */\n\treadonly shards: readonly Node<FactStore<T>>[];\n\t/** Unified read view across all shards (derived). */\n\treadonly factStore: Node<FactStore<T>>;\n\treadonly dependentsIndex: Node<DependentsIndex>;\n\treadonly answer: Node<MemoryAnswer<T> | null>;\n\treadonly cascade: Node<readonly CascadeEvent[]>;\n\treadonly cascadeOverflow: Node<CascadeOverflow | null>;\n\treadonly review: Node<ReviewRequest | null>;\n\treadonly consolidated: Node<readonly MemoryFragment<T>[]>;\n\treadonly events: ReactiveLogBundle<FactStoreAuditRecord>;\n\t/**\n\t * Payload-carrying, replayable log of every committed fragment. Present iff\n\t * {@link ReactiveFactStoreConfig.recordIngest} is `true`. Unlike\n\t * {@link ReactiveFactStoreGraph.events} (action-only audit), each entry is\n\t * the full {@link MemoryFragment} — `attachStorage` it for a durable,\n\t * replayable projection source (see `recordIngest` docs for the recipe).\n\t */\n\treadonly ingestLog?: ReactiveLogBundle<MemoryFragment<T>>;\n\t/** Reactive read: a single fact by id (SENTINEL until the fact exists). */\n\titemNode(id: FactId): Node<MemoryFragment<T> | undefined>;\n}\n\n// ── Constants ────────────────────────────────────────────────────────────\n\n/**\n * Max number of dropped cascade-target ids included in a {@link CascadeOverflow}\n * `sample`. Deliberately decoupled from `cascadeMaxIterations` — it bounds the\n * diagnostic payload size, not the recursion budget.\n */\nconst OVERFLOW_SAMPLE_SIZE = 8;\n\n// ── Helpers ──────────────────────────────────────────────────────────────\n\nfunction factMeta(kind: string, extra?: Record<string, unknown>): Record<string, unknown> {\n\treturn domainMeta(\"memory\", kind, extra);\n}\n\n/** Deterministic, universal-safe FNV-1a 32-bit string hash (no `node:crypto`). */\nfunction fnv1a(s: string): number {\n\tlet h = 0x811c9dc5;\n\tfor (let i = 0; i < s.length; i += 1) {\n\t\th ^= s.charCodeAt(i);\n\t\t// 32-bit FNV prime multiply via shifts (avoids BigInt / float drift).\n\t\th = (h + ((h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24))) >>> 0;\n\t}\n\treturn h >>> 0;\n}\n\nfunction makeReadHandle<T>(byId: ReadonlyMap<FactId, MemoryFragment<T>>): StoreReadHandle<T> {\n\treturn {\n\t\tget: (id) => byId.get(id),\n\t\thas: (id) => byId.has(id),\n\t\tget size() {\n\t\t\treturn byId.size;\n\t\t},\n\t\tvalues: () => byId.values(),\n\t};\n}\n\n/** Bi-temporal validity test: is `f` valid at instant `asOf`? */\nfunction currentlyValid<T>(f: MemoryFragment<T>, asOf?: bigint): boolean {\n\tif (asOf === undefined) return f.validTo === undefined;\n\tif (f.validFrom !== undefined && asOf < f.validFrom) return false;\n\tif (f.validTo !== undefined && asOf >= f.validTo) return false;\n\treturn true;\n}\n\nfunction lastOf<X>(batch: readonly unknown[] | undefined, prev: unknown): X | undefined {\n\treturn batch != null && batch.length > 0 ? (batch.at(-1) as X) : (prev as X | undefined);\n}\n\n// ── Factory ──────────────────────────────────────────────────────────────\n\n/**\n * Build a static-topology reactive fact store (DS-14.7 architecture C).\n *\n * Topology (~12 fixed nodes — never grows with fact count):\n * - `shards[0..N]` — `state<FactStore<T>>` columnar stores (default 4 shards).\n * - `factStore` — derived union read view across shards.\n * - `dependentsIndex` — `state<DependentsIndex>` reverse-dep map, unsharded,\n * updated synchronously + atomically with each commit (Q9-open-2).\n * - `extractOp` — derived: ingest → admission-filtered fragment + dep edges.\n * - `invalidationDetector` — derived: scans committed store for `validTo`-set\n * / low-confidence facts, resolves dependents via `dependentsIndex`, emits\n * cascade messages.\n * - `cascade` — topic node carrying `CascadeEvent[]`.\n * - `cascadeProcessor` — derived, **synchronous**, `meta.cycle:\"cascade\"`:\n * dedupes by factId, writes invalidations back to shards, recurses until\n * fixpoint OR `cascadeMaxIterations` → `cascadeOverflow`.\n * - `cascadeOverflow` — per-batch overflow summary node.\n * - `queryOp` / `answer` — structured `MemoryQuery` → results (SENTINEL-safe).\n * - `outcomeProcessor` — outcome signal → confidence write-back.\n * - `consolidated` — cron-tick → summarized fragments on the\n * `consolidated` topic,\n * default-wired back into the ingest path.\n * - `review` — low-confidence proactive-verification requests.\n *\n * The cascade cycle (`invalidationDetector → cascade → cascadeProcessor →\n * shards → invalidationDetector`) is a real, bounded reactive cycle. Both\n * `invalidationDetector` and `cascadeProcessor` are tagged\n * `meta.cycle:\"cascade\"` and every cascade message carries `causalReason`, so\n * `describe()` / `explain()` surface the otherwise-invisible\n * `dependentsIndex` lookup (COMPOSITION-GUIDE §24).\n *\n * @category memory\n */\nexport function reactiveFactStore<T>(\n\tconfig: ReactiveFactStoreConfig<T>,\n): ReactiveFactStoreGraph<T> {\n\tconst shardCount = Math.max(1, config.shardCount ?? 4);\n\tconst maxIterations = Math.max(1, config.cascadeMaxIterations ?? 8);\n\tconst reviewThreshold = config.reviewThreshold ?? 0.3;\n\tconst shardBy = config.shardBy ?? ((f: MemoryFragment<T>) => fnv1a(String(f.id)) % shardCount);\n\n\t// Cascade recursion depth counter. Reset to 0 on every external ingest\n\t// (a fresh root = a fresh cascade budget) and on a true fixpoint (detector\n\t// emits `[]`). Bounded by `maxIterations`; overflow stops the recursion.\n\t// This counter is a *backstop* for pathological cycles only — primary\n\t// termination is the per-root semantic contract below (F1/F5).\n\tlet cascadeIteration = 0;\n\n\t// F1/F5 — per-root cascade dedupe across waves. A fact only enters the\n\t// cascade as a root when it transitions to obsolete (`validTo` set), and\n\t// a given obsolete root emits its cascade exactly ONCE across all waves.\n\t// `processedRoots` tracks root ids that have already emitted; a root\n\t// re-detected in a later wave WITHOUT a new obsolescence transition does\n\t// not re-emit. This bounds the loop by the finite set of newly-obsolete\n\t// roots per external change, independent of `cascadeIteration` resets\n\t// (which an ingest / consolidator wire-back would otherwise defeat).\n\tconst processedRoots = new Set<FactId>();\n\n\tconst graph = new Graph(\"reactive_fact_store\") as ReactiveFactStoreGraph<T>;\n\n\tconst events = createAuditLog<FactStoreAuditRecord>({\n\t\tname: \"events\",\n\t\tretainedLimit: 1024,\n\t\tgraph,\n\t});\n\tconst seqCursor = registerCursor(graph, \"seq\", 0);\n\n\t// Opt-in payload-carrying ingest log (rebuildable-projection source).\n\t// Fed from `ingestAudit` (every committed fragment, post-admission).\n\tconst ingestLog: ReactiveLogBundle<MemoryFragment<T>> | undefined = config.recordIngest\n\t\t? reactiveLog<MemoryFragment<T>>([], { name: \"ingest_log\" })\n\t\t: undefined;\n\tif (ingestLog) graph.addDisposer(() => ingestLog.dispose());\n\n\t// ── shards: state<FactStore<T>> ──────────────────────────────────────\n\tconst emptyStore = (): FactStore<T> => ({ byId: new Map() });\n\tconst shards: Node<FactStore<T>>[] = [];\n\tfor (let s = 0; s < shardCount; s += 1) {\n\t\tconst shard = node<FactStore<T>>([], {\n\t\t\tinitial: emptyStore(),\n\t\t\tname: `shard_${s}`,\n\t\t\tdescribeKind: \"state\",\n\t\t\tmeta: factMeta(\"factstore\", { shard: s }),\n\t\t});\n\t\tgraph.add(shard, { name: `shard_${s}` });\n\t\tgraph.addDisposer(keepalive(shard));\n\t\tshards.push(shard);\n\t}\n\n\tconst shardIndexFor = (f: MemoryFragment<T>): number => {\n\t\tconst key = shardBy(f);\n\t\tconst n = typeof key === \"number\" ? key : fnv1a(String(key));\n\t\tconst idx = ((n % shardCount) + shardCount) % shardCount;\n\t\treturn idx;\n\t};\n\n\t// Resolve which shard a given id lives in by scanning current snapshots\n\t// (cascade write-backs reference ids without re-deriving the fragment).\n\tconst findShardOf = (id: FactId): number => {\n\t\tfor (let s = 0; s < shardCount; s += 1) {\n\t\t\tconst fs = shards[s]!.cache as FactStore<T> | undefined;\n\t\t\tif (fs?.byId.has(id)) return s;\n\t\t}\n\t\treturn -1;\n\t};\n\n\tconst allFacts = (): Map<FactId, MemoryFragment<T>> => {\n\t\tconst out = new Map<FactId, MemoryFragment<T>>();\n\t\tfor (const sh of shards) {\n\t\t\tconst fs = sh.cache as FactStore<T> | undefined;\n\t\t\tif (!fs) continue;\n\t\t\tfor (const [k, v] of fs.byId) out.set(k, v);\n\t\t}\n\t\treturn out;\n\t};\n\n\tconst commitFragment = (f: MemoryFragment<T>): void => {\n\t\tconst idx = shardIndexFor(f);\n\t\tconst cur = (shards[idx]!.cache as FactStore<T> | undefined) ?? emptyStore();\n\t\tconst next = new Map(cur.byId);\n\t\tnext.set(f.id, f);\n\t\tshards[idx]!.emit({ byId: next });\n\t};\n\n\tconst replaceFragment = (\n\t\tid: FactId,\n\t\tmut: (prev: MemoryFragment<T>) => MemoryFragment<T>,\n\t): boolean => {\n\t\tconst idx = findShardOf(id);\n\t\tif (idx < 0) return false;\n\t\tconst cur = shards[idx]!.cache as FactStore<T>;\n\t\tconst prev = cur.byId.get(id);\n\t\tif (!prev) return false;\n\t\tconst next = new Map(cur.byId);\n\t\tnext.set(id, mut(prev));\n\t\tshards[idx]!.emit({ byId: next });\n\t\treturn true;\n\t};\n\n\t// ── dependentsIndex: state<DependentsIndex>, unsharded ───────────────\n\tconst dependentsIndex = node<DependentsIndex>([], {\n\t\tinitial: new Map() as DependentsIndex,\n\t\tname: \"dependents_index\",\n\t\tdescribeKind: \"state\",\n\t\tmeta: factMeta(\"factstore\", { role: \"dependents_index\" }),\n\t});\n\tgraph.add(dependentsIndex, { name: \"dependents_index\" });\n\tgraph.addDisposer(keepalive(dependentsIndex));\n\n\t// Synchronous + atomic with the commit (Q9-open-2): add reverse edges\n\t// `source → [..., fact.id]` for every dependency the fragment declares.\n\tconst indexFragment = (f: MemoryFragment<T>, deps: readonly FactId[]): void => {\n\t\tconst cur = dependentsIndex.cache as DependentsIndex;\n\t\tconst next = new Map<FactId, FactId[]>();\n\t\tfor (const [k, v] of cur) next.set(k, [...v]);\n\t\tfor (const src of deps) {\n\t\t\tconst bucket = next.get(src) ?? [];\n\t\t\tif (!bucket.includes(f.id)) bucket.push(f.id);\n\t\t\tnext.set(src, bucket);\n\t\t}\n\t\tdependentsIndex.emit(next as DependentsIndex);\n\t};\n\n\t// ── factStore: unified read view (derived union over shards) ─────────\n\tconst factStore = node<FactStore<T>>(\n\t\tshards,\n\t\t(batchData, actions, ctx) => {\n\t\t\tvoid batchData;\n\t\t\tvoid ctx;\n\t\t\tactions.emit({ byId: allFacts() });\n\t\t},\n\t\t{\n\t\t\tname: \"fact_store\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tinitial: emptyStore(),\n\t\t\tmeta: factMeta(\"factstore\", { role: \"read_view\" }),\n\t\t\t// F10a: `allFacts()` builds a fresh Map every detector retrigger.\n\t\t\t// Fragments are immutable (replaced wholesale on mutation), so a\n\t\t\t// same-size + per-key-identity check is a sound structural equality\n\t\t\t// that stops `factStore` (and its `review` dependent) from re-firing\n\t\t\t// every cascade wave when nothing actually changed.\n\t\t\tequals: (a: FactStore<T>, b: FactStore<T>) => {\n\t\t\t\tif (a === b) return true;\n\t\t\t\tif (a.byId.size !== b.byId.size) return false;\n\t\t\t\tfor (const [k, v] of a.byId) {\n\t\t\t\t\tif (b.byId.get(k) !== v) return false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t},\n\t\t},\n\t);\n\tgraph.add(factStore, { name: \"fact_store\" });\n\tgraph.addDisposer(keepalive(factStore));\n\n\t// ── extractOp: ingest → admission filter → commit + index ────────────\n\tconst extractOp = node<MemoryFragment<T> | null>(\n\t\tconfig.admissionFilter ? [config.ingest, config.admissionFilter] : [config.ingest],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst f = lastOf<MemoryFragment<T>>(batchData[0], ctx.prevData[0]);\n\t\t\tif (f == null) {\n\t\t\t\tactions.emit(null);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (config.admissionFilter) {\n\t\t\t\tconst filter = lastOf<AdmissionFilter<T>>(batchData[1], ctx.prevData[1]);\n\t\t\t\tif (filter && !filter(f)) {\n\t\t\t\t\tactions.emit(null);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst deps = config.extractDependencies(f);\n\t\t\t// External ingest = a fresh cascade root → reset the depth budget.\n\t\t\tcascadeIteration = 0;\n\t\t\t// F1/F5: a (re-)ingested id is a fresh fact version. Clear it from\n\t\t\t// `processedRoots` so a NEW obsolescence transition on this id\n\t\t\t// (e.g. re-ingest with `validTo` set) re-drives the cascade exactly\n\t\t\t// once, rather than being permanently suppressed.\n\t\t\tprocessedRoots.delete(f.id);\n\t\t\t// Synchronous + atomic: commit fragment, then index its dep edges.\n\t\t\tcommitFragment(f);\n\t\t\tindexFragment(f, deps);\n\t\t\tactions.emit(f);\n\t\t},\n\t\t{\n\t\t\tname: \"extract_op\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tmeta: factMeta(\"extract\"),\n\t\t},\n\t);\n\tgraph.add(extractOp, { name: \"extract_op\" });\n\tgraph.addDisposer(keepalive(extractOp));\n\n\t// ── invalidationDetector: store → cascade messages ───────────────────\n\t// F1/F5 per-root semantic contract: a fact drives the cascade as a root\n\t// ONLY when it is obsolete (`validTo` set). A low-confidence-but-still-live\n\t// fact (no `validTo`) does NOT by itself emit a cascade — it surfaces via\n\t// the `review` topic instead, so it cannot perpetually re-emit a cascade\n\t// every detector pass. Each obsolete root emits its cascade exactly once\n\t// across all waves (`processedRoots` dedupe): a root re-detected in a later\n\t// wave without a fresh obsolescence transition is skipped. Termination is\n\t// therefore bounded by the finite set of newly-obsolete roots per external\n\t// change — robust against `cascadeIteration` resets from ingest /\n\t// consolidator wire-back. The empty-array emit is the fixpoint\n\t// short-circuit; `cascadeMaxIterations` remains a backstop for pathological\n\t// LLM-extracted cycles (A→B→A) only.\n\tconst invalidationDetector = node<readonly CascadeEvent[]>(\n\t\t[...shards],\n\t\t(batchData, actions, ctx) => {\n\t\t\tvoid batchData;\n\t\t\tvoid ctx;\n\t\t\tconst facts = allFacts();\n\t\t\tconst index = dependentsIndex.cache as DependentsIndex;\n\t\t\tconst out: CascadeEvent[] = [];\n\t\t\tconst seen = new Set<FactId>();\n\t\t\tfor (const f of facts.values()) {\n\t\t\t\t// F1/F5(a): ONLY obsolete facts drive the cascade as roots. A\n\t\t\t\t// low-confidence-but-still-live fact is handled by `review`,\n\t\t\t\t// never by the cascade loop.\n\t\t\t\tconst obsolete = f.validTo !== undefined;\n\t\t\t\tif (!obsolete) continue;\n\t\t\t\t// F1/F5(b): each obsolete root emits its cascade exactly once\n\t\t\t\t// across all waves. A root re-detected later (still obsolete,\n\t\t\t\t// no fresh transition) is skipped — convergence is independent\n\t\t\t\t// of `cascadeIteration` resets.\n\t\t\t\tif (processedRoots.has(f.id)) continue;\n\t\t\t\tconst dependents = index.get(f.id) ?? [];\n\t\t\t\tfor (const dep of dependents) {\n\t\t\t\t\t// F3: only cascade onto dependents that are still live. A\n\t\t\t\t\t// non-existent fact (phantom edge — `extractDependencies`\n\t\t\t\t\t// named an un-ingested FactId) is NOT a live dependent;\n\t\t\t\t\t// neither is a dependent already carrying `validTo`.\n\t\t\t\t\tconst depFact = facts.get(dep);\n\t\t\t\t\tif (!depFact || depFact.validTo !== undefined) continue;\n\t\t\t\t\tconst k = `${f.id}->${dep}`;\n\t\t\t\t\tif (seen.has(k)) continue;\n\t\t\t\t\tseen.add(k);\n\t\t\t\t\tout.push({\n\t\t\t\t\t\tfactId: dep,\n\t\t\t\t\t\trootFactId: f.id,\n\t\t\t\t\t\treason: \"obsolete\",\n\t\t\t\t\t\t// `obsolete` guard above guarantees `f.validTo` is set.\n\t\t\t\t\t\trootValidTo: f.validTo as bigint,\n\t\t\t\t\t\titeration: cascadeIteration + 1,\n\t\t\t\t\t\tcausalReason: `dependentsIndex[${f.id}] → ${dep} (obsolete: validTo set)`,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\t// Mark the root processed once considered (whether or not it\n\t\t\t\t// had a still-live dependent) — it must not re-drive a later\n\t\t\t\t// wave without a fresh obsolescence transition.\n\t\t\t\tprocessedRoots.add(f.id);\n\t\t\t}\n\t\t\tif (out.length === 0) {\n\t\t\t\t// True fixpoint — reset the depth counter so the next external\n\t\t\t\t// root starts a fresh cascade budget.\n\t\t\t\tcascadeIteration = 0;\n\t\t\t}\n\t\t\tactions.emit(out);\n\t\t},\n\t\t{\n\t\t\tname: \"invalidation_detector\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tinitial: [] as readonly CascadeEvent[],\n\t\t\tmeta: factMeta(\"invalidation\", { cycle: \"cascade\" }),\n\t\t},\n\t);\n\tgraph.add(invalidationDetector, { name: \"invalidation_detector\" });\n\tgraph.addDisposer(keepalive(invalidationDetector));\n\n\t// ── cascade topic node ───────────────────────────────────────────────\n\tconst cascade = node<readonly CascadeEvent[]>(\n\t\t[invalidationDetector],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst evts = lastOf<readonly CascadeEvent[]>(batchData[0], ctx.prevData[0]) ?? [];\n\t\t\tactions.emit(evts);\n\t\t},\n\t\t{\n\t\t\tname: \"cascade\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tinitial: [] as readonly CascadeEvent[],\n\t\t\tmeta: factMeta(\"cascade_topic\", { cycle: \"cascade\" }),\n\t\t},\n\t);\n\tgraph.add(cascade, { name: \"cascade\" });\n\tgraph.addDisposer(keepalive(cascade));\n\n\t// ── cascadeOverflow (per-batch summary, Q9-open-4) ───────────────────\n\tconst cascadeOverflow = node<CascadeOverflow | null>([], {\n\t\tinitial: null,\n\t\tname: \"cascade_overflow\",\n\t\tdescribeKind: \"state\",\n\t\tmeta: factMeta(\"cascade_overflow\"),\n\t});\n\tgraph.add(cascadeOverflow, { name: \"cascade_overflow\" });\n\tgraph.addDisposer(keepalive(cascadeOverflow));\n\n\t// ── cascadeProcessor (SYNCHRONOUS, meta.cycle:\"cascade\") ─────────────\n\t// Per-wave dedupe by target factId, mark each dependent obsolete\n\t// (write-back → re-triggers invalidationDetector), bounded by\n\t// `cascadeMaxIterations`. NOTE: this is DATA-array dedupe, NOT spec §1.4\n\t// INVALIDATE idempotency — termination comes from the detector's\n\t// obsolete-only + per-root-once contract plus the empty-array fixpoint\n\t// short-circuit, not a spec §1.4 guarantee.\n\tconst cascadeProcessor = node<readonly CascadeEvent[]>(\n\t\t[cascade],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst evts = lastOf<readonly CascadeEvent[]>(batchData[0], ctx.prevData[0]) ?? [];\n\t\t\tif (evts.length === 0) {\n\t\t\t\tactions.emit([]);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Dedupe by target factId (diamond-merge at message granularity).\n\t\t\tconst byId = new Map<FactId, CascadeEvent>();\n\t\t\tfor (const e of evts) if (!byId.has(e.factId)) byId.set(e.factId, e);\n\n\t\t\tcascadeIteration += 1;\n\t\t\tif (cascadeIteration > maxIterations) {\n\t\t\t\t// Cap hit (pathological dependency web / cycle). Emit a\n\t\t\t\t// per-batch overflow summary (Q9-open-4) and STOP the recursion\n\t\t\t\t// definitively: do NOT write back (no shard mutation → detector\n\t\t\t\t// does not re-fire) and settle the cascade topic with `[]` so\n\t\t\t\t// the cycle breaks. `cascadeIteration` stays above the cap until\n\t\t\t\t// the next external ingest resets it (via extractOp), so a\n\t\t\t\t// degenerate cycle cannot immediately re-enter.\n\t\t\t\tconst sample = [...byId.keys()].slice(0, OVERFLOW_SAMPLE_SIZE);\n\t\t\t\tconst rootFactId = evts[0]?.rootFactId ?? \"\";\n\t\t\t\tcascadeOverflow.emit({\n\t\t\t\t\tdroppedCount: byId.size,\n\t\t\t\t\tsample,\n\t\t\t\t\trootFactId,\n\t\t\t\t});\n\t\t\t\tevents.append({\n\t\t\t\t\taction: \"overflow\",\n\t\t\t\t\treason: \"cascade\",\n\t\t\t\t\tid: rootFactId,\n\t\t\t\t\tt_ns: wallClockNs(),\n\t\t\t\t\tseq: bumpCursor(seqCursor),\n\t\t\t\t});\n\t\t\t\tactions.emit([]);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Write-back: mark each dependent obsolete iff not already. Each\n\t\t\t// shard `emit` re-triggers `invalidationDetector` (it deps on\n\t\t\t// `[...shards]`) — that IS the recursion edge. No separate trigger\n\t\t\t// node is needed; the detector's \"still live\" predicate plus the\n\t\t\t// empty-emit fixpoint reset terminate the cycle.\n\t\t\t// Deterministic: the dependent inherits the triggering root's own\n\t\t\t// `validTo` (NOT a fresh `monotonicNs()` read), so replaying the\n\t\t\t// same ingest stream yields byte-identical `validTo`. Transitive\n\t\t\t// chains inherit the original root's time.\n\t\t\tfor (const [id, e] of byId) {\n\t\t\t\treplaceFragment(id, (prev) =>\n\t\t\t\t\tprev.validTo !== undefined ? prev : { ...prev, validTo: e.rootValidTo },\n\t\t\t\t);\n\t\t\t}\n\t\t\tactions.emit([...byId.values()]);\n\t\t},\n\t\t{\n\t\t\tname: \"cascade_processor\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tinitial: [] as readonly CascadeEvent[],\n\t\t\tmeta: factMeta(\"cascade_processor\", { cycle: \"cascade\" }),\n\t\t},\n\t);\n\tgraph.add(cascadeProcessor, { name: \"cascade_processor\" });\n\tgraph.addDisposer(keepalive(cascadeProcessor));\n\n\t// ── review: low-confidence proactive verification ────────────────────\n\tconst review = node<ReviewRequest | null>(\n\t\t[factStore],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst fs = lastOf<FactStore<T>>(batchData[0], ctx.prevData[0]);\n\t\t\tif (fs == null) {\n\t\t\t\tactions.emit(null);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfor (const f of fs.byId.values()) {\n\t\t\t\tif (f.confidence < reviewThreshold && f.validTo === undefined) {\n\t\t\t\t\tactions.emit({\n\t\t\t\t\t\tfactId: f.id,\n\t\t\t\t\t\tconfidence: f.confidence,\n\t\t\t\t\t\tthreshold: reviewThreshold,\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tactions.emit(null);\n\t\t},\n\t\t{\n\t\t\tname: \"review\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tinitial: null,\n\t\t\tmeta: factMeta(\"review\"),\n\t\t\t// F10a: dedupe on the requested factId (null === no request) so a\n\t\t\t// stable low-confidence fact does not re-emit a review every wave.\n\t\t\tequals: (a: ReviewRequest | null, b: ReviewRequest | null) =>\n\t\t\t\t(a?.factId ?? null) === (b?.factId ?? null),\n\t\t},\n\t);\n\tgraph.add(review, { name: \"review\" });\n\tgraph.addDisposer(keepalive(review));\n\n\t// ── outcomeProcessor: RL signal → confidence write-back ──────────────\n\tif (config.outcome) {\n\t\tconst outcomeProcessor = node<OutcomeSignal | null>(\n\t\t\tconfig.scoring ? [config.outcome, config.scoring] : [config.outcome],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst sig = lastOf<OutcomeSignal>(batchData[0], ctx.prevData[0]);\n\t\t\t\tif (sig == null) {\n\t\t\t\t\tactions.emit(null);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\treplaceFragment(sig.factId, (prev) => {\n\t\t\t\t\tlet nextConf = prev.confidence;\n\t\t\t\t\tif (config.scoring) {\n\t\t\t\t\t\tconst policy = lastOf<ScoringPolicy<T>>(batchData[1], ctx.prevData[1]);\n\t\t\t\t\t\tif (policy) {\n\t\t\t\t\t\t\tnextConf = policy(prev, makeReadHandle(allFacts()));\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnextConf = Math.max(0, Math.min(1, prev.confidence + sig.reward));\n\t\t\t\t\t}\n\t\t\t\t\treturn { ...prev, confidence: nextConf };\n\t\t\t\t});\n\t\t\t\tactions.emit(sig);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"outcome_processor\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tinitial: null,\n\t\t\t\tmeta: factMeta(\"outcome\"),\n\t\t\t},\n\t\t);\n\t\tgraph.add(outcomeProcessor, { name: \"outcome_processor\" });\n\t\tgraph.addDisposer(keepalive(outcomeProcessor));\n\t}\n\n\t// ── queryOp / answer (structured MemoryQuery, SENTINEL-safe) ─────────\n\t// Per COMPOSITION-GUIDE §3/§10: `answer` emits `null` while there has been\n\t// no query yet (SENTINEL on the query dep). Downstream consumers use the\n\t// `=== null` guard.\n\tconst answer = node<MemoryAnswer<T> | null>(\n\t\tconfig.query ? [config.query, factStore] : [factStore],\n\t\t(batchData, actions, ctx) => {\n\t\t\tif (!config.query) {\n\t\t\t\tactions.emit(null);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst q = lastOf<MemoryQuery>(batchData[0], ctx.prevData[0]);\n\t\t\tconst fs = lastOf<FactStore<T>>(batchData[1], ctx.prevData[1]);\n\t\t\tif (q == null) {\n\t\t\t\t// No query has been issued yet — null per the SENTINEL guard.\n\t\t\t\tactions.emit(null);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst store = fs ?? emptyStore();\n\t\t\tlet results = [...store.byId.values()].filter((f) => {\n\t\t\t\tif (q.tags && q.tags.length > 0 && !q.tags.some((t) => f.tags.includes(t))) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tif (q.minConfidence !== undefined && f.confidence < q.minConfidence) return false;\n\t\t\t\tif (!currentlyValid(f, q.asOf)) return false;\n\t\t\t\treturn true;\n\t\t\t});\n\t\t\tresults.sort((a, b) => b.confidence - a.confidence || Number(b.t_ns - a.t_ns));\n\t\t\tif (q.limit !== undefined) results = results.slice(0, Math.max(0, q.limit));\n\t\t\tactions.emit({ query: q, results });\n\t\t},\n\t\t{\n\t\t\tname: \"answer\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tinitial: null,\n\t\t\tmeta: factMeta(\"query\", { role: \"output\" }),\n\t\t},\n\t);\n\tgraph.add(answer, { name: \"answer\" });\n\tgraph.addDisposer(keepalive(answer));\n\n\t// ── consolidator (cron-fed) → consolidated topic → wired back ────────\n\tconst consolidated = node<readonly MemoryFragment<T>[]>(\n\t\tconfig.consolidateTrigger ? [config.consolidateTrigger] : [],\n\t\t(batchData, actions, ctx) => {\n\t\t\tvoid batchData;\n\t\t\tvoid ctx;\n\t\t\tif (!config.consolidateTrigger || !config.consolidate) {\n\t\t\t\tactions.emit([]);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst fragments = config.consolidate(makeReadHandle(allFacts()));\n\t\t\t// Default wire-back into the ingest path (Q9-open-6): the pattern\n\t\t\t// commits + indexes successor fragments; callers that need to gate\n\t\t\t// can subscribe to `consolidated` and intercept.\n\t\t\tfor (const f of fragments) {\n\t\t\t\tconst deps = config.extractDependencies(f);\n\t\t\t\t// F1/F5: wired-back successor is a fresh fact version — same\n\t\t\t\t// processedRoots reset as the ingest path so a later obsolescence\n\t\t\t\t// of this id can re-cascade exactly once.\n\t\t\t\tprocessedRoots.delete(f.id);\n\t\t\t\tcommitFragment(f);\n\t\t\t\tindexFragment(f, deps);\n\t\t\t\tevents.append({\n\t\t\t\t\taction: \"consolidate\",\n\t\t\t\t\tid: f.id,\n\t\t\t\t\tt_ns: wallClockNs(),\n\t\t\t\t\tseq: bumpCursor(seqCursor),\n\t\t\t\t});\n\t\t\t}\n\t\t\tactions.emit(fragments);\n\t\t},\n\t\t{\n\t\t\tname: \"consolidated\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tinitial: [] as readonly MemoryFragment<T>[],\n\t\t\tmeta: factMeta(\"consolidator\"),\n\t\t},\n\t);\n\tgraph.add(consolidated, { name: \"consolidated\" });\n\tgraph.addDisposer(keepalive(consolidated));\n\n\t// ── ingest audit (records every committed fragment) ──────────────────\n\tconst ingestAudit = node<MemoryFragment<T> | null>(\n\t\t[extractOp],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst f = lastOf<MemoryFragment<T> | null>(batchData[0], ctx.prevData[0]);\n\t\t\tif (f != null) {\n\t\t\t\tevents.append({\n\t\t\t\t\taction: \"ingest\",\n\t\t\t\t\tid: f.id,\n\t\t\t\t\tt_ns: wallClockNs(),\n\t\t\t\t\tseq: bumpCursor(seqCursor),\n\t\t\t\t});\n\t\t\t\t// Payload-carrying replay log (opt-in). Append the full\n\t\t\t\t// committed fragment so the store is a rebuildable projection.\n\t\t\t\tingestLog?.append(f);\n\t\t\t}\n\t\t\tactions.emit(f ?? null);\n\t\t},\n\t\t{\n\t\t\tname: \"_ingest_audit\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tinitial: null,\n\t\t\tmeta: factMeta(\"audit\"),\n\t\t},\n\t);\n\tgraph.add(ingestAudit, { name: \"_ingest_audit\" });\n\tgraph.addDisposer(keepalive(ingestAudit));\n\n\t// ── itemNode reactive read ───────────────────────────────────────────\n\tfunction itemNode(id: FactId): Node<MemoryFragment<T> | undefined> {\n\t\treturn node<MemoryFragment<T> | undefined>(\n\t\t\t[factStore],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst fs = lastOf<FactStore<T>>(batchData[0], ctx.prevData[0]);\n\t\t\t\tactions.emit(fs?.byId.get(id));\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: `item_${id}`,\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: factMeta(\"item\"),\n\t\t\t},\n\t\t);\n\t}\n\n\tconst out = Object.assign(graph, {\n\t\tshards: shards as readonly Node<FactStore<T>>[],\n\t\tfactStore,\n\t\tdependentsIndex,\n\t\tanswer,\n\t\tcascade,\n\t\tcascadeOverflow,\n\t\treview,\n\t\tconsolidated,\n\t\tevents,\n\t\t...(ingestLog ? { ingestLog } : {}),\n\t\titemNode,\n\t}) as ReactiveFactStoreGraph<T>;\n\treturn out;\n}\n"],"mappings":"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","names":["node","wallClockNs","keepalive","Graph","out","node","Graph","out","keepalive","wallClockNs"]}