@beyondwork/docx-react-component 1.0.106 → 1.0.108

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 (190) hide show
  1. package/package.json +19 -5
  2. package/src/api/geometry-overlay-rects.ts +5 -0
  3. package/src/api/package-version.ts +1 -1
  4. package/src/api/page-anchor-id.ts +5 -0
  5. package/src/api/public-types.ts +16 -9
  6. package/src/api/table-node-specs.ts +6 -0
  7. package/src/api/v3/_create.ts +2 -1
  8. package/src/api/v3/_page-anchor-id.ts +52 -0
  9. package/src/api/v3/_runtime-handle.ts +92 -1
  10. package/src/api/v3/ai/_audit-time.ts +5 -0
  11. package/src/api/v3/ai/_pe2-evidence.ts +38 -0
  12. package/src/api/v3/ai/attach.ts +7 -2
  13. package/src/api/v3/ai/replacement.ts +101 -18
  14. package/src/api/v3/ai/resolve.ts +2 -2
  15. package/src/api/v3/ai/review.ts +177 -3
  16. package/src/api/v3/index.ts +1 -0
  17. package/src/api/v3/runtime/collab.ts +462 -0
  18. package/src/api/v3/runtime/document.ts +503 -20
  19. package/src/api/v3/runtime/geometry.ts +97 -0
  20. package/src/api/v3/runtime/layout.ts +744 -0
  21. package/src/api/v3/runtime/perf-probe.ts +14 -0
  22. package/src/api/v3/runtime/viewport.ts +9 -8
  23. package/src/api/v3/ui/_types.ts +149 -55
  24. package/src/api/v3/ui/chrome-preset-model.ts +5 -5
  25. package/src/api/v3/ui/debug.ts +115 -2
  26. package/src/api/v3/ui/index.ts +13 -0
  27. package/src/api/v3/ui/overlays.ts +0 -8
  28. package/src/api/v3/ui/surface.ts +56 -0
  29. package/src/api/v3/ui/viewport.ts +22 -9
  30. package/src/core/commands/image-commands.ts +1 -0
  31. package/src/core/commands/index.ts +6 -0
  32. package/src/core/schema/text-schema.ts +43 -5
  33. package/src/core/selection/mapping.ts +8 -1
  34. package/src/core/selection/review-anchors.ts +5 -1
  35. package/src/core/state/text-transaction.ts +8 -2
  36. package/src/io/export/serialize-revisions.ts +149 -1
  37. package/src/io/normalize/normalize-text.ts +6 -0
  38. package/src/io/ooxml/parse-bookmark-references.ts +55 -0
  39. package/src/io/ooxml/parse-fields.ts +24 -2
  40. package/src/io/ooxml/parse-headers-footers.ts +38 -5
  41. package/src/io/ooxml/parse-main-document.ts +153 -9
  42. package/src/io/ooxml/parse-numbering.ts +20 -0
  43. package/src/io/ooxml/parse-revisions.ts +19 -8
  44. package/src/io/opc/package-reader.ts +98 -8
  45. package/src/model/anchor.ts +4 -3
  46. package/src/model/canonical-document.ts +220 -2
  47. package/src/model/canonical-hash.ts +221 -0
  48. package/src/model/canonical-layout-inputs.ts +245 -6
  49. package/src/model/layout/index.ts +1 -0
  50. package/src/model/layout/page-graph-types.ts +118 -1
  51. package/src/model/review/revision-types.ts +14 -3
  52. package/src/preservation/store.ts +20 -4
  53. package/src/review/README.md +1 -1
  54. package/src/review/store/revision-actions.ts +14 -2
  55. package/src/runtime/collab/event-types.ts +67 -1
  56. package/src/runtime/collab/runtime-collab-sync.ts +177 -5
  57. package/src/runtime/diagnostics/layout-guard-warning.ts +18 -0
  58. package/src/runtime/document-heading-outline.ts +147 -0
  59. package/src/runtime/document-navigation.ts +8 -243
  60. package/src/runtime/document-runtime.ts +240 -97
  61. package/src/runtime/edit-dispatch/dispatch-text-command.ts +11 -0
  62. package/src/runtime/formatting/layout-inputs.ts +38 -5
  63. package/src/runtime/formatting/numbering/geometry.ts +28 -2
  64. package/src/runtime/geometry/adjacent-geometry-intake.ts +835 -0
  65. package/src/runtime/geometry/caret-geometry.ts +5 -6
  66. package/src/runtime/geometry/geometry-facet.ts +60 -10
  67. package/src/runtime/geometry/geometry-index.ts +591 -20
  68. package/src/runtime/geometry/geometry-types.ts +59 -0
  69. package/src/runtime/geometry/hit-test.ts +11 -1
  70. package/src/runtime/geometry/overlay-rects.ts +5 -3
  71. package/src/runtime/geometry/project-anchors.ts +1 -1
  72. package/src/runtime/geometry/word-layout-v2-line-intake.ts +323 -0
  73. package/src/runtime/layout/index.ts +6 -0
  74. package/src/runtime/layout/layout-engine-instance.ts +6 -1
  75. package/src/runtime/layout/layout-engine-version.ts +181 -16
  76. package/src/runtime/layout/layout-facet-types.ts +6 -0
  77. package/src/runtime/layout/page-graph.ts +21 -4
  78. package/src/runtime/layout/paginated-layout-engine.ts +139 -15
  79. package/src/runtime/layout/project-block-fragments.ts +265 -7
  80. package/src/runtime/layout/public-facet.ts +78 -24
  81. package/src/runtime/layout/table-row-continuation-contract.ts +107 -0
  82. package/src/runtime/layout/table-row-split.ts +92 -35
  83. package/src/runtime/prerender/cache-envelope.ts +2 -2
  84. package/src/runtime/prerender/cache-key.ts +5 -4
  85. package/src/runtime/prerender/customxml-cache.ts +0 -1
  86. package/src/runtime/render/render-kernel.ts +1 -1
  87. package/src/runtime/revision-runtime.ts +112 -10
  88. package/src/runtime/scopes/_scope-dependencies.ts +1 -0
  89. package/src/runtime/scopes/action-validation.ts +22 -2
  90. package/src/runtime/scopes/capabilities.ts +316 -0
  91. package/src/runtime/scopes/compile-scope-bundle.ts +14 -0
  92. package/src/runtime/scopes/compiler-service.ts +108 -4
  93. package/src/runtime/scopes/content-control-evidence.ts +79 -0
  94. package/src/runtime/scopes/create-issue.ts +5 -5
  95. package/src/runtime/scopes/evidence.ts +91 -0
  96. package/src/runtime/scopes/formatting/apply.ts +2 -0
  97. package/src/runtime/scopes/geometry-evidence.ts +130 -0
  98. package/src/runtime/scopes/index.ts +54 -0
  99. package/src/runtime/scopes/issue-lifecycle.ts +224 -0
  100. package/src/runtime/scopes/layout-evidence.ts +374 -0
  101. package/src/runtime/scopes/multi-paragraph-refusal.ts +37 -0
  102. package/src/runtime/scopes/preservation-boundary.ts +7 -1
  103. package/src/runtime/scopes/replacement/apply.ts +97 -34
  104. package/src/runtime/scopes/scope-kinds/paragraph.ts +108 -12
  105. package/src/runtime/scopes/semantic-scope-types.ts +242 -3
  106. package/src/runtime/scopes/visualization.ts +28 -0
  107. package/src/runtime/surface-projection.ts +44 -5
  108. package/src/runtime/telemetry/perf-probe.ts +216 -0
  109. package/src/runtime/virtualized-rendering.ts +36 -1
  110. package/src/runtime/workflow/ai-issue-lifecycle.ts +253 -0
  111. package/src/runtime/workflow/coordinator.ts +39 -11
  112. package/src/runtime/workflow/derived-scope-resolver.ts +63 -9
  113. package/src/runtime/workflow/index.ts +3 -0
  114. package/src/runtime/workflow/overlay-lane-types.ts +58 -0
  115. package/src/runtime/workflow/overlay-lanes.ts +168 -10
  116. package/src/runtime/workflow/overlay-store.ts +2 -2
  117. package/src/runtime/workflow/redline-posture-calibration.ts +257 -0
  118. package/src/runtime/workflow/word-field-matrix-calibration.ts +231 -0
  119. package/src/session/_sync-legacy.ts +17 -27
  120. package/src/session/import/loader.ts +6 -4
  121. package/src/session/import/source-package-evidence.ts +186 -2
  122. package/src/session/index.ts +5 -6
  123. package/src/session/session.ts +30 -56
  124. package/src/session/types.ts +8 -13
  125. package/src/shell/session-bootstrap.ts +155 -81
  126. package/src/ui/WordReviewEditor.tsx +520 -12
  127. package/src/ui/editor-shell-view.tsx +14 -4
  128. package/src/ui/editor-surface-controller.tsx +5 -3
  129. package/src/ui/headless/selection-tool-resolver.ts +1 -2
  130. package/src/ui/presence-overlay-lane.ts +0 -1
  131. package/src/ui/ui-controller-factory.ts +7 -0
  132. package/src/ui-tailwind/chrome/build-context-menu-entries.ts +5 -1
  133. package/src/ui-tailwind/chrome/editor-action-registry.ts +105 -5
  134. package/src/ui-tailwind/chrome/editor-actions-to-palette.ts +7 -0
  135. package/src/ui-tailwind/chrome/layer-debug-contracts.ts +208 -0
  136. package/src/ui-tailwind/chrome/resolve-target-kind.ts +13 -0
  137. package/src/ui-tailwind/chrome/tw-alert-banner.tsx +11 -3
  138. package/src/ui-tailwind/chrome/tw-command-palette.tsx +36 -6
  139. package/src/ui-tailwind/chrome/tw-context-menu.tsx +6 -1
  140. package/src/ui-tailwind/chrome/tw-display-mode-selector.tsx +42 -109
  141. package/src/ui-tailwind/chrome/tw-inline-find-bar.tsx +26 -6
  142. package/src/ui-tailwind/chrome/tw-navigation-command-bar.tsx +328 -0
  143. package/src/ui-tailwind/chrome/tw-object-context-toolbar.tsx +8 -4
  144. package/src/ui-tailwind/chrome/tw-runtime-repl-dialog.tsx +129 -1
  145. package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +19 -5
  146. package/src/ui-tailwind/chrome/tw-selection-tool-structure.tsx +5 -1
  147. package/src/ui-tailwind/chrome/tw-workspace-chrome-host.tsx +28 -12
  148. package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +30 -3
  149. package/src/ui-tailwind/chrome-overlay/tw-object-selection-overlay.tsx +116 -10
  150. package/src/ui-tailwind/chrome-overlay/tw-page-stack-overlay-layer.tsx +223 -94
  151. package/src/ui-tailwind/chrome-overlay/tw-presence-overlay-lane.tsx +157 -0
  152. package/src/ui-tailwind/chrome-overlay/tw-review-overlay-lane-markers.tsx +259 -0
  153. package/src/ui-tailwind/chrome-overlay/tw-scope-card-layer.tsx +5 -2
  154. package/src/ui-tailwind/chrome-overlay/tw-substrate-overlay-lanes.tsx +314 -0
  155. package/src/ui-tailwind/debug/README.md +4 -1
  156. package/src/ui-tailwind/debug/layer11-consumer-readiness.ts +272 -0
  157. package/src/ui-tailwind/debug/layer11-word-field-matrix-evidence.ts +160 -0
  158. package/src/ui-tailwind/editor-surface/perf-probe.ts +14 -215
  159. package/src/ui-tailwind/editor-surface/pm-decorations.ts +42 -0
  160. package/src/ui-tailwind/editor-surface/pm-position-map.ts +38 -2
  161. package/src/ui-tailwind/editor-surface/pm-schema.ts +14 -4
  162. package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +34 -5
  163. package/src/ui-tailwind/editor-surface/runtime-decoration-plugin.ts +9 -19
  164. package/src/ui-tailwind/editor-surface/surface-build-keys.ts +2 -2
  165. package/src/ui-tailwind/editor-surface/tw-page-block-view.helpers.ts +145 -0
  166. package/src/ui-tailwind/editor-surface/tw-page-block-view.tsx +16 -11
  167. package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +8 -10
  168. package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +3 -0
  169. package/src/ui-tailwind/page-stack/tw-page-chrome-entry.tsx +4 -2
  170. package/src/ui-tailwind/page-stack/tw-page-stack-chrome-layer.tsx +60 -20
  171. package/src/ui-tailwind/page-stack/tw-region-block-renderer.tsx +16 -11
  172. package/src/ui-tailwind/review/tw-health-panel.tsx +36 -17
  173. package/src/ui-tailwind/review/tw-review-rail.tsx +7 -4
  174. package/src/ui-tailwind/review-workspace/diagnostics-visibility.ts +44 -0
  175. package/src/ui-tailwind/review-workspace/page-shell-metrics.ts +11 -0
  176. package/src/ui-tailwind/review-workspace/tw-review-workspace-rail.tsx +16 -1
  177. package/src/ui-tailwind/review-workspace/types.ts +26 -12
  178. package/src/ui-tailwind/review-workspace/use-diagnostics-signal.ts +40 -11
  179. package/src/ui-tailwind/review-workspace/use-layout-facet-render-signal.ts +2 -1
  180. package/src/ui-tailwind/review-workspace/use-page-markers.ts +15 -26
  181. package/src/ui-tailwind/review-workspace/use-scope-card-state.ts +35 -18
  182. package/src/ui-tailwind/review-workspace/use-selection-toolbar-placement.ts +41 -32
  183. package/src/ui-tailwind/review-workspace/use-status-bar-page-facts.ts +2 -1
  184. package/src/ui-tailwind/review-workspace/use-workspace-side-effects.ts +2 -1
  185. package/src/ui-tailwind/status/tw-status-bar.tsx +6 -5
  186. package/src/ui-tailwind/toolbar/tw-role-action-region.tsx +52 -80
  187. package/src/ui-tailwind/toolbar/tw-shell-header.tsx +12 -48
  188. package/src/ui-tailwind/toolbar/tw-toolbar-icon-button.tsx +9 -4
  189. package/src/ui-tailwind/toolbar/tw-toolbar.tsx +328 -361
  190. package/src/ui-tailwind/tw-review-workspace.tsx +152 -286
