@patronage/software-factory 1.0.0-alpha.33 → 1.0.0-alpha.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -17,8 +17,8 @@ declare const boundaryManifestBaseSchema: z.ZodObject<{
17
17
  boundary: z.ZodString;
18
18
  closeout: z.ZodOptional<z.ZodObject<{
19
19
  review: z.ZodEnum<{
20
- oracle: "oracle";
21
20
  "independent-model": "independent-model";
21
+ oracle: "oracle";
22
22
  human: "human";
23
23
  }>;
24
24
  }, z.core.$loose>>;
@@ -26,8 +26,8 @@ declare const boundaryManifestBaseSchema: z.ZodObject<{
26
26
  integrationBranch: z.ZodOptional<z.ZodString>;
27
27
  schemaVersion: z.ZodLiteral<1>;
28
28
  topology: z.ZodEnum<{
29
- flagged: "flagged";
30
29
  "each-to-main": "each-to-main";
30
+ flagged: "flagged";
31
31
  stacked: "stacked";
32
32
  "each-to-epic": "each-to-epic";
33
33
  }>;
@@ -36,8 +36,8 @@ declare const boundaryManifestBaseSchema: z.ZodObject<{
36
36
  issues: z.ZodArray<z.ZodNumber>;
37
37
  name: z.ZodString;
38
38
  review: z.ZodEnum<{
39
- oracle: "oracle";
40
39
  "independent-model": "independent-model";
40
+ oracle: "oracle";
41
41
  human: "human";
42
42
  }>;
43
43
  }, z.core.$loose>>;
@@ -46,8 +46,8 @@ declare const boundaryManifestSchema: z.ZodObject<{
46
46
  boundary: z.ZodString;
47
47
  closeout: z.ZodOptional<z.ZodObject<{
48
48
  review: z.ZodEnum<{
49
- oracle: "oracle";
50
49
  "independent-model": "independent-model";
50
+ oracle: "oracle";
51
51
  human: "human";
52
52
  }>;
53
53
  }, z.core.$loose>>;
@@ -55,8 +55,8 @@ declare const boundaryManifestSchema: z.ZodObject<{
55
55
  integrationBranch: z.ZodOptional<z.ZodString>;
56
56
  schemaVersion: z.ZodLiteral<1>;
57
57
  topology: z.ZodEnum<{
58
- flagged: "flagged";
59
58
  "each-to-main": "each-to-main";
59
+ flagged: "flagged";
60
60
  stacked: "stacked";
61
61
  "each-to-epic": "each-to-epic";
62
62
  }>;
@@ -65,8 +65,8 @@ declare const boundaryManifestSchema: z.ZodObject<{
65
65
  issues: z.ZodArray<z.ZodNumber>;
66
66
  name: z.ZodString;
67
67
  review: z.ZodEnum<{
68
- oracle: "oracle";
69
68
  "independent-model": "independent-model";
69
+ oracle: "oracle";
70
70
  human: "human";
71
71
  }>;
72
72
  }, z.core.$loose>>;
@@ -151,8 +151,8 @@ declare const boundaryReviewProofBaseSchema: z.ZodObject<{
151
151
  }>;
152
152
  producer: z.ZodString;
153
153
  rung: z.ZodEnum<{
154
- oracle: "oracle";
155
154
  "independent-model": "independent-model";
155
+ oracle: "oracle";
156
156
  human: "human";
157
157
  }>;
158
158
  schemaVersion: z.ZodLiteral<1>;
@@ -195,8 +195,8 @@ declare const boundaryReviewProofSchema: z.ZodObject<{
195
195
  }>;
196
196
  producer: z.ZodString;
197
197
  rung: z.ZodEnum<{
198
- oracle: "oracle";
199
198
  "independent-model": "independent-model";
199
+ oracle: "oracle";
200
200
  human: "human";
201
201
  }>;
202
202
  schemaVersion: z.ZodLiteral<1>;
@@ -1423,6 +1423,16 @@ declare const mergeFreezeStateSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
1423
1423
  reason: z.ZodString;
1424
1424
  recordedAt: z.ZodISODateTime;
1425
1425
  schemaVersion: z.ZodLiteral<1>;
1426
+ verification: z.ZodOptional<z.ZodObject<{
1427
+ jobs: z.ZodRecord<z.ZodString, z.ZodEnum<{
1428
+ success: "success";
1429
+ failure: "failure";
1430
+ cancelled: "cancelled";
1431
+ skipped: "skipped";
1432
+ }>>;
1433
+ runAttempt: z.ZodNumber;
1434
+ runId: z.ZodNumber;
1435
+ }, z.core.$strip>>;
1426
1436
  }, z.core.$strip>, z.ZodObject<{
1427
1437
  active: z.ZodLiteral<false>;
1428
1438
  clearRationale: z.ZodOptional<z.ZodString>;
@@ -1432,6 +1442,16 @@ declare const mergeFreezeStateSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
1432
1442
  reason: z.ZodString;
1433
1443
  recordedAt: z.ZodISODateTime;
1434
1444
  schemaVersion: z.ZodLiteral<1>;
1445
+ verification: z.ZodOptional<z.ZodObject<{
1446
+ jobs: z.ZodRecord<z.ZodString, z.ZodEnum<{
1447
+ success: "success";
1448
+ failure: "failure";
1449
+ cancelled: "cancelled";
1450
+ skipped: "skipped";
1451
+ }>>;
1452
+ runAttempt: z.ZodNumber;
1453
+ runId: z.ZodNumber;
1454
+ }, z.core.$strip>>;
1435
1455
  }, z.core.$strip>], "active">;
1436
1456
  type MergeFreezeState = z.infer<typeof mergeFreezeStateSchema>;
1437
1457
  /**
@@ -1666,8 +1686,8 @@ declare const managedReadinessLedgerSchema: z.ZodObject<{
1666
1686
  reviewedHeadSha: z.ZodOptional<z.ZodString>;
1667
1687
  reviewedPatchId: z.ZodOptional<z.ZodString>;
1668
1688
  status: z.ZodEnum<{
1669
- "not-required": "not-required";
1670
1689
  stale: "stale";
1690
+ "not-required": "not-required";
1671
1691
  blocked: "blocked";
1672
1692
  current: "current";
1673
1693
  missing: "missing";
@@ -1678,8 +1698,8 @@ declare const managedReadinessLedgerSchema: z.ZodObject<{
1678
1698
  reviewedHeadSha: z.ZodOptional<z.ZodString>;
1679
1699
  reviewedPatchId: z.ZodOptional<z.ZodString>;
1680
1700
  status: z.ZodEnum<{
1681
- "not-required": "not-required";
1682
1701
  stale: "stale";
1702
+ "not-required": "not-required";
1683
1703
  blocked: "blocked";
1684
1704
  current: "current";
1685
1705
  missing: "missing";
@@ -2668,8 +2688,8 @@ declare const evidenceEnvelopeBaseSchema: z.ZodObject<{
2668
2688
  producer: z.ZodString;
2669
2689
  requestId: z.ZodOptional<z.ZodString>;
2670
2690
  rung: z.ZodOptional<z.ZodEnum<{
2671
- oracle: "oracle";
2672
2691
  "independent-model": "independent-model";
2692
+ oracle: "oracle";
2673
2693
  human: "human";
2674
2694
  }>>;
2675
2695
  schemaVersion: z.ZodLiteral<1>;
@@ -2695,8 +2715,8 @@ declare const evidenceEnvelopeSchema: z.ZodObject<{
2695
2715
  producer: z.ZodString;
2696
2716
  requestId: z.ZodOptional<z.ZodString>;
2697
2717
  rung: z.ZodOptional<z.ZodEnum<{
2698
- oracle: "oracle";
2699
2718
  "independent-model": "independent-model";
2719
+ oracle: "oracle";
2700
2720
  human: "human";
2701
2721
  }>>;
2702
2722
  schemaVersion: z.ZodLiteral<1>;
@@ -2798,8 +2818,8 @@ declare const loadEvidenceEnvelopes: (cwd: string) => LoadedEvidenceEnvelope[];
2798
2818
  //#region src/review-proof-applicability.d.ts
2799
2819
  declare const REVIEW_STATUS_VALUES: readonly ["not-required", "current", "stale", "missing", "blocked"];
2800
2820
  declare const reviewStatusSchema: z.ZodEnum<{
2801
- "not-required": "not-required";
2802
2821
  stale: "stale";
2822
+ "not-required": "not-required";
2803
2823
  blocked: "blocked";
2804
2824
  current: "current";
2805
2825
  missing: "missing";
@@ -2916,8 +2936,8 @@ declare const boundaryCheckProofSchema: z.ZodObject<{
2916
2936
  wave: z.ZodString;
2917
2937
  }, z.core.$strip>>;
2918
2938
  demandedRung: z.ZodOptional<z.ZodEnum<{
2919
- oracle: "oracle";
2920
2939
  "independent-model": "independent-model";
2940
+ oracle: "oracle";
2921
2941
  human: "human";
2922
2942
  }>>;
2923
2943
  epicIssue: z.ZodNumber;
@@ -2932,8 +2952,8 @@ declare const boundaryCheckProofSchema: z.ZodObject<{
2932
2952
  commentUrl: z.ZodOptional<z.ZodString>;
2933
2953
  producer: z.ZodString;
2934
2954
  rung: z.ZodEnum<{
2935
- oracle: "oracle";
2936
2955
  "independent-model": "independent-model";
2956
+ oracle: "oracle";
2937
2957
  human: "human";
2938
2958
  }>;
2939
2959
  sessionId: z.ZodOptional<z.ZodString>;
@@ -3577,18 +3597,18 @@ declare const LegacyWorkerCloseoutStatusTraceEventSchema: z.ZodObject<{
3577
3597
  threadId: z.ZodOptional<z.ZodString>;
3578
3598
  workerId: z.ZodOptional<z.ZodString>;
3579
3599
  archiveStatus: z.ZodOptional<z.ZodEnum<{
3600
+ skipped: "skipped";
3580
3601
  unavailable: "unavailable";
3581
3602
  archived: "archived";
3582
- skipped: "skipped";
3583
3603
  "not-applicable": "not-applicable";
3584
3604
  pending: "pending";
3585
3605
  }>>;
3586
3606
  closeoutReason: z.ZodOptional<z.ZodString>;
3587
3607
  eventType: z.ZodLiteral<"worker-closeout-lessons">;
3588
3608
  lessonStatus: z.ZodOptional<z.ZodEnum<{
3609
+ skipped: "skipped";
3589
3610
  captured: "captured";
3590
3611
  unavailable: "unavailable";
3591
- skipped: "skipped";
3592
3612
  }>>;
3593
3613
  lessonSummary: z.ZodOptional<z.ZodString>;
3594
3614
  typeVersion: z.ZodLiteral<2>;
@@ -3975,18 +3995,18 @@ declare const FACTORY_TRACE_EVENT_DEFINITIONS: readonly [DefinedTraceEvent<"revi
3975
3995
  threadId: z.ZodOptional<z.ZodString>;
3976
3996
  workerId: z.ZodOptional<z.ZodString>;
3977
3997
  archiveStatus: z.ZodOptional<z.ZodEnum<{
3998
+ skipped: "skipped";
3978
3999
  unavailable: "unavailable";
3979
4000
  archived: "archived";
3980
- skipped: "skipped";
3981
4001
  "not-applicable": "not-applicable";
3982
4002
  pending: "pending";
3983
4003
  }>>;
3984
4004
  closeoutReason: z.ZodOptional<z.ZodString>;
3985
4005
  eventType: z.ZodLiteral<"worker-closeout-lessons">;
3986
4006
  lessonStatus: z.ZodOptional<z.ZodEnum<{
4007
+ skipped: "skipped";
3987
4008
  captured: "captured";
3988
4009
  unavailable: "unavailable";
3989
- skipped: "skipped";
3990
4010
  }>>;
3991
4011
  lessonSummary: z.ZodOptional<z.ZodString>;
3992
4012
  typeVersion: z.ZodLiteral<2>;
@@ -4016,17 +4036,17 @@ declare const FACTORY_TRACE_EVENT_DEFINITIONS: readonly [DefinedTraceEvent<"revi
4016
4036
  }, z.core.$strict>], "lessonStatus">;
4017
4037
  readonly 2: z.ZodObject<{
4018
4038
  archiveStatus: z.ZodOptional<z.ZodEnum<{
4039
+ skipped: "skipped";
4019
4040
  unavailable: "unavailable";
4020
4041
  archived: "archived";
4021
- skipped: "skipped";
4022
4042
  "not-applicable": "not-applicable";
4023
4043
  pending: "pending";
4024
4044
  }>>;
4025
4045
  closeoutReason: z.ZodOptional<z.ZodString>;
4026
4046
  lessonStatus: z.ZodOptional<z.ZodEnum<{
4047
+ skipped: "skipped";
4027
4048
  captured: "captured";
4028
4049
  unavailable: "unavailable";
4029
- skipped: "skipped";
4030
4050
  }>>;
4031
4051
  lessonSummary: z.ZodOptional<z.ZodString>;
4032
4052
  observedAt: z.ZodString;
@@ -4138,8 +4158,8 @@ declare const FACTORY_TRACE_EVENT_DEFINITIONS: readonly [DefinedTraceEvent<"revi
4138
4158
  interiorCycle: z.ZodOptional<z.ZodNumber>;
4139
4159
  observedAt: z.ZodString;
4140
4160
  purpose: z.ZodEnum<{
4141
- code: "code";
4142
4161
  review: "review";
4162
+ code: "code";
4143
4163
  }>;
4144
4164
  slotResolution: z.ZodObject<{
4145
4165
  effort: z.ZodEnum<{
@@ -4157,18 +4177,18 @@ declare const FACTORY_TRACE_EVENT_DEFINITIONS: readonly [DefinedTraceEvent<"revi
4157
4177
  }>;
4158
4178
  model: z.ZodString;
4159
4179
  tier: z.ZodEnum<{
4180
+ oracle: "oracle";
4160
4181
  review: "review";
4161
4182
  delegate: "delegate";
4162
- oracle: "oracle";
4163
4183
  workhorse: "workhorse";
4164
4184
  scout: "scout";
4165
4185
  }>;
4166
4186
  }, z.core.$strict>;
4167
4187
  startedAt: z.ZodString;
4168
4188
  tier: z.ZodEnum<{
4189
+ oracle: "oracle";
4169
4190
  review: "review";
4170
4191
  delegate: "delegate";
4171
- oracle: "oracle";
4172
4192
  workhorse: "workhorse";
4173
4193
  scout: "scout";
4174
4194
  }>;
@@ -4217,8 +4237,8 @@ declare const FACTORY_TRACE_EVENT_DEFINITIONS: readonly [DefinedTraceEvent<"revi
4217
4237
  interiorCycle: z.ZodOptional<z.ZodNumber>;
4218
4238
  observedAt: z.ZodString;
4219
4239
  purpose: z.ZodEnum<{
4220
- code: "code";
4221
4240
  review: "review";
4241
+ code: "code";
4222
4242
  }>;
4223
4243
  slotResolution: z.ZodObject<{
4224
4244
  effort: z.ZodEnum<{
@@ -4236,18 +4256,18 @@ declare const FACTORY_TRACE_EVENT_DEFINITIONS: readonly [DefinedTraceEvent<"revi
4236
4256
  }>;
4237
4257
  model: z.ZodString;
4238
4258
  tier: z.ZodEnum<{
4259
+ oracle: "oracle";
4239
4260
  review: "review";
4240
4261
  delegate: "delegate";
4241
- oracle: "oracle";
4242
4262
  workhorse: "workhorse";
4243
4263
  scout: "scout";
4244
4264
  }>;
4245
4265
  }, z.core.$strict>;
4246
4266
  startedAt: z.ZodString;
4247
4267
  tier: z.ZodEnum<{
4268
+ oracle: "oracle";
4248
4269
  review: "review";
4249
4270
  delegate: "delegate";
4250
- oracle: "oracle";
4251
4271
  workhorse: "workhorse";
4252
4272
  scout: "scout";
4253
4273
  }>;
@@ -4287,8 +4307,8 @@ declare const FACTORY_TRACE_EVENT_DEFINITIONS: readonly [DefinedTraceEvent<"revi
4287
4307
  interiorCycle: z.ZodOptional<z.ZodNumber>;
4288
4308
  observedAt: z.ZodString;
4289
4309
  purpose: z.ZodEnum<{
4290
- code: "code";
4291
4310
  review: "review";
4311
+ code: "code";
4292
4312
  }>;
4293
4313
  slotResolution: z.ZodObject<{
4294
4314
  effort: z.ZodEnum<{
@@ -4306,18 +4326,18 @@ declare const FACTORY_TRACE_EVENT_DEFINITIONS: readonly [DefinedTraceEvent<"revi
4306
4326
  }>;
4307
4327
  model: z.ZodString;
4308
4328
  tier: z.ZodEnum<{
4329
+ oracle: "oracle";
4309
4330
  review: "review";
4310
4331
  delegate: "delegate";
4311
- oracle: "oracle";
4312
4332
  workhorse: "workhorse";
4313
4333
  scout: "scout";
4314
4334
  }>;
4315
4335
  }, z.core.$strict>;
4316
4336
  startedAt: z.ZodString;
4317
4337
  tier: z.ZodEnum<{
4338
+ oracle: "oracle";
4318
4339
  review: "review";
4319
4340
  delegate: "delegate";
4320
- oracle: "oracle";
4321
4341
  workhorse: "workhorse";
4322
4342
  scout: "scout";
4323
4343
  }>;
@@ -4360,17 +4380,17 @@ declare const FACTORY_TRACE_EVENT_DEFINITIONS: readonly [DefinedTraceEvent<"revi
4360
4380
  exitCode: number | null;
4361
4381
  harness: string;
4362
4382
  observedAt: string;
4363
- purpose: "code" | "review";
4383
+ purpose: "review" | "code";
4364
4384
  slotResolution: {
4365
4385
  effort: "high" | "low" | "medium" | "xhigh";
4366
4386
  engine: string;
4367
4387
  layerSource: "committedDefault" | "operatorSession" | "userConfig";
4368
4388
  model: string;
4369
- tier: "review" | "delegate" | "oracle" | "workhorse" | "scout";
4389
+ tier: "oracle" | "review" | "delegate" | "workhorse" | "scout";
4370
4390
  fallbackTier?: "delegate" | undefined;
4371
4391
  };
4372
4392
  startedAt: string;
4373
- tier: "review" | "delegate" | "oracle" | "workhorse" | "scout";
4393
+ tier: "oracle" | "review" | "delegate" | "workhorse" | "scout";
4374
4394
  tokenUsage: {
4375
4395
  source: "cursor-csv" | "codex-json" | "cursor-json" | "claude-json";
4376
4396
  status: "available";
@@ -4714,13 +4734,13 @@ declare const evaluateReadiness: (input: EvaluationInput) => {
4714
4734
  reviews: {
4715
4735
  correctness: {
4716
4736
  required: boolean;
4717
- status: "not-required" | "stale" | "blocked" | "current" | "missing";
4737
+ status: "stale" | "not-required" | "blocked" | "current" | "missing";
4718
4738
  reviewedHeadSha?: string | undefined;
4719
4739
  reviewedPatchId?: string | undefined;
4720
4740
  };
4721
4741
  security?: {
4722
4742
  required: boolean;
4723
- status: "not-required" | "stale" | "blocked" | "current" | "missing";
4743
+ status: "stale" | "not-required" | "blocked" | "current" | "missing";
4724
4744
  reviewedHeadSha?: string | undefined;
4725
4745
  reviewedPatchId?: string | undefined;
4726
4746
  } | undefined;
package/dist/index.js CHANGED
@@ -20,7 +20,7 @@ import http from "node:http";
20
20
  import { pathToFileURL } from "node:url";
21
21
  //#region package.json
22
22
  var name = "@patronage/software-factory";
23
- var version = "1.0.0-alpha.33";
23
+ var version = "1.0.0-alpha.34";
24
24
  //#endregion
25
25
  //#region src/cli-entry.ts
26
26
  /**
@@ -1349,7 +1349,11 @@ function resolveDiffBase(cwd, base) {
1349
1349
  }
1350
1350
  }
1351
1351
  function statusPorcelain(cwd) {
1352
- return runCapture("git", ["status", "--porcelain"], cwd).stdout.trim();
1352
+ return runCapture("git", [
1353
+ "status",
1354
+ "--porcelain",
1355
+ "--untracked-files=all"
1356
+ ], cwd).stdout.trim();
1353
1357
  }
1354
1358
  function filesFromNameStatus(value) {
1355
1359
  return value.split("\n").filter(Boolean).flatMap((line) => {
@@ -2507,27 +2511,9 @@ function tryReadProof(read, filePath) {
2507
2511
  function readOptionalProof(read, filePath) {
2508
2512
  return tryReadProof(read, filePath).proof;
2509
2513
  }
2510
- const normalizeStatusPath = (filePath) => filePath.replaceAll("\\", "/").replace(/^\.\//u, "");
2511
- const decodeStatusPath = (filePath) => {
2512
- const trimmed = filePath.trim();
2513
- if (trimmed.startsWith("\"") && trimmed.endsWith("\"")) try {
2514
- return JSON.parse(trimmed);
2515
- } catch {}
2516
- return trimmed;
2517
- };
2518
- const statusLinePaths = (line) => {
2519
- const xyStatus = line.slice(0, 2);
2520
- const porcelainPath = line.slice(3);
2521
- return xyStatus[0] === "R" || xyStatus[0] === "C" || xyStatus[1] === "R" || xyStatus[1] === "C" ? porcelainPath.split(" -> ").map(decodeStatusPath) : [decodeStatusPath(porcelainPath)];
2522
- };
2523
- function assertCleanWorktreeForProof({ changedFiles, cwd, dirtyMessage, statusPorcelain }) {
2514
+ function assertCleanWorktreeForProof({ cwd, dirtyMessage, statusPorcelain }) {
2524
2515
  const status = statusPorcelain(cwd);
2525
- const changedFileSet = new Set(changedFiles.map(normalizeStatusPath));
2526
- const offendingLines = status.split("\n").filter((line) => {
2527
- if (line.length < 3) return false;
2528
- return statusLinePaths(line).some((filePath) => changedFileSet.has(normalizeStatusPath(filePath)));
2529
- });
2530
- if (offendingLines.length > 0) throw new Error(`${dirtyMessage}\n${offendingLines.join("\n")}`);
2516
+ if (status.trim().length > 0) throw new Error(`${dirtyMessage}\n${status}`);
2531
2517
  }
2532
2518
  //#endregion
2533
2519
  //#region src/battery-shell-command.ts
@@ -9188,6 +9174,11 @@ function runPrVerify(args, dependencies = {}) {
9188
9174
  });
9189
9175
  };
9190
9176
  try {
9177
+ assertCleanWorktreeForProof({
9178
+ cwd,
9179
+ dirtyMessage: "pr:verify requires committed input; the worktree is dirty. Commit changes or use a clean isolated checkout before verification.",
9180
+ statusPorcelain: git.statusPorcelain
9181
+ });
9191
9182
  for (const command of commands) {
9192
9183
  if (scopedOutNames.has(command.name)) continue;
9193
9184
  console.log(`\n> ${command.name}: ${command.command}`);
@@ -9236,11 +9227,11 @@ function runPrVerify(args, dependencies = {}) {
9236
9227
  }
9237
9228
  }
9238
9229
  assertCleanWorktreeForProof({
9239
- changedFiles: files,
9240
9230
  cwd,
9241
9231
  dirtyMessage: "pr:verify passed, but the worktree is dirty. Commit or stash changes before writing typed proof.",
9242
9232
  statusPorcelain: git.statusPorcelain
9243
9233
  });
9234
+ if (git.currentHeadSha(cwd) !== headSha) throw new Error("pr:verify candidate HEAD changed during verification. Re-run verification on the final committed head.");
9244
9235
  const previousProof = readPreviousPrVerifyProof(cwd, output);
9245
9236
  const baselineFullProofs = resolvedMode === "docs-only" ? baselineFullProofsForDocsOnly({
9246
9237
  previousProof,
@@ -15998,6 +15989,16 @@ const MERGE_FREEZE_SCHEMA_VERSION = 1;
15998
15989
  const CHECK_RUNS_PER_PAGE$1 = 100;
15999
15990
  const CHECK_RUN_PAGE_LIMIT$1 = 10;
16000
15991
  const shaSchema$2 = z.string().regex(/^[0-9a-f]{40}$/u);
15992
+ const verificationSchema = z.object({
15993
+ jobs: z.record(z.string(), z.enum([
15994
+ "success",
15995
+ "failure",
15996
+ "cancelled",
15997
+ "skipped"
15998
+ ])),
15999
+ runAttempt: z.number().int().positive(),
16000
+ runId: z.number().int().positive()
16001
+ });
16001
16002
  const activeMergeFreezeStateSchema = z.object({
16002
16003
  active: z.literal(true),
16003
16004
  generationId: z.number().int().positive(),
@@ -16005,7 +16006,8 @@ const activeMergeFreezeStateSchema = z.object({
16005
16006
  outcome: z.enum(["active", "stale"]),
16006
16007
  reason: z.string().min(1),
16007
16008
  recordedAt: z.iso.datetime(),
16008
- schemaVersion: z.literal(MERGE_FREEZE_SCHEMA_VERSION)
16009
+ schemaVersion: z.literal(MERGE_FREEZE_SCHEMA_VERSION),
16010
+ verification: verificationSchema.optional()
16009
16011
  });
16010
16012
  const inactiveMergeFreezeStateSchema = z.object({
16011
16013
  active: z.literal(false),
@@ -16015,7 +16017,8 @@ const inactiveMergeFreezeStateSchema = z.object({
16015
16017
  outcome: z.literal("inactive"),
16016
16018
  reason: z.string().min(1),
16017
16019
  recordedAt: z.iso.datetime(),
16018
- schemaVersion: z.literal(MERGE_FREEZE_SCHEMA_VERSION)
16020
+ schemaVersion: z.literal(MERGE_FREEZE_SCHEMA_VERSION),
16021
+ verification: verificationSchema.optional()
16019
16022
  });
16020
16023
  const mergeFreezeStateSchema = z.discriminatedUnion("active", [activeMergeFreezeStateSchema, inactiveMergeFreezeStateSchema]);
16021
16024
  /**
@@ -19726,7 +19729,6 @@ async function runPrReview(args, dependencies = {}) {
19726
19729
  });
19727
19730
  const files = git.changedFiles(cwd, base.sha);
19728
19731
  assertCleanWorktreeForProof({
19729
- changedFiles: files,
19730
19732
  cwd,
19731
19733
  dirtyMessage: "pr:review requires a clean worktree so proof matches committed PR content.",
19732
19734
  statusPorcelain: git.statusPorcelain
@@ -20872,6 +20874,8 @@ const workflowRunJobSchema = z.object({
20872
20874
  head_sha: z.string(),
20873
20875
  id: z.number().int(),
20874
20876
  name: z.string(),
20877
+ run_attempt: z.number().int().positive(),
20878
+ run_id: z.number().int().positive(),
20875
20879
  steps: z.array(z.object({
20876
20880
  conclusion: z.string().nullable(),
20877
20881
  name: z.string()
@@ -20882,7 +20886,8 @@ const workflowRunRecordSchema = z.object({
20882
20886
  head_sha: z.string(),
20883
20887
  id: z.number().int(),
20884
20888
  path: z.string(),
20885
- repository: z.object({ full_name: z.string() })
20889
+ repository: z.object({ full_name: z.string() }),
20890
+ run_attempt: z.number().int().positive()
20886
20891
  });
20887
20892
  /** The deployment environment one target's receipts live in. */
20888
20893
  const deploymentReceiptEnvironment = (target) => target;
@@ -20931,20 +20936,27 @@ const trustReceipt = (args, deployment) => {
20931
20936
  const { receipt } = bound;
20932
20937
  let runRecord;
20933
20938
  let jobRecords;
20939
+ let latestRunRecord;
20934
20940
  try {
20935
- runRecord = args.transport.getWorkflowRun(receipt.workflow.runId);
20936
- jobRecords = args.transport.listWorkflowRunJobs(receipt.workflow.runId);
20941
+ runRecord = args.transport.getWorkflowRunAttempt(receipt.workflow.runId, receipt.workflow.runAttempt);
20942
+ jobRecords = args.transport.listWorkflowRunJobs(receipt.workflow.runId, receipt.workflow.runAttempt);
20943
+ latestRunRecord = args.transport.getWorkflowRun(receipt.workflow.runId);
20937
20944
  } catch (error) {
20938
20945
  return { reason: `${label} names run ${receipt.workflow.runId}, which could not be read (transport error code: ${transportCode(error)})` };
20939
20946
  }
20940
20947
  const run = workflowRunRecordSchema.safeParse(runRecord);
20941
20948
  if (!run.success) return { reason: `${label} names run ${receipt.workflow.runId}, which GitHub does not record` };
20942
20949
  const expectedBranch = args.identity.ref.replace(/^refs\/heads\//u, "");
20943
- if (run.data.path !== args.identity.workflowPath || run.data.repository.full_name !== args.identity.repository || run.data.head_sha.toLowerCase() !== receipt.sourceSha || run.data.head_branch !== expectedBranch) return { reason: `${label} names run ${receipt.workflow.runId}, whose recorded workflow, repository, head, or branch disagrees with the receipt` };
20944
- const jobs = z.object({ jobs: z.array(workflowRunJobSchema) }).safeParse(jobRecords);
20945
- if (!jobs.success) return { reason: `${label} names run ${receipt.workflow.runId}, whose job records are malformed` };
20950
+ if (run.data.id !== Number(receipt.workflow.runId) || run.data.run_attempt !== receipt.workflow.runAttempt || run.data.path !== args.identity.workflowPath || run.data.repository.full_name !== args.identity.repository || run.data.head_sha.toLowerCase() !== receipt.sourceSha || run.data.head_branch !== expectedBranch) return { reason: `${label} names run ${receipt.workflow.runId}, whose recorded run, attempt, workflow, repository, head, or branch disagrees with the receipt` };
20951
+ const latestRun = workflowRunRecordSchema.safeParse(latestRunRecord);
20952
+ if (!latestRun.success || latestRun.data.id !== run.data.id || latestRun.data.run_attempt !== receipt.workflow.runAttempt || latestRun.data.path !== run.data.path || latestRun.data.repository.full_name !== run.data.repository.full_name || latestRun.data.head_sha !== run.data.head_sha || latestRun.data.head_branch !== run.data.head_branch) return { reason: `${label} producing attempt is no longer the current matching run attempt; reconciliation is required` };
20953
+ const jobs = z.object({
20954
+ jobs: z.array(workflowRunJobSchema),
20955
+ total_count: z.number().int().nonnegative()
20956
+ }).safeParse(jobRecords);
20957
+ if (!jobs.success || jobs.data.total_count !== jobs.data.jobs.length) return { reason: `${label} names run ${receipt.workflow.runId}, whose job records are malformed or incomplete` };
20946
20958
  const stepName = boundReceiptStepName(deployment.id);
20947
- if (jobs.data.jobs.find((job) => job.conclusion === "success" && job.head_sha.toLowerCase() === receipt.sourceSha && job.steps?.some((step) => step.name === stepName && step.conclusion === "success")) === void 0) return { reason: `${label} names run ${receipt.workflow.runId}, but no succeeded job of that run at ${receipt.sourceSha} bound deployment ${deployment.id}` };
20959
+ if (jobs.data.jobs.find((job) => job.conclusion === "success" && job.run_id === Number(receipt.workflow.runId) && job.run_attempt === receipt.workflow.runAttempt && job.head_sha.toLowerCase() === receipt.sourceSha && job.steps?.some((step) => step.name === stepName && step.conclusion === "success")) === void 0) return { reason: `${label} names run ${receipt.workflow.runId}, but no succeeded job of that run at ${receipt.sourceSha} bound deployment ${deployment.id}` };
20948
20960
  return {
20949
20961
  baseline: {
20950
20962
  deploymentId: deployment.id,
@@ -21109,9 +21121,10 @@ const ghDeploymentReceiptTransport = (cwd, repository, run = defaultGhRunner) =>
21109
21121
  createDeployment: (body) => post(`${base}/deployments`, body),
21110
21122
  createDeploymentStatus: (deploymentId, body) => post(`${base}/deployments/${deploymentId}/statuses`, body),
21111
21123
  getWorkflowRun: (runId) => api(`${base}/actions/runs/${runId}`),
21124
+ getWorkflowRunAttempt: (runId, attempt) => api(`${base}/actions/runs/${runId}/attempts/${attempt}`),
21112
21125
  listDeploymentStatuses: (deploymentId) => api(`${base}/deployments/${deploymentId}/statuses?per_page=${RECEIPT_PAGE_SIZE}`),
21113
21126
  listDeployments: () => api(`${base}/deployments?per_page=${RECEIPT_PAGE_SIZE}`),
21114
- listWorkflowRunJobs: (runId) => api(`${base}/actions/runs/${runId}/jobs?per_page=${RECEIPT_PAGE_SIZE}`)
21127
+ listWorkflowRunJobs: (runId, attempt) => api(`${base}/actions/runs/${runId}/attempts/${attempt}/jobs?per_page=${RECEIPT_PAGE_SIZE}`)
21115
21128
  };
21116
21129
  };
21117
21130
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patronage/software-factory",
3
- "version": "1.0.0-alpha.33",
3
+ "version": "1.0.0-alpha.34",
4
4
  "description": "Shared Patronage software factory CLI and project-profile validation tools",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -37,7 +37,7 @@
37
37
  "picomatch": "^4.0.5",
38
38
  "yaml": "^2.9.0",
39
39
  "zod": "4.4.3",
40
- "@patronage/factory-ci": "1.0.0-alpha.33"
40
+ "@patronage/factory-ci": "1.0.0-alpha.34"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/node": "24.13.3",