valent-pipeline 0.19.65 → 0.19.66

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.65",
3
+ "version": "0.19.66",
4
4
  "description": "v3 multi-agent AI pipeline for software development lifecycle",
5
5
  "type": "module",
6
6
  "bin": {
@@ -167,6 +167,42 @@ function isMergedInto(root, branch, target) {
167
167
  }
168
168
  }
169
169
 
170
+ // RESUME-path backlog refresh (M-208). The create-path sync (startStory, the `merge --no-ff target`
171
+ // below) fires ONLY on create — never on a RESUME, because a full merge there would move HEAD past the
172
+ // critic pin (the documented constraint at the create-path guard). But a --from-story bug-fix branch
173
+ // can still END UP missing the target-filed bug entry across a resume: if the entry is filed to the
174
+ // target AFTER the branch is cut (the rejecting sprint's rollover-persist lands ~seconds after the
175
+ // branch base, or the create launch dies before the entry exists) and the run then RESUMES the branch,
176
+ // the create refresh never re-runs → `backlog ship --story <bug>` errors "backlog item not found"
177
+ // (3.5-BUG-001, the M-36/M-65 class on the resume surface). Bring ONLY the target-canonical backlog
178
+ // forward — a single path-scoped chore commit, NOT a merge — so the entry arrives while the pin and all
179
+ // code stay exactly put (the backlog is already target-wins on every merge, REFRESH_TARGET_WINS). A
180
+ // no-op when the branch backlog already matches the target (the create refresh delivered it, or nothing
181
+ // was filed) so a resume never churns an empty commit; gated to inline --from-story fixes (basedOnStory)
182
+ // whose target genuinely advanced, mirroring the create-path guard.
183
+ function syncBacklogFromTargetOnResume(gitDir, root, story, target) {
184
+ const backlogFile = 'pipeline-backlog.yaml';
185
+ try {
186
+ if (!target || !branchExists(root, target)) return false;
187
+ const rec = readFlowRecord(gitDir, story) || readFlowRecord(root, story);
188
+ if (!rec || !rec.basedOnStory) return false; // only inline bug fixes need this
189
+ if (mergeInProgress(gitDir)) return false; // never touch a half-merged tree
190
+ const branch = rec.branch || currentBranch(gitDir);
191
+ if (!branch || isMergedInto(root, target, branch)) return false; // target not ahead → nothing to inherit
192
+ git(gitDir, ['checkout', target, '--', backlogFile]); // stage the target's canonical backlog blob
193
+ const staged = git(gitDir, ['diff', '--cached', '--name-only'])
194
+ .split('\n').map((s) => s.trim()).filter(Boolean);
195
+ if (!staged.includes(backlogFile)) return false; // already current → no empty commit
196
+ git(gitDir, ['commit', '-m',
197
+ buildCommitMessage({ storyId: story, phase: 'sync',
198
+ summary: `inherit target backlog (filed bug entries) on resume — no code merge, pin intact (M-208)` }),
199
+ '--', backlogFile]);
200
+ return true;
201
+ } catch {
202
+ return false; // best-effort: a sync failure leaves the branch as it was (degraded, not wedged)
203
+ }
204
+ }
205
+
170
206
  // --- worktree mode (parallel story execution) -------------------------------------------------
171
207
  // Each parallel story gets its own worktree under `<root>/<worktreeDir>/<storyId>` with the story
172
208
  // branch checked out there; the MAIN checkout stays on the target branch and is the only place
@@ -470,7 +506,10 @@ export function startStory({ root, story, targetBranch = '', prefix = 'story/',
470
506
  const onBranch = currentBranch(root);
471
507
 
472
508
  if (!worktree && onBranch === branch) {
473
- return { branch, base: readFlowRecord(root, story)?.base ?? null, created: false, resumed: true };
509
+ const rec = readFlowRecord(root, story);
510
+ const backlogResynced = syncBacklogFromTargetOnResume(root, root, story, rec?.target);
511
+ return { branch, base: rec?.base ?? null, created: false, resumed: true,
512
+ ...(backlogResynced ? { backlogResynced: true } : {}) };
474
513
  }
475
514
 
476
515
  // Leftover dirt belongs to whatever produced it (planning artifacts, a prior crash) — sweep it
@@ -516,7 +555,10 @@ export function startStory({ root, story, targetBranch = '', prefix = 'story/',
516
555
  // when intact, and a half-created worktree (crash between `worktree add` and setup) gets
517
556
  // its missing pieces — setup_commands must therefore be idempotent (documented).
518
557
  const setup = setupWorktree(root, existing, setupCommands);
519
- return { branch, base: readFlowRecord(existing, story)?.base ?? null, worktree: existing, created: false, resumed: true, snapshotSha, ...setup };
558
+ const rec = readFlowRecord(existing, story) || readFlowRecord(root, story);
559
+ const backlogResynced = syncBacklogFromTargetOnResume(existing, root, story, rec?.target);
560
+ return { branch, base: rec?.base ?? null, worktree: existing, created: false, resumed: true, snapshotSha,
561
+ ...(backlogResynced ? { backlogResynced: true } : {}), ...setup };
520
562
  }
521
563
  const creating = !branchExists(root, branch);
522
564
  if (creating) {
@@ -586,7 +628,10 @@ export function startStory({ root, story, targetBranch = '', prefix = 'story/',
586
628
 
587
629
  if (branchExists(root, branch)) {
588
630
  git(root, ['checkout', branch]);
589
- return { branch, base: readFlowRecord(root, story)?.base ?? null, created: false, resumed: true, snapshotSha };
631
+ const rec = readFlowRecord(root, story);
632
+ const backlogResynced = syncBacklogFromTargetOnResume(root, root, story, rec?.target);
633
+ return { branch, base: rec?.base ?? null, created: false, resumed: true, snapshotSha,
634
+ ...(backlogResynced ? { backlogResynced: true } : {}) };
590
635
  }
591
636
  if (!branchExists(root, base)) throw new Error(`base branch "${base}" does not exist`);
592
637