forked from package-url/packageurl-js
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathlockstep.schema.json
More file actions
463 lines (463 loc) · 26.2 KB
/
lockstep.schema.json
File metadata and controls
463 lines (463 loc) · 26.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://github.com/SocketDev/lockstep.schema.json",
"title": "lockstep manifest",
"description": "Unified lock-step manifest shared across Socket repos. One schema, all cases — the `kind` discriminator on each row selects which flavor of lock-step applies. Single-file manifests work for repos with one cohesive concern; the `includes[]` field carves a manifest into per-area files (e.g. lockstep-acorn.json + lockstep-build.json) when one repo tracks multiple independent concerns.",
"type": "object",
"required": ["rows"],
"properties": {
"$schema": {
"description": "JSON Schema reference for editor autocompletion. Conventionally `./lockstep.schema.json` — both the manifest and its schema live side-by-side at repo root.",
"type": "string"
},
"description": {
"description": "Human-readable description of what this manifest tracks. Read by humans, not parsed. One short paragraph.",
"type": "string"
},
"area": {
"description": "Optional label for this manifest file. Used as a grouping key in harness output (per-area summaries). Defaults to 'root' for the top-level file and to the filename stem (with the `lockstep-` prefix stripped) for included files.",
"type": "string"
},
"includes": {
"description": "Relative paths to sub-manifests. The harness loads each and merges its rows into a single flattened view. Top-level `upstreams` and `sites` maps override any same-keyed entries from included manifests (top wins on conflict).",
"type": "array",
"items": {
"type": "string"
}
},
"upstreams": {
"description": "Named upstream submodules. Each entry pairs a submodule path with its repo URL. Referenced by rows[].upstream on file-fork / version-pin / feature-parity / spec-conformance rows. Omit when the manifest only has lang-parity rows.",
"type": "object",
"patternProperties": {
"^(.*)$": {
"additionalProperties": false,
"description": "A submodule + its upstream repo URL. Referenced by file-fork / version-pin / feature-parity / spec-conformance rows via `upstream`.",
"type": "object",
"required": ["submodule", "repo"],
"properties": {
"submodule": {
"description": "Submodule path, relative to repo root. Must match an entry in `.gitmodules`.",
"type": "string"
},
"repo": {
"pattern": "^https?://[^/\\s]+",
"description": "Upstream repository URL (http:// or https:// + host). Anchored at the host so empty URLs fail validation rather than failing at git-fetch time.",
"type": "string"
}
}
}
}
},
"sites": {
"description": "Named sibling ports (typically per-language: `cpp`, `go`, `rust`, `typescript`). Referenced by rows[].ports.<site> on lang-parity rows. Omit when the manifest has no lang-parity rows.",
"type": "object",
"patternProperties": {
"^(.*)$": {
"additionalProperties": false,
"description": "A sibling port (typically per-language). Referenced by lang-parity rows via `ports.<site-key>`.",
"type": "object",
"required": ["path"],
"properties": {
"path": {
"description": "Path to the port's root directory, relative to repo root. The harness reads files under this path when checking the port's assertions.",
"type": "string"
},
"language": {
"description": "Language label for human reports (e.g. `cpp`, `go`, `rust`, `typescript`). The harness does no language-specific processing — it's purely informational.",
"type": "string"
}
}
}
}
},
"rows": {
"description": "The actual checks the harness runs. Empty array is valid (and expected for repos that have no upstream relationships — e.g. socket-cli's empty rows).",
"type": "array",
"items": {
"anyOf": [
{
"additionalProperties": false,
"description": "A local file derived from an upstream file with intentional modifications. Drift = upstream moved forward on this path; we may need to cherry-pick or update our deviations.",
"type": "object",
"required": [
"kind",
"id",
"upstream",
"local",
"upstream_path",
"forked_at_sha",
"deviations"
],
"properties": {
"kind": {
"const": "file-fork",
"type": "string"
},
"id": {
"pattern": "^[a-z0-9][a-z0-9-]*(/[A-Za-z0-9_-]+)?$",
"description": "Stable identifier, unique within the manifest. Kebab-case (lowercase letters / digits / hyphens). For ids that mirror an external API name, use a namespace prefix: `api/findNodeAt`, `node/parseURL`. The slash separates the kebab namespace from the free-form leaf.",
"type": "string"
},
"upstream": {
"description": "Key into the top-level `upstreams` map. The harness errors if no matching upstream entry exists.",
"type": "string"
},
"criticality": {
"minimum": 1,
"maximum": 10,
"description": "Stay-in-step importance. Anchors: 1 = cosmetic / nice-to-have; 5 = behavioral parity expected; 10 = security-sensitive. The harness surfaces high-criticality drift louder and gates feature-parity rows on the criticality/10 floor.",
"type": "integer"
},
"conformance_test": {
"description": "Path (relative to repo root) of a test that enforces behavior parity (modulo documented deviations). Strongly recommended — static checks catch syntactic drift, not behavioral. A row without a conformance test relies entirely on code-pattern / fixture-snapshot checks.",
"type": "string"
},
"notes": {
"description": "Free-form context: why this row exists, gotchas, links to related issues / PRs / upstream discussions. Read by humans, not by the harness.",
"type": "string"
},
"local": {
"description": "Path (relative to repo root) of our ported copy of the upstream file.",
"type": "string"
},
"upstream_path": {
"description": "Path within the upstream submodule (relative to the submodule root) of the source file we forked from.",
"type": "string"
},
"forked_at_sha": {
"pattern": "^[0-9a-f]{40}$",
"description": "Full 40-char SHA of the upstream commit we forked from. The harness runs `git log <sha>..HEAD -- <upstream_path>` inside the submodule to surface drift.",
"type": "string"
},
"deviations": {
"minItems": 1,
"description": "Human-readable list of intentional differences from upstream. Zero deviations = the file should not be forked; consume upstream directly. Each entry is one short sentence (e.g. `swap require() for import` or `remove Node 14 fallback`).",
"type": "array",
"items": {
"type": "string"
}
}
}
},
{
"additionalProperties": false,
"description": "A submodule pinned to an upstream release. Drift = upstream cut a new release we haven't adopted.",
"type": "object",
"required": [
"kind",
"id",
"upstream",
"pinned_sha",
"upgrade_policy"
],
"properties": {
"kind": {
"const": "version-pin",
"type": "string"
},
"id": {
"pattern": "^[a-z0-9][a-z0-9-]*(/[A-Za-z0-9_-]+)?$",
"description": "Stable identifier, unique within the manifest. Kebab-case (lowercase letters / digits / hyphens). For ids that mirror an external API name, use a namespace prefix: `api/findNodeAt`, `node/parseURL`. The slash separates the kebab namespace from the free-form leaf.",
"type": "string"
},
"upstream": {
"description": "Key into the top-level `upstreams` map. The harness errors if no matching upstream entry exists.",
"type": "string"
},
"criticality": {
"minimum": 1,
"maximum": 10,
"description": "Stay-in-step importance. Anchors: 1 = cosmetic / nice-to-have; 5 = behavioral parity expected; 10 = security-sensitive. The harness surfaces high-criticality drift louder and gates feature-parity rows on the criticality/10 floor.",
"type": "integer"
},
"conformance_test": {
"description": "Path (relative to repo root) of a test that enforces behavior parity (modulo documented deviations). Strongly recommended — static checks catch syntactic drift, not behavioral. A row without a conformance test relies entirely on code-pattern / fixture-snapshot checks.",
"type": "string"
},
"notes": {
"description": "Free-form context: why this row exists, gotchas, links to related issues / PRs / upstream discussions. Read by humans, not by the harness.",
"type": "string"
},
"pinned_sha": {
"pattern": "^[0-9a-f]{40}$",
"description": "Full 40-char SHA the submodule is pinned to. Authoritative — the harness compares this against the submodule HEAD, not against `pinned_tag`.",
"type": "string"
},
"pinned_tag": {
"description": "Human-readable release tag for reports / PR titles (e.g. `v3.2.1`). Informational only — `pinned_sha` is the source of truth. Useful when an upstream cuts a release without changing semver but moves the SHA.",
"type": "string"
},
"upgrade_policy": {
"description": "`track-latest` = any new release is actionable; updating-lockstep auto-bumps. `major-gate` = patch / minor auto-bump; major bumps surfaced as advisory. `locked` = explicit decision per upgrade; the harness reports drift but never auto-bumps. Pick `locked` when bumping is gated on a coordinated change in another repo (e.g. Node vendoring temporal-rs).",
"anyOf": [
{
"const": "track-latest",
"type": "string"
},
{
"const": "major-gate",
"type": "string"
},
{
"const": "locked",
"type": "string"
}
]
}
}
},
{
"additionalProperties": false,
"description": "A behavioral feature reimplemented locally to match upstream behavior. Three-pillar validation: code patterns + test patterns + fixture snapshot. The total score is averaged across present pillars; rows below the criticality / 10 floor surface as drift.",
"type": "object",
"required": ["kind", "id", "upstream", "criticality", "local_area"],
"properties": {
"kind": {
"const": "feature-parity",
"type": "string"
},
"id": {
"pattern": "^[a-z0-9][a-z0-9-]*(/[A-Za-z0-9_-]+)?$",
"description": "Stable identifier, unique within the manifest. Kebab-case (lowercase letters / digits / hyphens). For ids that mirror an external API name, use a namespace prefix: `api/findNodeAt`, `node/parseURL`. The slash separates the kebab namespace from the free-form leaf.",
"type": "string"
},
"upstream": {
"description": "Key into the top-level `upstreams` map. The harness errors if no matching upstream entry exists.",
"type": "string"
},
"criticality": {
"minimum": 1,
"maximum": 10,
"description": "Stay-in-step importance. Anchors: 1 = cosmetic / nice-to-have; 5 = behavioral parity expected; 10 = security-sensitive. The harness surfaces high-criticality drift louder and gates feature-parity rows on the criticality/10 floor.",
"type": "integer"
},
"conformance_test": {
"description": "Path (relative to repo root) of a test that enforces behavior parity (modulo documented deviations). Strongly recommended — static checks catch syntactic drift, not behavioral. A row without a conformance test relies entirely on code-pattern / fixture-snapshot checks.",
"type": "string"
},
"notes": {
"description": "Free-form context: why this row exists, gotchas, links to related issues / PRs / upstream discussions. Read by humans, not by the harness.",
"type": "string"
},
"local_area": {
"description": "Path (relative to repo root) of the local module / directory implementing the feature. The code-pattern scan targets this directory recursively, excluding test files (matched by `*.test.{ts,mts,js,mjs}` and `*.spec.*`).",
"type": "string"
},
"test_area": {
"description": "Path (relative to repo root) of the directory where tests for this feature live. When absent, the harness searches for tests inside `local_area`. Useful when tests live in a sibling directory (e.g. `local_area=src/auth`, `test_area=test/auth`).",
"type": "string"
},
"code_patterns": {
"description": "Regex patterns the local implementation must contain. Prefer anchored patterns (function signatures, exported symbols) over loose keywords to avoid matching comments. Each pattern is searched independently across `local_area`; missing patterns lower the code score.",
"type": "array",
"items": {
"type": "string"
}
},
"test_patterns": {
"description": "Regex patterns the test suite must contain. Same scoring as `code_patterns` but searched across `test_area` (or `local_area` when `test_area` is absent).",
"type": "array",
"items": {
"type": "string"
}
},
"fixture_check": {
"additionalProperties": false,
"description": "Golden-input verification. Snapshot-based diffs replace the brittle hardcoded-count checks the harness used historically (sdxgen's lock-step-features lesson).",
"type": "object",
"required": ["fixture_path"],
"properties": {
"fixture_path": {
"description": "Path (relative to repo root) of the input fixture the local implementation runs against.",
"type": "string"
},
"snapshot_path": {
"description": "Path (relative to repo root) of the snapshot file the implementation's output is diffed against. When absent, the harness only checks that the fixture is processed without error — no output comparison.",
"type": "string"
},
"diff_tolerance": {
"description": "How the snapshot diff is computed. `exact` = byte-identical; the strictest check. `line-by-line` = per-line diff after normalizing line endings (CRLF / LF); tolerates trailing-newline drift. `semantic` = harness-defined deeper comparison (typically AST or normalized JSON for output that has equivalent representations); each row kind documents what `semantic` means in its context.",
"anyOf": [
{
"const": "exact",
"type": "string"
},
{
"const": "line-by-line",
"type": "string"
},
{
"const": "semantic",
"type": "string"
}
]
}
}
}
}
},
{
"additionalProperties": false,
"description": "A local reimplementation of an external specification. Drift = the spec was revised; we may need to update our impl, the spec_version, or both.",
"type": "object",
"required": [
"kind",
"id",
"upstream",
"local_impl",
"spec_version"
],
"properties": {
"kind": {
"const": "spec-conformance",
"type": "string"
},
"id": {
"pattern": "^[a-z0-9][a-z0-9-]*(/[A-Za-z0-9_-]+)?$",
"description": "Stable identifier, unique within the manifest. Kebab-case (lowercase letters / digits / hyphens). For ids that mirror an external API name, use a namespace prefix: `api/findNodeAt`, `node/parseURL`. The slash separates the kebab namespace from the free-form leaf.",
"type": "string"
},
"upstream": {
"description": "Key into the top-level `upstreams` map. The harness errors if no matching upstream entry exists.",
"type": "string"
},
"criticality": {
"minimum": 1,
"maximum": 10,
"description": "Stay-in-step importance. Anchors: 1 = cosmetic / nice-to-have; 5 = behavioral parity expected; 10 = security-sensitive. The harness surfaces high-criticality drift louder and gates feature-parity rows on the criticality/10 floor.",
"type": "integer"
},
"conformance_test": {
"description": "Path (relative to repo root) of a test that enforces behavior parity (modulo documented deviations). Strongly recommended — static checks catch syntactic drift, not behavioral. A row without a conformance test relies entirely on code-pattern / fixture-snapshot checks.",
"type": "string"
},
"notes": {
"description": "Free-form context: why this row exists, gotchas, links to related issues / PRs / upstream discussions. Read by humans, not by the harness.",
"type": "string"
},
"local_impl": {
"description": "Path (relative to repo root) of our reimplementation of the spec. Either a file or a directory.",
"type": "string"
},
"spec_version": {
"description": "Version label of the spec we conform to (e.g. `ECMAScript-2024`, `RFC-9110`, commit SHA, or upstream tag). Free-form — the harness only checks for drift via the upstream submodule, not the version string itself.",
"type": "string"
},
"spec_path": {
"description": "Path within the upstream submodule to the spec document. Used to scope drift detection to the spec file (rather than every change in the upstream repo).",
"type": "string"
}
}
},
{
"additionalProperties": false,
"description": "N sibling language ports of one spec within a single project. Drift = a port diverged from its siblings (one implemented, others opt-out without reason / or vice versa), or a `rejected` anti-pattern was reintroduced.",
"type": "object",
"required": [
"kind",
"id",
"name",
"description",
"category",
"ports"
],
"properties": {
"kind": {
"const": "lang-parity",
"type": "string"
},
"id": {
"pattern": "^[a-z0-9][a-z0-9-]*(/[A-Za-z0-9_-]+)?$",
"description": "Stable identifier, unique within the manifest. Kebab-case (lowercase letters / digits / hyphens). For ids that mirror an external API name, use a namespace prefix: `api/findNodeAt`, `node/parseURL`. The slash separates the kebab namespace from the free-form leaf.",
"type": "string"
},
"name": {
"description": "Short human-readable label for this row (e.g. `Range parsing`, `Async iterators`). Used in report headers; not parsed.",
"type": "string"
},
"description": {
"description": "One-paragraph description of what behavior this row asserts on each port. Read by humans; not parsed.",
"type": "string"
},
"category": {
"description": "Grouping tag for report aggregation (e.g. `parser`, `runtime`, `api`). The single magic value is `rejected` — RESERVED for anti-patterns: every port MUST be `opt-out`, and any port flipping to `implemented` exits 2 ('rejected anti-pattern reintroduced'). Use freely otherwise.",
"type": "string"
},
"criticality": {
"minimum": 1,
"maximum": 10,
"description": "Stay-in-step importance. Anchors: 1 = cosmetic / nice-to-have; 5 = behavioral parity expected; 10 = security-sensitive. The harness surfaces high-criticality drift louder and gates feature-parity rows on the criticality/10 floor.",
"type": "integer"
},
"conformance_test": {
"description": "Path (relative to repo root) of a test that enforces behavior parity (modulo documented deviations). Strongly recommended — static checks catch syntactic drift, not behavioral. A row without a conformance test relies entirely on code-pattern / fixture-snapshot checks.",
"type": "string"
},
"notes": {
"description": "Free-form context: why this row exists, gotchas, links to related issues / PRs / upstream discussions. Read by humans, not by the harness.",
"type": "string"
},
"assertions": {
"description": "Assertions checked against each port. Each entry is `{kind: string, ...}`; the harness dispatches on `kind`. See AssertionSchema description for known kinds; unknown kinds skip with a log line. Mutually compatible with `matrix_files` (a row can have both, neither, or one).",
"type": "array",
"items": {
"description": "A typed assertion the lang-parity row asserts on each port. Shape: `{kind: string, ...kind-specific fields}`. The lockstep harness dispatches on `kind`; per-kind contracts are documented in the harness, not here.",
"type": "object",
"patternProperties": {
"^(.*)$": {}
}
}
},
"matrix_files": {
"description": "Paths (relative to this manifest) of `lockstep-lang-*.json` sub-manifests this row indexes. For inventory-style rows that group many smaller checks under one parent. The harness loads each and merges its rows.",
"type": "array",
"items": {
"type": "string"
}
},
"ports": {
"description": "Per-port status map. Keys MUST match top-level `sites` keys exactly — the harness errors on stray ports / missing sites. Each value is `{status: 'implemented' | 'opt-out', ...}` per PortStatusSchema.",
"type": "object",
"patternProperties": {
"^(.*)$": {
"additionalProperties": false,
"description": "Per-port status for a lang-parity row. The `ports` map on a row pairs each top-level `sites` key with one of these.",
"type": "object",
"required": ["status"],
"properties": {
"status": {
"description": "`implemented` = port meets the row's assertions; `opt-out` = port consciously skips this row (requires `reason`).",
"anyOf": [
{
"const": "implemented",
"type": "string"
},
{
"const": "opt-out",
"type": "string"
}
]
},
"reason": {
"description": "Why this port opts out. SCHEMA-CONDITIONAL: required when status is `opt-out`. The TypeBox type cannot express the conditional, but the harness rejects opt-out rows with empty / missing reason.",
"type": "string"
},
"path": {
"description": "Optional path to this port's implementation of the row. Useful for module-inventory rows where each language points at a different directory; redundant when the port's overall layout already encodes the path.",
"type": "string"
},
"note": {
"description": "Optional free-form note attached to this specific port's status. For multi-port context, prefer the row-level `notes` field.",
"type": "string"
}
}
}
}
}
}
}
]
}
}
}
}