valent-pipeline 0.19.26 → 0.19.27

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.26",
3
+ "version": "0.19.27",
4
4
  "description": "v3 multi-agent AI pipeline for software development lifecycle",
5
5
  "type": "module",
6
6
  "bin": {
@@ -17,7 +17,7 @@ import { randomBytes } from 'crypto';
17
17
  import { parse as parseYaml } from 'yaml';
18
18
  import {
19
19
  runEvidence, pinGate, formatRunTrailer, formatRunDigest, resolveRoot, evidenceDir, latestRun, latestPins,
20
- verifyIntegrity, assertRules, assertRedRules, snapshotFiles, buildProof, utcCompact,
20
+ verifyIntegrity, assertRules, assertRedRules, pinSourceDelta, snapshotFiles, buildProof, utcCompact,
21
21
  latestAssert, collectFailingCases, authenticateBaseline, verifyShipEvidence, sha256Hex,
22
22
  validStoryId, recordStageResults,
23
23
  } from '../lib/evidence.js';
@@ -342,6 +342,19 @@ export async function evidenceAssertCmd(options) {
342
342
  .map((s) => s.trim())
343
343
  .filter(Boolean);
344
344
 
345
+ // Pin coherence v3 (2026-06-17): a pin/tested SHA mismatch is incoherent only if SOURCE moved
346
+ // between the pin and the tested commit — compute the per-gate source delta here (git IO) so
347
+ // assertRules stays pure. A bookkeeping-only commit (start-story snapshot, board/run state, a
348
+ // re-pin) leaves the reviewed code intact and keeps the pin coherent.
349
+ const pinsForCheck = latestPins(evDir);
350
+ const pinDelta = {};
351
+ for (const gate of requirePins) {
352
+ const pin = pinsForCheck instanceof Map ? pinsForCheck.get(gate) : pinsForCheck?.[gate];
353
+ if (pin && run.record.git && pin.sha !== run.record.git.sha) {
354
+ pinDelta[gate] = pinSourceDelta({ root, fromSha: pin.sha, toSha: run.record.git.sha });
355
+ }
356
+ }
357
+
345
358
  const result = assertRules({
346
359
  record: run.record,
347
360
  parsedReports,
@@ -349,11 +362,12 @@ export async function evidenceAssertCmd(options) {
349
362
  manifestCases,
350
363
  baseline,
351
364
  baselineAuth,
352
- pins: latestPins(evDir),
365
+ pins: pinsForCheck,
353
366
  requirePins,
354
367
  allowDirty: !options.strictDirty,
355
368
  redBaseline,
356
369
  frozenSpecForced: !!options.redBaseline,
370
+ pinDelta,
357
371
  });
358
372
 
359
373
  const verdictRecord = {
Binary file
@@ -177,6 +177,11 @@ const STATE_EXCLUDE_PATTERNS = [
177
177
  // is refused ("local changes would be overwritten"). A transient local pointer has no business in
178
178
  // git history; keep it on disk, out of git. (Root cause of a 3rd Sprint-1 zero-ship, 2026-06-13.)
179
179
  '.valent-pipeline/run-state.json',
180
+ // Resolve snapshots + scratch the orchestrator/skills drop next to a run. start-story's pre-branch
181
+ // snapshot used to sweep these onto the integration branch, creating no-source-delta commits that
182
+ // false-rejected pin coherence AND contaminated the next story's base (2026-06-17). Off git.
183
+ '.resolve-snapshot.json',
184
+ 'scratch/',
180
185
  ];
181
186
 
182
187
  /**
@@ -73,8 +73,10 @@ function stripLineComment(line) {
73
73
  }
74
74
 
75
75
  /**
76
- * Scan one story test file for un-waived skip/only/todo markers. A waiver is `// valent-waiver: ...`
77
- * on the same line or the line immediately above the marker.
76
+ * Scan one story test file for un-waived skip/only/todo markers. A waiver is `valent-waiver:` on the
77
+ * marker's own line (including embedded in an it.skip/describe.skip title) or in the comment/decorator
78
+ * block immediately preceding it (up to 3 lines up — multi-line reasons, a wrapped decorator). Waivers
79
+ * sit on or above the marker by convention, so the window only looks back, never forward.
78
80
  * @returns {Array<{kind:'unwaived-skip', file:string, line:number, detail:string}>}
79
81
  */
80
82
  function scanSkips(file) {
@@ -86,7 +88,7 @@ function scanSkips(file) {
86
88
  SKIP_MARKER.lastIndex = 0;
87
89
  const m = code.match(SKIP_MARKER);
88
90
  if (!m) continue;
89
- const waived = WAIVER_RE.test(raw) || (i > 0 && WAIVER_RE.test(lines[i - 1]));
91
+ const waived = WAIVER_RE.test(raw) || lines.slice(Math.max(0, i - 3), i).some((l) => WAIVER_RE.test(l));
90
92
  if (waived) continue;
91
93
  out.push({
92
94
  kind: 'unwaived-skip',