@volter/supercode-orchestrator 0.5.108 → 0.5.109

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.
Files changed (2) hide show
  1. package/board/dispatch.mjs +12 -5
  2. package/package.json +1 -1
@@ -1010,9 +1010,15 @@ export async function closeRequested(board, report, { taskId = null, caller = nu
1010
1010
  (report.closed ??= []).push({ task_id: row.task_id, ...session, released: true });
1011
1011
  continue;
1012
1012
  }
1013
- // A close that failed for a reason another attempt cannot change is tried once and raised as an incident, not tried
1014
- // every round (each attempt is a process). A deferred close (an offline machine, a run that still owns the pane) waits.
1015
- if (session.close_failed_at && session.close_error && !/^close deferred/.test(session.close_error)) continue;
1013
+ // A final refusal stops further close attempts. Only an authorized observation of this exact pane may establish
1014
+ // absence: panes.list can be filtered or carry missing context keys. Unknown/invisible keeps the original failure.
1015
+ const finalFailure = Boolean(session.close_failed_at && session.close_error && !/^close deferred/.test(session.close_error));
1016
+ if (finalFailure) {
1017
+ if (!session.pane) continue;
1018
+ const r = await doorOn(session.machine ?? localMachine(), 'harness.v1.panes.presence', { pane: session.pane }, { timeout: 10_000, as: boardAddress(board.label) });
1019
+ const observed = r.code === 0 ? json(r.stdout.trim(), null) : null;
1020
+ if (observed?.pane !== session.pane || observed.present !== false) continue;
1021
+ }
1016
1022
  const active = view(board, (db) => db.prepare(`SELECT r.id, r.metadata FROM task_runs r WHERE r.ended_at IS NULL OR EXISTS (SELECT 1 FROM tasks t WHERE t.current_run_id = r.id)`).all());
1017
1023
  // Persist retries even for historical ends that did not have a close_session action. The close is claimed in the
1018
1024
  // same transaction, before the pane or process is touched: of two rounds (or a round and a verb) that read one close,
@@ -1039,7 +1045,7 @@ export async function closeRequested(board, report, { taskId = null, caller = nu
1039
1045
  if (row.ended_at) { const inTurn = await turnAtClose(session); if (inTurn) throw new Error(`close deferred: ${inTurn}`); }
1040
1046
  await stopSession(board, session);
1041
1047
  }
1042
- } else {
1048
+ } else if (!finalFailure) {
1043
1049
  if (!panes.has(machine)) {
1044
1050
  const r = await doorOn(machine, 'harness.v1.panes.list',{}, { timeout: 60_000, as: boardAddress(board.label) });
1045
1051
  const list = r.code === 0 ? json(r.stdout.trim(), null) : null;
@@ -1088,7 +1094,8 @@ export async function closeRequested(board, report, { taskId = null, caller = nu
1088
1094
  const subscribed = db.prepare('SELECT r.id, r.metadata FROM task_runs r WHERE r.ended_at IS NULL OR EXISTS (SELECT 1 FROM tasks t WHERE t.current_run_id = r.id)').all()
1089
1095
  .some((r) => addressOf(json(r.metadata, {})?.supercode) === address && r.id !== row.id);
1090
1096
  const unsubscribed = subscribed ? 0 : db.prepare("DELETE FROM kanban_notify_subs WHERE platform = 'supercode' AND chat_id = ? AND (task_id = ? OR json_extract(delivery_metadata, '$.role') = 'worker')").run(address, row.task_id).changes;
1091
- event(db, row.task_id, 'session_closed', { session_id: session.session_id, pane: session.pane, machine: session.machine, unsubscribed }, row.id);
1097
+ event(db, row.task_id, 'session_closed', { session_id: session.session_id, pane: session.pane, machine: session.machine, unsubscribed,
1098
+ ...(finalFailure ? { reason: 'authorized pane presence observed absence after an earlier close refusal' } : {}) }, row.id);
1092
1099
  }
1093
1100
  });
1094
1101
  if (error) report.undelivered.push([row.task_id, addressOf(session), error, 'close']);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/supercode-orchestrator",
3
- "version": "0.5.108",
3
+ "version": "0.5.109",
4
4
  "type": "module",
5
5
  "description": "The orchestrator runtime over the Volter Harness ontology: one typed operational model whose folder is its serialization, read and written through the harness orchestration doors (docs/ORCHESTRATOR-IR.md)",
6
6
  "exports": {