@contractspec/lib.surface-runtime 0.2.3 → 0.3.2

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 (153) hide show
  1. package/dist/adapters/ai-sdk-stub.js +1 -6
  2. package/dist/adapters/blocknote-stub.js +3 -8
  3. package/dist/adapters/dnd-kit-adapter.js +6 -11
  4. package/dist/adapters/dnd-kit-stub.js +1 -6
  5. package/dist/adapters/floating-ui-stub.js +4 -9
  6. package/dist/adapters/index.js +7 -176
  7. package/dist/adapters/interfaces.js +0 -1
  8. package/dist/adapters/motion-stub.js +2 -7
  9. package/dist/adapters/resizable-panels-stub.js +7 -12
  10. package/dist/browser/adapters/ai-sdk-stub.js +1 -5
  11. package/dist/browser/adapters/blocknote-stub.js +3 -7
  12. package/dist/browser/adapters/dnd-kit-adapter.js +6 -10
  13. package/dist/browser/adapters/dnd-kit-stub.js +1 -5
  14. package/dist/browser/adapters/floating-ui-stub.js +4 -8
  15. package/dist/browser/adapters/index.js +7 -175
  16. package/dist/browser/adapters/motion-stub.js +2 -6
  17. package/dist/browser/adapters/resizable-panels-stub.js +5 -9
  18. package/dist/browser/evals/golden-harness.js +4 -825
  19. package/dist/browser/examples/pm-workbench.bundle.js +2 -316
  20. package/dist/browser/i18n/catalogs/en.js +1 -5
  21. package/dist/browser/i18n/catalogs/es.js +1 -5
  22. package/dist/browser/i18n/catalogs/fr.js +1 -5
  23. package/dist/browser/i18n/catalogs/index.js +3 -133
  24. package/dist/browser/i18n/index.js +3 -168
  25. package/dist/browser/i18n/keys.js +1 -5
  26. package/dist/browser/i18n/messages.js +6 -137
  27. package/dist/browser/index.js +4 -2466
  28. package/dist/browser/react/BundleProvider.js +12 -19
  29. package/dist/browser/react/BundleRenderer.js +19 -662
  30. package/dist/browser/react/OverlayConflictResolver.js +12 -180
  31. package/dist/browser/react/PatchProposalCard.js +9 -177
  32. package/dist/browser/react/RegionRenderer.js +14 -60
  33. package/dist/browser/react/SlotRenderer.js +15 -58
  34. package/dist/browser/react/WidgetPalette.js +6 -10
  35. package/dist/browser/react/index.js +14 -790
  36. package/dist/browser/runtime/apply-surface-patch.js +3 -208
  37. package/dist/browser/runtime/audit-events.js +8 -19
  38. package/dist/browser/runtime/build-context.js +2 -6
  39. package/dist/browser/runtime/extension-registry.js +3 -9
  40. package/dist/browser/runtime/field-renderer-registry.js +5 -11
  41. package/dist/browser/runtime/index.js +54 -1487
  42. package/dist/browser/runtime/overlay-alignment.js +8 -19
  43. package/dist/browser/runtime/overlay-signer.js +2 -7
  44. package/dist/browser/runtime/override-store.js +3 -9
  45. package/dist/browser/runtime/planner-prompt.js +2 -6
  46. package/dist/browser/runtime/planner-tools.js +3 -9
  47. package/dist/browser/runtime/policy-eval.js +3 -135
  48. package/dist/browser/runtime/preference-adapter.js +2 -62
  49. package/dist/browser/runtime/resolve-bundle.js +10 -447
  50. package/dist/browser/runtime/resolve-preferences.js +3 -7
  51. package/dist/browser/runtime/rollback.js +2 -325
  52. package/dist/browser/runtime/widget-registry.js +1 -5
  53. package/dist/browser/spec/define-module-bundle.js +2 -67
  54. package/dist/browser/spec/index.js +9 -317
  55. package/dist/browser/spec/validate-bundle.js +3 -8
  56. package/dist/browser/spec/validate-surface-patch.js +5 -11
  57. package/dist/browser/telemetry/index.js +4 -16
  58. package/dist/browser/telemetry/surface-metrics.js +7 -16
  59. package/dist/evals/golden-context.js +0 -1
  60. package/dist/evals/golden-harness.js +4 -826
  61. package/dist/examples/pm-workbench.bundle.js +2 -317
  62. package/dist/i18n/catalogs/en.js +1 -6
  63. package/dist/i18n/catalogs/es.js +1 -6
  64. package/dist/i18n/catalogs/fr.js +1 -6
  65. package/dist/i18n/catalogs/index.js +3 -134
  66. package/dist/i18n/index.js +3 -169
  67. package/dist/i18n/keys.js +1 -6
  68. package/dist/i18n/messages.js +6 -138
  69. package/dist/index.js +4 -2467
  70. package/dist/node/adapters/ai-sdk-stub.js +1 -5
  71. package/dist/node/adapters/blocknote-stub.js +3 -7
  72. package/dist/node/adapters/dnd-kit-adapter.js +6 -10
  73. package/dist/node/adapters/dnd-kit-stub.js +1 -5
  74. package/dist/node/adapters/floating-ui-stub.js +4 -8
  75. package/dist/node/adapters/index.js +7 -175
  76. package/dist/node/adapters/motion-stub.js +2 -6
  77. package/dist/node/adapters/resizable-panels-stub.js +5 -9
  78. package/dist/node/evals/golden-harness.js +4 -825
  79. package/dist/node/examples/pm-workbench.bundle.js +2 -316
  80. package/dist/node/i18n/catalogs/en.js +1 -5
  81. package/dist/node/i18n/catalogs/es.js +1 -5
  82. package/dist/node/i18n/catalogs/fr.js +1 -5
  83. package/dist/node/i18n/catalogs/index.js +3 -133
  84. package/dist/node/i18n/index.js +3 -168
  85. package/dist/node/i18n/keys.js +1 -5
  86. package/dist/node/i18n/messages.js +6 -137
  87. package/dist/node/index.js +4 -2466
  88. package/dist/node/react/BundleProvider.js +12 -19
  89. package/dist/node/react/BundleRenderer.js +19 -662
  90. package/dist/node/react/OverlayConflictResolver.js +12 -180
  91. package/dist/node/react/PatchProposalCard.js +9 -177
  92. package/dist/node/react/RegionRenderer.js +14 -60
  93. package/dist/node/react/SlotRenderer.js +15 -58
  94. package/dist/node/react/WidgetPalette.js +6 -10
  95. package/dist/node/react/index.js +14 -790
  96. package/dist/node/runtime/apply-surface-patch.js +3 -208
  97. package/dist/node/runtime/audit-events.js +8 -19
  98. package/dist/node/runtime/build-context.js +2 -6
  99. package/dist/node/runtime/extension-registry.js +3 -9
  100. package/dist/node/runtime/field-renderer-registry.js +5 -11
  101. package/dist/node/runtime/index.js +54 -1487
  102. package/dist/node/runtime/overlay-alignment.js +8 -19
  103. package/dist/node/runtime/overlay-signer.js +2 -7
  104. package/dist/node/runtime/override-store.js +3 -9
  105. package/dist/node/runtime/planner-prompt.js +2 -6
  106. package/dist/node/runtime/planner-tools.js +3 -9
  107. package/dist/node/runtime/policy-eval.js +3 -135
  108. package/dist/node/runtime/preference-adapter.js +2 -62
  109. package/dist/node/runtime/resolve-bundle.js +10 -447
  110. package/dist/node/runtime/resolve-preferences.js +3 -7
  111. package/dist/node/runtime/rollback.js +2 -325
  112. package/dist/node/runtime/widget-registry.js +1 -5
  113. package/dist/node/spec/define-module-bundle.js +2 -67
  114. package/dist/node/spec/index.js +9 -317
  115. package/dist/node/spec/validate-bundle.js +3 -8
  116. package/dist/node/spec/validate-surface-patch.js +5 -11
  117. package/dist/node/telemetry/index.js +4 -16
  118. package/dist/node/telemetry/surface-metrics.js +7 -16
  119. package/dist/react/BundleProvider.js +12 -20
  120. package/dist/react/BundleRenderer.d.ts +3 -1
  121. package/dist/react/BundleRenderer.js +19 -663
  122. package/dist/react/OverlayConflictResolver.js +12 -181
  123. package/dist/react/PatchProposalCard.js +9 -178
  124. package/dist/react/RegionRenderer.js +14 -61
  125. package/dist/react/SlotRenderer.js +15 -59
  126. package/dist/react/WidgetPalette.js +6 -11
  127. package/dist/react/index.js +14 -791
  128. package/dist/runtime/apply-surface-patch.js +3 -209
  129. package/dist/runtime/audit-events.js +8 -20
  130. package/dist/runtime/build-context.js +2 -7
  131. package/dist/runtime/extension-registry.js +3 -10
  132. package/dist/runtime/field-renderer-registry.js +9 -16
  133. package/dist/runtime/index.js +54 -1488
  134. package/dist/runtime/overlay-alignment.js +8 -20
  135. package/dist/runtime/overlay-signer.js +2 -8
  136. package/dist/runtime/override-store.js +3 -10
  137. package/dist/runtime/planner-prompt.js +11 -9
  138. package/dist/runtime/planner-tools.js +4 -11
  139. package/dist/runtime/policy-eval.js +3 -136
  140. package/dist/runtime/preference-adapter.js +2 -63
  141. package/dist/runtime/resolve-bundle.js +10 -448
  142. package/dist/runtime/resolve-preferences.js +3 -8
  143. package/dist/runtime/rollback.js +2 -326
  144. package/dist/runtime/widget-registry.js +1 -6
  145. package/dist/spec/define-module-bundle.js +2 -68
  146. package/dist/spec/index.js +9 -318
  147. package/dist/spec/types.js +0 -1
  148. package/dist/spec/validate-bundle.js +3 -9
  149. package/dist/spec/validate-surface-patch.js +5 -12
  150. package/dist/spec/verification-snapshot-types.js +0 -1
  151. package/dist/telemetry/index.js +4 -17
  152. package/dist/telemetry/surface-metrics.js +7 -17
  153. package/package.json +7 -7
