@miraland-labs/conduit-bridge 0.16.189 → 0.16.191

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/dist/execution.js CHANGED
@@ -35,7 +35,7 @@ import { boundedTail, captureVerificationFailure, DeliveryReportDefectError, det
35
35
  import { ensureChangeEvidence } from "./ensure-change-evidence.js";
36
36
  import { ensureDemonstrationEvidence } from "./ensure-demonstration-evidence.js";
37
37
  import { ensureNormativeEvidence } from "./ensure-normative-evidence.js";
38
- import { changedPathsSince, compareWorktreeState, diffStatSince, worktreeStateFingerprint, worktreeWrittenPaths } from "./git-witness.js";
38
+ import { changedPathsSince, compareWorktreeState, diffStatSince, mergeBaseWithDefaultBranch, trackedDefaultBranchRef, worktreeStateFingerprint, worktreeWrittenPaths } from "./git-witness.js";
39
39
  import { assertNormativeRefsMaterialized, checkNormativeMarkers, materializeNormativeRefs, NORMATIVE_MARKER_PREFIX, NORMATIVE_REF_PREFIX, parseNormativeRefs, } from "./normative-refs.js";
40
40
  import { checkIntegrationObligations, INTEGRATION_OBLIGATION_PREFIX, parseIntegrationObligations, } from "./integration-obligations.js";
41
41
  /** Keep a Mac awake only while an assignment is active; display sleep remains allowed. */
@@ -431,8 +431,9 @@ const executionContractSchema = z.object({
431
431
  repository_fingerprint: z.string().nullable().optional().default(null),
432
432
  requested_base_commit: z.string().nullable().optional().default(null),
433
433
  claimed_head: z.string().nullable().optional().default(null),
434
- // For a rework, the control plane carries the first revision's resolved attempt start. Older
435
- // contracts omit it and use the T136 worktree-start fallback below.
434
+ // The control plane may carry the first revision's resolved attempt start. Rework and resume
435
+ // measure from the default-branch fork point; this field is the fallback when that fork
436
+ // point cannot be computed.
436
437
  delivery_base_commit: z.string().nullable().optional().default(null),
437
438
  source_attempt_id: z.string().uuid().nullable().optional().default(null),
438
439
  // The change request and head commit the returned delivery left behind. A rework that keeps the
@@ -1231,21 +1232,30 @@ async function runAttempt(client, config, driver, workspace, brief, taskId, watc
1231
1232
  await removeAttemptWorktree(workspace, attemptWorkspace).catch(() => undefined);
1232
1233
  }
1233
1234
  };
1234
- // T136: a first revision's witness starts at the commit the attempt worktree actually checked
1235
- // out. When main has moved past the requested base, that resolved start is the claimed head;
1236
- // diffing from the requested base would report commits that predate the agent as its work.
1237
- // T138: a rework carries the first revision's resolved start, because its worktree starts at the
1238
- // previous delivery's head. That lets a prose-only rework witness the original pack while still
1239
- // including any new rework changes. A conflict rework is different: it is pinned to the live base
1240
- // tip and starts fresh there, so the control plane sends no carried base and the requested base --
1241
- // the pinned tip -- is the delivery base. Diffing from the first revision's start would report
1242
- // every commit the base gained in between as the agent's own work. Older contracts fall back to
1243
- // the T136 rule.
1244
- const rework = task.delivery_state === "changes_requested" || Boolean(executionContract.prior_head_commit);
1245
- const deliveryBaseCommit = executionContract.delivery_base_commit
1246
- ?? (rework
1247
- ? (executionContract.requested_base_commit ?? spec.repository?.base_commit ?? worktreeStart)
1248
- : worktreeStart);
1235
+ // T136: a fresh attempt witnesses from the commit the worktree checked out. When main has
1236
+ // moved past the requested base, that resolved start is the claimed head; diffing from the
1237
+ // requested base would report commits that predate the agent as its work.
1238
+ // A rework or a resumed delivery measures from the merge-base of HEAD with origin/<branch>,
1239
+ // where <branch> is the branch the source checkout has checked out — the branch ensureCheckout
1240
+ // tracks. fetch updates that ref. fetch does not update origin/HEAD. Contract
1241
+ // delivery_base_commit and requested_base_commit apply only when that merge-base cannot be
1242
+ // computed. A contract base from the first attempt's start counts later default-branch commits
1243
+ // as the agent's writes (2026-10-23, task eff1253c). Diagnosis uses the same rule.
1244
+ const reworkOrResume = isReworkOrResumeDelivery({
1245
+ deliveryState: task.delivery_state,
1246
+ priorHeadCommit: executionContract.prior_head_commit,
1247
+ resumeFromAttemptId: executionContract.resume_from_attempt_id,
1248
+ });
1249
+ let deliveryBaseCommit = await resolveDeliveryBaseCommit({
1250
+ worktree: attemptWorkspace,
1251
+ sourceWorkspace: workspace,
1252
+ reworkOrResume,
1253
+ worktreeStart,
1254
+ taskId,
1255
+ deliveryBaseCommit: executionContract.delivery_base_commit,
1256
+ requestedBaseCommit: executionContract.requested_base_commit,
1257
+ repositoryBaseCommit: spec.repository?.base_commit,
1258
+ });
1249
1259
  // Only when the worktree really stands at the timed-out run's head: a computer that cannot reach
1250
1260
  // that commit starts at the base (resolveAttemptStartCommit), and the agent must not be told the
1251
1261
  // work is there.
@@ -1992,6 +2002,21 @@ async function runAttempt(client, config, driver, workspace, brief, taskId, watc
1992
2002
  retainAttemptWorktree = await failAttemptFromDriverResult(result);
1993
2003
  return;
1994
2004
  }
2005
+ // The agent may have rebased or merged the default branch during its turn (CR25 rework,
2006
+ // 2026-10-24: the base fixed at attempt start counted the default branch's own commits as the
2007
+ // agent's writes). Measure a rework from where the tree stands now.
2008
+ if (reworkOrResume) {
2009
+ deliveryBaseCommit = await resolveDeliveryBaseCommit({
2010
+ worktree: attemptWorkspace,
2011
+ sourceWorkspace: workspace,
2012
+ reworkOrResume,
2013
+ worktreeStart,
2014
+ taskId,
2015
+ deliveryBaseCommit: executionContract.delivery_base_commit,
2016
+ requestedBaseCommit: executionContract.requested_base_commit,
2017
+ repositoryBaseCommit: spec.repository?.base_commit,
2018
+ });
2019
+ }
1995
2020
  watchdog.phase("land");
1996
2021
  if (requiresLandCommit({ grants, spec })) {
1997
2022
  try {
@@ -3008,6 +3033,37 @@ function referenceKind(kind) {
3008
3033
  * Implemented in git-witness.ts; re-exported for control-plane test pins and investigation.
3009
3034
  */
3010
3035
  export { changedPathsSince } from "./git-witness.js";
3036
+ /**
3037
+ * A rework or a resumed delivery, from the signals the attempt contract carries.
3038
+ *
3039
+ * Diagnosis is not a separate case: the same three signals select the base.
3040
+ */
3041
+ export function isReworkOrResumeDelivery(input) {
3042
+ return input.deliveryState === "changes_requested"
3043
+ || Boolean(input.priorHeadCommit)
3044
+ || Boolean(input.resumeFromAttemptId);
3045
+ }
3046
+ /**
3047
+ * Commit that changedPathsSince, diffStatSince, and the land checks measure from.
3048
+ *
3049
+ * A fresh attempt keeps the worktree start. A rework or a resumed delivery uses the merge-base
3050
+ * of HEAD with `origin/<branch>` on the source checkout. Contract bases apply only when that
3051
+ * merge-base cannot be computed. One log line names the base this attempt used.
3052
+ */
3053
+ export async function resolveDeliveryBaseCommit(input) {
3054
+ const ref = input.reworkOrResume ? await trackedDefaultBranchRef(input.sourceWorkspace) : null;
3055
+ const fork = ref ? await mergeBaseWithDefaultBranch(input.worktree, ref) : null;
3056
+ const base = !input.reworkOrResume
3057
+ ? input.worktreeStart
3058
+ : fork
3059
+ ?? input.deliveryBaseCommit
3060
+ ?? input.requestedBaseCommit
3061
+ ?? input.repositoryBaseCommit
3062
+ ?? input.worktreeStart;
3063
+ const via = fork && ref ? ` (merge-base with ${ref})` : "";
3064
+ console.log(`Assignment ${input.taskId} delivery base ${base}${via}`);
3065
+ return base;
3066
+ }
3011
3067
  /**
3012
3068
  * Does this attempt earn a verification dry run?
3013
3069
  *
@@ -21,6 +21,44 @@ async function gitFields(worktree, args) {
21
21
  return null;
22
22
  }
23
23
  }
24
+ /**
25
+ * Fork point of HEAD with the fetched default-branch ref.
26
+ *
27
+ * Null when the ref is missing or the two histories do not meet. Callers then use the
28
+ * contract base. A merge of that ref into the attempt branch moves this commit forward,
29
+ * so the diff still names only the branch's own files.
30
+ */
31
+ export async function mergeBaseWithDefaultBranch(worktree, defaultBranchRef) {
32
+ try {
33
+ const { stdout } = await execFileAsync("git", ["-C", worktree, "merge-base", "HEAD", defaultBranchRef], { timeout: 30_000, maxBuffer: 1_000_000 });
34
+ const sha = stdout.trim().toLowerCase();
35
+ return /^[0-9a-f]{7,64}$/.test(sha) ? sha : null;
36
+ }
37
+ catch {
38
+ return null;
39
+ }
40
+ }
41
+ /**
42
+ * `origin/<branch>` for the branch this checkout has checked out.
43
+ *
44
+ * `ensureCheckout` leaves that branch checked out. `fetchOrigin` and `refreshSourceWorkspace`
45
+ * update `origin/<branch>`. They do not update `origin/HEAD`, so this function never reads it.
46
+ * Null when HEAD is detached or `origin/<branch>` is absent; callers then use the contract base.
47
+ */
48
+ export async function trackedDefaultBranchRef(workspace) {
49
+ try {
50
+ const { stdout } = await execFileAsync("git", ["-C", workspace, "rev-parse", "--abbrev-ref", "HEAD"], { timeout: 30_000, maxBuffer: 1_000_000 });
51
+ const branch = stdout.trim();
52
+ if (!branch || branch === "HEAD")
53
+ return null;
54
+ const ref = `origin/${branch}`;
55
+ await execFileAsync("git", ["-C", workspace, "rev-parse", "--verify", "--quiet", `${ref}^{commit}`], { timeout: 30_000, maxBuffer: 1_000_000 });
56
+ return ref;
57
+ }
58
+ catch {
59
+ return null;
60
+ }
61
+ }
24
62
  /**
25
63
  * Paths changed on the attempt branch since `startCommit`, including uncommitted work.
26
64
  * Null when git cannot answer — callers must not treat null as failure.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miraland-labs/conduit-bridge",
3
- "version": "0.16.189",
3
+ "version": "0.16.191",
4
4
  "description": "Conduit Bridge CLI — join, connect, disconnect, multi-driver lanes, and run Claude Code / Codex / Cursor / OpenCode / Pi / Kiro / Antigravity / Grok Build agents for a Conduit organization",
5
5
  "type": "module",
6
6
  "bin": {