@ai-matrx/content-ir-react 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/dist/{component-resolution.types-BS1ySIg-.d.cts → component-resolution.types-C1MzCf2s.d.cts} +13 -0
  3. package/dist/{component-resolution.types-BS1ySIg-.d.ts → component-resolution.types-C1MzCf2s.d.ts} +13 -0
  4. package/dist/{component-resolution.types-fvR92hW7.d.cts → component-resolution.types-DLO2w-0n.d.cts} +13 -0
  5. package/dist/{component-resolution.types-fvR92hW7.d.ts → component-resolution.types-DLO2w-0n.d.ts} +13 -0
  6. package/dist/db-component.d.cts +1 -1
  7. package/dist/db-component.d.ts +1 -1
  8. package/dist/{host-types-DvGv8s9L.d.cts → host-types-CDcLW0TD.d.cts} +7 -2
  9. package/dist/{host-types-CZ_Bkp4R.d.ts → host-types-CpItjcYh.d.ts} +7 -2
  10. package/dist/host.cjs.map +1 -1
  11. package/dist/host.d.cts +3 -3
  12. package/dist/host.d.ts +3 -3
  13. package/dist/host.js.map +1 -1
  14. package/dist/index.cjs +16 -0
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +4 -4
  17. package/dist/index.d.ts +4 -4
  18. package/dist/index.js +16 -0
  19. package/dist/index.js.map +1 -1
  20. package/dist/react.cjs.map +1 -1
  21. package/dist/react.d.cts +2 -2
  22. package/dist/react.d.ts +2 -2
  23. package/dist/react.js.map +1 -1
  24. package/dist/resolver.cjs +14 -0
  25. package/dist/resolver.cjs.map +1 -1
  26. package/dist/resolver.d.cts +11 -2
  27. package/dist/resolver.d.ts +11 -2
  28. package/dist/resolver.js +14 -0
  29. package/dist/resolver.js.map +1 -1
  30. package/dist/{route-C1XNcubB.d.ts → route-PUuEuEug.d.ts} +7 -2
  31. package/dist/{route-C55jsF4B.d.cts → route-QL2Vqf2e.d.cts} +7 -2
  32. package/dist/route.cjs +2 -0
  33. package/dist/route.cjs.map +1 -1
  34. package/dist/route.d.cts +2 -2
  35. package/dist/route.d.ts +2 -2
  36. package/dist/route.js +2 -0
  37. package/dist/route.js.map +1 -1
  38. package/package.json +2 -2
package/dist/resolver.js CHANGED
@@ -23,6 +23,13 @@ var ComponentResolver = class {
23
23
  db = /* @__PURE__ */ new Map();
24
24
  warmPromise = null;
25
25
  warmFailureLogged = false;
26
+ /**
27
+ * True once a list load has RUN TO COMPLETION (success or failure), or once
28
+ * any rows have been ingested by any tier. Until then `resolve()` answering
29
+ * null means "I have not looked yet" — never "no such component". See THE
30
+ * COLD-VERDICT RULE on `ComponentResolutionSource.hasSettled`.
31
+ */
32
+ settled = false;
26
33
  /**
27
34
  * When the last successful wholesale refresh landed, or null for "never".
28
35
  * Explicitly nullable rather than 0: with a host-supplied clock that starts
@@ -280,6 +287,7 @@ var ComponentResolver = class {
280
287
  if (!this.warmPromise) {
281
288
  this.warmPromise = loadAll().then((rows) => {
282
289
  this.ingestDbRows(rows);
290
+ this.settled = true;
283
291
  }).catch((error) => {
284
292
  const message = `component-resolver warm load failed (compiled bootstrap still serving): ${describe(error)}`;
285
293
  if (!this.warmFailureLogged) {
@@ -292,11 +300,17 @@ var ComponentResolver = class {
292
300
  ...errorFields(error),
293
301
  raw: error
294
302
  });
303
+ this.settled = true;
295
304
  this.warmPromise = null;
296
305
  });
297
306
  }
298
307
  return this.warmPromise;
299
308
  }
309
+ /** @see ComponentResolutionSource.hasSettled */
310
+ hasSettled() {
311
+ if (!this.options.loadAll) return true;
312
+ return this.settled || this.db.size > 0;
313
+ }
300
314
  };
