halfcycle 0.4.13 → 0.4.14

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 (52) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/bin/bin.bundle.mjs +4105 -369
  3. package/bin/pre-tool-use-filter.sh +93 -1
  4. package/dist/bin.d.ts +1 -0
  5. package/dist/bin.d.ts.map +1 -1
  6. package/dist/bin.js +0 -0
  7. package/dist/build-record/pair-io.d.ts +49 -0
  8. package/dist/build-record/pair-io.d.ts.map +1 -0
  9. package/dist/build-record/render-change.d.ts +25 -0
  10. package/dist/build-record/render-change.d.ts.map +1 -0
  11. package/dist/build-record/render-v2.d.ts +10 -5
  12. package/dist/build-record/render-v2.d.ts.map +1 -1
  13. package/dist/build-record/write-change.d.ts +63 -0
  14. package/dist/build-record/write-change.d.ts.map +1 -0
  15. package/dist/build-record/write.d.ts +5 -15
  16. package/dist/build-record/write.d.ts.map +1 -1
  17. package/dist/change.d.ts +136 -0
  18. package/dist/change.d.ts.map +1 -0
  19. package/dist/check-tasks.d.ts +71 -0
  20. package/dist/check-tasks.d.ts.map +1 -0
  21. package/dist/claude-plan.d.ts +114 -0
  22. package/dist/claude-plan.d.ts.map +1 -0
  23. package/dist/cli-contract.d.ts +12 -1
  24. package/dist/cli-contract.d.ts.map +1 -1
  25. package/dist/cli.js +5192 -2132
  26. package/dist/cli.js.map +3 -3
  27. package/dist/close-phase.d.ts +53 -1
  28. package/dist/close-phase.d.ts.map +1 -1
  29. package/dist/index.js +1529 -911
  30. package/dist/index.js.map +3 -3
  31. package/dist/install-manifest.d.ts +11 -1
  32. package/dist/install-manifest.d.ts.map +1 -1
  33. package/dist/install.d.ts +58 -1
  34. package/dist/install.d.ts.map +1 -1
  35. package/dist/merge-settings.d.ts +21 -2
  36. package/dist/merge-settings.d.ts.map +1 -1
  37. package/dist/open-phase.d.ts +1 -1
  38. package/dist/open-phase.d.ts.map +1 -1
  39. package/dist/pace.d.ts +138 -0
  40. package/dist/pace.d.ts.map +1 -0
  41. package/dist/phase-work.d.ts +37 -0
  42. package/dist/phase-work.d.ts.map +1 -0
  43. package/dist/plan.d.ts +5 -2
  44. package/dist/plan.d.ts.map +1 -1
  45. package/dist/prove.d.ts +77 -0
  46. package/dist/prove.d.ts.map +1 -0
  47. package/dist/review.d.ts +19 -1
  48. package/dist/review.d.ts.map +1 -1
  49. package/dist/system-report.d.ts +1 -1
  50. package/dist/system-report.d.ts.map +1 -1
  51. package/dist/uninstall.d.ts.map +1 -1
  52. package/package.json +11 -11
package/dist/index.js CHANGED
@@ -2,7 +2,8 @@
2
2
  import { execFileSync as execFileSync2 } from "node:child_process";
3
3
  import { createHash as createHash2 } from "node:crypto";
