@contractspec/lib.personalization 6.0.26 → 6.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contractspec/lib.personalization",
3
- "version": "6.0.26",
3
+ "version": "6.1.1",
4
4
  "description": "Behavior tracking, analysis, and adaptation helpers for ContractSpec personalization.",
5
5
  "keywords": [
6
6
  "contractspec",
@@ -32,16 +32,16 @@
32
32
  "typecheck": "tsc --noEmit"
33
33
  },
34
34
  "dependencies": {
35
- "@contractspec/lib.bus": "3.7.26",
35
+ "@contractspec/lib.bus": "3.7.28",
36
36
  "@contractspec/lib.schema": "3.7.14",
37
- "@contractspec/lib.contracts-spec": "6.1.0",
38
- "@contractspec/lib.knowledge": "3.8.2",
39
- "@contractspec/lib.overlay-engine": "3.7.26",
37
+ "@contractspec/lib.contracts-spec": "6.3.0",
38
+ "@contractspec/lib.knowledge": "3.8.4",
39
+ "@contractspec/lib.overlay-engine": "3.7.28",
40
40
  "@opentelemetry/api": "^1.9.1"
41
41
  },
42
42
  "peerDependencies": {
43
43
  "@opentelemetry/api": "^1.9.1",
44
- "@contractspec/lib.surface-runtime": "0.5.26"
44
+ "@contractspec/lib.surface-runtime": "0.5.28"
45
45
  },