301
315
  export {
302
316
  ComponentResolver
@@ -1 +1 @@
1
- {"version":3,"sources":["../host/error-report.ts","../resolver/component-resolver.ts"],"sourcesContent":["/**\n * THE SCREAM SEAM.\n *\n * Every recovery path in this package is loud: a defective component row, a\n * failed resolver load, a kind whose component throws on a provisional value.\n * The package refuses to own where those screams land — matrx-frontend routes\n * them to the Error Inspector, the dashboard to its own log, the extension to\n * its background page. Each host binds one function.\n *\n * A host that binds a no-op has chosen silence, which is a defect in itself;\n * {@link consoleErrorReporter} is the honest default.\n */\n\nexport interface ContentIrErrorReport {\n /** Always `\"content-ir\"` — hosts key their capture stores on it. */\n source: \"content-ir\";\n message: string;\n name?: string;\n stack?: string;\n /** Free-form grouping key (the host's `relation`), e.g. `\"partial-kind\"`. */\n relation?: string;\n raw?: unknown;\n}\n\nexport type ContentIrErrorReporter = (report: ContentIrErrorReport) => void;\n\n/** The default when a host binds nothing: never silent. */\nexport const consoleErrorReporter: ContentIrErrorReporter = (report) => {\n console.error(`[content-ir] ${report.message}`, report.raw ?? \"\");\n};\n","/**\n * The Shape System component RESOLVER (rulings R1 + R6): (kind, platform,\n * role) → component, with two tiers:\n *\n * - eager: a COMPILED bootstrap the host ships in its bundle — the\n * trusted-at-boot floor, available at import so the render seam can gate\n * synchronously from the first streamed byte.\n * - warm: one `content_ir.kind_component` list fetch per app session\n * (`ensureWarm`). A DB row for a (kind, platform, role) OVERRIDES the\n * compiled entry once warm; the compiled floor keeps answering until then\n * (and forever, on DB failure).\n *\n * Resolution is SYNCHRONOUS (the render seam calls it per block); the only\n * async work is the loading, off the render path.\n *\n * WHAT MOVED AND WHY. This class was matrx-frontend's `ComponentRegistry`. It\n * is a large part of why a second UI could not render a kind: every tier rule,\n * every repaint counter, every dedupe latch lived in one app. Nothing about it\n * is Next.js, Redux, or Supabase — the only host-specific parts were the two\n * loaders and the error sink, which are now constructor arguments.\n */\n\nimport type { ContentIrErrorReporter } from \"../host/error-report\";\nimport { consoleErrorReporter } from \"../host/error-report\";\nimport type {\n ComponentResolution,\n ComponentResolutionSource,\n ComponentRole,\n KindComponentRow,\n SystemComponentEntry,\n} from \"./component-resolution.types\";\n\nexport interface ComponentResolverOptions {\n /**\n * The compiled bootstrap, as a THUNK resolved on first use: a host's system\n * component table is often mid-initialization when this module evaluates\n * (matrx-frontend's registry cluster has a deliberate import cycle).\n */\n compiledEntries?: () => SystemComponentEntry[];\n /** The warm/refresh list load — every `kind_component` row the user may see. */\n loadAll?: () => Promise<KindComponentRow[]>;\n /** The eager single-kind load fired the moment a kind is identified mid-stream. */\n loadForKind?: (kind: string, platform: string) => Promise<KindComponentRow[]>;\n /** Where recovery screams land. Defaults to `console.error`, never silence. */\n reportError?: ContentIrErrorReporter;\n /** Clock seam — the refresh rate limiter. Defaults to `Date.now`. */\n now?: () => number;\n}\n\n/** Unit separator — a character no kind slug, platform, or role can contain. */\nconst KEY_SEPARATOR = String.fromCharCode(1);\n\nfunction keyOf(kind: string, platform: string, role: string): string {\n return `${kind}${KEY_SEPARATOR}${platform}${KEY_SEPARATOR}${role}`;\n}\n\nfunction describe(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/** Error-shaped fields, spread-safe under `exactOptionalPropertyTypes`. */\nfunction errorFields(error: unknown): { name?: string; stack?: string } {\n if (!(error instanceof Error)) return {};\n return {\n name: error.name,\n ...(error.stack === undefined ? {} : { stack: error.stack }),\n };\n}\n\nexport class ComponentResolver implements ComponentResolutionSource {\n private compiled: Map<string, SystemComponentEntry> | null = null;\n private readonly db = new Map<string, KindComponentRow>();\n private warmPromise: Promise<void> | null = null;\n private warmFailureLogged = false;\n /**\n * When the last successful wholesale refresh landed, or null for \"never\".\n * Explicitly nullable rather than 0: with a host-supplied clock that starts\n * near zero, a `0` sentinel makes the FIRST refresh look rate-limited and\n * silently skip.\n */\n private lastRefreshAt: number | null = null;\n private refreshPromise: Promise<void> | null = null;\n private readonly listeners = new Set<() => void>();\n /**\n * Cold single-kind fetch dedupe (streaming eager path). In-flight is keyed\n * by (kind, platform) — the fetch unit; misses are keyed by (kind, platform,\n * role) so a miss on web/output never suppresses other roles, and CLEARED on\n * every wholesale refresh (a component created mid-session becomes eagerly\n * fetchable again — misses are cheap to re-verify).\n */\n private readonly coldInFlight = new Set<string>();\n private readonly coldMisses = new Set<string>();\n /** Monotonic db-tier version — the repaint hook's snapshot key. */\n private version = 0;\n /** Per-kind versions + listeners (granular repaint) + wholesale epoch. */\n private readonly kindVersions = new Map<string, number>();\n private readonly kindListeners = new Map<string, Set<() => void>>();\n private epoch = 0;\n\n private readonly reportError: ContentIrErrorReporter;\n private readonly now: () => number;\n\n private readonly options: ComponentResolverOptions;\n\n // Explicit field, not a parameter property: consumers compile this source\n // directly, and a strict host (the dashboard) sets `erasableSyntaxOnly`,\n // under which parameter properties are a hard error.\n constructor(options: ComponentResolverOptions = {}) {\n this.options = options;\n this.reportError = options.reportError ?? consoleErrorReporter;\n this.now = options.now ?? (() => Date.now());\n }\n\n private compiledMap(): Map<string, SystemComponentEntry> {\n if (!this.compiled) {\n this.compiled = new Map();\n for (const entry of this.options.compiledEntries?.() ?? []) {\n this.compiled.set(keyOf(entry.kind, entry.platform, entry.role), entry);\n }\n }\n return this.compiled;\n }\n\n /**\n * Synchronous resolve — the render seam's per-block call. DB override first\n * (once warm), compiled floor second, null for unknown.\n */\n resolve(\n kind: string,\n platform: string,\n role: ComponentRole,\n ): ComponentResolution | null {\n const key = keyOf(kind, platform, role);\n\n const dbRow = this.db.get(key);\n if (dbRow) {\n return {\n componentKey: dbRow.componentKey,\n source: dbRow.source,\n config: dbRow.config,\n isActive: dbRow.isActive,\n resolvedBy: \"db\",\n componentSource: dbRow.componentSource,\n propsTransform: dbRow.propsTransform,\n hasComponentSource:\n dbRow.hasComponentSource ??\n Boolean(dbRow.componentSource && dbRow.componentSource.trim()),\n pinnedKindVersion: dbRow.pinnedKindVersion,\n updatedAt: dbRow.updatedAt,\n createdBy: dbRow.createdBy,\n };\n }\n\n const compiledEntry = this.compiledMap().get(key);\n if (compiledEntry) {\n return {\n componentKey: compiledEntry.componentKey,\n source: compiledEntry.source,\n config: compiledEntry.config,\n isActive: true, // trusted at bootstrap (R6)\n resolvedBy: \"compiled\",\n componentSource: null,\n propsTransform: null,\n hasComponentSource: false,\n pinnedKindVersion: null,\n updatedAt: null,\n createdBy: null,\n };\n }\n\n return null;\n }\n\n /** R6 floor check: compiled-bootstrap membership = always render-trusted. */\n hasCompiled(kind: string, platform: string, role: ComponentRole): boolean {\n return this.compiledMap().has(keyOf(kind, platform, role));\n }\n\n /**\n * Pure ingest — the warm landing point and the unit-test seam. First row per\n * key wins: rows arrive is_default-first / sort_order-asc from the source.\n */\n ingestDbRows(rows: readonly KindComponentRow[]): void {\n const changedKinds = new Set<string>();\n for (const row of rows) {\n const key = keyOf(row.kind, row.platform, row.role);\n if (!this.db.has(key)) {\n this.db.set(key, row);\n changedKinds.add(row.kind);\n }\n }\n // Warm/cold ingest is a resolver-tier change the render seam must see — a\n // db component landing AFTER a region finalized re-runs the route via the\n // repaint hook. Per-kind bumps keep the repaint granular.\n if (changedKinds.size > 0) {\n for (const kind of changedKinds) this.bumpKind(kind);\n this.notifyChanged();\n }\n }\n\n /**\n * Refresh landing point: REPLACE the db tier wholesale (same\n * first-row-per-key contract as {@link ingestDbRows}) so edits, deletions,\n * and is_active flips all take effect. Always notifies.\n */\n replaceDbRows(rows: readonly KindComponentRow[]): void {\n this.db.clear();\n // Wholesale invalidation: every recorded miss is stale (a component\n // created mid-session must become eagerly fetchable again).\n this.coldMisses.clear();\n for (const row of rows) {\n const key = keyOf(row.kind, row.platform, row.role);\n if (!this.db.has(key)) this.db.set(key, row);\n }\n // A wholesale replace ALWAYS notifies (deletions/flips count too), and\n // bumps the epoch so EVERY per-kind subscriber re-snapshots.\n this.epoch += 1;\n for (const set of this.kindListeners.values()) {\n for (const listener of set) listener();\n }\n this.notifyChanged();\n }\n\n getVersion(): number {\n return this.version;\n }\n\n getKindVersion(kind: string): number {\n return this.epoch + (this.kindVersions.get(kind) ?? 0);\n }\n\n subscribeKind(kind: string, listener: () => void): () => void {\n const set = this.kindListeners.get(kind) ?? new Set<() => void>();\n set.add(listener);\n this.kindListeners.set(kind, set);\n return () => {\n set.delete(listener);\n if (set.size === 0) this.kindListeners.delete(kind);\n };\n }\n\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n private bumpKind(kind: string): void {\n this.kindVersions.set(kind, (this.kindVersions.get(kind) ?? 0) + 1);\n const listeners = this.kindListeners.get(kind);\n if (listeners) for (const listener of listeners) listener();\n }\n\n private notifyChanged(): void {\n this.version += 1;\n for (const listener of this.listeners) listener();\n }\n\n /**\n * A warm metadata shell is resolved enough for routing, but not for the\n * host's db-component renderer. Its body must still come from the cold\n * single-kind loader.\n */\n private needsColdFetch(\n kind: string,\n platform: string,\n role: ComponentRole,\n ): boolean {\n const resolution = this.resolve(kind, platform, role);\n return (\n resolution === null ||\n (resolution.resolvedBy === \"db\" &&\n resolution.hasComponentSource &&\n resolution.componentSource === null)\n );\n }\n\n /**\n * Cold rows are the authoritative heavy form of warm metadata shells. Keep\n * the same first-row-per-key winner contract, but replace an existing shell\n * so `componentSource` / `propsTransform` can land and repaint the kind.\n */\n private ingestColdRows(rows: readonly KindComponentRow[]): void {\n const winners = new Map<string, KindComponentRow>();\n for (const row of rows) {\n const key = keyOf(row.kind, row.platform, row.role);\n if (!winners.has(key)) winners.set(key, row);\n }\n if (winners.size === 0) return;\n\n const changedKinds = new Set<string>();\n for (const [key, row] of winners) {\n this.db.set(key, row);\n changedKinds.add(row.kind);\n }\n for (const kind of changedKinds) this.bumpKind(kind);\n this.notifyChanged();\n }\n\n /**\n * The eager lightweight single-kind fetch (streaming path): the moment a\n * cloud kind is identified mid-stream, pull ONLY that kind's resolver rows\n * and ingest them so {@link resolve} can answer before — or shortly after —\n * the region completes. Deduped in-flight and by known-miss. Fire-and-forget;\n * failures are loud (the warm list remains the backstop).\n */\n requestComponent(kind: string, platform: string, role: ComponentRole): void {\n const loadForKind = this.options.loadForKind;\n if (!loadForKind) return;\n if (!this.needsColdFetch(kind, platform, role)) return;\n const missKey = keyOf(kind, platform, role);\n const flightKey = `${kind}${KEY_SEPARATOR}${platform}`;\n if (this.coldInFlight.has(flightKey) || this.coldMisses.has(missKey)) {\n return;\n }\n this.coldInFlight.add(flightKey);\n\n void (async () => {\n try {\n this.ingestColdRows(await loadForKind(kind, platform));\n // Record the miss for exactly the requested (kind, platform, role) —\n // rows may exist for OTHER roles on this platform; those must not be\n // suppressed, and this one must not be re-fetched until a refresh.\n if (this.needsColdFetch(kind, platform, role)) {\n this.coldMisses.add(missKey);\n }\n } catch (error) {\n this.reportError({\n source: \"content-ir\",\n message: `component-resolver cold fetch failed for \"${kind}\": ${describe(error)}`,\n ...errorFields(error),\n raw: error,\n });\n } finally {\n this.coldInFlight.delete(flightKey);\n }\n })();\n }\n\n /**\n * Refresh-on-view: re-fetch the warm list and REPLACE the db tier, so an\n * edited `source='db'` component (its `updated_at` bump re-keys the host's\n * compile cache) renders fresh on the next view. Deduped in-flight and\n * rate-limited by `maxAgeMs` (default 10s) — mounting several previews costs\n * one fetch. Server-side edits do NOT push to open clients; the contract is\n * refresh-on-view via this call.\n */\n refresh(maxAgeMs = 10_000): Promise<void> {\n const loadAll = this.options.loadAll;\n if (!loadAll) return Promise.resolve();\n if (this.refreshPromise) return this.refreshPromise;\n if (\n this.lastRefreshAt !== null &&\n this.now() - this.lastRefreshAt < maxAgeMs\n ) {\n return Promise.resolve();\n }\n // Any refresh intent invalidates recorded misses immediately (also cleared\n // in replaceDbRows when the fetch lands) — cheap to re-verify.\n this.coldMisses.clear();\n\n this.refreshPromise = loadAll()\n .then((rows) => {\n this.lastRefreshAt = this.now();\n this.replaceDbRows(rows);\n })\n .catch((error: unknown) => {\n // Loud recovery: the current tier keeps answering; a refresh failure is\n // a real defect (same posture as the warm loader).\n this.reportError({\n source: \"content-ir\",\n message: `component-resolver refresh failed (current resolver tier still serving): ${describe(error)}`,\n ...errorFields(error),\n raw: error,\n });\n })\n .finally(() => {\n this.refreshPromise = null;\n });\n return this.refreshPromise;\n }\n\n /** One list fetch per app session; failed loads retry on the next call. */\n ensureWarm(): Promise<void> {\n const loadAll = this.options.loadAll;\n if (!loadAll) return Promise.resolve();\n if (!this.warmPromise) {\n this.warmPromise = loadAll()\n .then((rows) => {\n this.ingestDbRows(rows);\n })\n .catch((error: unknown) => {\n // Loud recovery: the compiled floor keeps rendering, but a warm\n // failure is a real defect — one console scream (first failure) plus\n // a structured report per attempt, then retryable.\n const message = `component-resolver warm load failed (compiled bootstrap still serving): ${describe(error)}`;\n if (!this.warmFailureLogged) {\n this.warmFailureLogged = true;\n console.error(`[content-ir] ${message}`);\n }\n this.reportError({\n source: \"content-ir\",\n message,\n ...errorFields(error),\n raw: error,\n });\n this.warmPromise = null;\n });\n }\n return this.warmPromise;\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../host/error-report.ts","../resolver/component-resolver.ts"],"sourcesContent":["/**\n * THE SCREAM SEAM.\n *\n * Every recovery path in this package is loud: a defective component row, a\n * failed resolver load, a kind whose component throws on a provisional value.\n * The package refuses to own where those screams land — matrx-frontend routes\n * them to the Error Inspector, the dashboard to its own log, the extension to\n * its background page. Each host binds one function.\n *\n * A host that binds a no-op has chosen silence, which is a defect in itself;\n * {@link consoleErrorReporter} is the honest default.\n */\n\nexport interface ContentIrErrorReport {\n /** Always `\"content-ir\"` — hosts key their capture stores on it. */\n source: \"content-ir\";\n message: string;\n name?: string;\n stack?: string;\n /** Free-form grouping key (the host's `relation`), e.g. `\"partial-kind\"`. */\n relation?: string;\n raw?: unknown;\n}\n\nexport type ContentIrErrorReporter = (report: ContentIrErrorReport) => void;\n\n/** The default when a host binds nothing: never silent. */\nexport const consoleErrorReporter: ContentIrErrorReporter = (report) => {\n console.error(`[content-ir] ${report.message}`, report.raw ?? \"\");\n};\n","/**\n * The Shape System component RESOLVER (rulings R1 + R6): (kind, platform,\n * role) → component, with two tiers:\n *\n * - eager: a COMPILED bootstrap the host ships in its bundle — the\n * trusted-at-boot floor, available at import so the render seam can gate\n * synchronously from the first streamed byte.\n * - warm: one `content_ir.kind_component` list fetch per app session\n * (`ensureWarm`). A DB row for a (kind, platform, role) OVERRIDES the\n * compiled entry once warm; the compiled floor keeps answering until then\n * (and forever, on DB failure).\n *\n * Resolution is SYNCHRONOUS (the render seam calls it per block); the only\n * async work is the loading, off the render path.\n *\n * WHAT MOVED AND WHY. This class was matrx-frontend's `ComponentRegistry`. It\n * is a large part of why a second UI could not render a kind: every tier rule,\n * every repaint counter, every dedupe latch lived in one app. Nothing about it\n * is Next.js, Redux, or Supabase — the only host-specific parts were the two\n * loaders and the error sink, which are now constructor arguments.\n */\n\nimport type { ContentIrErrorReporter } from \"../host/error-report\";\nimport { consoleErrorReporter } from \"../host/error-report\";\nimport type {\n ComponentResolution,\n ComponentResolutionSource,\n ComponentRole,\n KindComponentRow,\n SystemComponentEntry,\n} from \"./component-resolution.types\";\n\nexport interface ComponentResolverOptions {\n /**\n * The compiled bootstrap, as a THUNK resolved on first use: a host's system\n * component table is often mid-initialization when this module evaluates\n * (matrx-frontend's registry cluster has a deliberate import cycle).\n */\n compiledEntries?: () => SystemComponentEntry[];\n /** The warm/refresh list load — every `kind_component` row the user may see. */\n loadAll?: () => Promise<KindComponentRow[]>;\n /** The eager single-kind load fired the moment a kind is identified mid-stream. */\n loadForKind?: (kind: string, platform: string) => Promise<KindComponentRow[]>;\n /** Where recovery screams land. Defaults to `console.error`, never silence. */\n reportError?: ContentIrErrorReporter;\n /** Clock seam — the refresh rate limiter. Defaults to `Date.now`. */\n now?: () => number;\n}\n\n/** Unit separator — a character no kind slug, platform, or role can contain. */\nconst KEY_SEPARATOR = String.fromCharCode(1);\n\nfunction keyOf(kind: string, platform: string, role: string): string {\n return `${kind}${KEY_SEPARATOR}${platform}${KEY_SEPARATOR}${role}`;\n}\n\nfunction describe(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/** Error-shaped fields, spread-safe under `exactOptionalPropertyTypes`. */\nfunction errorFields(error: unknown): { name?: string; stack?: string } {\n if (!(error instanceof Error)) return {};\n return {\n name: error.name,\n ...(error.stack === undefined ? {} : { stack: error.stack }),\n };\n}\n\nexport class ComponentResolver implements ComponentResolutionSource {\n private compiled: Map<string, SystemComponentEntry> | null = null;\n private readonly db = new Map<string, KindComponentRow>();\n private warmPromise: Promise<void> | null = null;\n private warmFailureLogged = false;\n /**\n * True once a list load has RUN TO COMPLETION (success or failure), or once\n * any rows have been ingested by any tier. Until then `resolve()` answering\n * null means \"I have not looked yet\" — never \"no such component\". See THE\n * COLD-VERDICT RULE on `ComponentResolutionSource.hasSettled`.\n */\n private settled = false;\n /**\n * When the last successful wholesale refresh landed, or null for \"never\".\n * Explicitly nullable rather than 0: with a host-supplied clock that starts\n * near zero, a `0` sentinel makes the FIRST refresh look rate-limited and\n * silently skip.\n */\n private lastRefreshAt: number | null = null;\n private refreshPromise: Promise<void> | null = null;\n private readonly listeners = new Set<() => void>();\n /**\n * Cold single-kind fetch dedupe (streaming eager path). In-flight is keyed\n * by (kind, platform) — the fetch unit; misses are keyed by (kind, platform,\n * role) so a miss on web/output never suppresses other roles, and CLEARED on\n * every wholesale refresh (a component created mid-session becomes eagerly\n * fetchable again — misses are cheap to re-verify).\n */\n private readonly coldInFlight = new Set<string>();\n private readonly coldMisses = new Set<string>();\n /** Monotonic db-tier version — the repaint hook's snapshot key. */\n private version = 0;\n /** Per-kind versions + listeners (granular repaint) + wholesale epoch. */\n private readonly kindVersions = new Map<string, number>();\n private readonly kindListeners = new Map<string, Set<() => void>>();\n private epoch = 0;\n\n private readonly reportError: ContentIrErrorReporter;\n private readonly now: () => number;\n\n private readonly options: ComponentResolverOptions;\n\n // Explicit field, not a parameter property: consumers compile this source\n // directly, and a strict host (the dashboard) sets `erasableSyntaxOnly`,\n // under which parameter properties are a hard error.\n constructor(options: ComponentResolverOptions = {}) {\n this.options = options;\n this.reportError = options.reportError ?? consoleErrorReporter;\n this.now = options.now ?? (() => Date.now());\n }\n\n private compiledMap(): Map<string, SystemComponentEntry> {\n if (!this.compiled) {\n this.compiled = new Map();\n for (const entry of this.options.compiledEntries?.() ?? []) {\n this.compiled.set(keyOf(entry.kind, entry.platform, entry.role), entry);\n }\n }\n return this.compiled;\n }\n\n /**\n * Synchronous resolve — the render seam's per-block call. DB override first\n * (once warm), compiled floor second, null for unknown.\n */\n resolve(\n kind: string,\n platform: string,\n role: ComponentRole,\n ): ComponentResolution | null {\n const key = keyOf(kind, platform, role);\n\n const dbRow = this.db.get(key);\n if (dbRow) {\n return {\n componentKey: dbRow.componentKey,\n source: dbRow.source,\n config: dbRow.config,\n isActive: dbRow.isActive,\n resolvedBy: \"db\",\n componentSource: dbRow.componentSource,\n propsTransform: dbRow.propsTransform,\n hasComponentSource:\n dbRow.hasComponentSource ??\n Boolean(dbRow.componentSource && dbRow.componentSource.trim()),\n pinnedKindVersion: dbRow.pinnedKindVersion,\n updatedAt: dbRow.updatedAt,\n createdBy: dbRow.createdBy,\n };\n }\n\n const compiledEntry = this.compiledMap().get(key);\n if (compiledEntry) {\n return {\n componentKey: compiledEntry.componentKey,\n source: compiledEntry.source,\n config: compiledEntry.config,\n isActive: true, // trusted at bootstrap (R6)\n resolvedBy: \"compiled\",\n componentSource: null,\n propsTransform: null,\n hasComponentSource: false,\n pinnedKindVersion: null,\n updatedAt: null,\n createdBy: null,\n };\n }\n\n return null;\n }\n\n /** R6 floor check: compiled-bootstrap membership = always render-trusted. */\n hasCompiled(kind: string, platform: string, role: ComponentRole): boolean {\n return this.compiledMap().has(keyOf(kind, platform, role));\n }\n\n /**\n * Pure ingest — the warm landing point and the unit-test seam. First row per\n * key wins: rows arrive is_default-first / sort_order-asc from the source.\n */\n ingestDbRows(rows: readonly KindComponentRow[]): void {\n const changedKinds = new Set<string>();\n for (const row of rows) {\n const key = keyOf(row.kind, row.platform, row.role);\n if (!this.db.has(key)) {\n this.db.set(key, row);\n changedKinds.add(row.kind);\n }\n }\n // Warm/cold ingest is a resolver-tier change the render seam must see — a\n // db component landing AFTER a region finalized re-runs the route via the\n // repaint hook. Per-kind bumps keep the repaint granular.\n if (changedKinds.size > 0) {\n for (const kind of changedKinds) this.bumpKind(kind);\n this.notifyChanged();\n }\n }\n\n /**\n * Refresh landing point: REPLACE the db tier wholesale (same\n * first-row-per-key contract as {@link ingestDbRows}) so edits, deletions,\n * and is_active flips all take effect. Always notifies.\n */\n replaceDbRows(rows: readonly KindComponentRow[]): void {\n this.db.clear();\n // Wholesale invalidation: every recorded miss is stale (a component\n // created mid-session must become eagerly fetchable again).\n this.coldMisses.clear();\n for (const row of rows) {\n const key = keyOf(row.kind, row.platform, row.role);\n if (!this.db.has(key)) this.db.set(key, row);\n }\n // A wholesale replace ALWAYS notifies (deletions/flips count too), and\n // bumps the epoch so EVERY per-kind subscriber re-snapshots.\n this.epoch += 1;\n for (const set of this.kindListeners.values()) {\n for (const listener of set) listener();\n }\n this.notifyChanged();\n }\n\n getVersion(): number {\n return this.version;\n }\n\n getKindVersion(kind: string): number {\n return this.epoch + (this.kindVersions.get(kind) ?? 0);\n }\n\n subscribeKind(kind: string, listener: () => void): () => void {\n const set = this.kindListeners.get(kind) ?? new Set<() => void>();\n set.add(listener);\n this.kindListeners.set(kind, set);\n return () => {\n set.delete(listener);\n if (set.size === 0) this.kindListeners.delete(kind);\n };\n }\n\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n private bumpKind(kind: string): void {\n this.kindVersions.set(kind, (this.kindVersions.get(kind) ?? 0) + 1);\n const listeners = this.kindListeners.get(kind);\n if (listeners) for (const listener of listeners) listener();\n }\n\n private notifyChanged(): void {\n this.version += 1;\n for (const listener of this.listeners) listener();\n }\n\n /**\n * A warm metadata shell is resolved enough for routing, but not for the\n * host's db-component renderer. Its body must still come from the cold\n * single-kind loader.\n */\n private needsColdFetch(\n kind: string,\n platform: string,\n role: ComponentRole,\n ): boolean {\n const resolution = this.resolve(kind, platform, role);\n return (\n resolution === null ||\n (resolution.resolvedBy === \"db\" &&\n resolution.hasComponentSource &&\n resolution.componentSource === null)\n );\n }\n\n /**\n * Cold rows are the authoritative heavy form of warm metadata shells. Keep\n * the same first-row-per-key winner contract, but replace an existing shell\n * so `componentSource` / `propsTransform` can land and repaint the kind.\n */\n private ingestColdRows(rows: readonly KindComponentRow[]): void {\n const winners = new Map<string, KindComponentRow>();\n for (const row of rows) {\n const key = keyOf(row.kind, row.platform, row.role);\n if (!winners.has(key)) winners.set(key, row);\n }\n if (winners.size === 0) return;\n\n const changedKinds = new Set<string>();\n for (const [key, row] of winners) {\n this.db.set(key, row);\n changedKinds.add(row.kind);\n }\n for (const kind of changedKinds) this.bumpKind(kind);\n this.notifyChanged();\n }\n\n /**\n * The eager lightweight single-kind fetch (streaming path): the moment a\n * cloud kind is identified mid-stream, pull ONLY that kind's resolver rows\n * and ingest them so {@link resolve} can answer before — or shortly after —\n * the region completes. Deduped in-flight and by known-miss. Fire-and-forget;\n * failures are loud (the warm list remains the backstop).\n */\n requestComponent(kind: string, platform: string, role: ComponentRole): void {\n const loadForKind = this.options.loadForKind;\n if (!loadForKind) return;\n if (!this.needsColdFetch(kind, platform, role)) return;\n const missKey = keyOf(kind, platform, role);\n const flightKey = `${kind}${KEY_SEPARATOR}${platform}`;\n if (this.coldInFlight.has(flightKey) || this.coldMisses.has(missKey)) {\n return;\n }\n this.coldInFlight.add(flightKey);\n\n void (async () => {\n try {\n this.ingestColdRows(await loadForKind(kind, platform));\n // Record the miss for exactly the requested (kind, platform, role) —\n // rows may exist for OTHER roles on this platform; those must not be\n // suppressed, and this one must not be re-fetched until a refresh.\n if (this.needsColdFetch(kind, platform, role)) {\n this.coldMisses.add(missKey);\n }\n } catch (error) {\n this.reportError({\n source: \"content-ir\",\n message: `component-resolver cold fetch failed for \"${kind}\": ${describe(error)}`,\n ...errorFields(error),\n raw: error,\n });\n } finally {\n this.coldInFlight.delete(flightKey);\n }\n })();\n }\n\n /**\n * Refresh-on-view: re-fetch the warm list and REPLACE the db tier, so an\n * edited `source='db'` component (its `updated_at` bump re-keys the host's\n * compile cache) renders fresh on the next view. Deduped in-flight and\n * rate-limited by `maxAgeMs` (default 10s) — mounting several previews costs\n * one fetch. Server-side edits do NOT push to open clients; the contract is\n * refresh-on-view via this call.\n */\n refresh(maxAgeMs = 10_000): Promise<void> {\n const loadAll = this.options.loadAll;\n if (!loadAll) return Promise.resolve();\n if (this.refreshPromise) return this.refreshPromise;\n if (\n this.lastRefreshAt !== null &&\n this.now() - this.lastRefreshAt < maxAgeMs\n ) {\n return Promise.resolve();\n }\n // Any refresh intent invalidates recorded misses immediately (also cleared\n // in replaceDbRows when the fetch lands) — cheap to re-verify.\n this.coldMisses.clear();\n\n this.refreshPromise = loadAll()\n .then((rows) => {\n this.lastRefreshAt = this.now();\n this.replaceDbRows(rows);\n })\n .catch((error: unknown) => {\n // Loud recovery: the current tier keeps answering; a refresh failure is\n // a real defect (same posture as the warm loader).\n this.reportError({\n source: \"content-ir\",\n message: `component-resolver refresh failed (current resolver tier still serving): ${describe(error)}`,\n ...errorFields(error),\n raw: error,\n });\n })\n .finally(() => {\n this.refreshPromise = null;\n });\n return this.refreshPromise;\n }\n\n /** One list fetch per app session; failed loads retry on the next call. */\n ensureWarm(): Promise<void> {\n const loadAll = this.options.loadAll;\n if (!loadAll) return Promise.resolve();\n if (!this.warmPromise) {\n this.warmPromise = loadAll()\n .then((rows) => {\n this.ingestDbRows(rows);\n this.settled = true;\n })\n .catch((error: unknown) => {\n // Loud recovery: the compiled floor keeps rendering, but a warm\n // failure is a real defect — one console scream (first failure) plus\n // a structured report per attempt, then retryable.\n const message = `component-resolver warm load failed (compiled bootstrap still serving): ${describe(error)}`;\n if (!this.warmFailureLogged) {\n this.warmFailureLogged = true;\n console.error(`[content-ir] ${message}`);\n }\n this.reportError({\n source: \"content-ir\",\n message,\n ...errorFields(error),\n raw: error,\n });\n // A FAILED load still settles: the compiled floor becomes the\n // honest answer, and holding every block in limbo forever would be\n // a worse failure than a visible one. The retry stays available.\n this.settled = true;\n this.warmPromise = null;\n });\n }\n return this.warmPromise;\n }\n\n /** @see ComponentResolutionSource.hasSettled */\n hasSettled(): boolean {\n // No list loader configured = nothing to wait for: the compiled floor IS\n // the complete truth for this resolver, so it is settled from birth. (A\n // host that never wired a loader must not have every block held forever.)\n if (!this.options.loadAll) return true;\n return this.settled || this.db.size > 0;\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,4 +1,4 @@
1
- import { C as ComponentResolutionSource, b as ContentIrErrorReporter, a as ComponentResolution } from './component-resolution.types-fvR92hW7.js';
1
+ import { C as ComponentResolutionSource, b as ContentIrErrorReporter, a as ComponentResolution } from './component-resolution.types-DLO2w-0n.js';
2
2
  import { ReactNode } from 'react';
3
3
  import { KindDefinition, CanonicalBlockIR, PartialKindEvent } from '@ai-matrx/content-ir';
4
4
 
@@ -121,7 +121,12 @@ interface ContentIrHost extends ContentIrRenderSeams {
121
121
  */
122
122
  interface KindRouteEnv {
123
123
  kinds: Pick<KindDefinitionSource, "getDefinition">;
124
- components: Pick<ComponentResolutionSource, "resolve">;
124
+ /**
125
+ * `hasSettled` is optional and read ONLY to suppress a negative verdict from
126
+ * a registry that has not loaded yet — see THE COLD-VERDICT RULE on
127
+ * `ComponentResolutionSource`.
128
+ */
129
+ components: Pick<ComponentResolutionSource, "resolve"> & Partial<Pick<ComponentResolutionSource, "hasSettled">>;
125
130
  reportError: ContentIrErrorReporter;
126
131
  platform: string;
127
132
  }
@@ -1,4 +1,4 @@
1
- import { C as ComponentResolutionSource, b as ContentIrErrorReporter, a as ComponentResolution } from './component-resolution.types-fvR92hW7.cjs';
1
+ import { C as ComponentResolutionSource, b as ContentIrErrorReporter, a as ComponentResolution } from './component-resolution.types-DLO2w-0n.cjs';
2
2
  import { ReactNode } from 'react';
3
3
  import { KindDefinition, CanonicalBlockIR, PartialKindEvent } from '@ai-matrx/content-ir';
4
4
 
@@ -121,7 +121,12 @@ interface ContentIrHost extends ContentIrRenderSeams {
121
121
  */
122
122
  interface KindRouteEnv {
123
123
  kinds: Pick<KindDefinitionSource, "getDefinition">;
124
- components: Pick<ComponentResolutionSource, "resolve">;
124
+ /**
125
+ * `hasSettled` is optional and read ONLY to suppress a negative verdict from
126
+ * a registry that has not loaded yet — see THE COLD-VERDICT RULE on
127
+ * `ComponentResolutionSource`.
128
+ */
129
+ components: Pick<ComponentResolutionSource, "resolve"> & Partial<Pick<ComponentResolutionSource, "hasSettled">>;
125
130
  reportError: ContentIrErrorReporter;
126
131
  platform: string;
127
132
  }
package/dist/route.cjs CHANGED
@@ -123,6 +123,8 @@ function applyIrKindRoute(block, env, options) {
123
123
  if (envelope.root.kindState === "pending_schema") return block;
124
124
  const def = env.kinds.getDefinition(kind);
125
125
  const resolution = env.components.resolve(kind, env.platform, "output");
126
+ const componentsSettled = env.components.hasSettled?.() ?? true;
127
+ if (!componentsSettled && !resolution && !def) return block;
126
128
  if (envelope.root.kindState === "raw") {
127
129
  return routeToGeneric(
128
130
  block,
@@ -1 +1 @@
1
- {"version":3,"sources":["../route.ts","../route/kind-route.ts","../route/partial-kind-route.ts","../route/route-binding.ts"],"sourcesContent":["/**\n * `@ai-matrx/content-ir-react/route` — the pure render decisions, callable\n * outside React (reducers, stream accumulators, server-side shape doctors,\n * tests): THE KIND ROUTE, the provisional (streaming partial kinds) route,\n * and the per-host binding factory. Pure TS — deliberately unstamped.\n */\nexport * from \"./route/kind-route\";\nexport * from \"./route/partial-kind-route\";\nexport * from \"./route/route-binding\";\n","/**\n * THE KIND ROUTE — the render flip, as a pure block transform.\n *\n * A block whose `metadata.__ir` envelope resolved a REGISTERED kind is routed\n * to that kind's component: via the legacy-bridge facet (`legacyBlockType` +\n * `toLegacyServerData`) when the kind has one, so the block enters the host's\n * existing renderer as its real type with envelope-derived serverData;\n * otherwise via the component resolver. Blocks with no envelope, an\n * unregistered kind, or no bridge facet pass through UNTOUCHED — the strangler\n * seam.\n *\n * This is where a bare/fenced JSON flashcard_set — which a text detector could\n * only ever call \"code\" — becomes real flashcards, live while streaming.\n *\n * PORTABILITY. This function was matrx-frontend's `react/kind-route.ts` and is\n * the single most-copied thing in the system: every UI that renders a kind has\n * to make exactly these decisions in exactly this order, and a second\n * implementation of them is a guaranteed divergence. It takes its registries,\n * its platform, and its error sink as an {@link KindRouteEnv} argument rather\n * than importing them, so it is callable from a reducer, a stream accumulator,\n * a test, or a React render — in any app.\n *\n * Semantics: `matrx-frontend/features/content-ir/docs/SHAPE_SYSTEM.md`\n * (registry, dual gate, `kind_component` resolution, rulings R1 + R6).\n */\n\nimport {\n envelopeFromCompleteValue,\n readEnvelope,\n readObjectKind,\n} from \"@ai-matrx/content-ir\";\nimport type { ComponentResolution } from \"../resolver/component-resolution.types\";\nimport type { IrRoutableBlock, KindRouteEnv } from \"../host/host-types\";\n\n/**\n * Runtime routing marker (the Shape System's verification hook): stamped on\n * `metadata.__ir_route` whenever a block routes AND the component resolver\n * produced the decision. `by` says which resolver tier answered (\"compiled\"\n * floor vs a warm `content_ir.kind_component` row) — the live proof of\n * registry-resolution vs hard-coded fallback. Metadata-only, non-breaking.\n */\nexport const IR_ROUTE_KEY = \"__ir_route\" as const;\n\n/**\n * The component key the R6 generic fallback routes to — the official renderer\n * for a KNOWN shape that nothing render-trusted claims. Hosts map this key to\n * their generic structured view (the package ships one: `GenericStructuredView`).\n */\nexport const GENERIC_STRUCTURED_COMPONENT_KEY = \"generic_structured\" as const;\n\n/**\n * The block type a DB-sourced (user-authored) kind component renders as.\n * FE-synthesized: produced ONLY here, never emitted upstream. A host that has\n * no sandbox for user components simply does not map this key — the block then\n * falls to that host's unknown-type handling, which is honest.\n */\nexport const DB_KIND_COMPONENT_KEY = \"db_kind_component\" as const;\n\n/**\n * A DB row is render-trusted as a USER component when it is active, declares\n * `source='db'` (R1: db = web sandbox only), and actually carries a component\n * body. An active db-source row WITHOUT a body is a data defect — reported\n * loudly, and the route then falls through to the bundled behavior (never\n * un-render).\n */\nfunction isDbSourceResolution(\n resolution: ComponentResolution | null,\n): resolution is ComponentResolution {\n return (\n resolution !== null &&\n resolution.resolvedBy === \"db\" &&\n resolution.source === \"db\" &&\n resolution.isActive\n );\n}\n\n// SESSION LATCH ON A globalThis SLOT — never a module-level variable. With the\n// package built `splitting: false` in dual ESM/CJS and multiple subpath\n// entries, this module is duplicated into the root bundle and the `./route`\n// bundle, and CJS/ESM each instantiate their own graph — a module-level Set\n// would silently split the latch (the kit confirm-opener precedent). Never\n// \"clean this up\" into a module local.\nconst SOURCELESS_DB_ROW_SLOT = Symbol.for(\n \"ai-matrx.content-ir-react.sourceless-db-row-reports\",\n);\ntype SourcelessSlotHolder = typeof globalThis & {\n [SOURCELESS_DB_ROW_SLOT]?: Set<string>;\n};\nconst reportedSourcelessDbRows: Set<string> = ((globalThis as SourcelessSlotHolder)[\n SOURCELESS_DB_ROW_SLOT\n] ??= new Set<string>());\n\n/** Loud recovery: an active source='db' row with no component_source. */\nfunction reportDbRowWithoutSource(kind: string, env: KindRouteEnv): void {\n const message = `[content-ir] kind_component for \"${kind}\" declares source='db' + is_active but has NO component_source — data defect; falling through to bundled rendering.`;\n if (!reportedSourcelessDbRows.has(kind)) {\n reportedSourcelessDbRows.add(kind);\n console.error(message);\n }\n env.reportError({ source: \"content-ir\", message, raw: { kind } });\n}\n\n/** Test-only reset of the once-per-kind console latch. */\nexport function resetSourcelessDbRowReports(): void {\n reportedSourcelessDbRows.clear();\n}\n\n/**\n * The db-override flip (R6: db overrides bundled): an ACTIVE `source='db'` row\n * carrying a component body wins over BOTH the compiled bridge and any bundled\n * resolution. The block re-types to `db_kind_component`; the host re-resolves\n * the row and compiles/sandboxes it. Returns null when the flip does not apply.\n */\nfunction routeToDbComponent<T extends IrRoutableBlock>(\n block: T,\n kind: string,\n resolution: ComponentResolution | null,\n env: KindRouteEnv,\n): T | null {\n if (!isDbSourceResolution(resolution)) return null;\n // Gate on the FLAG, not body presence: a lazy host's warm list is\n // body-less (metadata only) and the body arrives per kind via the cold\n // fetch — the row still routes, and the renderer compiles the body once it\n // lands. A row whose flag says it truly has no body screams and falls\n // through, exactly as before.\n if (!resolution.hasComponentSource) {\n reportDbRowWithoutSource(kind, env);\n return null;\n }\n if (block.type === DB_KIND_COMPONENT_KEY) return block;\n return {\n ...block,\n type: DB_KIND_COMPONENT_KEY,\n // The compiled/sandboxed component reads the envelope, never the raw\n // region's annotation serverData (same poison rule as bridged kinds).\n serverData: undefined,\n metadata: withRouteMarker(block.metadata, resolution),\n };\n}\n\n/** Why a block landed on the generic viewer instead of a real renderer. */\nexport type GenericFallbackReason =\n /** No compiled bridge and no `content_ir.kind_component` row at all. */\n | \"no-component\"\n /** A component row exists but is held `is_active = false`. */\n | \"inactive\"\n /**\n * An ACTIVE component row exists and names `generic_structured` — i.e. the\n * fallback, registered under a component's name. This reads as coverage to\n * every count-the-rows check on the platform and is not: the reader still\n * gets a key/value dump. Kept as its own reason because the repair differs\n * (author a component AND retire the decoy row), and because a page that\n * silently marked itself `by: \"bundled\"` here is how 226 of 428 active\n * kinds came to be certified as renderable while rendering generically\n * (found 2026-08-23).\n */\n | \"generic-row\"\n /**\n * The envelope carries a kind-preserved RAW: the payload identified a\n * registered kind and its value FAILED a check — a schema violation, an\n * array-item kind mismatch, a duplicate key, a contradicted speculation.\n * The instance is BROKEN, not component-less — the repair is fixing the\n * payload or the schema, and the generic floor must acknowledge the kind and\n * surface the recorded problems.\n *\n * NOT this: a kind whose schema was never available (`kindState:\n * \"unverified\"`). Nothing checked that value, so calling it broken is a\n * false accusation — it routes to its component. The two were one state\n * until 2026-08-29 and conflating them was a platform-wide outage.\n */\n | \"broken-instance\"\n /**\n * The slug is not in the registry at all (typo, foreign emitter, a shape\n * not yet created). Routed anyway — Arman's 2026-08-29 ruling: a root\n * `__kind` key means the kind system owns the render, no exceptions. The\n * repair is creating/registering the shape (or fixing the slug).\n */\n | \"unregistered\";\n\nexport interface IrRouteMarker {\n by: ComponentResolution[\"resolvedBy\"] | \"generic\";\n key: string;\n /**\n * Only on the generic fallback: the shape is NOT render-trusted, so the\n * viewer must say so out loud (R6 — never an error, never hidden content).\n */\n unverified?: true;\n reason?: GenericFallbackReason;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isRouteMarker(value: unknown): value is IrRouteMarker {\n return (\n isRecord(value) &&\n typeof value.by === \"string\" &&\n typeof value.key === \"string\"\n );\n}\n\n/** Read the routing marker a block picked up at the seam (or null). */\nexport function readIrRouteMarker(\n metadata: Record<string, unknown> | null | undefined,\n): IrRouteMarker | null {\n const candidate = metadata?.[IR_ROUTE_KEY];\n return isRouteMarker(candidate) ? candidate : null;\n}\n\nfunction withRouteMarker(\n metadata: Record<string, unknown> | undefined,\n resolution: ComponentResolution,\n): Record<string, unknown> {\n return {\n ...metadata,\n [IR_ROUTE_KEY]: {\n by: resolution.resolvedBy,\n key: resolution.componentKey,\n } satisfies IrRouteMarker,\n };\n}\n\n/**\n * R6's sanctioned disposition for a shape the platform KNOWS (a kind\n * definition supplied its schema) but nothing render-trusted claims: the\n * generic structured viewer, carrying an honest \"unverified shape\" affordance\n * — never an error, never a raw code block, never hidden content.\n *\n * `serverData` is CLEARED for the same reason the resolver-only path clears\n * it: a raw region's annotation (`{ language: \"json\" }`) is not kind data, and\n * the generic viewer reads the envelope, not serverData.\n */\nfunction routeToGeneric<T extends IrRoutableBlock>(\n block: T,\n reason: GenericFallbackReason,\n): T {\n if (block.type === GENERIC_STRUCTURED_COMPONENT_KEY) return block;\n\n return {\n ...block,\n type: GENERIC_STRUCTURED_COMPONENT_KEY,\n serverData: undefined,\n metadata: {\n ...block.metadata,\n [IR_ROUTE_KEY]: {\n by: \"generic\",\n key: GENERIC_STRUCTURED_COMPONENT_KEY,\n unverified: true,\n reason,\n } satisfies IrRouteMarker,\n },\n };\n}\n\nexport interface KindRouteOptions {\n /**\n * Block types this host OWNS and the route must never re-type, however good\n * the envelope on them looks.\n *\n * matrx-frontend passes `[\"artifact\"]`: an artifact block has an identity, a\n * version, and a Canvas to open in, and since 2026-08-18 it carries\n * `metadata.__ir` so SELECTORS can read the envelope. That envelope is DATA\n * there, not a route — re-typing it to the bare kind component would strip\n * the artifact chrome and lose the door to the Canvas.\n */\n ownedTypes?: readonly string[];\n}\n\nexport function applyIrKindRoute<T extends IrRoutableBlock>(\n block: T,\n env: KindRouteEnv,\n options?: KindRouteOptions,\n): T {\n if (options?.ownedTypes?.includes(block.type)) return block;\n\n const envelope = readEnvelope(block.metadata);\n if (!envelope) return block;\n\n const kind = envelope.root.kind;\n if (!kind) return block; // raw / pending — the host's own rendering stands\n\n // An identified kind whose SCHEMA is still cold-fetching (pending_schema) has\n // no compliant value yet — routing now would hand a component early scalars\n // at best. The host's loading layer owns this window; the parser upgrades in\n // place the moment the schema lands, and end() converts a lost race to a\n // kind-preserving raw — both of which route normally.\n if (envelope.root.kindState === \"pending_schema\") return block;\n\n const def = env.kinds.getDefinition(kind);\n const resolution = env.components.resolve(kind, env.platform, \"output\");\n\n // A kind-preserved `raw` is a BROKEN instance: something CHECKED this value\n // and it failed — a schema violation, an array-item kind mismatch, a\n // duplicate key, a contradicted speculation. No component (bridge or db) may\n // claim a non-compliant value; the generic floor acknowledges the kind and\n // the envelope's recorded problems (residue notices, the raw_fallback\n // reason) are the host's to show. An UNREGISTERED slug routes here too —\n // Arman's 2026-08-29 ruling: a root `__kind` key means the kind system owns\n // the render, NO exceptions. Repaint upgrades it the moment the registries\n // learn more.\n //\n // 🚨 `unverified` DELIBERATELY DOES NOT MATCH HERE, AND MUST NEVER BE ADDED.\n // That state means no schema was ever available, so nothing was checked —\n // the value is intact and quite possibly perfect. It falls through to the\n // component paths below exactly as it did before 2026-08-28, when this gate\n // read the old undifferentiated `raw` and took ~221 live kinds' components\n // away overnight: every kind whose schema cannot be reconstructed (nested\n // objects, arrays of children, loose fields) degrades this way, and each one\n // rendered as a key/value dump while its purpose-built component sat one\n // line below, never asked for. Widening this condition re-opens that outage.\n // See `IrKindState` in @ai-matrx/content-ir.\n if (envelope.root.kindState === \"raw\") {\n return routeToGeneric(\n block,\n def || resolution ? \"broken-instance\" : \"unregistered\",\n );\n }\n\n // ── DB user-component path — db overrides bundled (ruling R6) ─────────────\n // Checked FIRST so a user's registered component actually renders; a\n // defective row (no source) screams and falls through to bundled behavior —\n // never un-renders.\n const dbRouted = routeToDbComponent(block, kind, resolution, env);\n if (dbRouted) return dbRouted;\n\n // ── Compiled-bridge path — trusted at bootstrap (ruling R6) ───────────────\n // A kind carrying a legacyBlockType facet ALWAYS routes: the host's existing\n // behavior for every registered kind, and the production floor a DB row can\n // refine (the marker records which tier resolved) but never un-render.\n if (def?.legacyBlockType) {\n // A block ALREADY emitted as the legacy type carrying its own serverData is\n // authoritative — the server typed it AND provided the component's data.\n if (block.type === def.legacyBlockType && block.serverData) return block;\n\n // ROUTING a raw region (e.g. \"code\" → \"flashcards\"): the envelope is the\n // single source of truth. The block's own serverData here is NOT kind data\n // — it is the raw region's annotation (`{ language: \"json\" }`). Preferring\n // that junk handed the legacy component `{ language: \"json\" }` instead of\n // cards/questions/slides — the 2026-07-04 \"No flashcards available yet\"\n // bug — so it is REPLACED (bridge output) or CLEARED (bridgeless kinds\n // parse `content` themselves), never forwarded.\n const serverData = def.toLegacyServerData?.(envelope);\n\n if (block.type === def.legacyBlockType && serverData === undefined) {\n return block; // nothing to change — keep reference stability\n }\n\n return {\n ...block,\n type: def.legacyBlockType,\n serverData,\n ...(resolution\n ? { metadata: withRouteMarker(block.metadata, resolution) }\n : null),\n };\n }\n\n // ── Resolver-only path (no compiled bridge): the registry decides ─────────\n // R6: only an ACTIVE resolution is render-trusted. An inactive row means\n // \"held\", not \"route it anyway\".\n if (resolution?.isActive) {\n // A row naming the fallback is NOT a resolution. Routing it as one stamped\n // `by: \"bundled\"` on the block and told every reader the shape had a\n // renderer — the platform's own generic viewer, wearing a component's\n // clothes. It goes to the honest generic path with its own reason instead.\n if (resolution.componentKey === GENERIC_STRUCTURED_COMPONENT_KEY) {\n return routeToGeneric(block, \"generic-row\");\n }\n if (block.type === resolution.componentKey) return block;\n\n return {\n ...block,\n type: resolution.componentKey,\n // No compiled bridge exists — the routed component parses `content`\n // itself; the raw region's annotation serverData is CLEARED.\n serverData: undefined,\n metadata: withRouteMarker(block.metadata, resolution),\n };\n }\n\n // ── R6 generic fallback: a KNOWN shape that nothing render-trusted claims ─\n // `def` exists ⇒ a kind definition supplied this kind's schema: the platform\n // knows the shape. It has no compiled bridge, and either no `kind_component`\n // row at all (`no-component`) or one held inactive (`inactive`). R6 sends\n // exactly this case to the generic structured viewer with an \"unverified\n // shape\" affordance — the disposition that retires permanently-red\n // \"no-component root\" kinds without pretending they have renderers.\n if (def) {\n return routeToGeneric(block, resolution ? \"inactive\" : \"no-component\");\n }\n\n // A kind slug the platform has NO definition for (a typo, a foreign\n // emitter, a not-yet-created shape). 🚨 Arman's ruling, 2026-08-29: a root\n // `__kind` key means the kind system owns the render — NO exceptions. The\n // old strangler carve-out (\"not ours to claim\", teaching content stayed a\n // raw code block) is retired: an unregistered kind renders through the\n // generic floor with `reason: \"unregistered\"`, so the reader always sees\n // the payload acknowledged AS a kind instance with what is known about it.\n // A repaint hook upgrades this block the moment the registries learn the\n // kind.\n return routeToGeneric(block, \"unregistered\");\n}\n\n/**\n * Rehydration route for STRUCTURED persisted artifacts.\n *\n * A materialized kind artifact stores its zero-loss value object (carrying\n * `__kind`) alongside its row. Given that stored value, derive the registered\n * kind's legacy `serverData` WITHOUT re-parsing any text: the value wraps into\n * a complete envelope and runs through the same `toLegacyServerData` bridge the\n * live stream uses. Returns null for non-objects, unregistered kinds, or kinds\n * without a legacy bridge — callers fall back to their string-payload path.\n */\nexport function kindServerDataFromStoredValue(\n value: unknown,\n env: Pick<KindRouteEnv, \"kinds\">,\n): Record<string, unknown> | null {\n if (!isRecord(value)) return null;\n const kind = readObjectKind(value);\n if (!kind) return null;\n\n const def = env.kinds.getDefinition(kind);\n if (!def?.toLegacyServerData) return null;\n\n return def.toLegacyServerData(envelopeFromCompleteValue(value, kind)) ?? null;\n}\n","/**\n * Routing the PROVISIONAL half of the streaming partial-kinds contract.\n *\n * Cross-repo system-of-record (read it before changing anything here):\n * `common-docs/systems/content-ir-system/STREAMING_PARTIAL_KINDS.md` §8.\n * The reader/validator half lives in `@ai-matrx/content-ir` (`wire/partial-kind`);\n * the wire gate runs in each host's stream ingest.\n *\n * WHAT THIS DOES\n * --------------\n * While a structured region streams, the server announces what it thinks the\n * region IS and what has arrived so far (`metadata.__ir_partial`). This module\n * turns that provisional event into a routed block that renders through the\n * EXACT SAME component the final value renders in — which is the entire point:\n * a bespoke skeleton renderer would be a second render path and is banned.\n *\n * HOW, without touching the verified channel\n * ------------------------------------------\n * `root` is deliberately `IrStructuredNode`-shaped, so the event wraps into a\n * `CanonicalBlockIR` and every existing reader — the compiled bridge, the\n * component resolver, the db-component flip, the generic viewer — works\n * unchanged. That provisional envelope is placed on a RENDER-LOCAL COPY of the\n * block's metadata under `__ir`, never on the wire and never in host state. The\n * block also carries `__ir_provisional: true` so any downstream reader can tell\n * a provisional render from a verified one.\n *\n * THE POSTURE: WITHHOLD BY DEFAULT, OPT IN PER KIND\n * -------------------------------------------------\n * A provisional value MAY be missing required fields — that is what the\n * `partial_unvalidated` notice declares — and §8 of the contract requires that\n * a component which throws on an absent field is not routed one. Rather than\n * audit every component, the default is WITHHOLD: nothing changes and the block\n * keeps its loading skeleton. A kind opts in with `partialReady: true` on its\n * registry definition. If an opted-in component throws anyway,\n * `ProvisionalKindBoundary` screams and calls `markKindPartialUnsafe`, which\n * drops that kind back to withhold for the rest of the session — loud recovery,\n * never a broken surface.\n *\n * TERMINALS\n * ---------\n * `superseded` and `retracted` produce NO provisional render, so the swap to\n * the final value happens in the same frame the terminal arrives — never a\n * flicker through an empty state. Both are explicit EVENTS: the terminal is\n * never inferred from the arrival of `__ir`, because a completed block often\n * has no `__ir` at all (unregistered kind, schema drift, cold catalog) and\n * inferring it would leave the skeleton up forever in exactly those cases.\n */\n\nimport {\n IR_ENVELOPE_KEY,\n IR_PARTIAL_KEY,\n IR_VERSION,\n isProvisionalKind,\n readEnvelope,\n readPartialKindEvent,\n} from \"@ai-matrx/content-ir\";\nimport type { CanonicalBlockIR, PartialKindEvent } from \"@ai-matrx/content-ir\";\nimport type { IrRoutableBlock, KindRouteEnv } from \"../host/host-types\";\nimport { applyIrKindRoute, type KindRouteOptions } from \"./kind-route\";\n\n/**\n * Marker stamped on a render-local block whose `__ir` is PROVISIONAL. Never\n * emitted by a producer, never persisted, never on the wire.\n */\nexport const IR_PROVISIONAL_KEY = \"__ir_provisional\" as const;\n\n/** True when this block's metadata carries a provisional (not verified) envelope. */\nexport function isProvisionalBlock(\n metadata: Record<string, unknown> | null | undefined,\n): boolean {\n return metadata?.[IR_PROVISIONAL_KEY] === true;\n}\n\n/** Wrap a validated `partial` event into the envelope shape every IR reader consumes. */\nexport function envelopeFromPartialKind(\n event: PartialKindEvent,\n): CanonicalBlockIR {\n return {\n v: IR_VERSION,\n // The partial channel is only ever produced by the Python detector; the\n // envelope's `engine` union has no third member and inventing one would\n // break every existing reader.\n engine: \"py-block-detector\",\n fingerprint: event.fingerprint,\n root: event.root,\n };\n}\n\n/**\n * Kinds whose component threw while rendering a provisional value. Session-\n * scoped: the kind falls back to withhold (its loading skeleton) until a\n * reload, so one bad component cannot keep re-throwing on every block.\n */\n// SESSION LATCH ON A globalThis SLOT — never a module-level variable. This\n// latch is WRITTEN from the `./react` bundle (ProvisionalKindBoundary calls\n// markKindPartialUnsafe) and READ from the `./route` bundle\n// (isPartialReadyKind); with `splitting: false` dual ESM/CJS output those are\n// different module instantiations, and a module-level Set would silently split\n// the writer from the reader (the kit confirm-opener precedent). Never \"clean\n// this up\" into a module local.\nconst PARTIAL_UNSAFE_SLOT = Symbol.for(\n \"ai-matrx.content-ir-react.partial-unsafe-kinds\",\n);\ntype PartialUnsafeSlotHolder = typeof globalThis & {\n [PARTIAL_UNSAFE_SLOT]?: Set<string>;\n};\nconst partialUnsafeKinds: Set<string> = ((globalThis as PartialUnsafeSlotHolder)[\n PARTIAL_UNSAFE_SLOT\n] ??= new Set<string>());\n\n/** Loud recovery hook — called by ProvisionalKindBoundary when a render throws. */\nexport function markKindPartialUnsafe(kind: string): void {\n partialUnsafeKinds.add(kind);\n}\n\n/** Test-only reset of the session latch. */\nexport function resetPartialUnsafeKinds(): void {\n partialUnsafeKinds.clear();\n}\n\n/**\n * Has this kind opted in to being handed a provisional value? Withhold is the\n * default; see the module doc.\n */\nexport function isPartialReadyKind(\n kind: string,\n env: Pick<KindRouteEnv, \"kinds\">,\n): boolean {\n if (!kind || partialUnsafeKinds.has(kind)) return false;\n return env.kinds.getDefinition(kind)?.partialReady === true;\n}\n\nexport interface PartialRenderOptions extends KindRouteOptions {\n /**\n * Is the STREAM still running? Message-wide, deliberately — not this block's\n * own completion.\n *\n * 🚨 THE ANTI-STUCK-SKELETON BACKSTOP. Law 1 of the contract says every\n * partial ends in exactly one terminal, and that law is the ONLY thing\n * standing between a user and a \"Still arriving\" skeleton that never\n * resolves. It is a producer guarantee with at least three ways to not fire:\n * the drain skips a block missing from the final block list, the emitter\n * early-returns once the stream ended or was cancelled (so a client abort\n * drops every retraction), and a flush failure is swallowed so it never kills\n * a run.\n *\n * Once the stream is over, no terminal can ever arrive, so a still-open\n * provisional is stuck by definition — drop it and let the block's own\n * content and `__ir` be the truth. Correct to be message-wide: a terminal for\n * THIS block may still be in flight while the block itself looks finished.\n *\n * `undefined` reads as active, so a caller that does not thread stream state\n * keeps live rendering rather than silently losing it.\n */\n streamActive?: boolean;\n}\n\n/**\n * The ANNOUNCED-but-not-yet-renderable state: the server has said what this\n * region is, and the region cannot render its real component yet.\n *\n * WHY THIS EXISTS SEPARATELY FROM THE VERIFIED CHANNEL. On a chat stream the\n * host's own accumulator fills `__ir` in as it parses. A WORKFLOW run's lane\n * does not: when the server opens the block scope it marks the text channel\n * `block_shadowed` and the lane stops feeding its accumulator, precisely so one\n * region is never rendered twice under two sets of block ids\n * (STREAMING_PARTIAL_KINDS.md §7b rule 4). So on a run page there is NO\n * streaming `__ir` — the ONLY thing that knows what the region is, is the\n * partial channel. Without this, a workflow node's structured answer fell\n * through to the raw-text renderer: a generic loader, then raw JSON\n * accumulating, then a swap at the end.\n *\n * Returns the provisional envelope to feed the kind's loading component, or\n * null when there is nothing announced (no event, a terminal, a dead stream).\n * Deliberately independent of `partialReady`: withholding a VALUE from a\n * component that might throw on it is a real decision, but withholding the\n * kind's own loading state is not — a skeleton cannot throw, and the reader\n * seeing what is coming is the whole point.\n */\nexport function resolveAnnouncedKindLoading(\n block: { metadata?: Record<string, unknown> },\n options?: Pick<PartialRenderOptions, \"streamActive\">,\n): { kind: string; envelope: CanonicalBlockIR } | null {\n // Same anti-stuck-skeleton backstop as resolveProvisionalKindRender: once the\n // stream is over no terminal can arrive, so a still-open announcement is\n // stuck by definition and must not hold a loader on screen forever.\n if (options?.streamActive === false) return null;\n\n const event = readPartialKindEvent(block.metadata);\n if (!isProvisionalKind(event)) return null;\n const kind = event.root.kind;\n if (!kind) return null;\n\n // A region that already VERIFIED is the truth; never cover it with a loader.\n const verified = readEnvelope(block.metadata);\n if (verified && verified.root.status === \"complete\") return null;\n\n return { kind, envelope: envelopeFromPartialKind(event) };\n}\n\nexport interface ProvisionalKindRender<T> {\n /** The routed block — same type/serverData shape the final value produces. */\n block: T;\n /** The announced (speculative) kind. */\n kind: string;\n /** Per-block ordering key, for diagnostics. */\n seq: number;\n /** The provisional envelope — feeds the loading skeleton used as the throw fallback. */\n envelope: CanonicalBlockIR;\n}\n\n/**\n * Resolve a block's provisional render, or null when there is nothing to show\n * provisionally (no event, a terminal event, a withheld kind, a kind nothing\n * can route, or a verified envelope that already won).\n *\n * Pure: no React, no host state, no side effects beyond the registry reads.\n */\nexport function resolveProvisionalKindRender<\n T extends IrRoutableBlock & { metadata?: Record<string, unknown> },\n>(\n block: T,\n env: KindRouteEnv,\n options?: PartialRenderOptions,\n): ProvisionalKindRender<T> | null {\n if (options?.streamActive === false) return null;\n\n const event = readPartialKindEvent(block.metadata);\n // Terminal (superseded / retracted) → no provisional render, in this frame.\n if (!isProvisionalKind(event)) return null;\n\n const kind = event.root.kind;\n if (!isPartialReadyKind(kind, env)) return null;\n\n // A verified envelope that has already completed is the truth — a late or\n // duplicated partial must never displace it.\n const verified = readEnvelope(block.metadata);\n if (verified && verified.root.status === \"complete\") return null;\n\n const { [IR_PARTIAL_KEY]: _partial, ...rest } = block.metadata ?? {};\n void _partial;\n\n const envelope = envelopeFromPartialKind(event);\n\n const provisionalBlock = {\n ...block,\n // The raw region annotation (`{ language: \"json\" }`) is not kind data —\n // same poison rule the verified route follows.\n serverData: undefined,\n metadata: {\n ...rest,\n [IR_ENVELOPE_KEY]: envelope,\n [IR_PROVISIONAL_KEY]: true,\n },\n } as T;\n\n const routed = applyIrKindRoute(provisionalBlock, env, options);\n // Nothing claimed it (unknown kind, no component) — `applyIrKindRoute`\n // returns the SAME reference. Withhold rather than render raw partial JSON.\n if (routed === provisionalBlock) return null;\n // A bridged kind whose bridge DECLINED this value (too thin to render — a\n // quiz with no answerable question yet) routed on type alone, which would\n // hand the component the partial JSON text to parse. Withhold: the loading\n // skeleton stays up for this frame and the next `seq` tries again.\n if (\n env.kinds.getDefinition(kind)?.toLegacyServerData &&\n !(routed as { serverData?: unknown }).serverData\n ) {\n return null;\n }\n\n return { block: routed, kind, seq: event.seq, envelope };\n}\n","/**\n * THE BOUND ROUTE — the pure route functions with a host's env and owned\n * types partially applied, built ONCE in a host wiring module.\n *\n * Every host was writing the same wrapper file by hand: one function per pure\n * route, each forwarding `matrx…Env` + `ownedTypes` (matrx-frontend carried\n * two such modules; the dashboard a third). Per C22 that repeated delta is\n * package-provided: a host module now only INJECTS (its env, its owned block\n * types) and re-exports what this factory returns.\n *\n * The functions are the exact pure routes — read `kind-route.ts` /\n * `partial-kind-route.ts` for semantics; nothing behavioral lives here.\n */\n\nimport type { IrRoutableBlock, KindRouteEnv } from \"../host/host-types\";\nimport {\n applyIrKindRoute,\n kindServerDataFromStoredValue,\n type KindRouteOptions,\n} from \"./kind-route\";\nimport {\n isPartialReadyKind,\n resolveProvisionalKindRender,\n type PartialRenderOptions,\n type ProvisionalKindRender,\n} from \"./partial-kind-route\";\n\nexport interface KindRouteBinding {\n /** Route one block through the bound registries. */\n applyIrKindRoute<T extends IrRoutableBlock>(block: T): T;\n /**\n * Rehydration route for STRUCTURED persisted artifacts: given a stored\n * zero-loss value object, derive the registered kind's legacy `serverData`\n * with no re-parse. Null for non-objects, unregistered kinds, or kinds\n * without a legacy bridge.\n */\n kindServerDataFromStoredValue(value: unknown): Record<string, unknown> | null;\n /** Has this kind opted in to being handed a provisional value? */\n isPartialReadyKind(kind: string): boolean;\n /**\n * Resolve a block's provisional render, or null when there is nothing to\n * show provisionally (no event, a terminal event, a withheld kind, a kind\n * nothing can route, or a verified envelope that already won).\n */\n resolveProvisionalKindRender<\n T extends IrRoutableBlock & { metadata?: Record<string, unknown> },\n >(\n block: T,\n options?: Pick<PartialRenderOptions, \"streamActive\">,\n ): ProvisionalKindRender<T> | null;\n}\n\n/** Bind the pure routes to one host's env + owned block types. */\nexport function createKindRouteBinding(\n env: KindRouteEnv,\n options?: KindRouteOptions,\n): KindRouteBinding {\n const ownedTypes = options?.ownedTypes;\n return {\n applyIrKindRoute: (block) =>\n applyIrKindRoute(block, env, ownedTypes ? { ownedTypes } : undefined),\n kindServerDataFromStoredValue: (value) =>\n kindServerDataFromStoredValue(value, env),\n isPartialReadyKind: (kind) => isPartialReadyKind(kind, env),\n resolveProvisionalKindRender: (block, streamOptions) =>\n resolveProvisionalKindRender(block, env, {\n ...streamOptions,\n ...(ownedTypes ? { ownedTypes } : null),\n }),\n };\n}\n"],"mappings":"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","names":["import_content_ir"]}
1
+ {"version":3,"sources":["../route.ts","../route/kind-route.ts","../route/partial-kind-route.ts","../route/route-binding.ts"],"sourcesContent":["/**\n * `@ai-matrx/content-ir-react/route` — the pure render decisions, callable\n * outside React (reducers, stream accumulators, server-side shape doctors,\n * tests): THE KIND ROUTE, the provisional (streaming partial kinds) route,\n * and the per-host binding factory. Pure TS — deliberately unstamped.\n */\nexport * from \"./route/kind-route\";\nexport * from \"./route/partial-kind-route\";\nexport * from \"./route/route-binding\";\n","/**\n * THE KIND ROUTE — the render flip, as a pure block transform.\n *\n * A block whose `metadata.__ir` envelope resolved a REGISTERED kind is routed\n * to that kind's component: via the legacy-bridge facet (`legacyBlockType` +\n * `toLegacyServerData`) when the kind has one, so the block enters the host's\n * existing renderer as its real type with envelope-derived serverData;\n * otherwise via the component resolver. Blocks with no envelope, an\n * unregistered kind, or no bridge facet pass through UNTOUCHED — the strangler\n * seam.\n *\n * This is where a bare/fenced JSON flashcard_set — which a text detector could\n * only ever call \"code\" — becomes real flashcards, live while streaming.\n *\n * PORTABILITY. This function was matrx-frontend's `react/kind-route.ts` and is\n * the single most-copied thing in the system: every UI that renders a kind has\n * to make exactly these decisions in exactly this order, and a second\n * implementation of them is a guaranteed divergence. It takes its registries,\n * its platform, and its error sink as an {@link KindRouteEnv} argument rather\n * than importing them, so it is callable from a reducer, a stream accumulator,\n * a test, or a React render — in any app.\n *\n * Semantics: `matrx-frontend/features/content-ir/docs/SHAPE_SYSTEM.md`\n * (registry, dual gate, `kind_component` resolution, rulings R1 + R6).\n */\n\nimport {\n envelopeFromCompleteValue,\n readEnvelope,\n readObjectKind,\n} from \"@ai-matrx/content-ir\";\nimport type { ComponentResolution } from \"../resolver/component-resolution.types\";\nimport type { IrRoutableBlock, KindRouteEnv } from \"../host/host-types\";\n\n/**\n * Runtime routing marker (the Shape System's verification hook): stamped on\n * `metadata.__ir_route` whenever a block routes AND the component resolver\n * produced the decision. `by` says which resolver tier answered (\"compiled\"\n * floor vs a warm `content_ir.kind_component` row) — the live proof of\n * registry-resolution vs hard-coded fallback. Metadata-only, non-breaking.\n */\nexport const IR_ROUTE_KEY = \"__ir_route\" as const;\n\n/**\n * The component key the R6 generic fallback routes to — the official renderer\n * for a KNOWN shape that nothing render-trusted claims. Hosts map this key to\n * their generic structured view (the package ships one: `GenericStructuredView`).\n */\nexport const GENERIC_STRUCTURED_COMPONENT_KEY = \"generic_structured\" as const;\n\n/**\n * The block type a DB-sourced (user-authored) kind component renders as.\n * FE-synthesized: produced ONLY here, never emitted upstream. A host that has\n * no sandbox for user components simply does not map this key — the block then\n * falls to that host's unknown-type handling, which is honest.\n */\nexport const DB_KIND_COMPONENT_KEY = \"db_kind_component\" as const;\n\n/**\n * A DB row is render-trusted as a USER component when it is active, declares\n * `source='db'` (R1: db = web sandbox only), and actually carries a component\n * body. An active db-source row WITHOUT a body is a data defect — reported\n * loudly, and the route then falls through to the bundled behavior (never\n * un-render).\n */\nfunction isDbSourceResolution(\n resolution: ComponentResolution | null,\n): resolution is ComponentResolution {\n return (\n resolution !== null &&\n resolution.resolvedBy === \"db\" &&\n resolution.source === \"db\" &&\n resolution.isActive\n );\n}\n\n// SESSION LATCH ON A globalThis SLOT — never a module-level variable. With the\n// package built `splitting: false` in dual ESM/CJS and multiple subpath\n// entries, this module is duplicated into the root bundle and the `./route`\n// bundle, and CJS/ESM each instantiate their own graph — a module-level Set\n// would silently split the latch (the kit confirm-opener precedent). Never\n// \"clean this up\" into a module local.\nconst SOURCELESS_DB_ROW_SLOT = Symbol.for(\n \"ai-matrx.content-ir-react.sourceless-db-row-reports\",\n);\ntype SourcelessSlotHolder = typeof globalThis & {\n [SOURCELESS_DB_ROW_SLOT]?: Set<string>;\n};\nconst reportedSourcelessDbRows: Set<string> = ((globalThis as SourcelessSlotHolder)[\n SOURCELESS_DB_ROW_SLOT\n] ??= new Set<string>());\n\n/** Loud recovery: an active source='db' row with no component_source. */\nfunction reportDbRowWithoutSource(kind: string, env: KindRouteEnv): void {\n const message = `[content-ir] kind_component for \"${kind}\" declares source='db' + is_active but has NO component_source — data defect; falling through to bundled rendering.`;\n if (!reportedSourcelessDbRows.has(kind)) {\n reportedSourcelessDbRows.add(kind);\n console.error(message);\n }\n env.reportError({ source: \"content-ir\", message, raw: { kind } });\n}\n\n/** Test-only reset of the once-per-kind console latch. */\nexport function resetSourcelessDbRowReports(): void {\n reportedSourcelessDbRows.clear();\n}\n\n/**\n * The db-override flip (R6: db overrides bundled): an ACTIVE `source='db'` row\n * carrying a component body wins over BOTH the compiled bridge and any bundled\n * resolution. The block re-types to `db_kind_component`; the host re-resolves\n * the row and compiles/sandboxes it. Returns null when the flip does not apply.\n */\nfunction routeToDbComponent<T extends IrRoutableBlock>(\n block: T,\n kind: string,\n resolution: ComponentResolution | null,\n env: KindRouteEnv,\n): T | null {\n if (!isDbSourceResolution(resolution)) return null;\n // Gate on the FLAG, not body presence: a lazy host's warm list is\n // body-less (metadata only) and the body arrives per kind via the cold\n // fetch — the row still routes, and the renderer compiles the body once it\n // lands. A row whose flag says it truly has no body screams and falls\n // through, exactly as before.\n if (!resolution.hasComponentSource) {\n reportDbRowWithoutSource(kind, env);\n return null;\n }\n if (block.type === DB_KIND_COMPONENT_KEY) return block;\n return {\n ...block,\n type: DB_KIND_COMPONENT_KEY,\n // The compiled/sandboxed component reads the envelope, never the raw\n // region's annotation serverData (same poison rule as bridged kinds).\n serverData: undefined,\n metadata: withRouteMarker(block.metadata, resolution),\n };\n}\n\n/** Why a block landed on the generic viewer instead of a real renderer. */\nexport type GenericFallbackReason =\n /** No compiled bridge and no `content_ir.kind_component` row at all. */\n | \"no-component\"\n /** A component row exists but is held `is_active = false`. */\n | \"inactive\"\n /**\n * An ACTIVE component row exists and names `generic_structured` — i.e. the\n * fallback, registered under a component's name. This reads as coverage to\n * every count-the-rows check on the platform and is not: the reader still\n * gets a key/value dump. Kept as its own reason because the repair differs\n * (author a component AND retire the decoy row), and because a page that\n * silently marked itself `by: \"bundled\"` here is how 226 of 428 active\n * kinds came to be certified as renderable while rendering generically\n * (found 2026-08-23).\n */\n | \"generic-row\"\n /**\n * The envelope carries a kind-preserved RAW: the payload identified a\n * registered kind and its value FAILED a check — a schema violation, an\n * array-item kind mismatch, a duplicate key, a contradicted speculation.\n * The instance is BROKEN, not component-less — the repair is fixing the\n * payload or the schema, and the generic floor must acknowledge the kind and\n * surface the recorded problems.\n *\n * NOT this: a kind whose schema was never available (`kindState:\n * \"unverified\"`). Nothing checked that value, so calling it broken is a\n * false accusation — it routes to its component. The two were one state\n * until 2026-08-29 and conflating them was a platform-wide outage.\n */\n | \"broken-instance\"\n /**\n * The slug is not in the registry at all (typo, foreign emitter, a shape\n * not yet created). Routed anyway — Arman's 2026-08-29 ruling: a root\n * `__kind` key means the kind system owns the render, no exceptions. The\n * repair is creating/registering the shape (or fixing the slug).\n */\n | \"unregistered\";\n\nexport interface IrRouteMarker {\n by: ComponentResolution[\"resolvedBy\"] | \"generic\";\n key: string;\n /**\n * Only on the generic fallback: the shape is NOT render-trusted, so the\n * viewer must say so out loud (R6 — never an error, never hidden content).\n */\n unverified?: true;\n reason?: GenericFallbackReason;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isRouteMarker(value: unknown): value is IrRouteMarker {\n return (\n isRecord(value) &&\n typeof value.by === \"string\" &&\n typeof value.key === \"string\"\n );\n}\n\n/** Read the routing marker a block picked up at the seam (or null). */\nexport function readIrRouteMarker(\n metadata: Record<string, unknown> | null | undefined,\n): IrRouteMarker | null {\n const candidate = metadata?.[IR_ROUTE_KEY];\n return isRouteMarker(candidate) ? candidate : null;\n}\n\nfunction withRouteMarker(\n metadata: Record<string, unknown> | undefined,\n resolution: ComponentResolution,\n): Record<string, unknown> {\n return {\n ...metadata,\n [IR_ROUTE_KEY]: {\n by: resolution.resolvedBy,\n key: resolution.componentKey,\n } satisfies IrRouteMarker,\n };\n}\n\n/**\n * R6's sanctioned disposition for a shape the platform KNOWS (a kind\n * definition supplied its schema) but nothing render-trusted claims: the\n * generic structured viewer, carrying an honest \"unverified shape\" affordance\n * — never an error, never a raw code block, never hidden content.\n *\n * `serverData` is CLEARED for the same reason the resolver-only path clears\n * it: a raw region's annotation (`{ language: \"json\" }`) is not kind data, and\n * the generic viewer reads the envelope, not serverData.\n */\nfunction routeToGeneric<T extends IrRoutableBlock>(\n block: T,\n reason: GenericFallbackReason,\n): T {\n if (block.type === GENERIC_STRUCTURED_COMPONENT_KEY) return block;\n\n return {\n ...block,\n type: GENERIC_STRUCTURED_COMPONENT_KEY,\n serverData: undefined,\n metadata: {\n ...block.metadata,\n [IR_ROUTE_KEY]: {\n by: \"generic\",\n key: GENERIC_STRUCTURED_COMPONENT_KEY,\n unverified: true,\n reason,\n } satisfies IrRouteMarker,\n },\n };\n}\n\nexport interface KindRouteOptions {\n /**\n * Block types this host OWNS and the route must never re-type, however good\n * the envelope on them looks.\n *\n * matrx-frontend passes `[\"artifact\"]`: an artifact block has an identity, a\n * version, and a Canvas to open in, and since 2026-08-18 it carries\n * `metadata.__ir` so SELECTORS can read the envelope. That envelope is DATA\n * there, not a route — re-typing it to the bare kind component would strip\n * the artifact chrome and lose the door to the Canvas.\n */\n ownedTypes?: readonly string[];\n}\n\nexport function applyIrKindRoute<T extends IrRoutableBlock>(\n block: T,\n env: KindRouteEnv,\n options?: KindRouteOptions,\n): T {\n if (options?.ownedTypes?.includes(block.type)) return block;\n\n const envelope = readEnvelope(block.metadata);\n if (!envelope) return block;\n\n const kind = envelope.root.kind;\n if (!kind) return block; // raw / pending — the host's own rendering stands\n\n // An identified kind whose SCHEMA is still cold-fetching (pending_schema) has\n // no compliant value yet — routing now would hand a component early scalars\n // at best. The host's loading layer owns this window; the parser upgrades in\n // place the moment the schema lands, and end() converts a lost race to a\n // kind-preserving raw — both of which route normally.\n if (envelope.root.kindState === \"pending_schema\") return block;\n\n const def = env.kinds.getDefinition(kind);\n const resolution = env.components.resolve(kind, env.platform, \"output\");\n\n // 🚨 THE COLD-VERDICT RULE (Arman, 2026-08-31). A registry that has not\n // loaded yet must never be allowed to publish a NEGATIVE verdict. Every\n // \"this shape isn't registered\" / \"no component\" answer below is a durable,\n // user-visible claim written into the block's metadata — and on the first\n // paint of a fresh tab the resolver has fetched nothing, so those claims\n // were being produced by a registry whose honest answer is \"I haven't\n // looked\". The reader saw a key/value dump captioned \"this shape isn't\n // registered on this platform\" for a shape that was registered, active, and\n // had a component the whole time.\n //\n // Holding the block (exactly as `pending_schema` does) hands the window to\n // the host's loading layer; `useEnsureKindRenderable` fetches, the per-kind\n // repaint fires, and this function re-runs with a settled registry. A\n // POSITIVE answer is never suppressed — if the compiled floor or an already\n // ingested row can name a component, the paths below run immediately.\n const componentsSettled = env.components.hasSettled?.() ?? true;\n if (!componentsSettled && !resolution && !def) return block;\n\n // A kind-preserved `raw` is a BROKEN instance: something CHECKED this value\n // and it failed — a schema violation, an array-item kind mismatch, a\n // duplicate key, a contradicted speculation. No component (bridge or db) may\n // claim a non-compliant value; the generic floor acknowledges the kind and\n // the envelope's recorded problems (residue notices, the raw_fallback\n // reason) are the host's to show. An UNREGISTERED slug routes here too —\n // Arman's 2026-08-29 ruling: a root `__kind` key means the kind system owns\n // the render, NO exceptions. Repaint upgrades it the moment the registries\n // learn more.\n //\n // 🚨 `unverified` DELIBERATELY DOES NOT MATCH HERE, AND MUST NEVER BE ADDED.\n // That state means no schema was ever available, so nothing was checked —\n // the value is intact and quite possibly perfect. It falls through to the\n // component paths below exactly as it did before 2026-08-28, when this gate\n // read the old undifferentiated `raw` and took ~221 live kinds' components\n // away overnight: every kind whose schema cannot be reconstructed (nested\n // objects, arrays of children, loose fields) degrades this way, and each one\n // rendered as a key/value dump while its purpose-built component sat one\n // line below, never asked for. Widening this condition re-opens that outage.\n // See `IrKindState` in @ai-matrx/content-ir.\n if (envelope.root.kindState === \"raw\") {\n return routeToGeneric(\n block,\n def || resolution ? \"broken-instance\" : \"unregistered\",\n );\n }\n\n // ── DB user-component path — db overrides bundled (ruling R6) ─────────────\n // Checked FIRST so a user's registered component actually renders; a\n // defective row (no source) screams and falls through to bundled behavior —\n // never un-renders.\n const dbRouted = routeToDbComponent(block, kind, resolution, env);\n if (dbRouted) return dbRouted;\n\n // ── Compiled-bridge path — trusted at bootstrap (ruling R6) ───────────────\n // A kind carrying a legacyBlockType facet ALWAYS routes: the host's existing\n // behavior for every registered kind, and the production floor a DB row can\n // refine (the marker records which tier resolved) but never un-render.\n if (def?.legacyBlockType) {\n // A block ALREADY emitted as the legacy type carrying its own serverData is\n // authoritative — the server typed it AND provided the component's data.\n if (block.type === def.legacyBlockType && block.serverData) return block;\n\n // ROUTING a raw region (e.g. \"code\" → \"flashcards\"): the envelope is the\n // single source of truth. The block's own serverData here is NOT kind data\n // — it is the raw region's annotation (`{ language: \"json\" }`). Preferring\n // that junk handed the legacy component `{ language: \"json\" }` instead of\n // cards/questions/slides — the 2026-07-04 \"No flashcards available yet\"\n // bug — so it is REPLACED (bridge output) or CLEARED (bridgeless kinds\n // parse `content` themselves), never forwarded.\n const serverData = def.toLegacyServerData?.(envelope);\n\n if (block.type === def.legacyBlockType && serverData === undefined) {\n return block; // nothing to change — keep reference stability\n }\n\n return {\n ...block,\n type: def.legacyBlockType,\n serverData,\n ...(resolution\n ? { metadata: withRouteMarker(block.metadata, resolution) }\n : null),\n };\n }\n\n // ── Resolver-only path (no compiled bridge): the registry decides ─────────\n // R6: only an ACTIVE resolution is render-trusted. An inactive row means\n // \"held\", not \"route it anyway\".\n if (resolution?.isActive) {\n // A row naming the fallback is NOT a resolution. Routing it as one stamped\n // `by: \"bundled\"` on the block and told every reader the shape had a\n // renderer — the platform's own generic viewer, wearing a component's\n // clothes. It goes to the honest generic path with its own reason instead.\n if (resolution.componentKey === GENERIC_STRUCTURED_COMPONENT_KEY) {\n return routeToGeneric(block, \"generic-row\");\n }\n if (block.type === resolution.componentKey) return block;\n\n return {\n ...block,\n type: resolution.componentKey,\n // No compiled bridge exists — the routed component parses `content`\n // itself; the raw region's annotation serverData is CLEARED.\n serverData: undefined,\n metadata: withRouteMarker(block.metadata, resolution),\n };\n }\n\n // ── R6 generic fallback: a KNOWN shape that nothing render-trusted claims ─\n // `def` exists ⇒ a kind definition supplied this kind's schema: the platform\n // knows the shape. It has no compiled bridge, and either no `kind_component`\n // row at all (`no-component`) or one held inactive (`inactive`). R6 sends\n // exactly this case to the generic structured viewer with an \"unverified\n // shape\" affordance — the disposition that retires permanently-red\n // \"no-component root\" kinds without pretending they have renderers.\n if (def) {\n return routeToGeneric(block, resolution ? \"inactive\" : \"no-component\");\n }\n\n // A kind slug the platform has NO definition for (a typo, a foreign\n // emitter, a not-yet-created shape). 🚨 Arman's ruling, 2026-08-29: a root\n // `__kind` key means the kind system owns the render — NO exceptions. The\n // old strangler carve-out (\"not ours to claim\", teaching content stayed a\n // raw code block) is retired: an unregistered kind renders through the\n // generic floor with `reason: \"unregistered\"`, so the reader always sees\n // the payload acknowledged AS a kind instance with what is known about it.\n // A repaint hook upgrades this block the moment the registries learn the\n // kind.\n return routeToGeneric(block, \"unregistered\");\n}\n\n/**\n * Rehydration route for STRUCTURED persisted artifacts.\n *\n * A materialized kind artifact stores its zero-loss value object (carrying\n * `__kind`) alongside its row. Given that stored value, derive the registered\n * kind's legacy `serverData` WITHOUT re-parsing any text: the value wraps into\n * a complete envelope and runs through the same `toLegacyServerData` bridge the\n * live stream uses. Returns null for non-objects, unregistered kinds, or kinds\n * without a legacy bridge — callers fall back to their string-payload path.\n */\nexport function kindServerDataFromStoredValue(\n value: unknown,\n env: Pick<KindRouteEnv, \"kinds\">,\n): Record<string, unknown> | null {\n if (!isRecord(value)) return null;\n const kind = readObjectKind(value);\n if (!kind) return null;\n\n const def = env.kinds.getDefinition(kind);\n if (!def?.toLegacyServerData) return null;\n\n return def.toLegacyServerData(envelopeFromCompleteValue(value, kind)) ?? null;\n}\n","/**\n * Routing the PROVISIONAL half of the streaming partial-kinds contract.\n *\n * Cross-repo system-of-record (read it before changing anything here):\n * `common-docs/systems/content-ir-system/STREAMING_PARTIAL_KINDS.md` §8.\n * The reader/validator half lives in `@ai-matrx/content-ir` (`wire/partial-kind`);\n * the wire gate runs in each host's stream ingest.\n *\n * WHAT THIS DOES\n * --------------\n * While a structured region streams, the server announces what it thinks the\n * region IS and what has arrived so far (`metadata.__ir_partial`). This module\n * turns that provisional event into a routed block that renders through the\n * EXACT SAME component the final value renders in — which is the entire point:\n * a bespoke skeleton renderer would be a second render path and is banned.\n *\n * HOW, without touching the verified channel\n * ------------------------------------------\n * `root` is deliberately `IrStructuredNode`-shaped, so the event wraps into a\n * `CanonicalBlockIR` and every existing reader — the compiled bridge, the\n * component resolver, the db-component flip, the generic viewer — works\n * unchanged. That provisional envelope is placed on a RENDER-LOCAL COPY of the\n * block's metadata under `__ir`, never on the wire and never in host state. The\n * block also carries `__ir_provisional: true` so any downstream reader can tell\n * a provisional render from a verified one.\n *\n * THE POSTURE: WITHHOLD BY DEFAULT, OPT IN PER KIND\n * -------------------------------------------------\n * A provisional value MAY be missing required fields — that is what the\n * `partial_unvalidated` notice declares — and §8 of the contract requires that\n * a component which throws on an absent field is not routed one. Rather than\n * audit every component, the default is WITHHOLD: nothing changes and the block\n * keeps its loading skeleton. A kind opts in with `partialReady: true` on its\n * registry definition. If an opted-in component throws anyway,\n * `ProvisionalKindBoundary` screams and calls `markKindPartialUnsafe`, which\n * drops that kind back to withhold for the rest of the session — loud recovery,\n * never a broken surface.\n *\n * TERMINALS\n * ---------\n * `superseded` and `retracted` produce NO provisional render, so the swap to\n * the final value happens in the same frame the terminal arrives — never a\n * flicker through an empty state. Both are explicit EVENTS: the terminal is\n * never inferred from the arrival of `__ir`, because a completed block often\n * has no `__ir` at all (unregistered kind, schema drift, cold catalog) and\n * inferring it would leave the skeleton up forever in exactly those cases.\n */\n\nimport {\n IR_ENVELOPE_KEY,\n IR_PARTIAL_KEY,\n IR_VERSION,\n isProvisionalKind,\n readEnvelope,\n readPartialKindEvent,\n} from \"@ai-matrx/content-ir\";\nimport type { CanonicalBlockIR, PartialKindEvent } from \"@ai-matrx/content-ir\";\nimport type { IrRoutableBlock, KindRouteEnv } from \"../host/host-types\";\nimport { applyIrKindRoute, type KindRouteOptions } from \"./kind-route\";\n\n/**\n * Marker stamped on a render-local block whose `__ir` is PROVISIONAL. Never\n * emitted by a producer, never persisted, never on the wire.\n */\nexport const IR_PROVISIONAL_KEY = \"__ir_provisional\" as const;\n\n/** True when this block's metadata carries a provisional (not verified) envelope. */\nexport function isProvisionalBlock(\n metadata: Record<string, unknown> | null | undefined,\n): boolean {\n return metadata?.[IR_PROVISIONAL_KEY] === true;\n}\n\n/** Wrap a validated `partial` event into the envelope shape every IR reader consumes. */\nexport function envelopeFromPartialKind(\n event: PartialKindEvent,\n): CanonicalBlockIR {\n return {\n v: IR_VERSION,\n // The partial channel is only ever produced by the Python detector; the\n // envelope's `engine` union has no third member and inventing one would\n // break every existing reader.\n engine: \"py-block-detector\",\n fingerprint: event.fingerprint,\n root: event.root,\n };\n}\n\n/**\n * Kinds whose component threw while rendering a provisional value. Session-\n * scoped: the kind falls back to withhold (its loading skeleton) until a\n * reload, so one bad component cannot keep re-throwing on every block.\n */\n// SESSION LATCH ON A globalThis SLOT — never a module-level variable. This\n// latch is WRITTEN from the `./react` bundle (ProvisionalKindBoundary calls\n// markKindPartialUnsafe) and READ from the `./route` bundle\n// (isPartialReadyKind); with `splitting: false` dual ESM/CJS output those are\n// different module instantiations, and a module-level Set would silently split\n// the writer from the reader (the kit confirm-opener precedent). Never \"clean\n// this up\" into a module local.\nconst PARTIAL_UNSAFE_SLOT = Symbol.for(\n \"ai-matrx.content-ir-react.partial-unsafe-kinds\",\n);\ntype PartialUnsafeSlotHolder = typeof globalThis & {\n [PARTIAL_UNSAFE_SLOT]?: Set<string>;\n};\nconst partialUnsafeKinds: Set<string> = ((globalThis as PartialUnsafeSlotHolder)[\n PARTIAL_UNSAFE_SLOT\n] ??= new Set<string>());\n\n/** Loud recovery hook — called by ProvisionalKindBoundary when a render throws. */\nexport function markKindPartialUnsafe(kind: string): void {\n partialUnsafeKinds.add(kind);\n}\n\n/** Test-only reset of the session latch. */\nexport function resetPartialUnsafeKinds(): void {\n partialUnsafeKinds.clear();\n}\n\n/**\n * Has this kind opted in to being handed a provisional value? Withhold is the\n * default; see the module doc.\n */\nexport function isPartialReadyKind(\n kind: string,\n env: Pick<KindRouteEnv, \"kinds\">,\n): boolean {\n if (!kind || partialUnsafeKinds.has(kind)) return false;\n return env.kinds.getDefinition(kind)?.partialReady === true;\n}\n\nexport interface PartialRenderOptions extends KindRouteOptions {\n /**\n * Is the STREAM still running? Message-wide, deliberately — not this block's\n * own completion.\n *\n * 🚨 THE ANTI-STUCK-SKELETON BACKSTOP. Law 1 of the contract says every\n * partial ends in exactly one terminal, and that law is the ONLY thing\n * standing between a user and a \"Still arriving\" skeleton that never\n * resolves. It is a producer guarantee with at least three ways to not fire:\n * the drain skips a block missing from the final block list, the emitter\n * early-returns once the stream ended or was cancelled (so a client abort\n * drops every retraction), and a flush failure is swallowed so it never kills\n * a run.\n *\n * Once the stream is over, no terminal can ever arrive, so a still-open\n * provisional is stuck by definition — drop it and let the block's own\n * content and `__ir` be the truth. Correct to be message-wide: a terminal for\n * THIS block may still be in flight while the block itself looks finished.\n *\n * `undefined` reads as active, so a caller that does not thread stream state\n * keeps live rendering rather than silently losing it.\n */\n streamActive?: boolean;\n}\n\n/**\n * The ANNOUNCED-but-not-yet-renderable state: the server has said what this\n * region is, and the region cannot render its real component yet.\n *\n * WHY THIS EXISTS SEPARATELY FROM THE VERIFIED CHANNEL. On a chat stream the\n * host's own accumulator fills `__ir` in as it parses. A WORKFLOW run's lane\n * does not: when the server opens the block scope it marks the text channel\n * `block_shadowed` and the lane stops feeding its accumulator, precisely so one\n * region is never rendered twice under two sets of block ids\n * (STREAMING_PARTIAL_KINDS.md §7b rule 4). So on a run page there is NO\n * streaming `__ir` — the ONLY thing that knows what the region is, is the\n * partial channel. Without this, a workflow node's structured answer fell\n * through to the raw-text renderer: a generic loader, then raw JSON\n * accumulating, then a swap at the end.\n *\n * Returns the provisional envelope to feed the kind's loading component, or\n * null when there is nothing announced (no event, a terminal, a dead stream).\n * Deliberately independent of `partialReady`: withholding a VALUE from a\n * component that might throw on it is a real decision, but withholding the\n * kind's own loading state is not — a skeleton cannot throw, and the reader\n * seeing what is coming is the whole point.\n */\nexport function resolveAnnouncedKindLoading(\n block: { metadata?: Record<string, unknown> },\n options?: Pick<PartialRenderOptions, \"streamActive\">,\n): { kind: string; envelope: CanonicalBlockIR } | null {\n // Same anti-stuck-skeleton backstop as resolveProvisionalKindRender: once the\n // stream is over no terminal can arrive, so a still-open announcement is\n // stuck by definition and must not hold a loader on screen forever.\n if (options?.streamActive === false) return null;\n\n const event = readPartialKindEvent(block.metadata);\n if (!isProvisionalKind(event)) return null;\n const kind = event.root.kind;\n if (!kind) return null;\n\n // A region that already VERIFIED is the truth; never cover it with a loader.\n const verified = readEnvelope(block.metadata);\n if (verified && verified.root.status === \"complete\") return null;\n\n return { kind, envelope: envelopeFromPartialKind(event) };\n}\n\nexport interface ProvisionalKindRender<T> {\n /** The routed block — same type/serverData shape the final value produces. */\n block: T;\n /** The announced (speculative) kind. */\n kind: string;\n /** Per-block ordering key, for diagnostics. */\n seq: number;\n /** The provisional envelope — feeds the loading skeleton used as the throw fallback. */\n envelope: CanonicalBlockIR;\n}\n\n/**\n * Resolve a block's provisional render, or null when there is nothing to show\n * provisionally (no event, a terminal event, a withheld kind, a kind nothing\n * can route, or a verified envelope that already won).\n *\n * Pure: no React, no host state, no side effects beyond the registry reads.\n */\nexport function resolveProvisionalKindRender<\n T extends IrRoutableBlock & { metadata?: Record<string, unknown> },\n>(\n block: T,\n env: KindRouteEnv,\n options?: PartialRenderOptions,\n): ProvisionalKindRender<T> | null {\n if (options?.streamActive === false) return null;\n\n const event = readPartialKindEvent(block.metadata);\n // Terminal (superseded / retracted) → no provisional render, in this frame.\n if (!isProvisionalKind(event)) return null;\n\n const kind = event.root.kind;\n if (!isPartialReadyKind(kind, env)) return null;\n\n // A verified envelope that has already completed is the truth — a late or\n // duplicated partial must never displace it.\n const verified = readEnvelope(block.metadata);\n if (verified && verified.root.status === \"complete\") return null;\n\n const { [IR_PARTIAL_KEY]: _partial, ...rest } = block.metadata ?? {};\n void _partial;\n\n const envelope = envelopeFromPartialKind(event);\n\n const provisionalBlock = {\n ...block,\n // The raw region annotation (`{ language: \"json\" }`) is not kind data —\n // same poison rule the verified route follows.\n serverData: undefined,\n metadata: {\n ...rest,\n [IR_ENVELOPE_KEY]: envelope,\n [IR_PROVISIONAL_KEY]: true,\n },\n } as T;\n\n const routed = applyIrKindRoute(provisionalBlock, env, options);\n // Nothing claimed it (unknown kind, no component) — `applyIrKindRoute`\n // returns the SAME reference. Withhold rather than render raw partial JSON.\n if (routed === provisionalBlock) return null;\n // A bridged kind whose bridge DECLINED this value (too thin to render — a\n // quiz with no answerable question yet) routed on type alone, which would\n // hand the component the partial JSON text to parse. Withhold: the loading\n // skeleton stays up for this frame and the next `seq` tries again.\n if (\n env.kinds.getDefinition(kind)?.toLegacyServerData &&\n !(routed as { serverData?: unknown }).serverData\n ) {\n return null;\n }\n\n return { block: routed, kind, seq: event.seq, envelope };\n}\n","/**\n * THE BOUND ROUTE — the pure route functions with a host's env and owned\n * types partially applied, built ONCE in a host wiring module.\n *\n * Every host was writing the same wrapper file by hand: one function per pure\n * route, each forwarding `matrx…Env` + `ownedTypes` (matrx-frontend carried\n * two such modules; the dashboard a third). Per C22 that repeated delta is\n * package-provided: a host module now only INJECTS (its env, its owned block\n * types) and re-exports what this factory returns.\n *\n * The functions are the exact pure routes — read `kind-route.ts` /\n * `partial-kind-route.ts` for semantics; nothing behavioral lives here.\n */\n\nimport type { IrRoutableBlock, KindRouteEnv } from \"../host/host-types\";\nimport {\n applyIrKindRoute,\n kindServerDataFromStoredValue,\n type KindRouteOptions,\n} from \"./kind-route\";\nimport {\n isPartialReadyKind,\n resolveProvisionalKindRender,\n type PartialRenderOptions,\n type ProvisionalKindRender,\n} from \"./partial-kind-route\";\n\nexport interface KindRouteBinding {\n /** Route one block through the bound registries. */\n applyIrKindRoute<T extends IrRoutableBlock>(block: T): T;\n /**\n * Rehydration route for STRUCTURED persisted artifacts: given a stored\n * zero-loss value object, derive the registered kind's legacy `serverData`\n * with no re-parse. Null for non-objects, unregistered kinds, or kinds\n * without a legacy bridge.\n */\n kindServerDataFromStoredValue(value: unknown): Record<string, unknown> | null;\n /** Has this kind opted in to being handed a provisional value? */\n isPartialReadyKind(kind: string): boolean;\n /**\n * Resolve a block's provisional render, or null when there is nothing to\n * show provisionally (no event, a terminal event, a withheld kind, a kind\n * nothing can route, or a verified envelope that already won).\n */\n resolveProvisionalKindRender<\n T extends IrRoutableBlock & { metadata?: Record<string, unknown> },\n >(\n block: T,\n options?: Pick<PartialRenderOptions, \"streamActive\">,\n ): ProvisionalKindRender<T> | null;\n}\n\n/** Bind the pure routes to one host's env + owned block types. */\nexport function createKindRouteBinding(\n env: KindRouteEnv,\n options?: KindRouteOptions,\n): KindRouteBinding {\n const ownedTypes = options?.ownedTypes;\n return {\n applyIrKindRoute: (block) =>\n applyIrKindRoute(block, env, ownedTypes ? { ownedTypes } : undefined),\n kindServerDataFromStoredValue: (value) =>\n kindServerDataFromStoredValue(value, env),\n isPartialReadyKind: (kind) => isPartialReadyKind(kind, env),\n resolveProvisionalKindRender: (block, streamOptions) =>\n resolveProvisionalKindRender(block, env, {\n ...streamOptions,\n ...(ownedTypes ? { ownedTypes } : null),\n }),\n };\n}\n"],"mappings":"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","names":["import_content_ir"]}
package/dist/route.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- export { D as DB_KIND_COMPONENT_KEY, G as GENERIC_STRUCTURED_COMPONENT_KEY, c as GenericFallbackReason, I as IR_PROVISIONAL_KEY, d as IR_ROUTE_KEY, g as IrRouteMarker, h as KindRouteBinding, i as KindRouteOptions, P as PartialRenderOptions, j as ProvisionalKindRender, k as applyIrKindRoute, l as createKindRouteBinding, m as envelopeFromPartialKind, n as isPartialReadyKind, o as isProvisionalBlock, p as kindServerDataFromStoredValue, q as markKindPartialUnsafe, r as readIrRouteMarker, s as resetPartialUnsafeKinds, t as resetSourcelessDbRowReports, u as resolveAnnouncedKindLoading, v as resolveProvisionalKindRender } from './route-C55jsF4B.cjs';
2
- import './component-resolution.types-fvR92hW7.cjs';
1
+ export { D as DB_KIND_COMPONENT_KEY, G as GENERIC_STRUCTURED_COMPONENT_KEY, c as GenericFallbackReason, I as IR_PROVISIONAL_KEY, d as IR_ROUTE_KEY, g as IrRouteMarker, h as KindRouteBinding, i as KindRouteOptions, P as PartialRenderOptions, j as ProvisionalKindRender, k as applyIrKindRoute, l as createKindRouteBinding, m as envelopeFromPartialKind, n as isPartialReadyKind, o as isProvisionalBlock, p as kindServerDataFromStoredValue, q as markKindPartialUnsafe, r as readIrRouteMarker, s as resetPartialUnsafeKinds, t as resetSourcelessDbRowReports, u as resolveAnnouncedKindLoading, v as resolveProvisionalKindRender } from './route-QL2Vqf2e.cjs';
2
+ import './component-resolution.types-DLO2w-0n.cjs';
3
3
  import 'react';
4
4
  import '@ai-matrx/content-ir';
package/dist/route.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { D as DB_KIND_COMPONENT_KEY, G as GENERIC_STRUCTURED_COMPONENT_KEY, c as GenericFallbackReason, I as IR_PROVISIONAL_KEY, d as IR_ROUTE_KEY, g as IrRouteMarker, h as KindRouteBinding, i as KindRouteOptions, P as PartialRenderOptions, j as ProvisionalKindRender, k as applyIrKindRoute, l as createKindRouteBinding, m as envelopeFromPartialKind, n as isPartialReadyKind, o as isProvisionalBlock, p as kindServerDataFromStoredValue, q as markKindPartialUnsafe, r as readIrRouteMarker, s as resetPartialUnsafeKinds, t as resetSourcelessDbRowReports, u as resolveAnnouncedKindLoading, v as resolveProvisionalKindRender } from './route-C1XNcubB.js';
2
- import './component-resolution.types-fvR92hW7.js';
1
+ export { D as DB_KIND_COMPONENT_KEY, G as GENERIC_STRUCTURED_COMPONENT_KEY, c as GenericFallbackReason, I as IR_PROVISIONAL_KEY, d as IR_ROUTE_KEY, g as IrRouteMarker, h as KindRouteBinding, i as KindRouteOptions, P as PartialRenderOptions, j as ProvisionalKindRender, k as applyIrKindRoute, l as createKindRouteBinding, m as envelopeFromPartialKind, n as isPartialReadyKind, o as isProvisionalBlock, p as kindServerDataFromStoredValue, q as markKindPartialUnsafe, r as readIrRouteMarker, s as resetPartialUnsafeKinds, t as resetSourcelessDbRowReports, u as resolveAnnouncedKindLoading, v as resolveProvisionalKindRender } from './route-PUuEuEug.js';
2
+ import './component-resolution.types-DLO2w-0n.js';
3
3
  import 'react';
4
4
  import '@ai-matrx/content-ir';
package/dist/route.js CHANGED
@@ -86,6 +86,8 @@ function applyIrKindRoute(block, env, options) {
86
86
  if (envelope.root.kindState === "pending_schema") return block;
87
87
  const def = env.kinds.getDefinition(kind);
88
88
  const resolution = env.components.resolve(kind, env.platform, "output");
89
+ const componentsSettled = env.components.hasSettled?.() ?? true;
90
+ if (!componentsSettled && !resolution && !def) return block;
89
91
  if (envelope.root.kindState === "raw") {
90
92
  return routeToGeneric(
91
93
  block,