4
4
  import { existsSync as existsSync3, lstatSync, mkdirSync as mkdirSync4, readFileSync as readFileSync4, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "node:fs";
5
- import { dirname as dirname3, join as join5, posix, relative } from "node:path";
5
+ import { homedir as homedir2 } from "node:os";
6
+ import { dirname as dirname3, isAbsolute as isAbsolute2, join as join5, posix, relative, resolve } from "node:path";
6
7
  import { fileURLToPath } from "node:url";
7
8
 
8
9
  // ../core/dist/guard-record.js
@@ -267,13 +268,69 @@ var REMOTE_FORMS = [
267
268
  var SIGN_IN_COMMAND = '"npx halfcycle"';
268
269
  var HOOK_REMEDY = `Run ${SIGN_IN_COMMAND} in the project folder to sign in.`;
269
270
 
270
- // ../events/dist/result.js
271
+ // ../core/dist/task-plan.js
271
272
  import { z as z2 } from "zod";
272
- var firedGuardSchema = z2.object({
273
- guardId: z2.string(),
274
- patternRef: z2.string(),
273
+ var TASK_PLAN_TASKS_MAX = 500;
274
+ var TASK_PLAN_ID_MAX = 64;
275
+ var TASK_PLAN_KINDS = ["build", "review", "spec", "walk", "check"];
276
+ var CONTROL_CHARACTER = /[\u0000-\u001f\u007f-\u009f]/;
277
+ var planText = z2.string().refine((text) => !CONTROL_CHARACTER.test(text), { message: "holds a control character" });
278
+ var taskIdSchema = z2.string().min(1).max(TASK_PLAN_ID_MAX).refine((text) => !CONTROL_CHARACTER.test(text), { message: "holds a control character" });
279
+ var taskPlanTaskSchema = z2.object({
280
+ id: taskIdSchema,
281
+ kind: z2.enum(TASK_PLAN_KINDS),
282
+ dependsOn: z2.array(taskIdSchema).max(TASK_PLAN_TASKS_MAX),
283
+ reviews: taskIdSchema.optional(),
284
+ heldBy: z2.literal("person").optional(),
285
+ touches: z2.object({
286
+ files: z2.array(planText).optional(),
287
+ interfaces: z2.array(planText).optional()
288
+ }).strict().optional(),
289
+ wholeProject: z2.literal(true).optional(),
290
+ ships: z2.enum(["deploy", "release"]).optional()
291
+ }).strict().superRefine((task, ctx) => {
292
+ if (task.reviews !== void 0 && task.kind !== "review") {
293
+ ctx.addIssue({
294
+ code: "custom",
295
+ path: ["reviews"],
296
+ message: "only a review task names the task it reviews"
297
+ });
298
+ }
299
+ if (task.wholeProject !== void 0 && task.kind !== "check") {
300
+ ctx.addIssue({
301
+ code: "custom",
302
+ path: ["wholeProject"],
303
+ message: "only a check task is a whole-project check"
304
+ });
305
+ }
306
+ if ((task.kind === "review" || task.kind === "check" || task.kind === "walk") && ((task.touches?.files?.length ?? 0) > 0 || (task.touches?.interfaces?.length ?? 0) > 0)) {
307
+ ctx.addIssue({
308
+ code: "custom",
309
+ path: ["touches"],
310
+ message: "a review, check or walk task touches nothing"
311
+ });
312
+ }
313
+ });
314
+ var taskPlanSchema = z2.object({
315
+ phase: z2.string().min(1).refine((text) => !CONTROL_CHARACTER.test(text), { message: "holds a control character" }),
316
+ tasks: z2.array(taskPlanTaskSchema).max(TASK_PLAN_TASKS_MAX)
317
+ }).strict();
318
+ var taskListRowSchema = z2.object({
319
+ id: planText,
320
+ dependsOn: z2.array(planText)
321
+ }).loose();
322
+ var taskListFileSchema = z2.union([
323
+ z2.object({ phase: planText, tasks: z2.array(taskListRowSchema) }).loose(),
324
+ z2.array(z2.unknown())
325
+ ]);
326
+
327
+ // ../events/dist/result.js
328
+ import { z as z3 } from "zod";
329
+ var firedGuardSchema = z3.object({
330
+ guardId: z3.string(),
331
+ patternRef: z3.string(),
275
332
  severity: severitySchema,
276
- explanation: z2.string(),
333
+ explanation: z3.string(),
277
334
  /**
278
335
  * The repo-relative path of the file this firing was decided on. The matcher
279
336
  * has the file live at the moment it decides to fire; this is the field that
@@ -297,62 +354,62 @@ var firedGuardSchema = z2.object({
297
354
  * safe-parse it and decide what to do with a refusal, rather than assume the
298
355
  * two shapes agree.
299
356
  */
300
- path: z2.string().optional()
357
+ path: z3.string().optional()
301
358
  }).strict();
302
- var notRunCheckSchema = z2.object({
359
+ var notRunCheckSchema = z3.object({
303
360
  /** Which check did not run, by the same reference a fired check carries. */
304
- patternRef: z2.string(),
361
+ patternRef: z3.string(),
305
362
  /**
306
363
  * Why it could not run, in plain words — what this client did not send, or
307
364
  * that the check's kind is not implemented yet. Never the check's own rule.
308
365
  */
309
- reason: z2.string()
366
+ reason: z3.string()
310
367
  }).strict();
311
- var resultEnvelopeSchema = z2.object({
312
- guardsFired: z2.array(firedGuardSchema),
368
+ var resultEnvelopeSchema = z3.object({
369
+ guardsFired: z3.array(firedGuardSchema),
313
370
  severity: severitySchema.nullable(),
314
- blocking: z2.boolean(),
315
- explanation: z2.string(),
371
+ blocking: z3.boolean(),
372
+ explanation: z3.string(),
316
373
  /**
317
374
  * The checks that could not run on this edit, each named with the reason.
318
375
  * Absent when every check ran — so an evaluation where nothing was skipped
319
376
  * looks exactly as it always has, and an absent list is never an empty one.
320
377
  */
321
- notRun: z2.array(notRunCheckSchema).optional()
378
+ notRun: z3.array(notRunCheckSchema).optional()
322
379
  }).strict();
323
- var wireErrorSchema = z2.object({
324
- statusCode: z2.number(),
325
- error: z2.string(),
326
- message: z2.string()
380
+ var wireErrorSchema = z3.object({
381
+ statusCode: z3.number(),
382
+ error: z3.string(),
383
+ message: z3.string()
327
384
  }).strict();
328
385
 
329
386
  // ../events/dist/build-record.js
330
- import { z as z5 } from "zod";
387
+ import { z as z6 } from "zod";
331
388
 
332
389
  // ../events/dist/state.js
333
- import { z as z4 } from "zod";
390
+ import { z as z5 } from "zod";
334
391
 
335
392
  // ../events/dist/human-agent.js
336
- import { z as z3 } from "zod";
393
+ import { z as z4 } from "zod";
337
394
  var HUMAN_AGENT = "Human";
338
395
  var AGENT_NAME_MAX = 32;
339
- var agentNameSchema = z3.string().min(1).max(AGENT_NAME_MAX);
396
+ var agentNameSchema = z4.string().min(1).max(AGENT_NAME_MAX);
340
397
 
341
398
  // ../events/dist/state.js
342
- var utcIso8601 = z4.string().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/, "must be a UTC ISO-8601 timestamp ending in Z");
399
+ var utcIso8601 = z5.string().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/, "must be a UTC ISO-8601 timestamp ending in Z");
343
400
  var STATE_RECORD_FORMAT = "halfcycle-state-record/v1";
344
- var stepIdSchema = z4.string().regex(/^(l[0-5](-l[0-5])?|xl)\.[a-z0-9-]+$/);
345
- var methodVersionSchema = z4.string().regex(RELEASE_VERSION_PATTERN);
401
+ var stepIdSchema = z5.string().regex(/^(l[0-5](-l[0-5])?|xl)\.[a-z0-9-]+$/);
402
+ var methodVersionSchema = z5.string().regex(RELEASE_VERSION_PATTERN);
346
403
  var anchorPathRegex = /^(?!\/)(?!.*#)(?!method\/)(?!(.*\/)?docs\/method\/).+$/;
347
- var recordKindSchema = z4.enum(["artefact", "step-run", "gate", "intervention"]);
348
- var methodLayerSchema = z4.enum(["l0", "l1", "l2", "l3", "l3-l4", "l4", "l5", "xl"]);
404
+ var recordKindSchema = z5.enum(["artefact", "step-run", "gate", "intervention"]);
405
+ var methodLayerSchema = z5.enum(["l0", "l1", "l2", "l3", "l3-l4", "l4", "l5", "xl"]);
349
406
  var PHASE_SCOPED_LAYERS = ["l4", "l5"];
350
407
  function isPhaseScopedLayer(layer) {
351
408
  return PHASE_SCOPED_LAYERS.includes(layer);
352
409
  }
353
- var evidenceKindSchema = z4.enum(["anchor", "diff", "repro", "question-answer", "no-op"]);
354
- var declarableEvidenceKindSchema = z4.enum(["anchor", "diff", "repro", "question-answer"]);
355
- var dispositionSchema = z4.enum([
410
+ var evidenceKindSchema = z5.enum(["anchor", "diff", "repro", "question-answer", "no-op"]);
411
+ var declarableEvidenceKindSchema = z5.enum(["anchor", "diff", "repro", "question-answer"]);
412
+ var dispositionSchema = z5.enum([
356
413
  "prevented",
357
414
  "corrected-in-spec",
358
415
  "corrected-in-scope",
@@ -362,20 +419,20 @@ var dispositionSchema = z4.enum([
362
419
  "surfaced",
363
420
  "filed-forward"
364
421
  ]);
365
- var mechanismSchema = z4.enum(["guard", "verdict", "served-step", "method-step"]);
366
- var artefactStateSchema = z4.enum(["created", "updated"]);
422
+ var mechanismSchema = z5.enum(["guard", "verdict", "served-step", "method-step"]);
423
+ var artefactStateSchema = z5.enum(["created", "updated"]);
367
424
  var QUALIFIED_OUTCOMES = ["declined", "parked"];
368
- var qualifiedOutcomeSchema = z4.enum(QUALIFIED_OUTCOMES);
425
+ var qualifiedOutcomeSchema = z5.enum(QUALIFIED_OUTCOMES);
369
426
  function isQualifiedOutcome(outcome) {
370
427
  return QUALIFIED_OUTCOMES.includes(outcome);
371
428
  }
372
- var runOutcomeSchema = z4.enum([
429
+ var runOutcomeSchema = z5.enum([
373
430
  "completed",
374
431
  "attempted-failed",
375
432
  ...QUALIFIED_OUTCOMES
376
433
  ]);
377
- var gateKindSchema = z4.enum(["approval", "mechanical"]);
378
- var gateVerdictSchema = z4.enum(["pass", "fail", ...QUALIFIED_OUTCOMES]);
434
+ var gateKindSchema = z5.enum(["approval", "mechanical"]);
435
+ var gateVerdictSchema = z5.enum(["pass", "fail", ...QUALIFIED_OUTCOMES]);
379
436
  function outcomeReasonIssue(outcome, reason) {
380
437
  if (isQualifiedOutcome(outcome) && reason === void 0) {
381
438
  return { message: `outcomeReason is required when the outcome is '${outcome}'` };
@@ -387,47 +444,47 @@ function outcomeReasonIssue(outcome, reason) {
387
444
  }
388
445
  return null;
389
446
  }
390
- var anchorEvidenceSchema = z4.object({
391
- kind: z4.literal("anchor"),
392
- path: z4.string().regex(anchorPathRegex),
447
+ var anchorEvidenceSchema = z5.object({
448
+ kind: z5.literal("anchor"),
449
+ path: z5.string().regex(anchorPathRegex),
393
450
  // Optional 1-based line number within the file at `path`. Present when the
394
451
  // writer knows the exact line; omitted — never `0`, never `null` — when it
395
452
  // does not, because a line number is not always obtainable. Absence is a
396
453
  // valid, permanent state here, not a gap meant to be filled in later.
397
- line: z4.number().optional()
454
+ line: z5.number().optional()
398
455
  }).strict();
399
- var diffEvidenceSchema = z4.object({
400
- kind: z4.literal("diff"),
401
- ref: z4.string()
456
+ var diffEvidenceSchema = z5.object({
457
+ kind: z5.literal("diff"),
458
+ ref: z5.string()
402
459
  }).strict();
403
- var reproEvidenceSchema = z4.object({
404
- kind: z4.literal("repro"),
405
- steps: z4.string().max(2e3)
460
+ var reproEvidenceSchema = z5.object({
461
+ kind: z5.literal("repro"),
462
+ steps: z5.string().max(2e3)
406
463
  }).strict();
407
- var questionAnswerEvidenceSchema = z4.object({
408
- kind: z4.literal("question-answer"),
409
- question: z4.string().max(2e3),
410
- before: z4.string().max(2e3),
411
- after: z4.string().max(2e3)
464
+ var questionAnswerEvidenceSchema = z5.object({
465
+ kind: z5.literal("question-answer"),
466
+ question: z5.string().max(2e3),
467
+ before: z5.string().max(2e3),
468
+ after: z5.string().max(2e3)
412
469
  }).strict();
413
- var noOpEvidenceSchema = z4.object({
414
- kind: z4.literal("no-op"),
415
- inspected: z4.string().max(2e3),
416
- unchangedBecause: z4.string().max(2e3)
470
+ var noOpEvidenceSchema = z5.object({
471
+ kind: z5.literal("no-op"),
472
+ inspected: z5.string().max(2e3),
473
+ unchangedBecause: z5.string().max(2e3)
417
474
  }).strict();
418
- var evidenceSchema = z4.discriminatedUnion("kind", [
475
+ var evidenceSchema = z5.discriminatedUnion("kind", [
419
476
  anchorEvidenceSchema,
420
477
  diffEvidenceSchema,
421
478
  reproEvidenceSchema,
422
479
  questionAnswerEvidenceSchema,
423
480
  noOpEvidenceSchema
424
481
  ]);
425
- var stateRecordEnvelopeSchema = z4.object({
426
- format: z4.literal(STATE_RECORD_FORMAT),
482
+ var stateRecordEnvelopeSchema = z5.object({
483
+ format: z5.literal(STATE_RECORD_FORMAT),
427
484
  recordKind: recordKindSchema,
428
- recordId: z4.string().uuid(),
485
+ recordId: z5.string().uuid(),
429
486
  methodVersion: methodVersionSchema,
430
- engagementId: z4.string(),
487
+ engagementId: z5.string(),
431
488
  stepId: stepIdSchema,
432
489
  // Immutable: names when the thing happened, never when a later disposition
433
490
  // moved.
@@ -443,38 +500,38 @@ var stateRecordEnvelopeSchema = z4.object({
443
500
  // for the whole project rather than per phase. Absence is meaningful on its
444
501
  // own — it is never replaced with a placeholder value, and it is read as
445
502
  // "satisfies any phase", not as "unknown".
446
- phase: z4.string().optional()
503
+ phase: z5.string().optional()
447
504
  });
448
- var artefactRefSchema = z4.object({
449
- name: z4.string(),
450
- parent: z4.string()
505
+ var artefactRefSchema = z5.object({
506
+ name: z5.string(),
507
+ parent: z5.string()
451
508
  }).strict();
452
- var coverageSchema = z4.object({
453
- asked: z4.number().int().nonnegative(),
454
- answered: z4.number().int().nonnegative()
509
+ var coverageSchema = z5.object({
510
+ asked: z5.number().int().nonnegative(),
511
+ answered: z5.number().int().nonnegative()
455
512
  }).strict().superRefine((coverage, ctx) => {
456
513
  if (coverage.answered > coverage.asked) {
457
514
  ctx.addIssue({
458
- code: z4.ZodIssueCode.custom,
515
+ code: z5.ZodIssueCode.custom,
459
516
  path: ["answered"],
460
517
  message: "answered cannot be more than asked"
461
518
  });
462
519
  }
463
520
  });
464
- var projectTierSchema = z4.number().int().min(0).max(3);
521
+ var projectTierSchema = z5.number().int().min(0).max(3);
465
522
  var artefactRecordSchema = stateRecordEnvelopeSchema.extend({
466
- recordKind: z4.literal("artefact"),
523
+ recordKind: z5.literal("artefact"),
467
524
  artefactRef: artefactRefSchema,
468
525
  // Some layer wrote it, by construction — an empty array is not a legitimate
469
526
  // state, so the schema says so.
470
- writtenByLayers: z4.array(methodLayerSchema).min(1),
527
+ writtenByLayers: z5.array(methodLayerSchema).min(1),
471
528
  state: artefactStateSchema
472
529
  }).strict();
473
530
  var stepRunRecordSchema = stateRecordEnvelopeSchema.extend({
474
- recordKind: z4.literal("step-run"),
531
+ recordKind: z5.literal("step-run"),
475
532
  runOutcome: runOutcomeSchema,
476
- failureReason: z4.string().optional(),
477
- outcomeReason: z4.string().max(2e3).optional(),
533
+ failureReason: z5.string().optional(),
534
+ outcomeReason: z5.string().max(2e3).optional(),
478
535
  // Who did this step, as the session reported it. Absent when not reported.
479
536
  agent: agentNameSchema.optional(),
480
537
  // When the session began this step. Absent when not reported.
@@ -484,29 +541,29 @@ var stepRunRecordSchema = stateRecordEnvelopeSchema.extend({
484
541
  }).strict().superRefine((rec, ctx) => {
485
542
  if (rec.runOutcome === "attempted-failed" && rec.failureReason === void 0) {
486
543
  ctx.addIssue({
487
- code: z4.ZodIssueCode.custom,
544
+ code: z5.ZodIssueCode.custom,
488
545
  path: ["failureReason"],
489
546
  message: "failureReason is required when runOutcome is 'attempted-failed'"
490
547
  });
491
548
  }
492
549
  if (rec.runOutcome !== "attempted-failed" && rec.failureReason !== void 0) {
493
550
  ctx.addIssue({
494
- code: z4.ZodIssueCode.custom,
551
+ code: z5.ZodIssueCode.custom,
495
552
  path: ["failureReason"],
496
553
  message: "failureReason is only present when runOutcome is 'attempted-failed'"
497
554
  });
498
555
  }
499
556
  const issue = outcomeReasonIssue(rec.runOutcome, rec.outcomeReason);
500
557
  if (issue) {
501
- ctx.addIssue({ code: z4.ZodIssueCode.custom, path: ["outcomeReason"], ...issue });
558
+ ctx.addIssue({ code: z5.ZodIssueCode.custom, path: ["outcomeReason"], ...issue });
502
559
  }
503
560
  });
504
561
  var gateRecordSchema = stateRecordEnvelopeSchema.extend({
505
- recordKind: z4.literal("gate"),
562
+ recordKind: z5.literal("gate"),
506
563
  gateKind: gateKindSchema,
507
564
  verdict: gateVerdictSchema,
508
- actor: z4.string(),
509
- outcomeReason: z4.string().max(2e3).optional(),
565
+ actor: z5.string(),
566
+ outcomeReason: z5.string().max(2e3).optional(),
510
567
  coverage: coverageSchema.optional(),
511
568
  // Who did the step this checkpoint is on, as reported. Absent when not reported.
512
569
  agent: agentNameSchema.optional(),
@@ -516,21 +573,21 @@ var gateRecordSchema = stateRecordEnvelopeSchema.extend({
516
573
  }).strict().superRefine((rec, ctx) => {
517
574
  const issue = outcomeReasonIssue(rec.verdict, rec.outcomeReason);
518
575
  if (issue) {
519
- ctx.addIssue({ code: z4.ZodIssueCode.custom, path: ["outcomeReason"], ...issue });
576
+ ctx.addIssue({ code: z5.ZodIssueCode.custom, path: ["outcomeReason"], ...issue });
520
577
  }
521
578
  });
522
579
  var interventionRecordSchema = stateRecordEnvelopeSchema.extend({
523
- recordKind: z4.literal("intervention"),
580
+ recordKind: z5.literal("intervention"),
524
581
  layer: methodLayerSchema,
525
582
  mechanism: mechanismSchema,
526
583
  severity: severitySchema,
527
584
  disposition: dispositionSchema,
528
- summary: z4.string().max(2e3),
585
+ summary: z5.string().max(2e3),
529
586
  coverage: coverageSchema.optional(),
530
587
  // Who caught it, as the session reported. Absent when not reported.
531
588
  agent: agentNameSchema.optional()
532
589
  }).strict();
533
- var stateRecordSchema = z4.discriminatedUnion("recordKind", [
590
+ var stateRecordSchema = z5.discriminatedUnion("recordKind", [
534
591
  artefactRecordSchema,
535
592
  stepRunRecordSchema,
536
593
  gateRecordSchema,
@@ -539,9 +596,9 @@ var stateRecordSchema = z4.discriminatedUnion("recordKind", [
539
596
 
540
597
  // ../events/dist/control-characters.js
541
598
  var CONTROL_CHARACTER_CLASS = "\\p{Cc}";
542
- var CONTROL_CHARACTER = new RegExp(CONTROL_CHARACTER_CLASS, "u");
599
+ var CONTROL_CHARACTER2 = new RegExp(CONTROL_CHARACTER_CLASS, "u");
543
600
  function hasControlCharacter(text) {
544
- return CONTROL_CHARACTER.test(text);
601
+ return CONTROL_CHARACTER2.test(text);
545
602
  }
546
603
 
547
604
  // ../events/dist/phase-identity.js
@@ -632,16 +689,16 @@ var ACTOR_MAX = 200;
632
689
  var FINDING_MAX = 500;
633
690
  var FINDINGS_SHOWN_MAX = 50;
634
691
  var PHASE_CLOSE_REASON_MAX = 1900;
635
- var closeCommitSchema = z5.string().regex(/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/, "must be a full commit hash: 40 or 64 lowercase hex characters");
636
- var walkVerdictSchema = z5.enum(["clean", "defects"]);
637
- var acceptanceOutcomeSchema = z5.object({
692
+ var closeCommitSchema = z6.string().regex(/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/, "must be a full commit hash: 40 or 64 lowercase hex characters");
693
+ var walkVerdictSchema = z6.enum(["clean", "defects"]);
694
+ var acceptanceOutcomeSchema = z6.object({
638
695
  verdict: walkVerdictSchema,
639
- findings: z5.number().int().nonnegative(),
640
- findingsDetail: z5.array(z5.object({ summary: z5.string().refine((v) => !hasLoneSurrogate(v), { message: LONE_SURROGATE_MESSAGE }) }).strict())
696
+ findings: z6.number().int().nonnegative(),
697
+ findingsDetail: z6.array(z6.object({ summary: z6.string().refine((v) => !hasLoneSurrogate(v), { message: LONE_SURROGATE_MESSAGE }) }).strict())
641
698
  }).strict();
642
- var closeDecisionSchema = z5.enum(["done-when-met", "override"]);
699
+ var closeDecisionSchema = z6.enum(["done-when-met", "override"]);
643
700
  function plainText(max) {
644
- const base = max === void 0 ? z5.string() : z5.string().max(max);
701
+ const base = max === void 0 ? z6.string() : z6.string().max(max);
645
702
  return base.refine((v) => !hasControlCharacter(v), {
646
703
  message: "must be one line with no control characters (no line breaks, tabs or NUL)"
647
704
  }).refine((v) => !hasLoneSurrogate(v), { message: LONE_SURROGATE_MESSAGE });
@@ -653,81 +710,81 @@ function statementText(max) {
653
710
  }
654
711
  var closeActorSchema = plainText(ACTOR_MAX);
655
712
  var PHASE_NAME_RULE = `must be a phase name: not empty, no slash or backslash, not starting with a dot, no control characters, at most ${PHASE_NAME_MAX_BYTES} bytes`;
656
- var phaseNameSchema = z5.string().refine((v) => isValidPhaseIdentity(v), {
713
+ var phaseNameSchema = z6.string().refine((v) => isValidPhaseIdentity(v), {
657
714
  message: PHASE_NAME_RULE
658
715
  });
659
- var phaseIdentitySchema = z5.union([z5.string(), z5.number()], { error: "must be a phase name or a whole number" }).refine((v) => isValidPhaseIdentity(v), { message: PHASE_NAME_RULE });
660
- var closeStatementsSchema = z5.object({
716
+ var phaseIdentitySchema = z6.union([z6.string(), z6.number()], { error: "must be a phase name or a whole number" }).refine((v) => isValidPhaseIdentity(v), { message: PHASE_NAME_RULE });
717
+ var closeStatementsSchema = z6.object({
661
718
  thesis: statementText(STATEMENT_MAX).nullable(),
662
719
  outcome: statementText(STATEMENT_MAX).nullable(),
663
- deviations: z5.array(statementText(DEVIATION_MAX)).max(DEVIATIONS_MAX),
720
+ deviations: z6.array(statementText(DEVIATION_MAX)).max(DEVIATIONS_MAX),
664
721
  closeCommit: closeCommitSchema.nullable()
665
722
  }).strict();
666
- var closedBySchema = z5.discriminatedUnion("kind", [
667
- z5.object({ kind: z5.literal("account"), email: plainText().nullable() }).strict(),
668
- z5.object({ kind: z5.literal("no-account") }).strict(),
669
- z5.object({ kind: z5.literal("account-removed") }).strict(),
670
- z5.object({ kind: z5.literal("not-recorded") }).strict()
723
+ var closedBySchema = z6.discriminatedUnion("kind", [
724
+ z6.object({ kind: z6.literal("account"), email: plainText().nullable() }).strict(),
725
+ z6.object({ kind: z6.literal("no-account") }).strict(),
726
+ z6.object({ kind: z6.literal("account-removed") }).strict(),
727
+ z6.object({ kind: z6.literal("not-recorded") }).strict()
671
728
  ]);
672
729
  var STEP_NAME_MAX = 200;
673
730
  var stepNameSchema = plainText(STEP_NAME_MAX).refine((v) => v.trim().length > 0, {
674
731
  message: "must not be blank"
675
732
  });
676
- var unfinishedStepSchema = z5.object({
733
+ var unfinishedStepSchema = z6.object({
677
734
  stepId: plainText(),
678
- state: z5.enum(["parked", "failed"]),
735
+ state: z6.enum(["parked", "failed"]),
679
736
  name: stepNameSchema.optional()
680
737
  }).strict();
681
- var crossedSchema = z5.discriminatedUnion("kind", [
682
- z5.object({ kind: z5.literal("none") }).strict(),
683
- z5.object({ kind: z5.literal("unfinished-steps"), steps: z5.array(unfinishedStepSchema).min(1) }).strict(),
684
- z5.object({ kind: z5.literal("clean-over-findings"), findings: z5.number().int().min(1) }).strict(),
685
- z5.object({ kind: z5.literal("not-recorded") }).strict()
738
+ var crossedSchema = z6.discriminatedUnion("kind", [
739
+ z6.object({ kind: z6.literal("none") }).strict(),
740
+ z6.object({ kind: z6.literal("unfinished-steps"), steps: z6.array(unfinishedStepSchema).min(1) }).strict(),
741
+ z6.object({ kind: z6.literal("clean-over-findings"), findings: z6.number().int().min(1) }).strict(),
742
+ z6.object({ kind: z6.literal("not-recorded") }).strict()
686
743
  ]);
687
- var seatCoverageSchema = z5.object({
688
- enrolled: z5.number().int().nonnegative(),
689
- conformant: z5.number().int().nonnegative()
744
+ var seatCoverageSchema = z6.object({
745
+ enrolled: z6.number().int().nonnegative(),
746
+ conformant: z6.number().int().nonnegative()
690
747
  }).strict().refine((c) => c.conformant <= c.enrolled, {
691
748
  message: "conformant cannot exceed enrolled",
692
749
  path: ["conformant"]
693
750
  });
694
- var observedCloseSchema = z5.object({
695
- sequence: z5.number().int().min(1),
751
+ var observedCloseSchema = z6.object({
752
+ sequence: z6.number().int().min(1),
696
753
  closedAt: utcIso8601,
697
754
  closedBy: closedBySchema,
698
755
  crossed: crossedSchema,
699
756
  seatCoverage: seatCoverageSchema.nullable()
700
757
  }).strict();
701
- var couldNotRunCheckSchema = z5.object({
758
+ var couldNotRunCheckSchema = z6.object({
702
759
  check: plainText(),
703
760
  description: plainText().nullable(),
704
761
  reason: plainText()
705
762
  }).strict();
706
- var firedCheckSchema = z5.object({
763
+ var firedCheckSchema = z6.object({
707
764
  check: plainText(),
708
765
  description: plainText().nullable(),
709
766
  severity: severitySchema,
710
767
  explanation: plainText().nullable(),
711
- occurrences: z5.number().int().min(1)
768
+ occurrences: z6.number().int().min(1)
712
769
  }).strict();
713
- var phaseChecksSchema = z5.discriminatedUnion("state", [
714
- z5.object({ state: z5.literal("not-observed") }).strict(),
715
- z5.object({
716
- state: z5.literal("nothing-fired"),
717
- runs: z5.number().int().min(1),
718
- couldNotRun: z5.array(couldNotRunCheckSchema)
770
+ var phaseChecksSchema = z6.discriminatedUnion("state", [
771
+ z6.object({ state: z6.literal("not-observed") }).strict(),
772
+ z6.object({
773
+ state: z6.literal("nothing-fired"),
774
+ runs: z6.number().int().min(1),
775
+ couldNotRun: z6.array(couldNotRunCheckSchema)
719
776
  }).strict(),
720
- z5.object({
721
- state: z5.literal("fired"),
722
- runs: z5.number().int().min(1),
723
- couldNotRun: z5.array(couldNotRunCheckSchema),
724
- fired: z5.array(firedCheckSchema).min(1)
777
+ z6.object({
778
+ state: z6.literal("fired"),
779
+ runs: z6.number().int().min(1),
780
+ couldNotRun: z6.array(couldNotRunCheckSchema),
781
+ fired: z6.array(firedCheckSchema).min(1)
725
782
  }).strict()
726
783
  ]);
727
- var observedSchema = z5.object({
784
+ var observedSchema = z6.object({
728
785
  engagementId: plainText(),
729
786
  methodVersion: methodVersionSchema,
730
- closes: z5.array(observedCloseSchema).min(1),
787
+ closes: z6.array(observedCloseSchema).min(1),
731
788
  checks: phaseChecksSchema
732
789
  }).strict().superRefine((o, ctx) => {
733
790
  o.closes.forEach((close, i) => {
@@ -740,18 +797,18 @@ var observedSchema = z5.object({
740
797
  }
741
798
  });
742
799
  });
743
- var attestedWalkSchema = z5.object({
800
+ var attestedWalkSchema = z6.object({
744
801
  verdict: walkVerdictSchema,
745
- findings: z5.array(plainText(FINDING_MAX)).max(FINDINGS_SHOWN_MAX),
746
- findingsNotShown: z5.number().int().nonnegative()
802
+ findings: z6.array(plainText(FINDING_MAX)).max(FINDINGS_SHOWN_MAX),
803
+ findingsNotShown: z6.number().int().nonnegative()
747
804
  }).strict();
748
- var attestedStatementsSchema = z5.object({
805
+ var attestedStatementsSchema = z6.object({
749
806
  thesis: plainText(STATEMENT_MAX).nullable(),
750
807
  outcome: plainText(STATEMENT_MAX).nullable(),
751
- deviations: z5.array(plainText(DEVIATION_MAX)).max(DEVIATIONS_MAX)
808
+ deviations: z6.array(plainText(DEVIATION_MAX)).max(DEVIATIONS_MAX)
752
809
  }).strict();
753
- var attestedCloseSchema = z5.object({
754
- sequence: z5.number().int().min(1),
810
+ var attestedCloseSchema = z6.object({
811
+ sequence: z6.number().int().min(1),
755
812
  decision: closeDecisionSchema,
756
813
  actor: plainText(ACTOR_MAX).nullable(),
757
814
  reason: plainText(PHASE_CLOSE_REASON_MAX).nullable(),
@@ -759,8 +816,8 @@ var attestedCloseSchema = z5.object({
759
816
  closeCommit: closeCommitSchema.nullable(),
760
817
  statements: attestedStatementsSchema
761
818
  }).strict();
762
- var attestedSchema = z5.object({
763
- closes: z5.array(attestedCloseSchema)
819
+ var attestedSchema = z6.object({
820
+ closes: z6.array(attestedCloseSchema)
764
821
  }).strict();
765
822
  function checkRecordHalves(record2, ctx) {
766
823
  const observedBySequence = new Map(record2.observed.closes.map((c) => [c.sequence, c]));
@@ -791,18 +848,18 @@ function checkRecordHalves(record2, ctx) {
791
848
  }
792
849
  });
793
850
  }
794
- var buildRecordV2Schema = z5.object({
795
- format: z5.literal(BUILD_RECORD_V2_FORMAT),
851
+ var buildRecordV2Schema = z6.object({
852
+ format: z6.literal(BUILD_RECORD_V2_FORMAT),
796
853
  phase: phaseNameSchema,
797
854
  observed: observedSchema,
798
855
  attested: attestedSchema
799
856
  }).strict().superRefine(checkRecordHalves);
800
857
 
801
858
  // ../events/dist/build-snapshot.js
802
- import { z as z7 } from "zod";
859
+ import { z as z8 } from "zod";
803
860
 
804
861
  // ../events/dist/system-description.js
805
- import { z as z6 } from "zod";
862
+ import { z as z7 } from "zod";
806
863
  var SYSTEM_DESCRIPTION_FORMAT = 1;
807
864
  var SYSTEM_PARTS_MAX = 60;
808
865
  var SYSTEM_CONNECTIONS_MAX = 400;
@@ -814,11 +871,11 @@ var SYSTEM_PART_DESCRIPTION_MAX = 160;
814
871
  var SYSTEM_CONNECTION_LABEL_MAX = 60;
815
872
  var SYSTEM_PART_ID_PATTERN = /^[a-z][a-z0-9-]{0,39}$/;
816
873
  var SYSTEM_LANES = ["clients", "edge", "services", "data", "external"];
817
- var systemLaneSchema = z6.enum(SYSTEM_LANES, {
874
+ var systemLaneSchema = z7.enum(SYSTEM_LANES, {
818
875
  error: `must be one of ${SYSTEM_LANES.join(", ")}`
819
876
  });
820
877
  var SYSTEM_CONNECTION_KINDS = ["call", "event", "write", "external"];
821
- var systemConnectionKindSchema = z6.enum(SYSTEM_CONNECTION_KINDS, {
878
+ var systemConnectionKindSchema = z7.enum(SYSTEM_CONNECTION_KINDS, {
822
879
  error: `must be one of ${SYSTEM_CONNECTION_KINDS.join(", ")}`
823
880
  });
824
881
  var LINE_SEPARATOR = /[\u2028\u2029]/;
@@ -827,7 +884,7 @@ function descriptionText(max) {
827
884
  message: "must be one line: it holds a line or paragraph separator"
828
885
  });
829
886
  }
830
- var systemPartIdSchema = z6.string().regex(SYSTEM_PART_ID_PATTERN, {
887
+ var systemPartIdSchema = z7.string().regex(SYSTEM_PART_ID_PATTERN, {
831
888
  message: "must be a short id: a lowercase letter, then lowercase letters, digits or hyphens, 40 characters at most"
832
889
  }).refine((v) => !looksLikeSecret(v), { message: "looks like a password or key; choose another id" });
833
890
  function hasEmptySegment(pattern) {
@@ -843,50 +900,50 @@ var SEGMENT_CHARACTERS = /^[A-Za-z0-9._\-*]*$/;
843
900
  function hasForeignCharacter(pattern) {
844
901
  return pattern.split("/").some((segment) => !SEGMENT_CHARACTERS.test(segment));
845
902
  }
846
- var systemOwnedPatternSchema = z6.string().max(SYSTEM_OWNED_PATTERN_MAX, { message: `must be at most ${SYSTEM_OWNED_PATTERN_MAX} characters` }).refine((v) => !hasEmptySegment(v), {
903
+ var systemOwnedPatternSchema = z7.string().max(SYSTEM_OWNED_PATTERN_MAX, { message: `must be at most ${SYSTEM_OWNED_PATTERN_MAX} characters` }).refine((v) => !hasEmptySegment(v), {
847
904
  message: "must not start or end with a slash, or have two slashes together"
848
905
  }).refine((v) => !hasDotSegment(v), { message: 'must not have a "." or ".." folder in it' }).refine((v) => !hasPartialDoubleStar(v), { message: '"**" must stand alone between slashes' }).refine((v) => !hasForeignCharacter(v), {
849
906
  message: 'may use only letters, digits, ".", "_", "-" and "*" between slashes'
850
907
  }).refine((v) => !looksLikeSecret(v), {
851
908
  message: "this path looks like a credential; list a shorter folder above it"
852
909
  });
853
- var systemPartSchema = z6.object({
910
+ var systemPartSchema = z7.object({
854
911
  id: systemPartIdSchema,
855
912
  name: descriptionText(SYSTEM_PART_NAME_MAX),
856
913
  description: descriptionText(SYSTEM_PART_DESCRIPTION_MAX),
857
914
  lane: systemLaneSchema,
858
- slot: z6.number({ error: `must be a whole number from 0 to ${SYSTEM_SLOT_MAX}` }).int({ error: `must be a whole number from 0 to ${SYSTEM_SLOT_MAX}` }).min(0, { error: `must be a whole number from 0 to ${SYSTEM_SLOT_MAX}` }).max(SYSTEM_SLOT_MAX, { error: `must be a whole number from 0 to ${SYSTEM_SLOT_MAX}` }),
859
- outside: z6.boolean(),
860
- owns: z6.array(systemOwnedPatternSchema).max(SYSTEM_OWNS_MAX, { message: `can list at most ${SYSTEM_OWNS_MAX} paths` })
915
+ slot: z7.number({ error: `must be a whole number from 0 to ${SYSTEM_SLOT_MAX}` }).int({ error: `must be a whole number from 0 to ${SYSTEM_SLOT_MAX}` }).min(0, { error: `must be a whole number from 0 to ${SYSTEM_SLOT_MAX}` }).max(SYSTEM_SLOT_MAX, { error: `must be a whole number from 0 to ${SYSTEM_SLOT_MAX}` }),
916
+ outside: z7.boolean(),
917
+ owns: z7.array(systemOwnedPatternSchema).max(SYSTEM_OWNS_MAX, { message: `can list at most ${SYSTEM_OWNS_MAX} paths` })
861
918
  }).strict();
862
- var systemConnectionSchema = z6.object({
919
+ var systemConnectionSchema = z7.object({
863
920
  from: systemPartIdSchema,
864
921
  to: systemPartIdSchema,
865
922
  kind: systemConnectionKindSchema,
866
923
  label: descriptionText(SYSTEM_CONNECTION_LABEL_MAX)
867
924
  }).strict();
868
- var systemDescriptionSchema = z6.object({
869
- format: z6.literal(SYSTEM_DESCRIPTION_FORMAT, { error: `must be ${SYSTEM_DESCRIPTION_FORMAT}` }),
870
- parts: z6.array(systemPartSchema).min(1, { message: "must list at least one part" }).max(SYSTEM_PARTS_MAX, { message: `can hold at most ${SYSTEM_PARTS_MAX} parts (five lanes of twelve slots)` }),
871
- connections: z6.array(systemConnectionSchema).max(SYSTEM_CONNECTIONS_MAX, { message: `can hold at most ${SYSTEM_CONNECTIONS_MAX} connections` })
925
+ var systemDescriptionSchema = z7.object({
926
+ format: z7.literal(SYSTEM_DESCRIPTION_FORMAT, { error: `must be ${SYSTEM_DESCRIPTION_FORMAT}` }),
927
+ parts: z7.array(systemPartSchema).min(1, { message: "must list at least one part" }).max(SYSTEM_PARTS_MAX, { message: `can hold at most ${SYSTEM_PARTS_MAX} parts (five lanes of twelve slots)` }),
928
+ connections: z7.array(systemConnectionSchema).max(SYSTEM_CONNECTIONS_MAX, { message: `can hold at most ${SYSTEM_CONNECTIONS_MAX} connections` })
872
929
  }).strict();
873
- var systemDescriptionProblemSchema = z6.object({
874
- path: z6.string(),
875
- message: z6.string()
930
+ var systemDescriptionProblemSchema = z7.object({
931
+ path: z7.string(),
932
+ message: z7.string()
876
933
  }).strict();
877
- var systemReportRecordedSchema = z6.object({
878
- outcome: z6.literal("recorded"),
879
- version: z6.number().int().min(1),
934
+ var systemReportRecordedSchema = z7.object({
935
+ outcome: z7.literal("recorded"),
936
+ version: z7.number().int().min(1),
880
937
  reportedAt: utcIso8601
881
938
  }).strict();
882
- var systemReportRefusedSchema = z6.object({
883
- outcome: z6.literal("refused"),
884
- problems: z6.array(systemDescriptionProblemSchema).min(1)
939
+ var systemReportRefusedSchema = z7.object({
940
+ outcome: z7.literal("refused"),
941
+ problems: z7.array(systemDescriptionProblemSchema).min(1)
885
942
  }).strict();
886
- var systemReportUnavailableSchema = z6.object({
887
- outcome: z6.literal("unavailable")
943
+ var systemReportUnavailableSchema = z7.object({
944
+ outcome: z7.literal("unavailable")
888
945
  }).strict();
889
- var systemReportResultSchema = z6.discriminatedUnion("outcome", [
946
+ var systemReportResultSchema = z7.discriminatedUnion("outcome", [
890
947
  systemReportRecordedSchema,
891
948
  systemReportRefusedSchema,
892
949
  systemReportUnavailableSchema
@@ -894,20 +951,20 @@ var systemReportResultSchema = z6.discriminatedUnion("outcome", [
894
951
  var SYSTEM_DRAW_SVG_MAX_BYTES = 2 * 1024 * 1024;
895
952
  var SYSTEM_DRAW_MERMAID_MAX_BYTES = 256 * 1024;
896
953
  var SYSTEM_DRAW_PNG_MAX_BYTES = 8 * 1024 * 1024;
897
- var systemDrawArchitectureRequestSchema = z6.object({
898
- picture: z6.literal("architecture"),
899
- version: z6.number().int().min(1)
954
+ var systemDrawArchitectureRequestSchema = z7.object({
955
+ picture: z7.literal("architecture"),
956
+ version: z7.number().int().min(1)
900
957
  }).strict();
901
- var systemDrawPhaseRequestSchema = z6.object({
902
- picture: z6.literal("phase"),
958
+ var systemDrawPhaseRequestSchema = z7.object({
959
+ picture: z7.literal("phase"),
903
960
  phase: phaseIdentitySchema,
904
- planVersion: z6.number().int().min(1)
961
+ planVersion: z7.number().int().min(1)
905
962
  }).strict();
906
- var systemDrawClosedPhaseRequestSchema = z6.object({
907
- picture: z6.literal("closed-phase"),
963
+ var systemDrawClosedPhaseRequestSchema = z7.object({
964
+ picture: z7.literal("closed-phase"),
908
965
  phase: phaseIdentitySchema
909
966
  }).strict();
910
- var systemDrawRequestSchema = z6.discriminatedUnion("picture", [
967
+ var systemDrawRequestSchema = z7.discriminatedUnion("picture", [
911
968
  systemDrawArchitectureRequestSchema,
912
969
  systemDrawPhaseRequestSchema,
913
970
  systemDrawClosedPhaseRequestSchema
@@ -938,23 +995,23 @@ function base64DecodedLength(text) {
938
995
  const padding = text.endsWith("==") ? 2 : text.endsWith("=") ? 1 : 0;
939
996
  return text.length / 4 * 3 - padding;
940
997
  }
941
- var systemPictureSchema = z6.object({
942
- svg: z6.string().min(1).refine((v) => utf8ByteLength2(v) <= SYSTEM_DRAW_SVG_MAX_BYTES, { message: "the picture is larger than 2 MB" }),
943
- png: z6.string().min(1).refine((v) => v.length % 4 === 0 && BASE64.test(v), { message: "the image is not valid base64" }).refine((v) => base64DecodedLength(v) <= SYSTEM_DRAW_PNG_MAX_BYTES, { message: "the image is larger than 8 MB" })
998
+ var systemPictureSchema = z7.object({
999
+ svg: z7.string().min(1).refine((v) => utf8ByteLength2(v) <= SYSTEM_DRAW_SVG_MAX_BYTES, { message: "the picture is larger than 2 MB" }),
1000
+ png: z7.string().min(1).refine((v) => v.length % 4 === 0 && BASE64.test(v), { message: "the image is not valid base64" }).refine((v) => base64DecodedLength(v) <= SYSTEM_DRAW_PNG_MAX_BYTES, { message: "the image is larger than 8 MB" })
944
1001
  }).strict();
945
- var systemDrawRefusedSchema = z6.object({
946
- outcome: z6.literal("refused"),
947
- reason: z6.string().min(1)
1002
+ var systemDrawRefusedSchema = z7.object({
1003
+ outcome: z7.literal("refused"),
1004
+ reason: z7.string().min(1)
948
1005
  }).strict();
949
- var systemDrawUnavailableSchema = z6.object({
950
- outcome: z6.literal("unavailable")
1006
+ var systemDrawUnavailableSchema = z7.object({
1007
+ outcome: z7.literal("unavailable")
951
1008
  }).strict();
952
- var systemDrawNotClosedSchema = z6.object({
953
- outcome: z6.literal("not-closed")
1009
+ var systemDrawNotClosedSchema = z7.object({
1010
+ outcome: z7.literal("not-closed")
954
1011
  }).strict();
955
1012
 
956
1013
  // ../events/dist/build-snapshot.js
957
- var buildTaskStateSchema = z7.enum([
1014
+ var buildTaskStateSchema = z8.enum([
958
1015
  "pending",
959
1016
  "in-flight",
960
1017
  "completed",
@@ -967,27 +1024,27 @@ var BUILD_TASK_WHY_OUTSIDE_PLAN_MAX = 160;
967
1024
  var BUILD_TASK_BUDGET_MAX_MINUTES = 10080;
968
1025
  var BUILD_TASK_NOTE_MAX = 240;
969
1026
  var BUILD_TASK_CLEAR_COMMAND_MAX = 240;
970
- var buildTaskKindSchema = z7.enum(["build", "review", "spec", "walk", "check"]);
971
- var buildTaskIdSchema = z7.string().min(1).max(64);
972
- var buildTaskSchema = z7.object({
1027
+ var buildTaskKindSchema = z8.enum(["build", "review", "spec", "walk", "check"]);
1028
+ var buildTaskIdSchema = z8.string().min(1).max(64);
1029
+ var buildTaskSchema = z8.object({
973
1030
  // The task's own id, as the coordinator's graph names it.
974
1031
  id: buildTaskIdSchema,
975
1032
  // What the task is, in the coordinator's words. A description of the work,
976
1033
  // bounded and scanned — never an excerpt of anybody's code.
977
- title: z7.string().min(1).max(BUILD_TASK_TITLE_MAX),
1034
+ title: z8.string().min(1).max(BUILD_TASK_TITLE_MAX),
978
1035
  // What the task is doing right now.
979
1036
  state: buildTaskStateSchema,
980
1037
  // Who holds it — a bare callsign, or the value naming a person when the work is
981
1038
  // a person's. Absent when nothing has been dispatched to it yet.
982
1039
  agent: agentNameSchema.optional(),
983
1040
  // The kind of work the holder does. Present exactly when an agent holds it.
984
- discipline: z7.string().min(1).max(64).optional(),
1041
+ discipline: z8.string().min(1).max(64).optional(),
985
1042
  // How much thinking the holder brings. Present exactly when an agent holds it,
986
1043
  // and there is no field naming the supplier behind it.
987
- tier: z7.string().min(1).max(32).optional(),
1044
+ tier: z8.string().min(1).max(32).optional(),
988
1045
  // The tasks this one cannot start before. Always present; empty means it waits
989
1046
  // on nothing, which is different from not having been computed.
990
- dependsOn: z7.array(buildTaskIdSchema).max(BUILD_SNAPSHOT_TASK_LIMIT),
1047
+ dependsOn: z8.array(buildTaskIdSchema).max(BUILD_SNAPSHOT_TASK_LIMIT),
991
1048
  // The one task this task checks, when it is a check on other work. Absent on a
992
1049
  // task that is doing the work rather than checking it.
993
1050
  reviews: buildTaskIdSchema.optional(),
@@ -1001,13 +1058,13 @@ var buildTaskSchema = z7.object({
1001
1058
  settledAt: utcIso8601.optional(),
1002
1059
  // The parts of this project's system the task builds, by their ids. Absent when
1003
1060
  // it builds none; never an empty list.
1004
- builds: z7.array(systemPartIdSchema).min(1).max(SYSTEM_PARTS_MAX).optional(),
1061
+ builds: z8.array(systemPartIdSchema).min(1).max(SYSTEM_PARTS_MAX).optional(),
1005
1062
  // In one line, why the task built a part the phase's plan does not include, in
1006
1063
  // the words of whoever holds it. Absent when it gave no reason.
1007
1064
  whyOutsidePlan: descriptionText(BUILD_TASK_WHY_OUTSIDE_PLAN_MAX).optional(),
1008
1065
  // How long the task is expected to take, in whole minutes, from one minute to one
1009
1066
  // week. A plan, not a measurement; absent when no budget was set.
1010
- budgetMinutes: z7.number().int().min(1).max(BUILD_TASK_BUDGET_MAX_MINUTES).optional(),
1067
+ budgetMinutes: z8.number().int().min(1).max(BUILD_TASK_BUDGET_MAX_MINUTES).optional(),
1011
1068
  // What kind of work the task is: building, checking other work, writing what to
1012
1069
  // build, a person trying the product, or a run of the project's own checks.
1013
1070
  // Absent when the graph does not say.
@@ -1024,14 +1081,14 @@ var buildTaskSchema = z7.object({
1024
1081
  }).strict().superRefine((task, ctx) => {
1025
1082
  if (task.reviews !== void 0 && task.reviews === task.id) {
1026
1083
  ctx.addIssue({
1027
- code: z7.ZodIssueCode.custom,
1084
+ code: z8.ZodIssueCode.custom,
1028
1085
  path: ["reviews"],
1029
1086
  message: `'${task.id}' reviews itself \u2014 a review names the OTHER task it checks.`
1030
1087
  });
1031
1088
  }
1032
1089
  if (task.layer !== void 0 && !isPhaseScopedLayer(task.layer)) {
1033
1090
  ctx.addIssue({
1034
- code: z7.ZodIssueCode.custom,
1091
+ code: z8.ZodIssueCode.custom,
1035
1092
  path: ["layer"],
1036
1093
  message: `'${task.layer}' is not a wave a phase runs \u2014 expected one of ${PHASE_SCOPED_LAYERS.join(", ")}.`
1037
1094
  });
@@ -1040,29 +1097,29 @@ var buildTaskSchema = z7.object({
1040
1097
  for (const field of ["discipline", "tier"]) {
1041
1098
  if (profiled && task[field] === void 0) {
1042
1099
  ctx.addIssue({
1043
- code: z7.ZodIssueCode.custom,
1100
+ code: z8.ZodIssueCode.custom,
1044
1101
  path: [field],
1045
1102
  message: `'${field}' is required on a task an agent holds.`
1046
1103
  });
1047
1104
  }
1048
1105
  if (!profiled && task[field] !== void 0) {
1049
1106
  ctx.addIssue({
1050
- code: z7.ZodIssueCode.custom,
1107
+ code: z8.ZodIssueCode.custom,
1051
1108
  path: [field],
1052
1109
  message: task.agent === void 0 ? `'${field}' must be absent on a task nobody holds.` : `'${field}' must be absent on work a person holds.`
1053
1110
  });
1054
1111
  }
1055
1112
  }
1056
1113
  });
1057
- var buildPhaseSchema = z7.string().min(1).max(128);
1114
+ var buildPhaseSchema = z8.string().min(1).max(128);
1058
1115
  var BUILD_PHASE_TITLE_MAX = 160;
1059
- var buildPhaseTitleSchema = z7.string().min(1).max(BUILD_PHASE_TITLE_MAX);
1060
- var buildTaskListSchema = z7.array(buildTaskSchema).max(BUILD_SNAPSHOT_TASK_LIMIT).superRefine((tasks, ctx) => {
1116
+ var buildPhaseTitleSchema = z8.string().min(1).max(BUILD_PHASE_TITLE_MAX);
1117
+ var buildTaskListSchema = z8.array(buildTaskSchema).max(BUILD_SNAPSHOT_TASK_LIMIT).superRefine((tasks, ctx) => {
1061
1118
  const seen = /* @__PURE__ */ new Set();
1062
1119
  for (const [index, task] of tasks.entries()) {
1063
1120
  if (seen.has(task.id)) {
1064
1121
  ctx.addIssue({
1065
- code: z7.ZodIssueCode.custom,
1122
+ code: z8.ZodIssueCode.custom,
1066
1123
  path: [index, "id"],
1067
1124
  message: `duplicate task id '${task.id}' \u2014 one graph names each task once.`
1068
1125
  });
@@ -1070,13 +1127,13 @@ var buildTaskListSchema = z7.array(buildTaskSchema).max(BUILD_SNAPSHOT_TASK_LIMI
1070
1127
  seen.add(task.id);
1071
1128
  }
1072
1129
  });
1073
- var buildTaskMarkSchema = z7.object({
1130
+ var buildTaskMarkSchema = z8.object({
1074
1131
  // The task that was marked.
1075
1132
  task: buildTaskIdSchema,
1076
1133
  // When it was first marked.
1077
1134
  at: utcIso8601
1078
1135
  }).strict();
1079
- var buildSnapshotSchema = z7.object({
1136
+ var buildSnapshotSchema = z8.object({
1080
1137
  // Which phase this graph belongs to.
1081
1138
  phase: buildPhaseSchema,
1082
1139
  // That phase's name in words, when the project gives it one.
@@ -1089,9 +1146,9 @@ var buildSnapshotSchema = z7.object({
1089
1146
  builtWithoutApproval: utcIso8601.optional(),
1090
1147
  // Each task that started on a part still waiting for approval, and when it was
1091
1148
  // first seen doing so. Absent when there is none.
1092
- tasksBuiltWithoutApproval: z7.array(buildTaskMarkSchema).min(1).max(BUILD_SNAPSHOT_TASK_LIMIT).optional()
1149
+ tasksBuiltWithoutApproval: z8.array(buildTaskMarkSchema).min(1).max(BUILD_SNAPSHOT_TASK_LIMIT).optional()
1093
1150
  }).strict();
1094
- var buildPhaseEntrySchema = z7.object({
1151
+ var buildPhaseEntrySchema = z8.object({
1095
1152
  // Which phase has a stored graph.
1096
1153
  phase: buildPhaseSchema,
1097
1154
  // That phase's name in words, when the project gave it one.
@@ -1099,9 +1156,9 @@ var buildPhaseEntrySchema = z7.object({
1099
1156
  // When that phase's graph was last reported.
1100
1157
  reportedAt: utcIso8601,
1101
1158
  // Present when work on this phase was reported with no approval of its scope in force.
1102
- builtWithoutApproval: z7.literal(true).optional()
1159
+ builtWithoutApproval: z8.literal(true).optional()
1103
1160
  }).strict();
1104
- var buildSnapshotReportSchema = z7.object({
1161
+ var buildSnapshotReportSchema = z8.object({
1105
1162
  // Which phase this graph belongs to.
1106
1163
  phase: buildPhaseSchema,
1107
1164
  // That phase's name in words, when the project gives it one.
@@ -1110,9 +1167,9 @@ var buildSnapshotReportSchema = z7.object({
1110
1167
  // one thing this route does not accept.
1111
1168
  tasks: buildTaskListSchema
1112
1169
  }).strict();
1113
- var buildSnapshotReportResultSchema = z7.object({
1170
+ var buildSnapshotReportResultSchema = z8.object({
1114
1171
  // What happened. One outcome today; a refusal travels as the shared wire error.
1115
- outcome: z7.literal("recorded"),
1172
+ outcome: z8.literal("recorded"),
1116
1173
  // Which phase the graph was recorded against.
1117
1174
  phase: buildPhaseSchema,
1118
1175
  // When it was recorded.
@@ -1120,27 +1177,55 @@ var buildSnapshotReportResultSchema = z7.object({
1120
1177
  }).strict();
1121
1178
 
1122
1179
  // ../events/dist/phase-plan.js
1123
- import { z as z8 } from "zod";
1180
+ import { z as z10 } from "zod";
1181
+
1182
+ // ../events/dist/change-path-order.js
1183
+ import { z as z9 } from "zod";
1184
+ var PATH_ORDER = Object.freeze(["small", "mini", "full"]);
1185
+ var changePathSchema = z9.enum(PATH_ORDER);
1186
+ var PHASE_PATHS = Object.freeze(["mini", "full"]);
1187
+ var phasePathSchema = z9.enum(PHASE_PATHS);
1188
+ var changeUpPathSchema = z9.enum(["mini", "full"]);
1189
+ var CHANGE_PATH_NEXT = Object.freeze({
1190
+ small: Object.freeze({ say: "make the small change", section: "small" }),
1191
+ mini: Object.freeze({ say: "scope the mini phase", section: "mini" }),
1192
+ full: Object.freeze({ say: "plan the next phase", section: "full" })
1193
+ });
1194
+ var changePathNextSchema = z9.object({
1195
+ say: z9.enum([CHANGE_PATH_NEXT.small.say, CHANGE_PATH_NEXT.mini.say, CHANGE_PATH_NEXT.full.say]),
1196
+ section: changePathSchema
1197
+ }).strict();
1198
+ var CHANGE_SENTENCE_MAX = 4e3;
1199
+ var planMovedUpSchema = z9.object({
1200
+ to: z9.literal("full"),
1201
+ sentence: z9.string().min(1).max(CHANGE_SENTENCE_MAX),
1202
+ next: changePathNextSchema
1203
+ }).strict().refine((m) => m.next.say === CHANGE_PATH_NEXT.full.say && m.next.section === CHANGE_PATH_NEXT.full.section, {
1204
+ message: "names the full path's next phrase and section",
1205
+ path: ["next"]
1206
+ });
1207
+
1208
+ // ../events/dist/phase-plan.js
1124
1209
  var PHASE_PLAN_FORMAT = 1;
1125
1210
  var PHASE_PLAN_CHANGES_MAX = 60;
1126
1211
  var PHASE_PLAN_SUMMARY_MAX = 160;
1127
1212
  var SCOPE_NOTE_MAX = 500;
1128
1213
  var PHASE_PLAN_PHASE_MAX = buildPhaseSchema.maxLength ?? 0;
1129
1214
  var PHASE_PLAN_CHANGE_KINDS = ["add", "change", "remove"];
1130
- var phasePlanChangeSchema = z8.enum(PHASE_PLAN_CHANGE_KINDS, {
1215
+ var phasePlanChangeSchema = z10.enum(PHASE_PLAN_CHANGE_KINDS, {
1131
1216
  error: `must be one of ${PHASE_PLAN_CHANGE_KINDS.join(", ")}`
1132
1217
  });
1133
1218
  var phasePlanPhaseSchema = phaseIdentitySchema.refine((v) => !isValidPhaseIdentity(v) || buildPhaseSchema.safeParse(String(v)).success, { message: `must be at most ${PHASE_PLAN_PHASE_MAX} characters` });
1134
1219
  var phasePlanSummarySchema = descriptionText(PHASE_PLAN_SUMMARY_MAX);
1135
- var phasePlanEntrySchema = z8.object({
1220
+ var phasePlanEntrySchema = z10.object({
1136
1221
  part: systemPartIdSchema,
1137
1222
  change: phasePlanChangeSchema,
1138
1223
  summary: phasePlanSummarySchema
1139
1224
  }).strict();
1140
- var phasePlanSchema = z8.object({
1141
- format: z8.literal(PHASE_PLAN_FORMAT, { error: `must be ${PHASE_PLAN_FORMAT}` }),
1225
+ var phasePlanSchema = z10.object({
1226
+ format: z10.literal(PHASE_PLAN_FORMAT, { error: `must be ${PHASE_PLAN_FORMAT}` }),
1142
1227
  phase: phasePlanPhaseSchema,
1143
- changes: z8.array(phasePlanEntrySchema).min(1, { message: "must list at least one part" }).max(PHASE_PLAN_CHANGES_MAX, { message: `can list at most ${PHASE_PLAN_CHANGES_MAX} parts` })
1228
+ changes: z10.array(phasePlanEntrySchema).min(1, { message: "must list at least one part" }).max(PHASE_PLAN_CHANGES_MAX, { message: `can list at most ${PHASE_PLAN_CHANGES_MAX} parts` })
1144
1229
  }).strict();
1145
1230
  var scopePhaseSchema = buildPhaseSchema.refine((v) => isValidPhaseIdentity(v), {
1146
1231
  message: "must be a phase name"
@@ -1152,109 +1237,110 @@ var SCOPE_STATE_NAMES = [
1152
1237
  "approved",
1153
1238
  "partly-stale"
1154
1239
  ];
1155
- var scopeStateNameSchema = z8.enum(SCOPE_STATE_NAMES);
1240
+ var scopeStateNameSchema = z10.enum(SCOPE_STATE_NAMES);
1156
1241
  var plannedScopeStateSchema = scopeStateNameSchema.exclude(["not-planned"]);
1157
1242
  var SCOPE_PART_STATUSES = ["approved", "waiting"];
1158
- var scopePartStatusSchema = z8.enum(SCOPE_PART_STATUSES);
1243
+ var scopePartStatusSchema = z10.enum(SCOPE_PART_STATUSES);
1159
1244
  var SCOPE_ACTS = ["approve", "send-back"];
1160
- var scopeActSchema = z8.enum(SCOPE_ACTS);
1245
+ var scopeActSchema = z10.enum(SCOPE_ACTS);
1161
1246
  var SCOPE_GIVEN_IN = ["console", "chat"];
1162
- var scopeGivenInSchema = z8.enum(SCOPE_GIVEN_IN);
1247
+ var scopeGivenInSchema = z10.enum(SCOPE_GIVEN_IN);
1163
1248
  var scopeNoteSchema = descriptionText(SCOPE_NOTE_MAX);
1164
- var scopeNoteWireSchema = z8.string().max(SCOPE_NOTE_MAX);
1249
+ var scopeNoteWireSchema = z10.string().max(SCOPE_NOTE_MAX);
1165
1250
  var SCOPE_PART_VERDICTS = ["ok", "change"];
1166
- var scopePartVerdictSchema = z8.enum(SCOPE_PART_VERDICTS);
1167
- var scopeDecisionPartSchema = z8.object({
1251
+ var scopePartVerdictSchema = z10.enum(SCOPE_PART_VERDICTS);
1252
+ var scopeDecisionPartSchema = z10.object({
1168
1253
  part: systemPartIdSchema,
1169
1254
  verdict: scopePartVerdictSchema,
1170
1255
  note: scopeNoteWireSchema.optional()
1171
1256
  }).strict();
1172
- var planVersionSchema = z8.number().int().min(1);
1173
- var carriedPhaseSchema = z8.object({
1257
+ var planVersionSchema = z10.number().int().min(1);
1258
+ var carriedPhaseSchema = z10.object({
1174
1259
  phase: scopePhaseSchema,
1175
- number: z8.number().int().min(1)
1260
+ number: z10.number().int().min(1)
1176
1261
  }).strict();
1177
1262
  var carriedFromEntrySchema = carriedPhaseSchema.extend({
1178
1263
  part: systemPartIdSchema
1179
1264
  }).strict();
1180
- var phasePlanRequestSchema = z8.object({
1181
- descriptionVersion: z8.number().int().min(1),
1182
- plan: z8.unknown()
1265
+ var phasePlanRequestSchema = z10.object({
1266
+ descriptionVersion: z10.number().int().min(1),
1267
+ plan: z10.unknown()
1183
1268
  }).strict();
1184
- var phasePlanRecordedSchema = z8.object({
1185
- outcome: z8.literal("recorded"),
1269
+ var phasePlanRecordedSchema = z10.object({
1270
+ outcome: z10.literal("recorded"),
1186
1271
  version: planVersionSchema,
1187
- phaseNumber: z8.number().int().min(1),
1272
+ phaseNumber: z10.number().int().min(1),
1188
1273
  state: plannedScopeStateSchema,
1189
- changedParts: z8.array(systemPartIdSchema).max(PHASE_PLAN_CHANGES_MAX),
1190
- typedApprovalOffered: z8.boolean(),
1274
+ changedParts: z10.array(systemPartIdSchema).max(PHASE_PLAN_CHANGES_MAX),
1275
+ typedApprovalOffered: z10.boolean(),
1191
1276
  reportedAt: utcIso8601,
1192
- carriedFrom: z8.array(carriedFromEntrySchema).min(1).max(PHASE_PLAN_CHANGES_MAX).optional()
1277
+ carriedFrom: z10.array(carriedFromEntrySchema).min(1).max(PHASE_PLAN_CHANGES_MAX).optional(),
1278
+ movedUp: planMovedUpSchema.optional()
1193
1279
  }).strict();
1194
- var phasePlanRefusedSchema = z8.object({
1195
- outcome: z8.literal("refused"),
1196
- problems: z8.array(systemDescriptionProblemSchema).min(1)
1280
+ var phasePlanRefusedSchema = z10.object({
1281
+ outcome: z10.literal("refused"),
1282
+ problems: z10.array(systemDescriptionProblemSchema).min(1)
1197
1283
  }).strict();
1198
- var phasePlanUnavailableSchema = z8.object({
1199
- outcome: z8.literal("unavailable")
1284
+ var phasePlanUnavailableSchema = z10.object({
1285
+ outcome: z10.literal("unavailable")
1200
1286
  }).strict();
1201
1287
  var REMOVAL_OWED_ACTS = ["dropped", "removed"];
1202
- var removalOwedPartSchema = z8.object({
1288
+ var removalOwedPartSchema = z10.object({
1203
1289
  part: systemPartIdSchema,
1204
1290
  name: systemPartSchema.shape.name,
1205
1291
  phase: scopePhaseSchema,
1206
- number: z8.number().int().min(1),
1207
- act: z8.enum(REMOVAL_OWED_ACTS)
1292
+ number: z10.number().int().min(1),
1293
+ act: z10.enum(REMOVAL_OWED_ACTS)
1208
1294
  }).strict();
1209
- var phasePlanRemovalOwedSchema = z8.object({
1210
- outcome: z8.literal("removal-owed"),
1211
- parts: z8.array(removalOwedPartSchema).min(1).max(SYSTEM_PARTS_MAX)
1295
+ var phasePlanRemovalOwedSchema = z10.object({
1296
+ outcome: z10.literal("removal-owed"),
1297
+ parts: z10.array(removalOwedPartSchema).min(1).max(SYSTEM_PARTS_MAX)
1212
1298
  }).strict();
1213
- var phasePlanResultSchema = z8.discriminatedUnion("outcome", [
1299
+ var phasePlanResultSchema = z10.discriminatedUnion("outcome", [
1214
1300
  phasePlanRecordedSchema,
1215
1301
  phasePlanRefusedSchema,
1216
1302
  phasePlanUnavailableSchema,
1217
1303
  phasePlanRemovalOwedSchema
1218
1304
  ]);
1219
- var scopeApproveRequestSchema = z8.object({
1220
- act: z8.literal("approve"),
1305
+ var scopeApproveRequestSchema = z10.object({
1306
+ act: z10.literal("approve"),
1221
1307
  planVersion: planVersionSchema,
1222
- parts: z8.array(scopeDecisionPartSchema).max(PHASE_PLAN_CHANGES_MAX)
1308
+ parts: z10.array(scopeDecisionPartSchema).max(PHASE_PLAN_CHANGES_MAX)
1223
1309
  }).strict();
1224
- var scopeSendBackRequestSchema = z8.object({
1225
- act: z8.literal("send-back"),
1310
+ var scopeSendBackRequestSchema = z10.object({
1311
+ act: z10.literal("send-back"),
1226
1312
  planVersion: planVersionSchema,
1227
- parts: z8.array(scopeDecisionPartSchema).max(PHASE_PLAN_CHANGES_MAX),
1313
+ parts: z10.array(scopeDecisionPartSchema).max(PHASE_PLAN_CHANGES_MAX),
1228
1314
  note: scopeNoteWireSchema.optional()
1229
1315
  }).strict();
1230
- var scopeDecisionRequestSchema = z8.discriminatedUnion("act", [
1316
+ var scopeDecisionRequestSchema = z10.discriminatedUnion("act", [
1231
1317
  scopeApproveRequestSchema,
1232
1318
  scopeSendBackRequestSchema
1233
1319
  ]);
1234
- var scopeDecisionRecordedSchema = z8.object({
1235
- outcome: z8.literal("recorded"),
1320
+ var scopeDecisionRecordedSchema = z10.object({
1321
+ outcome: z10.literal("recorded"),
1236
1322
  act: scopeActSchema,
1237
1323
  phase: scopePhaseSchema,
1238
1324
  planVersion: planVersionSchema,
1239
1325
  state: plannedScopeStateSchema,
1240
1326
  decidedAt: utcIso8601
1241
1327
  }).strict();
1242
- var scopeDecisionAlreadyApprovedSchema = z8.object({
1243
- outcome: z8.literal("already-approved"),
1244
- replanNeeded: z8.boolean(),
1245
- reason: z8.string().min(1)
1328
+ var scopeDecisionAlreadyApprovedSchema = z10.object({
1329
+ outcome: z10.literal("already-approved"),
1330
+ replanNeeded: z10.boolean(),
1331
+ reason: z10.string().min(1)
1246
1332
  }).strict();
1247
- var scopeDecisionRefusedSchema = z8.object({
1248
- outcome: z8.literal("refused"),
1249
- problems: z8.array(systemDescriptionProblemSchema).min(1)
1333
+ var scopeDecisionRefusedSchema = z10.object({
1334
+ outcome: z10.literal("refused"),
1335
+ problems: z10.array(systemDescriptionProblemSchema).min(1)
1250
1336
  }).strict();
1251
- var scopeDecisionUnavailableSchema = z8.object({
1252
- outcome: z8.literal("unavailable")
1337
+ var scopeDecisionUnavailableSchema = z10.object({
1338
+ outcome: z10.literal("unavailable")
1253
1339
  }).strict();
1254
1340
  function reasonOutcome(outcome) {
1255
- return z8.object({ outcome: z8.literal(outcome), reason: z8.string().min(1) }).strict();
1341
+ return z10.object({ outcome: z10.literal(outcome), reason: z10.string().min(1) }).strict();
1256
1342
  }
1257
- var scopeDecisionResultSchema = z8.discriminatedUnion("outcome", [
1343
+ var scopeDecisionResultSchema = z10.discriminatedUnion("outcome", [
1258
1344
  scopeDecisionRecordedSchema,
1259
1345
  scopeDecisionAlreadyApprovedSchema,
1260
1346
  scopeDecisionRefusedSchema,
@@ -1264,357 +1350,88 @@ var scopeDecisionResultSchema = z8.discriminatedUnion("outcome", [
1264
1350
  reasonOutcome("plan-changed"),
1265
1351
  reasonOutcome("build-started")
1266
1352
  ]);
1267
- var scopeReadPartSchema = z8.object({
1353
+ var scopeReadPartSchema = z10.object({
1268
1354
  part: systemPartIdSchema,
1269
1355
  name: systemPartSchema.shape.name,
1270
1356
  change: phasePlanChangeSchema,
1271
1357
  summary: phasePlanSummarySchema,
1272
1358
  status: scopePartStatusSchema,
1273
- changed: z8.boolean(),
1359
+ changed: z10.boolean(),
1274
1360
  carriedFrom: carriedPhaseSchema.optional()
1275
1361
  }).strict();
1276
- var scopeReadDecisionSchema = z8.object({
1362
+ var scopeReadDecisionSchema = z10.object({
1277
1363
  act: scopeActSchema,
1278
1364
  planVersion: planVersionSchema,
1279
1365
  givenIn: scopeGivenInSchema,
1280
1366
  at: utcIso8601,
1281
- parts: z8.array(scopeDecisionPartSchema).max(PHASE_PLAN_CHANGES_MAX),
1367
+ parts: z10.array(scopeDecisionPartSchema).max(PHASE_PLAN_CHANGES_MAX),
1282
1368
  note: scopeNoteWireSchema.optional()
1283
1369
  }).strict();
1284
- var scopeReadNotPlannedSchema = z8.object({
1370
+ var scopeReadNotPlannedSchema = z10.object({
1285
1371
  phase: scopePhaseSchema,
1286
- state: z8.literal("not-planned"),
1287
- canDecide: z8.boolean()
1372
+ state: z10.literal("not-planned"),
1373
+ canDecide: z10.boolean()
1288
1374
  }).strict();
1289
- var scopeReadPlannedSchema = z8.object({
1375
+ var scopeReadPlannedSchema = z10.object({
1290
1376
  phase: scopePhaseSchema,
1291
1377
  state: plannedScopeStateSchema,
1292
- phaseNumber: z8.number().int().min(1),
1378
+ phaseNumber: z10.number().int().min(1),
1293
1379
  planVersion: planVersionSchema,
1294
- parts: z8.array(scopeReadPartSchema).min(1).max(PHASE_PLAN_CHANGES_MAX),
1295
- decisions: z8.array(scopeReadDecisionSchema),
1296
- canDecide: z8.boolean(),
1297
- replanLine: z8.string().min(1).optional()
1380
+ parts: z10.array(scopeReadPartSchema).min(1).max(PHASE_PLAN_CHANGES_MAX),
1381
+ decisions: z10.array(scopeReadDecisionSchema),
1382
+ canDecide: z10.boolean(),
1383
+ replanLine: z10.string().min(1).optional()
1298
1384
  }).strict();
1299
- var scopeReadSchema = z8.union([scopeReadNotPlannedSchema, scopeReadPlannedSchema]);
1385
+ var scopeReadSchema = z10.union([scopeReadNotPlannedSchema, scopeReadPlannedSchema]);
1300
1386
 
1301
- // ../events/dist/crew.js
1302
- import { z as z9 } from "zod";
1303
- var crewGroupSchema = z9.enum(["analyst-architect", "builder", "reviewer", "lead"]);
1304
- var crewTierSchema = z9.enum(["deep", "standard", "fast"]);
1305
- var CREW_DISCIPLINE_MAX = 64;
1306
- var crewFaceHeadSchema = z9.enum(["sq", "sqr", "rnd", "dome", "hex", "gable"]);
1307
- var crewFaceAntennaSchema = z9.enum(["none", "stalk", "twin", "dish"]);
1308
- var crewFaceEyesSchema = z9.enum(["dots", "bars", "visor", "cyclops"]);
1309
- var crewFaceMouthSchema = z9.enum(["line", "grid", "dots", "wave"]);
1310
- var crewFaceSchema = z9.object({
1311
- // The outline of the head. Members who do the same kind of work share one, so a
1312
- // team is recognisable before any name is read.
1313
- head: crewFaceHeadSchema,
1314
- // What sits on top of the head, if anything.
1315
- antenna: crewFaceAntennaSchema,
1316
- // The eyes.
1317
- eyes: crewFaceEyesSchema,
1318
- // The mouth.
1319
- mouth: crewFaceMouthSchema,
1320
- // Whether this member is drawn with ears.
1321
- ears: z9.boolean()
1387
+ // ../events/dist/observed-changes.js
1388
+ import { z as z12 } from "zod";
1389
+
1390
+ // ../events/dist/code-link.js
1391
+ import { z as z11 } from "zod";
1392
+ var codeLinkAddressSchema = z11.string().regex(GITHUB_REPOSITORY_ADDRESS, { message: "must be a GitHub repository address: https://github.com/<owner>/<repo>" }).refine((v) => !looksLikeSecret(v), { message: "looks like a password or key, so it is not sent" });
1393
+ var codeLinkFactsSchema = z11.object({
1394
+ repositoryAddress: codeLinkAddressSchema.nullable(),
1395
+ headOnGitHub: z11.boolean()
1396
+ }).strict().refine((v) => !(v.headOnGitHub && v.repositoryAddress === null), {
1397
+ message: "cannot be true when the code is not on GitHub",
1398
+ path: ["headOnGitHub"]
1399
+ });
1400
+ var PART_CODE_LINK_SCOPES = ["part", "phase"];
1401
+ var PART_CODE_LINK_RANGE_REASONS = ["not-github", "not-pushed"];
1402
+ var PART_CODE_LINK_URL_PREFIX = "https://github.com/";
1403
+ var partCodeLinkGithubSchema = z11.object({
1404
+ kind: z11.literal("github"),
1405
+ scope: z11.enum(PART_CODE_LINK_SCOPES),
1406
+ url: z11.string().startsWith(PART_CODE_LINK_URL_PREFIX, { message: "must start with https://github.com/" })
1322
1407
  }).strict();
1323
- var crewRoleSchema = z9.enum([
1324
- "business-analyst",
1325
- "architect",
1326
- "spec-writer",
1327
- "builder",
1328
- "context-docs",
1329
- "spec-reviewer",
1330
- "code-test-reviewer",
1331
- "delivery-lead",
1332
- "quality-lead"
1408
+ var partCodeLinkRangeSchema = z11.object({
1409
+ kind: z11.literal("range"),
1410
+ why: z11.enum(PART_CODE_LINK_RANGE_REASONS),
1411
+ from: closeCommitSchema,
1412
+ to: closeCommitSchema
1413
+ }).strict();
1414
+ var partCodeLinkNoneSchema = z11.object({
1415
+ kind: z11.literal("none")
1416
+ }).strict();
1417
+ var partCodeLinkSchema = z11.discriminatedUnion("kind", [
1418
+ partCodeLinkGithubSchema,
1419
+ partCodeLinkRangeSchema,
1420
+ partCodeLinkNoneSchema
1333
1421
  ]);
1334
- var crewMemberSchema = z9.object({
1335
- // The agent's name. The same names on every project, so a name is a
1336
- // vocabulary a returning client already knows.
1337
- callsign: z9.string().min(1).max(32),
1338
- // Which of the four teams this member belongs to.
1339
- group: crewGroupSchema,
1340
- // The part this member plays, which decides the stages it leads and helps with.
1341
- role: crewRoleSchema,
1342
- // The kind of work this member takes. A task names a discipline, and only
1343
- // agents holding it can be dispatched to it.
1344
- discipline: z9.string().min(1).max(CREW_DISCIPLINE_MAX),
1345
- // How much thinking this member brings. There is no field naming the supplier
1346
- // behind it, on this shape or on any other.
1347
- tier: crewTierSchema,
1348
- // How this member's face is drawn. The same face on every project, so a
1349
- // returning client recognises a member before reading the name.
1350
- face: crewFaceSchema
1351
- }).strict();
1352
- var CREW_ROSTER = [
1353
- // ── analysts and architects ─────────────────────────────────────────────────
1354
- {
1355
- callsign: "SOFIA",
1356
- group: "analyst-architect",
1357
- role: "business-analyst",
1358
- discipline: "business analyst",
1359
- tier: "deep",
1360
- face: { head: "gable", antenna: "stalk", eyes: "dots", mouth: "wave", ears: false }
1361
- },
1362
- {
1363
- callsign: "BEA",
1364
- group: "analyst-architect",
1365
- role: "business-analyst",
1366
- discipline: "business analyst",
1367
- tier: "standard",
1368
- face: { head: "gable", antenna: "none", eyes: "visor", mouth: "line", ears: false }
1369
- },
1370
- {
1371
- callsign: "WREN",
1372
- group: "analyst-architect",
1373
- role: "architect",
1374
- discipline: "solution architect",
1375
- tier: "deep",
1376
- face: { head: "gable", antenna: "dish", eyes: "bars", mouth: "line", ears: true }
1377
- },
1378
- {
1379
- callsign: "PEI",
1380
- group: "analyst-architect",
1381
- role: "architect",
1382
- discipline: "technical architect",
1383
- tier: "standard",
1384
- face: { head: "gable", antenna: "twin", eyes: "cyclops", mouth: "dots", ears: false }
1385
- },
1386
- // ── builders: code ──────────────────────────────────────────────────────────
1387
- {
1388
- callsign: "ADA",
1389
- group: "builder",
1390
- role: "builder",
1391
- discipline: "implementation",
1392
- tier: "deep",
1393
- face: { head: "sq", antenna: "stalk", eyes: "dots", mouth: "line", ears: false }
1394
- },
1395
- {
1396
- callsign: "OTTO",
1397
- group: "builder",
1398
- role: "builder",
1399
- discipline: "implementation",
1400
- tier: "deep",
1401
- face: { head: "sq", antenna: "twin", eyes: "bars", mouth: "grid", ears: true }
1402
- },
1403
- {
1404
- callsign: "MILO",
1405
- group: "builder",
1406
- role: "builder",
1407
- discipline: "implementation",
1408
- tier: "standard",
1409
- face: { head: "sqr", antenna: "stalk", eyes: "dots", mouth: "dots", ears: false }
1410
- },
1411
- {
1412
- callsign: "NOVA",
1413
- group: "builder",
1414
- role: "builder",
1415
- discipline: "implementation",
1416
- tier: "standard",
1417
- face: { head: "sq", antenna: "dish", eyes: "cyclops", mouth: "line", ears: false }
1418
- },
1419
- {
1420
- callsign: "HUGO",
1421
- group: "builder",
1422
- role: "builder",
1423
- discipline: "infrastructure",
1424
- tier: "standard",
1425
- face: { head: "sq", antenna: "twin", eyes: "dots", mouth: "grid", ears: true }
1426
- },
1427
- // ── builders: specs and docs ────────────────────────────────────────────────
1428
- {
1429
- callsign: "IRIS",
1430
- group: "builder",
1431
- role: "spec-writer",
1432
- discipline: "feature spec",
1433
- tier: "deep",
1434
- face: { head: "dome", antenna: "stalk", eyes: "visor", mouth: "line", ears: false }
1435
- },
1436
- {
1437
- callsign: "JUNO",
1438
- group: "builder",
1439
- role: "spec-writer",
1440
- discipline: "feature spec",
1441
- tier: "standard",
1442
- face: { head: "dome", antenna: "none", eyes: "dots", mouth: "wave", ears: false }
1443
- },
1444
- {
1445
- callsign: "LEX",
1446
- group: "builder",
1447
- role: "context-docs",
1448
- discipline: "context & docs",
1449
- tier: "fast",
1450
- face: { head: "dome", antenna: "twin", eyes: "bars", mouth: "dots", ears: false }
1451
- },
1452
- // ── reviewers ───────────────────────────────────────────────────────────────
1453
- {
1454
- callsign: "VERA",
1455
- group: "reviewer",
1456
- role: "spec-reviewer",
1457
- discipline: "spec consistency",
1458
- tier: "deep",
1459
- face: { head: "rnd", antenna: "stalk", eyes: "visor", mouth: "line", ears: false }
1460
- },
1461
- {
1462
- callsign: "ODIN",
1463
- group: "reviewer",
1464
- role: "spec-reviewer",
1465
- discipline: "cross-spec audit",
1466
- tier: "deep",
1467
- face: { head: "rnd", antenna: "dish", eyes: "cyclops", mouth: "line", ears: false }
1468
- },
1469
- {
1470
- callsign: "CASS",
1471
- group: "reviewer",
1472
- role: "code-test-reviewer",
1473
- discipline: "code review",
1474
- tier: "deep",
1475
- face: { head: "rnd", antenna: "none", eyes: "visor", mouth: "grid", ears: true }
1476
- },
1477
- {
1478
- callsign: "THEO",
1479
- group: "reviewer",
1480
- role: "code-test-reviewer",
1481
- discipline: "code review",
1482
- tier: "standard",
1483
- face: { head: "rnd", antenna: "twin", eyes: "bars", mouth: "line", ears: false }
1484
- },
1485
- {
1486
- callsign: "KAI",
1487
- group: "reviewer",
1488
- role: "code-test-reviewer",
1489
- discipline: "code review",
1490
- tier: "standard",
1491
- face: { head: "rnd", antenna: "none", eyes: "bars", mouth: "line", ears: true }
1492
- },
1493
- {
1494
- callsign: "ECHO",
1495
- group: "reviewer",
1496
- role: "code-test-reviewer",
1497
- discipline: "test quality",
1498
- tier: "standard",
1499
- face: { head: "rnd", antenna: "stalk", eyes: "dots", mouth: "wave", ears: false }
1500
- },
1501
- {
1502
- callsign: "MAVIS",
1503
- group: "reviewer",
1504
- role: "code-test-reviewer",
1505
- discipline: "suites & coverage",
1506
- tier: "standard",
1507
- face: { head: "rnd", antenna: "none", eyes: "visor", mouth: "dots", ears: false }
1508
- },
1509
- {
1510
- callsign: "ZARA",
1511
- group: "reviewer",
1512
- role: "code-test-reviewer",
1513
- discipline: "smoke & walk aid",
1514
- tier: "standard",
1515
- face: { head: "rnd", antenna: "dish", eyes: "bars", mouth: "wave", ears: false }
1516
- },
1517
- {
1518
- callsign: "NORA",
1519
- group: "reviewer",
1520
- role: "code-test-reviewer",
1521
- discipline: "evidence & provenance",
1522
- tier: "fast",
1523
- face: { head: "rnd", antenna: "twin", eyes: "dots", mouth: "line", ears: false }
1524
- },
1525
- // ── leads ───────────────────────────────────────────────────────────────────
1526
- {
1527
- callsign: "ARGUS",
1528
- group: "lead",
1529
- role: "quality-lead",
1530
- discipline: "quality lead \xB7 every diff",
1531
- tier: "standard",
1532
- face: { head: "hex", antenna: "dish", eyes: "visor", mouth: "grid", ears: true }
1533
- },
1534
- {
1535
- callsign: "ATLAS",
1536
- group: "lead",
1537
- role: "delivery-lead",
1538
- discipline: "delivery lead",
1539
- tier: "deep",
1540
- face: { head: "hex", antenna: "twin", eyes: "cyclops", mouth: "line", ears: true }
1541
- }
1542
- ];
1543
- var CREW_ROSTER_SIZE = CREW_ROSTER.length;
1544
- var CREW_CALLSIGNS = CREW_ROSTER.map((member) => member.callsign);
1545
- var crewLayerSchema = methodLayerSchema.extract(["l0", "l1", "l2", "l3", "l4", "l5"]);
1546
- var crewRoleLayersSchema = z9.object({
1547
- leads: z9.array(crewLayerSchema),
1548
- helps: z9.array(crewLayerSchema)
1549
- }).strict();
1550
-
1551
- // ../events/dist/build-record-v3.js
1552
- import { z as z14 } from "zod";
1553
-
1554
- // ../events/dist/board-vocabulary.js
1555
- import { z as z10 } from "zod";
1556
- var boardStepStateSchema = z10.enum([
1557
- "not-instrumented",
1558
- "done",
1559
- "did-not-pass",
1560
- "could-not-complete",
1561
- "not-yet-available",
1562
- "qualified"
1563
- ]);
1564
- var boardGateNameSchema = z10.enum([
1565
- "scope",
1566
- "architecture",
1567
- "specs",
1568
- "taskgraph",
1569
- "phase-close"
1570
- ]);
1571
-
1572
- // ../events/dist/code-link.js
1573
- import { z as z11 } from "zod";
1574
- var codeLinkAddressSchema = z11.string().regex(GITHUB_REPOSITORY_ADDRESS, { message: "must be a GitHub repository address: https://github.com/<owner>/<repo>" }).refine((v) => !looksLikeSecret(v), { message: "looks like a password or key, so it is not sent" });
1575
- var codeLinkFactsSchema = z11.object({
1576
- repositoryAddress: codeLinkAddressSchema.nullable(),
1577
- headOnGitHub: z11.boolean()
1578
- }).strict().refine((v) => !(v.headOnGitHub && v.repositoryAddress === null), {
1579
- message: "cannot be true when the code is not on GitHub",
1580
- path: ["headOnGitHub"]
1581
- });
1582
- var PART_CODE_LINK_SCOPES = ["part", "phase"];
1583
- var PART_CODE_LINK_RANGE_REASONS = ["not-github", "not-pushed"];
1584
- var PART_CODE_LINK_URL_PREFIX = "https://github.com/";
1585
- var partCodeLinkGithubSchema = z11.object({
1586
- kind: z11.literal("github"),
1587
- scope: z11.enum(PART_CODE_LINK_SCOPES),
1588
- url: z11.string().startsWith(PART_CODE_LINK_URL_PREFIX, { message: "must start with https://github.com/" })
1589
- }).strict();
1590
- var partCodeLinkRangeSchema = z11.object({
1591
- kind: z11.literal("range"),
1592
- why: z11.enum(PART_CODE_LINK_RANGE_REASONS),
1593
- from: closeCommitSchema,
1594
- to: closeCommitSchema
1595
- }).strict();
1596
- var partCodeLinkNoneSchema = z11.object({
1597
- kind: z11.literal("none")
1598
- }).strict();
1599
- var partCodeLinkSchema = z11.discriminatedUnion("kind", [
1600
- partCodeLinkGithubSchema,
1601
- partCodeLinkRangeSchema,
1602
- partCodeLinkNoneSchema
1603
- ]);
1604
-
1605
- // ../events/dist/observed-changes.js
1606
- import { z as z12 } from "zod";
1607
- var OBSERVED_PATHS_LISTED_MAX = 50;
1608
- var OBSERVED_PATH_MAX = 300;
1609
- var OBSERVED_COUNT_MAX = 1e6;
1610
- var observedCountSchema = z12.number({ error: `must be a whole number from 0 to ${OBSERVED_COUNT_MAX}` }).int({ error: `must be a whole number from 0 to ${OBSERVED_COUNT_MAX}` }).min(0, { error: `must be a whole number from 0 to ${OBSERVED_COUNT_MAX}` }).max(OBSERVED_COUNT_MAX, { error: `must be a whole number from 0 to ${OBSERVED_COUNT_MAX}` });
1611
- var observedDescriptionVersionSchema = z12.number().int().min(1);
1612
- var observedPathSchema = z12.string().min(1, { message: "must not be empty" }).max(OBSERVED_PATH_MAX, { message: `must be at most ${OBSERVED_PATH_MAX} characters` });
1613
- var observedPathListSchema = z12.array(observedPathSchema).max(OBSERVED_PATHS_LISTED_MAX, { message: `can list at most ${OBSERVED_PATHS_LISTED_MAX} paths` }).refine((paths) => new Set(paths).size === paths.length, { message: "must name each path once" });
1614
- var observedMethodFilesSchema = z12.object({
1615
- added: observedCountSchema,
1616
- changed: observedCountSchema,
1617
- removed: observedCountSchema
1422
+
1423
+ // ../events/dist/observed-changes.js
1424
+ var OBSERVED_PATHS_LISTED_MAX = 50;
1425
+ var OBSERVED_PATH_MAX = 300;
1426
+ var OBSERVED_COUNT_MAX = 1e6;
1427
+ var observedCountSchema = z12.number({ error: `must be a whole number from 0 to ${OBSERVED_COUNT_MAX}` }).int({ error: `must be a whole number from 0 to ${OBSERVED_COUNT_MAX}` }).min(0, { error: `must be a whole number from 0 to ${OBSERVED_COUNT_MAX}` }).max(OBSERVED_COUNT_MAX, { error: `must be a whole number from 0 to ${OBSERVED_COUNT_MAX}` });
1428
+ var observedDescriptionVersionSchema = z12.number().int().min(1);
1429
+ var observedPathSchema = z12.string().min(1, { message: "must not be empty" }).max(OBSERVED_PATH_MAX, { message: `must be at most ${OBSERVED_PATH_MAX} characters` });
1430
+ var observedPathListSchema = z12.array(observedPathSchema).max(OBSERVED_PATHS_LISTED_MAX, { message: `can list at most ${OBSERVED_PATHS_LISTED_MAX} paths` }).refine((paths) => new Set(paths).size === paths.length, { message: "must name each path once" });
1431
+ var observedMethodFilesSchema = z12.object({
1432
+ added: observedCountSchema,
1433
+ changed: observedCountSchema,
1434
+ removed: observedCountSchema
1618
1435
  }).strict();
1619
1436
  var observedFilesSchema = z12.object({
1620
1437
  added: observedCountSchema,
@@ -1737,111 +1554,734 @@ var OBSERVE_NOT_SENT_REASONS = [
1737
1554
  "refused",
1738
1555
  "unreachable"
1739
1556
  ];
1740
- var observeRunRecordedSchema = z12.object({ outcome: z12.literal("recorded") }).strict();
1741
- var observeRunKeptSchema = z12.object({ outcome: z12.literal("kept") }).strict();
1742
- var observeRunNotSentSchema = z12.object({
1743
- outcome: z12.literal("not-sent"),
1744
- reason: z12.enum(OBSERVE_NOT_SENT_REASONS)
1557
+ var observeRunRecordedSchema = z12.object({ outcome: z12.literal("recorded") }).strict();
1558
+ var observeRunKeptSchema = z12.object({ outcome: z12.literal("kept") }).strict();
1559
+ var observeRunNotSentSchema = z12.object({
1560
+ outcome: z12.literal("not-sent"),
1561
+ reason: z12.enum(OBSERVE_NOT_SENT_REASONS)
1562
+ }).strict();
1563
+ var observeRunResultSchema = z12.discriminatedUnion("outcome", [
1564
+ observeRunRecordedSchema,
1565
+ observeRunKeptSchema,
1566
+ observeRunNotSentSchema
1567
+ ]);
1568
+ var observedChecksFiredSchema = z12.array(z12.string().min(1)).refine((names) => names.every((name, i) => i === 0 || names[i - 1] < name), {
1569
+ message: "must be sorted, each name once"
1570
+ });
1571
+ var observedCountingSchema = z12.discriminatedUnion("state", [
1572
+ z12.object({
1573
+ state: z12.literal("counted"),
1574
+ startCommit: closeCommitSchema,
1575
+ startRecordedAt: utcIso8601,
1576
+ headCommit: closeCommitSchema,
1577
+ headCommittedAt: utcIso8601,
1578
+ commits: observedCountSchema,
1579
+ countedAt: utcIso8601
1580
+ }).strict(),
1581
+ z12.object({
1582
+ state: z12.literal("not-counted-yet"),
1583
+ startCommit: closeCommitSchema,
1584
+ startRecordedAt: utcIso8601
1585
+ }).strict(),
1586
+ z12.object({
1587
+ state: z12.literal("cannot-count")
1588
+ }).strict()
1589
+ ]);
1590
+ var observedPartSchema = z12.object({
1591
+ part: systemPartIdSchema,
1592
+ files: observedFilesSchema.nullable(),
1593
+ checksFired: observedChecksFiredSchema
1594
+ }).strict().refine((v) => v.files !== null && filesChanged(v.files) >= 1 || v.checksFired.length >= 1, {
1595
+ message: "a part is listed only when files changed under it or a check fired on one",
1596
+ path: ["files"]
1597
+ });
1598
+ var observedOutsideSchema = z12.object({
1599
+ files: observedFilesSchema.nullable(),
1600
+ paths: observedPathListSchema,
1601
+ checksFired: observedChecksFiredSchema
1602
+ }).strict().refine((v) => pathsFitTheCount(v.files, v.paths), {
1603
+ message: "lists more paths than files changed",
1604
+ path: ["paths"]
1605
+ });
1606
+ var observedChangesSchema = z12.object({
1607
+ phase: phaseNameSchema,
1608
+ counting: observedCountingSchema,
1609
+ descriptionVersion: observedDescriptionVersionSchema.nullable(),
1610
+ parts: z12.array(observedPartSchema).max(SYSTEM_PARTS_MAX),
1611
+ methodFiles: observedMethodFilesSchema.nullable(),
1612
+ outsideEveryPart: observedOutsideSchema,
1613
+ codeLink: codeLinkFactsSchema.nullable()
1614
+ }).strict().superRefine((v, ctx) => {
1615
+ checkPartsUnique(v.parts, ctx, ["parts"]);
1616
+ const counted2 = v.counting.state === "counted";
1617
+ const rule = counted2 ? "must be present when the phase is counted" : "must be null until the phase is counted";
1618
+ if (v.methodFiles !== null !== counted2)
1619
+ ctx.addIssue({ code: "custom", path: ["methodFiles"], message: rule });
1620
+ if (v.outsideEveryPart.files !== null !== counted2) {
1621
+ ctx.addIssue({ code: "custom", path: ["outsideEveryPart", "files"], message: rule });
1622
+ }
1623
+ if (v.codeLink !== null !== counted2)
1624
+ ctx.addIssue({ code: "custom", path: ["codeLink"], message: rule });
1625
+ v.parts.forEach((entry, i) => {
1626
+ if (entry.files !== null !== counted2)
1627
+ ctx.addIssue({ code: "custom", path: ["parts", i, "files"], message: rule });
1628
+ });
1629
+ if (counted2 && v.descriptionVersion === null) {
1630
+ ctx.addIssue({ code: "custom", path: ["descriptionVersion"], message: "must name the version the counts used" });
1631
+ }
1632
+ });
1633
+ var partOutsideThePlanSchema = z12.object({
1634
+ part: systemPartIdSchema,
1635
+ name: systemPartSchema.shape.name,
1636
+ seen: observedFilesSchema.nullable(),
1637
+ tasks: z12.array(observedSaidSchema.extend({ id: buildTaskSchema.shape.id }).strict()).max(BUILD_SNAPSHOT_TASK_LIMIT)
1638
+ }).strict();
1639
+ function shortCommit(commit) {
1640
+ return commit.slice(0, 7);
1641
+ }
1642
+
1643
+ // ../events/dist/work-record.js
1644
+ import { z as z14 } from "zod";
1645
+
1646
+ // ../events/dist/crew-tier.js
1647
+ import { z as z13 } from "zod";
1648
+ var crewTierSchema = z13.enum(["deep", "standard", "fast"]);
1649
+
1650
+ // ../events/dist/work-record.js
1651
+ var agentWorkText = statementText(STATEMENT_MAX);
1652
+ var WORK_FINDINGS_MAX = 100;
1653
+ var WORK_ANSWERS_MAX = 100;
1654
+ var WORK_ATTEMPT_LIMIT = 4;
1655
+ var WORK_CLAIM_CHECKS_MAX = 20;
1656
+ var findingIdSchema = z14.string().regex(/^F[1-9][0-9]?\.[AQ][1-9][0-9]{0,2}$/, { message: "must be a finding id such as F1.A1" });
1657
+ var WORK_STAGES = Object.freeze(["asked", "quality"]);
1658
+ var workStageSchema = z14.enum(WORK_STAGES);
1659
+ var workVerdictSchema = z14.enum(["pass", "fail"]);
1660
+ var WORK_FINDING_KINDS = Object.freeze([
1661
+ "asked",
1662
+ "quality",
1663
+ "unrecorded-call",
1664
+ "undeclared-listed-decision"
1665
+ ]);
1666
+ var workFindingKindSchema = z14.enum(WORK_FINDING_KINDS);
1667
+ var WORK_ASKED_ONLY_FINDING_KINDS = Object.freeze([
1668
+ "unrecorded-call",
1669
+ "undeclared-listed-decision"
1670
+ ]);
1671
+ var workOutcomeSchema = z14.enum(["fixed", "declined", "deferred"]);
1672
+ var DIAGNOSIS_CAUSES = Object.freeze([
1673
+ "spec",
1674
+ "ordering",
1675
+ "approach",
1676
+ "capability",
1677
+ "environment",
1678
+ "review"
1679
+ ]);
1680
+ var diagnosisCauseSchema = z14.enum(DIAGNOSIS_CAUSES);
1681
+ var diagnosisNextSchema = z14.enum(["different-way", "stop", "ask-person"]);
1682
+ var callUndoableSchema = z14.enum(["yes", "no"]);
1683
+ var callKindSchema = z14.enum(["default", "listed"]);
1684
+ var commitShaSchema = closeCommitSchema;
1685
+ var workChangeIdSchema = z14.string().uuid({ message: "must be the change id Halfcycle gave" });
1686
+ var workTaskSubjectSchema = z14.object({
1687
+ kind: z14.literal("task"),
1688
+ phase: buildPhaseSchema,
1689
+ task: buildTaskIdSchema
1690
+ }).strict();
1691
+ var workChangeSubjectSchema = z14.object({
1692
+ kind: z14.literal("change"),
1693
+ change: workChangeIdSchema
1694
+ }).strict();
1695
+ var workPhaseSubjectSchema = z14.object({
1696
+ kind: z14.literal("phase"),
1697
+ phase: buildPhaseSchema
1698
+ }).strict();
1699
+ var workSubjectSchema = z14.discriminatedUnion("kind", [
1700
+ workTaskSubjectSchema,
1701
+ workChangeSubjectSchema,
1702
+ workPhaseSubjectSchema
1703
+ ]);
1704
+ var workItemSubjectSchema = z14.discriminatedUnion("kind", [workTaskSubjectSchema, workChangeSubjectSchema]);
1705
+ var workFindingInputSchema = z14.object({
1706
+ kind: workFindingKindSchema,
1707
+ says: agentWorkText
1708
+ }).strict();
1709
+ var workReviewRecordSchema = z14.object({
1710
+ record: z14.literal("review"),
1711
+ subject: workItemSubjectSchema,
1712
+ stage: workStageSchema,
1713
+ verdict: workVerdictSchema,
1714
+ reviewer: agentNameSchema,
1715
+ builder: agentNameSchema,
1716
+ builderTier: crewTierSchema,
1717
+ head: commitShaSchema,
1718
+ findings: z14.array(workFindingInputSchema).max(WORK_FINDINGS_MAX, { message: `can carry at most ${WORK_FINDINGS_MAX} findings` }),
1719
+ retryReason: agentWorkText.optional(),
1720
+ diagnosis: z14.string().uuid({ message: "must be the diagnosis id Halfcycle gave" }).optional(),
1721
+ followsDiagnosis: z14.boolean().optional()
1722
+ }).strict().refine((r) => r.stage === "asked" || r.findings.every((f) => !WORK_ASKED_ONLY_FINDING_KINDS.includes(f.kind)), {
1723
+ message: "a review for quality cannot raise an unrecorded call or an undeclared listed decision",
1724
+ path: ["findings"]
1725
+ });
1726
+ var workAnswerSchema = z14.object({
1727
+ finding: findingIdSchema,
1728
+ outcome: workOutcomeSchema,
1729
+ reason: agentWorkText.optional()
1730
+ }).strict().refine((a) => a.outcome === "fixed" === (a.reason === void 0), {
1731
+ message: "a reason is given exactly when a finding is declined or deferred",
1732
+ path: ["reason"]
1733
+ });
1734
+ var workOutcomesRecordSchema = z14.object({
1735
+ record: z14.literal("outcomes"),
1736
+ subject: workItemSubjectSchema,
1737
+ by: agentNameSchema,
1738
+ answers: z14.array(workAnswerSchema).min(1, { message: "must answer at least one finding" }).max(WORK_ANSWERS_MAX, { message: `can carry at most ${WORK_ANSWERS_MAX} answers` })
1739
+ }).strict().refine((r) => new Set(r.answers.map((a) => a.finding)).size === r.answers.length, {
1740
+ message: "answers each finding once",
1741
+ path: ["answers"]
1742
+ });
1743
+ var workClaimsRecordSchema = z14.object({
1744
+ record: z14.literal("claims"),
1745
+ subject: workItemSubjectSchema,
1746
+ head: commitShaSchema,
1747
+ by: agentNameSchema,
1748
+ checks: z14.array(z14.object({ label: agentWorkText }).strict()).min(1, { message: "must name at least one check" }).max(WORK_CLAIM_CHECKS_MAX, { message: `can name at most ${WORK_CLAIM_CHECKS_MAX} checks` })
1749
+ }).strict().refine((r) => new Set(r.checks.map((c) => c.label)).size === r.checks.length, {
1750
+ message: "names each check once",
1751
+ path: ["checks"]
1752
+ });
1753
+ var workDiagnosisRecordSchema = z14.object({
1754
+ record: z14.literal("diagnosis"),
1755
+ subject: workItemSubjectSchema,
1756
+ afterAttempt: z14.number().int().min(2, { message: "must be attempt 2 or later" }).max(WORK_ATTEMPT_LIMIT - 1, { message: `must be attempt ${WORK_ATTEMPT_LIMIT - 1} or earlier` }),
1757
+ by: agentNameSchema,
1758
+ cause: diagnosisCauseSchema,
1759
+ says: agentWorkText,
1760
+ next: diagnosisNextSchema,
1761
+ change: agentWorkText.optional(),
1762
+ question: agentWorkText.optional(),
1763
+ answer: agentWorkText.optional()
1764
+ }).strict().refine((r) => r.next === "different-way" === (r.change !== void 0), {
1765
+ message: "says what will change exactly when the next step is to try a different way",
1766
+ path: ["change"]
1767
+ }).refine((r) => r.next === "ask-person" === (r.question !== void 0), {
1768
+ message: "carries a question exactly when the next step is to ask the person",
1769
+ path: ["question"]
1770
+ });
1771
+ var workCallRecordSchema = z14.object({
1772
+ record: z14.literal("call"),
1773
+ subject: workSubjectSchema,
1774
+ by: agentNameSchema,
1775
+ question: agentWorkText,
1776
+ chose: agentWorkText,
1777
+ statedDefault: agentWorkText,
1778
+ undoable: callUndoableSchema,
1779
+ how: agentWorkText.optional()
1780
+ }).strict().refine((r) => r.undoable === "yes" === (r.how !== void 0), {
1781
+ message: "says how to undo it exactly when it can be undone",
1782
+ path: ["how"]
1783
+ });
1784
+ var workRecordSchema = z14.discriminatedUnion("record", [
1785
+ workReviewRecordSchema,
1786
+ workOutcomesRecordSchema,
1787
+ workClaimsRecordSchema,
1788
+ workDiagnosisRecordSchema,
1789
+ workCallRecordSchema
1790
+ ]);
1791
+ var WORK_STANDINGS = Object.freeze([
1792
+ "not-reviewed",
1793
+ "stopped",
1794
+ "held",
1795
+ "needs-diagnosis",
1796
+ "failed",
1797
+ "in-review",
1798
+ "findings-open",
1799
+ "passed"
1800
+ ]);
1801
+ var workStandingSchema = z14.enum(WORK_STANDINGS);
1802
+ var workRecordResultSchema = z14.object({
1803
+ outcome: z14.enum(["recorded", "kept"]),
1804
+ attempt: z14.number().int().min(1).optional(),
1805
+ findings: z14.array(findingIdSchema).max(WORK_FINDINGS_MAX).optional(),
1806
+ diagnosis: z14.string().uuid().optional(),
1807
+ standing: workStandingSchema,
1808
+ says: z14.string().min(1)
1809
+ }).strict();
1810
+ var WORK_REFUSAL_STATUS = Object.freeze({
1811
+ "phase-not-open": 409,
1812
+ "unknown-task": 400,
1813
+ "unknown-change": 404,
1814
+ "change-finished": 409,
1815
+ "out-of-order": 409,
1816
+ "same-agent": 409,
1817
+ "already-recorded": 409,
1818
+ "already-answered": 409,
1819
+ "unknown-finding": 400,
1820
+ "findings-unanswered": 409,
1821
+ "listed-decision-passed": 400,
1822
+ "needs-diagnosis": 409,
1823
+ "no-diagnosis-due": 409,
1824
+ "not-fresh": 409,
1825
+ "graph-unchanged": 409,
1826
+ "no-graph": 400,
1827
+ "wrong-diagnosis": 409,
1828
+ "diagnosis-not-followed": 400,
1829
+ stopped: 409,
1830
+ held: 409,
1831
+ "attempt-limit": 409,
1832
+ "same-attempt": 409,
1833
+ "call-not-recorded": 409
1834
+ });
1835
+ var WORK_REFUSALS = Object.freeze(Object.keys(WORK_REFUSAL_STATUS));
1836
+ var workRefusalSchema = z14.enum(WORK_REFUSALS);
1837
+ var workRefusalErrorSchema = wireErrorSchema.extend({ error: workRefusalSchema }).strict().refine((e) => e.statusCode === WORK_REFUSAL_STATUS[e.error], {
1838
+ message: "carries the status its refusal is answered with",
1839
+ path: ["statusCode"]
1840
+ });
1841
+ var testCommandIdSchema = z14.string().regex(/^[0-9a-f]{16}$/, { message: "must be 16 lower-case hex characters" });
1842
+ var workCountSchema = z14.number().int().min(0);
1843
+ var testRunReportSchema = z14.object({
1844
+ runId: z14.string().uuid(),
1845
+ subject: workItemSubjectSchema,
1846
+ label: agentWorkText,
1847
+ when: z14.enum(["before", "after"]),
1848
+ commandId: testCommandIdSchema,
1849
+ head: commitShaSchema,
1850
+ changedOutsideTests: workCountSchema,
1851
+ uncommitted: workCountSchema,
1852
+ beforeRunId: z14.string().uuid().nullable(),
1853
+ changedSinceBefore: workCountSchema.nullable(),
1854
+ exitCode: z14.number().int().nullable(),
1855
+ timedOut: z14.boolean(),
1856
+ passed: workCountSchema.nullable(),
1857
+ failed: workCountSchema.nullable(),
1858
+ durationMs: workCountSchema,
1859
+ startedAt: utcIso8601,
1860
+ reason: agentWorkText.optional()
1861
+ }).strict().refine((r) => r.passed === null === (r.failed === null), {
1862
+ message: "counts both passed and failed, or neither",
1863
+ path: ["failed"]
1864
+ }).refine((r) => r.when === "after" || r.beforeRunId === null && r.changedSinceBefore === null, {
1865
+ message: "a run before the change is measured against no earlier run",
1866
+ path: ["beforeRunId"]
1867
+ }).refine((r) => !r.timedOut || r.exitCode === null, {
1868
+ message: "a run that timed out has no exit code",
1869
+ path: ["exitCode"]
1870
+ });
1871
+ var testRunResultSchema = z14.object({ outcome: z14.literal("recorded") }).strict();
1872
+ var TEST_PROOF_REASONS = Object.freeze([
1873
+ "no-run-before",
1874
+ "before-after-change",
1875
+ "not-counted",
1876
+ "passed-before",
1877
+ "no-run-after",
1878
+ "command-changed",
1879
+ "not-after-before",
1880
+ "nothing-changed",
1881
+ "failed-after",
1882
+ "after-not-at-claimed-head"
1883
+ ]);
1884
+ var testProofReasonSchema = z14.enum(TEST_PROOF_REASONS);
1885
+ var testProofStateSchema = z14.enum(["proven", "not-proven", "unchecked"]);
1886
+ var testRunCountsSchema = z14.object({
1887
+ passed: workCountSchema.nullable(),
1888
+ failed: workCountSchema.nullable(),
1889
+ durationMs: workCountSchema,
1890
+ timedOut: z14.boolean()
1891
+ }).strict();
1892
+ var workTestSchema = z14.object({
1893
+ label: agentWorkText,
1894
+ state: testProofStateSchema,
1895
+ why: testProofReasonSchema.optional(),
1896
+ claimedBy: agentNameSchema,
1897
+ before: testRunCountsSchema.optional(),
1898
+ after: testRunCountsSchema.optional()
1899
+ }).strict().refine((t) => t.state === "not-proven" === (t.why !== void 0), {
1900
+ message: "gives a reason exactly when a check is not proven",
1901
+ path: ["why"]
1902
+ });
1903
+ var workFindingOutcomeSchema = z14.object({
1904
+ outcome: workOutcomeSchema,
1905
+ reason: agentWorkText.optional(),
1906
+ by: agentNameSchema
1907
+ }).strict().refine((o) => o.outcome === "fixed" === (o.reason === void 0), {
1908
+ message: "a reason is given exactly when a finding is declined or deferred",
1909
+ path: ["reason"]
1910
+ });
1911
+ var workFindingSchema = z14.object({
1912
+ id: findingIdSchema,
1913
+ kind: workFindingKindSchema,
1914
+ says: agentWorkText,
1915
+ outcome: workFindingOutcomeSchema.optional()
1916
+ }).strict();
1917
+ var workStageViewSchema = z14.object({
1918
+ reviewer: agentNameSchema,
1919
+ verdict: workVerdictSchema,
1920
+ findings: z14.array(workFindingSchema).max(WORK_FINDINGS_MAX)
1921
+ }).strict();
1922
+ var workAttemptSchema = z14.object({
1923
+ attempt: z14.number().int().min(1),
1924
+ builder: agentNameSchema,
1925
+ builderTier: crewTierSchema,
1926
+ head: commitShaSchema,
1927
+ retryReason: agentWorkText.optional(),
1928
+ diagnosis: z14.string().uuid().optional(),
1929
+ followsDiagnosis: z14.boolean().optional(),
1930
+ asked: workStageViewSchema.optional(),
1931
+ quality: workStageViewSchema.optional()
1932
+ }).strict();
1933
+ var workDiagnosisSchema = z14.object({
1934
+ id: z14.string().uuid(),
1935
+ afterAttempt: z14.number().int().min(2).max(WORK_ATTEMPT_LIMIT - 1),
1936
+ by: agentNameSchema,
1937
+ cause: diagnosisCauseSchema,
1938
+ says: agentWorkText,
1939
+ next: diagnosisNextSchema,
1940
+ change: agentWorkText.optional(),
1941
+ question: agentWorkText.optional(),
1942
+ answer: agentWorkText.optional()
1943
+ }).strict().refine((d) => d.next === "different-way" === (d.change !== void 0), {
1944
+ message: "says what will change exactly when the next step is to try a different way",
1945
+ path: ["change"]
1946
+ }).refine((d) => d.next === "ask-person" === (d.question !== void 0), {
1947
+ message: "carries a question exactly when the next step is to ask the person",
1948
+ path: ["question"]
1949
+ });
1950
+ var workCallSchema = z14.object({
1951
+ subject: workSubjectSchema,
1952
+ by: agentNameSchema,
1953
+ kind: callKindSchema,
1954
+ question: agentWorkText,
1955
+ chose: agentWorkText,
1956
+ statedDefault: agentWorkText,
1957
+ undoable: callUndoableSchema,
1958
+ how: agentWorkText.nullable(),
1959
+ at: utcIso8601
1960
+ }).strict().superRefine((c, ctx) => checkReadCallHow(c, ctx));
1961
+ function checkReadCallHow(c, ctx) {
1962
+ if (c.undoable === "yes" !== (c.how !== null)) {
1963
+ ctx.addIssue({ code: "custom", path: ["how"], message: "says how to undo it exactly when it can be undone" });
1964
+ }
1965
+ }
1966
+ var workTaskViewSchema = z14.object({
1967
+ task: buildTaskIdSchema,
1968
+ standing: workStandingSchema,
1969
+ attempts: z14.array(workAttemptSchema),
1970
+ diagnoses: z14.array(workDiagnosisSchema),
1971
+ tests: z14.array(workTestSchema)
1972
+ }).strict();
1973
+ var WORK_CLAIM_ACTS = Object.freeze(["accept", "reject"]);
1974
+ var workClaimActSchema = z14.enum(WORK_CLAIM_ACTS);
1975
+ var workClaimAnswerSchema = z14.object({
1976
+ act: workClaimActSchema,
1977
+ note: z14.string().min(1).max(SCOPE_NOTE_MAX).nullable()
1978
+ }).strict().refine((a) => a.act === "reject" === (a.note !== null), {
1979
+ message: "carries the owner's note exactly on a reject",
1980
+ path: ["note"]
1981
+ });
1982
+ var workUncheckedClaimSchema = z14.object({
1983
+ task: buildTaskIdSchema,
1984
+ label: agentWorkText,
1985
+ head: commitShaSchema,
1986
+ claimedBy: agentNameSchema,
1987
+ answer: workClaimAnswerSchema.nullable()
1988
+ }).strict();
1989
+ var phaseWorkSchema = z14.object({
1990
+ phase: buildPhaseSchema,
1991
+ tasks: z14.array(workTaskViewSchema),
1992
+ calls: z14.array(workCallSchema),
1993
+ uncheckedClaims: z14.array(workUncheckedClaimSchema)
1994
+ }).strict();
1995
+
1996
+ // ../events/dist/crew.js
1997
+ import { z as z15 } from "zod";
1998
+ var crewGroupSchema = z15.enum(["analyst-architect", "builder", "reviewer", "lead"]);
1999
+ var CREW_DISCIPLINE_MAX = 64;
2000
+ var crewFaceHeadSchema = z15.enum(["sq", "sqr", "rnd", "dome", "hex", "gable"]);
2001
+ var crewFaceAntennaSchema = z15.enum(["none", "stalk", "twin", "dish"]);
2002
+ var crewFaceEyesSchema = z15.enum(["dots", "bars", "visor", "cyclops"]);
2003
+ var crewFaceMouthSchema = z15.enum(["line", "grid", "dots", "wave"]);
2004
+ var crewFaceSchema = z15.object({
2005
+ // The outline of the head. Members who do the same kind of work share one, so a
2006
+ // team is recognisable before any name is read.
2007
+ head: crewFaceHeadSchema,
2008
+ // What sits on top of the head, if anything.
2009
+ antenna: crewFaceAntennaSchema,
2010
+ // The eyes.
2011
+ eyes: crewFaceEyesSchema,
2012
+ // The mouth.
2013
+ mouth: crewFaceMouthSchema,
2014
+ // Whether this member is drawn with ears.
2015
+ ears: z15.boolean()
2016
+ }).strict();
2017
+ var crewRoleSchema = z15.enum([
2018
+ "business-analyst",
2019
+ "architect",
2020
+ "spec-writer",
2021
+ "builder",
2022
+ "context-docs",
2023
+ "spec-reviewer",
2024
+ "code-test-reviewer",
2025
+ "delivery-lead",
2026
+ "quality-lead"
2027
+ ]);
2028
+ var crewMemberSchema = z15.object({
2029
+ // The agent's name. The same names on every project, so a name is a
2030
+ // vocabulary a returning client already knows.
2031
+ callsign: z15.string().min(1).max(32),
2032
+ // Which of the four teams this member belongs to.
2033
+ group: crewGroupSchema,
2034
+ // The part this member plays, which decides the stages it leads and helps with.
2035
+ role: crewRoleSchema,
2036
+ // The kind of work this member takes. A task names a discipline, and only
2037
+ // agents holding it can be dispatched to it.
2038
+ discipline: z15.string().min(1).max(CREW_DISCIPLINE_MAX),
2039
+ // How much thinking this member brings. There is no field naming the supplier
2040
+ // behind it, on this shape or on any other.
2041
+ tier: crewTierSchema,
2042
+ // How this member's face is drawn. The same face on every project, so a
2043
+ // returning client recognises a member before reading the name.
2044
+ face: crewFaceSchema
2045
+ }).strict();
2046
+ var CREW_ROSTER = [
2047
+ // ── analysts and architects ─────────────────────────────────────────────────
2048
+ {
2049
+ callsign: "SOFIA",
2050
+ group: "analyst-architect",
2051
+ role: "business-analyst",
2052
+ discipline: "business analyst",
2053
+ tier: "deep",
2054
+ face: { head: "gable", antenna: "stalk", eyes: "dots", mouth: "wave", ears: false }
2055
+ },
2056
+ {
2057
+ callsign: "BEA",
2058
+ group: "analyst-architect",
2059
+ role: "business-analyst",
2060
+ discipline: "business analyst",
2061
+ tier: "standard",
2062
+ face: { head: "gable", antenna: "none", eyes: "visor", mouth: "line", ears: false }
2063
+ },
2064
+ {
2065
+ callsign: "WREN",
2066
+ group: "analyst-architect",
2067
+ role: "architect",
2068
+ discipline: "solution architect",
2069
+ tier: "deep",
2070
+ face: { head: "gable", antenna: "dish", eyes: "bars", mouth: "line", ears: true }
2071
+ },
2072
+ {
2073
+ callsign: "PEI",
2074
+ group: "analyst-architect",
2075
+ role: "architect",
2076
+ discipline: "technical architect",
2077
+ tier: "standard",
2078
+ face: { head: "gable", antenna: "twin", eyes: "cyclops", mouth: "dots", ears: false }
2079
+ },
2080
+ // ── builders: code ──────────────────────────────────────────────────────────
2081
+ {
2082
+ callsign: "ADA",
2083
+ group: "builder",
2084
+ role: "builder",
2085
+ discipline: "implementation",
2086
+ tier: "deep",
2087
+ face: { head: "sq", antenna: "stalk", eyes: "dots", mouth: "line", ears: false }
2088
+ },
2089
+ {
2090
+ callsign: "OTTO",
2091
+ group: "builder",
2092
+ role: "builder",
2093
+ discipline: "implementation",
2094
+ tier: "deep",
2095
+ face: { head: "sq", antenna: "twin", eyes: "bars", mouth: "grid", ears: true }
2096
+ },
2097
+ {
2098
+ callsign: "MILO",
2099
+ group: "builder",
2100
+ role: "builder",
2101
+ discipline: "implementation",
2102
+ tier: "standard",
2103
+ face: { head: "sqr", antenna: "stalk", eyes: "dots", mouth: "dots", ears: false }
2104
+ },
2105
+ {
2106
+ callsign: "NOVA",
2107
+ group: "builder",
2108
+ role: "builder",
2109
+ discipline: "implementation",
2110
+ tier: "standard",
2111
+ face: { head: "sq", antenna: "dish", eyes: "cyclops", mouth: "line", ears: false }
2112
+ },
2113
+ {
2114
+ callsign: "HUGO",
2115
+ group: "builder",
2116
+ role: "builder",
2117
+ discipline: "infrastructure",
2118
+ tier: "standard",
2119
+ face: { head: "sq", antenna: "twin", eyes: "dots", mouth: "grid", ears: true }
2120
+ },
2121
+ // ── builders: specs and docs ────────────────────────────────────────────────
2122
+ {
2123
+ callsign: "IRIS",
2124
+ group: "builder",
2125
+ role: "spec-writer",
2126
+ discipline: "feature spec",
2127
+ tier: "deep",
2128
+ face: { head: "dome", antenna: "stalk", eyes: "visor", mouth: "line", ears: false }
2129
+ },
2130
+ {
2131
+ callsign: "JUNO",
2132
+ group: "builder",
2133
+ role: "spec-writer",
2134
+ discipline: "feature spec",
2135
+ tier: "standard",
2136
+ face: { head: "dome", antenna: "none", eyes: "dots", mouth: "wave", ears: false }
2137
+ },
2138
+ {
2139
+ callsign: "LEX",
2140
+ group: "builder",
2141
+ role: "context-docs",
2142
+ discipline: "context & docs",
2143
+ tier: "fast",
2144
+ face: { head: "dome", antenna: "twin", eyes: "bars", mouth: "dots", ears: false }
2145
+ },
2146
+ // ── reviewers ───────────────────────────────────────────────────────────────
2147
+ {
2148
+ callsign: "VERA",
2149
+ group: "reviewer",
2150
+ role: "spec-reviewer",
2151
+ discipline: "spec consistency",
2152
+ tier: "deep",
2153
+ face: { head: "rnd", antenna: "stalk", eyes: "visor", mouth: "line", ears: false }
2154
+ },
2155
+ {
2156
+ callsign: "ODIN",
2157
+ group: "reviewer",
2158
+ role: "spec-reviewer",
2159
+ discipline: "cross-spec audit",
2160
+ tier: "deep",
2161
+ face: { head: "rnd", antenna: "dish", eyes: "cyclops", mouth: "line", ears: false }
2162
+ },
2163
+ {
2164
+ callsign: "CASS",
2165
+ group: "reviewer",
2166
+ role: "code-test-reviewer",
2167
+ discipline: "code review",
2168
+ tier: "deep",
2169
+ face: { head: "rnd", antenna: "none", eyes: "visor", mouth: "grid", ears: true }
2170
+ },
2171
+ {
2172
+ callsign: "THEO",
2173
+ group: "reviewer",
2174
+ role: "code-test-reviewer",
2175
+ discipline: "code review",
2176
+ tier: "standard",
2177
+ face: { head: "rnd", antenna: "twin", eyes: "bars", mouth: "line", ears: false }
2178
+ },
2179
+ {
2180
+ callsign: "KAI",
2181
+ group: "reviewer",
2182
+ role: "code-test-reviewer",
2183
+ discipline: "code review",
2184
+ tier: "standard",
2185
+ face: { head: "rnd", antenna: "none", eyes: "bars", mouth: "line", ears: true }
2186
+ },
2187
+ {
2188
+ callsign: "ECHO",
2189
+ group: "reviewer",
2190
+ role: "code-test-reviewer",
2191
+ discipline: "test quality",
2192
+ tier: "standard",
2193
+ face: { head: "rnd", antenna: "stalk", eyes: "dots", mouth: "wave", ears: false }
2194
+ },
2195
+ {
2196
+ callsign: "MAVIS",
2197
+ group: "reviewer",
2198
+ role: "code-test-reviewer",
2199
+ discipline: "suites & coverage",
2200
+ tier: "standard",
2201
+ face: { head: "rnd", antenna: "none", eyes: "visor", mouth: "dots", ears: false }
2202
+ },
2203
+ {
2204
+ callsign: "ZARA",
2205
+ group: "reviewer",
2206
+ role: "code-test-reviewer",
2207
+ discipline: "smoke & walk aid",
2208
+ tier: "standard",
2209
+ face: { head: "rnd", antenna: "dish", eyes: "bars", mouth: "wave", ears: false }
2210
+ },
2211
+ {
2212
+ callsign: "NORA",
2213
+ group: "reviewer",
2214
+ role: "code-test-reviewer",
2215
+ discipline: "evidence & provenance",
2216
+ tier: "fast",
2217
+ face: { head: "rnd", antenna: "twin", eyes: "dots", mouth: "line", ears: false }
2218
+ },
2219
+ // ── leads ───────────────────────────────────────────────────────────────────
2220
+ {
2221
+ callsign: "ARGUS",
2222
+ group: "lead",
2223
+ role: "quality-lead",
2224
+ discipline: "quality lead \xB7 every diff",
2225
+ tier: "standard",
2226
+ face: { head: "hex", antenna: "dish", eyes: "visor", mouth: "grid", ears: true }
2227
+ },
2228
+ {
2229
+ callsign: "ATLAS",
2230
+ group: "lead",
2231
+ role: "delivery-lead",
2232
+ discipline: "delivery lead",
2233
+ tier: "deep",
2234
+ face: { head: "hex", antenna: "twin", eyes: "cyclops", mouth: "line", ears: true }
2235
+ }
2236
+ ];
2237
+ var CREW_ROSTER_SIZE = CREW_ROSTER.length;
2238
+ var CREW_CALLSIGNS = CREW_ROSTER.map((member) => member.callsign);
2239
+ var crewLayerSchema = methodLayerSchema.extract(["l0", "l1", "l2", "l3", "l4", "l5"]);
2240
+ var crewRoleLayersSchema = z15.object({
2241
+ leads: z15.array(crewLayerSchema),
2242
+ helps: z15.array(crewLayerSchema)
1745
2243
  }).strict();
1746
- var observeRunResultSchema = z12.discriminatedUnion("outcome", [
1747
- observeRunRecordedSchema,
1748
- observeRunKeptSchema,
1749
- observeRunNotSentSchema
2244
+
2245
+ // ../events/dist/build-record-v3.js
2246
+ import { z as z18 } from "zod";
2247
+
2248
+ // ../events/dist/board-vocabulary.js
2249
+ import { z as z16 } from "zod";
2250
+ var boardStepStateSchema = z16.enum([
2251
+ "not-instrumented",
2252
+ "done",
2253
+ "did-not-pass",
2254
+ "could-not-complete",
2255
+ "not-yet-available",
2256
+ "qualified"
1750
2257
  ]);
1751
- var observedChecksFiredSchema = z12.array(z12.string().min(1)).refine((names) => names.every((name, i) => i === 0 || names[i - 1] < name), {
1752
- message: "must be sorted, each name once"
1753
- });
1754
- var observedCountingSchema = z12.discriminatedUnion("state", [
1755
- z12.object({
1756
- state: z12.literal("counted"),
1757
- startCommit: closeCommitSchema,
1758
- startRecordedAt: utcIso8601,
1759
- headCommit: closeCommitSchema,
1760
- headCommittedAt: utcIso8601,
1761
- commits: observedCountSchema,
1762
- countedAt: utcIso8601
1763
- }).strict(),
1764
- z12.object({
1765
- state: z12.literal("not-counted-yet"),
1766
- startCommit: closeCommitSchema,
1767
- startRecordedAt: utcIso8601
1768
- }).strict(),
1769
- z12.object({
1770
- state: z12.literal("cannot-count")
1771
- }).strict()
2258
+ var boardGateNameSchema = z16.enum([
2259
+ "scope",
2260
+ "architecture",
2261
+ "specs",
2262
+ "taskgraph",
2263
+ "phase-close"
1772
2264
  ]);
1773
- var observedPartSchema = z12.object({
1774
- part: systemPartIdSchema,
1775
- files: observedFilesSchema.nullable(),
1776
- checksFired: observedChecksFiredSchema
1777
- }).strict().refine((v) => v.files !== null && filesChanged(v.files) >= 1 || v.checksFired.length >= 1, {
1778
- message: "a part is listed only when files changed under it or a check fired on one",
1779
- path: ["files"]
1780
- });
1781
- var observedOutsideSchema = z12.object({
1782
- files: observedFilesSchema.nullable(),
1783
- paths: observedPathListSchema,
1784
- checksFired: observedChecksFiredSchema
1785
- }).strict().refine((v) => pathsFitTheCount(v.files, v.paths), {
1786
- message: "lists more paths than files changed",
1787
- path: ["paths"]
1788
- });
1789
- var observedChangesSchema = z12.object({
1790
- phase: phaseNameSchema,
1791
- counting: observedCountingSchema,
1792
- descriptionVersion: observedDescriptionVersionSchema.nullable(),
1793
- parts: z12.array(observedPartSchema).max(SYSTEM_PARTS_MAX),
1794
- methodFiles: observedMethodFilesSchema.nullable(),
1795
- outsideEveryPart: observedOutsideSchema,
1796
- codeLink: codeLinkFactsSchema.nullable()
1797
- }).strict().superRefine((v, ctx) => {
1798
- checkPartsUnique(v.parts, ctx, ["parts"]);
1799
- const counted2 = v.counting.state === "counted";
1800
- const rule = counted2 ? "must be present when the phase is counted" : "must be null until the phase is counted";
1801
- if (v.methodFiles !== null !== counted2)
1802
- ctx.addIssue({ code: "custom", path: ["methodFiles"], message: rule });
1803
- if (v.outsideEveryPart.files !== null !== counted2) {
1804
- ctx.addIssue({ code: "custom", path: ["outsideEveryPart", "files"], message: rule });
1805
- }
1806
- if (v.codeLink !== null !== counted2)
1807
- ctx.addIssue({ code: "custom", path: ["codeLink"], message: rule });
1808
- v.parts.forEach((entry, i) => {
1809
- if (entry.files !== null !== counted2)
1810
- ctx.addIssue({ code: "custom", path: ["parts", i, "files"], message: rule });
1811
- });
1812
- if (counted2 && v.descriptionVersion === null) {
1813
- ctx.addIssue({ code: "custom", path: ["descriptionVersion"], message: "must name the version the counts used" });
1814
- }
1815
- });
1816
- var partOutsideThePlanSchema = z12.object({
1817
- part: systemPartIdSchema,
1818
- name: systemPartSchema.shape.name,
1819
- seen: observedFilesSchema.nullable(),
1820
- tasks: z12.array(observedSaidSchema.extend({ id: buildTaskSchema.shape.id }).strict()).max(BUILD_SNAPSHOT_TASK_LIMIT)
1821
- }).strict();
1822
- function shortCommit(commit) {
1823
- return commit.slice(0, 7);
1824
- }
1825
2265
 
1826
2266
  // ../events/dist/phase-review.js
1827
- import { z as z13 } from "zod";
2267
+ import { z as z17 } from "zod";
1828
2268
  var BUILT_PART_ACTS = Object.freeze(["accept", "question", "send-back"]);
1829
2269
  var NOT_BUILT_PART_ACTS = Object.freeze(["carry", "drop"]);
1830
2270
  var REVIEW_ACTS = Object.freeze([...BUILT_PART_ACTS, ...NOT_BUILT_PART_ACTS]);
1831
- var reviewActSchema = z13.enum(REVIEW_ACTS);
2271
+ var reviewActSchema = z17.enum(REVIEW_ACTS);
1832
2272
  function reviewActsFor(built) {
1833
2273
  return built ? BUILT_PART_ACTS : NOT_BUILT_PART_ACTS;
1834
2274
  }
1835
2275
  var REVIEW_NOTE_MAX = SCOPE_NOTE_MAX;
1836
- var reviewNoteWireSchema = z13.string().max(REVIEW_NOTE_MAX);
1837
- var reviewNoteSchema = z13.string().min(1).max(REVIEW_NOTE_MAX);
2276
+ var reviewNoteWireSchema = z17.string().max(REVIEW_NOTE_MAX);
2277
+ var reviewNoteSchema = z17.string().min(1).max(REVIEW_NOTE_MAX);
1838
2278
  var REVIEW_ANSWER_MAX = 1e3;
1839
- var reviewAgentAnswerSchema = z13.string().min(1).max(REVIEW_ANSWER_MAX);
2279
+ var reviewAgentAnswerSchema = z17.string().min(1).max(REVIEW_ANSWER_MAX);
1840
2280
  var REVIEW_PARTS_MAX = PHASE_PLAN_CHANGES_MAX * 2;
1841
2281
  var REVIEW_PART_CHANGES = Object.freeze([...PHASE_PLAN_CHANGE_KINDS, "not-in-plan"]);
1842
- var reviewPartChangeSchema = z13.enum(REVIEW_PART_CHANGES);
2282
+ var reviewPartChangeSchema = z17.enum(REVIEW_PART_CHANGES);
1843
2283
  var REVIEW_DECISIONS = Object.freeze(["accepted", "carried", "dropped"]);
1844
- var reviewDecisionSchema = z13.enum(REVIEW_DECISIONS);
2284
+ var reviewDecisionSchema = z17.enum(REVIEW_DECISIONS);
1845
2285
  function actOf(decision) {
1846
2286
  if (decision === "accepted")
1847
2287
  return "accept";
@@ -1853,10 +2293,10 @@ var reviewCarriedToSchema = carriedPhaseSchema.nullable();
1853
2293
  var reviewStepNameSchema = stepNameSchema.refine((v) => !stepIdSchema.safeParse(v.trim()).success, {
1854
2294
  message: "must be the step's plain name"
1855
2295
  });
1856
- var reviewStepSchema = z13.object({
2296
+ var reviewStepSchema = z17.object({
1857
2297
  name: reviewStepNameSchema.nullable(),
1858
2298
  state: unfinishedStepSchema.shape.state,
1859
- judged: z13.boolean()
2299
+ judged: z17.boolean()
1860
2300
  }).strict();
1861
2301
  function codeLinkLine(link) {
1862
2302
  switch (link.kind) {
@@ -1873,41 +2313,41 @@ function codeLinkLine(link) {
1873
2313
  function assertNever(value) {
1874
2314
  throw new Error(`unexpected value: ${JSON.stringify(value)}`);
1875
2315
  }
1876
- var openReviewRequestSchema = z13.object({
2316
+ var openReviewRequestSchema = z17.object({
1877
2317
  actor: closeActorSchema,
1878
2318
  acceptanceOutcome: acceptanceOutcomeSchema,
1879
2319
  statements: closeStatementsSchema
1880
2320
  }).strict();
1881
2321
  var REVIEW_OPEN_TASKS_SHOWN_MAX = 10;
1882
- var reviewOpenedSchema = z13.object({
1883
- outcome: z13.literal("opened"),
1884
- round: z13.number().int().min(1),
1885
- parts: z13.number().int().min(0).max(REVIEW_PARTS_MAX),
1886
- notBuilt: z13.number().int().min(0).max(REVIEW_PARTS_MAX),
1887
- counted: z13.boolean(),
1888
- typedReviewOffered: z13.boolean()
2322
+ var reviewOpenedSchema = z17.object({
2323
+ outcome: z17.literal("opened"),
2324
+ round: z17.number().int().min(1),
2325
+ parts: z17.number().int().min(0).max(REVIEW_PARTS_MAX),
2326
+ notBuilt: z17.number().int().min(0).max(REVIEW_PARTS_MAX),
2327
+ counted: z17.boolean(),
2328
+ typedReviewOffered: z17.boolean()
1889
2329
  }).strict().refine((v) => v.notBuilt <= v.parts, { message: "cannot exceed the parts in the round", path: ["notBuilt"] });
1890
- var reviewTasksOpenSchema = z13.object({
1891
- outcome: z13.literal("tasks-open"),
1892
- open: z13.array(buildTaskSchema.shape.title).min(1).max(REVIEW_OPEN_TASKS_SHOWN_MAX),
1893
- more: z13.number().int().min(0).max(BUILD_SNAPSHOT_TASK_LIMIT)
2330
+ var reviewTasksOpenSchema = z17.object({
2331
+ outcome: z17.literal("tasks-open"),
2332
+ open: z17.array(buildTaskSchema.shape.title).min(1).max(REVIEW_OPEN_TASKS_SHOWN_MAX),
2333
+ more: z17.number().int().min(0).max(BUILD_SNAPSHOT_TASK_LIMIT)
1894
2334
  }).strict();
1895
- var reviewOutstandingSchema = z13.object({
1896
- outcome: z13.literal("outstanding"),
1897
- steps: z13.array(reviewStepSchema).min(1)
2335
+ var reviewOutstandingSchema = z17.object({
2336
+ outcome: z17.literal("outstanding"),
2337
+ steps: z17.array(reviewStepSchema).min(1)
1898
2338
  }).strict();
1899
- var reviewCleanOverFindingsSchema = z13.object({
1900
- outcome: z13.literal("clean-over-findings"),
1901
- findings: z13.number().int().min(1)
2339
+ var reviewCleanOverFindingsSchema = z17.object({
2340
+ outcome: z17.literal("clean-over-findings"),
2341
+ findings: z17.number().int().min(1)
1902
2342
  }).strict();
1903
- var reviewRefusedSchema = z13.object({
1904
- outcome: z13.literal("refused"),
1905
- problems: z13.array(systemDescriptionProblemSchema).min(1)
2343
+ var reviewRefusedSchema = z17.object({
2344
+ outcome: z17.literal("refused"),
2345
+ problems: z17.array(systemDescriptionProblemSchema).min(1)
1906
2346
  }).strict();
1907
2347
  function bareReviewOutcome(outcome) {
1908
- return z13.object({ outcome: z13.literal(outcome) }).strict();
2348
+ return z17.object({ outcome: z17.literal(outcome) }).strict();
1909
2349
  }
1910
- var openReviewResultSchema = z13.discriminatedUnion("outcome", [
2350
+ var openReviewResultSchema = z17.discriminatedUnion("outcome", [
1911
2351
  reviewOpenedSchema,
1912
2352
  reviewTasksOpenSchema,
1913
2353
  bareReviewOutcome("no-build"),
@@ -1917,23 +2357,33 @@ var openReviewResultSchema = z13.discriminatedUnion("outcome", [
1917
2357
  reviewRefusedSchema,
1918
2358
  bareReviewOutcome("unavailable")
1919
2359
  ]);
1920
- var reviewPhaseNotOpenSchema = z13.object({
1921
- statusCode: z13.literal(409),
1922
- error: z13.literal("PhaseNotOpen"),
1923
- message: z13.string().min(1),
1924
- openPhase: z13.string().nullable()
2360
+ var reviewPhaseNotOpenSchema = z17.object({
2361
+ statusCode: z17.literal(409),
2362
+ error: z17.literal("PhaseNotOpen"),
2363
+ message: z17.string().min(1),
2364
+ openPhase: z17.string().nullable()
1925
2365
  }).strict();
1926
- var openReviewAnswerSchema = z13.union([openReviewResultSchema, reviewPhaseNotOpenSchema]);
1927
- var reviewDecisionEntrySchema = z13.object({
2366
+ var openReviewAnswerSchema = z17.union([openReviewResultSchema, reviewPhaseNotOpenSchema]);
2367
+ var reviewDecisionEntrySchema = z17.object({
1928
2368
  part: systemPartIdSchema,
1929
2369
  act: reviewActSchema,
1930
2370
  note: reviewNoteWireSchema.optional()
1931
2371
  }).strict();
1932
- var reviewDecisionRequestSchema = z13.object({
1933
- reviewVersion: z13.number().int().min(0),
1934
- decisions: z13.array(reviewDecisionEntrySchema).max(REVIEW_PARTS_MAX)
2372
+ var reviewClaimActSchema = workClaimActSchema;
2373
+ var REVIEW_CLAIMS_MAX = BUILD_SNAPSHOT_TASK_LIMIT * WORK_CLAIM_CHECKS_MAX;
2374
+ var reviewClaimAnswerSchema = z17.object({
2375
+ task: buildTaskIdSchema,
2376
+ label: agentWorkText,
2377
+ head: commitShaSchema,
2378
+ act: reviewClaimActSchema,
2379
+ note: reviewNoteWireSchema.optional()
2380
+ }).strict();
2381
+ var reviewDecisionRequestSchema = z17.object({
2382
+ reviewVersion: z17.number().int().min(0),
2383
+ decisions: z17.array(reviewDecisionEntrySchema).max(REVIEW_PARTS_MAX),
2384
+ claims: z17.array(reviewClaimAnswerSchema).max(REVIEW_CLAIMS_MAX)
1935
2385
  }).strict();
1936
- var reviewDecidedSchema = z13.object({
2386
+ var reviewDecidedSchema = z17.object({
1937
2387
  part: systemPartIdSchema,
1938
2388
  name: systemPartSchema.shape.name,
1939
2389
  act: reviewActSchema,
@@ -1942,39 +2392,51 @@ var reviewDecidedSchema = z13.object({
1942
2392
  message: "is present exactly on a carry",
1943
2393
  path: ["carriedTo"]
1944
2394
  });
1945
- var reviewRecordedSchema = z13.object({
1946
- outcome: z13.literal("recorded"),
1947
- decided: z13.array(reviewDecidedSchema).max(REVIEW_PARTS_MAX),
1948
- waiting: z13.number().int().min(0).max(REVIEW_PARTS_MAX),
1949
- closed: z13.boolean(),
1950
- reviewVersion: z13.number().int().min(1)
2395
+ var reviewRecordedSchema = z17.object({
2396
+ outcome: z17.literal("recorded"),
2397
+ decided: z17.array(reviewDecidedSchema).max(REVIEW_PARTS_MAX),
2398
+ waiting: z17.number().int().min(0).max(REVIEW_PARTS_MAX),
2399
+ closed: z17.boolean(),
2400
+ reviewVersion: z17.number().int().min(1)
1951
2401
  }).strict().superRefine((v, ctx) => {
1952
2402
  if (v.closed && v.waiting !== 0) {
1953
2403
  ctx.addIssue({ code: "custom", path: ["waiting"], message: "must be 0 once the phase is closed" });
1954
2404
  }
1955
- if (v.decided.length === 0 && !v.closed) {
1956
- ctx.addIssue({ code: "custom", path: ["decided"], message: "may be empty only when the phase closed" });
1957
- }
1958
2405
  });
1959
2406
  var REVIEW_NOT_DECIDABLE_WHY = Object.freeze(["settled", "question-waiting", "sent-back"]);
1960
- var reviewNotDecidablePartSchema = z13.object({
2407
+ var reviewNotDecidablePartSchema = z17.object({
1961
2408
  part: systemPartIdSchema,
1962
2409
  name: systemPartSchema.shape.name,
1963
- why: z13.enum(REVIEW_NOT_DECIDABLE_WHY)
2410
+ why: z17.enum(REVIEW_NOT_DECIDABLE_WHY)
2411
+ }).strict();
2412
+ var REVIEW_CLAIM_NOT_DECIDABLE_WHY = Object.freeze(["not-unchecked", "answered", "claim-changed"]);
2413
+ var reviewClaimNotDecidableWhySchema = z17.enum(REVIEW_CLAIM_NOT_DECIDABLE_WHY);
2414
+ var reviewNotDecidableClaimSchema = z17.object({
2415
+ task: buildTaskIdSchema,
2416
+ label: agentWorkText,
2417
+ why: reviewClaimNotDecidableWhySchema
1964
2418
  }).strict();
1965
- var reviewNotDecidableSchema = z13.object({
1966
- outcome: z13.literal("not-decidable"),
1967
- parts: z13.array(reviewNotDecidablePartSchema).min(1).max(REVIEW_PARTS_MAX)
2419
+ var reviewNotDecidableSchema = z17.object({
2420
+ outcome: z17.literal("not-decidable"),
2421
+ parts: z17.array(reviewNotDecidablePartSchema).max(REVIEW_PARTS_MAX),
2422
+ claims: z17.array(reviewNotDecidableClaimSchema).max(REVIEW_CLAIMS_MAX)
2423
+ }).strict().refine((v) => v.parts.length + v.claims.length > 0, {
2424
+ message: "names at least one part or claim",
2425
+ path: ["parts"]
2426
+ });
2427
+ var reviewPartsNotDecidableSchema = z17.object({
2428
+ outcome: z17.literal("not-decidable"),
2429
+ parts: z17.array(reviewNotDecidablePartSchema).min(1).max(REVIEW_PARTS_MAX)
1968
2430
  }).strict();
1969
- var reviewCloseRefusedSchema = z13.object({
1970
- outcome: z13.literal("close-refused"),
1971
- steps: z13.array(reviewStepSchema)
2431
+ var reviewCloseRefusedSchema = z17.object({
2432
+ outcome: z17.literal("close-refused"),
2433
+ steps: z17.array(reviewStepSchema)
1972
2434
  }).strict();
1973
- var reviewWalkChangedSchema = z13.object({
1974
- outcome: z13.literal("walk-changed"),
1975
- findings: z13.number().int().min(1)
2435
+ var reviewWalkChangedSchema = z17.object({
2436
+ outcome: z17.literal("walk-changed"),
2437
+ findings: z17.number().int().min(1)
1976
2438
  }).strict();
1977
- var reviewDecisionResultSchema = z13.discriminatedUnion("outcome", [
2439
+ var reviewDecisionResultSchema = z17.discriminatedUnion("outcome", [
1978
2440
  reviewRecordedSchema,
1979
2441
  bareReviewOutcome("review-changed"),
1980
2442
  bareReviewOutcome("no-review"),
@@ -1986,33 +2448,33 @@ var reviewDecisionResultSchema = z13.discriminatedUnion("outcome", [
1986
2448
  reviewRefusedSchema,
1987
2449
  bareReviewOutcome("unavailable")
1988
2450
  ]);
1989
- var reviewSentBackSchema = z13.object({
1990
- round: z13.number().int().min(1),
2451
+ var reviewSentBackSchema = z17.object({
2452
+ round: z17.number().int().min(1),
1991
2453
  note: reviewNoteSchema
1992
2454
  }).strict();
1993
- var reviewQuestionSchema = z13.object({
2455
+ var reviewQuestionSchema = z17.object({
1994
2456
  question: reviewNoteSchema,
1995
2457
  agentAnswer: reviewAgentAnswerSchema.optional()
1996
2458
  }).strict();
1997
- var reviewTaskSchema = z13.object({
2459
+ var reviewTaskSchema = z17.object({
1998
2460
  title: buildTaskSchema.shape.title,
1999
2461
  state: buildTaskStateSchema
2000
2462
  }).strict();
2001
- var reviewViewPartSchema = z13.object({
2463
+ var reviewViewPartSchema = z17.object({
2002
2464
  part: systemPartIdSchema,
2003
2465
  name: systemPartSchema.shape.name,
2004
2466
  change: reviewPartChangeSchema,
2005
- built: z13.boolean(),
2006
- builtWithoutApproval: z13.boolean(),
2007
- decidable: z13.boolean(),
2008
- waiting: z13.boolean(),
2467
+ built: z17.boolean(),
2468
+ builtWithoutApproval: z17.boolean(),
2469
+ decidable: z17.boolean(),
2470
+ waiting: z17.boolean(),
2009
2471
  decision: reviewDecisionSchema.optional(),
2010
2472
  reason: reviewNoteSchema.optional(),
2011
2473
  carriedTo: reviewCarriedToSchema.optional(),
2012
- sentBack: z13.array(reviewSentBackSchema),
2013
- questions: z13.array(reviewQuestionSchema),
2014
- tasks: z13.array(reviewTaskSchema).max(BUILD_SNAPSHOT_TASK_LIMIT),
2015
- said: z13.array(observedSaidSchema).max(BUILD_SNAPSHOT_TASK_LIMIT),
2474
+ sentBack: z17.array(reviewSentBackSchema),
2475
+ questions: z17.array(reviewQuestionSchema),
2476
+ tasks: z17.array(reviewTaskSchema).max(BUILD_SNAPSHOT_TASK_LIMIT),
2477
+ said: z17.array(observedSaidSchema).max(BUILD_SNAPSHOT_TASK_LIMIT),
2016
2478
  codeLink: partCodeLinkSchema
2017
2479
  }).strict().superRefine((v, ctx) => {
2018
2480
  if (v.waiting !== (v.decision === void 0)) {
@@ -2035,29 +2497,29 @@ var reviewViewPartSchema = z13.object({
2035
2497
  ctx.addIssue({ code: "custom", path: ["built"], message: "is always true for a part outside the plan" });
2036
2498
  }
2037
2499
  });
2038
- var reviewPhaseNumberSchema = z13.number().int().min(1).nullable();
2039
- var phaseReviewNoneSchema = z13.object({
2040
- state: z13.literal("none"),
2500
+ var reviewPhaseNumberSchema = z17.number().int().min(1).nullable();
2501
+ var phaseReviewNoneSchema = z17.object({
2502
+ state: z17.literal("none"),
2041
2503
  phase: scopePhaseSchema,
2042
2504
  number: reviewPhaseNumberSchema,
2043
- closedWithoutReview: z13.boolean()
2505
+ closedWithoutReview: z17.boolean()
2044
2506
  }).strict();
2045
- var reviewWalkSchema = z13.object({
2507
+ var reviewWalkSchema = z17.object({
2046
2508
  verdict: walkVerdictSchema,
2047
- findings: z13.number().int().min(0)
2509
+ findings: z17.number().int().min(0)
2048
2510
  }).strict();
2049
2511
  function reviewedViewSchema(state) {
2050
- return z13.object({
2051
- state: z13.literal(state),
2512
+ return z17.object({
2513
+ state: z17.literal(state),
2052
2514
  phase: scopePhaseSchema,
2053
2515
  number: reviewPhaseNumberSchema,
2054
- cycle: z13.number().int().min(0),
2055
- round: z13.number().int().min(1),
2056
- reviewVersion: z13.number().int().min(1),
2057
- typedReviewOffered: z13.boolean(),
2058
- counted: z13.boolean(),
2516
+ cycle: z17.number().int().min(0),
2517
+ round: z17.number().int().min(1),
2518
+ reviewVersion: z17.number().int().min(1),
2519
+ typedReviewOffered: z17.boolean(),
2520
+ counted: z17.boolean(),
2059
2521
  walk: reviewWalkSchema,
2060
- parts: z13.array(reviewViewPartSchema).max(REVIEW_PARTS_MAX),
2522
+ parts: z17.array(reviewViewPartSchema).max(REVIEW_PARTS_MAX),
2061
2523
  observed: observedChangesSchema.nullable(),
2062
2524
  description: systemDescriptionSchema
2063
2525
  }).strict().superRefine((v, ctx) => {
@@ -2085,7 +2547,7 @@ function reviewedViewSchema(state) {
2085
2547
  }
2086
2548
  var phaseReviewOpenSchema = reviewedViewSchema("open");
2087
2549
  var phaseReviewClosedSchema = reviewedViewSchema("closed");
2088
- var phaseReviewViewSchema = z13.discriminatedUnion("state", [
2550
+ var phaseReviewViewSchema = z17.discriminatedUnion("state", [
2089
2551
  phaseReviewNoneSchema,
2090
2552
  phaseReviewOpenSchema,
2091
2553
  phaseReviewClosedSchema
@@ -2093,45 +2555,45 @@ var phaseReviewViewSchema = z13.discriminatedUnion("state", [
2093
2555
 
2094
2556
  // ../events/dist/build-record-v3.js
2095
2557
  var BUILD_RECORD_V3_FORMAT = "halfcycle-build-record/v3";
2096
- var recordRoundStatedSchema = z14.object({
2558
+ var recordRoundStatedSchema = z18.object({
2097
2559
  actor: attestedCloseSchema.shape.actor,
2098
2560
  statements: attestedStatementsSchema
2099
2561
  }).strict();
2100
- var recordReviewRoundSchema = z14.object({
2101
- round: z14.number().int().min(1),
2562
+ var recordReviewRoundSchema = z18.object({
2563
+ round: z18.number().int().min(1),
2102
2564
  openedAt: utcIso8601,
2103
2565
  verdict: walkVerdictSchema,
2104
- findings: z14.number().int().min(0),
2566
+ findings: z18.number().int().min(0),
2105
2567
  stated: recordRoundStatedSchema.optional()
2106
2568
  }).strict();
2107
- var recordReviewApprovalSchema = z14.discriminatedUnion("kind", [
2108
- z14.object({
2109
- kind: z14.literal("approved"),
2569
+ var recordReviewApprovalSchema = z18.discriminatedUnion("kind", [
2570
+ z18.object({
2571
+ kind: z18.literal("approved"),
2110
2572
  planVersion: planVersionSchema,
2111
2573
  givenIn: scopeGivenInSchema,
2112
2574
  approvedAt: utcIso8601
2113
2575
  }).strict(),
2114
- z14.object({ kind: z14.literal("none") }).strict()
2576
+ z18.object({ kind: z18.literal("none") }).strict()
2115
2577
  ]);
2116
- var recordReviewGateSchema = z14.object({
2578
+ var recordReviewGateSchema = z18.object({
2117
2579
  gate: boardGateNameSchema,
2118
2580
  state: boardStepStateSchema
2119
2581
  }).strict();
2120
- var recordReviewQuestionSchema = z14.object({
2582
+ var recordReviewQuestionSchema = z18.object({
2121
2583
  question: reviewNoteSchema,
2122
2584
  agentAnswer: reviewAgentAnswerSchema
2123
2585
  }).strict();
2124
- var recordReviewPartSchema = z14.object({
2586
+ var recordReviewPartSchema = z18.object({
2125
2587
  part: systemPartIdSchema,
2126
2588
  name: systemPartSchema.shape.name,
2127
2589
  change: reviewPartChangeSchema,
2128
- built: z14.boolean(),
2129
- builtWithoutApproval: z14.boolean(),
2590
+ built: z18.boolean(),
2591
+ builtWithoutApproval: z18.boolean(),
2130
2592
  decision: reviewDecisionSchema,
2131
2593
  reason: reviewNoteSchema.optional(),
2132
2594
  carriedTo: reviewCarriedToSchema.optional(),
2133
- sentBack: z14.array(reviewSentBackSchema),
2134
- questions: z14.array(recordReviewQuestionSchema),
2595
+ sentBack: z18.array(reviewSentBackSchema),
2596
+ questions: z18.array(recordReviewQuestionSchema),
2135
2597
  codeLink: partCodeLinkSchema
2136
2598
  }).strict().superRefine((v, ctx) => {
2137
2599
  const carriedOrDropped = v.decision === "carried" || v.decision === "dropped";
@@ -2143,23 +2605,24 @@ var recordReviewPartSchema = z14.object({
2143
2605
  }
2144
2606
  });
2145
2607
  var SPINE_ORDER = boardGateNameSchema.options;
2146
- var recordReviewGatesSchema = z14.array(recordReviewGateSchema).superRefine((gates, ctx) => {
2608
+ var recordReviewGatesSchema = z18.array(recordReviewGateSchema).superRefine((gates, ctx) => {
2147
2609
  const inOrder = gates.length === SPINE_ORDER.length && gates.every((g, i) => g.gate === SPINE_ORDER[i]);
2148
2610
  if (!inOrder) {
2149
2611
  ctx.addIssue({ code: "custom", message: `must be exactly the five checkpoints in order: ${SPINE_ORDER.join(", ")}` });
2150
2612
  }
2151
2613
  });
2152
- var recordReviewSchema = z14.object({
2153
- sequence: z14.number().int().min(1),
2154
- cycle: z14.number().int().min(0),
2155
- rounds: z14.array(recordReviewRoundSchema).min(1),
2614
+ var recordReviewSchema = z18.object({
2615
+ sequence: z18.number().int().min(1),
2616
+ cycle: z18.number().int().min(0),
2617
+ rounds: z18.array(recordReviewRoundSchema).min(1),
2156
2618
  approval: recordReviewApprovalSchema,
2157
2619
  planVersion: planVersionSchema.nullable(),
2158
2620
  descriptionVersion: observedDescriptionVersionSchema,
2159
2621
  gates: recordReviewGatesSchema,
2160
2622
  observed: observedChangesSchema.nullable(),
2161
- parts: z14.array(recordReviewPartSchema).max(REVIEW_PARTS_MAX)
2162
- }).strict().superRefine((v, ctx) => {
2623
+ parts: z18.array(recordReviewPartSchema).max(REVIEW_PARTS_MAX)
2624
+ }).strict().superRefine((v, ctx) => checkRecordReview(v, ctx));
2625
+ function checkRecordReview(v, ctx) {
2163
2626
  v.rounds.forEach((r, i) => {
2164
2627
  if (r.round !== i + 1) {
2165
2628
  ctx.addIssue({ code: "custom", path: ["rounds", i, "round"], message: "rounds must be numbered 1, 2, 3 \u2026 in order with no gap" });
@@ -2177,12 +2640,13 @@ var recordReviewSchema = z14.object({
2177
2640
  ctx.addIssue({ code: "custom", path: ["parts", i, "codeLink"], message: "must be none when nothing was observed" });
2178
2641
  }
2179
2642
  });
2180
- });
2181
- var buildRecordV3Schema = z14.object({
2643
+ }
2644
+ var buildRecordV3Schema = z18.object({
2182
2645
  ...buildRecordV2Schema.shape,
2183
- format: z14.literal(BUILD_RECORD_V3_FORMAT),
2646
+ format: z18.literal(BUILD_RECORD_V3_FORMAT),
2184
2647
  review: recordReviewSchema
2185
- }).strict().superRefine((record2, ctx) => {
2648
+ }).strict().superRefine((record2, ctx) => checkReviewedRecord(record2, ctx));
2649
+ function checkReviewedRecord(record2, ctx) {
2186
2650
  checkRecordHalves(record2, ctx);
2187
2651
  const closes = record2.observed.closes;
2188
2652
  const newest = closes[closes.length - 1].sequence;
@@ -2208,24 +2672,11 @@ var buildRecordV3Schema = z14.object({
2208
2672
  if (record2.review.observed !== null && record2.review.observed.phase !== record2.phase) {
2209
2673
  ctx.addIssue({ code: "custom", path: ["review", "observed", "phase"], message: "must be this record's phase" });
2210
2674
  }
2211
- });
2212
- var buildRecordSchema = z14.discriminatedUnion("format", [buildRecordV2Schema, buildRecordV3Schema]);
2213
- function removalsOf(record2) {
2214
- if (record2.format !== BUILD_RECORD_V3_FORMAT)
2215
- return [];
2216
- const out = [];
2217
- for (const p of record2.review.parts) {
2218
- if (p.change === "add" && p.decision === "dropped")
2219
- out.push({ part: p.part, name: p.name, act: "dropped" });
2220
- else if (p.change === "remove" && p.decision === "accepted")
2221
- out.push({ part: p.part, name: p.name, act: "removed" });
2222
- }
2223
- return out;
2224
2675
  }
2225
2676
 
2226
2677
  // ../events/dist/device-auth.js
2227
- import { z as z15 } from "zod";
2228
- var utcIso86012 = z15.string().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/, "must be a UTC ISO-8601 timestamp ending in Z");
2678
+ import { z as z19 } from "zod";
2679
+ var utcIso86012 = z19.string().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/, "must be a UTC ISO-8601 timestamp ending in Z");
2229
2680
  var DEVICE_AUTH_STATUS = {
2230
2681
  /** The poll: minted, nobody has acted yet. Keep polling. 200. */
2231
2682
  PENDING: "pending",
@@ -2266,25 +2717,25 @@ var DEVICE_POLL_REFUSALS = [
2266
2717
  DEVICE_AUTH_STATUS.EXPIRED,
2267
2718
  DEVICE_AUTH_STATUS.UNKNOWN
2268
2719
  ];
2269
- var deviceAuthStartResponseSchema = z15.object({
2270
- deviceCode: z15.string().min(1),
2271
- userCode: z15.string().min(1),
2272
- verificationUrl: z15.string().min(1),
2720
+ var deviceAuthStartResponseSchema = z19.object({
2721
+ deviceCode: z19.string().min(1),
2722
+ userCode: z19.string().min(1),
2723
+ verificationUrl: z19.string().min(1),
2273
2724
  expiresAt: utcIso86012,
2274
- pollIntervalMs: z15.number().int().positive()
2725
+ pollIntervalMs: z19.number().int().positive()
2275
2726
  }).strict();
2276
- var devicePollPendingSchema = z15.object({
2277
- status: z15.literal(DEVICE_AUTH_STATUS.PENDING),
2278
- pollIntervalMs: z15.number().int().positive()
2727
+ var devicePollPendingSchema = z19.object({
2728
+ status: z19.literal(DEVICE_AUTH_STATUS.PENDING),
2729
+ pollIntervalMs: z19.number().int().positive()
2279
2730
  }).strict();
2280
- var devicePollApprovedSchema = z15.object({
2281
- status: z15.literal(DEVICE_AUTH_STATUS.APPROVED),
2282
- accountId: z15.string().min(1),
2283
- credential: z15.string().min(1),
2731
+ var devicePollApprovedSchema = z19.object({
2732
+ status: z19.literal(DEVICE_AUTH_STATUS.APPROVED),
2733
+ accountId: z19.string().min(1),
2734
+ credential: z19.string().min(1),
2284
2735
  expiresAt: utcIso86012
2285
2736
  }).strict();
2286
- var deviceAuthRefusalSchema = z15.object({
2287
- status: z15.enum([
2737
+ var deviceAuthRefusalSchema = z19.object({
2738
+ status: z19.enum([
2288
2739
  DEVICE_AUTH_STATUS.DECLINED,
2289
2740
  DEVICE_AUTH_STATUS.EXPIRED,
2290
2741
  DEVICE_AUTH_STATUS.UNKNOWN,
@@ -2295,25 +2746,25 @@ var deviceAuthRefusalSchema = z15.object({
2295
2746
  DEVICE_AUTH_STATUS.ALREADY_DECIDED,
2296
2747
  DEVICE_AUTH_STATUS.TERMS_REQUIRED
2297
2748
  ]),
2298
- message: z15.string().min(1)
2749
+ message: z19.string().min(1)
2299
2750
  }).strict();
2300
- var devicePollResponseSchema = z15.union([
2751
+ var devicePollResponseSchema = z19.union([
2301
2752
  devicePollPendingSchema,
2302
2753
  devicePollApprovedSchema,
2303
2754
  deviceAuthRefusalSchema
2304
2755
  ]);
2305
- var deviceConfirmRequestSchema = z15.object({
2306
- userCode: z15.string().min(1),
2307
- decision: z15.enum(["approve", "decline"]),
2308
- externalAuthId: z15.string().min(1).optional(),
2309
- email: z15.string().optional(),
2310
- acceptTerms: z15.boolean().optional()
2756
+ var deviceConfirmRequestSchema = z19.object({
2757
+ userCode: z19.string().min(1),
2758
+ decision: z19.enum(["approve", "decline"]),
2759
+ externalAuthId: z19.string().min(1).optional(),
2760
+ email: z19.string().optional(),
2761
+ acceptTerms: z19.boolean().optional()
2311
2762
  }).strict();
2312
- var deviceConfirmRecordedSchema = z15.object({
2313
- status: z15.literal(DEVICE_AUTH_STATUS.RECORDED),
2314
- accountId: z15.string().min(1).optional()
2763
+ var deviceConfirmRecordedSchema = z19.object({
2764
+ status: z19.literal(DEVICE_AUTH_STATUS.RECORDED),
2765
+ accountId: z19.string().min(1).optional()
2315
2766
  }).strict();
2316
- var deviceConfirmResponseSchema = z15.union([
2767
+ var deviceConfirmResponseSchema = z19.union([
2317
2768
  deviceConfirmRecordedSchema,
2318
2769
  deviceAuthRefusalSchema
2319
2770
  ]);
@@ -2325,20 +2776,20 @@ function projectPageUrl(engagementId) {
2325
2776
  }
2326
2777
 
2327
2778
  // ../events/dist/credential-wire.js
2328
- import { z as z16 } from "zod";
2329
- var engagementCredentialResponseSchema = z16.object({
2330
- engagementId: z16.string(),
2331
- sessionToken: z16.string(),
2332
- mcpUrl: z16.string(),
2333
- guardUrl: z16.string(),
2334
- controlTelemetryUrl: z16.string(),
2335
- methodVersion: z16.string().optional(),
2336
- consoleUrl: z16.string().optional()
2779
+ import { z as z20 } from "zod";
2780
+ var engagementCredentialResponseSchema = z20.object({
2781
+ engagementId: z20.string(),
2782
+ sessionToken: z20.string(),
2783
+ mcpUrl: z20.string(),
2784
+ guardUrl: z20.string(),
2785
+ controlTelemetryUrl: z20.string(),
2786
+ methodVersion: z20.string().optional(),
2787
+ consoleUrl: z20.string().optional()
2337
2788
  }).strict();
2338
- var ciTokenExchangeResponseSchema = z16.object({
2339
- token: z16.string(),
2789
+ var ciTokenExchangeResponseSchema = z20.object({
2790
+ token: z20.string(),
2340
2791
  expiresAt: utcIso8601,
2341
- engagementId: z16.string()
2792
+ engagementId: z20.string()
2342
2793
  }).strict();
2343
2794
  var NO_CREDENTIAL_PLACEHOLDER = "halfcycle:no-credential";
2344
2795
  var NOT_THIS_ACCOUNT_PLACEHOLDER = "halfcycle:not-this-account";
@@ -2355,42 +2806,118 @@ var PLACEHOLDER_SENTENCES = Object.freeze({
2355
2806
  });
2356
2807
 
2357
2808
  // ../events/dist/phase-record.js
2358
- import { z as z17 } from "zod";
2359
- var phaseRecordRefusalReasonSchema = z17.enum([
2809
+ import { z as z22 } from "zod";
2810
+
2811
+ // ../events/dist/build-record-v4.js
2812
+ import { z as z21 } from "zod";
2813
+ var BUILD_RECORD_V4_FORMAT = "halfcycle-build-record/v4";
2814
+ var recordReviewClaimSchema = z21.object({
2815
+ ...reviewClaimAnswerSchema.shape,
2816
+ note: reviewNoteSchema.nullable()
2817
+ }).strict().superRefine((c, ctx) => {
2818
+ if (c.act === "accept" !== (c.note === null)) {
2819
+ ctx.addIssue({ code: "custom", path: ["note"], message: "carries the owner's note exactly on a reject" });
2820
+ }
2821
+ });
2822
+ var recordCallSchema = z21.object(workCallSchema.shape).omit({ at: true }).strict().superRefine((c, ctx) => checkReadCallHow(c, ctx));
2823
+ var recordReviewV4Schema = z21.object({
2824
+ ...recordReviewSchema.shape,
2825
+ claims: z21.array(recordReviewClaimSchema).max(REVIEW_CLAIMS_MAX),
2826
+ calls: z21.array(recordCallSchema)
2827
+ }).strict().superRefine((v, ctx) => checkRecordReview(v, ctx));
2828
+ var buildRecordV4Schema = z21.object({
2829
+ ...buildRecordV3Schema.shape,
2830
+ format: z21.literal(BUILD_RECORD_V4_FORMAT),
2831
+ path: phasePathSchema,
2832
+ review: recordReviewV4Schema
2833
+ }).strict().superRefine((record2, ctx) => checkReviewedRecord(record2, ctx));
2834
+ var buildRecordSchema = z21.discriminatedUnion("format", [
2835
+ buildRecordV2Schema,
2836
+ buildRecordV3Schema,
2837
+ buildRecordV4Schema
2838
+ ]);
2839
+ var OWNER_REVIEW_FORMATS = Object.freeze([BUILD_RECORD_V3_FORMAT, BUILD_RECORD_V4_FORMAT]);
2840
+ function hasOwnerReview(record2) {
2841
+ return OWNER_REVIEW_FORMATS.includes(record2.format);
2842
+ }
2843
+ function keptClaimsOf(record2) {
2844
+ return record2.format === BUILD_RECORD_V4_FORMAT ? record2.review.claims : null;
2845
+ }
2846
+ function keptCallsOf(record2) {
2847
+ return record2.format === BUILD_RECORD_V4_FORMAT ? record2.review.calls : null;
2848
+ }
2849
+ function keptPathOf(record2) {
2850
+ return record2.format === BUILD_RECORD_V4_FORMAT ? record2.path : null;
2851
+ }
2852
+ function removalsOf(record2) {
2853
+ if (!hasOwnerReview(record2))
2854
+ return [];
2855
+ const out = [];
2856
+ for (const p of record2.review.parts) {
2857
+ if (p.change === "add" && p.decision === "dropped")
2858
+ out.push({ part: p.part, name: p.name, act: "dropped" });
2859
+ else if (p.change === "remove" && p.decision === "accepted")
2860
+ out.push({ part: p.part, name: p.name, act: "removed" });
2861
+ }
2862
+ return out;
2863
+ }
2864
+
2865
+ // ../events/dist/phase-record.js
2866
+ var phaseRecordRefusalReasonSchema = z22.enum([
2360
2867
  "still-open",
2361
2868
  "reopened",
2362
2869
  "never-opened",
2363
2870
  "never-closed",
2364
2871
  "closed-before-records"
2365
2872
  ]);
2366
- var phaseRecordRecordSchema = z17.object({
2367
- outcome: z17.literal("record"),
2873
+ var phaseRecordRecordSchema = z22.object({
2874
+ outcome: z22.literal("record"),
2368
2875
  phase: phaseNameSchema,
2369
2876
  record: buildRecordSchema
2370
2877
  }).strict().refine((body) => body.record.phase === body.phase, {
2371
2878
  message: "the record is for a different phase than the one asked for",
2372
2879
  path: ["record", "phase"]
2373
2880
  });
2374
- var phaseRecordWithheldSchema = z17.object({
2375
- outcome: z17.literal("withheld"),
2881
+ var phaseRecordWithheldSchema = z22.object({
2882
+ outcome: z22.literal("withheld"),
2376
2883
  phase: phaseNameSchema,
2377
- sequence: z17.number().int().min(1),
2884
+ sequence: z22.number().int().min(1),
2378
2885
  closedAt: utcIso8601,
2379
- message: z17.string()
2886
+ message: z22.string()
2380
2887
  }).strict();
2381
2888
  var phaseRecordRefusedSchema = wireErrorSchema.extend({
2382
- outcome: z17.literal("refused"),
2889
+ outcome: z22.literal("refused"),
2383
2890
  phase: phaseNameSchema,
2384
- statusCode: z17.literal(409),
2385
- error: z17.literal("PhaseRecordRefused"),
2891
+ statusCode: z22.literal(409),
2892
+ error: z22.literal("PhaseRecordRefused"),
2386
2893
  reason: phaseRecordRefusalReasonSchema
2387
2894
  }).strict();
2388
- var phaseRecordResponseSchema = z17.discriminatedUnion("outcome", [
2895
+ var phaseRecordResponseSchema = z22.discriminatedUnion("outcome", [
2389
2896
  phaseRecordRecordSchema,
2390
2897
  phaseRecordWithheldSchema,
2391
2898
  phaseRecordRefusedSchema
2392
2899
  ]);
2393
2900
 
2901
+ // ../events/dist/work-words.js
2902
+ var CALLS_HEADING = "Calls made without asking you";
2903
+ var CALLS_EXPLAINED = "These are the decisions the agents recorded taking on their own, each against a stated default. Halfcycle lists what they recorded; it cannot see a call an agent did not record.";
2904
+ function callMadeLine(call) {
2905
+ return `${call.by} decided "${call.question}": chose "${call.chose}". The stated default was "${call.statedDefault}".`;
2906
+ }
2907
+ function callUndoLine(call) {
2908
+ return call.undoable === "yes" ? `${call.by} says this can be undone: "${call.how ?? ""}"` : `${call.by} says this cannot be undone.`;
2909
+ }
2910
+ var NO_CALLS_LINE = "No agent recorded a call made without asking in this phase.";
2911
+ var UNCHECKED_CLAIMS_HEADING = "Checks nobody ran";
2912
+ function claimSaidLine(claim) {
2913
+ return `Task ${claim.task}: an agent said "${claim.label}" passes at commit ${claim.head}, and Halfcycle never ran it.`;
2914
+ }
2915
+ function recordedClaimLine(claim) {
2916
+ const said = claimSaidLine(claim);
2917
+ return claim.act === "accept" ? `${said} Accepted by the project's owner.` : `${said} Rejected by the project's owner: "${claim.note ?? ""}"`;
2918
+ }
2919
+ var NO_UNCHECKED_CLAIMS_LINE = "No agent said a check passes that Halfcycle never ran.";
2920
+
2394
2921
  // dist/engagement-credential.js
2395
2922
  import { chmodSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2396
2923
  import { platform as platform2 } from "node:os";
@@ -2860,8 +3387,12 @@ function parseManifest(text) {
2860
3387
  "eventsCreated",
2861
3388
  "hooksCreated",
2862
3389
  "permissionsCreated",
2863
- "denyCreated"
3390
+ "denyCreated",
3391
+ "statusLineSha256"
2864
3392
  ], '"settings"');
3393
+ if (s["statusLineSha256"] !== void 0 && (typeof s["statusLineSha256"] !== "string" || !HEX64.test(s["statusLineSha256"]))) {
3394
+ throw new UnreadableManifestError('"settings.statusLineSha256" is not a hash');
3395
+ }
2865
3396
  const settings = {
2866
3397
  created: bool(s["created"], "settings.created"),
2867
3398
  adopted: bool(s["adopted"], "settings.adopted"),
@@ -2871,7 +3402,8 @@ function parseManifest(text) {
2871
3402
  eventsCreated: stringArray(s["eventsCreated"], "settings.eventsCreated"),
2872
3403
  hooksCreated: bool(s["hooksCreated"], "settings.hooksCreated"),
2873
3404
  permissionsCreated: bool(s["permissionsCreated"], "settings.permissionsCreated"),
2874
- denyCreated: bool(s["denyCreated"], "settings.denyCreated")
3405
+ denyCreated: bool(s["denyCreated"], "settings.denyCreated"),
3406
+ ...typeof s["statusLineSha256"] === "string" ? { statusLineSha256: s["statusLineSha256"] } : {}
2875
3407
  };
2876
3408
  let mcp;
2877
3409
  if (raw["mcp"] !== void 0) {
@@ -2949,6 +3481,7 @@ function recordSettings(draft, observed) {
2949
3481
  draft.settings = observed;
2950
3482
  return;
2951
3483
  }
3484
+ const statusLineSha256 = observed.statusLineSha256 ?? prev.statusLineSha256;
2952
3485
  draft.settings = {
2953
3486
  created: prev.created,
2954
3487
  adopted: prev.adopted,
@@ -2958,7 +3491,8 @@ function recordSettings(draft, observed) {
2958
3491
  eventsCreated: union(prev.eventsCreated, observed.eventsCreated),
2959
3492
  hooksCreated: prev.hooksCreated,
2960
3493
  permissionsCreated: prev.permissionsCreated,
2961
- denyCreated: prev.denyCreated
3494
+ denyCreated: prev.denyCreated,
3495
+ ...statusLineSha256 !== void 0 ? { statusLineSha256 } : {}
2962
3496
  };
2963
3497
  }
2964
3498
  function recordDenyRetired(draft, hashes) {
@@ -3052,7 +3586,7 @@ function withoutHalfcycleCommands(entry, halfcycleCommands) {
3052
3586
  const remaining = entry.hooks.filter((h) => !isHalfcycleCommand(h, halfcycleCommands));
3053
3587
  return remaining.length > 0 ? { ...entry, hooks: remaining } : null;
3054
3588
  }
3055
- function mergeSettings(existing, generated, retiredOurs) {
3589
+ function mergeSettings(existing, generated, retiredOurs, statusLine) {
3056
3590
  const merged = { ...existing };
3057
3591
  if (generated.$schema !== void 0) {
3058
3592
  merged.$schema = generated.$schema;
@@ -3075,6 +3609,9 @@ function mergeSettings(existing, generated, retiredOurs) {
3075
3609
  }
3076
3610
  merged.hooks = mergedHooks;
3077
3611
  merged.permissions = mergePermissions(existing.permissions, generated.permissions, retiredOurs);
3612
+ if (statusLine !== void 0 && !("statusLine" in existing)) {
3613
+ merged.statusLine = { ...statusLine };
3614
+ }
3078
3615
  return merged;
3079
3616
  }
3080
3617
  function mergePermissions(existing, generated, retiredOurs) {
@@ -3284,7 +3821,8 @@ function closedWriteSet() {
3284
3821
  GITATTRIBUTES_HEADER,
3285
3822
  ...lfRules([...Object.keys(OWNED_GENERATED_HEADERS), ...RETIRED_WRITE_SET_FILES])
3286
3823
  ]),
3287
- generatedSha256: sha256OfWhatThisVersionWrites(commands)
3824
+ generatedSha256: sha256OfWhatThisVersionWrites(commands),
3825
+ statusLineSha256: /* @__PURE__ */ new Set([canonicalSha256(HALFCYCLE_STATUS_LINE)])
3288
3826
  };
3289
3827
  }
3290
3828
  function sha256OfWhatThisVersionWrites(commands) {
@@ -3319,7 +3857,7 @@ function noteFile(draft, targetRepo, rel, outcome) {
3319
3857
  }
3320
3858
  recordInstalledFile(draft, rel, readFileSync4(join5(targetRepo, rel)));
3321
3859
  }
3322
- function recordSettingsMerge(draft, existing, generated, preexisted) {
3860
+ function recordSettingsMerge(draft, existing, generated, preexisted, merged) {
3323
3861
  const generatedHooks = generated.hooks ?? {};
3324
3862
  const hookCommands = Object.values(generatedHooks).flatMap((entries) => entries.flatMap((entry) => entry.hooks.map((h) => h.command)));
3325
3863
  const ours = /* @__PURE__ */ new Set([...hookCommands, ...HALFCYCLE_HOOK_COMMANDS]);
@@ -3336,9 +3874,16 @@ function recordSettingsMerge(draft, existing, generated, preexisted) {
3336
3874
  eventsCreated: Object.keys(generatedHooks).filter((event) => !(existingHooks && event in existingHooks)),
3337
3875
  hooksCreated: existing.hooks === void 0,
3338
3876
  permissionsCreated: existing.permissions === void 0,
3339
- denyCreated: existing.permissions?.deny === void 0
3877
+ denyCreated: existing.permissions?.deny === void 0,
3878
+ ...ourStatusLineSha256(merged) !== void 0 ? { statusLineSha256: ourStatusLineSha256(merged) } : {}
3340
3879
  });
3341
3880
  }
3881
+ function ourStatusLineSha256(settings) {
3882
+ if (!("statusLine" in settings))
3883
+ return void 0;
3884
+ const hash = canonicalSha256(settings["statusLine"]);
3885
+ return hash === canonicalSha256(HALFCYCLE_STATUS_LINE) ? hash : void 0;
3886
+ }
3342
3887
  function recordMcpMerge(draft, existingText, writtenText) {
3343
3888
  const before = existingText === null ? void 0 : JSON.parse(existingText);
3344
3889
  const servers = isPlainObject(before) ? before["mcpServers"] : void 0;
@@ -3589,6 +4134,29 @@ function settingsParseRefusal(targetRepo, err) {
3589
4134
  return `${file} could not be read as JSON${where} \u2014 fix it and run "npx halfcycle" again.`;
3590
4135
  }
3591
4136
  var SETTINGS_SCHEMA = "https://json.schemastore.org/claude-code-settings.json";
4137
+ var HALFCYCLE_STATUS_LINE = Object.freeze({
4138
+ type: "command",
4139
+ command: 'bash "$CLAUDE_PROJECT_DIR"/.claude/hooks/guard-runner.sh statusline'
4140
+ });
4141
+ function statusLineSetElsewhere(targetRepo, home = homedir2(), env = process.env) {
4142
+ const places = [join5(targetRepo, ".claude", "settings.local.json"), join5(home, ".claude", "settings.json")];
4143
+ const configDir = env["CLAUDE_CONFIG_DIR"];
4144
+ if (configDir !== void 0 && configDir !== "") {
4145
+ const expanded = configDir === "~" ? home : configDir.startsWith("~/") ? join5(home, configDir.slice(2)) : configDir;
4146
+ places.push(join5(isAbsolute2(expanded) ? expanded : resolve(expanded), "settings.json"));
4147
+ }
4148
+ return places.some((path) => {
4149
+ if (!existsSync3(path))
4150
+ return false;
4151
+ let value;
4152
+ try {
4153
+ value = JSON.parse(readFileSync4(path, "utf-8"));
4154
+ } catch {
4155
+ return true;
4156
+ }
4157
+ return !isPlainObject(value) || "statusLine" in value;
4158
+ });
4159
+ }
3592
4160
  function generateSettingsJson() {
3593
4161
  const hooks = {};
3594
4162
  for (const { event, matcher, timeout, command } of HALFCYCLE_HOOK_WIRING) {
@@ -4050,7 +4618,7 @@ function generateMcpRegistration(existing, mcpOrigin) {
4050
4618
  };
4051
4619
  return JSON.stringify(base, null, 2) + "\n";
4052
4620
  }
4053
- var REQUIRED_GITIGNORE_ENTRIES = [".halfcycle/state.json", `${ZONE_B_DIR}/`];
4621
+ var REQUIRED_GITIGNORE_ENTRIES = [".halfcycle/state.json", `${ZONE_B_DIR}/`, ".claude/worktrees/"];
4054
4622
  var GITIGNORE_HEADER = "# Halfcycle \u2014 machine-local secrets/state and Zone-B (never push to client remote)";
4055
4623
  function adoptBlockUnderHeader(before, header, claimable) {
4056
4624
  const claimed = [];
@@ -4323,9 +4891,10 @@ async function install(options) {
4323
4891
  throw new SettingsParseRefused(settingsParseRefusal(targetRepo, err));
4324
4892
  }
4325
4893
  const retiredOurs = retiredRulesThisInstallAdded(draft.previous);
4326
- recordSettingsMerge(draft, existingSettings, generatedSettings, settingsPreexisted);
4894
+ const statusLine = statusLineSetElsewhere(targetRepo, home, options.env) ? void 0 : HALFCYCLE_STATUS_LINE;
4895
+ const mergedSettings = mergeSettings(existingSettings, generatedSettings, retiredOurs, statusLine);
4896
+ recordSettingsMerge(draft, existingSettings, generatedSettings, settingsPreexisted, mergedSettings);
4327
4897
  recordDenyRetired(draft, retiredOurs.map((rule) => sha256Hex(rule)));
4328
- const mergedSettings = mergeSettings(existingSettings, generatedSettings, retiredOurs);
4329
4898
  const mergedSettingsText = inLineEndingOf(readFileOrNull(settingsPath), JSON.stringify(mergedSettings, null, 2) + "\n");
4330
4899
  mkdirSync4(dirname3(settingsPath), { recursive: true });
4331
4900
  writeFileSync4(settingsPath, mergedSettingsText, "utf-8");
@@ -5248,6 +5817,10 @@ var HEADER_CHECKS = "Halfcycle's checks are automatic rules drawn from the ways
5248
5817
  var HEADER_KEPT = "Halfcycle derived this record and kept a copy of it when the phase closed. It changes that copy afterwards in one way only. If an account that closed this phase is later deleted, its email is removed, and so is the name given at any close Halfcycle recorded as made by that account. The client's Halfcycle command-line tool wrote this file from the kept copy, when the phase closed or when the record was fetched again. So a later deletion reaches this file the next time the record is fetched. The same record, as data, is in the .json file of the same name beside this one. If the phase is closed again, this file is replaced by a new record that describes every close, this one included.";
5249
5818
  var HEADER_HIDDEN = "Some text in this record contains characters that do not print. Each is shown as U+ and its code of four or more hex digits; the .json file holds the text exactly.";
5250
5819
  var OBSERVED_LABEL = "**Observed by Halfcycle**";
5820
+ var PATH_LINE = Object.freeze({
5821
+ mini: "Path: mini phase",
5822
+ full: "Path: full phase"
5823
+ });
5251
5824
  var STATED_LABEL = "**Stated by the client** \u2014 Halfcycle did not check these.";
5252
5825
  var MISMATCHED_HALVES = "This Build Record could not be written: its two parts describe different closes.";
5253
5826
  function renderChecks(checks, p) {
@@ -5495,6 +6068,30 @@ function renderReview(record2, p) {
5495
6068
  blocks.push(removals);
5496
6069
  return blocks;
5497
6070
  }
6071
+ function renderCalls(calls, p) {
6072
+ if (calls.length === 0)
6073
+ return [`## ${CALLS_HEADING}`, NO_CALLS_LINE];
6074
+ const lines = calls.flatMap((c) => {
6075
+ const by = p.itemStart(c.by);
6076
+ return [
6077
+ `- ${callMadeLine({ by, question: p.text(c.question), chose: p.text(c.chose), statedDefault: p.text(c.statedDefault) })}`,
6078
+ ` - ${callUndoLine({ by: p.text(c.by), undoable: c.undoable, how: c.how === null ? null : p.text(c.how) })}`
6079
+ ];
6080
+ });
6081
+ return [`## ${CALLS_HEADING}`, CALLS_EXPLAINED, lines.join("\n")];
6082
+ }
6083
+ function renderClaims(claims, p) {
6084
+ if (claims.length === 0)
6085
+ return [`## ${UNCHECKED_CLAIMS_HEADING}`, NO_UNCHECKED_CLAIMS_LINE];
6086
+ const lines = claims.map((c) => `- ${recordedClaimLine({
6087
+ task: p.text(c.task),
6088
+ label: p.text(c.label),
6089
+ head: shortCommit(c.head),
6090
+ act: c.act,
6091
+ note: c.note === null ? null : p.text(c.note)
6092
+ })}`);
6093
+ return [`## ${UNCHECKED_CLAIMS_HEADING}`, lines.join("\n")];
6094
+ }
5498
6095
  var EARLIER_ROUNDS_LABEL = `${STATED_LABEL} What was said each time the owner's review was asked for, before the round that closed the phase. What was said for that last round is under the close above. If the account that asked for a round is later deleted, the name given for that round is removed.`;
5499
6096
  function renderRoundStated(round, stated, p) {
5500
6097
  const label = "> - Acceptance walk (the finished work tried as a user would, by someone other than its builder): ";
@@ -5539,7 +6136,8 @@ function renderBuildRecordV2Markdown(record2) {
5539
6136
  const closes = [...record2.observed.closes].sort((a, b) => a.sequence - b.sequence);
5540
6137
  const total = closes.length;
5541
6138
  const latest = closes[total - 1];
5542
- const rounds = record2.format === "halfcycle-build-record/v3" ? record2.review.rounds : [];
6139
+ const rounds = hasOwnerReview(record2) ? record2.review.rounds : [];
6140
+ const path = keptPathOf(record2);
5543
6141
  const roundsAfter = rounds.length <= 1 ? null : `after ${String(rounds.length)} rounds of the owner's review.${rounds.some((r) => r.stated !== void 0) ? ' What was said for each earlier round is under "Earlier rounds of the review".' : ""}`;
5544
6142
  const body = [
5545
6143
  `Phase: ${phase} (the name the client gave it)`,
@@ -5547,14 +6145,23 @@ function renderBuildRecordV2Markdown(record2) {
5547
6145
  [
5548
6146
  `- Method version: ${p.text(record2.observed.methodVersion)}. The Halfcycle method is updated from time to time, and each update has its own version number. This is the one the phase was run under. A project moves to a newer version only between phases.`,
5549
6147
  `- Project identifier: ${p.text(record2.observed.engagementId)}. Halfcycle keeps this project's records under this identifier.`,
5550
- `- Record format: ${p.text(record2.format)}. This names the layout this file and the .json file beside it follow, for software that reads them.`
6148
+ `- Record format: ${p.text(record2.format)}. This names the layout this file and the .json file beside it follow, for software that reads them.`,
6149
+ ...path === null ? [] : [`- ${PATH_LINE[path]}`]
5551
6150
  ].join("\n"),
5552
6151
  total === 1 ? roundsAfter === null ? "This phase was closed once." : `This phase was closed once, ${roundsAfter}` : `This phase was closed ${String(total)} times. The latest close is described first; each earlier close follows, as it was recorded when it was made.${roundsAfter === null ? "" : ` The latest close came ${roundsAfter}`}`,
5553
6152
  ...renderChecks(record2.observed.checks, p),
5554
6153
  ...renderClose(total === 1 ? "## The close" : `## The latest close (close ${String(latest.sequence)} of ${String(total)})`, latest, attestedBySequence.get(latest.sequence), record2.observed.checks.state, p, rounds.length > 1)
5555
6154
  ];
5556
- if (record2.format === "halfcycle-build-record/v3")
5557
- body.push(...renderReview(record2, p), ...renderEarlierRounds(record2, p));
6155
+ if (hasOwnerReview(record2))
6156
+ body.push(...renderReview(record2, p));
6157
+ const calls = keptCallsOf(record2);
6158
+ if (calls !== null)
6159
+ body.push(...renderCalls(calls, p));
6160
+ const claims = keptClaimsOf(record2);
6161
+ if (claims !== null)
6162
+ body.push(...renderClaims(claims, p));
6163
+ if (hasOwnerReview(record2))
6164
+ body.push(...renderEarlierRounds(record2, p));
5558
6165
  if (total > 1) {
5559
6166
  body.push("## Earlier closes");
5560
6167
  for (const close of closes.slice(0, -1)) {
@@ -5569,16 +6176,11 @@ function renderBuildRecordV2Markdown(record2) {
5569
6176
  }
5570
6177
 
5571
6178
  // dist/build-record/write.js
5572
- import { closeSync, existsSync as existsSync6, mkdirSync as mkdirSync6, openSync, readFileSync as readFileSync7, renameSync as renameSync2, rmSync as rmSync3, writeSync } from "node:fs";
5573
- import { basename, join as join8, resolve, relative as relative2, isAbsolute as isAbsolute2 } from "node:path";
5574
- var BUILD_RECORD_DIR = join8("docs", "build-records");
5575
- function assertInsideOutDir(outDir, candidate, identity) {
5576
- const rel = relative2(outDir, resolve(candidate));
5577
- const isPlainFilename = rel !== "" && rel !== ".." && !isAbsolute2(rel) && rel === basename(rel);
5578
- if (!isPlainFilename) {
5579
- throw new InvalidPhaseIdentityError(identity, BUILD_RECORD_DIR);
5580
- }
5581
- }
6179
+ import { existsSync as existsSync6, mkdirSync as mkdirSync6, rmSync as rmSync4 } from "node:fs";
6180
+ import { basename, join as join8, resolve as resolve2, relative as relative2, isAbsolute as isAbsolute3 } from "node:path";
6181
+
6182
+ // dist/build-record/pair-io.js
6183
+ import { closeSync, openSync, readFileSync as readFileSync7, renameSync as renameSync2, rmSync as rmSync3, writeSync } from "node:fs";
5582
6184
  function createExclusiveOnDisk(path, data) {
5583
6185
  const bytes = typeof data === "string" ? Buffer.from(data, "utf-8") : data;
5584
6186
  const fd = openSync(path, "wx");
@@ -5614,6 +6216,41 @@ function readIfPresent(path) {
5614
6216
  return null;
5615
6217
  }
5616
6218
  }
6219
+ function createPairExclusive(io, jsonPath, jsonText, mdPath, mdText) {
6220
+ let createdJson = false;
6221
+ try {
6222
+ io.createExclusive(jsonPath, jsonText);
6223
+ createdJson = true;
6224
+ io.createExclusive(mdPath, mdText);
6225
+ return "created";
6226
+ } catch (err) {
6227
+ if (createdJson)
6228
+ rmSync3(jsonPath, { force: true });
6229
+ if (!isEexist(err))
6230
+ throw err;
6231
+ return "exists";
6232
+ }
6233
+ }
6234
+ function replaceOne(io, tmp, finalPath, text) {
6235
+ rmSync3(tmp, { force: true });
6236
+ try {
6237
+ io.createExclusive(tmp, text);
6238
+ io.rename(tmp, finalPath);
6239
+ } catch (err) {
6240
+ rmSync3(tmp, { force: true });
6241
+ throw err;
6242
+ }
6243
+ }
6244
+
6245
+ // dist/build-record/write.js
6246
+ var BUILD_RECORD_DIR = join8("docs", "build-records");
6247
+ function assertInsideOutDir(outDir, candidate, identity) {
6248
+ const rel = relative2(outDir, resolve2(candidate));
6249
+ const isPlainFilename = rel !== "" && rel !== ".." && !isAbsolute3(rel) && rel === basename(rel);
6250
+ if (!isPlainFilename) {
6251
+ throw new InvalidPhaseIdentityError(identity, BUILD_RECORD_DIR);
6252
+ }
6253
+ }
5617
6254
  function isOwnEarlierRecord(existingText, served) {
5618
6255
  let parsedJson;
5619
6256
  try {
@@ -5642,7 +6279,7 @@ function writeRecordPair(repoRoot, phase, rawRecord, record2, io = NODE_RECORD_P
5642
6279
  if (!isValidPhaseIdentity(phase)) {
5643
6280
  throw new InvalidPhaseIdentityError(phase, BUILD_RECORD_DIR);
5644
6281
  }
5645
- const outDir = resolve(repoRoot, BUILD_RECORD_DIR);
6282
+ const outDir = resolve2(repoRoot, BUILD_RECORD_DIR);
5646
6283
  const segment = renderPhaseSegment(phase);
5647
6284
  const jsonPath = join8(outDir, `${segment}.json`);
5648
6285
  const mdPath = join8(outDir, `${segment}.md`);
@@ -5654,17 +6291,8 @@ function writeRecordPair(repoRoot, phase, rawRecord, record2, io = NODE_RECORD_P
5654
6291
  const jsonText = serialiseServedRecord(rawRecord);
5655
6292
  const mdText = renderBuildRecordV2Markdown(record2);
5656
6293
  mkdirSync6(outDir, { recursive: true });
5657
- let createdJson = false;
5658
- try {
5659
- io.createExclusive(jsonPath, jsonText);
5660
- createdJson = true;
5661
- io.createExclusive(mdPath, mdText);
6294
+ if (createPairExclusive(io, jsonPath, jsonText, mdPath, mdText) === "created") {
5662
6295
  return { kind: "created", jsonPath, mdPath };
5663
- } catch (err) {
5664
- if (createdJson)
5665
- rmSync3(jsonPath, { force: true });
5666
- if (!isEexist(err))
5667
- throw err;
5668
6296
  }
5669
6297
  const existingJson = readIfPresent(jsonPath);
5670
6298
  if (existingJson === null) {
@@ -5684,22 +6312,12 @@ function writeRecordPair(repoRoot, phase, rawRecord, record2, io = NODE_RECORD_P
5684
6312
  try {
5685
6313
  replaceOne(io, jsonTmp, jsonPath, existingJson);
5686
6314
  } catch {
5687
- rmSync3(jsonPath, { force: true });
6315
+ rmSync4(jsonPath, { force: true });
5688
6316
  }
5689
6317
  throw err;
5690
6318
  }
5691
6319
  return { kind: "replaced", jsonPath, mdPath };
5692
6320
  }
5693
- function replaceOne(io, tmp, finalPath, text) {
5694
- rmSync3(tmp, { force: true });
5695
- try {
5696
- io.createExclusive(tmp, text);
5697
- io.rename(tmp, finalPath);
5698
- } catch (err) {
5699
- rmSync3(tmp, { force: true });
5700
- throw err;
5701
- }
5702
- }
5703
6321
 
5704
6322
  // dist/build-record/obtain.js
5705
6323
  import { relative as relative3 } from "node:path";