mandrel 2.29.0 → 2.30.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.
|
@@ -106,6 +106,73 @@ function resolveBaselinePath({ cwd = process.cwd(), baselinePath } = {}) {
|
|
|
106
106
|
* rows: Array<{file: string, method: string, startLine: number, crap: number}>,
|
|
107
107
|
* }|null}
|
|
108
108
|
*/
|
|
109
|
+
/**
|
|
110
|
+
* The envelope-level fields the CRAP compat axes read off a *loaded* baseline
|
|
111
|
+
* — the set every read path owes `assertBaselineCompatible`.
|
|
112
|
+
*
|
|
113
|
+
* It exists because there are TWO read paths and they have now diverged three
|
|
114
|
+
* times. `check-baselines` loads through `baselines/reader.js`; the
|
|
115
|
+
* `quality-preview` pre-commit arm loads through `projectCrapEnvelopeToLegacy`
|
|
116
|
+
* below. Both are ALLOW-LISTS, both feed the same axes, and a stamp added to
|
|
117
|
+
* one and not the other yields two opposite verdicts on one file: Story #4866
|
|
118
|
+
* (`scoringSemantics`, `tsTranspilerVersion`), Story #4969 (`rows[].anonymous`)
|
|
119
|
+
* and Story #4986 (`provenanceStamped`, half-fixed by #4973) were each that
|
|
120
|
+
* same half-landing.
|
|
121
|
+
*
|
|
122
|
+
* Every one of those axes keys on a POSITIVE marker, so a dropped field reads
|
|
123
|
+
* `undefined` and fails the baseline closed with a remedy that cannot work —
|
|
124
|
+
* re-deriving it writes the stamp the read path then discards. The projection
|
|
125
|
+
* below is DERIVED from this list rather than repeating it, so a new stamp is
|
|
126
|
+
* carried here the moment it is named; a parity test holds the reader to the
|
|
127
|
+
* same set and names whichever path forgot one.
|
|
128
|
+
*
|
|
129
|
+
* Row-level markers are deliberately out: they are projected per-row, not as
|
|
130
|
+
* envelope stamps.
|
|
131
|
+
*
|
|
132
|
+
* Deliberately module-local, mirroring `SCORING_SEMANTICS` in
|
|
133
|
+
* `baselines/kinds/crap.js`: the writer's `envelopeExtras()` is the single
|
|
134
|
+
* production door to the stamp set, and exporting this list would add a second
|
|
135
|
+
* one that only a test reaches. The parity test holds this projection to
|
|
136
|
+
* `Object.keys(envelopeExtras())` instead, so a stamp the writer starts
|
|
137
|
+
* emitting fails the test here until it is named — which is the enforcement
|
|
138
|
+
* this list needs, not an export.
|
|
139
|
+
*/
|
|
140
|
+
const COMPAT_STAMP_FIELDS = Object.freeze([
|
|
141
|
+
'scoringSemantics',
|
|
142
|
+
'tsTranspilerVersion',
|
|
143
|
+
'provenanceStamped',
|
|
144
|
+
]);
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Per-stamp coercion applied on the way through the legacy projection. A field
|
|
148
|
+
* with no entry is carried VERBATIM, which is the correct default: the axes
|
|
149
|
+
* distinguish "stamped" from "absent", so inventing a value for a stamp the
|
|
150
|
+
* envelope never wrote is the one thing a read path must not do.
|
|
151
|
+
*/
|
|
152
|
+
const COMPAT_STAMP_NORMALIZERS = {
|
|
153
|
+
// `null` (not the running value) when unstamped, so `ts-transpiler-drift`
|
|
154
|
+
// can tell "written by a different transpiler" from "written before the
|
|
155
|
+
// stamp existed" instead of comparing a value against itself.
|
|
156
|
+
tsTranspilerVersion: (value) => (typeof value === 'string' ? value : null),
|
|
157
|
+
scoringSemantics: (value) => value ?? null,
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Project the compat stamps off a v2 envelope, driven by
|
|
162
|
+
* `COMPAT_STAMP_FIELDS`.
|
|
163
|
+
*
|
|
164
|
+
* @param {Record<string, unknown>} parsed
|
|
165
|
+
* @returns {Record<string, unknown>}
|
|
166
|
+
*/
|
|
167
|
+
function projectCompatStamps(parsed) {
|
|
168
|
+
const stamps = {};
|
|
169
|
+
for (const field of COMPAT_STAMP_FIELDS) {
|
|
170
|
+
const normalize = COMPAT_STAMP_NORMALIZERS[field];
|
|
171
|
+
stamps[field] = normalize ? normalize(parsed[field]) : parsed[field];
|
|
172
|
+
}
|
|
173
|
+
return stamps;
|
|
174
|
+
}
|
|
175
|
+
|
|
109
176
|
/**
|
|
110
177
|
* Story #1895: shipped baseline switched to the canonical envelope shape
|
|
111
178
|
* (`$schema`, `kernelVersion`, `generatedAt`, `rollup`, `rows` keyed on
|
|
@@ -122,6 +189,16 @@ function resolveBaselinePath({ cwd = process.cwd(), baselinePath } = {}) {
|
|
|
122
189
|
* They are carried verbatim now, `null` when the envelope never stamped them,
|
|
123
190
|
* so an axis can tell "written by a different transpiler" apart from "written
|
|
124
191
|
* before the stamp existed" instead of guessing.
|
|
192
|
+
*
|
|
193
|
+
* **This projection is one of TWO (Story #4986).** `check-baselines` reads a
|
|
194
|
+
* baseline through `baselines/reader.js`; `quality-preview` reads the same file
|
|
195
|
+
* through here. Both feed `assertBaselineCompatible`, so a stamp added to one
|
|
196
|
+
* allow-list and not the other produces two opposite verdicts on one envelope —
|
|
197
|
+
* which is what happened to `provenanceStamped`: #4973 added it to the reader
|
|
198
|
+
* and left this projection dropping it, so the pre-commit CRAP arm rejected
|
|
199
|
+
* every stamped baseline with an un-satisfiable "re-seed" remedy while the
|
|
200
|
+
* authoritative gate passed. The stamp block is derived from
|
|
201
|
+
* `COMPAT_STAMP_FIELDS` above so this projection cannot fall behind again.
|
|
125
202
|
*/
|
|
126
203
|
function projectCrapEnvelopeToLegacy(parsed) {
|
|
127
204
|
if (
|
|
@@ -134,11 +211,7 @@ function projectCrapEnvelopeToLegacy(parsed) {
|
|
|
134
211
|
return {
|
|
135
212
|
kernelVersion: parsed.kernelVersion,
|
|
136
213
|
escomplexVersion: resolveEscomplexVersion(),
|
|
137
|
-
|
|
138
|
-
typeof parsed.tsTranspilerVersion === 'string'
|
|
139
|
-
? parsed.tsTranspilerVersion
|
|
140
|
-
: null,
|
|
141
|
-
scoringSemantics: parsed.scoringSemantics ?? null,
|
|
214
|
+
...projectCompatStamps(parsed),
|
|
142
215
|
rows: parsed.rows.map((row) => ({
|
|
143
216
|
crap: row.crap,
|
|
144
217
|
file: row.path,
|
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.30.0](https://github.com/dsj1984/mandrel/compare/mandrel-v2.29.0...mandrel-v2.30.0) (2026-08-04)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
* **baselines:** carry provenanceStamped through the legacy CRAP projection ([#4986](https://github.com/dsj1984/mandrel/issues/4986)) ([#4987](https://github.com/dsj1984/mandrel/issues/4987)) ([921b521](https://github.com/dsj1984/mandrel/commit/921b521f2094c961fec84acca1f90e068cb77798))
|
|
24
|
+
|
|
18
25
|
## [2.29.0](https://github.com/dsj1984/mandrel/compare/mandrel-v2.28.0...mandrel-v2.29.0) (2026-08-03)
|
|
19
26
|
|
|
20
27
|
|
package/package.json
CHANGED