@coreplane/switchboard 1.256.0 → 1.258.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.
Files changed (63) hide show
  1. package/dist/assets/config/config.example.yaml +14 -0
  2. package/dist/assets/deploy/cloudflare-memory/worker.ts +340 -7
  3. package/dist/assets/deploy/cloudflare-resident/drain.ts +49 -4
  4. package/dist/assets/deploy/cloudflare-resident/worker.ts +52 -4
  5. package/dist/assets/package-lock.json +3 -3
  6. package/dist/assets/package.json +5 -3
  7. package/dist/assets/project.json +17 -9
  8. package/dist/assets/source.json +3 -3
  9. package/dist/assets/src/agents/registry.ts +65 -2
  10. package/dist/assets/src/core/authz/grants.ts +12 -0
  11. package/dist/assets/src/core/authz/policy.ts +15 -0
  12. package/dist/assets/src/core/budgets.ts +66 -18
  13. package/dist/assets/src/core/coordinator/contract.ts +45 -5
  14. package/dist/assets/src/core/coordinator/driver.ts +6 -3
  15. package/dist/assets/src/core/delivery.ts +8 -5
  16. package/dist/assets/src/core/pipelineStanding.ts +2 -0
  17. package/dist/assets/src/core/plane/decide.ts +477 -12
  18. package/dist/assets/src/core/plane/findings.ts +120 -0
  19. package/dist/assets/src/core/runEvents.ts +54 -14
  20. package/dist/assets/src/core/runFriction.ts +16 -0
  21. package/dist/assets/src/core/runLedger/types.ts +16 -3
  22. package/dist/assets/src/core/runRecord.ts +12 -0
  23. package/dist/assets/src/core/ship/contract.ts +14 -2
  24. package/dist/assets/src/core/ship/coordinator.ts +179 -51
  25. package/dist/assets/src/core/ship/renewal.ts +23 -20
  26. package/dist/assets/src/core/trace/attrs.ts +1 -1
  27. package/dist/assets/src/core/untrusted.ts +35 -0
  28. package/dist/assets/src/execution/residentCredentials.ts +7 -4
  29. package/dist/assets/web/dist/.vite/manifest.json +97 -72
  30. package/dist/assets/web/dist/assets/{DeliveryPage-BBAyLwPq.js → DeliveryPage-DadntjSp.js} +1 -1
  31. package/dist/assets/web/dist/assets/HomePage-BEEpTnVT.js +1 -0
  32. package/dist/assets/web/dist/assets/{PendingTurnRow-DGINv9XT.js → PendingTurnRow-DBPMLVsm.js} +1 -1
  33. package/dist/assets/web/dist/assets/PlanePage-DLusMGQ0.js +1 -0
  34. package/dist/assets/web/dist/assets/{ResidentDetailPage-jYhEeeyu.js → ResidentDetailPage-CPnHnrxy.js} +1 -1
  35. package/dist/assets/web/dist/assets/{ResidentsIndexPage-DvFmlV4U.js → ResidentsIndexPage-C9hASwHL.js} +1 -1
  36. package/dist/assets/web/dist/assets/RunFoldRow-OPe7Z0Cz.js +1 -0
  37. package/dist/assets/web/dist/assets/{RunRoutePage-CvZ-TOT3.js → RunRoutePage-o1xzkTGZ.js} +4 -4
  38. package/dist/assets/web/dist/assets/RunsIndexPage-0YAClYQh.js +1 -0
  39. package/dist/assets/web/dist/assets/{ScheduledPage-Viim-bus.js → ScheduledPage-BIdfC0V3.js} +1 -1
  40. package/dist/assets/web/dist/assets/{SettingsPage-CYUy8McC.js → SettingsPage-CnqWAjl3.js} +1 -1
  41. package/dist/assets/web/dist/assets/SilentTurn-DGNg0sIZ.js +2 -0
  42. package/dist/assets/web/dist/assets/SlackMark-CtiHrNjr.js +1 -0
  43. package/dist/assets/web/dist/assets/{StatusDot-Dv6UMaPy.js → StatusDot-D_D_iJS8.js} +1 -1
  44. package/dist/assets/web/dist/assets/{Tooltip-Bd-5Rypv.js → Tooltip-DVFmM7on.js} +1 -1
  45. package/dist/assets/web/dist/assets/UnitRoutePage-7fAXFoB_.js +1 -0
  46. package/dist/assets/web/dist/assets/budgets-BRLm6oID.js +1 -0
  47. package/dist/assets/web/dist/assets/{dist-Nl3uaxrP.js → dist-C1VX-_mm.js} +1 -1
  48. package/dist/assets/web/dist/assets/durationTone-CVpX_yIk.js +1 -0
  49. package/dist/assets/web/dist/assets/{indexRow-DborJPFp.js → indexRow-BO_GIdF6.js} +1 -1
  50. package/dist/assets/web/dist/assets/main-Cl7xHG34.js +28 -0
  51. package/dist/assets/web/dist/assets/main-DGC6WFqS.css +1 -0
  52. package/dist/assets/web/dist/assets/{sseReplay-DE6wv1Ua.js → sseReplay-BjlKmQsY.js} +1 -1
  53. package/dist/cli.js +3096 -1136
  54. package/package.json +1 -1
  55. package/dist/assets/web/dist/assets/HomePage-BEiStFwW.js +0 -3
  56. package/dist/assets/web/dist/assets/PlanePage-JEj-lqgz.js +0 -1
  57. package/dist/assets/web/dist/assets/RunFoldRow-DvWzR1JQ.js +0 -1
  58. package/dist/assets/web/dist/assets/RunsIndexPage-JqVSDOok.js +0 -1
  59. package/dist/assets/web/dist/assets/UnitRoutePage-B81wEnKN.js +0 -1
  60. package/dist/assets/web/dist/assets/budgets-c1eumrqD.js +0 -1
  61. package/dist/assets/web/dist/assets/durationTone-U_rOqo6r.js +0 -1
  62. package/dist/assets/web/dist/assets/main-C4QfwybO.css +0 -1
  63. package/dist/assets/web/dist/assets/main-DRxWlffc.js +0 -28
