mandrel 2.26.0 → 2.27.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.
|
@@ -182,6 +182,56 @@ function validate(kind, parsed, sourceHint) {
|
|
|
182
182
|
}
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
+
/**
|
|
186
|
+
* Internal: the ONE narrowing projection every loaded envelope passes through.
|
|
187
|
+
*
|
|
188
|
+
* `load` and `loadFile` reach a validated `parsed` envelope by different routes
|
|
189
|
+
* — one resolves the path from config, the other infers the kind from
|
|
190
|
+
* `$schema` — but the shape they hand back is the same narrow contract, so it
|
|
191
|
+
* is built here rather than written out at each exit.
|
|
192
|
+
*
|
|
193
|
+
* **That single-sourcing is the point, not tidiness.** The projection is an
|
|
194
|
+
* ALLOW-LIST: a field absent from it is silently dropped, and the envelope
|
|
195
|
+
* stamps below are read off the LOADED object by compat axes that fail closed
|
|
196
|
+
* when a stamp reads `undefined`. While the list was duplicated at the two
|
|
197
|
+
* exits, adding a stamp to one and not the other produced a gate that rejected
|
|
198
|
+
* every baseline in the repo for a stamp that was present on disk — which is
|
|
199
|
+
* exactly what happened to `provenanceStamped` between Story #4901 and this
|
|
200
|
+
* fix. One list means a new stamp cannot be half-added.
|
|
201
|
+
*
|
|
202
|
+
* @param {string} kind
|
|
203
|
+
* @param {object} parsed A validated baseline envelope.
|
|
204
|
+
* @returns {{ rollup: object, rows: Array<object>, kernelVersion: string, generatedAt: string }}
|
|
205
|
+
*/
|
|
206
|
+
function shapeEnvelope(kind, parsed) {
|
|
207
|
+
const rows = Array.isArray(parsed.rows)
|
|
208
|
+
? parsed.rows.map((row) => canonicaliseRow(kind, row))
|
|
209
|
+
: [];
|
|
210
|
+
return {
|
|
211
|
+
rollup: parsed.rollup ?? { '*': {} },
|
|
212
|
+
rows,
|
|
213
|
+
kernelVersion: parsed.kernelVersion,
|
|
214
|
+
generatedAt: parsed.generatedAt,
|
|
215
|
+
// Story #4775 — carry the per-kind scoring-semantics stamp through the
|
|
216
|
+
// narrowing. The gate's compat check reads it off the LOADED envelope, so
|
|
217
|
+
// dropping it here would make every baseline look unstamped and fail the
|
|
218
|
+
// whole repo closed on a stamp that is actually present on disk.
|
|
219
|
+
scoringSemantics: parsed.scoringSemantics,
|
|
220
|
+
// Story #4866 — same contract for the transpiler stamp. Dropping it here
|
|
221
|
+
// would leave the ts-transpiler compat axis reachable but blind: it would
|
|
222
|
+
// read `undefined` off every loaded envelope and pass vacuously, which is
|
|
223
|
+
// the exact deadness this Story exists to end.
|
|
224
|
+
tsTranspilerVersion: parsed.tsTranspilerVersion,
|
|
225
|
+
// Story #4901 — the coordinate-provenance marker, and the stamp that proved
|
|
226
|
+
// the warnings above were not hypothetical. Its `provenance-unstamped` axis
|
|
227
|
+
// keys on `!== true`, so while this line was missing the axis read
|
|
228
|
+
// `undefined` off every envelope and rejected each one with "baseline
|
|
229
|
+
// predates coordinate-provenance stamping" — un-satisfiable, because
|
|
230
|
+
// re-deriving the baseline writes the marker the reader then drops.
|
|
231
|
+
provenanceStamped: parsed.provenanceStamped,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
185
235
|
/**
|
|
186
236
|
* Internal: parse + validate + canonicalise. Used by both `load` and
|
|
187
237
|
* `loadFile`.
|
|
@@ -208,25 +258,7 @@ function readAndShape(kind, absolutePath) {
|
|
|
208
258
|
);
|
|
209
259
|
}
|
|
210
260
|
validate(kind, parsed, absolutePath);
|
|
211
|
-
|
|
212
|
-
? parsed.rows.map((row) => canonicaliseRow(kind, row))
|
|
213
|
-
: [];
|
|
214
|
-
return {
|
|
215
|
-
rollup: parsed.rollup ?? { '*': {} },
|
|
216
|
-
rows,
|
|
217
|
-
kernelVersion: parsed.kernelVersion,
|
|
218
|
-
generatedAt: parsed.generatedAt,
|
|
219
|
-
// Story #4775 — carry the per-kind scoring-semantics stamp through the
|
|
220
|
-
// narrowing. The gate's compat check reads it off the LOADED envelope, so
|
|
221
|
-
// dropping it here would make every baseline look unstamped and fail the
|
|
222
|
-
// whole repo closed on a stamp that is actually present on disk.
|
|
223
|
-
scoringSemantics: parsed.scoringSemantics,
|
|
224
|
-
// Story #4866 — same contract for the transpiler stamp. Dropping it here
|
|
225
|
-
// would leave the ts-transpiler compat axis reachable but blind: it would
|
|
226
|
-
// read `undefined` off every loaded envelope and pass vacuously, which is
|
|
227
|
-
// the exact deadness this Story exists to end.
|
|
228
|
-
tsTranspilerVersion: parsed.tsTranspilerVersion,
|
|
229
|
-
};
|
|
261
|
+
return shapeEnvelope(kind, parsed);
|
|
230
262
|
}
|
|
231
263
|
|
|
232
264
|
/**
|
|
@@ -306,25 +338,7 @@ export function loadFile(absolutePath, opts = {}) {
|
|
|
306
338
|
);
|
|
307
339
|
}
|
|
308
340
|
validate(kind, parsed, absolutePath);
|
|
309
|
-
|
|
310
|
-
? parsed.rows.map((row) => canonicaliseRow(kind, row))
|
|
311
|
-
: [];
|
|
312
|
-
return {
|
|
313
|
-
rollup: parsed.rollup ?? { '*': {} },
|
|
314
|
-
rows,
|
|
315
|
-
kernelVersion: parsed.kernelVersion,
|
|
316
|
-
generatedAt: parsed.generatedAt,
|
|
317
|
-
// Story #4775 — carry the per-kind scoring-semantics stamp through the
|
|
318
|
-
// narrowing. The gate's compat check reads it off the LOADED envelope, so
|
|
319
|
-
// dropping it here would make every baseline look unstamped and fail the
|
|
320
|
-
// whole repo closed on a stamp that is actually present on disk.
|
|
321
|
-
scoringSemantics: parsed.scoringSemantics,
|
|
322
|
-
// Story #4866 — same contract for the transpiler stamp. Dropping it here
|
|
323
|
-
// would leave the ts-transpiler compat axis reachable but blind: it would
|
|
324
|
-
// read `undefined` off every loaded envelope and pass vacuously, which is
|
|
325
|
-
// the exact deadness this Story exists to end.
|
|
326
|
-
tsTranspilerVersion: parsed.tsTranspilerVersion,
|
|
327
|
-
};
|
|
341
|
+
return shapeEnvelope(kind, parsed);
|
|
328
342
|
}
|
|
329
343
|
|
|
330
344
|
export const _internals = Object.freeze({
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -15,6 +15,13 @@ All notable changes to this project will be documented in this file.
|
|
|
15
15
|
-->
|
|
16
16
|
<!-- markdownlint-disable-file MD004 MD012 MD037 -->
|
|
17
17
|
|
|
18
|
+
## [2.27.0](https://github.com/dsj1984/mandrel/compare/mandrel-v2.26.0...mandrel-v2.27.0) (2026-08-03)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
* **baselines:** carry provenanceStamped through the reader's narrowing (refs [#4973](https://github.com/dsj1984/mandrel/issues/4973)) ([#4974](https://github.com/dsj1984/mandrel/issues/4974)) ([4a3795a](https://github.com/dsj1984/mandrel/commit/4a3795a2e3d60748d5b40b0288521af5a7a885ab))
|
|
24
|
+
|
|
18
25
|
## [2.26.0](https://github.com/dsj1984/mandrel/compare/mandrel-v2.25.0...mandrel-v2.26.0) (2026-08-03)
|
|
19
26
|
|
|
20
27
|
|
package/package.json
CHANGED