@coreplane/switchboard 1.260.6 → 1.261.0

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/cli.js CHANGED
@@ -4078,6 +4078,7 @@ function isHeadMaterial(event) {
4078
4078
  case "context":
4079
4079
  case "reference":
4080
4080
  case "run_meta":
4081
+ case "run_state":
4081
4082
  case "route":
4082
4083
  return true;
4083
4084
  case "run_note":
@@ -4847,7 +4848,7 @@ function analyzeRunFriction(events, opts = {}) {
4847
4848
  return;
4848
4849
  }
4849
4850
  if (ev.type === "artifact" && ev.direction === "out") outboundArtifacts++;
4850
- if (ev.type === "skill_use" || ev.type === "artifact" || ev.type === "review_artifact" || ev.type === "pr_description" || ev.type === "pr_opened" || ev.type === "coordinator_tag" || ev.type === "ship_handoff" || ev.type === "child_interrupted" || ev.type === "child_resumed" || ev.type === "review_posted" || ev.type === "ship_round" || ev.type === "ship_unit" || ev.type === "route" || ev.type === "operator" || ev.type === "refusal" || ev.type === "reference" || ev.type === "lease" || ev.type === "pushed_head") {
4851
+ if (ev.type === "skill_use" || ev.type === "artifact" || ev.type === "review_artifact" || ev.type === "pr_description" || ev.type === "pr_opened" || ev.type === "coordinator_tag" || ev.type === "ship_handoff" || ev.type === "child_interrupted" || ev.type === "child_resumed" || ev.type === "review_posted" || ev.type === "ship_round" || ev.type === "ship_unit" || ev.type === "route" || ev.type === "operator" || ev.type === "refusal" || ev.type === "reference" || ev.type === "run_state" || ev.type === "lease" || ev.type === "pushed_head") {
4851
4852
  sideFactEvents++;
4852
4853
  return;
4853
4854
  }
@@ -4929,6 +4930,7 @@ function analyzeRunFriction(events, opts = {}) {
4929
4930
  }
4930
4931
  return;
4931
4932
  }
4933
+ if (ev.type !== "run_note") return;
4932
4934
  switch (ev.kind) {
4933
4935
  case "wrap_up":
4934
4936
  wrapUp = { index, at: ev.at };
@@ -5882,6 +5884,26 @@ var init_contract2 = __esm({
5882
5884
  });
5883
5885
 
5884
5886
  // ../../src/core/pipelineStanding.ts
5887
+ function hostedStageDetail(stage) {
5888
+ switch (stage) {
5889
+ case "coding":
5890
+ return "coding a unit";
5891
+ case "review":
5892
+ return "reviewing a unit";
5893
+ case "fix":
5894
+ return "fixing review findings";
5895
+ case "approved":
5896
+ return "waiting for checks and merge";
5897
+ case "merge-ready":
5898
+ return "ready for a person to merge";
5899
+ case "merged":
5900
+ return "a unit merged";
5901
+ case "idle":
5902
+ return "waiting for the next pipeline step";
5903
+ case "ended":
5904
+ return "finishing the pipeline";
5905
+ }
5906
+ }
5885
5907
  function endingWordOf(kind) {
5886
5908
  return ENDING_WORDS[kind] ?? kind;
5887
5909
  }
@@ -6008,10 +6030,11 @@ function isPipelineSummaryShape(v) {
6008
6030
  }
6009
6031
  return true;
6010
6032
  }
6011
- var STAGES, OPEN_STAGES, ROUND_STAGE, ENDING_STAGE, ENDING_WORDS, ROUND_OUTCOME_WORDS, isFinite_;
6033
+ var HOSTED_PIPELINE_STARTING_DETAIL, STAGES, OPEN_STAGES, ROUND_STAGE, ENDING_STAGE, ENDING_WORDS, ROUND_OUTCOME_WORDS, isFinite_;
6012
6034
  var init_pipelineStanding = __esm({
6013
6035
  "../../src/core/pipelineStanding.ts"() {
6014
6036
  "use strict";
6037
+ HOSTED_PIPELINE_STARTING_DETAIL = "pipeline starting";
6015
6038
  STAGES = [
6016
6039
  "coding",
6017
6040
  "review",
@@ -16134,6 +16157,7 @@ var init_resident = __esm({
16134
16157
  * here: its `runtime-replaced` is the typed restart (`opWithReattach`). */
16135
16158
  runtimeReplacedStreak = 0;
16136
16159
  lastBinding;
16160
+ attachAttempt = 0;
16137
16161
  /** The thread's binding as the resident answered it on the most recent
16138
16162
  * successful attach — including a mid-run re-attach after an eviction, which
16139
16163
  * may land on a newer sha than the one the run started on. Undefined until
@@ -16300,6 +16324,7 @@ var init_resident = __esm({
16300
16324
  * an operation's wall clock is the command's, and a recovery attach is not
16301
16325
  * the command. */
16302
16326
  async attach(span, opts = {}) {
16327
+ this.attachAttempt++;
16303
16328
  const answer = await this.attachOnce(span, this.attachBoundMs("/attach"), opts.signal);
16304
16329
  if (answer.ok) return answer.binding;
16305
16330
  if (isDrainingRefusal(answer)) {
@@ -16348,14 +16373,16 @@ var init_resident = __esm({
16348
16373
  t0 + (left === void 0 ? DRAIN_WAIT_MAX_MS : Math.max(0, left - DRAIN_LEASE_RESERVE_MS))
16349
16374
  );
16350
16375
  let answer = first;
16351
- const note = (now) => this.opts.onSetupNote?.(
16352
- `waiting for the deploy to finish \xB7 ${Math.max(1, Math.round((now - t0) / MINUTE_MS))} min`
16353
- );
16376
+ await this.opts.onLiveStateObservation?.({
16377
+ state: "waiting_deploy",
16378
+ bound: deadline,
16379
+ reason: "deploy",
16380
+ attempt: this.attachAttempt
16381
+ });
16354
16382
  const waitSpan = span?.start("dispatch.workspace.attach.drain-wait");
16355
16383
  try {
16356
16384
  for (; ; ) {
16357
16385
  const now = systemClock();
16358
- note(now);
16359
16386
  if (now >= deadline)
16360
16387
  throw new ResidentDrainingError(this.opts.resource, now - t0, drainingUntil(answer), refusalWords(answer));
16361
16388
  await wakePause(Math.min(DRAIN_POLL_MS, deadline - now), opts.signal, "/attach");
@@ -16393,7 +16420,6 @@ var init_resident = __esm({
16393
16420
  }
16394
16421
  throw err2;
16395
16422
  } finally {
16396
- this.opts.onSetupNote?.(void 0);
16397
16423
  }
16398
16424
  }
16399
16425
  /** One `/attach`, answered rather than thrown: the binding on a 200, else
@@ -16700,6 +16726,13 @@ var init_resident = __esm({
16700
16726
  }
16701
16727
  };
16702
16728
  const t0 = systemClock();
16729
+ const wakeBound = t0 + wakeWaitBudget(opts.budgetMs);
16730
+ await this.opts.onLiveStateObservation?.({
16731
+ state: "waiting_repository",
16732
+ bound: wakeBound,
16733
+ reason: "repository_container",
16734
+ attempt: this.attachAttempt
16735
+ });
16703
16736
  let transient = opts.origin === "transient-refusal";
16704
16737
  const definite = (why) => residentWakeStrike(route2, refusal, why, "refused", opts.origin);
16705
16738
  const decide = (view) => transient && isUnansweredProbe(view) ? {
@@ -18413,7 +18446,7 @@ async function makeExecutor(opts, ctx, span) {
18413
18446
  resolveEnvs: () => gitIdentityEnvs(ctx.profile.identity, authorSourceOf(opts, ctx)),
18414
18447
  ...ctx.ownPr !== void 0 ? { ownPr: ctx.ownPr } : {},
18415
18448
  ...ctx.remainingMs !== void 0 ? { remainingMs: ctx.remainingMs } : {},
18416
- ...ctx.onSetupNote !== void 0 ? { onSetupNote: ctx.onSetupNote } : {}
18449
+ ...ctx.onLiveStateObservation !== void 0 ? { onLiveStateObservation: ctx.onLiveStateObservation } : {}
18417
18450
  },
18418
18451
  nonWarm,
18419
18452
  span,
@@ -18595,7 +18628,7 @@ async function reattachWorkspace(opts, ctx, recorded, span) {
18595
18628
  // resident holds its own credential, so the pairs alone ride.
18596
18629
  resolveEnvs: () => gitIdentityEnvs(ctx.profile.identity, authorSourceOf(opts, ctx)),
18597
18630
  ...ctx.remainingMs !== void 0 ? { remainingMs: ctx.remainingMs } : {},
18598
- ...ctx.onSetupNote !== void 0 ? { onSetupNote: ctx.onSetupNote } : {}
18631
+ ...ctx.onLiveStateObservation !== void 0 ? { onLiveStateObservation: ctx.onLiveStateObservation } : {}
18599
18632
  });
18600
18633
  let binding;
18601
18634
  try {
@@ -25400,6 +25433,199 @@ var init_frictionProposals = __esm({
25400
25433
  }
25401
25434
  });
25402
25435
 
25436
+ // ../../src/core/runLiveState.ts
25437
+ function safeLiveStateDetail(detail) {
25438
+ if (detail === void 0) return void 0;
25439
+ const line4 = oneLine(detail);
25440
+ if (line4 === "" || UNSAFE_DETAIL.test(line4)) return void 0;
25441
+ return redactAndCap(line4, LIVE_STATE_DETAIL_MAX - 1);
25442
+ }
25443
+ function assignRunLiveState(current, currentSeq, input) {
25444
+ if (input.expectedSeq !== currentSeq) return { ok: false, reason: "stale-sequence" };
25445
+ if (current === void 0 && input.state !== "admitted") return { ok: false, reason: "invalid-transition" };
25446
+ if (current?.state === "ended") return { ok: false, reason: "terminal" };
25447
+ if (input.state !== "ended") {
25448
+ if (input.bound === void 0) return { ok: false, reason: "bound-required" };
25449
+ if (!Number.isFinite(input.bound) || input.bound < input.at) return { ok: false, reason: "invalid-bound" };
25450
+ } else if (input.cause === void 0) return { ok: false, reason: "cause-required" };
25451
+ if (current !== void 0 && current.state !== input.state && !TRANSITIONS[current.state].includes(input.state))
25452
+ return { ok: false, reason: "invalid-transition" };
25453
+ const detail = safeLiveStateDetail(input.detail);
25454
+ const liveState = {
25455
+ state: input.state,
25456
+ since: current?.state === input.state ? current.since : input.at,
25457
+ ...input.state !== "ended" ? { bound: input.bound } : {},
25458
+ ...detail !== void 0 ? { detail } : {}
25459
+ };
25460
+ if (current?.state === input.state) return { ok: true, liveState };
25461
+ return {
25462
+ ok: true,
25463
+ liveState,
25464
+ event: {
25465
+ type: "run_state",
25466
+ ...liveState,
25467
+ ...input.state === "ended" ? { cause: input.cause } : {},
25468
+ at: input.at
25469
+ }
25470
+ };
25471
+ }
25472
+ function foldRunLiveState(events, materialized = {}) {
25473
+ let liveState = materialized.liveState;
25474
+ let liveStateSeq = materialized.liveStateSeq ?? 0;
25475
+ let leaseEndsAt;
25476
+ for (const event of [...events].sort((left, right) => (left.seq ?? 0) - (right.seq ?? 0))) {
25477
+ if (event.type === "lease" && event.endsAt !== void 0) leaseEndsAt = event.endsAt;
25478
+ const seq = event.seq ?? 0;
25479
+ if (seq <= liveStateSeq) continue;
25480
+ if (event.type === "run_state" && RUN_LIVE_STATE_NAMES.includes(event.state) && event.since !== void 0) {
25481
+ liveState = {
25482
+ state: event.state,
25483
+ since: event.since,
25484
+ ...event.bound !== void 0 ? { bound: event.bound } : {},
25485
+ ...event.detail !== void 0 ? { detail: event.detail } : {}
25486
+ };
25487
+ liveStateSeq = seq;
25488
+ continue;
25489
+ }
25490
+ if (event.type === "tool_call" && liveState?.state === "working" && event.at !== void 0 && event.boundMs !== void 0) {
25491
+ liveState = { ...liveState, bound: event.at + event.boundMs, detail: "running a tool" };
25492
+ liveStateSeq = seq;
25493
+ continue;
25494
+ }
25495
+ if (event.type === "tool_result" && liveState?.state === "working" && leaseEndsAt !== void 0) {
25496
+ liveState = { ...liveState, bound: leaseEndsAt, detail: "model turn" };
25497
+ liveStateSeq = seq;
25498
+ }
25499
+ }
25500
+ return {
25501
+ ...liveState !== void 0 ? { liveState } : {},
25502
+ ...liveStateSeq > 0 ? { liveStateSeq } : {}
25503
+ };
25504
+ }
25505
+ var RUN_LIVE_STATE_NAMES, LIVE_STATE_DETAIL_MAX, TRANSITIONS, UNSAFE_DETAIL;
25506
+ var init_runLiveState = __esm({
25507
+ "../../src/core/runLiveState.ts"() {
25508
+ "use strict";
25509
+ init_redact();
25510
+ RUN_LIVE_STATE_NAMES = [
25511
+ "admitted",
25512
+ "waiting_deploy",
25513
+ "waiting_repository",
25514
+ "falling_back",
25515
+ "preparing",
25516
+ "working",
25517
+ "waiting_provider",
25518
+ "wrapping_up",
25519
+ "ended"
25520
+ ];
25521
+ LIVE_STATE_DETAIL_MAX = 160;
25522
+ TRANSITIONS = {
25523
+ admitted: ["waiting_deploy", "waiting_repository", "falling_back", "preparing", "working", "wrapping_up", "ended"],
25524
+ waiting_deploy: ["waiting_repository", "falling_back", "preparing", "working", "wrapping_up", "ended"],
25525
+ waiting_repository: ["waiting_deploy", "falling_back", "preparing", "working", "wrapping_up", "ended"],
25526
+ falling_back: ["preparing", "working", "wrapping_up", "ended"],
25527
+ preparing: ["waiting_deploy", "waiting_repository", "falling_back", "working", "wrapping_up", "ended"],
25528
+ working: [
25529
+ "waiting_deploy",
25530
+ "waiting_repository",
25531
+ "falling_back",
25532
+ "preparing",
25533
+ "waiting_provider",
25534
+ "wrapping_up",
25535
+ "ended"
25536
+ ],
25537
+ waiting_provider: ["working", "wrapping_up", "ended"],
25538
+ wrapping_up: ["ended"],
25539
+ ended: []
25540
+ };
25541
+ UNSAFE_DETAIL = /(?:\bimage-stale\b|\battach-failed\b|\bparked-provider\b|<\/?(?:html|body|head)\b|\bbad gateway\b)/i;
25542
+ }
25543
+ });
25544
+
25545
+ // ../../src/core/plane/decide.ts
25546
+ function liveStateWords(state) {
25547
+ switch (state) {
25548
+ case "admitted":
25549
+ return "admitted";
25550
+ case "waiting_deploy":
25551
+ return "waiting for the current deploy";
25552
+ case "waiting_repository":
25553
+ return "waiting for the repository container";
25554
+ case "falling_back":
25555
+ return "switching to a fallback workspace";
25556
+ case "preparing":
25557
+ return "preparing the workspace";
25558
+ case "working":
25559
+ return "working";
25560
+ case "waiting_provider":
25561
+ return "waiting for the model provider";
25562
+ case "wrapping_up":
25563
+ return "wrapping up";
25564
+ case "ended":
25565
+ return "ended";
25566
+ }
25567
+ }
25568
+ function causeOfClose(status3, restarting) {
25569
+ switch (status3) {
25570
+ case "completed":
25571
+ return "completed";
25572
+ case "failed":
25573
+ return "failed";
25574
+ case "stopped_soft":
25575
+ case "stopped_hard":
25576
+ case "stopped":
25577
+ return "stopped";
25578
+ default:
25579
+ return restarting === true ? "resident_replaced" : "lease_lapsed";
25580
+ }
25581
+ }
25582
+ function endingCauseWords(cause) {
25583
+ switch (cause) {
25584
+ case "completed":
25585
+ return "it completed";
25586
+ case "failed":
25587
+ return "it failed";
25588
+ case "stopped":
25589
+ return "it was stopped";
25590
+ case "withdrawn":
25591
+ return "its wait was withdrawn";
25592
+ case "refused":
25593
+ return "its admission was refused";
25594
+ case "lease_lapsed":
25595
+ return "its lease lapsed with no heartbeat";
25596
+ case "resident_replaced":
25597
+ return "the resident container running it was replaced";
25598
+ case "runner_gone":
25599
+ return "the runner instance driving it is gone";
25600
+ }
25601
+ }
25602
+ function isReissueSteerText(text) {
25603
+ return /^the model provider .+ is answering again — re-issue the held turn and continue$/.test(text.trim());
25604
+ }
25605
+ function waitingWords(waiting2) {
25606
+ if (waiting2.length === 0) return "its turn";
25607
+ return waiting2.map(
25608
+ (c) => c.kind === "thread_free" ? "the thread's live run" : c.kind === "deploy_settled" ? "the pending deploy" : c.kind === "seat" ? `a seat on ${c.resident}` : c.kind === "memory" ? `memory on ${c.resident}` : c.kind === "provider_up" ? `the ${c.provider} provider` : `the ${c.window} window`
25609
+ ).join(", then ");
25610
+ }
25611
+ var PLANE_ENDING_CAUSES;
25612
+ var init_decide = __esm({
25613
+ "../../src/core/plane/decide.ts"() {
25614
+ "use strict";
25615
+ init_budgets();
25616
+ PLANE_ENDING_CAUSES = [
25617
+ "completed",
25618
+ "failed",
25619
+ "stopped",
25620
+ "withdrawn",
25621
+ "refused",
25622
+ "lease_lapsed",
25623
+ "resident_replaced",
25624
+ "runner_gone"
25625
+ ];
25626
+ }
25627
+ });
25628
+
25403
25629
  // ../../src/core/runEventLines.ts
25404
25630
  function parseRunEventLines(text) {
25405
25631
  const events = [];
@@ -25465,6 +25691,8 @@ function isRunEvent(v) {
25465
25691
  return typeof o.url === "string" && typeof o.number === "number" && typeof o.created === "boolean";
25466
25692
  case "pushed_head":
25467
25693
  return typeof o.ref === "string" && typeof o.sha === "string" && (o.by === "push" || o.by === "salvage");
25694
+ case "run_state":
25695
+ return typeof o.state === "string" && LIVE_STATES.has(o.state) && typeof o.since === "number" && (o.state === "ended" ? typeof o.cause === "string" && ENDING_CAUSES.has(o.cause) : typeof o.bound === "number");
25468
25696
  case "review_posted":
25469
25697
  return typeof o.repo === "string" && typeof o.number === "number" && typeof o.head === "string";
25470
25698
  case "ship_round":
@@ -25487,12 +25715,16 @@ function isRunEvent(v) {
25487
25715
  return false;
25488
25716
  }
25489
25717
  }
25490
- var NOTE_KINDS;
25718
+ var NOTE_KINDS, LIVE_STATES, ENDING_CAUSES;
25491
25719
  var init_runEventLines = __esm({
25492
25720
  "../../src/core/runEventLines.ts"() {
25493
25721
  "use strict";
25494
25722
  init_runEvents();
25723
+ init_runLiveState();
25724
+ init_decide();
25495
25725
  NOTE_KINDS = new Set(RUN_NOTE_KINDS);
25726
+ LIVE_STATES = new Set(RUN_LIVE_STATE_NAMES);
25727
+ ENDING_CAUSES = new Set(PLANE_ENDING_CAUSES);
25496
25728
  }
25497
25729
  });
25498
25730
 
@@ -32237,6 +32469,8 @@ function assembleRunRecord(input) {
32237
32469
  ...seal?.replyNote !== void 0 ? { replyNote: seal.replyNote } : {},
32238
32470
  ...snap !== null ? { stepCount: snap.stepCount } : {},
32239
32471
  status: input.status,
32472
+ ...snap?.liveState !== void 0 ? { liveState: snap.liveState } : {},
32473
+ ...snap?.liveStateSeq !== void 0 ? { liveStateSeq: snap.liveStateSeq } : {},
32240
32474
  eventCount: Math.max(snap?.eventCount ?? atFinish.length, seal?.eventCount ?? 0),
32241
32475
  storedEventCount: events.length,
32242
32476
  truncated: false,
@@ -32420,43 +32654,6 @@ var init_record = __esm({
32420
32654
  }
32421
32655
  });
32422
32656
 
32423
- // ../../src/core/plane/decide.ts
32424
- function endingCauseWords(cause) {
32425
- switch (cause) {
32426
- case "completed":
32427
- return "it completed";
32428
- case "failed":
32429
- return "it failed";
32430
- case "stopped":
32431
- return "it was stopped";
32432
- case "withdrawn":
32433
- return "its wait was withdrawn";
32434
- case "refused":
32435
- return "its admission was refused";
32436
- case "lease_lapsed":
32437
- return "its lease lapsed with no heartbeat";
32438
- case "resident_replaced":
32439
- return "the resident container running it was replaced";
32440
- case "runner_gone":
32441
- return "the runner instance driving it is gone";
32442
- }
32443
- }
32444
- function isReissueSteerText(text) {
32445
- return /^the model provider .+ is answering again — re-issue the held turn and continue$/.test(text.trim());
32446
- }
32447
- function waitingWords(waiting2) {
32448
- if (waiting2.length === 0) return "its turn";
32449
- return waiting2.map(
32450
- (c) => c.kind === "thread_free" ? "the thread's live run" : c.kind === "deploy_settled" ? "the pending deploy" : c.kind === "seat" ? `a seat on ${c.resident}` : c.kind === "memory" ? `memory on ${c.resident}` : c.kind === "provider_up" ? `the ${c.provider} provider` : `the ${c.window} window`
32451
- ).join(", then ");
32452
- }
32453
- var init_decide = __esm({
32454
- "../../src/core/plane/decide.ts"() {
32455
- "use strict";
32456
- init_budgets();
32457
- }
32458
- });
32459
-
32460
32657
  // ../../src/core/runsService.ts
32461
32658
  function runResource(view) {
32462
32659
  return {
@@ -32493,6 +32690,8 @@ function ledgerView(row2, events) {
32493
32690
  ...m.repo !== void 0 ? { repo: m.repo } : {},
32494
32691
  startedAt: row2.startedAt,
32495
32692
  finished: false,
32693
+ ...row2.liveState !== void 0 ? { liveState: row2.liveState } : {},
32694
+ ...row2.liveStateSeq !== void 0 ? { liveStateSeq: row2.liveStateSeq } : {},
32496
32695
  eventCount: events.length,
32497
32696
  ...activity !== void 0 ? { activity } : {},
32498
32697
  ...m.sourceUrl !== void 0 ? { sourceUrl: m.sourceUrl } : {},
@@ -32531,6 +32730,8 @@ function liveView(s) {
32531
32730
  ...s.stepCount !== void 0 ? { stepCount: s.stepCount } : {},
32532
32731
  ...s.schema !== void 0 ? { schema: s.schema } : {},
32533
32732
  ...s.status !== void 0 ? { status: s.status } : {},
32733
+ ...s.liveState !== void 0 ? { liveState: s.liveState } : {},
32734
+ ...s.liveStateSeq !== void 0 ? { liveStateSeq: s.liveStateSeq } : {},
32534
32735
  eventCount: s.eventCount,
32535
32736
  ...s.stop ? { stop: s.stop } : {},
32536
32737
  ...s.activity !== void 0 ? { activity: s.activity } : {},
@@ -32628,7 +32829,7 @@ function createRunsService(deps) {
32628
32829
  const prices = deps.prices ?? NO_PRICES;
32629
32830
  const clock4 = deps.clock ?? systemClock;
32630
32831
  const warn = deps.warn ?? ((m) => console.warn(m));
32631
- const describe12 = (err2) => err2 instanceof Error ? err2.message : String(err2);
32832
+ const describe13 = (err2) => err2 instanceof Error ? err2.message : String(err2);
32632
32833
  let listing;
32633
32834
  const liveRows = () => {
32634
32835
  if (!ledger) return null;
@@ -32648,7 +32849,7 @@ function createRunsService(deps) {
32648
32849
  try {
32649
32850
  rows = await pending2;
32650
32851
  } catch (err2) {
32651
- warn(`[runs] run ledger list failed \u2014 showing this process's runs only: ${describe12(err2)}`);
32852
+ warn(`[runs] run ledger list failed \u2014 showing this process's runs only: ${describe13(err2)}`);
32652
32853
  return [];
32653
32854
  }
32654
32855
  const foreign = rows.filter((row2) => !registry.getById(row2.runId));
@@ -32658,7 +32859,7 @@ function createRunsService(deps) {
32658
32859
  try {
32659
32860
  events = await ledger.readEvents(row2.runId);
32660
32861
  } catch (err2) {
32661
- warn(`[runs] run ledger events read failed for ${row2.runId}: ${describe12(err2)}`);
32862
+ warn(`[runs] run ledger events read failed for ${row2.runId}: ${describe13(err2)}`);
32662
32863
  }
32663
32864
  return ledgerView(row2, events);
32664
32865
  })
@@ -32672,7 +32873,7 @@ function createRunsService(deps) {
32672
32873
  if (!row2) return null;
32673
32874
  return { row: row2, events: await ledger.readEvents(id) };
32674
32875
  } catch (err2) {
32675
- warn(`[runs] run ledger read failed for ${id}: ${describe12(err2)}`);
32876
+ warn(`[runs] run ledger read failed for ${id}: ${describe13(err2)}`);
32676
32877
  return null;
32677
32878
  }
32678
32879
  };
@@ -32695,7 +32896,7 @@ function createRunsService(deps) {
32695
32896
  activity: row2.state === "waiting" ? `queued at position ${row2.position} \u2014 waiting on ${waiting2}` : row2.state === "admitted" ? "admitted \u2014 starting" : "withdrawn"
32696
32897
  };
32697
32898
  } catch (err2) {
32698
- warn(`[runs] plane queued read failed for ${id}: ${describe12(err2)}`);
32899
+ warn(`[runs] plane queued read failed for ${id}: ${describe13(err2)}`);
32699
32900
  return null;
32700
32901
  }
32701
32902
  };
@@ -32713,7 +32914,7 @@ function createRunsService(deps) {
32713
32914
  row2 = await storeSummary(id);
32714
32915
  } catch (err2) {
32715
32916
  warn(
32716
- `[runs] history store read failed for ${id} \u2014 serving the registry row without its record: ${describe12(err2)}`
32917
+ `[runs] history store read failed for ${id} \u2014 serving the registry row without its record: ${describe13(err2)}`
32717
32918
  );
32718
32919
  return {};
32719
32920
  }
@@ -32758,12 +32959,12 @@ function createRunsService(deps) {
32758
32959
  if (marked.ok) runnerStopped = true;
32759
32960
  else warn(`[runs] the runner's stop mark was refused for ${id} (${marked.reason})`);
32760
32961
  } catch (err2) {
32761
- warn(`[runs] the runner's stop mark failed for ${id}: ${describe12(err2)}`);
32962
+ warn(`[runs] the runner's stop mark failed for ${id}: ${describe13(err2)}`);
32762
32963
  }
32763
32964
  try {
32764
32965
  unitRows = await units.listUnits(instanceId);
32765
32966
  } catch (err2) {
32766
- warn(`[runs] unit rows unavailable for the hard stop of ${id}: ${describe12(err2)}`);
32967
+ warn(`[runs] unit rows unavailable for the hard stop of ${id}: ${describe13(err2)}`);
32767
32968
  }
32768
32969
  }
32769
32970
  registry.publish(id, { type: "answer", text: hostedSealAnswer(unitRows, runnerStopped), at: clock4() });
@@ -32809,7 +33010,7 @@ function createRunsService(deps) {
32809
33010
  if (!done.ok) warn(`[runs] run ledger finish refused for ${id} (${done.reason ?? "unknown"})`);
32810
33011
  }
32811
33012
  } catch (err2) {
32812
- warn(`[runs] run ledger finish failed for ${id}: ${describe12(err2)}`);
33013
+ warn(`[runs] run ledger finish failed for ${id}: ${describe13(err2)}`);
32813
33014
  }
32814
33015
  }
32815
33016
  return { ok: true, value: { id, mode: "hard", state: "stopping" } };
@@ -32988,7 +33189,7 @@ function createRunsService(deps) {
32988
33189
  const r = await ledger.requestStop(id, mode);
32989
33190
  if (r.ok) return { ok: true, value: { id, mode, state: "stopping" } };
32990
33191
  } catch (err2) {
32991
- warn(`[runs] run ledger stop failed for ${id}: ${describe12(err2)}`);
33192
+ warn(`[runs] run ledger stop failed for ${id}: ${describe13(err2)}`);
32992
33193
  }
32993
33194
  }
32994
33195
  if (await storeSummary(id)) return conflict;
@@ -32998,7 +33199,7 @@ function createRunsService(deps) {
32998
33199
  if (r.withdrawn) return { ok: true, value: { id, mode, state: "withdrawn" } };
32999
33200
  if (await ledger.planeQueued(id) !== null) return conflict;
33000
33201
  } catch (err2) {
33001
- warn(`[runs] plane withdraw failed for ${id}: ${describe12(err2)}`);
33202
+ warn(`[runs] plane withdraw failed for ${id}: ${describe13(err2)}`);
33002
33203
  }
33003
33204
  }
33004
33205
  return notFound;
@@ -34929,6 +35130,11 @@ var init_runLedgerWorker = __esm({
34929
35130
  if (events.length === 0) return { ok: true };
34930
35131
  return this.fenceResult(await this.post("/runs/append", { storeKey: this.opts.storeKey, runId: runId3, gen, events }));
34931
35132
  }
35133
+ async assignLiveState(runId3, gen, assignment) {
35134
+ this.checkIds(runId3, gen);
35135
+ const r = await this.post("/runs/live-state", { storeKey: this.opts.storeKey, runId: runId3, gen, assignment });
35136
+ return r.data;
35137
+ }
34932
35138
  async setState(runId3, gen, state) {
34933
35139
  this.checkIds(runId3, gen);
34934
35140
  return this.fenceResult(await this.post("/runs/state", { storeKey: this.opts.storeKey, runId: runId3, gen, state }));
@@ -35757,6 +35963,9 @@ function activityLine(e) {
35757
35963
  case "lease":
35758
35964
  return "lease started";
35759
35965
  // the harness's clocks: head material the run loop keeps off the card — never arrives here
35966
+ case "run_state":
35967
+ return "";
35968
+ // Existing renderers stay until the surface cutover to the shared wording table.
35760
35969
  case "skill_use":
35761
35970
  return `\u{1F4DA} skill ${e.skill} loaded`;
35762
35971
  case "artifact":
@@ -36700,7 +36909,7 @@ async function attachRoundWorkspace(input) {
36700
36909
  ...input.round.stopSignal !== void 0 ? { stopSignal: input.round.stopSignal } : {},
36701
36910
  ...input.round.remainingMs !== void 0 ? { remainingMs: input.round.remainingMs } : {},
36702
36911
  ...input.round.requester !== void 0 ? { requester: input.round.requester } : {},
36703
- ...input.round.onSetupNote !== void 0 ? { onSetupNote: input.round.onSetupNote } : {}
36912
+ ...input.round.onLiveStateObservation !== void 0 ? { onLiveStateObservation: input.round.onLiveStateObservation } : {}
36704
36913
  },
36705
36914
  input.span
36706
36915
  );
@@ -38586,6 +38795,8 @@ function summaryOf(run2, now) {
38586
38795
  ...m?.hosted ? { hosted: true } : {},
38587
38796
  ...run2.instanceId !== void 0 ? { instanceId: run2.instanceId } : {},
38588
38797
  ...run2.pipeline !== void 0 ? { pipeline: run2.pipeline } : {},
38798
+ ...run2.liveState !== void 0 ? { liveState: run2.liveState } : {},
38799
+ ...run2.liveStateSeq !== void 0 ? { liveStateSeq: run2.liveStateSeq } : {},
38589
38800
  finished: run2.finished,
38590
38801
  startedAt: run2.startedAt,
38591
38802
  ...run2.finishedAt !== void 0 ? { finishedAt: run2.finishedAt } : {},
@@ -38621,7 +38832,9 @@ function snapshotOf(run2) {
38621
38832
  ...run2.meta?.receivedAt !== void 0 ? { receivedAt: run2.meta.receivedAt } : {},
38622
38833
  eventCount: run2.eventCount,
38623
38834
  stepCount: run2.stepCount,
38624
- truncated: run2.eventCount > run2.backlog.length
38835
+ truncated: run2.eventCount > run2.backlog.length,
38836
+ ...run2.liveState !== void 0 ? { liveState: run2.liveState } : {},
38837
+ ...run2.liveStateSeq !== void 0 ? { liveStateSeq: run2.liveStateSeq } : {}
38625
38838
  };
38626
38839
  }
38627
38840
  function sealResultOf(run2) {
@@ -38705,6 +38918,7 @@ var init_runRegistry = __esm({
38705
38918
  init_projections();
38706
38919
  init_indexFeed();
38707
38920
  init_runPace();
38921
+ init_runLiveState();
38708
38922
  PACE_RING_CAP = 1200;
38709
38923
  UNSEALED_HOLD_MS = 15 * 6e4;
38710
38924
  RUN_LABEL_MAX2 = 200;
@@ -38778,6 +38992,10 @@ var init_runRegistry = __esm({
38778
38992
  if (!isSpanRecord(event)) run2.stepCount++;
38779
38993
  appendToBacklog(run2, this.bounds, { ...event, seq });
38780
38994
  }
38995
+ const replayedLiveState = foldRunLiveState(opts.replay ?? [], opts.liveState);
38996
+ const folded = opts.resetLiveState ? { liveStateSeq: replayedLiveState.liveStateSeq } : replayedLiveState;
38997
+ run2.liveState = folded.liveState;
38998
+ run2.liveStateSeq = folded.liveStateSeq;
38781
38999
  this.index.notify({ type: "upsert", run: summaryOf(run2, this.now()) });
38782
39000
  return { id, token: token2, control: run2.control, ...stored !== void 0 ? { label: stored } : {} };
38783
39001
  }
@@ -38866,6 +39084,32 @@ var init_runRegistry = __esm({
38866
39084
  }
38867
39085
  if (!span) this.index.notify({ type: "upsert", run: summaryOf(run2, this.now()) });
38868
39086
  }
39087
+ /** Apply an assignment only after its durable transaction acknowledged. The
39088
+ * boundary keeps the ledger-assigned stream sequence; subscribers cannot
39089
+ * observe either half before this call. */
39090
+ commitLiveState(id, committed) {
39091
+ const run2 = this.runs.get(id);
39092
+ if (!run2 || run2.finished || run2.sealedAt !== void 0) return false;
39093
+ const event = committed.event;
39094
+ if (event !== void 0) {
39095
+ const seq = event.seq;
39096
+ if (seq === void 0 || seq !== run2.eventCount + 1) return false;
39097
+ run2.eventCount = seq;
39098
+ run2.stepCount++;
39099
+ const stamped = { ...event, seq };
39100
+ appendToBacklog(run2, this.bounds, stamped);
39101
+ for (const sub of run2.subscribers) {
39102
+ try {
39103
+ sub.onEvent(stamped, seq);
39104
+ } catch {
39105
+ }
39106
+ }
39107
+ }
39108
+ run2.liveState = committed.liveState;
39109
+ run2.liveStateSeq = committed.liveStateSeq;
39110
+ this.index.notify({ type: "upsert", run: summaryOf(run2, this.now()) });
39111
+ return true;
39112
+ }
38869
39113
  /** Mark a run finished — the agent stopped: stamp `finishedAt`, send every
38870
39114
  * attached subscriber the `finished` frame WITHOUT detaching it (span records
38871
39115
  * still flow until the seal), and upsert the index. `status` is the terminal
@@ -41867,6 +42111,47 @@ var init_customInstructions = __esm({
41867
42111
  }
41868
42112
  });
41869
42113
 
42114
+ // ../../src/core/runEventLane.ts
42115
+ var RunEventLane;
42116
+ var init_runEventLane = __esm({
42117
+ "../../src/core/runEventLane.ts"() {
42118
+ "use strict";
42119
+ RunEventLane = class {
42120
+ constructor(publishNow) {
42121
+ this.publishNow = publishNow;
42122
+ }
42123
+ publishNow;
42124
+ tail;
42125
+ /** Publish synchronously while idle; otherwise preserve order behind the active write. */
42126
+ publish(event) {
42127
+ if (!this.tail) {
42128
+ this.publishNow(event);
42129
+ return;
42130
+ }
42131
+ void this.write(() => this.publishNow(event));
42132
+ }
42133
+ /** Queue one operation after every event or operation already accepted. */
42134
+ write(work) {
42135
+ const previous = this.tail ?? Promise.resolve();
42136
+ const next = previous.then(work);
42137
+ const settled = next.then(
42138
+ () => void 0,
42139
+ () => void 0
42140
+ );
42141
+ this.tail = settled;
42142
+ void settled.then(() => {
42143
+ if (this.tail === settled) this.tail = void 0;
42144
+ });
42145
+ return next;
42146
+ }
42147
+ /** Wait until every operation accepted so far has settled. */
42148
+ async drain() {
42149
+ await this.tail;
42150
+ }
42151
+ };
42152
+ }
42153
+ });
42154
+
41870
42155
  // ../../src/core/statusCoalescer.ts
41871
42156
  function coalesceStatus(inner, minIntervalMs, now = Date.now, schedule = setTimeout) {
41872
42157
  let lastSentAt = -Infinity;
@@ -42039,22 +42324,24 @@ async function registerRun(deps, ctx) {
42039
42324
  {
42040
42325
  id: runId3,
42041
42326
  startedAt,
42042
- ...resume ? { replay: resume.events } : ctx.restartCarried ? { replay: ctx.restartCarried.events, token: ctx.restartCarried.token } : {}
42327
+ ...carriedRow?.liveState !== void 0 ? { liveState: { liveState: carriedRow.liveState, liveStateSeq: carriedRow.liveStateSeq } } : {},
42328
+ ...resume ? { replay: resume.events } : ctx.restartCarried ? { replay: ctx.restartCarried.events, token: ctx.restartCarried.token, resetLiveState: true } : {}
42043
42329
  }
42044
42330
  );
42331
+ const events = new RunEventLane((event) => registry.publish(run2.id, event));
42045
42332
  if (ctx.restartCarried)
42046
- registry.publish(run2.id, { type: "run_note", kind: "resumed", summary: ctx.restartCarried.note, at: clock4() });
42333
+ events.publish({ type: "run_note", kind: "resumed", summary: ctx.restartCarried.note, at: clock4() });
42047
42334
  const liveUrl = liveViewLink(run2.id, run2.token);
42048
42335
  shell.setLink(liveUrl ? { url: liveUrl, label: "Live run" } : void 0);
42049
42336
  if (liveUrl) admitted.runLink = liveUrl;
42050
42337
  io.runStarted?.({ id: run2.id });
42051
- trace.bindRun(run2.id, (e) => registry.publish(run2.id, e));
42338
+ trace.bindRun(run2.id, (event) => events.publish(event));
42052
42339
  const publishText = (type, text, source3, raw) => {
42053
42340
  const redacted = redactSecrets(text);
42054
42341
  const body = { text: redacted, ...source3 ? { source: source3 } : {}, at: clock4() };
42055
42342
  const event = type === "input" ? { type, messageId: messageIdOf(msg, run2.id), ...body } : { type, ...body };
42056
42343
  const withRaw = raw !== void 0 ? { ...event, raw: redactSecrets(raw) } : event;
42057
- registry.publish(run2.id, utf8ByteLength(JSON.stringify(withRaw)) <= MAX_EVENT_BYTES ? withRaw : event);
42344
+ events.publish(utf8ByteLength(JSON.stringify(withRaw)) <= MAX_EVENT_BYTES ? withRaw : event);
42058
42345
  console.log(`[event] ${msg.threadKey} type=${type} bytes=${utf8ByteLength(redacted)}`);
42059
42346
  };
42060
42347
  const humanize = isMrkdwnChannel(msg.channelId);
@@ -42074,7 +42361,7 @@ async function registerRun(deps, ctx) {
42074
42361
  if (!resume && ctx.references) {
42075
42362
  const { conversations, blocks } = ctx.references;
42076
42363
  conversations.forEach((rc, i) => {
42077
- registry.publish(run2.id, {
42364
+ events.publish({
42078
42365
  type: "reference",
42079
42366
  url: rc.permalink,
42080
42367
  channelId: rc.ref.channelId,
@@ -42086,7 +42373,7 @@ async function registerRun(deps, ctx) {
42086
42373
  console.log(`[event] ${msg.threadKey} type=reference channel=${rc.ref.channelId} messages=${rc.messages.length}`);
42087
42374
  });
42088
42375
  }
42089
- const publishMeta = (repoCtx2) => registry.publish(run2.id, {
42376
+ const publishMeta = (repoCtx2) => events.publish({
42090
42377
  type: "run_meta",
42091
42378
  agent: agent.name,
42092
42379
  agentSource,
@@ -42118,7 +42405,7 @@ async function registerRun(deps, ctx) {
42118
42405
  if (!resume)
42119
42406
  for (const d of cardDecisions ?? []) {
42120
42407
  if (d.outcome !== "degraded") continue;
42121
- registry.publish(run2.id, {
42408
+ events.publish({
42122
42409
  type: "run_note",
42123
42410
  kind: "control_degraded",
42124
42411
  summary: oneLine(
@@ -42132,12 +42419,12 @@ async function registerRun(deps, ctx) {
42132
42419
  at: clock4()
42133
42420
  });
42134
42421
  }
42135
- if (!resume && route2) registry.publish(run2.id, { type: "route", ...route2, at: clock4() });
42136
- if (!resume && ctx.operator) registry.publish(run2.id, { type: "operator", ...ctx.operator, at: clock4() });
42422
+ if (!resume && route2) events.publish({ type: "route", ...route2, at: clock4() });
42423
+ if (!resume && ctx.operator) events.publish({ type: "operator", ...ctx.operator, at: clock4() });
42137
42424
  if (!resume && deps.config.config.runHistory?.includeContext !== false) {
42138
42425
  for (const text of contextMessageTexts(seedTurns ?? history, humanize)) publishText("context", text);
42139
42426
  }
42140
- return { run: run2, runId: runId3, channelVisibility, liveUrl, publishText, publishMeta };
42427
+ return { run: run2, runId: runId3, channelVisibility, liveUrl, events, publishText, publishMeta };
42141
42428
  }
42142
42429
  async function reserveRun(deps, ctx) {
42143
42430
  const {
@@ -42213,7 +42500,7 @@ async function reserveRun(deps, ctx) {
42213
42500
  }
42214
42501
  async function attachRound(deps, ctx) {
42215
42502
  const { threadKey, agent, profile, repoCtx, root, clock: clock4, reattach, stopSignal, remainingMs, requester } = ctx;
42216
- const { onSetupNote } = ctx;
42503
+ const { onLiveStateObservation } = ctx;
42217
42504
  const ownPr = agent.name === "review" ? void 0 : ownPrOf(repoCtx);
42218
42505
  return root.span("dispatch.workspace.attach", async (span) => {
42219
42506
  const graft = (steps, residentTotalMs) => graftResidentSteps(steps, {
@@ -42249,7 +42536,7 @@ async function attachRound(deps, ctx) {
42249
42536
  ...stopSignal !== void 0 ? { stopSignal } : {},
42250
42537
  ...remainingMs !== void 0 ? { remainingMs } : {},
42251
42538
  ...requester !== void 0 ? { requester } : {},
42252
- ...onSetupNote !== void 0 ? { onSetupNote } : {}
42539
+ ...onLiveStateObservation !== void 0 ? { onLiveStateObservation } : {}
42253
42540
  },
42254
42541
  logKey: threadKey,
42255
42542
  span
@@ -42306,10 +42593,10 @@ async function attachWorkspace(deps, ctx) {
42306
42593
  clock: clock4,
42307
42594
  // The requester whose binding names the author pair (record 0062).
42308
42595
  requester: msg.userId,
42309
- // A run admitted onto a drained fleet says so (issue 2044): the drain
42310
- // wait paints its one line here, and its end restores the attach label
42311
- // the card sink painted at the span's start.
42312
- onSetupNote: (note) => shell.setSetupLabel(note ?? `${displayNameOf("dispatch.workspace.attach")}\u2026`),
42596
+ onLiveStateObservation: async (observation) => {
42597
+ await ctx.onLiveStateObservation?.(observation);
42598
+ shell.setSetupLabel(`${liveStateWords(observation.state)}\u2026`);
42599
+ },
42313
42600
  ...reattach !== void 0 ? { reattach } : {},
42314
42601
  ...stopSignal !== void 0 ? { stopSignal } : {},
42315
42602
  ...remainingMs !== void 0 ? { remainingMs } : {}
@@ -42476,7 +42763,6 @@ var init_provision = __esm({
42476
42763
  init_factory();
42477
42764
  init_executor();
42478
42765
  init_residentTrace();
42479
- init_displayNames();
42480
42766
  init_resident();
42481
42767
  init_memory();
42482
42768
  init_budgets();
@@ -42489,12 +42775,14 @@ var init_provision = __esm({
42489
42775
  init_reviewRound();
42490
42776
  init_repoContext();
42491
42777
  init_runEvents();
42778
+ init_runEventLane();
42492
42779
  init_redact();
42493
42780
  init_runRecord();
42494
42781
  init_inboxMessage();
42495
42782
  init_statusCardFrame();
42496
42783
  init_statusCoalescer();
42497
42784
  init_types5();
42785
+ init_decide();
42498
42786
  init_record();
42499
42787
  init_reply();
42500
42788
  init_refusal();
@@ -48715,6 +49003,11 @@ var init_mirror = __esm({
48715
49003
  seedEchoPending = false;
48716
49004
  mirroredTail;
48717
49005
  iteration = 0;
49006
+ /** The loop counters on the last transcript-bearing step. A cursor-only
49007
+ * checkpoint repeats them so a post-loop turn cannot become part of the
49008
+ * resumable model loop merely by consuming a control row. */
49009
+ lastTurn = 0;
49010
+ lastIteration = 0;
48718
49011
  /** The rows written since the mirror started, and the compaction entries
48719
49012
  * among them by position — kept whether or not the ledger is wired, so
48720
49013
  * the harness holds this generation's copy of the record it wrote
@@ -48824,6 +49117,8 @@ var init_mirror = __esm({
48824
49117
  inboxConsumedSeq: this.inboxConsumedSeq,
48825
49118
  ...this.inboxDeferred()
48826
49119
  };
49120
+ this.lastTurn = report2.turn;
49121
+ this.lastIteration = report2.iteration;
48827
49122
  this.idx += turns.length;
48828
49123
  this.lastAssistantIdx = this.idx - 1;
48829
49124
  this.rows.push(...turns);
@@ -48852,6 +49147,8 @@ var init_mirror = __esm({
48852
49147
  inboxConsumedSeq: this.inboxConsumedSeq,
48853
49148
  ...this.inboxDeferred()
48854
49149
  };
49150
+ this.lastTurn = report2.turn;
49151
+ this.lastIteration = report2.iteration;
48855
49152
  this.idx += turns.length + 1;
48856
49153
  this.rows.push(...turns);
48857
49154
  this.compactionRows.push({ before: this.rows.length, entry });
@@ -48859,6 +49156,22 @@ var init_mirror = __esm({
48859
49156
  await this.deps.onStep(report2);
48860
49157
  return true;
48861
49158
  }
49159
+ /** Persist only the inbox cursor and its deferred exceptions. Post-loop
49160
+ * turns deliberately stay out of the resumable transcript, but a control
49161
+ * row they consume must survive a bot restart just as a loop step does. */
49162
+ async checkpointInbox() {
49163
+ if (!this.deps.onStep) return;
49164
+ await this.deps.onStep({
49165
+ turns: [],
49166
+ firstIdx: this.idx,
49167
+ inFlight: [],
49168
+ turn: this.lastTurn,
49169
+ iteration: this.lastIteration,
49170
+ remainingMs: Math.max(0, this.deps.remainingMs()),
49171
+ inboxConsumedSeq: this.inboxConsumedSeq,
49172
+ ...this.inboxDeferred()
49173
+ });
49174
+ }
48862
49175
  };
48863
49176
  }
48864
49177
  });
@@ -50388,6 +50701,7 @@ async function runPiHarnessOpen(deps, run2) {
50388
50701
  let parkSettled = false;
50389
50702
  let pendingReissue = [];
50390
50703
  let reissueInFlight;
50704
+ let reissueInFlightRows = [];
50391
50705
  let reissues = 0;
50392
50706
  let providerRetryReady = false;
50393
50707
  let providerRetryWait;
@@ -50400,20 +50714,21 @@ async function runPiHarnessOpen(deps, run2) {
50400
50714
  providerRetryWait = void 0;
50401
50715
  providerRetryGeneration += 1;
50402
50716
  pendingReissue = [];
50717
+ reissueInFlightRows = [];
50403
50718
  };
50404
50719
  const maybeReissue = () => {
50405
50720
  if (heldTurn === void 0 || !parkSettled || reissueInFlight !== void 0 || retryInFlight !== void 0)
50406
50721
  return;
50407
50722
  if (pendingReissue.length === 0) return;
50408
50723
  if (loopEnded || hardStopped || writeUp !== void 0 || finaleAborted) return;
50409
- const batch = pendingReissue.splice(0);
50724
+ reissueInFlightRows = pendingReissue.splice(0);
50410
50725
  reissues += 1;
50411
50726
  const id = reissues === 1 ? `${ids.prompt}:reissue` : `${ids.prompt}:reissue:${reissues}`;
50412
50727
  reissueInFlight = id;
50413
50728
  unechoed.push({
50414
50729
  message: REISSUE_PROMPT,
50415
- seq: Math.max(0, ...batch.map((i) => i.ledgerSeq ?? 0)),
50416
- inputs: batch
50730
+ seq: Math.max(0, ...reissueInFlightRows.map((i) => i.ledgerSeq ?? 0)),
50731
+ inputs: reissueInFlightRows
50417
50732
  });
50418
50733
  sends.send({ id, type: "prompt", message: REISSUE_PROMPT });
50419
50734
  };
@@ -50674,16 +50989,29 @@ ${stagedLine}` : prompt;
50674
50989
  save();
50675
50990
  }
50676
50991
  if (reissueInFlight !== void 0 && r.id === reissueInFlight) {
50677
- reissueInFlight = void 0;
50678
50992
  if (r.success === false) {
50993
+ reissueInFlight = void 0;
50679
50994
  parkSettled = false;
50680
50995
  const at = unechoed.findIndex((u) => u.message === REISSUE_PROMPT);
50681
- if (at >= 0) pendingReissue.push(...unechoed.splice(at, 1)[0].inputs);
50996
+ if (at >= 0) unechoed.splice(at, 1);
50997
+ pendingReissue.push(...reissueInFlightRows);
50998
+ reissueInFlightRows = [];
50682
50999
  note(
50683
51000
  "harness_error",
50684
51001
  `the reissue prompt was refused (${String(r.error ?? "no reason")}); the turn stays held for the next settle`
50685
51002
  );
50686
51003
  } else {
51004
+ drainFollowUps2();
51005
+ await steers;
51006
+ const at = unechoed.findIndex((u) => u.message === REISSUE_PROMPT);
51007
+ if (at >= 0) unechoed.splice(at, 1);
51008
+ mirror.inboxConsumedSeq = Math.max(
51009
+ mirror.inboxConsumedSeq,
51010
+ ...reissueInFlightRows.map((item) => item.ledgerSeq ?? 0),
51011
+ ...pendingReissue.map((item) => item.ledgerSeq ?? 0)
51012
+ );
51013
+ await mirror.checkpointInbox();
51014
+ reissueInFlight = void 0;
50687
51015
  clearProviderHold();
50688
51016
  }
50689
51017
  }
@@ -50692,7 +51020,16 @@ ${stagedLine}` : prompt;
50692
51020
  if (r.success === false) {
50693
51021
  parkSettled = false;
50694
51022
  note("harness_error", "the model retry prompt was refused; the transport failure remains held");
50695
- } else clearProviderHold();
51023
+ } else {
51024
+ drainFollowUps2();
51025
+ await steers;
51026
+ mirror.inboxConsumedSeq = Math.max(
51027
+ mirror.inboxConsumedSeq,
51028
+ ...pendingReissue.map((item) => item.ledgerSeq ?? 0)
51029
+ );
51030
+ await mirror.checkpointInbox();
51031
+ clearProviderHold();
51032
+ }
50696
51033
  }
50697
51034
  if (r.id === ids.prompt) {
50698
51035
  catchingUp = false;
@@ -51049,10 +51386,13 @@ ${stagedLine}` : prompt;
51049
51386
  `the follow-up turn's reissue prompt was refused (${String(obs.response.error ?? "no reason")}); the turn stays held for the next settle`
51050
51387
  );
51051
51388
  } else {
51389
+ drainTurnReissues();
51052
51390
  mirror.inboxConsumedSeq = Math.max(
51053
51391
  mirror.inboxConsumedSeq,
51054
- ...turnReissueInFlightRows.map((item) => item.ledgerSeq ?? 0)
51392
+ ...turnReissueInFlightRows.map((item) => item.ledgerSeq ?? 0),
51393
+ ...turnReissueRows.map((item) => item.ledgerSeq ?? 0)
51055
51394
  );
51395
+ await mirror.checkpointInbox();
51056
51396
  clearTurnProviderHold();
51057
51397
  }
51058
51398
  }
@@ -51067,6 +51407,7 @@ ${stagedLine}` : prompt;
51067
51407
  mirror.inboxConsumedSeq,
51068
51408
  ...turnReissueRows.map((item) => item.ledgerSeq ?? 0)
51069
51409
  );
51410
+ await mirror.checkpointInbox();
51070
51411
  clearTurnProviderHold();
51071
51412
  }
51072
51413
  }
@@ -52399,6 +52740,7 @@ async function runLoop(deps, ctx) {
52399
52740
  coordinator,
52400
52741
  seed
52401
52742
  } = ctx;
52743
+ const events = ctx.events ?? new RunEventLane((event) => registry.publish(run2.id, event));
52402
52744
  const agent = budgetedAgent(ctx.agent, profile);
52403
52745
  const { round: round2 } = ctx;
52404
52746
  let { executor } = round2.selection;
@@ -52472,13 +52814,11 @@ async function runLoop(deps, ctx) {
52472
52814
  const pushes = trackPushedBranch(typeof restored.pushedBranch === "string" ? restored.pushedBranch : void 0);
52473
52815
  let budgetEnded = false;
52474
52816
  let recordedPushedBranch;
52475
- const onEvent = (e) => {
52817
+ let modelBudgetEndsAt;
52818
+ const publishEvent = (e, startsRunBudget) => {
52476
52819
  registry.publish(run2.id, e);
52477
52820
  if (isSpanRecord(e)) return;
52478
- if (e.type === "lease") {
52479
- run2.control.startLease(() => e.endsAt - clock4());
52480
- return;
52481
- }
52821
+ if (startsRunBudget) return;
52482
52822
  if (e.type === "tool_call") toolCalls++;
52483
52823
  if (e.type === "run_note" && e.kind === "time_budget_exhausted") budgetEnded = true;
52484
52824
  if (isCodingPrRun) {
@@ -52498,6 +52838,47 @@ async function runLoop(deps, ctx) {
52498
52838
  lastActivity = bookkeeping && !showBookkeeping ? void 0 : cardActivity(e);
52499
52839
  card.update(currentFrame());
52500
52840
  };
52841
+ const onEvent = (e) => {
52842
+ const startsRunBudget = e.type === "lease";
52843
+ if (startsRunBudget) {
52844
+ modelBudgetEndsAt = e.endsAt;
52845
+ run2.control.startLease(() => e.endsAt - clock4());
52846
+ }
52847
+ void events.write(async () => {
52848
+ if ((e.type === "tool_call" || e.type === "tool_result") && typeof registry.commitLiveState === "function") {
52849
+ const summary = registry.getById(run2.id);
52850
+ if (summary?.liveState?.state === "working") {
52851
+ const at = e.at ?? clock4();
52852
+ const bound = e.type === "tool_call" && e.boundMs !== void 0 ? at + e.boundMs : modelBudgetEndsAt ?? summary.liveState.bound;
52853
+ if (bound !== void 0) {
52854
+ const sourceSeq = summary.eventCount + 1;
52855
+ const assignment = {
52856
+ expectedSeq: summary.liveStateSeq ?? 0,
52857
+ at,
52858
+ state: "working",
52859
+ bound,
52860
+ detail: e.type === "tool_call" ? "running a tool" : "model turn",
52861
+ sourceEvents: [{ ...e, seq: sourceSeq }]
52862
+ };
52863
+ try {
52864
+ if (ledgerRun?.tracked()) {
52865
+ const committed = await ledgerRun.assignLiveState(assignment);
52866
+ if (committed.ok) registry.commitLiveState(run2.id, committed);
52867
+ } else {
52868
+ const local = assignRunLiveState(summary.liveState, summary.liveStateSeq ?? 0, assignment);
52869
+ if (local.ok) registry.commitLiveState(run2.id, { ...local, liveStateSeq: sourceSeq });
52870
+ }
52871
+ } catch (err2) {
52872
+ console.warn(
52873
+ `[run] ${msg.threadKey} live-state projection failed: ${err2 instanceof Error ? err2.message : String(err2)}`
52874
+ );
52875
+ }
52876
+ }
52877
+ }
52878
+ }
52879
+ publishEvent(e, startsRunBudget);
52880
+ });
52881
+ };
52501
52882
  for (const s of mcpForRun?.servers ?? []) {
52502
52883
  if (s.unavailable !== void 0)
52503
52884
  onEvent({
@@ -52520,14 +52901,14 @@ async function runLoop(deps, ctx) {
52520
52901
  descriptionArtifact = startReviewDescription({
52521
52902
  store: deps.runStore,
52522
52903
  repoCtx,
52523
- publish: (e) => registry.publish(run2.id, e)
52904
+ publish: (event) => events.publish(event)
52524
52905
  });
52525
52906
  readingDiffBaseline = startReviewReadingDiff({
52526
52907
  executor,
52527
52908
  cfg: deps.config.config.review?.readingDiff,
52528
52909
  env: publicEnv(),
52529
52910
  baseRef: repoCtx.baseRef,
52530
- publish: (e) => registry.publish(run2.id, e),
52911
+ publish: (event) => events.publish(event),
52531
52912
  parent: root
52532
52913
  }).baseline.then((published) => {
52533
52914
  console.log(`[reading-diff] ${msg.threadKey} baseline ${published ? "published" : "none"}`);
@@ -52599,10 +52980,11 @@ async function runLoop(deps, ctx) {
52599
52980
  if (interrupted === void 0) runFailed = true;
52600
52981
  throw err2;
52601
52982
  } finally {
52983
+ await events.drain();
52602
52984
  const calls = callsInFlight(recordEvents(), statusNow());
52603
52985
  commandInFlight = calls.length > 0;
52604
52986
  if (commandInFlight)
52605
- registry.publish(run2.id, {
52987
+ events.publish({
52606
52988
  type: "run_note",
52607
52989
  kind: "workspace_torn_down",
52608
52990
  summary: redactAndCap(
@@ -52676,12 +53058,12 @@ async function runLoop(deps, ctx) {
52676
53058
  let reviewStoppedBeforeStart = false;
52677
53059
  const latchReviewStoppedBeforeStart = () => {
52678
53060
  if (reviewStoppedBeforeStart || agent.name !== "review") return reviewStoppedBeforeStart;
52679
- const events = recordEvents();
52680
- const stopAt = events.findIndex(
53061
+ const events2 = recordEvents();
53062
+ const stopAt = events2.findIndex(
52681
53063
  (event) => event.type === "run_note" && (event.kind === "stop_requested" || event.kind === "stopped")
52682
53064
  );
52683
53065
  if (stopAt < 0) return false;
52684
- reviewStoppedBeforeStart = !events.slice(0, stopAt).some((event) => event.type === "tool_call" && event.tool !== "update_status");
53066
+ reviewStoppedBeforeStart = !events2.slice(0, stopAt).some((event) => event.type === "tool_call" && event.tool !== "update_status");
52685
53067
  return reviewStoppedBeforeStart;
52686
53068
  };
52687
53069
  const clearStoppedReviewTail = () => {
@@ -52696,8 +53078,8 @@ async function runLoop(deps, ctx) {
52696
53078
  };
52697
53079
  const tailSkipped = () => run2.control.requested === "hard" || relaunchEndedRun || latchReviewStoppedBeforeStart();
52698
53080
  const releaseWorkspace = (span) => {
52699
- const events = recordEvents();
52700
- const pushed = pushedBranchesOf(events);
53081
+ const events2 = recordEvents();
53082
+ const pushed = pushedBranchesOf(events2);
52701
53083
  return round2.release({
52702
53084
  hardStopped: run2.control.requested === "hard",
52703
53085
  commandInFlight,
@@ -52715,7 +53097,7 @@ async function runLoop(deps, ctx) {
52715
53097
  const staged = await stageIntoWorkspace(files, {
52716
53098
  store: deps.artifacts,
52717
53099
  threadKey: msg.threadKey,
52718
- publish: (e) => registry.publish(run2.id, e),
53100
+ publish: (event) => events.publish(event),
52719
53101
  nextIndex: nextStagedIndex,
52720
53102
  executor,
52721
53103
  resident: round2.selection.resident !== void 0
@@ -53161,7 +53543,7 @@ async function runLoop(deps, ctx) {
53161
53543
  return { workspace, description: prDescription !== void 0 ? "submitted" : "not_submitted" };
53162
53544
  };
53163
53545
  if (leftBehind) {
53164
- registry.publish(run2.id, {
53546
+ events.publish({
53165
53547
  type: "run_note",
53166
53548
  kind: "work_left_behind",
53167
53549
  summary: oneLine(workLeftBehindSummary(leftBehind)),
@@ -53170,7 +53552,7 @@ async function runLoop(deps, ctx) {
53170
53552
  shell.note("quiet", workLeftBehindLabel(leftBehind));
53171
53553
  }
53172
53554
  if (prDescription) {
53173
- registry.publish(run2.id, {
53555
+ events.publish({
53174
53556
  type: "pr_description",
53175
53557
  description: redactPrDescription(prDescription),
53176
53558
  at: clock4()
@@ -53206,7 +53588,7 @@ async function runLoop(deps, ctx) {
53206
53588
  }
53207
53589
  } : {},
53208
53590
  descriptionTurnRan,
53209
- publish: (e) => registry.publish(run2.id, e),
53591
+ publish: (event) => events.publish(event),
53210
53592
  logKey: msg.threadKey
53211
53593
  })
53212
53594
  );
@@ -53244,7 +53626,7 @@ async function runLoop(deps, ctx) {
53244
53626
  fetchPrHead: deps.fetchPrHead ?? currentPrHeadSha,
53245
53627
  reply: (text) => io.reply(text),
53246
53628
  ack: (text) => replyAck(io, resolved.verbosity, text),
53247
- publish: (e) => registry.publish(run2.id, e),
53629
+ publish: (event) => events.publish(event),
53248
53630
  logKey: msg.threadKey
53249
53631
  })
53250
53632
  );
@@ -53255,7 +53637,7 @@ async function runLoop(deps, ctx) {
53255
53637
  gateBypassed = err2 instanceof HarnessGateBypassedError;
53256
53638
  if (err2 instanceof ModelPolicyRefusedError) failure2 = { kind: "policy_refusal" };
53257
53639
  else if (err2 instanceof ModelTransientFailureError) failure2 = { kind: "provider_transient" };
53258
- registry.publish(run2.id, {
53640
+ events.publish({
53259
53641
  type: "run_note",
53260
53642
  kind: "run_failed",
53261
53643
  summary: redactAndCap(err2 instanceof Error ? err2.message : String(err2), ENDING_NOTE_MAX)
@@ -53264,7 +53646,7 @@ async function runLoop(deps, ctx) {
53264
53646
  await endHarness().catch((endErr) => {
53265
53647
  const detail = `the harness session's end failed after the loop's own error: ${endErr instanceof Error ? endErr.message : String(endErr)}`;
53266
53648
  console.warn(`[run] ${msg.threadKey} ${detail}`);
53267
- registry.publish(run2.id, {
53649
+ events.publish({
53268
53650
  type: "run_note",
53269
53651
  kind: "harness_error",
53270
53652
  summary: redactAndCap(detail, ENDING_NOTE_MAX),
@@ -53273,13 +53655,13 @@ async function runLoop(deps, ctx) {
53273
53655
  });
53274
53656
  await preserveCodingChildWork("ending").catch((salvageErr) => {
53275
53657
  const summary = `the interrupted-work checkpoint failed before teardown: ${salvageErr instanceof Error ? salvageErr.message : String(salvageErr)}`;
53276
- registry.publish(run2.id, { type: "run_note", kind: "work_salvage", summary, at: clock4() });
53658
+ events.publish({ type: "run_note", kind: "work_salvage", summary, at: clock4() });
53277
53659
  shell.note("quiet", summary);
53278
53660
  });
53279
53661
  await root.span("post.workspace_release", (span) => releaseWorkspace(span));
53280
53662
  if (!interrupted) throw err2;
53281
53663
  if (coordinator !== void 0)
53282
- registry.publish(run2.id, {
53664
+ events.publish({
53283
53665
  type: "child_interrupted",
53284
53666
  parentInstanceId: coordinator.parentInstanceId,
53285
53667
  reason: redactAndCap(interrupted.message, ENDING_NOTE_MAX),
@@ -53294,12 +53676,49 @@ async function runLoop(deps, ctx) {
53294
53676
  };
53295
53677
  } finally {
53296
53678
  clearInterval(heartbeat);
53679
+ await events.drain();
53297
53680
  const status3 = statusNow();
53681
+ if (typeof registry.commitLiveState === "function") {
53682
+ const commitBoundary = async (state, at2) => {
53683
+ const summary = registry.getById(run2.id);
53684
+ if (!summary) return;
53685
+ const eventSeq = summary.eventCount + 1;
53686
+ const assignment = state === "ended" ? {
53687
+ expectedSeq: summary.liveStateSeq ?? 0,
53688
+ eventSeq,
53689
+ at: at2,
53690
+ state,
53691
+ cause: causeOfClose(status3, interrupted !== void 0)
53692
+ } : {
53693
+ expectedSeq: summary.liveStateSeq ?? 0,
53694
+ eventSeq,
53695
+ at: at2,
53696
+ state,
53697
+ bound: summary.liveState?.bound ?? at2,
53698
+ detail: "writing the final answer"
53699
+ };
53700
+ if (ledgerRun?.tracked()) {
53701
+ const committed = await ledgerRun.assignLiveState(assignment);
53702
+ if (committed.ok) registry.commitLiveState(run2.id, committed);
53703
+ return;
53704
+ }
53705
+ const local = assignRunLiveState(summary.liveState, summary.liveStateSeq ?? 0, assignment);
53706
+ if (!local.ok || !local.event) return;
53707
+ registry.commitLiveState(run2.id, {
53708
+ ...local,
53709
+ event: { ...local.event, seq: eventSeq },
53710
+ liveStateSeq: eventSeq
53711
+ });
53712
+ };
53713
+ const at = clock4();
53714
+ await commitBoundary("wrapping_up", at);
53715
+ await commitBoundary("ended", clock4());
53716
+ }
53298
53717
  registry.finish(run2.id, status3);
53299
53718
  const snap = registry.snapshot(run2.id, run2.token);
53300
- const events = snap?.events ?? [];
53719
+ const recordEventList = snap?.events ?? [];
53301
53720
  const finishedAt = snap?.finishedAt ?? clock4();
53302
- const diagnosis = analyzeRunFriction(events, {
53721
+ const diagnosis = analyzeRunFriction(recordEventList, {
53303
53722
  finished: true,
53304
53723
  truncated: snap?.truncated ?? false,
53305
53724
  window: { start: snap?.receivedAt ?? startedAt, end: finishedAt }
@@ -53432,10 +53851,13 @@ var init_runLoop = __esm({
53432
53851
  init_readingDiff();
53433
53852
  init_reviewDescription();
53434
53853
  init_runEvents();
53854
+ init_runEventLane();
53435
53855
  init_redact();
53436
53856
  init_runFriction();
53437
53857
  init_llmOutput();
53438
53858
  init_runRecord();
53859
+ init_runLiveState();
53860
+ init_decide();
53439
53861
  init_statusCardLabel();
53440
53862
  init_runPace();
53441
53863
  init_statusCardFrame();
@@ -54387,6 +54809,34 @@ async function runShipBranch(deps, msg, io, ctx) {
54387
54809
  ...REPLAY_EVERYTHING
54388
54810
  });
54389
54811
  }
54812
+ const admittedAt = clock4();
54813
+ const admittedEventSeq = (registry.getById(run2.id)?.eventCount ?? 0) + 1;
54814
+ const admittedAssignment = {
54815
+ expectedSeq: 0,
54816
+ eventSeq: admittedEventSeq,
54817
+ at: admittedAt,
54818
+ state: "admitted",
54819
+ bound: admittedAt + minutesToMs(profile.minutes),
54820
+ detail: "waiting for the pipeline to start"
54821
+ };
54822
+ if (ledgerRun) {
54823
+ const committed = await ledgerRun.assignLiveState(admittedAssignment);
54824
+ if (!committed.ok || !registry.commitLiveState(run2.id, committed))
54825
+ throw new RefusalError(
54826
+ refusalOf(
54827
+ "setup_failed",
54828
+ `hosted live state start was not committed (${committed.ok ? "registry sequence" : committed.reason})`
54829
+ )
54830
+ );
54831
+ } else {
54832
+ const local = assignRunLiveState(void 0, 0, admittedAssignment);
54833
+ if (local.ok && local.event)
54834
+ registry.commitLiveState(run2.id, {
54835
+ ...local,
54836
+ event: { ...local.event, seq: admittedEventSeq },
54837
+ liveStateSeq: admittedEventSeq
54838
+ });
54839
+ }
54390
54840
  const hostRefused = opened.kind === "untracked" && opened.why === "thread-live";
54391
54841
  const liveUrl = liveViewLink(run2.id, run2.token);
54392
54842
  ctx.live.runId = run2.id;
@@ -54457,7 +54907,23 @@ async function runShipBranch(deps, msg, io, ctx) {
54457
54907
  instanceId: outcome.instanceId,
54458
54908
  until: clock4() + minutesToMs(caps.maxMinutes + HOSTED_DEADLINE_MARGIN_MINUTES)
54459
54909
  };
54460
- ledgerRun.setState({ hosting });
54910
+ const summary = registry.getById(run2.id);
54911
+ const committed = await ledgerRun.assignLiveState({
54912
+ expectedSeq: summary?.liveStateSeq ?? 0,
54913
+ eventSeq: (summary?.eventCount ?? 0) + 1,
54914
+ at: clock4(),
54915
+ state: "working",
54916
+ bound: hosting.until,
54917
+ detail: HOSTED_PIPELINE_STARTING_DETAIL,
54918
+ statePatch: { hosting }
54919
+ });
54920
+ if (!committed.ok || !registry.commitLiveState(run2.id, committed))
54921
+ throw new RefusalError(
54922
+ refusalOf(
54923
+ "setup_failed",
54924
+ `hosted live state transition was not committed (${committed.ok ? "registry sequence" : committed.reason})`
54925
+ )
54926
+ );
54461
54927
  registry.publish(run2.id, {
54462
54928
  type: "run_meta",
54463
54929
  agent: agent.name,
@@ -54565,6 +55031,8 @@ var init_ship = __esm({
54565
55031
  init_runFriction();
54566
55032
  init_run2();
54567
55033
  init_runRegistry();
55034
+ init_runLiveState();
55035
+ init_pipelineStanding();
54568
55036
  init_statusCardFrame();
54569
55037
  init_types5();
54570
55038
  init_refusal();
@@ -55744,12 +56212,12 @@ async function dispatch(deps, msg, io, opts = {}) {
55744
56212
  ...operatorEvent ? { operator: operatorEvent } : {},
55745
56213
  ...references.conversations.length > 0 ? { references } : {}
55746
56214
  });
55747
- const { run: run2, runId: runId3, channelVisibility, liveUrl, publishText, publishMeta } = registration;
56215
+ const { run: run2, runId: runId3, channelVisibility, liveUrl, events, publishText, publishMeta } = registration;
55748
56216
  registered = run2;
55749
56217
  for (const summary of seedNotes)
55750
- registry.publish(run2.id, { type: "run_note", kind: "seed", summary: oneLine(summary), at: clock4() });
56218
+ events.publish({ type: "run_note", kind: "seed", summary: oneLine(summary), at: clock4() });
55751
56219
  if (opts.redispatch)
55752
- registry.publish(run2.id, {
56220
+ events.publish({
55753
56221
  type: "run_note",
55754
56222
  kind: "redispatch",
55755
56223
  summary: `confirmed after question ${opts.redispatch.code}`,
@@ -55764,7 +56232,7 @@ async function dispatch(deps, msg, io, opts = {}) {
55764
56232
  threadKey: msg.threadKey,
55765
56233
  nextIndex: nextStagedIndex,
55766
56234
  preserveWorkspaceIndexes: true,
55767
- publish: (e) => registry.publish(runId3, e)
56235
+ publish: (event) => events.publish(event)
55768
56236
  }) : void 0;
55769
56237
  const threadAssets = !resume && deps.artifacts && thread && thread.length > 0 ? readThreadAssets({ runs: runsService, store: deps.artifacts }, msg.threadKey).then(
55770
56238
  (assets) => assets.filter((a) => a.runId !== runId3)
@@ -55775,7 +56243,7 @@ async function dispatch(deps, msg, io, opts = {}) {
55775
56243
  {
55776
56244
  nextIndex: nextStagedIndex,
55777
56245
  messageId: messageIdOf(msg, runId3),
55778
- publish: (e) => registry.publish(runId3, e)
56246
+ publish: (event) => events.publish(event)
55779
56247
  }
55780
56248
  )
55781
56249
  ) : void 0;
@@ -55807,7 +56275,7 @@ async function dispatch(deps, msg, io, opts = {}) {
55807
56275
  reserved = reservation.reserved;
55808
56276
  requestRow = reservation.requestRow;
55809
56277
  if (reservation.untrackedWhy !== void 0) {
55810
- registry.publish(runId3, {
56278
+ events.publish({
55811
56279
  type: "run_note",
55812
56280
  kind: "ledger_untracked",
55813
56281
  summary: redactAndCap(
@@ -55821,6 +56289,100 @@ async function dispatch(deps, msg, io, opts = {}) {
55821
56289
  shell.note("debug", "untracked by the ledger");
55822
56290
  }
55823
56291
  }
56292
+ if (typeof registry.commitLiveState === "function") {
56293
+ await events.write(async () => {
56294
+ const current = registry.getById(runId3);
56295
+ if (current && current.liveState === void 0) {
56296
+ const at = clock4();
56297
+ const eventSeq = current.eventCount + 1;
56298
+ const assignment = {
56299
+ expectedSeq: 0,
56300
+ eventSeq,
56301
+ at,
56302
+ state: "admitted",
56303
+ bound: resume ? at + resume.plan.remainingMs : Math.max(startedAt + minutesToMs(profile.minutes), at + minutesToMs(profile.minutes)),
56304
+ detail: "waiting to attach the workspace",
56305
+ // A reservation is not subscribed to the registry until promotion.
56306
+ // Commit the setup stream that already exists with admission, or
56307
+ // advancing its ledger cursor here would make promotion skip it.
56308
+ ...reserved ? {
56309
+ sourceEvents: (registry.snapshotById(runId3)?.events ?? []).map((event) => ({
56310
+ ...event,
56311
+ seq: event.seq
56312
+ }))
56313
+ } : {},
56314
+ ...(current.liveStateSeq ?? 0) > 0 ? { restart: true } : {}
56315
+ };
56316
+ const tracked = reserved ?? ledgerRun;
56317
+ if (tracked?.tracked()) {
56318
+ let committed = await tracked.assignLiveState(assignment);
56319
+ if (!committed.ok && committed.reason === "stale-sequence" && (current.liveStateSeq ?? 0) > 0)
56320
+ committed = await tracked.assignLiveState({
56321
+ ...assignment,
56322
+ expectedSeq: current.liveStateSeq ?? 0,
56323
+ sourceEvents: void 0,
56324
+ restart: true
56325
+ });
56326
+ if (!committed.ok || !registry.commitLiveState(runId3, committed))
56327
+ throw new Error(
56328
+ `live state admission was not committed (${committed.ok ? "registry sequence" : committed.reason})`
56329
+ );
56330
+ } else {
56331
+ const expectedSeq = current.liveStateSeq ?? 0;
56332
+ const local = assignRunLiveState(void 0, expectedSeq, { ...assignment, expectedSeq });
56333
+ if (!local.ok || !local.event) throw new Error("live state admission was invalid");
56334
+ registry.commitLiveState(runId3, {
56335
+ ...local,
56336
+ event: { ...local.event, seq: eventSeq },
56337
+ liveStateSeq: eventSeq
56338
+ });
56339
+ }
56340
+ }
56341
+ });
56342
+ }
56343
+ const assignLive = async (next, at, detail) => {
56344
+ if (typeof registry.commitLiveState !== "function") return true;
56345
+ let accepted = false;
56346
+ await events.write(async () => {
56347
+ const summary = registry.getById(runId3);
56348
+ if (!summary) return;
56349
+ const eventSeq = summary.eventCount + 1;
56350
+ const assignment = {
56351
+ expectedSeq: summary.liveStateSeq ?? 0,
56352
+ eventSeq,
56353
+ at,
56354
+ state: next.state,
56355
+ bound: next.bound,
56356
+ ...detail !== void 0 ? { detail } : {}
56357
+ };
56358
+ const tracked = ledgerRun ?? reserved;
56359
+ if (tracked) {
56360
+ const committed = await tracked.assignLiveState(assignment);
56361
+ accepted = committed.ok && (registry.commitLiveState?.(runId3, committed) ?? true);
56362
+ return;
56363
+ }
56364
+ const local = assignRunLiveState(summary.liveState, summary.liveStateSeq ?? 0, assignment);
56365
+ if (!local.ok) return;
56366
+ accepted = registry.commitLiveState?.(runId3, {
56367
+ ...local,
56368
+ ...local.event ? { event: { ...local.event, seq: eventSeq } } : {},
56369
+ liveStateSeq: local.event ? eventSeq : summary.liveStateSeq ?? 0
56370
+ }) ?? true;
56371
+ });
56372
+ return accepted;
56373
+ };
56374
+ let residentAttachAttempt = 0;
56375
+ const observeResidentLiveState = async (observation) => {
56376
+ if (observation.attempt < residentAttachAttempt) return;
56377
+ residentAttachAttempt = observation.attempt;
56378
+ const accepted = await assignLive(
56379
+ { state: observation.state, bound: observation.bound },
56380
+ clock4(),
56381
+ liveStateWords(observation.state)
56382
+ );
56383
+ if (!accepted) throw new Error("resident live-state observation was stale or could not be committed");
56384
+ shell.setSetupLabel(`${liveStateWords(observation.state)}\u2026`);
56385
+ };
55824
56386
  const reattach = resume ? carriedWorkspaceBinding(resume.row) : void 0;
55825
56387
  const control = registered?.control;
55826
56388
  const attach = await attachWorkspace(deps, {
@@ -55840,7 +56402,8 @@ async function dispatch(deps, msg, io, opts = {}) {
55840
56402
  // during the attach ends its wake wait at once, and once the harness
55841
56403
  // starts the lease every attach the executor opens is clipped to the
55842
56404
  // run's remaining clock (execution.md item 9).
55843
- ...control ? { stopSignal: control.hardSignal, remainingMs: () => control.remainingMs() } : {}
56405
+ ...control ? { stopSignal: control.hardSignal, remainingMs: () => control.remainingMs() } : {},
56406
+ onLiveStateObservation: observeResidentLiveState
55844
56407
  });
55845
56408
  if (attach.kind === "refused") return ended;
55846
56409
  if (attach.kind === "stopped") {
@@ -55892,6 +56455,17 @@ async function dispatch(deps, msg, io, opts = {}) {
55892
56455
  return ended;
55893
56456
  }
55894
56457
  const { round: round2 } = attach;
56458
+ if (typeof registry.commitLiveState === "function") {
56459
+ const summary = registry.getById(runId3);
56460
+ const bound2 = summary?.liveState?.bound ?? startedAt + minutesToMs(profile.minutes);
56461
+ if (summary?.liveState && (summary.liveState.state === "waiting_deploy" || summary.liveState.state === "waiting_repository") && round2.selection.backend !== "resident") {
56462
+ if (!await assignLive({ state: "falling_back", bound: bound2 }, clock4(), "switching to a fallback workspace"))
56463
+ throw new Error("fallback live state could not be committed");
56464
+ }
56465
+ if (!await assignLive({ state: "preparing", bound: bound2 }, clock4(), "preparing the workspace"))
56466
+ throw new Error("preparation live state could not be committed");
56467
+ shell.setSetupLabel(`${liveStateWords("preparing")}\u2026`);
56468
+ }
55895
56469
  if (resume && ledgerRun) {
55896
56470
  const rebound = workspaceBindingFor(round2.selection, profile.machine);
55897
56471
  if (rebound !== void 0) ledgerRun.setState({ binding: rebound });
@@ -56073,6 +56647,12 @@ async function dispatch(deps, msg, io, opts = {}) {
56073
56647
  markUntracked: () => shell.note("debug", "untracked by the ledger"),
56074
56648
  ...seedActors !== void 0 ? { seedActors } : {}
56075
56649
  });
56650
+ if (typeof registry.commitLiveState === "function") {
56651
+ const summary = registry.getById(runId3);
56652
+ const bound2 = summary?.liveState?.bound ?? startedAt + minutesToMs(profile.minutes);
56653
+ if (!await assignLive({ state: "working", bound: bound2 }, clock4(), "model turn"))
56654
+ throw new Error("working live state could not be committed");
56655
+ }
56076
56656
  const sessionTools = sessionCapabilityFor(
56077
56657
  ledgerRun,
56078
56658
  deps.runLedger,
@@ -56114,6 +56694,7 @@ async function dispatch(deps, msg, io, opts = {}) {
56114
56694
  mcpForRun,
56115
56695
  run: run2,
56116
56696
  registry,
56697
+ events,
56117
56698
  round: round2,
56118
56699
  admitted,
56119
56700
  ledgerRun,
@@ -56442,6 +57023,8 @@ var init_dispatcher = __esm({
56442
57023
  init_registry();
56443
57024
  init_budgets();
56444
57025
  init_trace();
57026
+ init_runLiveState();
57027
+ init_decide();
56445
57028
  init_requestTrace();
56446
57029
  init_runShape();
56447
57030
  init_runEvents();
@@ -56973,7 +57556,7 @@ function createLedgerWriteThrough(opts) {
56973
57556
  }
56974
57557
  }
56975
57558
  event(event, seq) {
56976
- if (this.detached || this.finished) return;
57559
+ if (this.detached || this.finished || seq <= this.lastSeq) return;
56977
57560
  this.lastSeq = seq;
56978
57561
  const e = event;
56979
57562
  if (typeof e.at === "number") this.factLastEventAt = e.at;
@@ -56994,6 +57577,30 @@ function createLedgerWriteThrough(opts) {
56994
57577
  };
56995
57578
  this.flusher.push({ ...event, seq });
56996
57579
  }
57580
+ async assignLiveState(assignment) {
57581
+ if (this.detached || this.finished) return { ok: false, reason: "unknown-run" };
57582
+ await this.flusher.flush();
57583
+ await this.stateSending;
57584
+ try {
57585
+ const result = await ledger.assignLiveState(this.runId, gen, assignment);
57586
+ if (!result.ok) {
57587
+ if (result.reason === "fenced" || result.reason === "unknown-run")
57588
+ this.detach(`live state refused (${result.reason})`);
57589
+ return result;
57590
+ }
57591
+ this.state = {
57592
+ ...this.state,
57593
+ ...assignment.statePatch,
57594
+ liveState: result.liveState,
57595
+ liveStateSeq: result.liveStateSeq
57596
+ };
57597
+ this.lastSeq = Math.max(this.lastSeq, result.liveStateSeq);
57598
+ return result;
57599
+ } catch (err2) {
57600
+ warn(`[ledger] ${this.threadKey} live state not written: ${describe9(err2)}`);
57601
+ return { ok: false, reason: "unknown-run" };
57602
+ }
57603
+ }
56997
57604
  setState(patch) {
56998
57605
  if (this.detached) return;
56999
57606
  this.state = { ...this.state, ...patch };
@@ -57378,6 +57985,9 @@ var init_writeThrough = __esm({
57378
57985
  }
57379
57986
  event(_event, _seq) {
57380
57987
  }
57988
+ async assignLiveState(_assignment) {
57989
+ return { ok: false, reason: "unknown-run" };
57990
+ }
57381
57991
  setState(_patch) {
57382
57992
  }
57383
57993
  async finishing() {
@@ -70226,7 +70836,13 @@ async function launchResumes(deps, resumable, opts) {
70226
70836
  const handle2 = registry.create(row2.meta.label, rehostMeta(row2), {
70227
70837
  id: row2.runId,
70228
70838
  startedAt: row2.startedAt,
70229
- replay: run2.events
70839
+ replay: run2.events,
70840
+ ...row2.liveState !== void 0 ? {
70841
+ liveState: {
70842
+ liveState: row2.liveState,
70843
+ ...row2.liveStateSeq !== void 0 ? { liveStateSeq: row2.liveStateSeq } : {}
70844
+ }
70845
+ } : {}
70230
70846
  });
70231
70847
  const adopted = deps.runLedger.adopt({
70232
70848
  runId: row2.runId,
@@ -70667,6 +71283,72 @@ var init_adminModelProxy = __esm({
70667
71283
  }
70668
71284
  });
70669
71285
 
71286
+ // ../../src/core/providerLiveStateCoordinator.ts
71287
+ function createProviderLiveStateCoordinator(deps) {
71288
+ let tail = Promise.resolve();
71289
+ const enqueue = (label, work) => {
71290
+ const next = tail.then(work).catch((error) => {
71291
+ deps.warn(`${label} failed: ${describe11(error)}`);
71292
+ });
71293
+ tail = next;
71294
+ return next;
71295
+ };
71296
+ return {
71297
+ level: (provider, side, cause) => enqueue(`provider ${side} report for ${provider}`, async () => {
71298
+ await deps.runLedger.planeLevel({
71299
+ provider,
71300
+ name: "provider",
71301
+ side,
71302
+ ...side === "down" && cause !== void 0 ? { cause } : {}
71303
+ });
71304
+ if (side !== "up" || !deps.ledger) return;
71305
+ const rows = await deps.ledger.listLive();
71306
+ for (const row2 of rows) {
71307
+ if (row2.state.liveProvider !== provider || row2.liveState?.state !== "waiting_provider") continue;
71308
+ const tracked = deps.runLedger.liveRuns().find((run2) => run2.runId === row2.runId);
71309
+ const summary = deps.registry.getById(row2.runId);
71310
+ if (!tracked || !summary || row2.liveState.bound === void 0) continue;
71311
+ const committed = await tracked.assignLiveState({
71312
+ expectedSeq: summary.liveStateSeq ?? 0,
71313
+ eventSeq: summary.eventCount + 1,
71314
+ at: deps.clock(),
71315
+ state: "working",
71316
+ bound: row2.liveState.bound,
71317
+ detail: "model turn",
71318
+ statePatch: { liveProvider: void 0 }
71319
+ });
71320
+ if (committed.ok) deps.registry.commitLiveState(row2.runId, committed);
71321
+ }
71322
+ }),
71323
+ park: (runId3, provider) => enqueue(`provider park for ${runId3}`, async () => {
71324
+ await deps.runLedger.planePark(runId3, provider);
71325
+ const summary = deps.registry.getById(runId3);
71326
+ const tracked = deps.runLedger.liveRuns().find((run2) => run2.runId === runId3);
71327
+ const events = deps.registry.snapshotById(runId3)?.events ?? [];
71328
+ let leaseEndsAt;
71329
+ for (const event of events) if (event.type === "lease") leaseEndsAt = event.endsAt;
71330
+ if (!summary || !tracked || leaseEndsAt === void 0) return;
71331
+ const committed = await tracked.assignLiveState({
71332
+ expectedSeq: summary.liveStateSeq ?? 0,
71333
+ eventSeq: summary.eventCount + 1,
71334
+ at: deps.clock(),
71335
+ state: "waiting_provider",
71336
+ bound: leaseEndsAt,
71337
+ detail: "waiting for the model provider",
71338
+ statePatch: { liveProvider: provider }
71339
+ });
71340
+ if (committed.ok) deps.registry.commitLiveState(runId3, committed);
71341
+ })
71342
+ };
71343
+ }
71344
+ var describe11;
71345
+ var init_providerLiveStateCoordinator = __esm({
71346
+ "../../src/core/providerLiveStateCoordinator.ts"() {
71347
+ "use strict";
71348
+ describe11 = (error) => error instanceof Error ? error.message : String(error);
71349
+ }
71350
+ });
71351
+
70670
71352
  // ../../src/channels/adminTraceLog.ts
70671
71353
  function parseTraceLogQuery(search) {
70672
71354
  const query = {};
@@ -71176,7 +71858,7 @@ async function openThreadFromRequester(deps, instance, lead, at) {
71176
71858
  }
71177
71859
  };
71178
71860
  } catch (err2) {
71179
- return { ok: false, response: json3(502, { ok: false, error: "thread_failed", message: describe11(err2), at }) };
71861
+ return { ok: false, response: json3(502, { ok: false, error: "thread_failed", message: describe12(err2), at }) };
71180
71862
  }
71181
71863
  }
71182
71864
  function authorizeStep(headers, step, deps) {
@@ -71300,8 +71982,8 @@ async function spawn6(body, deps) {
71300
71982
  try {
71301
71983
  turn = await composeChild(req.brief, instance, row2, briefReaders(deps, instance));
71302
71984
  } catch (err2) {
71303
- log(`[coordinator] ${instance.id} ${req.step}: the brief could not be composed: ${describe11(err2)}`);
71304
- return json3(502, { ok: false, error: "brief_failed", message: describe11(err2), at });
71985
+ log(`[coordinator] ${instance.id} ${req.step}: the brief could not be composed: ${describe12(err2)}`);
71986
+ return json3(502, { ok: false, error: "brief_failed", message: describe12(err2), at });
71305
71987
  }
71306
71988
  } else {
71307
71989
  turn = { prompt: req.prompt };
@@ -71371,7 +72053,7 @@ ${foldThreadEvents(folded)}` };
71371
72053
  });
71372
72054
  } catch (err2) {
71373
72055
  releaseAdmission();
71374
- return json3(502, { ok: false, error: "spawn_failed", message: describe11(err2), at });
72056
+ return json3(502, { ok: false, error: "spawn_failed", message: describe12(err2), at });
71375
72057
  }
71376
72058
  const settled = dispatching.then(
71377
72059
  (outcome) => ({ kind: "ended", outcome }),
@@ -71380,7 +72062,7 @@ ${foldThreadEvents(folded)}` };
71380
72062
  void settled.then((end) => {
71381
72063
  releaseAdmission();
71382
72064
  if (end.kind === "threw")
71383
- log(`[coordinator] ${instance.id} ${req.step}: the child's dispatch threw: ${describe11(end.err)}`);
72065
+ log(`[coordinator] ${instance.id} ${req.step}: the child's dispatch threw: ${describe12(end.err)}`);
71384
72066
  });
71385
72067
  const first = await Promise.race([started.then((id) => ({ kind: "started", id })), settled]);
71386
72068
  if (first.kind === "started" || startedId !== void 0) {
@@ -71390,7 +72072,7 @@ ${foldThreadEvents(folded)}` };
71390
72072
  { instanceId: instance.id, unit: row2.unit },
71391
72073
  folded.map((e) => e.seq),
71392
72074
  req.step
71393
- ).catch((err2) => log(`[coordinator] ${instance.id} ${req.step}: the consumed marks failed: ${describe11(err2)}`));
72075
+ ).catch((err2) => log(`[coordinator] ${instance.id} ${req.step}: the consumed marks failed: ${describe12(err2)}`));
71394
72076
  log(
71395
72077
  `[coordinator] ${instance.id} ${req.step}: folded ${folded.length} thread event(s) into the ${req.preset} child`
71396
72078
  );
@@ -71398,7 +72080,7 @@ ${foldThreadEvents(folded)}` };
71398
72080
  log(`[coordinator] ${instance.id} ${req.step}: spawned ${req.preset} run ${runId3} in ${threadKey}`);
71399
72081
  return json3(200, { ok: true, runId: runId3, threadKey, at });
71400
72082
  }
71401
- if (first.kind === "threw") return json3(502, { ok: false, error: "spawn_failed", message: describe11(first.err), at });
72083
+ if (first.kind === "threw") return json3(502, { ok: false, error: "spawn_failed", message: describe12(first.err), at });
71402
72084
  const refusal = first.outcome.refusal;
71403
72085
  if (refusal === "coordinator_thread_live") {
71404
72086
  const now = await liveOnThread(deps.runs, instance, threadKey);
@@ -71618,7 +72300,7 @@ async function readRecord(body, deps) {
71618
72300
  try {
71619
72301
  pullRequest = await childPullRequestState(deps, instanceRow, typeof body.unit === "string" ? body.unit : void 0);
71620
72302
  } catch (err2) {
71621
- return json3(502, { ok: false, error: "github_unavailable", message: describe11(err2), at });
72303
+ return json3(502, { ok: false, error: "github_unavailable", message: describe12(err2), at });
71622
72304
  }
71623
72305
  if (!view.finished)
71624
72306
  return json3(200, {
@@ -71934,7 +72616,7 @@ async function prCheck(body, deps) {
71934
72616
  if (recover === void 0) {
71935
72617
  const ahead = instance.base === void 0 ? void 0 : await deps.commitsOverBase(instance.repo, instance.base, branch2).catch((err2) => {
71936
72618
  (deps.log ?? console.log)(
71937
- `[coordinator] ${instance.id} pr-check: the compare of ${branch2} over ${instance.base} could not be read: ${describe11(err2)}`
72619
+ `[coordinator] ${instance.id} pr-check: the compare of ${branch2} over ${instance.base} could not be read: ${describe12(err2)}`
71938
72620
  );
71939
72621
  return void 0;
71940
72622
  });
@@ -71958,7 +72640,7 @@ async function prCheck(body, deps) {
71958
72640
  if (state?.state !== "merged") throw new Error(`${instance.repo}#${merged.number} no longer reads merged`);
71959
72641
  return json3(200, { ok: true, ...state, at });
71960
72642
  } catch (err2) {
71961
- return json3(502, { ok: false, error: "github_unavailable", message: describe11(err2), at });
72643
+ return json3(502, { ok: false, error: "github_unavailable", message: describe12(err2), at });
71962
72644
  }
71963
72645
  }
71964
72646
  async function hostRunOf(deps, instance) {
@@ -71971,14 +72653,68 @@ async function hostRunOf(deps, instance) {
71971
72653
  return { kind: "not_host" };
71972
72654
  return { kind: "untracked" };
71973
72655
  }
71974
- function hostPublish(deps, instance, runId3, events, at) {
71975
- for (const event of events) deps.registry.publish(runId3, event);
72656
+ async function hostPublish(deps, instance, runId3, events, at) {
71976
72657
  const caps = instance.caps ?? resolveShipCaps(void 0);
71977
72658
  const hosting = {
71978
72659
  instanceId: instance.id,
71979
72660
  until: at + minutesToMs(caps.maxMinutes + HOSTED_DEADLINE_MARGIN_MINUTES)
71980
72661
  };
71981
- deps.ledgerRuns().find((run2) => run2.runId === runId3)?.setState({ hosting });
72662
+ const ledgerRun = deps.ledgerRuns().find((run2) => run2.runId === runId3);
72663
+ let summary = deps.registry.getById(runId3);
72664
+ if (ledgerRun && summary) {
72665
+ if (summary.liveState === void 0) {
72666
+ const admitted = await ledgerRun.assignLiveState({
72667
+ expectedSeq: 0,
72668
+ eventSeq: summary.eventCount + 1,
72669
+ at,
72670
+ state: "admitted",
72671
+ bound: hosting.until,
72672
+ detail: "waiting for the pipeline hand-off"
72673
+ });
72674
+ if (!admitted.ok || !deps.registry.commitLiveState(runId3, admitted))
72675
+ throw new Error(
72676
+ `hosted live state backfill was not committed (${admitted.ok ? "registry sequence" : admitted.reason})`
72677
+ );
72678
+ summary = deps.registry.getById(runId3);
72679
+ if (!summary) throw new Error("hosted run disappeared during live-state backfill");
72680
+ const working = await ledgerRun.assignLiveState({
72681
+ expectedSeq: summary.liveStateSeq ?? 0,
72682
+ eventSeq: summary.eventCount + 1,
72683
+ at,
72684
+ state: "working",
72685
+ bound: hosting.until,
72686
+ detail: "pipeline starting",
72687
+ statePatch: { hosting }
72688
+ });
72689
+ if (!working.ok || !deps.registry.commitLiveState(runId3, working))
72690
+ throw new Error(
72691
+ `hosted working backfill was not committed (${working.ok ? "registry sequence" : working.reason})`
72692
+ );
72693
+ summary = deps.registry.getById(runId3);
72694
+ if (!summary) throw new Error("hosted run disappeared after live-state backfill");
72695
+ }
72696
+ const firstSeq = summary.eventCount + 1;
72697
+ const sourceEvents = events.map((event, index) => ({ ...event, seq: firstSeq + index }));
72698
+ const prior = deps.registry.snapshotById(runId3)?.events.filter((event) => event.type === "ship_round" || event.type === "ship_unit") ?? [];
72699
+ const standing = pipelineStandingOf([...prior, ...events]);
72700
+ const stage = standing.changes.at(-1)?.stage ?? "idle";
72701
+ const committed = await ledgerRun.assignLiveState({
72702
+ expectedSeq: summary.liveStateSeq ?? 0,
72703
+ at,
72704
+ state: "working",
72705
+ bound: hosting.until,
72706
+ detail: hostedStageDetail(stage),
72707
+ statePatch: { hosting },
72708
+ sourceEvents
72709
+ });
72710
+ if (!committed.ok || !deps.registry.commitLiveState(runId3, committed))
72711
+ throw new Error(
72712
+ `hosted live state refresh was not committed (${committed.ok ? "registry sequence" : committed.reason})`
72713
+ );
72714
+ } else {
72715
+ ledgerRun?.setState({ hosting });
72716
+ }
72717
+ for (const event of events) deps.registry.publish(runId3, event);
71982
72718
  }
71983
72719
  function namesForeignRun(instance, body) {
71984
72720
  return typeof body.runId === "string" && body.runId !== instance.runId;
@@ -72064,7 +72800,7 @@ async function unitStart(body, deps) {
72064
72800
  row2 = { ...row2, startedAt: row2.startedAt ?? at };
72065
72801
  await deps.instances.putUnits([row2]);
72066
72802
  if (host.kind === "host")
72067
- hostPublish(
72803
+ await hostPublish(
72068
72804
  deps,
72069
72805
  instance,
72070
72806
  host.runId,
@@ -72113,7 +72849,7 @@ async function branch(body, deps) {
72113
72849
  await deps.createBranchRef(instance.repo, name, base);
72114
72850
  return json3(200, { ok: true, branch: name, base, at });
72115
72851
  } catch (err2) {
72116
- return json3(200, { ok: false, reason: describe11(err2), at });
72852
+ return json3(200, { ok: false, reason: describe12(err2), at });
72117
72853
  }
72118
72854
  }
72119
72855
  function unitLines(units, generated, severity) {
@@ -72194,7 +72930,7 @@ async function round(body, deps) {
72194
72930
  await deps.instances.putUnits([updated]);
72195
72931
  if (host.kind === "host") {
72196
72932
  const thread = unitThread(instance, updated, units.length);
72197
- hostPublish(
72933
+ await hostPublish(
72198
72934
  deps,
72199
72935
  instance,
72200
72936
  host.runId,
@@ -72228,7 +72964,7 @@ async function round(body, deps) {
72228
72964
  instance,
72229
72965
  units.map((u) => u.unit === updated.unit ? updated : u)
72230
72966
  ).catch(
72231
- (err2) => (deps.log ?? console.warn)(`[coordinator] ${instance.id}: the card could not be redrawn: ${describe11(err2)}`)
72967
+ (err2) => (deps.log ?? console.warn)(`[coordinator] ${instance.id}: the card could not be redrawn: ${describe12(err2)}`)
72232
72968
  );
72233
72969
  return json3(200, { ok: true, at });
72234
72970
  }
@@ -72402,7 +73138,7 @@ async function unitWake(body, deps) {
72402
73138
  instance,
72403
73139
  units.map((u) => u.unit === visible.unit ? visible : u)
72404
73140
  ).catch(
72405
- (err2) => (deps.log ?? console.warn)(`[coordinator] ${instance.id}: the card could not be redrawn: ${describe11(err2)}`)
73141
+ (err2) => (deps.log ?? console.warn)(`[coordinator] ${instance.id}: the card could not be redrawn: ${describe12(err2)}`)
72406
73142
  );
72407
73143
  return json3(200, { ok: true, answer, at });
72408
73144
  }
@@ -72465,7 +73201,7 @@ async function unitEnd(body, deps) {
72465
73201
  deps.runnerOwnership?.release(instance.repo, updated.pr.number);
72466
73202
  const thread = unitThread(instance, updated, units.length);
72467
73203
  if (host.kind === "host")
72468
- hostPublish(
73204
+ await hostPublish(
72469
73205
  deps,
72470
73206
  instance,
72471
73207
  host.runId,
@@ -72496,7 +73232,7 @@ async function unitEnd(body, deps) {
72496
73232
  `unit-end:${row2.unit}`
72497
73233
  ).catch(
72498
73234
  (err2) => (deps.log ?? console.warn)(
72499
- `[coordinator] ${instance.id} ${row2.unit}: the leftover marks failed: ${describe11(err2)}`
73235
+ `[coordinator] ${instance.id} ${row2.unit}: the leftover marks failed: ${describe12(err2)}`
72500
73236
  )
72501
73237
  );
72502
73238
  const freshTurn = {
@@ -72514,7 +73250,7 @@ async function unitEnd(body, deps) {
72514
73250
  };
72515
73251
  void deps.dispatch(freshTurn, io).catch(
72516
73252
  (err2) => (deps.log ?? console.warn)(
72517
- `[coordinator] ${instance.id} ${row2.unit}: the leftovers' fresh turn threw: ${describe11(err2)}`
73253
+ `[coordinator] ${instance.id} ${row2.unit}: the leftovers' fresh turn threw: ${describe12(err2)}`
72518
73254
  )
72519
73255
  );
72520
73256
  (deps.log ?? console.log)(
@@ -72531,7 +73267,7 @@ async function unitEnd(body, deps) {
72531
73267
  told = true;
72532
73268
  } catch (err2) {
72533
73269
  (deps.log ?? console.warn)(
72534
- `[coordinator] ${instance.id} ${row2.unit}: the report could not be posted: ${describe11(err2)}`
73270
+ `[coordinator] ${instance.id} ${row2.unit}: the report could not be posted: ${describe12(err2)}`
72535
73271
  );
72536
73272
  }
72537
73273
  }
@@ -72545,7 +73281,7 @@ ${ending.report}` + (rendered !== void 0 ? `
72545
73281
  ${rendered}` : "");
72546
73282
  await deps.github.commentIssue(instance.repo, row2.issue, comment).catch(
72547
73283
  (err2) => (deps.log ?? console.warn)(
72548
- `[coordinator] ${instance.id} ${row2.unit}: the board comment could not be posted: ${describe11(err2)}`
73284
+ `[coordinator] ${instance.id} ${row2.unit}: the board comment could not be posted: ${describe12(err2)}`
72549
73285
  )
72550
73286
  );
72551
73287
  }
@@ -72556,7 +73292,7 @@ ${rendered}` : "");
72556
73292
 
72557
73293
  ${ending.report}`).catch(
72558
73294
  (err2) => (deps.log ?? console.warn)(
72559
- `[coordinator] ${instance.id} ${row2.unit}: the human-gated report could not be posted on the pull request: ${describe11(err2)}`
73295
+ `[coordinator] ${instance.id} ${row2.unit}: the human-gated report could not be posted on the pull request: ${describe12(err2)}`
72560
73296
  )
72561
73297
  );
72562
73298
  }
@@ -72618,7 +73354,7 @@ async function rebaseStep(body, deps) {
72618
73354
  at
72619
73355
  });
72620
73356
  } catch (err2) {
72621
- return json3(200, { ok: true, outcome: "refused", reason: describe11(err2), at });
73357
+ return json3(200, { ok: true, outcome: "refused", reason: describe12(err2), at });
72622
73358
  }
72623
73359
  }
72624
73360
  async function merge(body, deps, subject2) {
@@ -72656,7 +73392,7 @@ async function merge(body, deps, subject2) {
72656
73392
  try {
72657
73393
  facts2 = await deps.fetchPrFacts(pr);
72658
73394
  } catch (err2) {
72659
- return json3(502, { ok: false, error: "github_unavailable", message: describe11(err2), at });
73395
+ return json3(502, { ok: false, error: "github_unavailable", message: describe12(err2), at });
72660
73396
  }
72661
73397
  if (facts2 === void 0)
72662
73398
  return json3(502, { ok: false, error: "github_unavailable", message: `${where} could not be read`, at });
@@ -72782,7 +73518,7 @@ async function merge(body, deps, subject2) {
72782
73518
  try {
72783
73519
  queued = await deps.enqueuePullRequest(pr, { sha: headSha });
72784
73520
  } catch (err2) {
72785
- return json3(502, { ok: false, error: "github_unavailable", message: describe11(err2), at });
73521
+ return json3(502, { ok: false, error: "github_unavailable", message: describe12(err2), at });
72786
73522
  }
72787
73523
  if (!queued.ok) return refused7(`GitHub refused to enqueue ${where}: ${queued.reason}`);
72788
73524
  log(
@@ -72799,7 +73535,7 @@ async function merge(body, deps, subject2) {
72799
73535
  title: facts2.title ?? `Merge pull request #${pr.number}`
72800
73536
  });
72801
73537
  } catch (err2) {
72802
- return json3(502, { ok: false, error: "github_unavailable", message: describe11(err2), at });
73538
+ return json3(502, { ok: false, error: "github_unavailable", message: describe12(err2), at });
72803
73539
  }
72804
73540
  if (!merged.ok) {
72805
73541
  if (merged.status === 405 && MERGE_QUEUE_405.test(merged.reason)) return enqueue();
@@ -72910,13 +73646,54 @@ async function finish(body, deps) {
72910
73646
  if (host.kind === "not_host") return json3(409, { ok: false, error: "not_host", at });
72911
73647
  const units = await deps.instances.listUnits(instance.id);
72912
73648
  if (host.kind === "host") {
72913
- hostPublish(
72914
- deps,
72915
- instance,
72916
- host.runId,
72917
- [{ type: "answer", text: planSummary(units, isGenerated2(instance)), at }],
72918
- at
72919
- );
73649
+ const ledgerRun = deps.ledgerRuns().find((run2) => run2.runId === host.runId);
73650
+ let summary = deps.registry.getById(host.runId);
73651
+ if (ledgerRun && summary) {
73652
+ if (summary.liveState === void 0) {
73653
+ await hostPublish(deps, instance, host.runId, [], at);
73654
+ summary = deps.registry.getById(host.runId);
73655
+ if (!summary) throw new Error("hosted run disappeared during finish backfill");
73656
+ }
73657
+ const bound = summary.liveState?.bound ?? at + minutesToMs(HOSTED_DEADLINE_MARGIN_MINUTES);
73658
+ const wrapping = await ledgerRun.assignLiveState({
73659
+ expectedSeq: summary.liveStateSeq ?? 0,
73660
+ eventSeq: summary.eventCount + 1,
73661
+ at,
73662
+ state: "wrapping_up",
73663
+ bound,
73664
+ detail: "writing the pipeline summary"
73665
+ });
73666
+ if (!wrapping.ok || !deps.registry.commitLiveState(host.runId, wrapping))
73667
+ throw new Error(`hosted wrap-up was not committed (${wrapping.ok ? "registry sequence" : wrapping.reason})`);
73668
+ summary = deps.registry.getById(host.runId);
73669
+ if (!summary) throw new Error("hosted run disappeared during wrap-up");
73670
+ const answer = { type: "answer", text: planSummary(units, isGenerated2(instance)), at };
73671
+ const answerSeq = summary.eventCount + 1;
73672
+ const refreshed = await ledgerRun.assignLiveState({
73673
+ expectedSeq: summary.liveStateSeq ?? 0,
73674
+ at,
73675
+ state: "wrapping_up",
73676
+ bound,
73677
+ detail: "writing the pipeline summary",
73678
+ sourceEvents: [{ ...answer, seq: answerSeq }]
73679
+ });
73680
+ if (!refreshed.ok || !deps.registry.commitLiveState(host.runId, refreshed))
73681
+ throw new Error(`hosted summary was not committed (${refreshed.ok ? "registry sequence" : refreshed.reason})`);
73682
+ deps.registry.publish(host.runId, answer);
73683
+ summary = deps.registry.getById(host.runId);
73684
+ if (!summary) throw new Error("hosted run disappeared before ending");
73685
+ const ended = await ledgerRun.assignLiveState({
73686
+ expectedSeq: summary.liveStateSeq ?? 0,
73687
+ eventSeq: summary.eventCount + 1,
73688
+ at,
73689
+ state: "ended",
73690
+ cause: body.outcome === "completed" ? "completed" : "failed"
73691
+ });
73692
+ if (!ended.ok || !deps.registry.commitLiveState(host.runId, ended))
73693
+ throw new Error(`hosted ending was not committed (${ended.ok ? "registry sequence" : ended.reason})`);
73694
+ } else {
73695
+ deps.registry.publish(host.runId, { type: "answer", text: planSummary(units, isGenerated2(instance)), at });
73696
+ }
72920
73697
  deps.registry.finish(host.runId, body.outcome);
72921
73698
  }
72922
73699
  await drawCard(deps, instance, units, { icon: body.outcome === "completed" ? "\u2705" : "\u26A0\uFE0F" }).catch(() => {
@@ -73078,13 +73855,13 @@ function createAdminCoordinatorHandler(deps) {
73078
73855
  }
73079
73856
  write(res, await answerCoordinatorStep(door, read.body, deps));
73080
73857
  } catch (err2) {
73081
- (deps.log ?? console.error)(`[coordinator] ${describe11(err2)}`);
73858
+ (deps.log ?? console.error)(`[coordinator] ${describe12(err2)}`);
73082
73859
  write(res, json3(500, { ok: false, error: "internal error" }));
73083
73860
  }
73084
73861
  })();
73085
73862
  };
73086
73863
  }
73087
- var COORDINATOR_ADMIN_PREFIX, MAX_SPAWN_PROMPT_CHARS, FINISHED_LOOKBACK_PAGES, MAX_ADMIN_BODY_BYTES, UNIT_ID, PRESETS_OF_KIND, invalid, json3, describe11, isGenerated2, EVERY_RUN, REVIEW_POSTED_CHECKS, REVIEW_POSTED_RECHECK_MS, githubSecondStart, CHILD_SUPERSESSION_REASONS, ROUND_OUTCOMES, ENDING_ICON, STEPS;
73864
+ var COORDINATOR_ADMIN_PREFIX, MAX_SPAWN_PROMPT_CHARS, FINISHED_LOOKBACK_PAGES, MAX_ADMIN_BODY_BYTES, UNIT_ID, PRESETS_OF_KIND, invalid, json3, describe12, isGenerated2, EVERY_RUN, REVIEW_POSTED_CHECKS, REVIEW_POSTED_RECHECK_MS, githubSecondStart, CHILD_SUPERSESSION_REASONS, ROUND_OUTCOMES, ENDING_ICON, STEPS;
73088
73865
  var init_adminCoordinator = __esm({
73089
73866
  "../../src/channels/adminCoordinator.ts"() {
73090
73867
  "use strict";
@@ -73131,7 +73908,7 @@ var init_adminCoordinator = __esm({
73131
73908
  };
73132
73909
  invalid = (error) => ({ ok: false, error });
73133
73910
  json3 = (status3, body) => ({ status: status3, body });
73134
- describe11 = (err2) => err2 instanceof Error ? err2.message : String(err2);
73911
+ describe12 = (err2) => err2 instanceof Error ? err2.message : String(err2);
73135
73912
  isGenerated2 = (instance) => instance.plan?.path === void 0;
73136
73913
  EVERY_RUN = { kind: "all" };
73137
73914
  REVIEW_POSTED_CHECKS = 3;
@@ -74366,6 +75143,13 @@ async function runBot() {
74366
75143
  if (process.env.PORT) {
74367
75144
  const ingress = createIngressHandler(deps, { auth, publicBaseUrl: process.env.PUBLIC_BASE_URL, personByEmail });
74368
75145
  const mcp2 = createMcpHandler(deps, { auth, commands, grantsFor: (id) => config.grantsFor(id), personByEmail });
75146
+ const providerLiveState = createProviderLiveStateCoordinator({
75147
+ runLedger,
75148
+ ledger: ledgerClient,
75149
+ registry: defaultRunRegistry,
75150
+ clock: systemClock,
75151
+ warn: (message4) => console.warn(`[provider-state] ${message4}`)
75152
+ });
74369
75153
  const modelProxy = createModelProxyHandler({
74370
75154
  bearers: runBearers,
74371
75155
  providers: () => config.config.providers,
@@ -74374,17 +75158,11 @@ async function runBot() {
74374
75158
  ...costsCfg?.prices ? { prices: () => costsCfg.prices } : {},
74375
75159
  secrets: processSecrets,
74376
75160
  clock: systemClock,
74377
- // The plane's provider seam (model-proxy item 12a; record 0064): a level
74378
- // and a park land on the write-through's plane routes, fire and forget —
74379
- // the null write-through swallows both where no ledger is configured.
75161
+ // The plane's provider seam (model-proxy item 12a; record 0064): one
75162
+ // coordinator sequences level and park writes; the proxy never waits.
74380
75163
  plane: {
74381
- level: (provider, side, cause) => void runLedger.planeLevel({
74382
- provider,
74383
- name: "provider",
74384
- side,
74385
- ...side === "down" && cause !== void 0 ? { cause } : {}
74386
- }),
74387
- park: (runId3, provider) => void runLedger.planePark(runId3, provider)
75164
+ level: (provider, side, cause) => void providerLiveState.level(provider, side, cause),
75165
+ park: (runId3, provider) => void providerLiveState.park(runId3, provider)
74388
75166
  }
74389
75167
  });
74390
75168
  const harnessRoutes = createHarnessRoutesHandler({ bearers: runBearers, harnesses, takeover });
@@ -75128,6 +75906,7 @@ var init_index = __esm({
75128
75906
  init_adminModelProxy();
75129
75907
  init_modelProxy();
75130
75908
  init_runBearers();
75909
+ init_providerLiveStateCoordinator();
75131
75910
  init_piHarness();
75132
75911
  init_harness2();
75133
75912
  init_relay();