@@ -22,6 +22,29 @@ import {
22
22
  getRemoteCursorStates as getRemoteCursorStatesImpl,
23
23
  type RemoteCursorState,
24
24
  } from "../../../runtime/collab/remote-cursor-awareness.ts";
25
+ import {
26
+ COMMAND_EVENT_SCHEMA_VERSION,
27
+ BROADCAST_COMMAND_TYPES,
28
+ LOCAL_ONLY_COMMAND_TYPES,
29
+ } from "../../../runtime/collab/event-types.ts";
30
+ import type {
31
+ RuntimeTelemetryEvent,
32
+ TelemetryChannel,
33
+ } from "../../../runtime/debug/types.ts";
34
+
35
+ const COMMAND_ORIGIN_KINDS = [
36
+ "local-typing",
37
+ "local-command",
38
+ "runtime",
39
+ "agent",
40
+ "import",
41
+ "field-refresh",
42
+ "unknown",
43
+ ] as const;
44
+
45
+ type CommandOriginKind = (typeof COMMAND_ORIGIN_KINDS)[number];
46
+
47
+ const COMMAND_ORIGIN_KIND_SET: ReadonlySet<string> = new Set(COMMAND_ORIGIN_KINDS);
25
48
 
26
49
  // Re-export so L11 consumers (remote-cursor-plugin) don't peek into
