@datashow/super-visual-contracts 0.0.0-stage → 0.1.0-rc.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.
package/package.json CHANGED
@@ -1,6 +1,32 @@
1
1
  {
2
2
  "name": "@datashow/super-visual-contracts",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0-rc.0",
4
+ "description": "Versioned schemas and loaders for Super Visual project contracts.",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": "./src/index.mjs",
8
+ "./schemas/*": "./schemas/*"
9
+ },
10
+ "files": [
11
+ "src",
12
+ "schemas"
13
+ ],
14
+ "license": "Apache-2.0",
15
+ "engines": {
16
+ "node": ">=22.12.0"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://github.com/Datashow-Pty-Ltd/super-visual.git",
21
+ "directory": "packages/contracts"
22
+ },
23
+ "homepage": "https://github.com/Datashow-Pty-Ltd/super-visual#readme",
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "dependencies": {
28
+ "ajv": "8.20.0",
29
+ "ajv-formats": "3.0.1",
30
+ "yaml": "2.9.1"
31
+ }
32
+ }
@@ -0,0 +1,122 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://supervisual.dev/contracts/claude-dashboard-bundle.v1.schema.json",
4
+ "title": "Super Visual Claude Dashboard intake bundle",
5
+ "description": "A documented Super Visual interchange format for Claude-style dashboard source. It is not an Anthropic export standard.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["contractVersion", "format", "name", "entry", "datasets", "routes"],
9
+ "properties": {
10
+ "contractVersion": { "type": "integer", "const": 1 },
11
+ "format": { "type": "string", "const": "claude-dashboard-bundle" },
12
+ "name": { "type": "string", "pattern": "^[a-z0-9]+(?:[._-][a-z0-9]+)*$" },
13
+ "title": { "type": "string", "minLength": 1 },
14
+ "entry": {
15
+ "type": "object",
16
+ "additionalProperties": false,
17
+ "required": ["html", "css", "script"],
18
+ "properties": {
19
+ "html": { "$ref": "#/$defs/safePath" },
20
+ "css": { "$ref": "#/$defs/safePath" },
21
+ "script": { "$ref": "#/$defs/safePath" }
22
+ }
23
+ },
24
+ "datasets": {
25
+ "type": "array",
26
+ "minItems": 1,
27
+ "uniqueItems": true,
28
+ "items": {
29
+ "type": "object",
30
+ "additionalProperties": false,
31
+ "required": ["id", "dimensions", "measures"],
32
+ "properties": {
33
+ "id": { "$ref": "#/$defs/id" },
34
+ "dimensions": {
35
+ "type": "array",
36
+ "minItems": 1,
37
+ "maxItems": 6,
38
+ "items": {
39
+ "type": "object",
40
+ "additionalProperties": false,
41
+ "required": ["column", "dimensionIndex"],
42
+ "properties": {
43
+ "column": { "type": "string", "minLength": 1 },
44
+ "dimensionIndex": { "type": "integer", "minimum": 0, "maximum": 5 },
45
+ "use": { "enum": ["key", "label"] },
46
+ "valueType": { "enum": ["string", "number"] }
47
+ }
48
+ }
49
+ },
50
+ "measures": {
51
+ "type": "array",
52
+ "minItems": 1,
53
+ "maxItems": 6,
54
+ "items": {
55
+ "type": "object",
56
+ "additionalProperties": false,
57
+ "required": ["column", "seriesKey"],
58
+ "properties": {
59
+ "column": { "type": "string", "minLength": 1 },
60
+ "seriesKey": { "type": "string", "minLength": 1 }
61
+ }
62
+ }
63
+ },
64
+ "includeAxisKeyAs": { "type": "string", "minLength": 1 },
65
+ "includeLabelAs": { "type": "string", "minLength": 1 }
66
+ }
67
+ }
68
+ },
69
+ "routes": {
70
+ "type": "array",
71
+ "minItems": 1,
72
+ "items": {
73
+ "type": "object",
74
+ "additionalProperties": false,
75
+ "required": ["id", "title", "datasets"],
76
+ "properties": {
77
+ "id": { "$ref": "#/$defs/id" },
78
+ "title": { "type": "string", "minLength": 1 },
79
+ "datasets": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/id" } }
80
+ }
81
+ }
82
+ },
83
+ "defaultParams": {
84
+ "type": "object",
85
+ "additionalProperties": {
86
+ "anyOf": [
87
+ { "type": ["string", "number", "boolean", "null"] },
88
+ { "type": "array", "items": { "type": ["string", "number", "boolean", "null"] } }
89
+ ]
90
+ }
91
+ },
92
+ "parameters": {
93
+ "type": "array",
94
+ "items": {
95
+ "type": "object",
96
+ "additionalProperties": false,
97
+ "required": ["name", "target"],
98
+ "properties": {
99
+ "name": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]*$" },
100
+ "target": { "type": "string", "pattern": "^.+\\[[^\\]]+\\]$" },
101
+ "values": {
102
+ "type": "object",
103
+ "additionalProperties": { "type": ["string", "number", "boolean"] }
104
+ }
105
+ }
106
+ }
107
+ },
108
+ "assets": {
109
+ "type": "array",
110
+ "uniqueItems": true,
111
+ "items": { "$ref": "#/$defs/safePath" }
112
+ }
113
+ },
114
+ "$defs": {
115
+ "id": { "type": "string", "pattern": "^[a-z0-9]+(?:[._-][a-z0-9]+)*$" },
116
+ "safePath": {
117
+ "type": "string",
118
+ "minLength": 1,
119
+ "not": { "pattern": "^(?:/|[A-Za-z]:|.*(?:^|/)\\.\\.(?:/|$))" }
120
+ }
121
+ }
122
+ }
@@ -0,0 +1,86 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://supervisual.dev/contracts/live-certification-record.schema.json",
4
+ "title": "Super Visual live certification record",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["contractVersion", "kind", "recordedAt", "commit", "operator", "environment", "workspace", "plan", "items", "connectionId", "cli", "browser", "evidence"],
8
+ "properties": {
9
+ "contractVersion": { "type": "integer", "const": 1 },
10
+ "kind": { "const": "super-visual-live-certification" },
11
+ "recordedAt": { "type": "string", "format": "date-time" },
12
+ "commit": { "type": "string", "pattern": "^[0-9a-f]{40}$" },
13
+ "operator": { "type": "string", "minLength": 1 },
14
+ "environment": { "enum": ["disposable-sandbox", "controlled-test"] },
15
+ "workspace": {
16
+ "type": "object",
17
+ "additionalProperties": false,
18
+ "required": ["id", "displayName"],
19
+ "properties": { "id": { "type": "string", "minLength": 1 }, "displayName": { "type": "string", "minLength": 1 } }
20
+ },
21
+ "plan": {
22
+ "type": "object",
23
+ "additionalProperties": false,
24
+ "required": ["id", "operations"],
25
+ "properties": {
26
+ "id": { "type": "string", "pattern": "^[0-9a-f]{20}$" },
27
+ "operations": { "type": "array", "minItems": 1, "items": { "enum": ["create", "update", "restore"] } }
28
+ }
29
+ },
30
+ "items": {
31
+ "type": "object",
32
+ "additionalProperties": false,
33
+ "required": ["semanticModelId", "reportId"],
34
+ "properties": { "semanticModelId": { "type": "string", "minLength": 1 }, "reportId": { "type": "string", "minLength": 1 } }
35
+ },
36
+ "connectionId": { "type": "string", "minLength": 1 },
37
+ "cli": {
38
+ "type": "object",
39
+ "additionalProperties": false,
40
+ "required": ["status", "connectionBinding", "reportBinding", "refresh", "acceptance"],
41
+ "properties": {
42
+ "status": { "enum": ["accepted", "published-unverified", "restored-unverified", "failed"] },
43
+ "connectionBinding": { "type": "boolean" },
44
+ "reportBinding": { "type": "boolean" },
45
+ "refresh": { "type": "string" },
46
+ "acceptance": {
47
+ "type": "object",
48
+ "additionalProperties": false,
49
+ "required": ["rowCount", "columnCount", "nonNull"],
50
+ "properties": {
51
+ "rowCount": { "type": "integer", "minimum": 0 },
52
+ "columnCount": { "type": "integer", "minimum": 0 },
53
+ "nonNull": { "type": "boolean" }
54
+ }
55
+ }
56
+ }
57
+ },
58
+ "browser": {
59
+ "type": "object",
60
+ "additionalProperties": false,
61
+ "required": ["reportOpens", "visualRenders", "labelsAndValues", "keyboardNavigation", "selectionInteraction", "noUnexpectedErrors"],
62
+ "properties": {
63
+ "reportOpens": { "type": "boolean" },
64
+ "visualRenders": { "type": "boolean" },
65
+ "labelsAndValues": { "type": "boolean" },
66
+ "keyboardNavigation": { "type": "boolean" },
67
+ "selectionInteraction": { "type": "boolean" },
68
+ "noUnexpectedErrors": { "type": "boolean" }
69
+ }
70
+ },
71
+ "evidence": {
72
+ "type": "array",
73
+ "items": {
74
+ "type": "object",
75
+ "additionalProperties": false,
76
+ "required": ["kind", "reference", "sha256"],
77
+ "properties": {
78
+ "kind": { "enum": ["receipt", "screenshot", "trace", "attestation"] },
79
+ "reference": { "type": "string", "minLength": 1 },
80
+ "sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" }
81
+ }
82
+ }
83
+ },
84
+ "notes": { "type": "string" }
85
+ }
86
+ }
@@ -0,0 +1,273 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://llm-power-bi.local/contracts/page-set.v2.schema.json",
4
+ "title": "Declarative analytical application page set",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["contractVersion", "shell", "pages", "interactions", "designRationale"],
8
+ "properties": {
9
+ "contractVersion": { "type": "integer", "const": 1 },
10
+ "shell": {
11
+ "type": "object",
12
+ "additionalProperties": false,
13
+ "required": ["id", "title", "defaultPage", "designSystem", "acceptedConcept", "governanceLabel", "locale", "currencyCode", "filterContext", "navigation", "theme"],
14
+ "properties": {
15
+ "id": { "type": "string", "pattern": "^[a-z][a-z0-9-]*$" },
16
+ "title": { "type": "string", "minLength": 1 },
17
+ "defaultPage": { "type": "string", "minLength": 1 },
18
+ "designSystem": {
19
+ "type": "object",
20
+ "additionalProperties": false,
21
+ "required": ["id", "sha256"],
22
+ "properties": {
23
+ "id": { "type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$" },
24
+ "sha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" }
25
+ }
26
+ },
27
+ "acceptedConcept": {
28
+ "type": "object",
29
+ "additionalProperties": false,
30
+ "required": ["id"],
31
+ "properties": {
32
+ "id": { "type": "string", "pattern": "^[a-z0-9]+(?:[._-][a-z0-9]+)*$" }
33
+ }
34
+ },
35
+ "governanceLabel": { "type": "string", "minLength": 1 },
36
+ "locale": { "type": "string", "minLength": 2 },
37
+ "currencyCode": { "type": "string", "pattern": "^$|^[A-Z]{3}$" },
38
+ "filterContext": { "type": "array", "items": { "$ref": "#/$defs/filterContext" } },
39
+ "navigation": {
40
+ "type": "array",
41
+ "minItems": 1,
42
+ "items": {
43
+ "type": "object",
44
+ "additionalProperties": false,
45
+ "required": ["page", "label"],
46
+ "properties": {
47
+ "page": { "type": "string", "minLength": 1 },
48
+ "label": { "type": "string", "minLength": 1 }
49
+ }
50
+ }
51
+ },
52
+ "theme": { "$ref": "#/$defs/theme" }
53
+ }
54
+ },
55
+ "pages": {
56
+ "type": "array",
57
+ "minItems": 1,
58
+ "items": {
59
+ "type": "object",
60
+ "additionalProperties": false,
61
+ "required": ["id", "title", "eyebrow", "summary", "search", "kpis", "widgets"],
62
+ "properties": {
63
+ "id": { "type": "string", "pattern": "^[a-z0-9]+(?:[._-][a-z0-9]+)*$" },
64
+ "title": { "type": "string", "minLength": 1 },
65
+ "eyebrow": { "type": "string", "minLength": 1 },
66
+ "summary": {
67
+ "type": "object",
68
+ "additionalProperties": false,
69
+ "required": ["headline", "body", "emphasisBinding"],
70
+ "properties": {
71
+ "headline": { "type": "string", "minLength": 1 },
72
+ "body": { "type": "string", "minLength": 1 },
73
+ "emphasisBinding": { "anyOf": [{ "$ref": "#/$defs/binding" }, { "type": "null" }] }
74
+ }
75
+ },
76
+ "search": {
77
+ "anyOf": [
78
+ {
79
+ "type": "object",
80
+ "additionalProperties": false,
81
+ "required": ["placeholder", "dataset", "filterTarget"],
82
+ "properties": {
83
+ "placeholder": { "type": "string", "minLength": 1 },
84
+ "dataset": { "$ref": "#/$defs/dataset" },
85
+ "filterTarget": { "type": "string", "minLength": 1 }
86
+ }
87
+ },
88
+ { "type": "null" }
89
+ ]
90
+ },
91
+ "kpis": {
92
+ "type": "array",
93
+ "maxItems": 5,
94
+ "items": {
95
+ "type": "object",
96
+ "additionalProperties": false,
97
+ "required": ["id", "conceptRegionId", "label", "binding", "reportWidgetIds", "businessQuestionIds", "format", "comparison"],
98
+ "properties": {
99
+ "id": { "type": "string", "minLength": 1 },
100
+ "conceptRegionId": { "$ref": "#/$defs/dataset" },
101
+ "label": { "type": "string", "minLength": 1 },
102
+ "binding": { "$ref": "#/$defs/binding" },
103
+ "reportWidgetIds": {
104
+ "type": "array",
105
+ "minItems": 1,
106
+ "items": { "$ref": "#/$defs/dataset" }
107
+ },
108
+ "businessQuestionIds": {
109
+ "type": "array",
110
+ "minItems": 1,
111
+ "items": { "$ref": "#/$defs/dataset" }
112
+ },
113
+ "format": { "type": "string", "enum": ["currency-compact", "number", "percent", "text"] },
114
+ "comparison": { "type": ["string", "null"] }
115
+ }
116
+ }
117
+ },
118
+ "widgets": {
119
+ "type": "array",
120
+ "minItems": 1,
121
+ "items": {
122
+ "type": "object",
123
+ "additionalProperties": false,
124
+ "required": ["id", "conceptRegionId", "primitive", "title", "subtitle", "dataset", "reportWidgetIds", "businessQuestionIds", "layout", "settings"],
125
+ "properties": {
126
+ "id": { "type": "string", "minLength": 1 },
127
+ "conceptRegionId": { "$ref": "#/$defs/dataset" },
128
+ "primitive": { "type": "string", "enum": ["line", "bar", "pie", "tree", "ranked-table", "small-multiples", "ticker", "sankey", "kpi-ledger"] },
129
+ "title": { "type": "string", "minLength": 1 },
130
+ "subtitle": { "type": ["string", "null"] },
131
+ "dataset": { "$ref": "#/$defs/dataset" },
132
+ "reportWidgetIds": {
133
+ "type": "array",
134
+ "minItems": 1,
135
+ "items": { "$ref": "#/$defs/dataset" }
136
+ },
137
+ "businessQuestionIds": {
138
+ "type": "array",
139
+ "minItems": 1,
140
+ "items": { "$ref": "#/$defs/dataset" }
141
+ },
142
+ "layout": {
143
+ "type": "object",
144
+ "additionalProperties": false,
145
+ "required": ["columns", "minHeight"],
146
+ "properties": {
147
+ "columns": { "type": "integer", "minimum": 3, "maximum": 12 },
148
+ "minHeight": { "type": "integer", "minimum": 180, "maximum": 900 }
149
+ }
150
+ },
151
+ "settings": {
152
+ "type": "object",
153
+ "additionalProperties": false,
154
+ "required": ["orientation", "curve", "showLegend", "showLabels", "sort", "limit", "emphasis"],
155
+ "properties": {
156
+ "orientation": { "type": ["string", "null"], "enum": ["horizontal", "vertical", null] },
157
+ "curve": { "type": ["string", "null"], "enum": ["linear", "monotoneX", "step", null] },
158
+ "showLegend": { "type": ["boolean", "null"] },
159
+ "showLabels": { "type": ["boolean", "null"] },
160
+ "sort": { "type": ["string", "null"], "enum": ["ascending", "descending", "none", null] },
161
+ "limit": { "type": ["integer", "null"], "minimum": 1, "maximum": 100 },
162
+ "emphasis": { "type": ["string", "null"], "enum": ["area", "line", "bars", "nodes", null] }
163
+ }
164
+ }
165
+ }
166
+ }
167
+ }
168
+ }
169
+ }
170
+ },
171
+ "interactions": {
172
+ "type": "array",
173
+ "items": {
174
+ "type": "object",
175
+ "additionalProperties": false,
176
+ "required": ["source", "action", "target", "invalidates"],
177
+ "properties": {
178
+ "source": { "type": "string", "minLength": 1 },
179
+ "action": { "type": "string", "const": "filter" },
180
+ "target": { "$ref": "#/$defs/dataset" },
181
+ "invalidates": { "type": "array", "items": { "$ref": "#/$defs/dataset" } }
182
+ }
183
+ }
184
+ },
185
+ "designRationale": {
186
+ "type": "object",
187
+ "additionalProperties": false,
188
+ "required": ["narrative", "decisions", "accessibility", "risks"],
189
+ "properties": {
190
+ "narrative": { "type": "string", "minLength": 1 },
191
+ "decisions": { "type": "array", "minItems": 1, "items": { "type": "string", "minLength": 1 } },
192
+ "accessibility": { "type": "array", "minItems": 1, "items": { "type": "string", "minLength": 1 } },
193
+ "risks": { "type": "array", "items": { "type": "string", "minLength": 1 } }
194
+ }
195
+ }
196
+ },
197
+ "$defs": {
198
+ "color": { "type": "string", "pattern": "^#[0-9A-Fa-f]{6}$" },
199
+ "theme": {
200
+ "type": "object",
201
+ "additionalProperties": false,
202
+ "required": ["background", "surface", "quietSurface", "text", "mutedText", "metadata", "rule", "accent", "attention", "positive", "negative", "context", "dataColors", "displayFont", "bodyFont", "contentWidth", "layoutColumns", "layoutGap", "cardRadius", "cardPadding", "kpiTopAccent", "grid", "density", "typography"],
203
+ "properties": {
204
+ "background": { "$ref": "#/$defs/color" },
205
+ "surface": { "$ref": "#/$defs/color" },
206
+ "quietSurface": { "$ref": "#/$defs/color" },
207
+ "text": { "$ref": "#/$defs/color" },
208
+ "mutedText": { "$ref": "#/$defs/color" },
209
+ "metadata": { "$ref": "#/$defs/color" },
210
+ "rule": { "$ref": "#/$defs/color" },
211
+ "grid": { "$ref": "#/$defs/color" },
212
+ "accent": { "$ref": "#/$defs/color" },
213
+ "attention": { "$ref": "#/$defs/color" },
214
+ "positive": { "$ref": "#/$defs/color" },
215
+ "negative": { "$ref": "#/$defs/color" },
216
+ "context": { "type": "array", "minItems": 2, "maxItems": 4, "items": { "$ref": "#/$defs/color" } },
217
+ "dataColors": { "type": "array", "minItems": 3, "maxItems": 8, "items": { "$ref": "#/$defs/color" } },
218
+ "displayFont": { "type": "string", "minLength": 1 },
219
+ "bodyFont": { "type": "string", "minLength": 1 },
220
+ "contentWidth": {
221
+ "type": ["integer", "string"],
222
+ "description": "A pixel width or valid CSS width expression."
223
+ },
224
+ "layoutColumns": { "type": "integer", "minimum": 1, "maximum": 24 },
225
+ "layoutGap": { "type": "integer", "minimum": 0, "maximum": 64 },
226
+ "cardRadius": { "type": "number", "minimum": 0, "maximum": 32 },
227
+ "cardPadding": { "type": "array", "minItems": 4, "maxItems": 4, "items": { "type": "integer", "minimum": 0, "maximum": 64 } },
228
+ "kpiTopAccent": { "type": "integer", "minimum": 0, "maximum": 16 },
229
+ "density": { "type": "string", "enum": ["compact", "comfortable"] },
230
+ "typography": {
231
+ "type": "object",
232
+ "additionalProperties": false,
233
+ "required": ["findingMin", "findingMax", "sectionTitle", "kpiValue", "body", "chart", "table", "metadata"],
234
+ "properties": {
235
+ "findingMin": { "type": "integer", "minimum": 32, "maximum": 56 },
236
+ "findingMax": { "type": "integer", "minimum": 44, "maximum": 80 },
237
+ "sectionTitle": { "type": "integer", "minimum": 18, "maximum": 28 },
238
+ "kpiValue": { "type": "integer", "minimum": 26, "maximum": 44 },
239
+ "body": { "type": "integer", "minimum": 13, "maximum": 18 },
240
+ "chart": { "type": "integer", "minimum": 11, "maximum": 16 },
241
+ "table": { "type": "integer", "minimum": 12, "maximum": 16 },
242
+ "metadata": { "type": "integer", "minimum": 10, "maximum": 14 }
243
+ }
244
+ }
245
+ }
246
+ },
247
+ "dataset": { "type": "string", "pattern": "^[a-z0-9]+(?:[._-][a-z0-9]+)*$" },
248
+ "filterContext": {
249
+ "type": "object",
250
+ "additionalProperties": false,
251
+ "required": ["target", "label", "mode", "required", "visible", "defaultValue", "reason"],
252
+ "properties": {
253
+ "target": { "type": "string", "pattern": "^.+\\[[^\\]]+\\]$" },
254
+ "label": { "type": "string", "minLength": 1 },
255
+ "mode": { "type": "string", "const": "single-select" },
256
+ "required": { "type": "boolean" },
257
+ "visible": { "type": "boolean" },
258
+ "defaultValue": { "type": ["string", "number", "boolean", "null"] },
259
+ "reason": { "type": "string", "minLength": 1 }
260
+ }
261
+ },
262
+ "binding": {
263
+ "type": "object",
264
+ "additionalProperties": false,
265
+ "required": ["dataset", "field", "aggregation"],
266
+ "properties": {
267
+ "dataset": { "$ref": "#/$defs/dataset" },
268
+ "field": { "type": "string", "minLength": 1 },
269
+ "aggregation": { "anyOf": [{ "type": "string", "enum": ["sum", "average", "count", "distinct-count", "derived"] }, { "type": "null" }] }
270
+ }
271
+ }
272
+ }
273
+ }
@@ -0,0 +1,159 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://llm-power-bi.local/contracts/report-app.schema.json",
4
+ "title": "Datashow report application",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["contractVersion", "application", "routes", "interactions", "implementation"],
8
+ "properties": {
9
+ "contractVersion": { "type": "integer", "const": 1 },
10
+ "application": {
11
+ "type": "object",
12
+ "additionalProperties": false,
13
+ "required": ["id", "title", "defaultRoute", "designSystem", "governanceLabel", "locale", "currencyCode", "filterContext", "navigation"],
14
+ "properties": {
15
+ "id": { "type": "string", "pattern": "^[a-z][a-z0-9-]*$" },
16
+ "title": { "type": "string", "minLength": 1 },
17
+ "defaultRoute": { "type": "string", "minLength": 1 },
18
+ "designSystem": {
19
+ "type": "object",
20
+ "additionalProperties": false,
21
+ "required": ["id", "sha256"],
22
+ "properties": {
23
+ "id": { "type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$" },
24
+ "sha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" }
25
+ }
26
+ },
27
+ "governanceLabel": { "type": "string", "minLength": 1 },
28
+ "locale": { "type": "string", "minLength": 2 },
29
+ "currencyCode": { "type": "string", "pattern": "^$|^[A-Z]{3}$" },
30
+ "filterContext": {
31
+ "type": "array",
32
+ "items": { "$ref": "#/$defs/filterContext" }
33
+ },
34
+ "navigation": {
35
+ "type": "array", "minItems": 1,
36
+ "items": {
37
+ "type": "object", "additionalProperties": false, "required": ["id", "label"],
38
+ "properties": { "id": { "type": "string" }, "label": { "type": "string", "minLength": 1 } }
39
+ }
40
+ }
41
+ }
42
+ },
43
+ "routes": {
44
+ "type": "array", "minItems": 1,
45
+ "items": {
46
+ "type": "object", "additionalProperties": false,
47
+ "required": ["id", "title", "eyebrow", "summary", "search", "kpis", "sections"],
48
+ "properties": {
49
+ "id": { "type": "string", "pattern": "^[a-z][a-z0-9-]*$" },
50
+ "title": { "type": "string", "minLength": 1 },
51
+ "eyebrow": { "type": "string", "minLength": 1 },
52
+ "summary": {
53
+ "type": "object", "additionalProperties": false, "required": ["headline", "body", "emphasisBinding"],
54
+ "properties": {
55
+ "headline": { "type": "string", "minLength": 1 },
56
+ "body": { "type": "string", "minLength": 1 },
57
+ "emphasisBinding": {
58
+ "anyOf": [
59
+ { "$ref": "#/$defs/binding" },
60
+ { "type": "null" }
61
+ ]
62
+ }
63
+ }
64
+ },
65
+ "search": {
66
+ "anyOf": [
67
+ {
68
+ "type": "object", "additionalProperties": false,
69
+ "required": ["enabled", "placeholder", "dataset", "filterTarget", "placement"],
70
+ "properties": {
71
+ "enabled": { "type": "boolean" }, "placeholder": { "type": "string", "minLength": 1 },
72
+ "dataset": { "$ref": "#/$defs/dataset" }, "filterTarget": { "type": "string", "minLength": 1 },
73
+ "placement": { "type": "string", "const": "top-right" }
74
+ }
75
+ },
76
+ { "type": "null" }
77
+ ]
78
+ },
79
+ "kpis": {
80
+ "type": "array",
81
+ "maxItems": 5,
82
+ "items": {
83
+ "type": "object", "additionalProperties": false, "required": ["id", "label", "binding", "format", "comparison"],
84
+ "properties": {
85
+ "id": { "type": "string" }, "label": { "type": "string" }, "binding": { "$ref": "#/$defs/binding" },
86
+ "format": { "type": "string", "enum": ["currency-compact", "number", "percent", "text"] },
87
+ "comparison": { "type": ["string", "null"] }
88
+ }
89
+ }
90
+ },
91
+ "sections": {
92
+ "type": "array", "minItems": 1,
93
+ "items": {
94
+ "type": "object", "additionalProperties": false,
95
+ "required": ["id", "component", "title", "subtitle", "dataset", "size", "settings"],
96
+ "properties": {
97
+ "id": { "type": "string" },
98
+ "component": { "type": "string", "enum": ["line", "bar", "pie", "treegraph", "ranked-table", "small-multiples", "ticker", "live-search", "sankey", "kpi-ledger"] },
99
+ "title": { "type": "string" }, "subtitle": { "type": ["string", "null"] }, "dataset": { "$ref": "#/$defs/dataset" },
100
+ "size": { "type": "string", "enum": ["compact", "standard", "wide", "full", "continuation"] },
101
+ "settings": {
102
+ "anyOf": [
103
+ { "type": "object", "additionalProperties": false, "properties": {}, "required": [] },
104
+ { "type": "null" }
105
+ ]
106
+ }
107
+ }
108
+ }
109
+ }
110
+ }
111
+ }
112
+ },
113
+ "interactions": {
114
+ "type": "array",
115
+ "items": {
116
+ "type": "object", "additionalProperties": false, "required": ["source", "action", "target", "invalidates"],
117
+ "properties": {
118
+ "source": { "type": "string" }, "action": { "type": "string", "const": "filter" }, "target": { "$ref": "#/$defs/dataset" },
119
+ "invalidates": { "type": "array", "items": { "$ref": "#/$defs/dataset" } }
120
+ }
121
+ }
122
+ },
123
+ "implementation": {
124
+ "type": "object", "additionalProperties": false, "required": ["mode", "sourceContract"],
125
+ "properties": {
126
+ "mode": { "type": "string", "const": "generated-react-source" },
127
+ "sourceContract": { "type": "string", "const": "report-source.v1" }
128
+ }
129
+ }
130
+ },
131
+ "$defs": {
132
+ "dataset": { "type": "string", "pattern": "^[a-z0-9]+(?:[._-][a-z0-9]+)*$" },
133
+ "filterContext": {
134
+ "type": "object", "additionalProperties": false,
135
+ "required": ["target", "label", "mode", "required", "visible", "defaultValue", "reason"],
136
+ "properties": {
137
+ "target": { "type": "string", "pattern": "^.+\\[[^\\]]+\\]$" },
138
+ "label": { "type": "string", "minLength": 1 },
139
+ "mode": { "type": "string", "const": "single-select" },
140
+ "required": { "type": "boolean" },
141
+ "visible": { "type": "boolean" },
142
+ "defaultValue": { "type": ["string", "number", "boolean", "null"] },
143
+ "reason": { "type": "string", "minLength": 1 }
144
+ }
145
+ },
146
+ "binding": {
147
+ "type": "object", "additionalProperties": false, "required": ["dataset", "field", "aggregation"],
148
+ "properties": {
149
+ "dataset": { "$ref": "#/$defs/dataset" }, "field": { "type": "string", "minLength": 1 },
150
+ "aggregation": {
151
+ "anyOf": [
152
+ { "type": "string", "enum": ["sum", "average", "count", "distinct-count", "derived"] },
153
+ { "type": "null" }
154
+ ]
155
+ }
156
+ }
157
+ }
158
+ }
159
+ }
@@ -0,0 +1,124 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://llm-power-bi.local/contracts/report-source-bundle.v2.schema.json",
4
+ "title": "High-fidelity React report source bundle",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["contractVersion", "designSystem", "acceptedConcept", "entry", "files", "routes", "bindings", "designRationale"],
8
+ "properties": {
9
+ "contractVersion": { "type": "integer", "const": 1 },
10
+ "designSystem": {
11
+ "type": "object",
12
+ "additionalProperties": false,
13
+ "required": ["id", "sha256"],
14
+ "properties": {
15
+ "id": { "type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$" },
16
+ "sha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" }
17
+ }
18
+ },
19
+ "acceptedConcept": {
20
+ "type": "object",
21
+ "additionalProperties": false,
22
+ "required": ["id"],
23
+ "properties": {
24
+ "id": { "type": "string", "pattern": "^[a-z0-9]+(?:[._-][a-z0-9]+)*$" }
25
+ }
26
+ },
27
+ "entry": { "type": "string", "const": "src/reportApplication.tsx" },
28
+ "files": {
29
+ "type": "array",
30
+ "minItems": 2,
31
+ "maxItems": 24,
32
+ "items": {
33
+ "type": "object",
34
+ "additionalProperties": false,
35
+ "required": ["path", "content"],
36
+ "properties": {
37
+ "path": { "type": "string", "pattern": "^(src/reportApplication\\.tsx|src/report/[A-Za-z0-9._/-]+\\.(tsx|ts)|style/report-design\\.less)$" },
38
+ "content": { "type": "string", "minLength": 1 }
39
+ }
40
+ }
41
+ },
42
+ "routes": {
43
+ "type": "array",
44
+ "minItems": 1,
45
+ "items": {
46
+ "type": "object",
47
+ "additionalProperties": false,
48
+ "required": ["id", "title", "datasets", "businessQuestionIds"],
49
+ "properties": {
50
+ "id": { "type": "string", "pattern": "^[a-z0-9]+(?:[._-][a-z0-9]+)*$" },
51
+ "title": { "type": "string", "minLength": 1 },
52
+ "datasets": { "type": "array", "minItems": 1, "items": { "type": "string", "pattern": "^[a-z0-9]+(?:[._-][a-z0-9]+)*$" } },
53
+ "businessQuestionIds": { "type": "array", "minItems": 1, "items": { "type": "string", "minLength": 1 } }
54
+ }
55
+ }
56
+ },
57
+ "bindings": {
58
+ "type": "array",
59
+ "minItems": 1,
60
+ "items": {
61
+ "type": "object",
62
+ "additionalProperties": false,
63
+ "required": ["dataset", "component", "reportWidgetIds", "businessQuestionIds"],
64
+ "properties": {
65
+ "dataset": { "type": "string", "pattern": "^[a-z0-9]+(?:[._-][a-z0-9]+)*$" },
66
+ "component": { "type": "string", "minLength": 1 },
67
+ "reportWidgetIds": { "type": "array", "minItems": 1, "items": { "type": "string", "minLength": 1 } },
68
+ "businessQuestionIds": { "type": "array", "minItems": 1, "items": { "type": "string", "minLength": 1 } }
69
+ }
70
+ }
71
+ },
72
+ "adapter": {
73
+ "type": "object",
74
+ "additionalProperties": false,
75
+ "required": ["kind", "contractVersion", "source", "dashApis", "assets", "parameters"],
76
+ "properties": {
77
+ "kind": { "type": "string", "const": "claude-dashboard" },
78
+ "contractVersion": { "type": "integer", "const": 1 },
79
+ "source": { "type": "string", "const": "supervisual-claude-dashboard-bundle.v1" },
80
+ "dashApis": { "type": "array", "uniqueItems": true, "items": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9.]*$" } },
81
+ "assets": {
82
+ "type": "array",
83
+ "items": {
84
+ "type": "object",
85
+ "additionalProperties": false,
86
+ "required": ["path", "sha256", "mediaType", "bytes"],
87
+ "properties": {
88
+ "path": { "type": "string", "minLength": 1 },
89
+ "sha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
90
+ "mediaType": { "type": "string", "minLength": 3 },
91
+ "bytes": { "type": "integer", "minimum": 0 }
92
+ }
93
+ }
94
+ },
95
+ "parameters": {
96
+ "type": "array",
97
+ "items": {
98
+ "type": "object",
99
+ "additionalProperties": false,
100
+ "required": ["name", "target"],
101
+ "properties": {
102
+ "name": { "type": "string", "minLength": 1 },
103
+ "target": { "type": "string", "pattern": "^.+\\[[^\\]]+\\]$" },
104
+ "values": { "type": "object", "additionalProperties": { "type": ["string", "number", "boolean"] } }
105
+ }
106
+ }
107
+ }
108
+ }
109
+ },
110
+ "designRationale": {
111
+ "type": "object",
112
+ "additionalProperties": false,
113
+ "required": ["direction", "pageCompositions", "dataVisualisation", "responsiveBehaviour", "accessibility", "risks"],
114
+ "properties": {
115
+ "direction": { "type": "string", "minLength": 1 },
116
+ "pageCompositions": { "type": "array", "minItems": 1, "items": { "type": "string", "minLength": 1 } },
117
+ "dataVisualisation": { "type": "array", "minItems": 1, "items": { "type": "string", "minLength": 1 } },
118
+ "responsiveBehaviour": { "type": "array", "minItems": 1, "items": { "type": "string", "minLength": 1 } },
119
+ "accessibility": { "type": "array", "minItems": 1, "items": { "type": "string", "minLength": 1 } },
120
+ "risks": { "type": "array", "items": { "type": "string", "minLength": 1 } }
121
+ }
122
+ }
123
+ }
124
+ }
@@ -0,0 +1,82 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://supervisual.dev/contracts/project.schema.json",
4
+ "title": "Super Visual project",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["contractVersion", "application", "target", "semantic", "source", "output"],
8
+ "properties": {
9
+ "contractVersion": { "type": "integer", "const": 1 },
10
+ "application": {
11
+ "type": "object",
12
+ "additionalProperties": false,
13
+ "required": ["id", "title", "entry", "style"],
14
+ "properties": {
15
+ "id": { "type": "string", "pattern": "^[a-z][a-z0-9-]*$" },
16
+ "title": { "type": "string", "minLength": 1 },
17
+ "entry": { "$ref": "#/$defs/safePath" },
18
+ "style": { "$ref": "#/$defs/safePath" }
19
+ }
20
+ },
21
+ "target": {
22
+ "type": "object",
23
+ "additionalProperties": false,
24
+ "required": ["platform", "visual"],
25
+ "properties": {
26
+ "platform": { "const": "powerbi" },
27
+ "visual": {
28
+ "type": "object",
29
+ "additionalProperties": false,
30
+ "required": ["name", "displayName", "guid", "version", "apiVersion"],
31
+ "properties": {
32
+ "name": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9]+$" },
33
+ "displayName": { "type": "string", "minLength": 1 },
34
+ "guid": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9]+$" },
35
+ "version": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+$" },
36
+ "apiVersion": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$" }
37
+ }
38
+ }
39
+ }
40
+ },
41
+ "semantic": {
42
+ "type": "object",
43
+ "additionalProperties": false,
44
+ "required": ["model", "broker", "pageSet"],
45
+ "properties": {
46
+ "model": { "$ref": "#/$defs/safePath" },
47
+ "broker": { "$ref": "#/$defs/safePath" },
48
+ "pageSet": { "$ref": "#/$defs/safePath" }
49
+ }
50
+ },
51
+ "source": {
52
+ "type": "object",
53
+ "additionalProperties": false,
54
+ "required": ["bundle"],
55
+ "properties": { "bundle": { "$ref": "#/$defs/safePath" } }
56
+ },
57
+ "output": {
58
+ "type": "object",
59
+ "additionalProperties": false,
60
+ "required": ["directory"],
61
+ "properties": { "directory": { "$ref": "#/$defs/safePath" } }
62
+ },
63
+ "compliance": {
64
+ "type": "object",
65
+ "additionalProperties": false,
66
+ "properties": {
67
+ "policies": {
68
+ "type": "array",
69
+ "items": { "enum": ["core", "powerbi", "powerbi-certified"] },
70
+ "uniqueItems": true
71
+ }
72
+ }
73
+ }
74
+ },
75
+ "$defs": {
76
+ "safePath": {
77
+ "type": "string",
78
+ "minLength": 1,
79
+ "not": { "pattern": "^(?:/|[A-Za-z]:|.*(?:^|/)\\.\\.(?:/|$))" }
80
+ }
81
+ }
82
+ }
@@ -0,0 +1,89 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://llm-power-bi.local/contracts/widget-broker.schema.json",
4
+ "title": "Report-specific widget broker contract",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["contractVersion", "summary", "adapterMode", "baseModelMutation", "dataView", "widgets", "cachePolicy", "risks"],
8
+ "properties": {
9
+ "contractVersion": { "type": "integer", "const": 1 },
10
+ "summary": { "type": "string", "minLength": 1 },
11
+ "adapterMode": { "type": "string", "const": "source-direct-import" },
12
+ "baseModelMutation": { "type": "boolean", "const": false },
13
+ "dataView": {
14
+ "type": "object",
15
+ "additionalProperties": false,
16
+ "required": ["mapping", "fields", "discriminator"],
17
+ "properties": {
18
+ "mapping": { "type": "string", "const": "table" },
19
+ "discriminator": { "type": "string", "const": "WidgetId" },
20
+ "fields": {
21
+ "type": "array",
22
+ "items": { "type": "string", "enum": ["WidgetId", "AxisKey", "Label", "Sort", "SeriesKey", "SeriesLabel", "WidgetValue", "BrokerContext"] },
23
+ "minItems": 8,
24
+ "maxItems": 8
25
+ }
26
+ }
27
+ },
28
+ "widgets": {
29
+ "type": "array",
30
+ "minItems": 1,
31
+ "items": {
32
+ "type": "object",
33
+ "additionalProperties": false,
34
+ "required": ["id", "title", "reportWidgetIds", "businessQuestionIds", "shape", "dimensions", "axis", "measures", "rowLimit", "rowSelection", "selectable", "invalidates"],
35
+ "properties": {
36
+ "id": { "type": "string", "pattern": "^[a-z0-9]+(?:[._-][a-z0-9]+)*$" },
37
+ "title": { "type": "string", "minLength": 1 },
38
+ "reportWidgetIds": {
39
+ "type": "array",
40
+ "minItems": 1,
41
+ "items": { "type": "string", "pattern": "^[a-z0-9]+(?:[._-][a-z0-9]+)*$" }
42
+ },
43
+ "businessQuestionIds": {
44
+ "type": "array",
45
+ "minItems": 1,
46
+ "items": { "type": "string", "pattern": "^[a-z0-9]+(?:[._-][a-z0-9]+)*$" }
47
+ },
48
+ "shape": { "type": "string", "enum": ["categorical", "series", "hierarchy", "flow"] },
49
+ "dimensions": {
50
+ "type": "array",
51
+ "items": {
52
+ "type": "object",
53
+ "additionalProperties": false,
54
+ "required": ["key", "label"],
55
+ "properties": {
56
+ "key": { "type": "string", "pattern": "^.+\\[[^\\]]+\\]$" },
57
+ "label": { "type": "string", "pattern": "^.+\\[[^\\]]+\\]$" }
58
+ }
59
+ },
60
+ "minItems": 1,
61
+ "maxItems": 6
62
+ },
63
+ "axis": { "type": "string", "pattern": "^.+\\[[^\\]]+\\]$" },
64
+ "measures": {
65
+ "type": "array",
66
+ "minItems": 1,
67
+ "maxItems": 6,
68
+ "items": { "type": "string", "pattern": "^(?:\\[[^\\],]+\\]|[^\\[\\],]+\\[[^\\],]+\\])$" }
69
+ },
70
+ "rowLimit": { "type": "integer", "minimum": 1, "maximum": 250 },
71
+ "rowSelection": { "enum": ["top-by-value", "bottom-by-value", "first-by-axis", "last-by-axis"] },
72
+ "selectable": { "type": "boolean" },
73
+ "invalidates": { "type": "array", "items": { "type": "string", "pattern": "^[a-z0-9]+(?:[._-][a-z0-9]+)*$" } }
74
+ }
75
+ }
76
+ },
77
+ "cachePolicy": {
78
+ "type": "object",
79
+ "additionalProperties": false,
80
+ "required": ["retainSourceWidget", "cancelStaleRequests", "externalFilterInvalidation"],
81
+ "properties": {
82
+ "retainSourceWidget": { "type": "boolean", "const": true },
83
+ "cancelStaleRequests": { "type": "boolean", "const": true },
84
+ "externalFilterInvalidation": { "type": "string", "const": "all-dependent-widgets" }
85
+ }
86
+ },
87
+ "risks": { "type": "array", "items": { "type": "string", "minLength": 1 } }
88
+ }
89
+ }
package/src/index.mjs ADDED
@@ -0,0 +1,139 @@
1
+ import { createHash } from "node:crypto";
2
+ import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import Ajv2020 from "ajv/dist/2020.js";
6
+ import addFormats from "ajv-formats";
7
+ import YAML from "yaml";
8
+
9
+ const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
10
+ const schemaNames = ["supervisual-project", "report-app", "page-set", "widget-broker", "report-source-bundle", "claude-dashboard-bundle", "live-certification-record"];
11
+ const ajv = new Ajv2020({ allErrors: true, strict: false });
12
+ addFormats(ajv);
13
+
14
+ const validators = new Map();
15
+ for (const name of schemaNames) {
16
+ const schema = JSON.parse(await readFile(path.join(packageRoot, "schemas", `${name}.schema.json`), "utf8"));
17
+ validators.set(name, ajv.compile(schema));
18
+ }
19
+
20
+ export function validateContract(name, value) {
21
+ const validate = validators.get(name);
22
+ if (!validate) throw new Error(`Unknown Super Visual contract ${name}`);
23
+ const ok = validate(value);
24
+ return {
25
+ ok: Boolean(ok),
26
+ errors: (validate.errors ?? []).map((error) => ({
27
+ path: error.instancePath || "/",
28
+ keyword: error.keyword,
29
+ message: error.message ?? "invalid value",
30
+ })),
31
+ };
32
+ }
33
+
34
+ export async function loadContract(name, filePath) {
35
+ const source = await readFile(filePath, "utf8");
36
+ const value = filePath.endsWith(".json") ? JSON.parse(source) : YAML.parse(source);
37
+ const result = validateContract(name, value);
38
+ if (!result.ok) {
39
+ throw new Error(`${name} contract is invalid:\n${result.errors.map((error) => `- ${error.path} ${error.message}`).join("\n")}`);
40
+ }
41
+ return value;
42
+ }
43
+
44
+ async function readStructured(filePath) {
45
+ const source = await readFile(filePath, "utf8");
46
+ return { source, value: filePath.endsWith(".json") ? JSON.parse(source) : YAML.parse(source) };
47
+ }
48
+
49
+ async function writeStructuredAtomic(filePath, value) {
50
+ const temporary = `${filePath}.supervisual-migrate.tmp`;
51
+ const source = filePath.endsWith(".json")
52
+ ? `${JSON.stringify(value, null, 2)}\n`
53
+ : YAML.stringify(value);
54
+ await writeFile(temporary, source, { flag: "wx" });
55
+ await rename(temporary, filePath);
56
+ }
57
+
58
+ /**
59
+ * Inspect or migrate source contracts without touching disposable generated output.
60
+ * The initial migration adds the v1 marker to legacy unversioned widget brokers.
61
+ */
62
+ export async function migrateProjectContracts(projectFile, { write = false, backupDirectory } = {}) {
63
+ const absoluteProject = path.resolve(projectFile);
64
+ const root = path.dirname(absoluteProject);
65
+ const projectDocument = await readStructured(absoluteProject);
66
+ const projectValidation = validateContract("supervisual-project", projectDocument.value);
67
+ if (!projectValidation.ok) {
68
+ throw new Error(`supervisual-project contract is invalid and cannot be migrated safely:\n${projectValidation.errors.map((error) => `- ${error.path} ${error.message}`).join("\n")}`);
69
+ }
70
+ const descriptors = [
71
+ { contract: "supervisual-project", file: absoluteProject, allowLegacyBroker: false },
72
+ { contract: "semantic-model", file: resolveProjectPath(root, projectDocument.value.semantic.model), allowLegacyBroker: false },
73
+ { contract: "widget-broker", file: resolveProjectPath(root, projectDocument.value.semantic.broker), allowLegacyBroker: true },
74
+ { contract: "page-set", file: resolveProjectPath(root, projectDocument.value.semantic.pageSet), allowLegacyBroker: false },
75
+ { contract: "report-source-bundle", file: resolveProjectPath(root, projectDocument.value.source.bundle), allowLegacyBroker: false },
76
+ ];
77
+ const documents = [];
78
+ const migrations = [];
79
+ for (const descriptor of descriptors) {
80
+ const document = descriptor.file === absoluteProject ? projectDocument : await readStructured(descriptor.file);
81
+ const version = document.value?.contractVersion;
82
+ const relativePath = path.relative(root, descriptor.file).split(path.sep).join("/") || path.basename(descriptor.file);
83
+ if (version === 1) {
84
+ documents.push({ contract: descriptor.contract, path: relativePath, version: 1, status: "current" });
85
+ continue;
86
+ }
87
+ if (descriptor.allowLegacyBroker && version === undefined) {
88
+ const migration = { contract: descriptor.contract, path: relativePath, from: "legacy-unversioned", to: 1, changes: ["add /contractVersion = 1"] };
89
+ documents.push({ contract: descriptor.contract, path: relativePath, version: null, status: "migration-available" });
90
+ migrations.push({ ...migration, descriptor, document, migrated: { contractVersion: 1, ...document.value } });
91
+ continue;
92
+ }
93
+ throw new Error(`${descriptor.contract} ${relativePath} uses unsupported contractVersion ${JSON.stringify(version)}; this CLI only supports version 1`);
94
+ }
95
+ if (!migrations.length) return { ok: true, status: "current", dryRun: !write, currentVersion: 1, documents, migrations: [] };
96
+ const publicMigrations = migrations.map(({ contract, path: migrationPath, from, to, changes }) => ({ contract, path: migrationPath, from, to, changes }));
97
+ if (!write) return { ok: true, status: "planned", dryRun: true, currentVersion: 1, documents, migrations: publicMigrations };
98
+ const migrationId = createHash("sha256").update(JSON.stringify(migrations.map((item) => ({ path: item.path, source: item.document.source })))).digest("hex").slice(0, 16);
99
+ const backupRoot = path.resolve(backupDirectory ?? path.join(root, ".supervisual", "migrations", migrationId));
100
+ for (const migration of migrations) {
101
+ const backupFile = resolveProjectPath(backupRoot, migration.path);
102
+ await mkdir(path.dirname(backupFile), { recursive: true });
103
+ await writeFile(backupFile, migration.document.source, { flag: "wx" });
104
+ }
105
+ for (const migration of migrations) await writeStructuredAtomic(migration.descriptor.file, migration.migrated);
106
+ return { ok: true, status: "migrated", dryRun: false, currentVersion: 1, documents, migrations: publicMigrations, backupDirectory: backupRoot };
107
+ }
108
+
109
+ export function evaluateLiveCertification(record) {
110
+ const validation = validateContract("live-certification-record", record);
111
+ if (!validation.ok) return { ok: false, status: "invalid", checks: [], errors: validation.errors };
112
+ const checks = [
113
+ { id: "identity.commit", pass: !/^0+$/.test(record.commit) },
114
+ { id: "identity.plan", pass: !/^0+$/.test(record.plan.id) },
115
+ { id: "identity.operator", pass: !/^replace-/i.test(record.operator) },
116
+ { id: "cli.accepted", pass: record.cli.status === "accepted" },
117
+ { id: "binding.connection", pass: record.cli.connectionBinding === true },
118
+ { id: "binding.report", pass: record.cli.reportBinding === true },
119
+ { id: "refresh.completed", pass: record.cli.refresh === "Completed" },
120
+ { id: "acceptance.rows", pass: record.cli.acceptance.rowCount > 0 },
121
+ { id: "acceptance.columns", pass: record.cli.acceptance.columnCount > 0 },
122
+ { id: "acceptance.nonNull", pass: record.cli.acceptance.nonNull === true },
123
+ ...Object.entries(record.browser).map(([id, pass]) => ({ id: `browser.${id}`, pass: pass === true })),
124
+ { id: "evidence.receipt", pass: record.evidence.some((item) => item.kind === "receipt") },
125
+ { id: "evidence.screenshot", pass: record.evidence.some((item) => item.kind === "screenshot") },
126
+ { id: "evidence.resolved", pass: record.evidence.every((item) => !/^replace-/i.test(item.reference) && !/^0+$/.test(item.sha256)) },
127
+ ];
128
+ const ok = checks.every((check) => check.pass);
129
+ return { ok, status: ok ? "certified" : "incomplete", checks, errors: [] };
130
+ }
131
+
132
+ export function resolveProjectPath(projectRoot, relativePath) {
133
+ const resolvedRoot = path.resolve(projectRoot);
134
+ const resolved = path.resolve(resolvedRoot, relativePath);
135
+ if (resolved !== resolvedRoot && !resolved.startsWith(`${resolvedRoot}${path.sep}`)) {
136
+ throw new Error(`Project path escapes its root: ${relativePath}`);
137
+ }
138
+ return resolved;
139
+ }
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.