flowviant 0.78.0 → 0.79.0

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.
@@ -19,11 +19,15 @@ import { baseBranchName } from './git.mjs';
19
19
  *
20
20
  * `git branch -d` IS THE GUARD, deliberately, rather than a stack of checks
21
21
  * of our own. It refuses an UNMERGED branch and it refuses one CHECKED OUT in
22
- * any worktree — which are two of the three conditions, enforced by the tool
23
- * that owns the truth instead of by our reading of it. Never `-D`: if git
24
- * objects, git is right and we stop. The third condition is ours and is the
25
- * name: only `session/<id>` exactly, so a branch the agent cut is never in
26
- * scope no matter what it was merged into.
22
+ * any worktree — enforced by the tool that owns the truth instead of by our
23
+ * reading of it. Never `-D`: if git objects, git is right and we stop. Two
24
+ * conditions are ours on top of it. The NAME: only `session/<id>` exactly, so
25
+ * a branch the agent cut is never in scope no matter what it was merged into.
26
+ * And ANCESTRY OF BASE: `-d` with no upstream judges "merged" against HEAD,
27
+ * so an operator parked on an experimental branch that merged the session
28
+ * work would get the delete while the narration below claimed "merged into
29
+ * <base>" for commits base has never seen — the claim is checked against the
30
+ * thing it names before git is asked at all.
27
31
  *
28
32
  * ORDERING IS LOAD-BEARING. This must not run while a ship report is still
29
33
  * undelivered. Ship's idempotency path recovers from a lost report by asking
@@ -45,6 +49,13 @@ export function sweepMergedBranch(sessionId, { git, repoRoot, baseRef, note, isR
45
49
  } catch {
46
50
  return false; // already gone, or never existed
47
51
  }
52
+ try {
53
+ git(['merge-base', '--is-ancestor', `refs/heads/${name}`, baseRef], repoRoot);
54
+ } catch {
55
+ // Not on base — merged into something, perhaps, but not into the thing the
56
+ // narration names, and not ours to retire on HEAD's say-so.
57
+ return false;
58
+ }
48
59
  try {
49
60
  git(['branch', '-d', name], repoRoot);
50
61
  } catch {