valent-pipeline 0.19.30 → 0.19.32
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 +1 -1
- package/src/commands/evidence.js +17 -3
- package/src/lib/crosscheck.js +20 -1
- package/src/lib/evidence.js +0 -0
package/package.json
CHANGED
package/src/commands/evidence.js
CHANGED
|
@@ -16,7 +16,7 @@ import { dirname, join, isAbsolute } from 'path';
|
|
|
16
16
|
import { randomBytes } from 'crypto';
|
|
17
17
|
import { parse as parseYaml } from 'yaml';
|
|
18
18
|
import {
|
|
19
|
-
runEvidence, pinGate, formatRunTrailer, formatRunDigest, resolveRoot, evidenceDir, latestRun, latestPins,
|
|
19
|
+
runEvidence, pinGate, formatRunTrailer, formatRunDigest, resolveRoot, evidenceDir, latestRun, resolveRunForAssert, latestPins,
|
|
20
20
|
verifyIntegrity, assertRules, assertRedRules, pinSourceDelta, snapshotFiles, buildProof, utcCompact,
|
|
21
21
|
latestAssert, collectFailingCases, authenticateBaseline, verifyShipEvidence, sha256Hex,
|
|
22
22
|
validStoryId, recordStageResults,
|
|
@@ -180,6 +180,18 @@ export async function evidenceAssertCmd(options) {
|
|
|
180
180
|
process.exit(2);
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
+
// Required acceptance case ids, read early so the run resolver can bind to the suite that actually
|
|
184
|
+
// carries them when a project multiplexes suites under one label (HARNESS-GAPS 2026-06-18 Gap 2).
|
|
185
|
+
// The full manifest is re-read below for the count/skips rules.
|
|
186
|
+
let requiredCaseIds = [];
|
|
187
|
+
try {
|
|
188
|
+
const mp = options.manifest ? abs(options.manifest) : join(root, 'stories', story, 'output', 'qa-test-spec.manifest.json');
|
|
189
|
+
if (existsSync(mp)) {
|
|
190
|
+
const m = JSON.parse(readFileSync(mp, 'utf-8'));
|
|
191
|
+
if (Array.isArray(m?.cases)) requiredCaseIds = m.cases.filter((c) => c?.kind === 'acceptance' && c?.required !== false && c?.id).map((c) => c.id);
|
|
192
|
+
}
|
|
193
|
+
} catch { requiredCaseIds = []; }
|
|
194
|
+
|
|
183
195
|
// Resolve the run: explicit --run, else the newest run for the label. Green demands a report
|
|
184
196
|
// (junit is the verdict's substance); red takes the newest run regardless — "no report at all"
|
|
185
197
|
// is itself a red-gate input (the weak-red rule judges it).
|
|
@@ -195,8 +207,10 @@ export async function evidenceAssertCmd(options) {
|
|
|
195
207
|
// No requireReport filter (review 2026-06-10 #5): a suite that crashes before emitting junit
|
|
196
208
|
// produces the NEWEST run with no reports — filtering it out silently asserted the previous
|
|
197
209
|
// (green, report-bearing) run instead. The newest run is always the one asserted; a report-less
|
|
198
|
-
// failing run now fails loudly via the green (zero cases) + run-integrity rules.
|
|
199
|
-
run
|
|
210
|
+
// failing run now fails loudly via the green (zero cases) + run-integrity rules. resolveRunForAssert
|
|
211
|
+
// additionally binds to the same-SHA run carrying the required cases when suites multiplex one label
|
|
212
|
+
// (Gap 2), preserving the report-less-crash-wins-newest invariant.
|
|
213
|
+
run = resolveRunForAssert(evDir, { label, requiredCaseIds });
|
|
200
214
|
}
|
|
201
215
|
if (!run) {
|
|
202
216
|
// --require-evidence (review 2026-06-10 #37): the graceful no-op exists for pre-evidence
|
package/src/lib/crosscheck.js
CHANGED
|
@@ -96,7 +96,26 @@ export function crosscheckVerdict({ reported = null, bugsBlock = null, assertVer
|
|
|
96
96
|
// but do not block; they are counted separately so they stay visible).
|
|
97
97
|
if (bugsBlock && Array.isArray(bugsBlock.bugs)) {
|
|
98
98
|
const isPre = (b) => b.preExisting === true || b.category === 'pre-existing';
|
|
99
|
-
|
|
99
|
+
// JUDGE severity-demotion auto-flow (HARNESS-GAPS 2026-06-18 Gap 1b; Matt 2026-06-18). JUDGE is the
|
|
100
|
+
// adjudication authority and may re-grade a bug (e.g. a test-only isolation bug P3->P4). When JUDGE
|
|
101
|
+
// EXPLICITLY carries a bug in its verdict at a LESS-blocking priority than bugs.md filed, the recount
|
|
102
|
+
// honors the adjudicated priority — the demotion is an explicit, audited decision (recorded in the
|
|
103
|
+
// verdict, the verdict-crosscheck.json, and the backlog carry). Safety is unchanged: only a CARRIED
|
|
104
|
+
// bug is re-graded, and only DOWNWARD; a bug JUDGE does not carry keeps its filed priority, so a
|
|
105
|
+
// SILENTLY-dropped open P1-P3 (the integrity breach this guards) still mismatches. A promotion is the
|
|
106
|
+
// safe over-report direction and is left as filed (the recount already tolerates JUDGE over-reporting).
|
|
107
|
+
const PRI_RANK = { P1: 1, P2: 2, P3: 3, P4: 4 };
|
|
108
|
+
const adjudicated = new Map(
|
|
109
|
+
(reported && Array.isArray(reported.bugs) ? reported.bugs : [])
|
|
110
|
+
.filter((b) => b && b.id && b.priority).map((b) => [b.id, b.priority]),
|
|
111
|
+
);
|
|
112
|
+
const effPriority = (b) => {
|
|
113
|
+
const adj = adjudicated.get(b.id);
|
|
114
|
+
return adj && (PRI_RANK[adj] ?? 99) > (PRI_RANK[b.priority] ?? 99) ? adj : b.priority;
|
|
115
|
+
};
|
|
116
|
+
const demotions = bugsBlock.bugs.filter((b) => effPriority(b) !== b.priority).map((b) => ({ id: b.id, from: b.priority, to: effPriority(b) }));
|
|
117
|
+
if (demotions.length) recounted.adjudicatedDemotions = demotions;
|
|
118
|
+
const open = bugsBlock.bugs.filter((b) => OPEN_STATUSES.has(b.status) && ['P1', 'P2', 'P3'].includes(effPriority(b)));
|
|
100
119
|
recounted.preExistingOpen = open.filter(isPre).length;
|
|
101
120
|
compare('openP1toP3', open.filter((b) => !isPre(b)).length);
|
|
102
121
|
|
package/src/lib/evidence.js
CHANGED
|
Binary file
|