You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs(spec): update conformance-tests.md for FR5a envelope assertion
Documents the post-FR5a envelope shape for `expected-errors.json`:
{ errors: [{ code, source: { format, files, jsonPath } }], warnings: [] }
The "errors and warnings as sorted sets" section now describes the two-layer
comparison: order-independent code-set + ordered per-error envelope deep-equal
on `source.format`, `source.files`, `source.jsonPath`. Pre-FR5a legacy fixtures
(`[{code}]` arrays) remain accepted by every port's harness — the envelope
assertion is skipped, only the code-set runs.
The runner pseudocode is updated to show the new envelope branch.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
└── expected-warnings.json # optional: array of warning message strings
34
34
```
35
35
36
36
**Exactly one** of `expected.json` or `expected-errors.json` must be present:
37
37
-`expected.json` → the Loader is expected to succeed (no errors). The canonical serialized output of the loaded root MUST deep-equal this file. The canonical shape is the **fused-key form** documented in [`wire-format.md`](wire-format.md) — every node is `{ "<type>.<subType>": <body> }`.
38
-
-`expected-errors.json` → the Loader is expected to emit errors. It is a JSON array of objects, each `{ "code": "ERR_*" }` (a stable `ErrorCode`; message text is NOT compared — it is Tier-2 idiomatic per language). The set of emitted error **codes** MUST equal the set of `code` values in this list (compared as sorted sets — order-independent).
38
+
-`expected-errors.json` → the Loader is expected to emit errors. Post-FR5a (ADR-0009), the file is an envelope object:
Per ADR-0009, every port's harness asserts (in declaration order, per error): `code`, `source.format`, `source.files`, and `source.jsonPath`. Error *message text* is NOT compared — only the stable `ErrorCode`; message wording is Tier-2 (idiomatic per language). Other envelope fields (`suggestions`, `fixture`, `node`, `yamlPosition`) are RECOMMENDED-only and are not asserted by the cross-port harness.
57
+
58
+
The legacy `[{ "code": "ERR_*" }]` array shape remains accepted by every port's parser for backward compat (the envelope assertion is skipped, only the code-set is compared) — pre-FR5a fixtures continue to work without rewrite. The cross-port migration of the corpus to the envelope shape lands in the FR5a coordinated work.
39
59
40
60
`expected-warnings.json` is optional. When present, the set of warnings MUST equal this list. When absent on a happy-path fixture, warnings are asserted empty.
41
61
@@ -83,12 +103,16 @@ These are the **only** reserved structural keys. Everything else inside a body i
83
103
-**Children in declaration order**. The order of children inside `children: [...]` reflects authoring order, not alphabetical order. Overlay merge appends; it does NOT re-sort.
84
104
-**`@fields` normalization**. Authoring may write `"@fields": "id"` (scalar); canonical form is always the array form `"@fields": ["id"]`.
85
105
86
-
### Errors and warnings as sorted sets
106
+
### Errors and warnings: code-set + envelope-deep-equal
107
+
108
+
Errors are compared at two layers (per FR5a / ADR-0009):
109
+
110
+
1.**Code-set check** — sorted sets of `code` values from `expected-errors.json` (envelope or legacy form) vs the loader-emitted codes. Order-independent (mirrors validation-pass dispatch order quirks).
111
+
2.**Envelope assertion (envelope-shape fixtures only)** — for every error in declaration order, the harness asserts `code`, `source.format`, `source.files`, and `source.jsonPath` exactly. JSONPath is the canonical form per [ADR-0009](decisions/ADR-0009-loader-error-envelope-and-source-on-node.md) — byte-identical across ports.
112
+
113
+
Warnings remain compared as **sorted sets of message strings**. Error *message text* is never compared — only the stable `ErrorCode`; message wording is Tier-2 (idiomatic per language).
87
114
88
-
Errors are compared as **sorted sets of `code` values** (the `code` field of each
89
-
`expected-errors.json` object), and warnings as **sorted sets of message strings**, to avoid
90
-
ordering issues across validation passes. Each is sorted before comparison. Error *message text*
91
-
is never compared — only the stable `ErrorCode`; message wording is Tier-2 (idiomatic per language).
115
+
Pre-FR5a fixtures using the legacy `[{"code": "..."}]` array shape get only the code-set check; the envelope assertion is skipped.
92
116
93
117
## TS conformance runner
94
118
@@ -102,7 +126,15 @@ for each subdirectory of fixtures/conformance/:
102
126
load result = Loader().loadFromDirectory(inputDir)
0 commit comments