@@ -233,6 +233,26 @@ export interface ChecksSettledPayload {
233
233
  settledAt: number;
234
234
  }
235
235
 
236
+ /** The event the merge watch sends a waiting unit when its pull request
237
+ * merged, whoever merged (record 0071, mechanism three): the unit ends
238
+ * `merged` by other. The type names the unit within the instance, the
239
+ * nudge's alphabet and clip rule. */
240
+ export const PULL_MERGED_EVENT_PREFIX = "pr-merged-";
241
+ export function pullMergedEventType(key: { instanceId: string; unit: string }): string {
242
+ const suffix = `-${key.unit}`;
243
+ const room = 100 - PULL_MERGED_EVENT_PREFIX.length - suffix.length;
244
+ return `${PULL_MERGED_EVENT_PREFIX}${key.instanceId.slice(0, room)}${suffix}`;
245
+ }
246
+
247
+ /** What the merged event carries — the pull request and the merge's facts;
248
+ * the waiting unit confirms through its own pr-check before it acts. */
249
+ export interface PullMergedPayload {
250
+ repo: string;
251
+ number: number;
252
+ sha: string;
253
+ mergedAt: string;
254
+ }
255
+
236
256
  /** What the event carries — ids, a status and a clock; the parent confirms
237
257
  * through `read-record` before it acts, so nothing more rides here. */
