@bridge_gpt/mcp-server 0.2.68 → 0.2.69

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.
@@ -235,6 +235,8 @@ export const END_CAUSE_VALUES = [
235
235
  "worker_exit", "completion_window", "job_timeout", "executor_abort",
236
236
  "executor_shutdown", "server_stop", "lease_lost",
237
237
  ];
238
+ /** BAPI-1421 (F4) — the end causes an executor may report (`lease_lost` is server-derived). */
239
+ export const EXECUTOR_REPORTABLE_END_CAUSE_VALUES = END_CAUSE_VALUES.filter((value) => value !== "lease_lost");
238
240
  export const MAX_TASKS = 64;
239
241
  export const MAX_DENIALS = 32;
240
242
  export const MAX_IDENTIFIER_CHARS = 128;
@@ -8,6 +8,7 @@
8
8
  * logged and never included in any error string.
9
9
  */
10
10
  import { RECONCILER_LIVENESS_VALUES } from "./types.js";
11
+ import { EXECUTOR_REPORTABLE_END_CAUSE_VALUES, } from "./completion-contract.js";
11
12
  import { readEpicRunCompletionState, } from "../conductor/bridge-api-client.js";
12
13
  /** BAPI-1258 — the server's stable `error_code` for refused capacity evidence. */
13
14
  export const UNSUPPORTED_TERMINAL_CAPACITY_ERROR_CODE = "UNSUPPORTED_TERMINAL_CAPACITY";
@@ -92,6 +93,41 @@ export function normalizePriorAttemptHeadSha(value, onMalformed) {
92
93
  onMalformed();
93
94
  return null;
94
95
  }
96
+ /**
97
+ * BAPI-1421 (F4) — normalize a claim's `end_cause_capability` to the recognized
98
+ * executor-reportable values. Absent, null, or malformed reads as an empty list
99
+ * (an older server), and an unknown string is dropped rather than trusted.
100
+ */
101
+ export function normalizeEndCauseCapability(value) {
102
+ if (!Array.isArray(value))
103
+ return [];
104
+ const allowed = new Set(EXECUTOR_REPORTABLE_END_CAUSE_VALUES);
105
+ const out = [];
106
+ for (const entry of value) {
107
+ if (allowed.has(entry) && !out.includes(entry)) {
108
+ out.push(entry);
109
+ }
110
+ }
111
+ return out;
112
+ }
113
+ /**
114
+ * BAPI-1421 (F4) — the completion envelope a claim may carry. A copy that keeps
115
+ * `end_cause` only when the claim's advertised list holds that exact value; an
116
+ * unadvertised cause is removed, never sent as null or rewritten. Every other
117
+ * evidence field is unchanged. An older server's strict `extra="forbid"`
118
+ * envelope would 422 an unknown key, so this is what keeps a newer executor
119
+ * wire-compatible with it.
120
+ */
121
+ export function envelopeForClaim(job, envelope) {
122
+ if (!("end_cause" in envelope))
123
+ return envelope;
124
+ const allowed = normalizeEndCauseCapability(job.end_cause_capability);
125
+ if (envelope.end_cause !== undefined && allowed.includes(envelope.end_cause)) {
126
+ return envelope;
127
+ }
128
+ const { end_cause: _omitted, ...rest } = envelope;
129
+ return rest;
130
+ }
95
131
  /** Bound a server-provided diagnostic snippet included in error strings. */
96
132
  function boundedDetail(text) {
97
133
  const trimmed = (text ?? "").trim();
@@ -207,13 +243,13 @@ function toConductorGetFetch(fetchLike) {
207
243
  * `undefined`/`null`) keeps a legacy terminal body byte-identical, which an
208
244
  * older server's strict `extra="forbid"` schema depends on.
209
245
  */
210
- function completionContractFields(report) {
246
+ function completionContractFields(job, report) {
211
247
  return {
212
248
  ...(report.completion_contract !== undefined
213
249
  ? { completion_contract: report.completion_contract }
214
250
  : {}),
215
251
  ...(report.completion_evidence !== undefined
216
- ? { completion_evidence: report.completion_evidence }
252
+ ? { completion_evidence: envelopeForClaim(job, report.completion_evidence) }
217
253
  : {}),
218
254
  };
219
255
  }
@@ -289,6 +325,9 @@ export function createExecutorHttpClient(config) {
289
325
  }
290
326
  // BAPI-1367: a malformed prior head fails closed to null with one
291
327
  // bounded warning naming only the job, never the raw value or a SHA.
328
+ // BAPI-1421 (F4): only recognized executor-reportable end causes are
329
+ // kept; an older server's absent key becomes an empty list.
330
+ job.end_cause_capability = normalizeEndCauseCapability(job.end_cause_capability);
292
331
  job.prior_attempt_head_sha = normalizePriorAttemptHeadSha(job.prior_attempt_head_sha, () => (config.warn ?? ((message) => console.error(message)))(`executor: ignoring malformed prior attempt head in the claim for job ${String(job.id)}; ` +
293
332
  `treating it as a first dispatch.`));
294
333
  return { kind: "claimed", job, reconcilerLiveness };
@@ -392,7 +431,7 @@ export function createExecutorHttpClient(config) {
392
431
  local_commit_count: completion.local_commit_count,
393
432
  last_commit_sha: completion.last_commit_sha,
394
433
  telemetry: completion.telemetry,
395
- ...completionContractFields(completion),
434
+ ...completionContractFields(job, completion),
396
435
  };
397
436
  return mutate(`/${job.id}/complete`, body, true, job.repo_name);
398
437
  },
@@ -409,7 +448,7 @@ export function createExecutorHttpClient(config) {
409
448
  local_commit_count: failure.local_commit_count,
410
449
  last_commit_sha: failure.last_commit_sha,
411
450
  telemetry: failure.telemetry,
412
- ...completionContractFields(failure),
451
+ ...completionContractFields(job, failure),
413
452
  };
414
453
  if (failure.capacity_evidence === undefined) {
415
454
  return mutate(`/${job.id}/fail`, body, false, job.repo_name);