27
50
  // `src/runtime/collab/**` for the state type.
@@ -222,6 +245,292 @@ export const getRemoteCursorStatesMetadata: ApiV3FnMetadata = {
222
245
  "§Runtime API § runtime.collab.getRemoteCursorStates. Direct delegation to getRemoteCursorStates (src/runtime/collab/remote-cursor-awareness.ts). Extracts remote peers' cursor states from a Yjs Awareness instance, filtered by localClientId and sanitized (color allowlisted to safe-hex or hashed fallback). Backs coord-07 §2.1 collab expansion remainder — PM remote-cursor plugin flips from src/runtime/collab/** to this seam.",
223
246
  };
224
247
 
248
+ /* ================================================================== */
249
+ /* getEventDiscipline — PE2 Slice 2 origin/channel read */
250
+ /* ================================================================== */
251
+
252
+ export interface CollabEventDiscipline {
253
+ readonly commandEventSchemaVersion: typeof COMMAND_EVENT_SCHEMA_VERSION;
254
+ readonly commandEventChannel: "runtime-command-event";
255
+ readonly awarenessChannel: "awareness";
256
+ readonly commandOriginKinds: typeof COMMAND_ORIGIN_KINDS;
257
+ readonly commandOriginSources: readonly [
258
+ "keyboard",
259
+ "toolbar",
260
+ "context_menu",
261
+ "comment_panel",
262
+ "review_panel",
263
+ "api",
264
+ "runtime",
265
+ "agent",
266
+ "import",
267
+ "field_refresh",
268
+ "unspecified",
269
+ ];
270
+ readonly originCoverage: readonly CollabOriginCoverage[];
271
+ readonly broadcastCommandTypes: readonly string[];
272
+ readonly localOnlyCommandTypes: readonly string[];
273
+ readonly remoteReplay: {
274
+ readonly appliesThroughRuntime: true;
275
+ readonly validatesBaseDocFingerprint: true;
276
+ readonly rejectsSchemaMismatch: true;
277
+ readonly coalescesByDefault: true;
278
+ };
279
+ readonly awarenessInputs: readonly [
280
+ "presence",
281
+ "remote-cursor",
282
+ "remote-selection",
283
+ "hover",
284
+ "typing-indicator",
285
+ "viewing-scope",
286
+ ];
287
+ }
288
+
289
+ export interface CollabOriginCoverage {
290
+ readonly class:
291
+ | "local-typing"
292
+ | "local-command"
293
+ | "remote-runtime-command-event"
294
+ | "remote-awareness"
295
+ | "agent"
296
+ | "import"
297
+ | "field-refresh";
298
+ readonly channel: "runtime-command-event" | "awareness";
299
+ readonly canonicalMutation: boolean;
300
+ readonly commandOriginKinds?: readonly CollabEventDiscipline["commandOriginKinds"][number][];
301
+ readonly commandOriginSources?: readonly CollabEventDiscipline["commandOriginSources"][number][];
302
+ readonly awarenessInputs?: readonly CollabEventDiscipline["awarenessInputs"][number][];
303
+ }
304
+
305
+ export interface CollabRemoteReplayState {
306
+ readonly attached: boolean;
307
+ readonly readOnly: boolean;
308
+ readonly baseDocFingerprint: string | null;
309
+ readonly appliedEventCount: number;
310
+ readonly remoteActivitySignal: {
311
+ readonly aborted: boolean;
312
+ };
313
+ readonly guardrails: {
314
+ readonly appliesThroughRuntime: true;
315
+ readonly validatesBaseDocFingerprint: true;
316
+ readonly rejectsSchemaMismatch: true;
317
+ readonly suppressesOutboundWhenReadOnly: true;
318
+ readonly suppressesInboundWhenReadOnly: true;
319
+ readonly coalescesByDefault: true;
320
+ };
321
+ readonly __mock?: true;
322
+ }
323
+
324
+ export interface CollabEventTelemetryChannelSummary {
325
+ readonly channel: Extract<TelemetryChannel, "api" | "command" | "collab">;
326
+ readonly enabled: boolean;
327
+ readonly bufferedEventCount: number;
328
+ readonly persistedInSessionRing: true;
329
+ readonly subscriptionCapable: true;
330
+ }
331
+
332
+ export interface CollabEventTelemetry {
333
+ readonly channels: readonly CollabEventTelemetryChannelSummary[];
334
+ readonly counters: {
335
+ readonly commandEventCount: number;
336
+ readonly collabEventCount: number;
337
+ readonly uxResponseEventCount: number;
338
+ readonly remoteReplayEventCount: number;
339
+ readonly schemaMismatchEventCount: number;
340
+ readonly totalAuditableEventCount: number;
341
+ };
342
+ readonly originKindCounts: Readonly<Partial<Record<CommandOriginKind, number>>>;
343
+ readonly lastEventTypes: readonly string[];
344
+ readonly retention: {
345
+ readonly kind: "session-ring-buffer";
346
+ readonly tailReadLimit: 256;
347
+ readonly cost: "caller-paid-snapshot";
348
+ };
349
+ }
350
+
351
+ export const getEventDisciplineMetadata: ApiV3FnMetadata = {
352
+ name: "runtime.collab.getEventDiscipline",
353
+ status: "live",
354
+ sourceLayer: "workflow-review",
355
+ liveEvidence: {
356
+ runnerTest: "test/api/v3/behavioral-coverage.test.ts",
357
+ commit: "refactor-07-pe2-origin-discipline",
358
+ },
359
+ uxIntent: { uiVisible: false, expectsUxResponse: "none" },
360
+ agentMetadata: {
361
+ readOrMutate: "read",
362
+ boundedScope: "session",
363
+ auditCategory: "collab-origin-discipline",
364
+ },
365
+ stateClass: "B-session",
366
+ persistsTo: "none",
367
+ broadcastsVia: "awareness",
368
+ rwdReference:
369
+ "§Runtime API § runtime.collab.getEventDiscipline. PE2 Slice-2 origin/channel read: exposes the distinction between runtime command-event replay and Awareness/session inputs. Command events carry normalized origin.kind/source on the shared command log; Awareness inputs remain session-only and must not mutate canonical document state.",
370
+ };
371
+
372
+ export const getRemoteReplayStateMetadata: ApiV3FnMetadata = {
373
+ name: "runtime.collab.getRemoteReplayState",
374
+ status: "live-with-adapter",
375
+ sourceLayer: "workflow-review",
376
+ liveEvidence: {
377
+ runnerTest: "test/api/v3/behavioral-coverage.test.ts",
378
+ commit: "refactor-07-pe2-remote-replay-state",
379
+ },
380
+ mockShape: {
381
+ deterministic: true,
382
+ seededFrom: "fixed",
383
+ shapeDescription:
384
+ "Detached remote replay snapshot — attached:false, readOnly:false, baseDocFingerprint:null, appliedEventCount:0, remoteActivitySignal.aborted:false. Emitted only when the handle carries no `collabSync`; hosts that pass RuntimeCollabSyncHandle get live replay guard state.",
385
+ carriesMockFlag: true,
386
+ },
387
+ uxIntent: { uiVisible: false, expectsUxResponse: "none" },
388
+ agentMetadata: {
389
+ readOrMutate: "read",
390
+ boundedScope: "session",
391
+ auditCategory: "collab-remote-replay-state",
392
+ },
393
+ stateClass: "B-session",
394
+ persistsTo: "none",
395
+ broadcastsVia: "awareness",
396
+ rwdReference:
397
+ "§Runtime API § runtime.collab.getRemoteReplayState. PE2 Slice-2 replay discipline read: projects the host-wired RuntimeCollabSyncHandle into plain values — base-doc fingerprint, read-only quarantine, applied-event dedup count, and remote-activity signal state — without exposing Yjs or runtime sync internals. The metadata keeps broadcastsVia:'awareness' because this is B-session posture shared as session awareness state; command-event replay remains the mutation transport and is described by getEventDiscipline.remoteReplay.",
398
+ };
399
+
400
+ export const getEventTelemetryMetadata: ApiV3FnMetadata = {
401
+ name: "runtime.collab.getEventTelemetry",
402
+ status: "live",
403
+ sourceLayer: "workflow-review",
404
+ liveEvidence: {
405
+ runnerTest: "test/api/v3/behavioral-coverage.test.ts",
406
+ commit: "refactor-07-pe2-event-telemetry-readback",
407
+ },
408
+ uxIntent: { uiVisible: false, expectsUxResponse: "none" },
409
+ agentMetadata: {
410
+ readOrMutate: "read",
411
+ boundedScope: "session",
412
+ auditCategory: "collab-event-telemetry",
413
+ contextPromptShape:
414
+ "Session telemetry counters for command/collab/api event channels, including origin-kind and replay/schema-mismatch counts.",
415
+ },
416
+ stateClass: "B-session",
417
+ persistsTo: "none",
418
+ broadcastsVia: "awareness",
419
+ rwdReference:
420
+ "§Runtime API § runtime.collab.getEventTelemetry. PE2 Slice-2 event/audit readback over the session TelemetryBus ring buffers. This is a caller-paid snapshot over command/collab/api tails, not a hot-path subscription primitive. Exposes persisted per-channel tail counts and origin-kind counters for command/collab/api events; `lastEventTypes` returns the 10 most recent auditable event types ordered by TelemetryBus seq across the three channels. Callers that need live updates subscribe to the same TelemetryBus channels through the runtime debug facet rather than inferring from Yjs internals.",
421
+ };
422
+
423
+ function eventOriginKind(event: RuntimeTelemetryEvent): CommandOriginKind | null {
424
+ const payload = event.payload;
425
+ if (!payload || typeof payload !== "object") return null;
426
+ const origin = (payload as { readonly origin?: unknown }).origin;
427
+ if (!origin || typeof origin !== "object") return null;
428
+ const kind = (origin as { readonly kind?: unknown }).kind;
429
+ return typeof kind === "string" && COMMAND_ORIGIN_KIND_SET.has(kind)
430
+ ? kind as CommandOriginKind
431
+ : null;
432
+ }
433
+
434
+ function countByOriginKind(
435
+ eventSets: readonly (readonly RuntimeTelemetryEvent[])[],
436
+ ): Partial<Record<CommandOriginKind, number>> {
437
+ const counts: Partial<Record<CommandOriginKind, number>> = {};
438
+ for (const events of eventSets) {
439
+ for (const event of events) {
440
+ const kind = eventOriginKind(event);
441
+ if (!kind) continue;
442
+ counts[kind] = (counts[kind] ?? 0) + 1;
443
+ }
444
+ }
445
+ return counts;
446
+ }
447
+
448
+ function countMatchingEvents(
449
+ eventSets: readonly (readonly RuntimeTelemetryEvent[])[],
450
+ predicate: (event: RuntimeTelemetryEvent) => boolean,
451
+ ): number {
452
+ let count = 0;
453
+ for (const events of eventSets) {
454
+ for (const event of events) {
455
+ if (predicate(event)) count += 1;
456
+ }
457
+ }
458
+ return count;
459
+ }
460
+
461
+ function eventSeq(event: RuntimeTelemetryEvent): number {
462
+ return typeof event.seq === "number" ? event.seq : 0;
463
+ }
464
+
465
+ function collectLastEventTypes(
466
+ eventSets: readonly (readonly RuntimeTelemetryEvent[])[],
467
+ ): readonly string[] {
468
+ const recent: RuntimeTelemetryEvent[] = [];
469
+ for (const events of eventSets) {
470
+ for (const event of events) {
471
+ const insertAt = recent.findIndex((existing) => eventSeq(event) < eventSeq(existing));
472
+ if (insertAt === -1) recent.push(event);
473
+ else recent.splice(insertAt, 0, event);
474
+ if (recent.length > 10) recent.shift();
475
+ }
476
+ }
477
+ return recent.map((event) => event.type);
478
+ }
479
+
480
+ function summarizeEventTelemetry(runtime: RuntimeApiHandle): CollabEventTelemetry {
481
+ const bus = runtime.debug.bus;
482
+ const commandEvents = bus.tail("command", 256);
483
+ const collabEvents = bus.tail("collab", 256);
484
+ const apiEvents = bus.tail("api", 256);
485
+ const auditableEventSets = [commandEvents, collabEvents, apiEvents] as const;
486
+ const channels = bus.getChannels();
487
+ const channelSummaries: CollabEventTelemetryChannelSummary[] = [
488
+ {
489
+ channel: "command",
490
+ enabled: channels.command,
491
+ bufferedEventCount: commandEvents.length,
492
+ persistedInSessionRing: true,
493
+ subscriptionCapable: true,
494
+ },
495
+ {
496
+ channel: "collab",
497
+ enabled: channels.collab,
498
+ bufferedEventCount: collabEvents.length,
499
+ persistedInSessionRing: true,
500
+ subscriptionCapable: true,
501
+ },
502
+ {
503
+ channel: "api",
504
+ enabled: channels.api,
505
+ bufferedEventCount: apiEvents.length,
506
+ persistedInSessionRing: true,
507
+ subscriptionCapable: true,
508
+ },
509
+ ];
510
+
511
+ return {
512
+ channels: channelSummaries,
513
+ counters: {
514
+ commandEventCount: commandEvents.length,
515
+ collabEventCount: collabEvents.length,
516
+ uxResponseEventCount: apiEvents.filter((event) => event.type.startsWith("ux.response.")).length,
517
+ remoteReplayEventCount: collabEvents.filter((event) => event.type.includes("remote-replay")).length,
518
+ schemaMismatchEventCount: countMatchingEvents(
519
+ auditableEventSets,
520
+ (event) => event.type.includes("schema_mismatch"),
521
+ ),
522
+ totalAuditableEventCount: commandEvents.length + collabEvents.length + apiEvents.length,
523
+ },
524
+ originKindCounts: countByOriginKind(auditableEventSets),
525
+ lastEventTypes: collectLastEventTypes(auditableEventSets),
526
+ retention: {
527
+ kind: "session-ring-buffer",
528
+ tailReadLimit: 256,
529
+ cost: "caller-paid-snapshot",
530
+ },
531
+ };
532
+ }
533
+
225
534
  /* ================================================================== */