@@ -1,445 +1,10 @@
1
- // @bun
2
- // src/telemetry/surface-metrics.ts
3
- import {
4
- createCounter,
5
- createHistogram
6
- } from "@contractspec/lib.observability/metrics";
7
- var METER_NAME = "@contractspec/lib.surface-runtime";
8
- var resolutionDurationMs = createHistogram("bundle_surface_resolution_duration_ms", "Time to resolve bundle spec to surface plan in milliseconds", METER_NAME);
9
- var patchAcceptanceCounter = createCounter("bundle_surface_patch_acceptance_total", "Total AI patch proposals accepted by user", METER_NAME);
10
- var patchRejectionCounter = createCounter("bundle_surface_patch_rejection_total", "Total AI patch proposals rejected by user", METER_NAME);
11
- var policyDenialCounter = createCounter("bundle_surface_policy_denial_total", "Total policy denials (actions denied by policy)", METER_NAME);
12
- var surfaceFallbackCounter = createCounter("bundle_surface_fallback_total", "Total surface or layout fallbacks during resolution", METER_NAME);
13
- var missingRendererCounter = createCounter("bundle_surface_renderer_missing_total", "Total slots with no renderer for requested node kind", METER_NAME);
14
- // src/runtime/resolve-preferences.ts
15
- var DIMENSION_KEYS = [
16
- "guidance",
17
- "density",
18
- "dataDepth",
19
- "control",
20
- "media",
21
- "pace",
22
- "narrative"
23
- ];
24
- var SCOPE_ORDER = [
25
- "user",
26
- "workspace-user",
27
- "bundle",
28
- "surface",
29
- "entity",
30
- "session"
31
- ];
32
- function mergeByScope(layers, ctx) {
33
- const merged = { ...ctx.preferences };
34
- const sourceByDimension = {};
35
- for (const scope of SCOPE_ORDER) {
36
- const layer = layers[scope];
37
- if (!layer)
38
- continue;
39
- for (const dim of DIMENSION_KEYS) {
40
- const val = layer[dim];
41
- if (val !== undefined) {
42
- merged[dim] = val;
43
- sourceByDimension[dim] = scope;
44
- }
45
- }
46
- }
47
- for (const dim of DIMENSION_KEYS) {
48
- if (sourceByDimension[dim] === undefined) {
49
- sourceByDimension[dim] = "session";
50
- }
51
- }
52
- return { canonical: merged, sourceByDimension };
53
- }
54
- function resolveConstraints(_canonical, _ctx) {
55
- return { constrained: {}, notes: [] };
56
- }
57
- function resolvePreferenceProfile(ctx) {
58
- const layers = {
59
- session: ctx.preferences
60
- };
61
- const { canonical, sourceByDimension } = mergeByScope(layers, ctx);
62
- const { constrained, notes } = resolveConstraints(canonical, ctx);
63
- return {
64
- canonical,
65
- sourceByDimension,
66
- constrained,
67
- notes
68
- };
69
- }
70
-
71
- // src/spec/validate-surface-patch.ts
72
- var VALID_OPS = [
73
- "insert-node",
74
- "replace-node",
75
- "remove-node",
76
- "move-node",
77
- "resize-panel",
78
- "set-layout",
79
- "reveal-field",
80
- "hide-field",
81
- "promote-action",
82
- "set-focus"
83
- ];
84
- var VALID_NODE_KINDS = [
85
- "metric-strip",
86
- "data-view",
87
- "entity-card",
88
- "entity-header",
89
- "entity-summary",
90
- "entity-section",
91
- "entity-field",
92
- "entity-activity",
93
- "entity-relations",
94
- "entity-timeline",
95
- "entity-comments",
96
- "entity-attachments",
97
- "entity-view-switcher",
98
- "entity-automation-panel",
99
- "rich-doc",
100
- "chat-thread",
101
- "assistant-panel",
102
- "action-bar",
103
- "timeline",
104
- "board",
105
- "table",
106
- "calendar",
107
- "form",
108
- "chart",
109
- "relation-graph",
110
- "custom-widget"
111
- ];
112
- function validateSurfaceNode(node, path) {
113
- if (!node.nodeId || typeof node.nodeId !== "string") {
114
- throw new Error(`${path}: nodeId must be a non-empty string`);
115
- }
116
- if (!node.kind || !VALID_NODE_KINDS.includes(node.kind)) {
117
- throw new Error(`${path}: kind must be one of ${VALID_NODE_KINDS.join(", ")}`);
118
- }
119
- if (node.children) {
120
- for (let i = 0;i < node.children.length; i++) {
121
- const child = node.children[i];
122
- if (child)
123
- validateSurfaceNode(child, `${path}.children[${i}]`);
124
- }
125
- }
126
- }
127
- function validateSurfacePatchOp(op, index) {
128
- const path = `ops[${index}]`;
129
- if (!op || typeof op !== "object" || !("op" in op)) {
130
- throw new Error(`${path}: must be an object with op field`);
131
- }
132
- const opType = op.op;
133
- if (!VALID_OPS.includes(opType)) {
134
- throw new Error(`${path}: op must be one of ${VALID_OPS.join(", ")}`);
135
- }
136
- switch (op.op) {
137
- case "insert-node":
138
- if (!op.slotId || typeof op.slotId !== "string") {
139
- throw new Error(`${path}: insert-node requires slotId string`);
140
- }
141
- if (!op.node) {
142
- throw new Error(`${path}: insert-node requires node`);
143
- }
144
- validateSurfaceNode(op.node, `${path}.node`);
145
- if (op.index !== undefined && typeof op.index !== "number") {
146
- throw new Error(`${path}: insert-node index must be number if present`);
147
- }
148
- break;
149
- case "replace-node":
150
- if (!op.nodeId || typeof op.nodeId !== "string") {
151
- throw new Error(`${path}: replace-node requires nodeId string`);
152
- }
153
- if (!op.node) {
154
- throw new Error(`${path}: replace-node requires node`);
155
- }
156
- validateSurfaceNode(op.node, `${path}.node`);
157
- break;
158
- case "remove-node":
159
- if (!op.nodeId || typeof op.nodeId !== "string") {
160
- throw new Error(`${path}: remove-node requires nodeId string`);
161
- }
162
- break;
163
- case "move-node":
164
- if (!op.nodeId || typeof op.nodeId !== "string") {
165
- throw new Error(`${path}: move-node requires nodeId string`);
166
- }
167
- if (!op.toSlotId || typeof op.toSlotId !== "string") {
168
- throw new Error(`${path}: move-node requires toSlotId string`);
169
- }
170
- if (op.index !== undefined && typeof op.index !== "number") {
171
- throw new Error(`${path}: move-node index must be number if present`);
172
- }
173
- break;
174
- case "resize-panel":
175
- if (!op.persistKey || typeof op.persistKey !== "string") {
176
- throw new Error(`${path}: resize-panel requires persistKey string`);
177
- }
178
- if (!Array.isArray(op.sizes) || op.sizes.some((s) => typeof s !== "number")) {
179
- throw new Error(`${path}: resize-panel requires sizes number[]`);
180
- }
181
- break;
182
- case "set-layout":
183
- if (!op.layoutId || typeof op.layoutId !== "string") {
184
- throw new Error(`${path}: set-layout requires layoutId string`);
185
- }
186
- break;
187
- case "reveal-field":
188
- case "hide-field":
189
- if (!op.fieldId || typeof op.fieldId !== "string") {
190
- throw new Error(`${path}: ${op.op} requires fieldId string`);
191
- }
192
- break;
193
- case "promote-action": {
194
- if (!op.actionId || typeof op.actionId !== "string") {
195
- throw new Error(`${path}: promote-action requires actionId string`);
196
- }
197
- const validPlacements = ["header", "inline", "context", "assistant"];
198
- if (!op.placement || !validPlacements.includes(op.placement)) {
199
- throw new Error(`${path}: promote-action placement must be one of ${validPlacements.join(", ")}`);
200
- }
201
- break;
202
- }
203
- case "set-focus":
204
- if (!op.targetId || typeof op.targetId !== "string") {
205
- throw new Error(`${path}: set-focus requires targetId string`);
206
- }
207
- break;
208
- default:
209
- throw new Error(`${path}: unknown op "${opType}"`);
210
- }
211
- }
212
- function validateSurfacePatch(ops) {
213
- if (!Array.isArray(ops)) {
214
- throw new Error("Patch ops must be an array");
215
- }
216
- for (let i = 0;i < ops.length; i++) {
217
- const op = ops[i];
218
- if (op)
219
- validateSurfacePatchOp(op, i);
220
- }
221
- }
222
- function validateSurfaceNodeAgainstKinds(node, allowedKinds, path) {
223
- if (!allowedKinds.includes(node.kind)) {
224
- throw new Error(`${path}: kind "${node.kind}" not in allowed list [${allowedKinds.join(", ")}]`);
225
- }
226
- if (node.children) {
227
- for (let i = 0;i < node.children.length; i++) {
228
- const child = node.children[i];
229
- if (child)
230
- validateSurfaceNodeAgainstKinds(child, allowedKinds, `${path}.children[${i}]`);
231
- }
232
- }
233
- }
234
- function validatePatchProposal(ops, constraints) {
235
- if (!Array.isArray(ops)) {
236
- throw new Error("Patch ops must be an array");
237
- }
238
- const { allowedOps, allowedSlots, allowedNodeKinds } = constraints;
239
- for (let i = 0;i < ops.length; i++) {
240
- const op = ops[i];
241
- if (!op)
242
- continue;
243
- const path = `ops[${i}]`;
244
- if (!allowedOps.includes(op.op)) {
245
- throw new Error(`${path}: op "${op.op}" not in allowed list [${allowedOps.join(", ")}]`);
246
- }
247
- switch (op.op) {
248
- case "insert-node":
249
- if (!allowedSlots.includes(op.slotId)) {
250
- throw new Error(`${path}: slotId "${op.slotId}" not in allowed slots [${allowedSlots.join(", ")}]`);
251
- }
252
- if (op.node) {
253
- validateSurfaceNodeAgainstKinds(op.node, allowedNodeKinds, `${path}.node`);
254
- }
255
- break;
256
- case "move-node":
257
- if (!allowedSlots.includes(op.toSlotId)) {
258
- throw new Error(`${path}: toSlotId "${op.toSlotId}" not in allowed slots [${allowedSlots.join(", ")}]`);
259
- }
260
- break;
261
- case "replace-node":
262
- if (op.node) {
263
- validateSurfaceNodeAgainstKinds(op.node, allowedNodeKinds, `${path}.node`);
264
- }
265
- break;
266
- default:
267
- break;
268
- }
269
- }
270
- validateSurfacePatch(ops);
271
- }
272
-
273
- // src/runtime/apply-surface-patch.ts
274
- import { Logger } from "@contractspec/lib.observability";
275
- var logger = new Logger("@contractspec/lib.surface-runtime");
276
- function findNode(nodes, nodeId) {
277
- for (const n of nodes) {
278
- if (n.nodeId === nodeId)
279
- return n;
280
- if (n.children) {
281
- const found = findNode(n.children, nodeId);
282
- if (found)
283
- return found;
284
- }
285
- }
286
- return;
287
- }
288
- function collectNodeIds(nodes) {
289
- const ids = new Set;
290
- for (const n of nodes) {
291
- ids.add(n.nodeId);
292
- if (n.children)
293
- collectNodeIds(n.children).forEach((id) => ids.add(id));
294
- }
295
- return ids;
296
- }
297
- function validateOp(op, nodeIds) {
298
- if (op.op === "remove-node" || op.op === "replace-node" || op.op === "move-node") {
299
- if (!nodeIds.has(op.nodeId)) {
300
- throw new Error(`Patch op references unknown nodeId: ${op.nodeId}`);
301
- }
302
- }
303
- if (op.op === "insert-node" && !op.node?.nodeId) {
304
- throw new Error("insert-node requires node with nodeId");
305
- }
306
- }
307
- function produceInverse(op, plan) {
308
- switch (op.op) {
309
- case "insert-node":
310
- return op.node ? { op: "remove-node", nodeId: op.node.nodeId } : null;
311
- case "remove-node": {
312
- const node = findNode(plan.nodes, op.nodeId);
313
- return node ? { op: "insert-node", slotId: "primary", node } : null;
314
- }
315
- case "replace-node": {
316
- const prev = findNode(plan.nodes, op.nodeId);
317
- return prev ? { op: "replace-node", nodeId: op.nodeId, node: prev } : null;
318
- }
319
- case "set-layout":
320
- return { op: "set-layout", layoutId: plan.layoutId };
321
- case "reveal-field":
322
- return { op: "hide-field", fieldId: op.fieldId };
323
- case "hide-field":
324
- return { op: "reveal-field", fieldId: op.fieldId };
325
- case "move-node":
326
- case "resize-panel":
327
- case "set-focus":
328
- case "promote-action":
329
- return null;
330
- default:
331
- return null;
332
- }
333
- }
334
- function applySurfacePatch(plan, ops) {
335
- if (ops.length === 0)
336
- return { plan, inverseOps: [] };
337
- validateSurfacePatch(ops);
338
- const nodeIds = collectNodeIds(plan.nodes);
339
- for (const op of ops) {
340
- validateOp(op, nodeIds);
341
- }
342
- let nextNodes = [...plan.nodes];
343
- let nextLayoutId = plan.layoutId;
344
- const inverseOps = [];
345
- for (const op of ops) {
346
- const inv = produceInverse(op, {
347
- ...plan,
348
- nodes: nextNodes,
349
- layoutId: nextLayoutId
350
- });
351
- if (inv)
352
- inverseOps.unshift(inv);
353
- switch (op.op) {
354
- case "insert-node":
355
- if (op.node)
356
- nextNodes = [...nextNodes, op.node];
357
- break;
358
- case "remove-node":
359
- nextNodes = nextNodes.filter((n) => n.nodeId !== op.nodeId);
360
- break;
361
- case "replace-node": {
362
- const replace = (nodes) => nodes.map((n) => n.nodeId === op.nodeId ? op.node : { ...n, children: n.children ? replace(n.children) : undefined });
363
- nextNodes = replace(nextNodes);
364
- break;
365
- }
366
- case "set-layout":
367
- nextLayoutId = op.layoutId;
368
- break;
369
- case "move-node":
370
- case "resize-panel":
371
- case "set-focus":
372
- case "reveal-field":
373
- case "hide-field":
374
- case "promote-action":
375
- break;
376
- }
377
- }
378
- const result = {
379
- plan: { ...plan, nodes: nextNodes, layoutId: nextLayoutId },
380
- inverseOps
381
- };
382
- logger.info("bundle.surface.patch.applied", {
383
- bundleKey: plan.bundleKey,
384
- surfaceId: plan.surfaceId,
385
- opCount: ops.length,
386
- opTypes: [...new Set(ops.map((o) => o.op))]
387
- });
388
- return result;
389
- }
390
-
391
- // src/runtime/override-store.ts
392
- function buildOverrideTargetKey(bundleKey, surfaceId, routeId) {
393
- return routeId ? `${bundleKey}:${routeId}:${surfaceId}` : `${bundleKey}:${surfaceId}`;
394
- }
395
- function createOverrideStoreWithApprovalGate(store, options) {
396
- const { requireApprovalForWorkspacePatches = false, requestApproval } = options;
397
- return {
398
- list: store.list.bind(store),
399
- async save(scope, targetKey, patch, saveOptions) {
400
- if (requireApprovalForWorkspacePatches && scope === "workspace" && requestApproval) {
401
- const approved = await requestApproval({ scope, targetKey, patch });
402
- if (!approved) {
403
- throw new Error("Workspace overlay save rejected: approval required and not granted");
404
- }
405
- }
406
- return store.save(scope, targetKey, patch, saveOptions);
407
- },
408
- remove: store.remove.bind(store)
409
- };
410
- }
411
- function createInMemoryOverrideStore() {
412
- const overrides = new Map;
413
- function nextId() {
414
- return `ov_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
415
- }
416
- return {
417
- async list(scope, targetKey) {
418
- return Array.from(overrides.values()).filter((o) => o.scope === scope && o.targetKey === targetKey);
419
- },
420
- async save(scope, targetKey, patch, options) {
421
- const overrideId = options?.overrideId ?? nextId();
422
- const stored = {
423
- overrideId,
424
- scope,
425
- targetKey,
426
- patch,
427
- createdAt: new Date().toISOString(),
428
- createdBy: options?.createdBy
429
- };
430
- overrides.set(overrideId, stored);
431
- return overrideId;
432
- },
433
- async remove(overrideId) {
434
- overrides.delete(overrideId);
435
- }
436
- };
437
- }
438
-
439
- // src/runtime/resolve-bundle.ts
440
1
  import { traceAsync } from "@contractspec/lib.observability/tracing";
441
- import { Logger as Logger2 } from "@contractspec/lib.observability";
442
- var logger2 = new Logger2("@contractspec/lib.surface-runtime");
2
+ import { Logger } from "@contractspec/lib.observability";
3
+ import { resolutionDurationMs, surfaceFallbackCounter } from "../telemetry";
4
+ import { resolvePreferenceProfile } from "./resolve-preferences";
5
+ import { applySurfacePatch } from "./apply-surface-patch";
6
+ import { buildOverrideTargetKey } from "./override-store";
7
+ const logger = new Logger("@contractspec/lib.surface-runtime");
443
8
  function getOpTarget(op) {
444
9
  switch (op.op) {
445
10
  case "hide-field":
@@ -545,7 +110,7 @@ function allowFromDecision(decision) {
545
110
  function generateResolutionId() {
546
111
  return `res_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
547
112
  }
548
- var OVERLAY_SCOPE_ORDER = [
113
+ const OVERLAY_SCOPE_ORDER = [
549
114
  "system",
550
115
  "workspace",
551
116
  "team",
@@ -564,7 +129,7 @@ function buildAdaptation(ctx) {
564
129
  notes
565
130
  };
566
131
  }
567
- async function resolveBundle(spec, ctx, options) {
132
+ export async function resolveBundle(spec, ctx, options) {
568
133
  return traceAsync("surface.resolveBundle", async (span) => {
569
134
  const start = performance.now();
570
135
  try {
@@ -578,7 +143,7 @@ async function resolveBundle(spec, ctx, options) {
578
143
  span.setAttribute("bundle.key", spec.meta.key);
579
144
  span.setAttribute("surface.id", plan.surfaceId);
580
145
  span.setAttribute("resolution.duration_ms", durationMs);
581
- logger2.info("bundle.surface.resolved", {
146
+ logger.info("bundle.surface.resolved", {
582
147
  bundleKey: spec.meta.key,
583
148
  surfaceId: plan.surfaceId,
584
149
  layoutId: plan.layoutId,
@@ -717,7 +282,7 @@ async function resolveBundleInternal(spec, ctx, options) {
717
282
  appliedOps: ov.patch.length
718
283
  });
719
284
  } catch (err) {
720
- logger2.warn("bundle.overlay.apply.failed", {
285
+ logger.warn("bundle.overlay.apply.failed", {
721
286
  overlayId: ov.overrideId,
722
287
  scope,
723
288
  error: err instanceof Error ? err.message : String(err)
@@ -763,6 +328,3 @@ function createErrorPlan(spec, ctx, err) {
763
328
  locale: ctx.locale
764
329
  };
765
330
  }
766
- export {
767
- resolveBundle
768
- };
@@ -1,6 +1,4 @@
1
- // @bun
2
- // src/runtime/resolve-preferences.ts
3
- var DIMENSION_KEYS = [
1
+ const DIMENSION_KEYS = [
4
2
  "guidance",
5
3
  "density",
6
4
  "dataDepth",
@@ -9,7 +7,7 @@ var DIMENSION_KEYS = [
9
7
  "pace",
10
8
  "narrative"
11
9
  ];
12
- var SCOPE_ORDER = [
10
+ const SCOPE_ORDER = [
13
11
  "user",
14
12
  "workspace-user",
15
13
  "bundle",
@@ -42,7 +40,7 @@ function mergeByScope(layers, ctx) {
42
40
  function resolveConstraints(_canonical, _ctx) {
43
41
  return { constrained: {}, notes: [] };
44
42
  }
45
- function resolvePreferenceProfile(ctx) {
43
+ export function resolvePreferenceProfile(ctx) {
46
44
  const layers = {
47
45
  session: ctx.preferences
48
46
  };
@@ -55,6 +53,3 @@ function resolvePreferenceProfile(ctx) {
55
53
  notes
56
54
  };
57
55
  }
58
- export {
59
- resolvePreferenceProfile
60
- };