@miraland-labs/conduit-bridge 0.16.121 → 0.16.130

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/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Local Bridge CLI for [Conduit](https://github.com/miralandlabs/conduit). Connects a computer to one organization, claims work, and drives a local agent.
4
4
 
5
- **Package version:** `0.16.95` — Conduit-fuel lanes bind organization aliases (T144), the Anthropic base URL is the origin (T148), the investigation lane resolves its model (T154); a hosted container image lives under `hosted/` (docs/HOSTED_RUNNER.md). Earlier (0.16.27) — work-package execution budgets reach every agent turn, are bounded by the machine ceiling, and expose their effective source for operations. Local-fuel provider refusals make the affected lane unavailable instead of repeatedly spending attempts; an operator who changes the lane's account or plan can invalidate that observation with `ops quota-clear <driver>`. Bridge discovers bounded repository verification commands, including Make targets `test`, `check`, `verify`, `replay`, `typecheck`, `lint`, and `build`. `ops disconnect` asks before it removes the runner service and clears credentials; pass `--yes` to skip the question. `ops.env` is enrollment/bootstrap defaults only: an explicit workspace does not inherit an old repository, and project switches do not rewrite global project state. `ops enroll` exchanges a single-use token, registers the machine, binds project affinity, provisions fuel keys, brings detected drivers online, and starts the runner in one command. On Linux, `ops install` refuses any effective systemd drop-in. A switch intent remains queued until the target runner heartbeat proves Bound. After every Bridge publish, operators must re-run `ops install` (LaunchAgent pins an absolute `cli.js`).
5
+ **Package version:** `0.16.125` — the workspace brief reports `declared_demonstration` so the planner knows whether the repository can show itself (KERNEL.md §51). Earlier (0.16.124) — when a project declares `.conduit/demonstrate`, Bridge runs that bounded command at the delivered head and attaches a stamped `preview` row (KERNEL.md §47). Earlier (0.16.95) — Conduit-fuel lanes bind organization aliases (T144), the Anthropic base URL is the origin (T148), the investigation lane resolves its model (T154); a hosted container image lives under `hosted/` (docs/HOSTED_RUNNER.md). Earlier (0.16.27) — work-package execution budgets reach every agent turn, are bounded by the machine ceiling, and expose their effective source for operations. Local-fuel provider refusals make the affected lane unavailable instead of repeatedly spending attempts; an operator who changes the lane's account or plan can invalidate that observation with `ops quota-clear <driver>`. Bridge discovers bounded repository verification commands, including Make targets `test`, `check`, `verify`, `replay`, `typecheck`, `lint`, and `build`. `ops disconnect` asks before it removes the runner service and clears credentials; pass `--yes` to skip the question. `ops.env` is enrollment/bootstrap defaults only: an explicit workspace does not inherit an old repository, and project switches do not rewrite global project state. `ops enroll` exchanges a single-use token, registers the machine, binds project affinity, provisions fuel keys, brings detected drivers online, and starts the runner in one command. On Linux, `ops install` refuses any effective systemd drop-in. A switch intent remains queued until the target runner heartbeat proves Bound. After every Bridge publish, operators must re-run `ops install` (LaunchAgent pins an absolute `cli.js`).
6
6
 
7
7
  ## Prerequisites
8
8
 
package/dist/brief.js CHANGED
@@ -3,6 +3,7 @@ import { join } from "node:path";
3
3
  import { execFile } from "node:child_process";
4
4
  import { promisify } from "node:util";
5
5
  import { isBoundedVerificationCommand } from "./execution-class.js";
6
+ import { readDeclaredDemonstration } from "./ensure-demonstration-evidence.js";
6
7
  import { gitOriginUrl, headCommitOrNull } from "./git.js";
7
8
  const execFileAsync = promisify(execFile);
8
9
  const MANIFESTS = [
@@ -39,6 +40,7 @@ export async function buildWorkspaceBrief(workspace) {
39
40
  manifests,
40
41
  verification: await discoverVerificationCommands(workspace, files),
41
42
  declared_verification: declared,
43
+ declared_demonstration: await readDeclaredDemonstration(workspace),
42
44
  };
43
45
  }
44
46
  /**
package/dist/driver.js CHANGED
@@ -696,7 +696,7 @@ export function claudeUsage(message) {
696
696
  */
697
697
  export const CLAUDE_CODE_KNOWN_MODELS = [
698
698
  "fable", "opus", "sonnet", "haiku",
699
- "claude-fable-5-1", "claude-opus-5", "claude-sonnet-5", "claude-haiku-4-5",
699
+ "claude-fable-5-1", "claude-opus-5-5", "claude-opus-5", "claude-sonnet-5", "claude-haiku-4-5",
700
700
  ];
701
701
  export const claudeCodeDriver = {
702
702
  name: "claude-code",
@@ -960,7 +960,8 @@ export function cursorRunArgs(input) {
960
960
  args.push(...modelArgs(cursorDriver, input.model));
961
961
  if (input.resumeSessionId)
962
962
  args.push("--resume", input.resumeSessionId);
963
- args.push(input.prompt);
963
+ // The prompt goes on stdin, as it does for codex: Linux caps one argument at 128 KiB
964
+ // (MAX_ARG_STRLEN) and an assignment contract exceeds that, which spawned `E2BIG`.
964
965
  return args;
965
966
  }
966
967
  /** Parse `agent --list-models` output: one "id - Label" line per model. */
@@ -999,7 +1000,9 @@ export const cursorDriver = {
999
1000
  vendor: "cursor",
1000
1001
  // Cursor's own first-party families only. `--list-models` also lists other vendors' models
1001
1002
  // Cursor proxies at a much higher price (the "Other Models" allowance) — those are not owned.
1002
- owns: (id) => id.startsWith("cursor-grok-") || id.startsWith("composer-"),
1003
+ // Grok 4.7 dropped the `cursor-` prefix (`grok-4.7-high`, 2026-09-26) but Cursor still lists it
1004
+ // under "Cursor Models", beside Grok 4.6 and Composer.
1005
+ owns: (id) => id.startsWith("cursor-grok-") || id.startsWith("grok-") || id.startsWith("composer-"),
1003
1006
  },
1004
1007
  async run(input) {
1005
1008
  const fuelSource = input.fuelSource === "local" ? "local" : "conduit";
@@ -1047,7 +1050,7 @@ export const cursorDriver = {
1047
1050
  capabilities: input.capabilities ?? [],
1048
1051
  diagnosis: input.workRole === "diagnose",
1049
1052
  });
1050
- const configured = await withCursorPermissions(input.workspace, { allow: projected.allow, deny: projected.deny }, () => execute(executable, cursorRunArgs({ ...input, trustWorkspace, executionClass, force: projected.force }), input.workspace, agentTurnTimeoutMs(input), undefined, "local", undefined, input.signal));
1053
+ const configured = await withCursorPermissions(input.workspace, { allow: projected.allow, deny: projected.deny }, () => execute(executable, cursorRunArgs({ ...input, trustWorkspace, executionClass, force: projected.force }), input.workspace, agentTurnTimeoutMs(input), undefined, "local", input.prompt, input.signal));
1051
1054
  const { code, stdout, stderr } = configured;
1052
1055
  const parsed = parseCursorOutput(stdout);
1053
1056
  // Cursor prints no token or cost figure, so the run reports the one fact it can prove: it ran.
@@ -0,0 +1,98 @@
1
+ /**
2
+ * When the project declares how it shows itself, Bridge runs that command at the delivered head and
3
+ * attaches what it printed. The agent never authors this entry (KERNEL.md §47, "See it").
4
+ *
5
+ * `.conduit/demonstrate` is one bounded command, `#` comments allowed, absent by default. It runs
6
+ * with the same shape check, runner and bound as a verification command, and it is never a gate:
7
+ * a demonstration that fails, times out or prints nothing attaches as `unverifiable` with its
8
+ * reason, and cannot fail a criterion.
9
+ */
10
+ import { readFile } from "node:fs/promises";
11
+ import { join } from "node:path";
12
+ import { runBoundedVerificationCommand } from "./ensure-test-evidence.js";
13
+ import { isRunnableVerificationCommand } from "./execution-class.js";
14
+ /** Fixed name the control plane reads to place the row on the decision card. */
15
+ export const DEMONSTRATION_ARTIFACT_NAME = "What it does (Bridge witness)";
16
+ export const DEMONSTRATION_DECLARATION_PATH = ".conduit/demonstrate";
17
+ /** The transcript is text the owner reads, not a log: the head, cut with a marker. */
18
+ export const DEMONSTRATION_MAX_CHARS = 4_000;
19
+ export function parseDeclaredDemonstration(text) {
20
+ for (const raw of text.split("\n")) {
21
+ const line = raw.split("#")[0].trim();
22
+ if (!line)
23
+ continue;
24
+ return isRunnableVerificationCommand(line) ? line : null;
25
+ }
26
+ return null;
27
+ }
28
+ export async function readDeclaredDemonstration(workspace) {
29
+ try {
30
+ return parseDeclaredDemonstration(await readFile(join(workspace, DEMONSTRATION_DECLARATION_PATH), "utf8"));
31
+ }
32
+ catch {
33
+ return null; // absent declaration, absent row
34
+ }
35
+ }
36
+ function boundedTranscript(text) {
37
+ const trimmed = text.trim();
38
+ const cut = trimmed.length > DEMONSTRATION_MAX_CHARS;
39
+ const kept = cut ? trimmed.slice(0, DEMONSTRATION_MAX_CHARS) : trimmed;
40
+ return [...kept.split("\n"), ...(cut ? [`… cut at ${DEMONSTRATION_MAX_CHARS.toLocaleString("en-US")} characters …`] : [])];
41
+ }
42
+ export async function ensureDemonstrationEvidence(input) {
43
+ const command = await readDeclaredDemonstration(input.workspace);
44
+ if (!command)
45
+ return input.report;
46
+ const run = input.runCommand ?? runBoundedVerificationCommand;
47
+ const withoutPrior = input.report.evidence.filter((item) => item.name !== DEMONSTRATION_ARTIFACT_NAME);
48
+ const attach = (details, witness, uri) => ({
49
+ ...input.report,
50
+ evidence: [...withoutPrior, {
51
+ kind: "preview",
52
+ name: DEMONSTRATION_ARTIFACT_NAME,
53
+ ...(uri ? { uri } : {}),
54
+ details: [`$ ${command}`, ...details],
55
+ acceptance_criteria: [],
56
+ witness,
57
+ }],
58
+ });
59
+ // A demonstration is repository code. Running it must consume the same explicit authority as a
60
+ // verification command; merely finding the declaration cannot grant shell execution to an
61
+ // observe-only package.
62
+ if (!input.grants.includes("test_run")) {
63
+ return attach(["Not run: this package does not hold test_run authority."], "unverifiable");
64
+ }
65
+ // The delivered code may demonstrate itself, but it may not author the command that earns the
66
+ // Bridge stamp in the same delivery. The declaration becomes a trusted project property only
67
+ // after an earlier delivery landed it. A missing path witness fails closed for the same reason.
68
+ if (input.changedPaths === null || input.changedPaths.includes(DEMONSTRATION_DECLARATION_PATH)) {
69
+ return attach([
70
+ `Not run: this delivery changed ${DEMONSTRATION_DECLARATION_PATH}; a delivery cannot author its own Bridge-witnessed demonstration.`,
71
+ ], "unverifiable");
72
+ }
73
+ let result;
74
+ try {
75
+ result = await run(command, input.workspace);
76
+ }
77
+ catch (error) {
78
+ return attach([`Could not run: ${error instanceof Error ? error.message : String(error)}`], "unverifiable");
79
+ }
80
+ if (result.code !== 0) {
81
+ return attach([...boundedTranscript(result.stderr || result.stdout), `exit ${result.code}`], "unverifiable");
82
+ }
83
+ if (!result.stdout.trim())
84
+ return attach(["The demonstration printed nothing."], "unverifiable");
85
+ const transcript = boundedTranscript(result.stdout);
86
+ // A line that is an https:// URL is the project publishing where to look; it becomes the preview reference.
87
+ const link = transcript.map((line) => line.trim()).find((line) => {
88
+ if (!line.startsWith("https://"))
89
+ return false;
90
+ try {
91
+ return new URL(line).protocol === "https:";
92
+ }
93
+ catch {
94
+ return false;
95
+ }
96
+ });
97
+ return attach(transcript, "bridge", link);
98
+ }
@@ -51,7 +51,7 @@ export async function ensureLandCommit(input) {
51
51
  if (!requiresLandCommit({ grants: input.grants, spec: input.spec })) {
52
52
  return { kind: "skipped" };
53
53
  }
54
- const base = input.spec.repository?.base_commit;
54
+ const base = input.baseCommit ?? input.spec.repository?.base_commit;
55
55
  if (!base)
56
56
  return { kind: "skipped" };
57
57
  const countAhead = input.countCommitsAhead ?? commitsAheadOfBase;
@@ -263,7 +263,7 @@ export async function ensureDeliveryPullRequest(input) {
263
263
  // files. GitHub then answers the pull-request call with an opaque 422 "No commits between main
264
264
  // and <branch>" (initiative efa56ccd, attempt 874fa0e3). Prove the branch carries work first, and
265
265
  // report the real condition instead of a forge validation error.
266
- const base = input.spec.repository?.base_commit;
266
+ const base = input.baseCommit ?? input.spec.repository?.base_commit;
267
267
  if (base) {
268
268
  const ahead = await countAhead(input.workspace, base);
269
269
  if (ahead === 0) {
@@ -101,7 +101,7 @@ export function verificationCommandsMentioned(text, offered = []) {
101
101
  const source = text.slice(0, 20_000);
102
102
  const verbatim = [...new Set(offered.map((command) => command.trim()))]
103
103
  .filter((command) => isBoundedVerificationCommand(command) && textNamesCommand(source, command));
104
- const pattern = /(?:^|[\s("'`])((?:npm run [A-Za-z0-9][A-Za-z0-9._:-]*|pnpm [A-Za-z0-9][A-Za-z0-9._:-]*|yarn [A-Za-z0-9][A-Za-z0-9._:-]*|cargo (?:test|check)|go test(?: \.\/\.\.\.)?|make [A-Za-z0-9][A-Za-z0-9._-]*|python3? -m [A-Za-z0-9_][\w.]*(?: [\w./=:-]*[./=-][\w./=:-]*)*|pytest(?: [\w./=-]*[./=-][\w./=-]*)?|python3? [\w./-]+\.py(?: [\w./=:-]*[./=-][\w./=:-]*)*|(?:\.\/gradlew|gradle|\.\/mvnw|mvn) test|Rscript tests\/testthat\.R|Rscript -e testthat::test_local\(\)))(?=$|[\s"'`),.;:])/g;
104
+ const pattern = /(?:^|[\s("'`])((?:npm run [A-Za-z0-9][A-Za-z0-9._:-]*|pnpm [A-Za-z0-9][A-Za-z0-9._:-]*|yarn [A-Za-z0-9][A-Za-z0-9._:-]*|cargo (?:test|check|clippy)|go test(?: \.\/\.\.\.)?|make [A-Za-z0-9][A-Za-z0-9._-]*|python3? -m [A-Za-z0-9_][\w.]*(?: [\w./=:-]*[./=-][\w./=:-]*)*|pytest(?: [\w./=-]*[./=-][\w./=-]*)?|python3? [\w./-]+\.py(?: [\w./=:-]*[./=-][\w./=:-]*)*|(?:\.\/gradlew|gradle|\.\/mvnw|mvn) test|Rscript tests\/testthat\.R|Rscript -e testthat::test_local\(\)))(?=$|[\s"'`),.;:])/g;
105
105
  const mentions = [...new Set([...source.matchAll(pattern)].map((match) => match[1]))]
106
106
  .filter((mention) => isBoundedVerificationCommand(mention)
107
107
  && !verbatim.some((command) => command === mention || command.startsWith(`${mention} `)));
@@ -13,7 +13,10 @@ export function isBoundedVerificationCommand(command) {
13
13
  // A `*` is a legal character in a Python argument (`-p test_*.py` is how a repository spells its
14
14
  // own gate). Bridge starts a gate with execFile and no shell, so the star stays literal and no
15
15
  // expansion can happen. Refusing it only dropped the declaration, with no reason given.
16
- return /^(npm run [A-Za-z0-9][A-Za-z0-9._:-]*|pnpm [A-Za-z0-9][A-Za-z0-9._:-]*|yarn [A-Za-z0-9][A-Za-z0-9._:-]*|cargo (test|check)|go test(?: \.\/\.\.\.)?|make [A-Za-z0-9][A-Za-z0-9._-]*|python3? -m [A-Za-z0-9_][\w.]*(?: [\w./=:*-]+)*|pytest(?: [\w./=*-]+)?|python3? [\w./-]+\.py(?: [\w./=:-]+)*|(?:\.\/gradlew|gradle|\.\/mvnw|mvn) test|Rscript tests\/testthat\.R|Rscript -e testthat::test_local\(\))$/.test(command);
16
+ // Cargo takes flags the same way: acme-sim registered `cargo clippy --all-targets -- -D warnings`
17
+ // on 2026-09-25, the rule admitted only a bare `cargo test|check`, and five deliveries shipped
18
+ // clippy failures because the gate was dropped before any attempt could run it.
19
+ return /^(npm run [A-Za-z0-9][A-Za-z0-9._:-]*|pnpm [A-Za-z0-9][A-Za-z0-9._:-]*|yarn [A-Za-z0-9][A-Za-z0-9._:-]*|cargo (test|check|clippy)(?: [\w./=:-]+)*|go test(?: \.\/\.\.\.)?|make [A-Za-z0-9][A-Za-z0-9._-]*|python3? -m [A-Za-z0-9_][\w.]*(?: [\w./=:*-]+)*|pytest(?: [\w./=*-]+)?|python3? [\w./-]+\.py(?: [\w./=:-]+)*|(?:\.\/gradlew|gradle|\.\/mvnw|mvn) test|Rscript tests\/testthat\.R|Rscript -e testthat::test_local\(\))$/.test(command);
17
20
  }
18
21
  /** Shell commands each grant authorizes — mapped per driver so they cannot drift. */
19
22
  export const branchCreateCommands = [
package/dist/execution.js CHANGED
@@ -27,6 +27,7 @@ import { agentClaimsRepositoryWork, claimsVsGitMismatch, isLandTreeEmpty, report
27
27
  const execFileAsync = promisify(execFile);
28
28
  import { boundedTail, captureVerificationFailure, detectGateRanNothing, ensureTestEvidence, needsTestEvidence, runBoundedVerificationCommand, verificationEvidenceCommands, VerificationGateRanNothingError } from "./ensure-test-evidence.js";
29
29
  import { ensureChangeEvidence } from "./ensure-change-evidence.js";
30
+ import { ensureDemonstrationEvidence } from "./ensure-demonstration-evidence.js";
30
31
  import { ensureNormativeEvidence } from "./ensure-normative-evidence.js";
31
32
  import { changedPathsSince, compareWorktreeState, diffStatSince, worktreeStateFingerprint, worktreeWrittenPaths } from "./git-witness.js";
32
33
  import { assertNormativeRefsMaterialized, checkNormativeMarkers, materializeNormativeRefs, NORMATIVE_MARKER_PREFIX, NORMATIVE_REF_PREFIX, parseNormativeRefs, } from "./normative-refs.js";
@@ -1179,7 +1180,11 @@ async function runAttempt(client, config, driver, workspace, brief, taskId, watc
1179
1180
  // diffing from the requested base would report commits that predate the agent as its work.
1180
1181
  // T138: a rework carries the first revision's resolved start, because its worktree starts at the
1181
1182
  // previous delivery's head. That lets a prose-only rework witness the original pack while still
1182
- // including any new rework changes. Older contracts fall back to the T136 rule.
1183
+ // including any new rework changes. A conflict rework is different: it is pinned to the live base
1184
+ // tip and starts fresh there, so the control plane sends no carried base and the requested base --
1185
+ // the pinned tip -- is the delivery base. Diffing from the first revision's start would report
1186
+ // every commit the base gained in between as the agent's own work. Older contracts fall back to
1187
+ // the T136 rule.
1183
1188
  const rework = task.delivery_state === "changes_requested" || Boolean(executionContract.prior_head_commit);
1184
1189
  const deliveryBaseCommit = executionContract.delivery_base_commit
1185
1190
  ?? (rework
@@ -1803,7 +1808,7 @@ async function runAttempt(client, config, driver, workspace, brief, taskId, watc
1803
1808
  watchdog.phase("land");
1804
1809
  if (requiresLandCommit({ grants, spec })) {
1805
1810
  try {
1806
- const land = await ensureLandCommit({ workspace: attemptWorkspace, spec, grants });
1811
+ const land = await ensureLandCommit({ workspace: attemptWorkspace, spec, grants, baseCommit: deliveryBaseCommit });
1807
1812
  if (land.kind === "committed") {
1808
1813
  await client.attemptRequest(taskId, "progress", {
1809
1814
  phase: "preparing_delivery",
@@ -1825,6 +1830,7 @@ async function runAttempt(client, config, driver, workspace, brief, taskId, watc
1825
1830
  spec,
1826
1831
  grants,
1827
1832
  agentReply: reportText,
1833
+ baseCommit: deliveryBaseCommit,
1828
1834
  })) {
1829
1835
  const continuation = await runLandContinuationTurn({
1830
1836
  config,
@@ -1859,7 +1865,7 @@ async function runAttempt(client, config, driver, workspace, brief, taskId, watc
1859
1865
  report = parseAgentReport(reportText, spec.acceptance ?? []);
1860
1866
  }
1861
1867
  catch (error) {
1862
- const gitEmpty = await isLandTreeEmpty({ workspace: attemptWorkspace, spec, grants });
1868
+ const gitEmpty = await isLandTreeEmpty({ workspace: attemptWorkspace, spec, grants, baseCommit: deliveryBaseCommit });
1863
1869
  const claimsWork = agentClaimsRepositoryWork(reportText);
1864
1870
  if (requiresLandCommit({ grants, spec }) && gitEmpty && claimsWork) {
1865
1871
  if (!landContinuationUsed) {
@@ -2059,7 +2065,7 @@ async function runAttempt(client, config, driver, workspace, brief, taskId, watc
2059
2065
  if (!landContinuationUsed
2060
2066
  && requiresLandCommit({ grants, spec })
2061
2067
  && reportClaimsRepositoryWork(report)
2062
- && await isLandTreeEmpty({ workspace: attemptWorkspace, spec, grants })) {
2068
+ && await isLandTreeEmpty({ workspace: attemptWorkspace, spec, grants, baseCommit: deliveryBaseCommit })) {
2063
2069
  const continuation = await runLandContinuationTurn({
2064
2070
  config,
2065
2071
  client,
@@ -2129,6 +2135,7 @@ async function runAttempt(client, config, driver, workspace, brief, taskId, watc
2129
2135
  maxDurationMs: workPackage?.max_duration_ms,
2130
2136
  resumeSessionId: agentSessionId,
2131
2137
  landContinuationUsed,
2138
+ landBaseCommit: deliveryBaseCommit,
2132
2139
  });
2133
2140
  // Mechanical land path: the agent only pushes; Bridge pushes again if needed and the control
2134
2141
  // plane opens the change request with the organization's forge connection.
@@ -2140,6 +2147,7 @@ async function runAttempt(client, config, driver, workspace, brief, taskId, watc
2140
2147
  report,
2141
2148
  spec,
2142
2149
  grants,
2150
+ baseCommit: deliveryBaseCommit,
2143
2151
  title: task.objective,
2144
2152
  repositoryFingerprint: executionContract.repository_fingerprint,
2145
2153
  priorPullRequestUrl: executionContract.prior_pull_request_url,
@@ -2166,6 +2174,16 @@ async function runAttempt(client, config, driver, workspace, brief, taskId, watc
2166
2174
  grants,
2167
2175
  changedPaths: actualPaths,
2168
2176
  });
2177
+ // §47 "See it": the project's own demonstration at the delivered head, never a gate.
2178
+ const beforeDemonstration = report;
2179
+ report = await ensureDemonstrationEvidence({
2180
+ workspace: attemptWorkspace,
2181
+ report,
2182
+ grants,
2183
+ changedPaths: actualPaths,
2184
+ });
2185
+ if (report !== beforeDemonstration)
2186
+ await discardWorktreeWrites(attemptWorkspace);
2169
2187
  const integrationCheck = await checkIntegrationObligations(attemptWorkspace, parseIntegrationObligations(spec.integration_obligations));
2170
2188
  if (!integrationCheck.ok) {
2171
2189
  throw new Error(`${INTEGRATION_OBLIGATION_PREFIX}: ${integrationCheck.failures.join("; ")}`);
@@ -2371,6 +2389,7 @@ async function finalizeRepositoryLand(input) {
2371
2389
  workspace: input.workspace,
2372
2390
  spec: input.spec,
2373
2391
  grants: input.grants,
2392
+ baseCommit: input.landBaseCommit,
2374
2393
  });
2375
2394
  if (land.kind === "committed") {
2376
2395
  await input.client.attemptRequest(input.taskId, "progress", {
@@ -2392,7 +2411,7 @@ async function finalizeRepositoryLand(input) {
2392
2411
  throw error;
2393
2412
  }
2394
2413
  if (input.landContinuationUsed) {
2395
- throw new AgentNoLandCommitError(input.spec.repository?.base_commit ?? "unknown");
2414
+ throw new AgentNoLandCommitError(input.landBaseCommit ?? input.spec.repository?.base_commit ?? "unknown");
2396
2415
  }
2397
2416
  const continuation = await runLandContinuationTurn({
2398
2417
  config: input.config,
@@ -2664,7 +2683,7 @@ async function prepareDelivery(client, attemptId, taskId, report) {
2664
2683
  metadata: {
2665
2684
  details: item.details,
2666
2685
  acceptance_criteria: item.acceptance_criteria,
2667
- ...(item.witness === "bridge" ? { witness: "bridge" } : {}),
2686
+ ...(item.witness ? { witness: item.witness } : {}),
2668
2687
  },
2669
2688
  idempotency_key: `bridge:artifact:${attemptId}:${index + 1}`,
2670
2689
  });
@@ -117,7 +117,7 @@ export const BRIDGE_CAUSES = {
117
117
  workspace_head_changed: { class: "environment", disposition: "hold", responsible_party: "computer_operator", message: "The checkout changed after Conduit prepared the assignment.", next_action: "Let the checkout settle, then recheck readiness." },
118
118
  base_not_ancestor: { class: "environment", disposition: "hold", responsible_party: "computer_operator", message: "Conduit could not prepare the required project version on this computer.", next_action: "No Git work is required from the product owner. Keep the computer and Bridge online, then try again so Bridge can refresh the project. If the hold returns, the computer operator should check Bridge's repository access." },
119
119
  workspace_dirty: { class: "environment", disposition: "hold", responsible_party: "computer_operator", message: "The source workspace has uncommitted changes.", next_action: "Commit, stash, or discard the local changes, then recheck readiness." },
120
- missing_verification: { class: "environment", disposition: "hold", responsible_party: "conduit", message: "This checkout has no verification commands Conduit can run for this package.", next_action: "Conductor will adjust how this package is verified. You do not need to author test commands or rewrite the plan for tooling." },
120
+ missing_verification: { class: "environment", disposition: "hold", responsible_party: "conduit", message: "This checkout has no verification commands Conduit can run for this package.", next_action: "Open the initiative and request a revision: Conduit re-plans this package without test evidence this checkout cannot produce. You never author test commands yourself." },
121
121
  verification_unwitnessable: { class: "environment", disposition: "hold", responsible_party: "computer_operator", message: "The project's verification command runs but prints nothing, so test evidence cannot be witnessed.", next_action: "Fix the verification recipe in the checkout so it prints real output, then recheck readiness. You do not need to author test commands for the agent." },
122
122
  execution_contract_failed: { class: "contract", disposition: "rework", responsible_party: "conduit", message: "The agent could not satisfy the approved execution contract.", next_action: "Review the last run and rework the same contract; change the plan only if its authority or outcome is wrong." },
123
123
  agent_no_land_commit: { class: "contract", disposition: "rework", responsible_party: "conduit", message: "The agent finished without committing the repository changes this package requires.", next_action: "Retry implement. Conductor will brief a land-focused recovery attempt — you do not need to edit technical constraints." },
@@ -790,18 +790,25 @@ export async function executeNextInvestigation(client, config, workspace, brief,
790
790
  : undefined;
791
791
  // T126: the prompt names the commands of the repository this lane opened — not the control
792
792
  // plane's idea of them — and carries the diff stat Bridge computed, since the lane cannot run git.
793
+ // Discover those commands from the delivered worktree, not the source checkout: a greenfield
794
+ // delivery can introduce its manifest and test gate in the commit this investigation verifies.
793
795
  const deliveryVerification = isDeliveryVerification(assignment);
796
+ const investigationBrief = deliveryVerification
797
+ ? await buildWorkspaceBrief(attemptWorkspace)
798
+ : liveBrief;
799
+ const verificationCommands = investigationBrief?.verification ?? [];
800
+ const declaredVerificationCommands = investigationBrief?.declared_verification ?? [];
794
801
  const gatesRun = deliveryVerification
795
802
  ? await runDeliveryVerificationGates({
796
803
  workspace: attemptWorkspace,
797
- verificationCommands: liveBrief?.verification ?? [],
798
- declaredVerificationCommands: liveBrief?.declared_verification ?? [],
804
+ verificationCommands,
805
+ declaredVerificationCommands,
799
806
  acceptance: assignment.acceptance ?? [],
800
807
  runCommand: options.runVerificationCommand,
801
808
  })
802
809
  : [];
803
810
  const context = {
804
- verificationCommands: liveBrief?.verification ?? [],
811
+ verificationCommands,
805
812
  diffStat: assignment.base_commit ? await diffStatSince(attemptWorkspace, assignment.base_commit) : null,
806
813
  gatesRun,
807
814
  };
@@ -815,7 +822,7 @@ export async function executeNextInvestigation(client, config, workspace, brief,
815
822
  workspace: attemptWorkspace,
816
823
  ...(selection.model ? { model: selection.model } : {}),
817
824
  grants: assignment.grants,
818
- verificationCommands: liveBrief?.verification ?? [],
825
+ verificationCommands,
819
826
  deliverable: "repository",
820
827
  // The same signal the read-only diagnosis lane uses; it is what denies edits in the driver.
821
828
  workRole: "diagnose",
@@ -33,7 +33,7 @@ async function listUncommittedPaths(workspace) {
33
33
  export async function isLandTreeEmpty(input) {
34
34
  if (!requiresLandCommit({ grants: input.grants, spec: input.spec }))
35
35
  return false;
36
- const base = input.spec.repository?.base_commit;
36
+ const base = input.baseCommit ?? input.spec.repository?.base_commit;
37
37
  if (!base)
38
38
  return false;
39
39
  const countAhead = input.countCommitsAhead ?? commitsAheadOfBase;
@@ -8,6 +8,7 @@ import { expandOpsValue } from "./ops.js";
8
8
  import { ensureCheckout } from "./checkout.js";
9
9
  import { bootstrapManagedWorkspace } from "./workspace-bootstrap.js";
10
10
  import { managedWorkspacePath } from "./managed-workspace-path.js";
11
+ import { refreshSourceWorkspace } from "./workspace-refresh.js";
11
12
  export { managedWorkspacePath } from "./managed-workspace-path.js";
12
13
  function pathsEqual(left, right) {
13
14
  return resolve(expandOpsValue(left)) === resolve(expandOpsValue(right));
@@ -32,6 +33,21 @@ export async function switchManagedWorkspace(managedRoot, repositoryUrl, deps =
32
33
  if (result === "cloned") {
33
34
  console.log(`Cloned ${repositoryUrl} into ${target}`);
34
35
  (deps.bootstrapWorkspace ?? bootstrapManagedWorkspace)(target);
36
+ return target;
37
+ }
38
+ // The runner's own refresh follows only the workspace it was started on. A managed checkout it
39
+ // switches into was never refreshed: acme-sim stayed shallow at a five-day-old main on
40
+ // 2026-09-25 while every claim read it. Follow origin here, before the claim reads the checkout.
41
+ // A dirty or diverged checkout is not moved; the attempt worktree refuses a dirty source.
42
+ const refresh = await refreshSourceWorkspace(target).catch(() => null);
43
+ if (refresh?.state === "fast_forwarded") {
44
+ console.log(`Managed workspace ${target} fast-forwarded to origin/${refresh.branch}.`);
45
+ }
46
+ else if (refresh?.state === "diverged") {
47
+ console.error(`Managed workspace ${target} cannot fast-forward: ${refresh.local_commits} local-only commit(s) on ${refresh.branch}. Park or push them.`);
48
+ }
49
+ else if (refresh?.state !== "up_to_date") {
50
+ console.error(`Managed workspace ${target} could not follow origin (dirty tree, detached HEAD, or fetch failed).`);
35
51
  }
36
52
  return target;
37
53
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miraland-labs/conduit-bridge",
3
- "version": "0.16.121",
3
+ "version": "0.16.130",
4
4
  "description": "Conduit Bridge CLI \u2014 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": {