valent-pipeline 0.19.29 → 0.19.31
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/lib/crosscheck.js +20 -1
- package/src/lib/evidence.js +0 -0
- package/src/lib/sprint.js +15 -8
package/package.json
CHANGED
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
|
package/src/lib/sprint.js
CHANGED
|
@@ -154,14 +154,21 @@ export function packSprint(stories, velocity, opts = {}) {
|
|
|
154
154
|
const groomed = stories.filter((s) => (!scope || scope.has(s.id)) && isExecReady(s) && bugsResolvable(s));
|
|
155
155
|
const byId = new Map(groomed.map((s) => [s.id, s]));
|
|
156
156
|
|
|
157
|
-
// Out-of-batch prerequisite check (review 2026-06-10 #20)
|
|
158
|
-
//
|
|
159
|
-
//
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
157
|
+
// Out-of-batch prerequisite check (review 2026-06-10 #20), now TRANSITIVE (HARNESS-GAPS 2026-06-18
|
|
158
|
+
// Gap 3): a depends_on clears only if it already landed (or is absent — pre-backlog work), OR is
|
|
159
|
+
// packable this sprint AND its OWN dependency chain likewise clears. Checking only DIRECT deps let
|
|
160
|
+
// an in-sprint dep whose prerequisite is unshipped slip in as a velocity-filler, building against
|
|
161
|
+
// unbuilt code — `resolveEligibleStories` already requires the WHOLE chain to be live; the packer
|
|
162
|
+
// must agree or the two disagree about what runs.
|
|
163
|
+
const outOfBatchDepsSatisfied = (story, seen = new Set()) => {
|
|
164
|
+
if (seen.has(story.id)) return true; // cycle guard — a dependency cycle is a backlog error, not the packer's to resolve
|
|
165
|
+
seen.add(story.id);
|
|
166
|
+
return depsOf(story).every((depId) => {
|
|
167
|
+
if (byId.has(depId)) return outOfBatchDepsSatisfied(byId.get(depId), seen); // in-sprint dep — its chain must hold too
|
|
168
|
+
const known = byIdAll.get(depId);
|
|
169
|
+
return !known || satisfied.has(known.status);
|
|
170
|
+
});
|
|
171
|
+
};
|
|
165
172
|
|
|
166
173
|
const byPriority = [...groomed].sort(
|
|
167
174
|
(a, b) => (a.priority ?? Infinity) - (b.priority ?? Infinity),
|