238
258
  export interface RunFinishedPayload {
@@ -379,17 +399,17 @@ export interface UnitIdle {
379
399
  wakes: number;
380
400
  }
381
401
 
382
- /** One unit of the plan an instance runs (a task string is a generated plan of
383
- * one unit, `U1`): its branch, the units it waits on, and — as the runner
384
- * reaches it — its thread, its pull request, the round boundaries the card
385
- * drew and how it ended. One row a person can read for "what happened to this
386
- * unit". */
387
402
  /** What the severity gate caught on a round: the level in force and the gated findings as `id (severity)`. */
388
403
  export interface RoundGate {
389
404
  level: AddressSeverity;
390
405
  findings: string[];
391
406
  }
392
407
 
408
+ /** One unit of the plan an instance runs (a task string is a generated plan of
409
+ * one unit, `U1`): its branch, the units it waits on, and — as the runner
410
+ * reaches it — its thread, its pull request, the round boundaries the card
411
+ * drew and how it ended. One row a person can read for "what happened to this
412
+ * unit". */
393
413
  export interface CoordinatorUnit {
394
414
  instanceId: string;
395
415
  /** `U<n>` as the plan spells it. */
@@ -606,6 +626,26 @@ export async function sendChecksSettled(
606
626
  }
607
627
  }
608
628
 
629
+ /** The one send per merged fact the watch observed (record 0071): best effort
630
+ * like `sendRunFinished` — a refusal is answered, never thrown; the waiting
631
+ * unit's bounded wait re-asks its own pr-check on its next chunk. */
632
+ export async function sendPullMerged(
633
+ workflow: WorkflowSender | undefined,
634
+ key: { instanceId: string; unit: string },
635
+ payload: PullMergedPayload,
636
+ ): Promise<RunFinishedSend> {
637
+ const instance = key.instanceId;
638
+ if (!workflow) return { kind: "no-binding", instance };
639
+ const type = pullMergedEventType(key);
640
+ try {
641
+ const handle = await workflow.get(instance);
642
+ await handle.sendEvent({ type, payload });
643
+ return { kind: "sent", instance, type };
644
+ } catch (err) {
645
+ return { kind: "failed", instance, type, reason: err instanceof Error ? err.message : String(err) };
646
+ }
647
+ }
648
+
609
649
  /** One deploy-roll signal to the child's parent (run-history item 47a): best
610
650
  * effort like `sendRunFinished` — a refusal is answered, never thrown; a lost
611
651
  * send costs the wait a chunk, never the round. */
@@ -61,7 +61,7 @@ import {
61
61
  type UnitEnding,
62
62
  type UnitPipelineState,
63
63
  stepPrefixOf,
64
- type UnitSession,
64
+ type LeaseSegmentProgress,
65
65
  } from "../ship/coordinator.js";
66
66
  import {
67
67
  checksSettledEventType,
@@ -451,12 +451,15 @@ function prCheckReturn(step: string, a: BotAnswer): StepReturn {
451
451
  * ask's answer carries `retried` instead: whether the re-run was dispatched,
452
452
  * so the machine never waits on a head an undispatched re-run left unchanged. */
453
453
  function checksReturn(step: string, a: BotAnswer): StepReturn {
454
- const { ok, checks, retried, at } = a.body;
454
+ const { ok, checks, draft, retried, at } = a.body;
455
455
  if (ok !== true) throw new UnreadableAnswer("checks", a, "ok");
456
456
  return {
457
457
  type: "checks",
458
458
  step,
459
459
  ...(isRoundChecks(checks) ? { checks } : {}),
460
+ // The pull request is a draft (issue 2063): the machine's table holds the
461
+ // unit for the ready event instead of merging or ending without a cause.
462
+ ...(draft === true ? { draft: true } : {}),
460
463
  ...(typeof retried === "boolean" ? { retried } : {}),
461
464
  at,
462
465
  };
@@ -691,7 +694,7 @@ async function runUnit(
691
694
  instanceId: string,
692
695
  node: PlanUnitNode,
693
696
  plan: PlanFacts,
694
- session?: UnitSession,
697
+ session?: LeaseSegmentProgress,
695
698
  ): Promise<UnitEnding> {
696
699
  const unit = node.id;
697
700
  // A renewal's segment names its steps under the segment (`U10/s2/…`), so
@@ -186,7 +186,10 @@ export interface WeekRow extends DeliveryIndicators {
186
186
  prs: number[];
187
187
  }
188
188
 
189
- export interface UnitRow extends DeliveryIndicators {
189
+ /** One row per board issue the pull requests link — the report's "Issues:"
190
+ * block and the Delivery page's table. The JSON field stays `units` (a served
191
+ * shape older readers hold); only the words are the issue's. */
192
+ export interface IssueRow extends DeliveryIndicators {
190
193
  /** The board issue, or null for the pull requests no issue claims. */
191
194
  issue: number | null;
192
195
  title: string;
@@ -198,7 +201,7 @@ export interface DeliveryReport {
198
201
  repo: string;
199
202
  range: DeliveryRange;
200
203
  weeks: WeekRow[];
201
- units: UnitRow[];
204
+ units: IssueRow[];
202
205
  prs: PullRequestRow[];
203
206
  totals: DeliveryIndicators;
204
207
  identities: DeliveryIdentities;
@@ -448,7 +451,7 @@ export function buildDeliveryReport(input: DeliveryInput): DeliveryReport {
448
451
  const key = p.issue?.number ?? null;
449
452
  byIssue.set(key, [...(byIssue.get(key) ?? []), p]);
450
453
  }
451
- const units: UnitRow[] = [...byIssue.entries()]
454
+ const units: IssueRow[] = [...byIssue.entries()]
452
455
  .sort(([a], [b]) => (a === null ? 1 : b === null ? -1 : a - b))
453
456
  .map(([issue, rows]) => {
454
457
  const first = rows.find((r) => r.issue !== undefined)?.issue;
@@ -572,7 +575,7 @@ function coverage(report: DeliveryReport): string {
572
575
  return `the newest ${report.totals.prsMerged} pull requests only${from}`;
573
576
  }
574
577
 
575
- /** One block per week, then the units — single-spaced lines, so chat carries them as they are. */
578
+ /** One block per week, then the issues — single-spaced lines, so chat carries them as they are. */
576
579
  export function renderDeliveryReport(report: DeliveryReport, nowMs: number = systemClock()): string {
577
580
  const lines: string[] = [
578
581
  [
@@ -597,7 +600,7 @@ export function renderDeliveryReport(report: DeliveryReport, nowMs: number = sys
597
600
  );
598
601
  }
599
602
  if (report.units.length > 0) {
600
- lines.push("", "Units:");
603
+ lines.push("", "Issues:");
601
604
  for (const u of report.units) {
602
605
  const prs = `${u.prs.length === 1 ? "PR" : "PRs"} ${u.prs.join(", ")}`;
603
606
  const who = u.issue === null ? "(no issue)" : `${u.issue} ${u.title}`;
@@ -99,6 +99,7 @@ export const ROUND_STAGE = {
99
99
  dequeued: "fix",
100
100
  aborted: "hold",
101
101
  stopped: "hold",
102
+ held: "hold",
102
103
  continued: "continue",
103
104
  idle: "idle",
104
105
  } as const satisfies Record<ShipRoundOutcome, Stage | "start" | "continue" | "hold">;
@@ -171,6 +172,7 @@ export const ROUND_OUTCOME_WORDS = {
171
172
  dequeued: "removed from the merge queue",
172
173
  aborted: "aborted",
173
174
  stopped: "stopped",
175
+ held: "held",
174
176
  continued: "continuing",
175
177
  idle: "idle",
176
178
  } as const satisfies Record<ShipRoundOutcome, string>;