valent-pipeline 0.19.33 → 0.19.34

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "valent-pipeline",
3
- "version": "0.19.33",
3
+ "version": "0.19.34",
4
4
  "description": "v3 multi-agent AI pipeline for software development lifecycle",
5
5
  "type": "module",
6
6
  "bin": {
@@ -2833,8 +2833,9 @@ async function runStory(story) {
2833
2833
  const evidenceNote = hasMachineEvidence
2834
2834
  ? `\n\nMACHINE EVIDENCE (authoritative): the deterministic Evidence gate already ran ` +
2835
2835
  `\`evidence assert\` + \`trace check\` (gate verdict: ${evGate.verdict}${evGate.escalated ? ', escalated after the rework cap' : ''}${evGate.advisory ? ', advisory' : ''}). ` +
2836
- `Read the NEWEST JSON under \`stories/${sid}/evidence/asserts/\`` +
2837
- `${evGate.verdictPath ? ` (the gate reported \`${evGate.verdictPath}\`)` : ''} and TRANSCRIBE testsPassed/testsFailed/openP1toP3 ` +
2836
+ (evGate.verdictPath
2837
+ ? `Read the assert JSON the Evidence gate VERIFIED \`${evGate.verdictPath}\` NOT merely the newest file under \`stories/${sid}/evidence/asserts/\` (a transient or mislabeled-label run can be newer and carry the wrong counts) — and TRANSCRIBE testsPassed/testsFailed/openP1toP3 `
2838
+ : `Read the NEWEST green qa-b JSON under \`stories/${sid}/evidence/asserts/\` and TRANSCRIBE testsPassed/testsFailed/openP1toP3 `) +
2838
2839
  `from its counts (openP1toP3 = bugs in the \`valent:bugs\` block of bugs.md with status open/fix-in-progress AND priority P1/P2/P3, EXCLUDING any with \`preExisting: true\` or \`category: pre-existing\` — baselined pre-existing bugs are non-blocking and the cross-check counts them separately, so including them here produces a verdict-integrity mismatch and refuses the ship) — do NOT count from execution-report.md prose. ` +
2839
2840
  `Set evidenceVerdict to the assert verdict and gitSha to the evidence run's SHA. Your job on numbers is ANOMALY ` +
2840
2841
  `DETECTION: FLAG as a discrepancy any claim in execution-report.md / traceability-matrix.md / bugs.md that the ` +
@@ -62,17 +62,31 @@ export function crosscheckVerdict({ reported = null, bugsBlock = null, assertVer
62
62
  // ship is claimed < actual — and refusing it stranded genuinely shippable stories. So an
63
63
  // over-report on these fields reconciles to the authoritative recount with a warning; an
64
64
  // under-report stays a hard mismatch. (Prompt tightening alone did not hold — the LLM still
65
- // over-counts; this is the mechanical backstop.) Good-thing counts (testsPassed) and exact-match
66
- // fields keep strict equality, where over-claiming IS the unsafe direction.
65
+ // over-counts; this is the mechanical backstop.)
66
+ //
67
+ // GOOD-thing counts (testsPassed) are the MIRROR IMAGE: the unsafe, ship-sneaking direction is
68
+ // OVER-claiming (padding green to look more passing than reality), so an over-claim stays a hard
69
+ // mismatch; an UNDER-report (claimed FEWER passes than the recount) is the safe direction — you
70
+ // cannot sneak a ship by under-stating passes, because the ship gates on the authoritative recount,
71
+ // not on this transcribed number — so it reconciles to the recount with a warning. This closes the
72
+ // JUDGE-verdict-path analogue of Gap 2 (label-multiplexing, 2026-06-18): a transcribed testsPassed
73
+ // bound to a transient/mislabeled qa-b run under-counts passes, which is harmless and must not
74
+ // refuse a ship the green assert already proved. Exact-match fields (verdict, reviewedSha) keep
75
+ // strict equality in both directions.
67
76
  const SAFE_IF_OVER_REPORTED = new Set(['testsFailed', 'openP1toP3']);
77
+ const SAFE_IF_UNDER_REPORTED = new Set(['testsPassed']);
68
78
  const compare = (field, actual) => {
69
79
  recounted[field] = actual;
70
80
  if (!claim(field) || reported[field] === actual) return;
71
- if (SAFE_IF_OVER_REPORTED.has(field) && typeof reported[field] === 'number'
72
- && typeof actual === 'number' && reported[field] > actual) {
81
+ const numeric = typeof reported[field] === 'number' && typeof actual === 'number';
82
+ if (numeric && SAFE_IF_OVER_REPORTED.has(field) && reported[field] > actual) {
73
83
  warnings.push(`${field}: self-reported ${reported[field]} but artifacts show ${actual} — over-report (safe, conservative direction), reconciled to the recount`);
74
84
  return;
75
85
  }
86
+ if (numeric && SAFE_IF_UNDER_REPORTED.has(field) && reported[field] < actual) {
87
+ warnings.push(`${field}: self-reported ${reported[field]} but artifacts show ${actual} — under-report (safe direction: under-stating passes cannot sneak a ship), reconciled to the recount`);
88
+ return;
89
+ }
76
90
  mismatches.push({ field, claimed: reported[field], actual });
77
91
  };
78
92