@coreplane/switchboard 1.265.0 → 1.265.1

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.
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "switchboard",
3
- "version": "1.265.0",
3
+ "version": "1.265.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "switchboard",
9
- "version": "1.265.0",
9
+ "version": "1.265.1",
10
10
  "license": "Apache-2.0",
11
11
  "workspaces": [
12
12
  "web",
@@ -21060,7 +21060,7 @@
21060
21060
  },
21061
21061
  "packages/switchboard": {
21062
21062
  "name": "@coreplane/switchboard",
21063
- "version": "1.265.0",
21063
+ "version": "1.265.1",
21064
21064
  "license": "Apache-2.0",
21065
21065
  "dependencies": {
21066
21066
  "@earendil-works/pi-ai": "0.85.1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "switchboard",
3
- "version": "1.265.0",
3
+ "version": "1.265.1",
4
4
  "private": true,
5
5
  "description": "Mention it in Slack and an agent reviews the PR, ships the fix, or answers the question — on the model you choose, with its tools running where you decide.",
6
6
  "license": "Apache-2.0",
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.265.0",
3
- "commit": "39607a27b4b5751330311c08f9068a6bc007ca80",
4
- "builtAt": "2026-09-26T04:13:47.389Z"
2
+ "version": "1.265.1",
3
+ "commit": "dccb10815d97823de2be35d9768379a2d9ff6aaf",
4
+ "builtAt": "2026-09-26T14:55:53.149Z"
5
5
  }
@@ -0,0 +1,173 @@
1
+ import type { ExistingPrPublicationBinding } from "./coordinator/contract.js";
2
+ import { COMMAND_CAP, TOOL_OUTPUT_CAP, type RunEvent } from "./runEvents.js";
3
+
4
+ export interface PublicationPushReceipt {
5
+ callId: string;
6
+ previousHeadSha: string;
7
+ repo: string;
8
+ pr: number;
9
+ owner: ExistingPrPublicationBinding["owner"];
10
+ }
11
+
12
+ type PushEvent = Extract<RunEvent, { type: "pushed_head" }>;
13
+ const fullSha = (s: string): boolean => /^[a-f0-9]{40}$/.test(s);
14
+ const refName = (s: string): boolean =>
15
+ /^[a-zA-Z0-9_/-]+(?:\.[a-zA-Z0-9_/-]+)*$/.test(s) && !s.includes("..") && !s.startsWith("-");
16
+ const shortRef = (s: string): string => s.replace(/^refs\/heads\//, "");
17
+
18
+ /** Deliberately not a shell interpreter. Only a standalone literal push can
19
+ * attest its result: pipelines, scripts, substitutions and compound commands
20
+ * cannot prove which operation produced stdout or the successful exit. */
21
+ export function leasedPushCommand(command: string): { ref: string; expectedHeadSha: string } | undefined {
22
+ if (command.length >= COMMAND_CAP) return;
23
+ const literal = command.replace(/[ \t]+2>&1[ \t]*$/, "");
24
+ if (!/^git push\s/.test(literal) || /[\n\r'"`$;|<>\\&]/.test(literal)) return;
25
+ const words = literal.trim().split(/\s+/).slice(2);
26
+ const leases = words.filter((w) => w.startsWith("--force-with-lease="));
27
+ if (leases.length !== 1) return;
28
+ const lease = /^--force-with-lease=refs\/heads\/([^:]+):([a-f0-9]{40})$/.exec(leases[0]!);
29
+ if (!lease || !refName(lease[1]!)) return;
30
+ const args = words.filter((w) => w !== leases[0] && w !== "-u" && w !== "--set-upstream");
31
+ if (args.length !== 2 || args[0] !== "origin") return;
32
+ const refs = args[1]!.split(":");
33
+ if (refs.length > 2 || shortRef(refs[0]!) !== lease[1] || shortRef(refs[1] ?? refs[0]!) !== lease[1]) return;
34
+ return { ref: lease[1]!, expectedHeadSha: lease[2]! };
35
+ }
36
+
37
+ /** A legacy record needs the complete pair, never its display summary, an
38
+ * assistant's prose or the remote head alone. More than one attempted push is
39
+ * intentionally ambiguous; historical reconciliation does not choose one. */
40
+ export function pairedPublicationPush(
41
+ events: readonly RunEvent[],
42
+ binding: ExistingPrPublicationBinding,
43
+ head: string,
44
+ callId?: string,
45
+ ): PushEvent | undefined {
46
+ if (!fullSha(head) || !fullSha(binding.expectedHeadSha) || head === binding.expectedHeadSha) return;
47
+ const calls = events.filter(
48
+ (e): e is Extract<RunEvent, { type: "tool_call" }> =>
49
+ e.type === "tool_call" &&
50
+ e.tool === "bash" &&
51
+ (callId === undefined ? /\bgit\s+push\b/.test(e.command ?? e.summary) : e.callId === callId),
52
+ );
53
+ if (calls.length !== 1) return;
54
+ const call = calls[0]!;
55
+ if (
56
+ !call.callId ||
57
+ !call.command ||
58
+ events.filter((e) => e.type === "tool_call" && e.callId === call.callId).length !== 1
59
+ )
60
+ return;
61
+ const command = leasedPushCommand(call.command);
62
+ if (command?.ref !== binding.publicationRef || command.expectedHeadSha !== binding.expectedHeadSha) return;
63
+ const results = events.filter(
64
+ (e): e is Extract<RunEvent, { type: "tool_result" }> => e.type === "tool_result" && e.callId === call.callId,
65
+ );
66
+ if (results.length !== 1) return;
67
+ const result = results[0]!;
68
+ if (
69
+ events.indexOf(result) <= events.indexOf(call) ||
70
+ result.tool !== "bash" ||
71
+ !result.ok ||
72
+ result.exitCode !== 0 ||
73
+ result.cut ||
74
+ !result.output ||
75
+ result.output.length >= TOOL_OUTPUT_CAP
76
+ )
77
+ return;
78
+ let lines = result.output.trim().split(/\r?\n/);
79
+ const tracking = `branch '${binding.publicationRef}' set up to track 'origin/${binding.publicationRef}'.`;
80
+ if (
81
+ /(?:^|\s)(?:-u|--set-upstream)(?:\s|$)/.test(call.command) &&
82
+ lines.filter((line) => line === tracking).length === 1
83
+ )
84
+ lines = lines.filter((line) => line !== tracking);
85
+ if (lines.length !== 2) return;
86
+ const remote = /^To (?:https:\/\/github\.com\/|git@github\.com:|github\.com:)([^\s]+?)(?:\.git)?$/.exec(lines[0]!);
87
+ const update = /^\s*\+?\s*([a-f0-9]{7,40})(\.{2,3})([a-f0-9]{7,40})\s+(\S+) -> (\S+)( \(forced update\))?$/.exec(
88
+ lines[1]!,
89
+ );
90
+ if (
91
+ !remote ||
92
+ remote[1]!.toLowerCase() !== binding.repo.toLowerCase() ||
93
+ !update ||
94
+ !binding.expectedHeadSha.startsWith(update[1]!) ||
95
+ !head.startsWith(update[3]!) ||
96
+ update[1] === update[3] ||
97
+ shortRef(update[4]!) !== binding.publicationRef ||
98
+ shortRef(update[5]!) !== binding.publicationRef
99
+ )
100
+ return;
101
+ return {
102
+ type: "pushed_head",
103
+ ref: binding.publicationRef,
104
+ sha: head,
105
+ by: "push",
106
+ receipt: {
107
+ callId: call.callId,
108
+ previousHeadSha: binding.expectedHeadSha,
109
+ repo: binding.repo,
110
+ pr: binding.pr,
111
+ owner: { ...binding.owner },
112
+ },
113
+ };
114
+ }
115
+
116
+ /** State is stored JSON, not an unchecked cast back into publication authority. */
117
+ export function publicationReceiptsFromState(value: unknown): PushEvent[] {
118
+ if (!Array.isArray(value)) return [];
119
+ const valid = value.every((v) => {
120
+ if (typeof v !== "object" || v === null) return false;
121
+ const r = v.receipt;
122
+ return (
123
+ v.type === "pushed_head" &&
124
+ v.by === "push" &&
125
+ typeof v.ref === "string" &&
126
+ refName(v.ref) &&
127
+ typeof v.sha === "string" &&
128
+ fullSha(v.sha) &&
129
+ typeof r === "object" &&
130
+ r !== null &&
131
+ typeof r.callId === "string" &&
132
+ r.callId.length > 0 &&
133
+ typeof r.previousHeadSha === "string" &&
134
+ fullSha(r.previousHeadSha) &&
135
+ typeof r.repo === "string" &&
136
+ Number.isSafeInteger(r.pr) &&
137
+ r.pr > 0 &&
138
+ typeof r.owner === "object" &&
139
+ r.owner !== null &&
140
+ typeof r.owner.instanceId === "string" &&
141
+ typeof r.owner.unit === "string"
142
+ );
143
+ });
144
+ return valid ? ([...value] as PushEvent[]) : [];
145
+ }
146
+
147
+ /** Only the run's typed, contiguous leased transitions can move its restart
148
+ * fence. The caller still verifies the fresh PR and attached workspace. */
149
+ export function restoredPublicationHead(
150
+ events: readonly RunEvent[],
151
+ binding: ExistingPrPublicationBinding,
152
+ ): string | undefined {
153
+ let head = binding.expectedHeadSha;
154
+ const seen = new Set<string>();
155
+ for (const e of events) {
156
+ if (e.type !== "pushed_head" || e.receipt === undefined) continue;
157
+ const r = e.receipt;
158
+ if (
159
+ e.ref !== binding.publicationRef ||
160
+ r.repo !== binding.repo ||
161
+ r.pr !== binding.pr ||
162
+ r.owner.instanceId !== binding.owner.instanceId ||
163
+ r.owner.unit !== binding.owner.unit ||
164
+ r.previousHeadSha !== head ||
165
+ !fullSha(e.sha) ||
166
+ seen.has(r.callId)
167
+ )
168
+ return;
169
+ seen.add(r.callId);
170
+ head = e.sha;
171
+ }
172
+ return head === binding.expectedHeadSha ? undefined : head;
173
+ }
@@ -944,12 +944,23 @@ export type RunEvent =
944
944
  ref: string;
945
945
  sha: string;
946
946
  by: "push" | "salvage";
947
+ /** Exact leased tool result, retained before any post-step can refuse. */
948
+ receipt?: import("./publicationPush.js").PublicationPushReceipt;
947
949
  /** No uncommitted or unpushed work at the push (record 0064): the fact
948
950
  * the plane's soft stop reads. Absent where the measure was missing. */
949
951
  clean?: boolean;
950
952
  seq?: number;
951
953
  at?: number;
952
954
  }
955
+ /** The server gate admitted this exact leased push, not a child's claim. */
956
+ | {
957
+ type: "publication_push_authorized";
958
+ callId: string;
959
+ ref: string;
960
+ expectedHeadSha: string;
961
+ seq?: number;
962
+ at?: number;
963
+ }
953
964
  /** The coordinator tag as a fact of the run (docs/reference/specs/run-history.md
954
965
  * item 48a): the instance the run is a child of, the unit its idempotency
955
966
  * key named, and the base branch its pull request targets — published by
package/dist/cli.js CHANGED
@@ -36249,6 +36249,8 @@ function activityLine(e) {
36249
36249
  case "pr_opened":
36250
36250
  return "PR opened";
36251
36251
  // published straight to the registry — never arrives here
36252
+ case "publication_push_authorized":
36253
+ return "push authorized";
36252
36254
  case "pushed_head":
36253
36255
  return `\u2B06 pushed ${e.ref} @ ${e.sha.slice(0, 7)}`;
36254
36256
  case "coordinator_tag":
@@ -50261,6 +50263,11 @@ function reachFor(identity2) {
50261
50263
  if (identity2 === "read") return READ_REACH;
50262
50264
  return NONE_REACH;
50263
50265
  }
50266
+ function publicationAttributionRefusal(rules, callId) {
50267
+ const pending2 = rules.publication?.attributingCallId;
50268
+ if (pending2 !== void 0 && pending2 !== callId)
50269
+ return "push attribution is still pending; no later tool may change the checkout until its result is recorded";
50270
+ }
50264
50271
  function openCodeToolWord(action) {
50265
50272
  const mapped = OPENCODE_ACTION_TO_TOOL_WORD[action];
50266
50273
  if (mapped !== void 0) return mapped;
@@ -50464,6 +50471,98 @@ var init_toolRules = __esm({
50464
50471
  }
50465
50472
  });
50466
50473
 
50474
+ // ../../src/core/publicationPush.ts
50475
+ function leasedPushCommand(command2) {
50476
+ if (command2.length >= COMMAND_CAP) return;
50477
+ const literal = command2.replace(/[ \t]+2>&1[ \t]*$/, "");
50478
+ if (!/^git push\s/.test(literal) || /[\n\r'"`$;|<>\\&]/.test(literal)) return;
50479
+ const words = literal.trim().split(/\s+/).slice(2);
50480
+ const leases = words.filter((w) => w.startsWith("--force-with-lease="));
50481
+ if (leases.length !== 1) return;
50482
+ const lease = /^--force-with-lease=refs\/heads\/([^:]+):([a-f0-9]{40})$/.exec(leases[0]);
50483
+ if (!lease || !refName(lease[1])) return;
50484
+ const args = words.filter((w) => w !== leases[0] && w !== "-u" && w !== "--set-upstream");
50485
+ if (args.length !== 2 || args[0] !== "origin") return;
50486
+ const refs = args[1].split(":");
50487
+ if (refs.length > 2 || shortRef(refs[0]) !== lease[1] || shortRef(refs[1] ?? refs[0]) !== lease[1]) return;
50488
+ return { ref: lease[1], expectedHeadSha: lease[2] };
50489
+ }
50490
+ function pairedPublicationPush(events, binding, head, callId) {
50491
+ if (!fullSha(head) || !fullSha(binding.expectedHeadSha) || head === binding.expectedHeadSha) return;
50492
+ const calls = events.filter(
50493
+ (e) => e.type === "tool_call" && e.tool === "bash" && (callId === void 0 ? /\bgit\s+push\b/.test(e.command ?? e.summary) : e.callId === callId)
50494
+ );
50495
+ if (calls.length !== 1) return;
50496
+ const call2 = calls[0];
50497
+ if (!call2.callId || !call2.command || events.filter((e) => e.type === "tool_call" && e.callId === call2.callId).length !== 1)
50498
+ return;
50499
+ const command2 = leasedPushCommand(call2.command);
50500
+ if (command2?.ref !== binding.publicationRef || command2.expectedHeadSha !== binding.expectedHeadSha) return;
50501
+ const results = events.filter(
50502
+ (e) => e.type === "tool_result" && e.callId === call2.callId
50503
+ );
50504
+ if (results.length !== 1) return;
50505
+ const result = results[0];
50506
+ if (events.indexOf(result) <= events.indexOf(call2) || result.tool !== "bash" || !result.ok || result.exitCode !== 0 || result.cut || !result.output || result.output.length >= TOOL_OUTPUT_CAP)
50507
+ return;
50508
+ let lines = result.output.trim().split(/\r?\n/);
50509
+ const tracking = `branch '${binding.publicationRef}' set up to track 'origin/${binding.publicationRef}'.`;
50510
+ if (/(?:^|\s)(?:-u|--set-upstream)(?:\s|$)/.test(call2.command) && lines.filter((line4) => line4 === tracking).length === 1)
50511
+ lines = lines.filter((line4) => line4 !== tracking);
50512
+ if (lines.length !== 2) return;
50513
+ const remote = /^To (?:https:\/\/github\.com\/|git@github\.com:|github\.com:)([^\s]+?)(?:\.git)?$/.exec(lines[0]);
50514
+ const update = /^\s*\+?\s*([a-f0-9]{7,40})(\.{2,3})([a-f0-9]{7,40})\s+(\S+) -> (\S+)( \(forced update\))?$/.exec(
50515
+ lines[1]
50516
+ );
50517
+ if (!remote || remote[1].toLowerCase() !== binding.repo.toLowerCase() || !update || !binding.expectedHeadSha.startsWith(update[1]) || !head.startsWith(update[3]) || update[1] === update[3] || shortRef(update[4]) !== binding.publicationRef || shortRef(update[5]) !== binding.publicationRef)
50518
+ return;
50519
+ return {
50520
+ type: "pushed_head",
50521
+ ref: binding.publicationRef,
50522
+ sha: head,
50523
+ by: "push",
50524
+ receipt: {
50525
+ callId: call2.callId,
50526
+ previousHeadSha: binding.expectedHeadSha,
50527
+ repo: binding.repo,
50528
+ pr: binding.pr,
50529
+ owner: { ...binding.owner }
50530
+ }
50531
+ };
50532
+ }
50533
+ function publicationReceiptsFromState(value) {
50534
+ if (!Array.isArray(value)) return [];
50535
+ const valid = value.every((v) => {
50536
+ if (typeof v !== "object" || v === null) return false;
50537
+ const r = v.receipt;
50538
+ return v.type === "pushed_head" && v.by === "push" && typeof v.ref === "string" && refName(v.ref) && typeof v.sha === "string" && fullSha(v.sha) && typeof r === "object" && r !== null && typeof r.callId === "string" && r.callId.length > 0 && typeof r.previousHeadSha === "string" && fullSha(r.previousHeadSha) && typeof r.repo === "string" && Number.isSafeInteger(r.pr) && r.pr > 0 && typeof r.owner === "object" && r.owner !== null && typeof r.owner.instanceId === "string" && typeof r.owner.unit === "string";
50539
+ });
50540
+ return valid ? [...value] : [];
50541
+ }
50542
+ function restoredPublicationHead(events, binding) {
50543
+ let head = binding.expectedHeadSha;
50544
+ const seen = /* @__PURE__ */ new Set();
50545
+ for (const e of events) {
50546
+ if (e.type !== "pushed_head" || e.receipt === void 0) continue;
50547
+ const r = e.receipt;
50548
+ if (e.ref !== binding.publicationRef || r.repo !== binding.repo || r.pr !== binding.pr || r.owner.instanceId !== binding.owner.instanceId || r.owner.unit !== binding.owner.unit || r.previousHeadSha !== head || !fullSha(e.sha) || seen.has(r.callId))
50549
+ return;
50550
+ seen.add(r.callId);
50551
+ head = e.sha;
50552
+ }
50553
+ return head === binding.expectedHeadSha ? void 0 : head;
50554
+ }
50555
+ var fullSha, refName, shortRef;
50556
+ var init_publicationPush = __esm({
50557
+ "../../src/core/publicationPush.ts"() {
50558
+ "use strict";
50559
+ init_runEvents();
50560
+ fullSha = (s) => /^[a-f0-9]{40}$/.test(s);
50561
+ refName = (s) => /^[a-zA-Z0-9_/-]+(?:\.[a-zA-Z0-9_/-]+)*$/.test(s) && !s.includes("..") && !s.startsWith("-");
50562
+ shortRef = (s) => s.replace(/^refs\/heads\//, "");
50563
+ }
50564
+ });
50565
+
50467
50566
  // ../../src/core/harness/pi/relay.ts
50468
50567
  function stillRunningNote(tool) {
50469
50568
  return `This ${tool} call is still running in the bot: the process that made it was relaunched while the call was in flight, and the call keeps running there rather than being re-run \u2014 do not run it again; its result is kept on the relay under the same call id.`;
@@ -50494,9 +50593,18 @@ function authorizeToolCall(harness, ask) {
50494
50593
  return { allow: false, reason: reason2 };
50495
50594
  };
50496
50595
  if (blocked2 !== void 0) return refuse3(blocked2);
50596
+ const pending2 = publicationAttributionRefusal(harness.rules, ask.toolCallId);
50597
+ if (pending2 !== void 0) return refuse3(pending2);
50497
50598
  if (harness.tools.some((t) => t.name === ask.tool)) return { allow: true };
50498
50599
  const verdict = judgeToolCall(ask.tool, ask.input, harness.rules);
50499
- if (verdict.verdict === "allowed") return { allow: true };
50600
+ if (verdict.verdict === "allowed") {
50601
+ const authority = harness.rules.publication?.authority;
50602
+ const input = ask.input;
50603
+ const push = ask.tool === "bash" && typeof input?.command === "string" ? leasedPushCommand(input.command) : void 0;
50604
+ if (push !== void 0 && authority !== void 0 && !("blocked" in authority) && push.ref === authority.ref && push.expectedHeadSha === authority.expectedHeadSha)
50605
+ harness.emit({ type: "publication_push_authorized", callId: ask.toolCallId, ...push });
50606
+ return { allow: true };
50607
+ }
50500
50608
  return refuse3(verdict.reason);
50501
50609
  }
50502
50610
  function answerCompaction(harness, ask) {
@@ -50563,6 +50671,7 @@ var init_relay = __esm({
50563
50671
  init_runEvents();
50564
50672
  init_compactionFallback();
50565
50673
  init_toolRules();
50674
+ init_publicationPush();
50566
50675
  HarnessRegistry = class {
50567
50676
  live = /* @__PURE__ */ new Map();
50568
50677
  /** The run drives a pi from here, its relayed calls kept beside it; the
@@ -52376,19 +52485,19 @@ var init_resume = __esm({
52376
52485
  // ../../src/core/existingPrPublication.ts
52377
52486
  function verifyExistingPrPublication(durable, local, remote) {
52378
52487
  if (durable === void 0) return blocked("the durable existing-PR binding is missing");
52379
- if (!fullSha(durable.expectedHeadSha)) return blocked("the durable expected head is not a full commit SHA");
52488
+ if (!fullSha2(durable.expectedHeadSha)) return blocked("the durable expected head is not a full commit SHA");
52380
52489
  if (durable.headRef !== durable.publicationRef)
52381
52490
  return blocked("the durable head ref and owned publication ref do not agree");
52382
52491
  if (local.repo !== durable.repo) return blocked("the resolved repository does not match the durable binding");
52383
52492
  if (local.pr !== durable.pr) return blocked("the resolved pull request does not match the durable binding");
52384
52493
  if (local.ref !== durable.headRef) return blocked("the resolved head ref does not match the durable binding");
52385
52494
  if (local.baseRef !== durable.baseRef) return blocked("the resolved base ref does not match the durable binding");
52386
- if (!fullSha(local.requestHeadSha)) return blocked("the request head is missing or not a full commit SHA");
52495
+ if (!fullSha2(local.requestHeadSha)) return blocked("the request head is missing or not a full commit SHA");
52387
52496
  if (local.requestHeadSha.toLowerCase() !== durable.expectedHeadSha.toLowerCase())
52388
52497
  return blocked("the request head does not match the durable expected commit");
52389
52498
  if (local.workspaceRef !== durable.publicationRef)
52390
52499
  return blocked("the checked-out publication ref does not match the durable binding");
52391
- if (!fullSha(local.workspaceHeadSha)) return blocked("the checked-out head is missing or not a full commit SHA");
52500
+ if (!fullSha2(local.workspaceHeadSha)) return blocked("the checked-out head is missing or not a full commit SHA");
52392
52501
  if (local.workspaceHeadSha.toLowerCase() !== durable.expectedHeadSha.toLowerCase())
52393
52502
  return blocked("the checked-out head does not match the durable expected commit");
52394
52503
  if (!sameOwner(local.owner, durable.owner)) return blocked("the publication owner changed");
@@ -52398,7 +52507,7 @@ function verifyExistingPrPublication(durable, local, remote) {
52398
52507
  if (remote.headBranchExists !== true) return blocked("the pull request head branch is missing or unknown");
52399
52508
  if (remote.headRef !== durable.headRef) return blocked("the pull request head ref moved");
52400
52509
  if (remote.baseRef !== durable.baseRef) return blocked("the pull request base ref moved");
52401
- if (!fullSha(remote.headSha)) return blocked("the fresh pull-request head is missing or not a full commit SHA");
52510
+ if (!fullSha2(remote.headSha)) return blocked("the fresh pull-request head is missing or not a full commit SHA");
52402
52511
  if (remote.headSha.toLowerCase() !== durable.expectedHeadSha.toLowerCase())
52403
52512
  return blocked("the pull request head moved from the durable expected commit");
52404
52513
  return {
@@ -52406,11 +52515,11 @@ function verifyExistingPrPublication(durable, local, remote) {
52406
52515
  publication: { ref: durable.publicationRef, expectedHeadSha: durable.expectedHeadSha.toLowerCase() }
52407
52516
  };
52408
52517
  }
52409
- var fullSha, sameOwner, blocked;
52518
+ var fullSha2, sameOwner, blocked;
52410
52519
  var init_existingPrPublication = __esm({
52411
52520
  "../../src/core/existingPrPublication.ts"() {
52412
52521
  "use strict";
52413
- fullSha = (value) => value !== void 0 && /^[0-9a-f]{40}$/i.test(value);
52522
+ fullSha2 = (value) => value !== void 0 && /^[0-9a-f]{40}$/i.test(value);
52414
52523
  sameOwner = (left, right) => left?.instanceId === right.instanceId && left.unit === right.unit;
52415
52524
  blocked = (reason2) => ({ ok: false, reason: reason2 });
52416
52525
  }
@@ -53437,6 +53546,14 @@ async function runLoop(deps, ctx) {
53437
53546
  let reviewHead = ctx.reviewHead;
53438
53547
  let lastActivityAt = ctx.loopStartedAt;
53439
53548
  const restored = resume?.row.state ?? {};
53549
+ const restoredReceipts = publicationReceiptsFromState(restored.publicationReceipts);
53550
+ const publicationReceipts = coordinator?.publication !== void 0 && restoredPublicationHead(restoredReceipts, coordinator.publication) !== void 0 ? restoredReceipts : [];
53551
+ const retainPublicationReceipts = () => {
53552
+ const history = registry.snapshot(run2.id, run2.token)?.events ?? [];
53553
+ const latest = publicationReceipts.at(-1);
53554
+ if (latest !== void 0 && !history.some((e) => e.type === "pushed_head" && e.ref === latest.ref))
53555
+ registry.publish(run2.id, latest);
53556
+ };
53440
53557
  let checklist = typeof restored.checklist === "string" ? restored.checklist : void 0;
53441
53558
  let lastActivity;
53442
53559
  let inFlightTool;
@@ -53473,6 +53590,23 @@ async function runLoop(deps, ctx) {
53473
53590
  let budgetEnded = false;
53474
53591
  let recordedPushedBranch;
53475
53592
  let modelBudgetEndsAt;
53593
+ const receiptAtToolResult = async (e) => {
53594
+ const binding2 = coordinator?.publication;
53595
+ const authority = existingPrPublicationFence?.authority;
53596
+ if (e.type !== "tool_result" || e.tool !== "bash" || !e.ok || e.exitCode !== 0 || e.cut || binding2 === void 0 || authority === void 0 || "blocked" in authority)
53597
+ return;
53598
+ const history = registry.snapshot(run2.id, run2.token)?.events ?? [];
53599
+ const gates = history.filter((event) => event.type === "publication_push_authorized" && event.callId === e.callId);
53600
+ if (gates.length !== 1 || gates[0]?.type !== "publication_push_authorized" || gates[0].ref !== authority.ref || gates[0].expectedHeadSha !== authority.expectedHeadSha)
53601
+ return;
53602
+ try {
53603
+ const head = (await executor.exec(`git rev-parse refs/heads/${authority.ref}`)).trim();
53604
+ const current = { ...binding2, expectedHeadSha: authority.expectedHeadSha };
53605
+ return pairedPublicationPush([...history, e], current, head, e.callId);
53606
+ } catch {
53607
+ return;
53608
+ }
53609
+ };
53476
53610
  const publishEvent = (e, startsRunBudget) => {
53477
53611
  registry.publish(run2.id, e);
53478
53612
  if (isSpanRecord(e)) return;
@@ -53497,12 +53631,16 @@ async function runLoop(deps, ctx) {
53497
53631
  card.update(currentFrame());
53498
53632
  };
53499
53633
  const onEvent = (e) => {
53634
+ if (e.type === "publication_push_authorized" && existingPrPublicationFence !== void 0)
53635
+ existingPrPublicationFence.attributingCallId = e.callId;
53500
53636
  const startsRunBudget = e.type === "lease";
53501
53637
  if (startsRunBudget) {
53502
53638
  modelBudgetEndsAt = e.endsAt;
53503
53639
  run2.control.startLease(() => e.endsAt - clock4());
53504
53640
  }
53505
53641
  void events.write(async () => {
53642
+ const receipt = await receiptAtToolResult(e);
53643
+ let receiptCommitted = false;
53506
53644
  if ((e.type === "tool_call" || e.type === "tool_result") && typeof registry.commitLiveState === "function") {
53507
53645
  const summary = registry.getById(run2.id);
53508
53646
  if (summary?.liveState?.state === "working") {
@@ -53516,12 +53654,16 @@ async function runLoop(deps, ctx) {
53516
53654
  state: "working",
53517
53655
  bound,
53518
53656
  detail: e.type === "tool_call" ? "running a tool" : "model turn",
53519
- sourceEvents: [{ ...e, seq: sourceSeq }]
53657
+ sourceEvents: [{ ...e, seq: sourceSeq }, ...receipt ? [{ ...receipt, seq: sourceSeq + 1, at }] : []],
53658
+ ...receipt ? { statePatch: { publicationReceipts: [...publicationReceipts, receipt] } } : {}
53520
53659
  };
53521
53660
  try {
53522
53661
  if (ledgerRun?.tracked()) {
53523
53662
  const committed = await ledgerRun.assignLiveState(assignment);
53524
- if (committed.ok) registry.commitLiveState(run2.id, committed);
53663
+ if (committed.ok) {
53664
+ registry.commitLiveState(run2.id, committed);
53665
+ receiptCommitted = true;
53666
+ }
53525
53667
  } else {
53526
53668
  const local = assignRunLiveState(summary.liveState, summary.liveStateSeq ?? 0, assignment);
53527
53669
  if (local.ok) registry.commitLiveState(run2.id, { ...local, liveStateSeq: sourceSeq });
@@ -53535,6 +53677,16 @@ async function runLoop(deps, ctx) {
53535
53677
  }
53536
53678
  }
53537
53679
  publishEvent(e, startsRunBudget);
53680
+ if (receipt !== void 0) {
53681
+ if (receiptCommitted) {
53682
+ publicationReceipts.push(receipt);
53683
+ publishEvent(receipt, false);
53684
+ existingPrPublication = { ref: receipt.ref, expectedHeadSha: receipt.sha };
53685
+ if (existingPrPublicationFence !== void 0) existingPrPublicationFence.authority = existingPrPublication;
53686
+ } else blockExistingPrPublication("the successful push receipt could not be committed durably");
53687
+ }
53688
+ if (e.type === "tool_result" && existingPrPublicationFence !== void 0 && existingPrPublicationFence.attributingCallId === e.callId)
53689
+ delete existingPrPublicationFence.attributingCallId;
53538
53690
  });
53539
53691
  };
53540
53692
  for (const s of mcpForRun?.servers ?? []) {
@@ -53686,6 +53838,8 @@ async function runLoop(deps, ctx) {
53686
53838
  };
53687
53839
  const preserveCodingChildWork = async (cue) => {
53688
53840
  if (workSalvageAttempted || !isCodingPrRun || coordinator === void 0) return;
53841
+ await events.drain();
53842
+ retainPublicationReceipts();
53689
53843
  if (!workspaceObserved) await observeWorkspaceNow();
53690
53844
  const target = coordinatorBranch === void 0 ? { skipped: "the ending checkpoint was skipped: the unit's branch is unavailable" } : salvageTargetOf({
53691
53845
  pushedBranch: pushes.branch(),
@@ -53839,6 +53993,40 @@ async function runLoop(deps, ctx) {
53839
53993
  };
53840
53994
  let workspaceBinding = workspaceBindingFor(round2.selection, profile.machine);
53841
53995
  try {
53996
+ const prBase = repoCtx.baseRef ?? await coordinatorBase;
53997
+ if (coordinator?.publication !== void 0) {
53998
+ const original = coordinator.publication;
53999
+ const restoredHead = resume === void 0 ? void 0 : restoredPublicationHead(publicationReceipts, original);
54000
+ const publication = restoredHead === void 0 ? original : { ...original, expectedHeadSha: restoredHead };
54001
+ const fresh = await (deps.fetchPrFacts ?? fetchPullRequestFacts)({
54002
+ repo: publication.repo,
54003
+ number: publication.pr
54004
+ }).catch(() => void 0);
54005
+ const verified = verifyExistingPrPublication(
54006
+ publication,
54007
+ {
54008
+ repo: repoCtx.repo,
54009
+ pr: repoCtx.pr,
54010
+ ref: repoCtx.ref,
54011
+ baseRef: prBase,
54012
+ requestHeadSha: restoredHead ?? repoCtx.headSha,
54013
+ workspaceRef: binding?.ref,
54014
+ workspaceHeadSha: binding?.sha,
54015
+ owner: {
54016
+ instanceId: coordinator.parentInstanceId,
54017
+ unit: unitOfIdempotencyKey(coordinator.idempotencyKey) ?? ""
54018
+ }
54019
+ },
54020
+ fresh
54021
+ );
54022
+ existingPrPublication = verified.ok ? verified.publication : { blocked: verified.reason };
54023
+ existingPrPublicationFence = { authority: existingPrPublication };
54024
+ if (!verified.ok)
54025
+ shell.note(
54026
+ "quiet",
54027
+ `Existing-PR publication is blocked: ${verified.reason}. Work stays on the bound checkout; no alternate branch or pull request will be published.`
54028
+ );
54029
+ }
53842
54030
  if (finish2) {
53843
54031
  onEvent({
53844
54032
  type: "run_note",
@@ -53904,38 +54092,6 @@ async function runLoop(deps, ctx) {
53904
54092
  const providerCfg = deps.config.config.providers[providerName];
53905
54093
  if (!providerCfg)
53906
54094
  throw new Error(`the ${harness.name} harness found no provider named ${providerName} in the config`);
53907
- const prBase = repoCtx.baseRef ?? await coordinatorBase;
53908
- if (coordinator?.publication !== void 0) {
53909
- const publication = coordinator.publication;
53910
- const fresh = await (deps.fetchPrFacts ?? fetchPullRequestFacts)({
53911
- repo: publication.repo,
53912
- number: publication.pr
53913
- }).catch(() => void 0);
53914
- const verified = verifyExistingPrPublication(
53915
- publication,
53916
- {
53917
- repo: repoCtx.repo,
53918
- pr: repoCtx.pr,
53919
- ref: repoCtx.ref,
53920
- baseRef: prBase,
53921
- requestHeadSha: repoCtx.headSha,
53922
- workspaceRef: binding?.ref,
53923
- workspaceHeadSha: binding?.sha,
53924
- owner: {
53925
- instanceId: coordinator.parentInstanceId,
53926
- unit: unitOfIdempotencyKey(coordinator.idempotencyKey) ?? ""
53927
- }
53928
- },
53929
- fresh
53930
- );
53931
- existingPrPublication = verified.ok ? verified.publication : { blocked: verified.reason };
53932
- existingPrPublicationFence = { authority: existingPrPublication };
53933
- if (!verified.ok)
53934
- shell.note(
53935
- "quiet",
53936
- `Existing-PR publication is blocked: ${verified.reason}. Work stays on the bound checkout; no alternate branch or pull request will be published.`
53937
- );
53938
- }
53939
54095
  const ownBranch = coordinator?.publication !== void 0 ? coordinator.publication.publicationRef : prBase !== void 0 ? binding?.ref ?? repoCtx.ref : void 0;
53940
54096
  const protectedBranches = [
53941
54097
  ...new Set(
@@ -54196,6 +54352,8 @@ async function runLoop(deps, ctx) {
54196
54352
  };
54197
54353
  const endingNeedsPreservation = isCodingPrRun && coordinator !== void 0 && (budgetEnded || run2.control.requested !== void 0);
54198
54354
  if (endingNeedsPreservation && run2.control.requested === "hard") await endHarness();
54355
+ await events.drain();
54356
+ retainPublicationReceipts();
54199
54357
  if (isCodingPrRun && !tailSkipped()) await observeWorkspaceNow();
54200
54358
  if (endingNeedsPreservation) await preserveCodingChildWork(budgetEnded ? "budget" : "ending");
54201
54359
  else if (isCodingPrRun && coordinator !== void 0 && !tailSkipped()) await preserveCodingChildWork("completion");
@@ -54411,6 +54569,7 @@ async function runLoop(deps, ctx) {
54411
54569
  } finally {
54412
54570
  clearInterval(heartbeat);
54413
54571
  await events.drain();
54572
+ retainPublicationReceipts();
54414
54573
  const status3 = statusNow();
54415
54574
  if (typeof registry.commitLiveState === "function") {
54416
54575
  const commitBoundary = async (state, at2) => {
@@ -54574,6 +54733,7 @@ var init_runLoop = __esm({
54574
54733
  init_githubPulls();
54575
54734
  init_repoContext();
54576
54735
  init_existingPrPublication();
54736
+ init_publicationPush();
54577
54737
  init_prDescription();
54578
54738
  init_handoff();
54579
54739
  init_reviewVerdict();
@@ -60848,7 +61008,7 @@ function isBudgetRefusal(error) {
60848
61008
  if (error.status !== void 0 && error.status !== 403) return false;
60849
61009
  return TURN_BUDGET_REFUSAL.test(error.message);
60850
61010
  }
60851
- function judgeOpenCodeAsk(action, resources, rules, relayedToolNames) {
61011
+ function judgeOpenCodeAsk(action, resources, rules, relayedToolNames, callId) {
60852
61012
  if (action === "doom_loop")
60853
61013
  return {
60854
61014
  reply: "reject",
@@ -60857,6 +61017,8 @@ function judgeOpenCodeAsk(action, resources, rules, relayedToolNames) {
60857
61017
  };
60858
61018
  const word = openCodeToolWord(action);
60859
61019
  const tool = TOOL_NAME_WORD[action] ?? word;
61020
+ const pending2 = publicationAttributionRefusal(rules, callId);
61021
+ if (pending2 !== void 0) return { reply: "reject", message: pending2, tool };
60860
61022
  if (relayedToolNames.has(action) || relayedToolNames.has(word)) return { reply: "once", tool: action };
60861
61023
  const refuse3 = (reason2) => ({ reply: "reject", message: reason2, tool });
60862
61024
  if (action === "external_directory") {
@@ -61677,6 +61839,7 @@ var init_bridge3 = __esm({
61677
61839
  "use strict";
61678
61840
  init_budgets();
61679
61841
  init_runEvents();
61842
+ init_publicationPush();
61680
61843
  init_contract4();
61681
61844
  init_container();
61682
61845
  init_reattach();
@@ -62544,9 +62707,14 @@ ${data.text}` : data.text;
62544
62707
  request2.action,
62545
62708
  Array.isArray(request2.resources) ? request2.resources : [],
62546
62709
  this.deps.rules,
62547
- this.deps.relayedToolNames
62710
+ this.deps.relayedToolNames,
62711
+ callId
62548
62712
  );
62549
62713
  if (this.answered.get(callId) !== "reject") this.answered.set(callId, verdict.reply);
62714
+ const authority = this.deps.rules.publication?.authority;
62715
+ const push = openCodeToolWord(request2.action) === "bash" && request2.resources?.length === 1 ? leasedPushCommand(request2.resources[0]) : void 0;
62716
+ if (this.answered.get(callId) === "once" && push !== void 0 && authority !== void 0 && !("blocked" in authority) && push.ref === authority.ref && push.expectedHeadSha === authority.expectedHeadSha)
62717
+ this.emit({ type: "publication_push_authorized", callId, ...push });
62550
62718
  this.decidedReplies.set(request2.id, { reply: verdict.reply, callId, echoed: false });
62551
62719
  const stepID = typeof request2.source?.messageID === "string" ? request2.source.messageID : void 0;
62552
62720
  if (verdict.reply === "reject") {
@@ -74048,6 +74216,36 @@ function publicationStepPrefix(row2) {
74048
74216
  }
74049
74217
  return prefix;
74050
74218
  }
74219
+ async function reconcileMissingFindingsPush(deps, instance, row2, runId3, head, siblings, after) {
74220
+ const binding = row2.publication;
74221
+ if (binding === void 0) return false;
74222
+ const read = await deps.runs.getRun(runId3, { include: "messages" });
74223
+ if (!read.ok) return false;
74224
+ const run2 = read.value;
74225
+ const complete2 = (r) => {
74226
+ const models = Object.values(r.usage?.byModel ?? {});
74227
+ return r.finished && r.persisted === true && !r.provisional && !r.restarting && r.truncated === false && r.events !== void 0 && r.eventCount === r.events.length && r.storedEventCount === r.events.length && r.events.every(
74228
+ (e) => e.type !== "tool_call" || e.tool !== "bash" || e.command !== void 0 && e.command.length < COMMAND_CAP && !e.command.includes("\u2026")
74229
+ ) && !r.events.some((e) => e.type === "tool_result" && e.cut || e.type === "pushed_head") && models.length > 0 && models.every((m) => typeof m.usd === "number" && Number.isFinite(m.usd) && m.usd >= 0);
74230
+ };
74231
+ const tags = run2.events?.filter((e) => e.type === "coordinator_tag") ?? [];
74232
+ const tag = tags.length === 1 ? tags[0] : void 0;
74233
+ if (!complete2(run2) || run2.status !== "completed" || (run2.pushed?.length ?? 0) !== 0 || run2.headSha !== head || run2.parentInstanceId !== instance.id || run2.userId !== instance.userId || run2.repo?.toLowerCase() !== instance.repo.toLowerCase() || run2.threadKey !== (row2.threadKey ?? instance.threadKey) || run2.agent !== "coding" || run2.startedAt < after || run2.finishedAt === void 0 || run2.finishedAt < run2.startedAt || tag?.parentInstanceId !== instance.id || tag.unit !== row2.unit || tag.base !== instance.base || !samePublicationBinding(tag.publication, binding) || run2.pr !== void 0 && (run2.pr.number !== binding.pr || run2.pr.head !== void 0 && run2.pr.head !== row2.branch) || pairedPublicationPush(run2.events, binding, head) === void 0)
74234
+ return false;
74235
+ for (const sibling of siblings.filter(
74236
+ (r) => r.id !== runId3 && r.agent === "coding" && (r.finishedAt === void 0 || r.finishedAt >= after)
74237
+ )) {
74238
+ if (!sibling.finished || sibling.status !== "failed" && sibling.status !== "interrupted" || sibling.parentInstanceId !== instance.id || sibling.userId !== instance.userId || sibling.repo?.toLowerCase() !== instance.repo.toLowerCase() || sibling.threadKey !== run2.threadKey || sibling.startedAt < after || sibling.finishedAt === void 0 || sibling.finishedAt > run2.startedAt || (sibling.pushed?.length ?? 0) > 0)
74239
+ return false;
74240
+ const prior = await deps.runs.getRun(sibling.id, { include: "messages" });
74241
+ if (!prior.ok || !complete2(prior.value) || prior.value.events.some(
74242
+ (e) => e.type === "pushed_head" || e.type === "tool_call" && e.tool === "bash" && /\bgit\s+push\b/.test(e.command ?? e.summary)
74243
+ ))
74244
+ return false;
74245
+ }
74246
+ const fresh = await deps.fetchPrFacts({ repo: instance.repo, number: binding.pr }).catch(() => void 0);
74247
+ return fresh?.state === "open" && fresh.sameRepoHead === true && fresh.headBranchExists === true && fresh.headRef === binding.headRef && fresh.baseRef === binding.baseRef && fresh.headSha === head && fresh.verifiedHead?.repo.toLowerCase() === instance.repo.toLowerCase() && fresh.verifiedHead.ref === binding.publicationRef && fresh.verifiedHead.sha === head;
74248
+ }
74051
74249
  async function advanceFindingsPublication(deps, instance, row2, facts2, runId3) {
74052
74250
  if (row2.publication === void 0 || facts2.headSha === row2.publication.expectedHeadSha) return row2;
74053
74251
  const child = await deps.runs.getRun(runId3, { include: "messages" });
@@ -74055,6 +74253,7 @@ async function advanceFindingsPublication(deps, instance, row2, facts2, runId3)
74055
74253
  const latestReview = [...row2.rounds].reverse().find((round2) => round2.agent === "review");
74056
74254
  const prefix = row2.recovery !== void 0 ? `${row2.unit}/recovery` : publicationStepPrefix(row2);
74057
74255
  const findingsPrefix = `${instance.id}:${prefix}/${latestReview?.index}/findings`;
74256
+ let reconciledPush = false;
74058
74257
  if (row2.recovery === void 0) {
74059
74258
  const tags = child.ok ? child.value.events?.filter((event) => event.type === "coordinator_tag") ?? [] : [];
74060
74259
  const tag = tags.length === 1 ? tags[0] : void 0;
@@ -74073,8 +74272,18 @@ async function advanceFindingsPublication(deps, instance, row2, facts2, runId3)
74073
74272
  (run2) => run2.id !== runId3 && !(run2.finished && (run2.status === "failed" || run2.status === "interrupted") && run2.agent === "coding" && run2.userId === instance.userId && run2.repo?.toLowerCase() === instance.repo.toLowerCase() && run2.threadKey === (row2.threadKey ?? instance.threadKey) && run2.startedAt >= latestReview.at && run2.finishedAt !== void 0 && run2.finishedAt >= run2.startedAt && run2.finishedAt <= child.value.startedAt && (run2.pushed?.length ?? 0) === 0)
74074
74273
  ))
74075
74274
  throw new PublicationBindingRefusal("publication_facts_mismatch");
74275
+ if (child.ok && (child.value.pushed?.length ?? 0) === 0 && fullHead(facts2.headSha))
74276
+ reconciledPush = await reconcileMissingFindingsPush(
74277
+ deps,
74278
+ instance,
74279
+ row2,
74280
+ runId3,
74281
+ facts2.headSha,
74282
+ listing.runs,
74283
+ latestReview.at
74284
+ );
74076
74285
  }
74077
- if (!child.ok || child.value.finished !== true || child.value.status !== "completed" || child.value.agent !== "coding" || child.value.parentInstanceId !== instance.id || child.value.userId !== instance.userId || child.value.repo?.toLowerCase() !== instance.repo.toLowerCase() || child.value.threadKey !== (row2.threadKey ?? instance.threadKey) || (row2.recovery !== void 0 ? child.value.idempotencyKey?.startsWith(`${instance.id}:${row2.unit}/recovery/`) !== true || !/\/findings(?:\/a[1-9][0-9]*)?$/.test(child.value.idempotencyKey ?? "") : !isStepAttempt(child.value.idempotencyKey, findingsPrefix)) || !fullHead(facts2.headSha) || child.value.headSha !== facts2.headSha || child.value.pushed?.some((push) => push.ref === row2.branch && push.sha === facts2.headSha) !== true || facts2.state !== "open" || facts2.sameRepoHead !== true || facts2.headBranchExists !== true || facts2.headRef !== row2.publication.headRef || facts2.baseRef !== row2.publication.baseRef || facts2.verifiedHead?.repo.toLowerCase() !== instance.repo.toLowerCase() || facts2.verifiedHead.ref !== row2.publication.publicationRef || facts2.verifiedHead.sha !== facts2.headSha || row2.publication.repo.toLowerCase() !== instance.repo.toLowerCase() || row2.publication.pr !== row2.pr?.number || row2.publication.baseRef !== instance.base || row2.publication.headRef !== row2.branch || row2.publication.publicationRef !== row2.branch || !samePublicationOwner(row2.publication.owner, owner))
74286
+ if (!child.ok || child.value.finished !== true || child.value.status !== "completed" || child.value.agent !== "coding" || child.value.parentInstanceId !== instance.id || child.value.userId !== instance.userId || child.value.repo?.toLowerCase() !== instance.repo.toLowerCase() || child.value.threadKey !== (row2.threadKey ?? instance.threadKey) || (row2.recovery !== void 0 ? child.value.idempotencyKey?.startsWith(`${instance.id}:${row2.unit}/recovery/`) !== true || !/\/findings(?:\/a[1-9][0-9]*)?$/.test(child.value.idempotencyKey ?? "") : !isStepAttempt(child.value.idempotencyKey, findingsPrefix)) || !fullHead(facts2.headSha) || child.value.headSha !== facts2.headSha || !reconciledPush && child.value.pushed?.some((push) => push.ref === row2.branch && push.sha === facts2.headSha) !== true || facts2.state !== "open" || facts2.sameRepoHead !== true || facts2.headBranchExists !== true || facts2.headRef !== row2.publication.headRef || facts2.baseRef !== row2.publication.baseRef || facts2.verifiedHead?.repo.toLowerCase() !== instance.repo.toLowerCase() || facts2.verifiedHead.ref !== row2.publication.publicationRef || facts2.verifiedHead.sha !== facts2.headSha || row2.publication.repo.toLowerCase() !== instance.repo.toLowerCase() || row2.publication.pr !== row2.pr?.number || row2.publication.baseRef !== instance.base || row2.publication.headRef !== row2.branch || row2.publication.publicationRef !== row2.branch || !samePublicationOwner(row2.publication.owner, owner))
74078
74287
  throw new PublicationBindingRefusal("publication_facts_mismatch");
74079
74288
  try {
74080
74289
  if (row2.recovery !== void 0 && deps.runnerOwnership?.claim(instance.repo, row2.publication.pr, owner) !== true)
@@ -74371,7 +74580,16 @@ async function recoverOriginalUnit(body, deps, caller) {
74371
74580
  const checkedAttempts = attempts.filter((run2) => run2.idempotencyKey === `${instance.id}:${checkedStep}`);
74372
74581
  const completed = checkedAttempts.length === 1 ? checkedAttempts[0] : void 0;
74373
74582
  const reviewFinishedAt = review.finishedAt;
74374
- if (reviewFinishedAt === void 0 || completed === void 0 || !completed.finished || completed.status !== "completed" || completed.agent !== "coding" || completed.userId !== instance.userId || completed.repo?.toLowerCase() !== instance.repo.toLowerCase() || completed.threadKey !== unitThreadKey || completed.pr !== void 0 && (completed.pr.number !== pr.number || completed.pr.head !== void 0 && completed.pr.head !== row2.branch) || completed.headSha !== facts2.headSha || expectedHead !== reviewedHead && expectedHead !== facts2.headSha || completed.pushed?.some((push) => push.ref !== row2.branch) === true || headMoved && completed.pushed?.some((push) => push.ref === row2.branch && push.sha === facts2.headSha) !== true || completed.startedAt < reviewFinishedAt || completed.finishedAt === void 0 || completed.finishedAt < completed.startedAt || completed.finishedAt > row2.ending.at || // Inspect every attempt, not just runs matching the current PR head:
74583
+ const reconciledPush = completed !== void 0 && headMoved && reviewFinishedAt !== void 0 && (completed.pushed?.length ?? 0) === 0 && await reconcileMissingFindingsPush(
74584
+ deps,
74585
+ instance,
74586
+ row2,
74587
+ completed.id,
74588
+ facts2.headSha,
74589
+ unitListing.runs,
74590
+ reviewFinishedAt
74591
+ );
74592
+ if (reviewFinishedAt === void 0 || completed === void 0 || !completed.finished || completed.status !== "completed" || completed.agent !== "coding" || completed.userId !== instance.userId || completed.repo?.toLowerCase() !== instance.repo.toLowerCase() || completed.threadKey !== unitThreadKey || completed.pr !== void 0 && (completed.pr.number !== pr.number || completed.pr.head !== void 0 && completed.pr.head !== row2.branch) || completed.headSha !== facts2.headSha || expectedHead !== reviewedHead && expectedHead !== facts2.headSha || completed.pushed?.some((push) => push.ref !== row2.branch) === true || headMoved && !reconciledPush && completed.pushed?.some((push) => push.ref === row2.branch && push.sha === facts2.headSha) !== true || completed.startedAt < reviewFinishedAt || completed.finishedAt === void 0 || completed.finishedAt < completed.startedAt || completed.finishedAt > row2.ending.at || // Inspect every attempt, not just runs matching the current PR head:
74375
74593
  // any competing success or push remains ambiguous after a later push.
74376
74594
  attempts.some(
74377
74595
  (run2) => run2.id !== completed.id && !(run2.finished && (run2.status === "failed" || run2.status === "interrupted") && run2.agent === "coding" && run2.userId === instance.userId && run2.repo?.toLowerCase() === instance.repo.toLowerCase() && run2.threadKey === unitThreadKey && run2.startedAt >= reviewFinishedAt && run2.finishedAt !== void 0 && run2.finishedAt >= run2.startedAt && run2.finishedAt <= completed.startedAt && (run2.pushed?.length ?? 0) === 0)
@@ -76035,6 +76253,7 @@ var init_adminCoordinator = __esm({
76035
76253
  "use strict";
76036
76254
  init_budgets();
76037
76255
  init_verbosity();
76256
+ init_publicationPush();
76038
76257
  init_prDescription();
76039
76258
  init_reply();
76040
76259
  init_registry();
@@ -76049,6 +76268,7 @@ var init_adminCoordinator = __esm({
76049
76268
  init_effort();
76050
76269
  init_reviewVerdict();
76051
76270
  init_runFriction();
76271
+ init_runEvents();
76052
76272
  init_runRecord();
76053
76273
  init_coordinator();
76054
76274
  init_renewal();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coreplane/switchboard",
3
- "version": "1.265.0",
3
+ "version": "1.265.1",
4
4
  "description": "Mention it in Slack and an agent reviews the PR, ships the fix, or answers the question — on the model you choose, with its tools running where you decide.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://openswitchboard.dev",