46
46
  "peerDependenciesMeta": {
47
47
  "@contractspec/lib.surface-runtime": {
@@ -56,84 +56,78 @@
56
56
  "exports": {
57
57
  ".": {
58
58
  "types": "./dist/index.d.ts",
59
- "browser": "./dist/browser/index.js",
60
59
  "bun": "./dist/index.js",
61
60
  "node": "./dist/node/index.js",
62
61
  "default": "./dist/index.js"
63
62
  },
64
63
  "./adapter": {
65
64
  "types": "./dist/adapter.d.ts",
66
- "browser": "./dist/browser/adapter.js",
67
65
  "bun": "./dist/adapter.js",
68
66
  "node": "./dist/node/adapter.js",
69
67
  "default": "./dist/adapter.js"
70
68
  },
71
69
  "./analyzer": {
72
70
  "types": "./dist/analyzer.d.ts",
73
- "browser": "./dist/browser/analyzer.js",
74
71
  "bun": "./dist/analyzer.js",
75
72
  "node": "./dist/node/analyzer.js",
76
73
  "default": "./dist/analyzer.js"
77
74
  },
75
+ "./data-view-preferences": {
76
+ "types": "./dist/data-view-preferences.d.ts",
77
+ "bun": "./dist/data-view-preferences.js",
78
+ "node": "./dist/node/data-view-preferences.js",
79
+ "default": "./dist/data-view-preferences.js"
80
+ },
78
81
  "./docs": {
79
82
  "types": "./dist/docs/index.d.ts",
80
- "browser": "./dist/browser/docs/index.js",
81
83
  "bun": "./dist/docs/index.js",
82
84
  "node": "./dist/node/docs/index.js",
83
85
  "default": "./dist/docs/index.js"
84
86
  },
85
87
  "./docs/behavior-tracking.docblock": {
86
88
  "types": "./dist/docs/behavior-tracking.docblock.d.ts",
87
- "browser": "./dist/browser/docs/behavior-tracking.docblock.js",
88
89
  "bun": "./dist/docs/behavior-tracking.docblock.js",
89
90
  "node": "./dist/node/docs/behavior-tracking.docblock.js",
90
91
  "default": "./dist/docs/behavior-tracking.docblock.js"
91
92
  },
92
93
  "./docs/overlay-engine.docblock": {
93
94
  "types": "./dist/docs/overlay-engine.docblock.d.ts",
94
- "browser": "./dist/browser/docs/overlay-engine.docblock.js",
95
95
  "bun": "./dist/docs/overlay-engine.docblock.js",
96
96
  "node": "./dist/node/docs/overlay-engine.docblock.js",
97
97
  "default": "./dist/docs/overlay-engine.docblock.js"
98
98
  },
99
99
  "./docs/workflow-composition.docblock": {
100
100
  "types": "./dist/docs/workflow-composition.docblock.d.ts",
101
- "browser": "./dist/browser/docs/workflow-composition.docblock.js",
102
101
  "bun": "./dist/docs/workflow-composition.docblock.js",
103
102
  "node": "./dist/node/docs/workflow-composition.docblock.js",
104
103
  "default": "./dist/docs/workflow-composition.docblock.js"
105
104
  },
106
105
  "./personalization.feature": {
107
106
  "types": "./dist/personalization.feature.d.ts",
108
- "browser": "./dist/browser/personalization.feature.js",
109
107
  "bun": "./dist/personalization.feature.js",
110
108
  "node": "./dist/node/personalization.feature.js",
111
109
  "default": "./dist/personalization.feature.js"
112
110
  },
113
111
  "./preference-dimensions": {
114
112
  "types": "./dist/preference-dimensions.d.ts",
115
- "browser": "./dist/browser/preference-dimensions.js",
116
113
  "bun": "./dist/preference-dimensions.js",
117
114
  "node": "./dist/node/preference-dimensions.js",
118
115
  "default": "./dist/preference-dimensions.js"
119
116
  },
120
117
  "./store": {
121
118
  "types": "./dist/store.d.ts",
122
- "browser": "./dist/browser/store.js",
123
119
  "bun": "./dist/store.js",
124
120
  "node": "./dist/node/store.js",
125
121
  "default": "./dist/store.js"
126
122
  },
127
123
  "./tracker": {
128
124
  "types": "./dist/tracker.d.ts",
129
- "browser": "./dist/browser/tracker.js",
130
125
  "bun": "./dist/tracker.js",
131
126
  "node": "./dist/node/tracker.js",
132
127
  "default": "./dist/tracker.js"
133
128
  },
134
129
  "./types": {
135
130
  "types": "./dist/types.d.ts",
136
- "browser": "./dist/browser/types.js",
137
131
  "bun": "./dist/types.js",
138
132
  "node": "./dist/node/types.js",
139
133
  "default": "./dist/types.js"
@@ -144,84 +138,78 @@
144
138
  "exports": {
145
139
  ".": {
146
140
  "types": "./dist/index.d.ts",
147
- "browser": "./dist/browser/index.js",
148
141
  "bun": "./dist/index.js",
149
142
  "node": "./dist/node/index.js",
150
143
  "default": "./dist/index.js"
151
144
  },
152
145
  "./adapter": {
153
146
  "types": "./dist/adapter.d.ts",
154
- "browser": "./dist/browser/adapter.js",
155
147
  "bun": "./dist/adapter.js",
156
148
  "node": "./dist/node/adapter.js",
157
149
  "default": "./dist/adapter.js"
158
150
  },
159
151
  "./analyzer": {
160
152
  "types": "./dist/analyzer.d.ts",
161
- "browser": "./dist/browser/analyzer.js",
162
153
  "bun": "./dist/analyzer.js",
163
154
  "node": "./dist/node/analyzer.js",
164
155
  "default": "./dist/analyzer.js"
165
156
  },
157
+ "./data-view-preferences": {
158
+ "types": "./dist/data-view-preferences.d.ts",
159
+ "bun": "./dist/data-view-preferences.js",
160
+ "node": "./dist/node/data-view-preferences.js",
161
+ "default": "./dist/data-view-preferences.js"
162
+ },
166
163
  "./docs": {
167
164
  "types": "./dist/docs/index.d.ts",
168
- "browser": "./dist/browser/docs/index.js",
169
165
  "bun": "./dist/docs/index.js",
170
166
  "node": "./dist/node/docs/index.js",
171
167
  "default": "./dist/docs/index.js"
172
168
  },
173
169
  "./docs/behavior-tracking.docblock": {
174
170
  "types": "./dist/docs/behavior-tracking.docblock.d.ts",
175
- "browser": "./dist/browser/docs/behavior-tracking.docblock.js",
176
171
  "bun": "./dist/docs/behavior-tracking.docblock.js",
177
172
  "node": "./dist/node/docs/behavior-tracking.docblock.js",
178
173
  "default": "./dist/docs/behavior-tracking.docblock.js"
179
174
  },
180
175
  "./docs/overlay-engine.docblock": {
181
176
  "types": "./dist/docs/overlay-engine.docblock.d.ts",
182
- "browser": "./dist/browser/docs/overlay-engine.docblock.js",
183
177
  "bun": "./dist/docs/overlay-engine.docblock.js",
184
178
  "node": "./dist/node/docs/overlay-engine.docblock.js",
185
179
  "default": "./dist/docs/overlay-engine.docblock.js"
186
180
  },
187
181
  "./docs/workflow-composition.docblock": {
188
182
  "types": "./dist/docs/workflow-composition.docblock.d.ts",
189
- "browser": "./dist/browser/docs/workflow-composition.docblock.js",
190
183
  "bun": "./dist/docs/workflow-composition.docblock.js",
191
184
  "node": "./dist/node/docs/workflow-composition.docblock.js",
192
185
  "default": "./dist/docs/workflow-composition.docblock.js"
193
186
  },
194
187
  "./personalization.feature": {
195
188
  "types": "./dist/personalization.feature.d.ts",
196
- "browser": "./dist/browser/personalization.feature.js",
197
189
  "bun": "./dist/personalization.feature.js",
198
190
  "node": "./dist/node/personalization.feature.js",
199
191
  "default": "./dist/personalization.feature.js"
200
192
  },
201
193
  "./preference-dimensions": {
202
194
  "types": "./dist/preference-dimensions.d.ts",
203
- "browser": "./dist/browser/preference-dimensions.js",
204
195
  "bun": "./dist/preference-dimensions.js",
205
196
  "node": "./dist/node/preference-dimensions.js",
206
197
  "default": "./dist/preference-dimensions.js"
207
198
  },
208
199
  "./store": {
209
200
  "types": "./dist/store.d.ts",
210
- "browser": "./dist/browser/store.js",
211
201
  "bun": "./dist/store.js",
212
202
  "node": "./dist/node/store.js",
213
203
  "default": "./dist/store.js"
214
204
  },
215
205
  "./tracker": {
216
206
  "types": "./dist/tracker.d.ts",
217
- "browser": "./dist/browser/tracker.js",
218
207
  "bun": "./dist/tracker.js",
219
208
  "node": "./dist/node/tracker.js",
220
209
  "default": "./dist/tracker.js"
221
210
  },
222
211
  "./types": {
223
212
  "types": "./dist/types.d.ts",
224
- "browser": "./dist/browser/types.js",
225
213
  "bun": "./dist/types.js",
226
214
  "node": "./dist/node/types.js",
227
215
  "default": "./dist/types.js"
@@ -1 +0,0 @@
1
- function o(t,e){let r=[];if(t.suggestedHiddenFields.forEach((i)=>{r.push({type:"hideField",field:i,reason:"Automatically hidden because usage is near zero"})}),t.frequentlyUsedFields.length)r.push({type:"reorderFields",fields:t.frequentlyUsedFields});if(!r.length)return null;return{overlayId:e.overlayId,version:e.version??"1.0.0",appliesTo:{tenantId:e.tenantId,capability:e.capability,userId:e.userId,role:e.role},modifications:r,metadata:{generatedAt:new Date().toISOString(),automated:!0}}}function n(t){return t.workflowBottlenecks.map((e)=>({workflow:e.workflow,step:e.step,note:`High drop rate (${Math.round(e.dropRate*100)}%) detected`}))}export{n as insightsToWorkflowAdaptations,o as insightsToOverlaySuggestion};
@@ -1 +0,0 @@
1
- class h{store;options;constructor(e,t={}){this.store=e;this.options=t}async analyze(e){let t={tenantId:e.tenantId,userId:e.userId,role:e.role};if(e.windowMs)t.since=Date.now()-e.windowMs;let i=await this.store.summarize(t);return y(i,this.options)}}function y(e,t){let i=t.fieldInactivityThreshold??3,d=t.minSamples??10,a=[],u=[];for(let[o,r]of Object.entries(e.fieldCounts)){if(r<=i)a.push(o);if(r>=i*4)u.push(o)}let c=Object.entries(e.workflowStepCounts).flatMap(([o,r])=>{let s=Object.values(r).reduce((n,l)=>n+l,0);if(!s||s<d)return[];return Object.entries(r).filter(([,n])=>n/s<0.4).map(([n,l])=>({workflow:o,step:n,dropRate:1-l/s}))}),f=m(e);return{unusedFields:a,suggestedHiddenFields:a.slice(0,5),frequentlyUsedFields:u.slice(0,10),workflowBottlenecks:c,layoutPreference:f}}function m(e){let t=Object.keys(e.fieldCounts).length;if(!t)return;if(t>=15)return"table";if(t>=8)return"grid";return"form"}export{h as BehaviorAnalyzer};
@@ -1,80 +0,0 @@
1
- import{registerDocBlocks as d}from"@contractspec/lib.contracts-spec/docs";var f=[{id:"docs.personalization.behavior-tracking",title:"Behavior Tracking",summary:"`@contractspec/lib.personalization` provides primitives to observe how tenants/users interact with specs and turn that telemetry into personalization insights.",kind:"reference",visibility:"public",route:"/docs/personalization/behavior-tracking",tags:["personalization","behavior-tracking"],body:`# Behavior Tracking
2
-
3
- \`@contractspec/lib.personalization\` provides primitives to observe how tenants/users interact with specs and turn that telemetry into personalization insights.
4
-
5
- ## Tracker
6
-
7
- \`\`\`ts
8
- import { createBehaviorTracker } from '@contractspec/lib.personalization';
9
- import { InMemoryBehaviorStore } from '@contractspec/lib.personalization/store';
10
-
11
- const tracker = createBehaviorTracker({
12
- store: new InMemoryBehaviorStore(),
13
- context: { tenantId: ctx.tenant.id, userId: ctx.identity.userId },
14
- autoFlushIntervalMs: 5000,
15
- });
16
-
17
- tracker.trackFieldAccess({ operation: 'billing.createOrder', field: 'internalNotes' });
18
- tracker.trackFeatureUsage({ feature: 'workflow-editor', action: 'opened' });
19
- tracker.trackWorkflowStep({ workflow: 'invoice-approval', step: 'review', status: 'entered' });
20
- \`\`\`
21
-
22
- All events are buffered and flushed either when the buffer hits 25 entries or when \`autoFlushIntervalMs\` elapses. Tracked metrics flow to OpenTelemetry via the meter/counter built into the tracker.
23
-
24
- ## Analyzer
25
-
26
- \`\`\`ts
27
- import { BehaviorAnalyzer } from '@contractspec/lib.personalization/analyzer';
28
-
29
- const analyzer = new BehaviorAnalyzer(store, { fieldInactivityThreshold: 2 });
30
- const insights = await analyzer.analyze({ tenantId: 'acme', userId: 'manager-42', windowMs: 7 * 24 * 60 * 60 * 1000 });
31
-
32
- /*
33
- {
34
- unusedFields: ['internalNotes'],
35
- suggestedHiddenFields: ['internalNotes'],
36
- frequentlyUsedFields: ['customerReference', 'items'],
37
- workflowBottlenecks: [{ workflow: 'invoice-approval', step: 'finance-review', dropRate: 0.6 }],
38
- layoutPreference: 'table'
39
- }
40
- */
41
- \`\`\`
42
-
43
- Use the analyzer output with the overlay adapter to generate suggestions automatically.
44
-
45
- ## Adapter
46
-
47
- \`\`\`ts
48
- import { insightsToOverlaySuggestion } from '@contractspec/lib.personalization/adapter';
49
-
50
- const overlay = insightsToOverlaySuggestion(insights, {
51
- overlayId: 'acme-order-form',
52
- tenantId: 'acme',
53
- capability: 'billing.createOrder',
54
- });
55
- \`\`\`
56
-
57
- When the adapter returns an overlay spec, pass it to the overlay engine to register or sign it.
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
- `}];d(f);export{f as personalization_behavior_tracking_DocBlocks};
@@ -1,212 +0,0 @@
1
- import{registerDocBlocks as m}from"@contractspec/lib.contracts-spec/docs";var d=[{id:"docs.personalization.behavior-tracking",title:"Behavior Tracking",summary:"`@contractspec/lib.personalization` provides primitives to observe how tenants/users interact with specs and turn that telemetry into personalization insights.",kind:"reference",visibility:"public",route:"/docs/personalization/behavior-tracking",tags:["personalization","behavior-tracking"],body:`# Behavior Tracking
2
-
3
- \`@contractspec/lib.personalization\` provides primitives to observe how tenants/users interact with specs and turn that telemetry into personalization insights.
4
-
5
- ## Tracker
6
-
7
- \`\`\`ts
8
- import { createBehaviorTracker } from '@contractspec/lib.personalization';
9
- import { InMemoryBehaviorStore } from '@contractspec/lib.personalization/store';
10
-
11
- const tracker = createBehaviorTracker({
12
- store: new InMemoryBehaviorStore(),
13
- context: { tenantId: ctx.tenant.id, userId: ctx.identity.userId },
14
- autoFlushIntervalMs: 5000,
15
- });
16
-
17
- tracker.trackFieldAccess({ operation: 'billing.createOrder', field: 'internalNotes' });
18
- tracker.trackFeatureUsage({ feature: 'workflow-editor', action: 'opened' });
19
- tracker.trackWorkflowStep({ workflow: 'invoice-approval', step: 'review', status: 'entered' });
20
- \`\`\`
21
-
22
- All events are buffered and flushed either when the buffer hits 25 entries or when \`autoFlushIntervalMs\` elapses. Tracked metrics flow to OpenTelemetry via the meter/counter built into the tracker.
23
-
24
- ## Analyzer
25
-
26
- \`\`\`ts
27
- import { BehaviorAnalyzer } from '@contractspec/lib.personalization/analyzer';
28
-
29
- const analyzer = new BehaviorAnalyzer(store, { fieldInactivityThreshold: 2 });
30
- const insights = await analyzer.analyze({ tenantId: 'acme', userId: 'manager-42', windowMs: 7 * 24 * 60 * 60 * 1000 });
31
-
32
- /*
33
- {
34
- unusedFields: ['internalNotes'],
35
- suggestedHiddenFields: ['internalNotes'],
36
- frequentlyUsedFields: ['customerReference', 'items'],
37
- workflowBottlenecks: [{ workflow: 'invoice-approval', step: 'finance-review', dropRate: 0.6 }],
38
- layoutPreference: 'table'
39
- }
40
- */
41
- \`\`\`
42
-
43
- Use the analyzer output with the overlay adapter to generate suggestions automatically.
44
-
45
- ## Adapter
46
-
47
- \`\`\`ts
48
- import { insightsToOverlaySuggestion } from '@contractspec/lib.personalization/adapter';
49
-
50
- const overlay = insightsToOverlaySuggestion(insights, {
51
- overlayId: 'acme-order-form',
52
- tenantId: 'acme',
53
- capability: 'billing.createOrder',
54
- });
55
- \`\`\`
56
-
57
- When the adapter returns an overlay spec, pass it to the overlay engine to register or sign it.
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
- `}];m(d);import{registerDocBlocks as j}from"@contractspec/lib.contracts-spec/docs";var q=[{id:"docs.personalization.overlay-engine",title:"Overlay Engine",summary:"`@contractspec/lib.overlay-engine` is the canonical runtime for OverlaySpecs. It validates specs, tracks scope precedence, and exposes hooks for React renderers.",kind:"reference",visibility:"public",route:"/docs/personalization/overlay-engine",tags:["personalization","overlay-engine"],body:`# Overlay Engine
81
-
82
- \`@contractspec/lib.overlay-engine\` is the canonical runtime for OverlaySpecs. It validates specs, tracks scope precedence, and exposes hooks for React renderers.
83
-
84
- ## Key APIs
85
-
86
- - \`defineOverlay(spec)\` – helper to keep specs typed.
87
- - \`OverlayRegistry\` – register signed overlays and retrieve them per context.
88
- - \`OverlayEngine\` – apply overlays to renderable targets, emit audit events, and merge modifications deterministically.
89
- - \`signOverlay(spec, privateKey)\` – Ed25519/RSA-PSS signer.
90
- - \`verifyOverlaySignature(overlay)\` – verify public key signatures.
91
- - \`useOverlay(engine, params)\` – client hook that returns \`{ target, overlaysApplied }\`.
92
-
93
- ## Scope Precedence
94
-
95
- Registrations are sorted by specificity:
96
-
97
- 1. Tenant overlays
98
- 2. Role overlays
99
- 3. User overlays
100
- 4. Device overlays
101
-
102
- Less specific overlays run first; more specific overlays override later.
103
-
104
- ## Example
105
-
106
- \`\`\`ts
107
- const registry = new OverlayRegistry();
108
- const engine = new OverlayEngine({
109
- registry,
110
- audit: (event) => auditLogService.record(event),
111
- });
112
-
113
- const overlay = defineOverlay({
114
- overlayId: 'acme-order-form',
115
- version: '1.0.0',
116
- appliesTo: {
117
- capability: 'billing.createOrder',
118
- tenantId: 'acme',
119
- },
120
- modifications: [
121
- { type: 'hideField', field: 'internalNotes' },
122
- { type: 'renameLabel', field: 'customerReference', newLabel: 'PO Number' },
123
- ],
124
- });
125
-
126
- const signedOverlay = await signOverlay(overlay, privateKeyPem);
127
- registry.register(signedOverlay);
128
-
129
- const result = engine.apply({
130
- target: { fields: baseFields },
131
- capability: 'billing.createOrder',
132
- tenantId: 'acme',
133
- userId: 'manager-7',
134
- });
135
- \`\`\`
136
-
137
- \`result.target.fields\` now carries the hidden and renamed outputs ready for rendering.
138
-
139
-
140
-
141
-
142
-
143
-
144
-
145
-
146
-
147
-
148
-
149
-
150
-
151
-
152
-
153
-
154
-
155
-
156
-
157
-
158
-
159
-
160
- `}];j(q);import{registerDocBlocks as u}from"@contractspec/lib.contracts-spec/docs";var x=[{id:"docs.personalization.workflow-composition",title:"Workflow Composition",summary:"`@contractspec/lib.workflow-composer` composes base WorkflowSpecs with tenant/role/device-specific extensions, strict validation, deterministic merge ordering, metadata/annotation overlays, and orphan-graph protection for hidden-step rewrites.",kind:"reference",visibility:"public",route:"/docs/personalization/workflow-composition",tags:["personalization","workflow-composition"],body:`# Workflow Composition
161
-
162
- \`@contractspec/lib.workflow-composer\` composes base WorkflowSpecs with tenant/role/device-specific extensions.
163
-
164
- ## Extensions
165
-
166
- \`\`\`ts
167
- import { WorkflowComposer } from '@contractspec/lib.workflow-composer';
168
- import { approvalStepTemplate } from '@contractspec/lib.workflow-composer/templates';
169
-
170
- const composer = new WorkflowComposer();
171
-
172
- composer.register({
173
- workflow: 'billing.invoiceApproval',
174
- tenantId: 'acme',
175
- priority: 10,
176
- customSteps: [
177
- {
178
- after: 'validate-invoice',
179
- inject: approvalStepTemplate({
180
- id: 'acme-legal-review',
181
- label: 'Legal Review (ACME)',
182
- description: 'Tenant-specific compliance step.',
183
- }),
184
- transitionFrom: 'validate-invoice',
185
- transitionTo: 'final-approval',
186
- },
187
- ],
188
- hiddenSteps: ['internal-audit'],
189
- metadata: { rollout: 'tenant-acme' },
190
- });
191
- \`\`\`
192
-
193
- ## Compose
194
-
195
- \`\`\`ts
196
- const runtimeSpec = composer.compose({
197
- base: BaseInvoiceWorkflow,
198
- tenantId: 'acme',
199
- });
200
-
201
- workflowRunner.execute(runtimeSpec, ctx);
202
- \`\`\`
203
-
204
- ## Guarantees
205
-
206
- - Extensions are normalized in deterministic priority order before composition.
207
- - Duplicate injected step ids, invalid anchors, and invalid transition endpoints are rejected early.
208
- - Hidden-step rewrites are validated so remaining steps stay reachable from the workflow entry step.
209
- - \`metadata\` and \`annotations\` overlays are merged into the composed runtime workflow for downstream observability and rollout tracing.
210
-
211
- This keeps tenant overlays additive, auditable, and replay-safe.
212
- `}];u(x);
@@ -1,81 +0,0 @@
1
- import{registerDocBlocks as b}from"@contractspec/lib.contracts-spec/docs";var d=[{id:"docs.personalization.overlay-engine",title:"Overlay Engine",summary:"`@contractspec/lib.overlay-engine` is the canonical runtime for OverlaySpecs. It validates specs, tracks scope precedence, and exposes hooks for React renderers.",kind:"reference",visibility:"public",route:"/docs/personalization/overlay-engine",tags:["personalization","overlay-engine"],body:`# Overlay Engine
2
-
3
- \`@contractspec/lib.overlay-engine\` is the canonical runtime for OverlaySpecs. It validates specs, tracks scope precedence, and exposes hooks for React renderers.
4
-
5
- ## Key APIs
6
-
7
- - \`defineOverlay(spec)\` – helper to keep specs typed.
8
- - \`OverlayRegistry\` – register signed overlays and retrieve them per context.
9
- - \`OverlayEngine\` – apply overlays to renderable targets, emit audit events, and merge modifications deterministically.
10
- - \`signOverlay(spec, privateKey)\` – Ed25519/RSA-PSS signer.
11
- - \`verifyOverlaySignature(overlay)\` – verify public key signatures.
12
- - \`useOverlay(engine, params)\` – client hook that returns \`{ target, overlaysApplied }\`.
13
-
14
- ## Scope Precedence
15
-
16
- Registrations are sorted by specificity:
17
-
18
- 1. Tenant overlays
19
- 2. Role overlays
20
- 3. User overlays
21
- 4. Device overlays
22
-
23
- Less specific overlays run first; more specific overlays override later.
24
-
25
- ## Example
26
-
27
- \`\`\`ts
28
- const registry = new OverlayRegistry();
29
- const engine = new OverlayEngine({
30
- registry,
31
- audit: (event) => auditLogService.record(event),
32
- });
33
-
34
- const overlay = defineOverlay({
35
- overlayId: 'acme-order-form',
36
- version: '1.0.0',
37
- appliesTo: {
38
- capability: 'billing.createOrder',
39
- tenantId: 'acme',
40
- },
41
- modifications: [
42
- { type: 'hideField', field: 'internalNotes' },
43
- { type: 'renameLabel', field: 'customerReference', newLabel: 'PO Number' },
44
- ],
45
- });
46
-
47
- const signedOverlay = await signOverlay(overlay, privateKeyPem);
48
- registry.register(signedOverlay);
49
-
50
- const result = engine.apply({
51
- target: { fields: baseFields },
52
- capability: 'billing.createOrder',
53
- tenantId: 'acme',
54
- userId: 'manager-7',
55
- });
56
- \`\`\`
57
-
58
- \`result.target.fields\` now carries the hidden and renamed outputs ready for rendering.
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
81
- `}];b(d);export{d as personalization_overlay_engine_DocBlocks};
@@ -1,53 +0,0 @@
1
- import{registerDocBlocks as b}from"@contractspec/lib.contracts-spec/docs";var d=[{id:"docs.personalization.workflow-composition",title:"Workflow Composition",summary:"`@contractspec/lib.workflow-composer` composes base WorkflowSpecs with tenant/role/device-specific extensions, strict validation, deterministic merge ordering, metadata/annotation overlays, and orphan-graph protection for hidden-step rewrites.",kind:"reference",visibility:"public",route:"/docs/personalization/workflow-composition",tags:["personalization","workflow-composition"],body:`# Workflow Composition
2
-
3
- \`@contractspec/lib.workflow-composer\` composes base WorkflowSpecs with tenant/role/device-specific extensions.
4
-
5
- ## Extensions
6
-
7
- \`\`\`ts
8
- import { WorkflowComposer } from '@contractspec/lib.workflow-composer';
9
- import { approvalStepTemplate } from '@contractspec/lib.workflow-composer/templates';
10
-
11
- const composer = new WorkflowComposer();
12
-
13
- composer.register({
14
- workflow: 'billing.invoiceApproval',
15
- tenantId: 'acme',
16
- priority: 10,
17
- customSteps: [
18
- {
19
- after: 'validate-invoice',
20
- inject: approvalStepTemplate({
21
- id: 'acme-legal-review',
22
- label: 'Legal Review (ACME)',
23
- description: 'Tenant-specific compliance step.',
24
- }),
25
- transitionFrom: 'validate-invoice',
26
- transitionTo: 'final-approval',
27
- },
28
- ],
29
- hiddenSteps: ['internal-audit'],
30
- metadata: { rollout: 'tenant-acme' },
31
- });
32
- \`\`\`
33
-
34
- ## Compose
35
-
36
- \`\`\`ts
37
- const runtimeSpec = composer.compose({
38
- base: BaseInvoiceWorkflow,
39
- tenantId: 'acme',
40
- });
41
-
42
- workflowRunner.execute(runtimeSpec, ctx);
43
- \`\`\`
44
-
45
- ## Guarantees
46
-
47
- - Extensions are normalized in deterministic priority order before composition.
48
- - Duplicate injected step ids, invalid anchors, and invalid transition endpoints are rejected early.
49
- - Hidden-step rewrites are validated so remaining steps stay reachable from the workflow entry step.
50
- - \`metadata\` and \`annotations\` overlays are merged into the composed runtime workflow for downstream observability and rollout tracing.
51
-
52
- This keeps tenant overlays additive, auditable, and replay-safe.
53
- `}];b(d);export{d as personalization_workflow_composition_DocBlocks};