226
535
  /* family factory */
227
536
  /* ================================================================== */
@@ -310,6 +619,159 @@ export function createCollabFamily(runtime: RuntimeApiHandle) {
310
619
  return getRemoteCursorStatesImpl(input.awareness, input.localClientId);
311
620
  },
312
621
 
622
+ getEventDiscipline(): CollabEventDiscipline {
623
+ // @endStateApi — live. Static protocol read for PE2 origin
624
+ // discipline: command events are replayed through runtime; awareness
625
+ // inputs are session overlays only. Kept here so agents and debug
626
+ // consumers do not infer transport policy from Yjs internals.
627
+ return {
628
+ commandEventSchemaVersion: COMMAND_EVENT_SCHEMA_VERSION,
629
+ commandEventChannel: "runtime-command-event",
630
+ awarenessChannel: "awareness",
631
+ commandOriginKinds: COMMAND_ORIGIN_KINDS,
632
+ commandOriginSources: [
633
+ "keyboard",
634
+ "toolbar",
635
+ "context_menu",
636
+ "comment_panel",
637
+ "review_panel",
638
+ "api",
639
+ "runtime",
640
+ "agent",
641
+ "import",
642
+ "field_refresh",
643
+ "unspecified",
644
+ ],
645
+ originCoverage: [
646
+ {
647
+ class: "local-typing",
648
+ channel: "runtime-command-event",
649
+ canonicalMutation: true,
650
+ commandOriginKinds: ["local-typing"],
651
+ commandOriginSources: ["keyboard"],
652
+ },
653
+ {
654
+ class: "local-command",
655
+ channel: "runtime-command-event",
656
+ canonicalMutation: true,
657
+ commandOriginKinds: ["local-command"],
658
+ commandOriginSources: [
659
+ "toolbar",
660
+ "context_menu",
661
+ "comment_panel",
662
+ "review_panel",
663
+ "api",
664
+ ],
665
+ },
666
+ {
667
+ class: "remote-runtime-command-event",
668
+ channel: "runtime-command-event",
669
+ canonicalMutation: true,
670
+ commandOriginKinds: ["runtime"],
671
+ commandOriginSources: ["runtime"],
672
+ },
673
+ {
674
+ class: "remote-awareness",
675
+ channel: "awareness",
676
+ canonicalMutation: false,
677
+ awarenessInputs: [
678
+ "presence",
679
+ "remote-cursor",
680
+ "remote-selection",
681
+ "hover",
682
+ "typing-indicator",
683
+ "viewing-scope",
684
+ ],
685
+ },
686
+ {
687
+ class: "agent",
688
+ channel: "runtime-command-event",
689
+ canonicalMutation: true,
690
+ commandOriginKinds: ["agent"],
691
+ commandOriginSources: ["agent"],
692
+ },
693
+ {
694
+ class: "import",
695
+ channel: "runtime-command-event",
696
+ canonicalMutation: true,
697
+ commandOriginKinds: ["import"],
698
+ commandOriginSources: ["import"],
699
+ },
700
+ {
701
+ class: "field-refresh",
702
+ channel: "runtime-command-event",
703
+ canonicalMutation: true,
704
+ commandOriginKinds: ["field-refresh"],
705
+ commandOriginSources: ["field_refresh"],
706
+ },
707
+ ],
708
+ broadcastCommandTypes: [...BROADCAST_COMMAND_TYPES].sort(),
709
+ localOnlyCommandTypes: [...LOCAL_ONLY_COMMAND_TYPES].sort(),
710
+ remoteReplay: {
711
+ appliesThroughRuntime: true,
712
+ validatesBaseDocFingerprint: true,
713
+ rejectsSchemaMismatch: true,
714
+ coalescesByDefault: true,
715
+ },
716
+ awarenessInputs: [
717
+ "presence",
718
+ "remote-cursor",
719
+ "remote-selection",
720
+ "hover",
721
+ "typing-indicator",
722
+ "viewing-scope",
723
+ ],
724
+ };
725
+ },
726
+
727
+ getRemoteReplayState(): CollabRemoteReplayState & Partial<MockPayload> {
728
+ // @endStateApi — live-with-adapter. Dynamic counterpart to
729
+ // getEventDiscipline(): exposes the current command-event replay
730
+ // guard posture as plain values while keeping the Yjs sync handle
731
+ // behind the RuntimeApiHandle.
732
+ const sync = runtime.collabSync;
733
+ const guardrails = {
734
+ appliesThroughRuntime: true,
735
+ validatesBaseDocFingerprint: true,
736
+ rejectsSchemaMismatch: true,
737
+ suppressesOutboundWhenReadOnly: true,
738
+ suppressesInboundWhenReadOnly: true,
739
+ coalescesByDefault: true,
740
+ } as const;
741
+ if (sync) {
742
+ return {
743
+ attached: true,
744
+ readOnly: sync.isReadOnly(),
745
+ baseDocFingerprint: sync.getBaseDocFingerprint(),
746
+ appliedEventCount: sync.getAppliedEventCount(),
747
+ remoteActivitySignal: {
748
+ aborted: sync.getRemoteActivitySignal().aborted,
749
+ },
750
+ guardrails,
751
+ };
752
+ }
753
+ return mockPayload(
754
+ "handle.collabSync not wired; hosts pass RuntimeCollabSyncHandle from createRuntimeCollabSync(...) to expose live replay guard state",
755
+ "CollabRemoteReplayState",
756
+ {
757
+ attached: false,
758
+ readOnly: false,
759
+ baseDocFingerprint: null,
760
+ appliedEventCount: 0,
761
+ remoteActivitySignal: { aborted: false },
762
+ guardrails,
763
+ },
764
+ );
765
+ },
766
+
767
+ getEventTelemetry(): CollabEventTelemetry {
768
+ // @endStateApi — live. Reads the session TelemetryBus tails as the
769
+ // durable-enough PE2 event/audit counter store for command/collab/api
770
+ // channels. Does not allocate or subscribe unless telemetry has already
771
+ // been enabled by the host/debug surface.
772
+ return summarizeEventTelemetry(runtime);
773
+ },
774
+
313
775
  getMetadataIntegrity(): CollabMetadataIntegritySnapshot & Partial<MockPayload> {
314
776
  // @endStateApi — live-with-adapter. Coord-07 §2.1 collab expansion
315
777
  // — exposes the tamper-gate state for agents without reaching into