@patronage/software-factory 0.25.0 → 0.30.0-alpha.1

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/schemas.d.ts CHANGED
@@ -109,105 +109,6 @@ interface FollowUpAction {
109
109
  command: string;
110
110
  }
111
111
  //#endregion
112
- //#region src/merge-preflight/worktree-held-branch.d.ts
113
- /**
114
- * Detects when a PR head branch is checked out in a local git worktree.
115
- *
116
- * `gh pr merge --delete-branch` fails when the local branch is held by a
117
- * worktree (git refuses to delete a checked-out branch), which previously
118
- * broke the auto-merge lane mid-merge (patronage/internal#284). The merge
119
- * preflight surfaces this as an actionable notice — not a hard fail — so the
120
- * operator merges without `--delete-branch` (or prunes the worktree first)
121
- * and defers local branch cleanup to closeout.
122
- */
123
- interface WorktreeHeldBranch {
124
- branch: string;
125
- worktreePath: string;
126
- }
127
- //#endregion
128
- //#region src/pr-readiness/merge-identity.d.ts
129
- interface PostProofCommit {
130
- sha: string;
131
- subject: string;
132
- }
133
- type MergeIdentityResult = {
134
- kind: "match";
135
- headSha: string;
136
- } | {
137
- kind: "diverged";
138
- liveHeadSha: string;
139
- postProofCommits?: PostProofCommit[];
140
- proofHeadSha: string;
141
- };
142
- type MergeGuardIdentity = MergeIdentityResult | {
143
- kind: "live-head-invalid";
144
- pr: number;
145
- received: string;
146
- } | {
147
- kind: "ready-proof-missing";
148
- errorDetail?: string;
149
- readyProofPath: string;
150
- } | {
151
- kind: "ready-proof-pr-mismatch";
152
- proofPr: number;
153
- requestedPr: number;
154
- } | {
155
- kind: "ready-proof-not-ready";
156
- blockingReasons: string[];
157
- status: string;
158
- };
159
- //#endregion
160
- //#region src/review-rungs.d.ts
161
- declare const EVIDENCE_REVIEW_RUNGS: readonly ["independent-model", "oracle", "human"];
162
- type EvidenceReviewRung = (typeof EVIDENCE_REVIEW_RUNGS)[number];
163
- //#endregion
164
- //#region src/pr-merge-check.d.ts
165
- interface PrMergeCheckProof {
166
- schemaVersion: 1;
167
- blockingReasons: string[];
168
- boundary?: {
169
- autoMerge: boolean;
170
- epic: number;
171
- review: EvidenceReviewRung;
172
- wave: string;
173
- };
174
- command: "patronage-factory pr:merge-check";
175
- /**
176
- * Machine-safe arg array for the obvious next action (#523): on `pass`, the
177
- * remote-only GitHub merge API invocation for this PR; on `fail`, the re-run that clears the
178
- * block (`pr:ready`, or `pr:verify` then `pr:ready` after a head
179
- * divergence). Same `argv` shape `factory:delegate --print` emits. Optional
180
- * and purely additive — existing consumers ignore it.
181
- */
182
- followUp?: FollowUpAction;
183
- identity: MergeGuardIdentity;
184
- /**
185
- * The pushed PR head SHA fetched from GitHub at check time. Absent only
186
- * when GitHub returned no usable 40-hex head (identity kind
187
- * "live-head-invalid"), which is itself a fail-closed blocking state.
188
- */
189
- liveHeadSha?: string;
190
- /**
191
- * Actionable operational notices that do not block the merge, e.g. a PR
192
- * head branch held by a local worktree, which makes
193
- * `gh pr merge --delete-branch` fail (patronage/internal#284).
194
- */
195
- notices?: string[];
196
- pr: number;
197
- status: "pass" | "fail";
198
- /**
199
- * Demands that were in force, were NOT met, and were waived by the operator
200
- * (#354). Each entry carries the demand's refusals verbatim, so a waived
201
- * demand can never read as a met one; the merge proceeds on the recorded
202
- * operator act, not on evidence.
203
- */
204
- waivedDemands?: WaivedDemand[];
205
- /** Present when the PR head branch is checked out in a local worktree. */
206
- worktreeHeldBranch?: WorktreeHeldBranch;
207
- /** All merge-relevant branches held by local worktrees (head and default). */
208
- worktreeHeldBranches?: WorktreeHeldBranch[];
209
- }
210
- //#endregion
211
112
  //#region src/diff-classification.d.ts
212
113
  declare const DIFF_CLASSIFICATIONS: readonly ["docs/process-only", "trivial", "non-trivial"];
213
114
  type DiffClassification = (typeof DIFF_CLASSIFICATIONS)[number];
@@ -252,6 +153,10 @@ interface ReviewFindingAttributes {
252
153
  title: string;
253
154
  }
254
155
  //#endregion
156
+ //#region src/review-rungs.d.ts
157
+ declare const EVIDENCE_REVIEW_RUNGS: readonly ["independent-model", "oracle", "human"];
158
+ type EvidenceReviewRung = (typeof EVIDENCE_REVIEW_RUNGS)[number];
159
+ //#endregion
255
160
  //#region src/review-ladder-ledger.d.ts
256
161
  type LadderCycleStage = "interior" | "gate";
257
162
  type LadderFindingReport = ReviewFindingAttributes;
@@ -371,12 +276,11 @@ declare const managedReadinessLedgerSchema: z.ZodObject<{
371
276
  name: z.ZodString;
372
277
  reason: z.ZodOptional<z.ZodString>;
373
278
  scope: z.ZodOptional<z.ZodObject<{
374
- classifications: z.ZodOptional<z.ZodArray<z.ZodEnum<{
279
+ classifications: z.ZodArray<z.ZodEnum<{
375
280
  "docs/process-only": "docs/process-only";
376
281
  trivial: "trivial";
377
282
  "non-trivial": "non-trivial";
378
- }>>>;
379
- labels: z.ZodOptional<z.ZodArray<z.ZodString>>;
283
+ }>>;
380
284
  }, z.core.$strict>>;
381
285
  scopeReason: z.ZodString;
382
286
  status: z.ZodEnum<{
@@ -577,7 +481,20 @@ type ManagedReadinessLedger = z.infer<typeof managedReadinessLedgerSchema>;
577
481
  //#endregion
578
482
  //#region src/pr-ready.d.ts
579
483
  interface PrReadyProof {
580
- schemaVersion: 2;
484
+ schemaVersion: 3;
485
+ /**
486
+ * What GitHub actually did when this run armed native auto-merge (#477).
487
+ * Present exactly when readiness passed and the arming ran; read back from
488
+ * the PR rather than inferred from the invocation, because `gh pr merge
489
+ * --auto` arms, merges, or does nothing with the same exit code and the same
490
+ * empty output. `not-armed` means the candidate is admitted but nothing will
491
+ * merge it, and `followUp` carries the re-dispatch.
492
+ */
493
+ arming?: {
494
+ detail?: string;
495
+ headSha: string;
496
+ outcome: "armed" | "merged" | "not-armed";
497
+ };
581
498
  /**
582
499
  * Why this run blocked, one entry per refusing demand (#391): `code` is the
583
500
  * demand key from the resolver's vocabulary, `detail` the one-sentence
@@ -590,11 +507,12 @@ interface PrReadyProof {
590
507
  humanBlockingReasons: string[];
591
508
  command: "patronage-factory pr:ready";
592
509
  /**
593
- * Machine-safe arg array for the obvious next action (#523): when `ready`,
594
- * the `pr:merge-check` that must precede a merge; otherwise the `pr:verify`
595
- * re-run that the blocking reasons name (re-verify the head, then re-run
596
- * pr:ready). Same `argv` shape `factory:delegate --print` emits. Optional
597
- * and purely additive.
510
+ * Machine-safe arg array for the obvious next action (#523): when `ready`
511
+ * but arming did not take effect, a `pr:ready` re-dispatch (idempotent on
512
+ * an unchanged head); otherwise the `gh pr ready` undraft repair or the
513
+ * `pr:verify` re-run that the blocking reasons name (re-verify the head,
514
+ * then re-run pr:ready). Same `argv` shape `factory:delegate --print`
515
+ * emits. Optional and purely additive.
598
516
  */
599
517
  followUp?: FollowUpAction;
600
518
  /**
@@ -604,6 +522,12 @@ interface PrReadyProof {
604
522
  * pushed HEAD, not a re-derivation. See the ledger schema.
605
523
  */
606
524
  ledger: ManagedReadinessLedger;
525
+ /**
526
+ * Actionable facts that did not block (#477): a settling merge-freeze
527
+ * generation that armed with a notice, and how each waived demand reads to a
528
+ * human. Absent when there are none.
529
+ */
530
+ notices?: string[];
607
531
  /** Committed profile blob evaluated by readiness. Required for merge. */
608
532
  profileBlobSha?: string;
609
533
  /** Checkout-relative committed profile path evaluated by readiness. */
@@ -612,6 +536,13 @@ interface PrReadyProof {
612
536
  /** Trusted checkout repository used for all GitHub reads and writes. */
613
537
  repository?: string;
614
538
  status: ReadinessStatus;
539
+ /**
540
+ * Demands that were in force, were NOT met, and were waived by the operator
541
+ * (#354, moved here from the merge-time proof by #477). Each entry carries
542
+ * the demand's refusals verbatim, so a waived demand can never read as a met
543
+ * one; the arming proceeds on the recorded operator act, not on evidence.
544
+ */
545
+ waivedDemands?: WaivedDemand[];
615
546
  }
616
547
  //#endregion
617
548
  //#region src/pr-readiness/external-evidence.d.ts
@@ -1296,64 +1227,24 @@ declare const boundaryCheckProofSchema: z.ZodObject<{
1296
1227
  }>;
1297
1228
  }, z.core.$strip>;
1298
1229
  type BoundaryCheckProofRecord = z.infer<typeof boundaryCheckProofSchema>;
1299
- declare const PR_MERGE_CHECK_SCHEMA_VERSION = 1;
1300
- declare const prMergeCheckProofSchema: z.ZodObject<{
1301
- blockingReasons: z.ZodArray<z.ZodString>;
1302
- command: z.ZodLiteral<"patronage-factory pr:merge-check">;
1303
- followUp: z.ZodOptional<z.ZodObject<{
1304
- argv: z.ZodArray<z.ZodString>;
1305
- command: z.ZodString;
1306
- }, z.core.$strict>>;
1307
- identity: z.ZodDiscriminatedUnion<[z.ZodObject<{
1308
- headSha: z.ZodString;
1309
- kind: z.ZodLiteral<"match">;
1310
- }, z.core.$strip>, z.ZodObject<{
1311
- kind: z.ZodLiteral<"diverged">;
1312
- liveHeadSha: z.ZodString;
1313
- postProofCommits: z.ZodOptional<z.ZodArray<z.ZodObject<{
1314
- sha: z.ZodString;
1315
- subject: z.ZodString;
1316
- }, z.core.$strip>>>;
1317
- proofHeadSha: z.ZodString;
1318
- }, z.core.$strip>, z.ZodObject<{
1319
- kind: z.ZodLiteral<"live-head-invalid">;
1320
- pr: z.ZodNumber;
1321
- received: z.ZodString;
1322
- }, z.core.$strip>, z.ZodObject<{
1323
- errorDetail: z.ZodOptional<z.ZodString>;
1324
- kind: z.ZodLiteral<"ready-proof-missing">;
1325
- readyProofPath: z.ZodString;
1326
- }, z.core.$strip>, z.ZodObject<{
1327
- kind: z.ZodLiteral<"ready-proof-pr-mismatch">;
1328
- proofPr: z.ZodNumber;
1329
- requestedPr: z.ZodNumber;
1330
- }, z.core.$strip>, z.ZodObject<{
1331
- blockingReasons: z.ZodArray<z.ZodString>;
1332
- kind: z.ZodLiteral<"ready-proof-not-ready">;
1333
- status: z.ZodString;
1334
- }, z.core.$strip>], "kind">;
1335
- liveHeadSha: z.ZodOptional<z.ZodString>;
1336
- notices: z.ZodOptional<z.ZodArray<z.ZodString>>;
1337
- pr: z.ZodNumber;
1338
- schemaVersion: z.ZodLiteral<1>;
1339
- status: z.ZodEnum<{
1340
- pass: "pass";
1341
- fail: "fail";
1342
- }>;
1343
- waivedDemands: z.ZodOptional<z.ZodArray<z.ZodType<WaivedDemand, unknown, z.core.$ZodTypeInternals<WaivedDemand, unknown>>>>;
1344
- worktreeHeldBranch: z.ZodOptional<z.ZodObject<{
1345
- branch: z.ZodString;
1346
- worktreePath: z.ZodString;
1347
- }, z.core.$strip>>;
1348
- }, z.core.$strip>;
1349
- declare const PR_READY_SCHEMA_VERSION = 2;
1230
+ declare const PR_READY_SCHEMA_VERSION = 3;
1350
1231
  /**
1351
- * The pr:ready proof versions a reader still accepts. `pr:ready` emits v2 only
1352
- * (#391) — one current contract — but v1 events were spooled before the bump
1353
- * and HQ must ingest them without degrading, so the wire schema parses both.
1232
+ * The pr:ready proof versions a reader still accepts. `pr:ready` emits v3 only
1233
+ * (#477) — one current contract — but v1 and v2 events were spooled before the
1234
+ * bumps and HQ must ingest them without degrading, so the wire schema parses
1235
+ * all three.
1354
1236
  */
1355
- declare const SUPPORTED_PR_READY_SCHEMA_VERSIONS: readonly [1, 2];
1237
+ declare const SUPPORTED_PR_READY_SCHEMA_VERSIONS: readonly [1, 2, 3];
1356
1238
  declare const prReadyProofSchema: z.ZodObject<{
1239
+ arming: z.ZodOptional<z.ZodObject<{
1240
+ detail: z.ZodOptional<z.ZodString>;
1241
+ headSha: z.ZodString;
1242
+ outcome: z.ZodEnum<{
1243
+ merged: "merged";
1244
+ armed: "armed";
1245
+ "not-armed": "not-armed";
1246
+ }>;
1247
+ }, z.core.$strip>>;
1357
1248
  blockedReasons: z.ZodOptional<z.ZodArray<z.ZodObject<{
1358
1249
  code: z.ZodString;
1359
1250
  detail: z.ZodString;
@@ -1382,12 +1273,11 @@ declare const prReadyProofSchema: z.ZodObject<{
1382
1273
  name: z.ZodString;
1383
1274
  reason: z.ZodOptional<z.ZodString>;
1384
1275
  scope: z.ZodOptional<z.ZodObject<{
1385
- classifications: z.ZodOptional<z.ZodArray<z.ZodEnum<{
1276
+ classifications: z.ZodArray<z.ZodEnum<{
1386
1277
  "docs/process-only": "docs/process-only";
1387
1278
  trivial: "trivial";
1388
1279
  "non-trivial": "non-trivial";
1389
- }>>>;
1390
- labels: z.ZodOptional<z.ZodArray<z.ZodString>>;
1280
+ }>>;
1391
1281
  }, z.core.$strict>>;
1392
1282
  scopeReason: z.ZodString;
1393
1283
  status: z.ZodEnum<{
@@ -1661,6 +1551,7 @@ declare const prReadyProofSchema: z.ZodObject<{
1661
1551
  verifiedHeadSha: z.ZodOptional<z.ZodString>;
1662
1552
  }, z.core.$strip>;
1663
1553
  }, z.core.$strip>;
1554
+ notices: z.ZodOptional<z.ZodArray<z.ZodString>>;
1664
1555
  profileBlobSha: z.ZodOptional<z.ZodString>;
1665
1556
  profilePath: z.ZodOptional<z.ZodString>;
1666
1557
  repairs: z.ZodDefault<z.ZodArray<z.ZodObject<{
@@ -1673,12 +1564,13 @@ declare const prReadyProofSchema: z.ZodObject<{
1673
1564
  command: z.ZodString;
1674
1565
  }, z.core.$strip>>>;
1675
1566
  repository: z.ZodOptional<z.ZodString>;
1676
- schemaVersion: z.ZodNumber & z.ZodType<1 | 2, number, z.core.$ZodTypeInternals<1 | 2, number>>;
1567
+ schemaVersion: z.ZodNumber & z.ZodType<1 | 2 | 3, number, z.core.$ZodTypeInternals<1 | 2 | 3, number>>;
1677
1568
  status: z.ZodEnum<{
1678
1569
  ready: "ready";
1679
1570
  blocked: "blocked";
1680
1571
  "slice-ready/not-final": "slice-ready/not-final";
1681
1572
  }>;
1573
+ waivedDemands: z.ZodOptional<z.ZodArray<z.ZodType<WaivedDemand, unknown, z.core.$ZodTypeInternals<WaivedDemand, unknown>>>>;
1682
1574
  }, z.core.$strip>;
1683
1575
  //#endregion
1684
- export { BLOCKED_REASONS_MAX, BLOCKED_REASON_DETAIL_MAX, BOUNDARY_CHECK_SCHEMA_VERSION, BOUNDARY_REVIEW_PROOF_KIND, type BlockedReason, BoundaryCheckProofRecord, type BoundaryReviewProof, type CloseoutArtifact, EVIDENCE_ENVELOPE_SCHEMA_VERSION, type EvidenceEnvelope, PR_MERGE_CHECK_SCHEMA_VERSION, PR_READY_SCHEMA_VERSION, PR_REVIEW_SCHEMA_VERSION, type ParsedRetroEnvelope, type PrMergeCheckProof, type PrReadyProof, type PrReviewProof, type PrVerifyProof, RETRO_ENVELOPE_SCHEMA_VERSION, RETRO_ENVELOPE_VALIDATORS, RETRO_ENVELOPE_WIRE_BOUNDS, type RetroEnvelope, SUPPORTED_PR_READY_SCHEMA_VERSIONS, SUPPORTED_PR_VERIFY_SCHEMA_VERSIONS, SUPPORTED_RETRO_ENVELOPE_SCHEMA_VERSIONS, type WaivedDemand, blockedReasonSchema, blockedReasonsSchema, boundaryCheckProofSchema, boundaryReviewProofSchema, closeoutArtifactSchema, evidenceEnvelopeSchema, prMergeCheckProofSchema, prReadyProofSchema, prReviewProofSchema, prVerifyProofSchema, retroEnvelopeV1Schema, retroEpicReference, waivedDemandSchema };
1576
+ export { BLOCKED_REASONS_MAX, BLOCKED_REASON_DETAIL_MAX, BOUNDARY_CHECK_SCHEMA_VERSION, BOUNDARY_REVIEW_PROOF_KIND, type BlockedReason, BoundaryCheckProofRecord, type BoundaryReviewProof, type CloseoutArtifact, EVIDENCE_ENVELOPE_SCHEMA_VERSION, type EvidenceEnvelope, PR_READY_SCHEMA_VERSION, PR_REVIEW_SCHEMA_VERSION, type ParsedRetroEnvelope, type PrReadyProof, type PrReviewProof, type PrVerifyProof, RETRO_ENVELOPE_SCHEMA_VERSION, RETRO_ENVELOPE_VALIDATORS, RETRO_ENVELOPE_WIRE_BOUNDS, type RetroEnvelope, SUPPORTED_PR_READY_SCHEMA_VERSIONS, SUPPORTED_PR_VERIFY_SCHEMA_VERSIONS, SUPPORTED_RETRO_ENVELOPE_SCHEMA_VERSIONS, type WaivedDemand, blockedReasonSchema, blockedReasonsSchema, boundaryCheckProofSchema, boundaryReviewProofSchema, closeoutArtifactSchema, evidenceEnvelopeSchema, prReadyProofSchema, prReviewProofSchema, prVerifyProofSchema, retroEnvelopeV1Schema, retroEpicReference, waivedDemandSchema };
package/dist/schemas.js CHANGED
@@ -10,6 +10,13 @@ Object.fromEntries(EVIDENCE_REVIEW_RUNGS$1.map((rung, index) => [rung, index]));
10
10
  //#region src/demand-keys.ts
11
11
  /** The demands that exist at most once per candidate. */
12
12
  const DEMAND_KEYS = {
13
+ /**
14
+ * The boundary wave that authorizes this candidate's merge schedule (#477).
15
+ * In force exactly when GitHub already has auto-merge enabled: a live
16
+ * schedule with no wave demand resolved is an unauthorized merge waiting to
17
+ * happen.
18
+ */
19
+ boundaryWave: "boundary-wave",
13
20
  /** The PR is still a draft. */
14
21
  draft: "draft",
15
22
  /** The candidate is not the intended final human review point. */
@@ -24,6 +31,12 @@ const DEMAND_KEYS = {
24
31
  mergeFreeze: "merge-freeze",
25
32
  /** GitHub's mergeability / merge-state rollup. */
26
33
  mergeState: "merge-state",
34
+ /**
35
+ * A native GitHub approval, demanded when the boundary wave in force does
36
+ * not authorize machine merge (#477). "Green = authorized to merge" is then
37
+ * a property of the branded required check itself.
38
+ */
39
+ nativeApproval: "native-approval",
27
40
  /** The PR body's required rendered sections. */
28
41
  prBodySections: "pr-body-sections",
29
42
  /** A current, head-bound, passing typed `pr:verify` proof. */
@@ -54,7 +67,7 @@ const percentEncode = (character) => {
54
67
  * demand nobody waived, and make HQ count two causes as one.
55
68
  *
56
69
  * Deterministic in both directions of use: the key a `pr:ready` proof records
57
- * is the key a `pr:merge-check` waiver matches.
70
+ * is the key a `pr:ready` waiver matches.
58
71
  */
59
72
  const demandQualifier = (value) => value.replaceAll(/[^A-Za-z0-9._/-]/gu, percentEncode);
60
73
  const FIXED_DEMAND_KEYS = Object.values(DEMAND_KEYS);
@@ -132,7 +145,7 @@ const demandKeySchema = z.string().refine((value) => {
132
145
  * reason codes must come from. A waiver store is durable operator evidence
133
146
  * written before today's vocabulary existed, so tightening its validation
134
147
  * would make an existing record parse as no waiver and let the next write drop
135
- * it. A waiver naming a key nobody resolves is already inert — `pr:merge-check`
148
+ * it. A waiver naming a key nobody resolves is already inert — `pr:ready`
136
149
  * reports it as an unapplied waiver — so nothing is admitted by accepting it.
137
150
  */
138
151
  const waiverDemandKeySchema = z.string().regex(/^[a-z][a-z0-9-]*(?::[A-Za-z0-9._%/-]+)?$/u, "A demand key is a lowercase family, optionally qualified by its resolved value (e.g. review-rung:human).");
@@ -979,67 +992,7 @@ const boundaryCheckProofSchema = z.object({
979
992
  }).optional(),
980
993
  status: z.enum(["ready", "blocked"])
981
994
  });
982
- const mergeGuardIdentitySchema = z.discriminatedUnion("kind", [
983
- z.object({
984
- headSha: z.string().regex(/^[0-9a-f]{40}$/u),
985
- kind: z.literal("match")
986
- }),
987
- z.object({
988
- kind: z.literal("diverged"),
989
- liveHeadSha: z.string().regex(/^[0-9a-f]{40}$/u),
990
- postProofCommits: z.array(z.object({
991
- sha: z.string().min(1),
992
- subject: z.string()
993
- })).optional(),
994
- proofHeadSha: z.string().regex(/^[0-9a-f]{40}$/u)
995
- }),
996
- z.object({
997
- kind: z.literal("live-head-invalid"),
998
- pr: z.number().int().positive(),
999
- received: z.string()
1000
- }),
1001
- z.object({
1002
- errorDetail: z.string().optional(),
1003
- kind: z.literal("ready-proof-missing"),
1004
- readyProofPath: z.string().min(1)
1005
- }),
1006
- z.object({
1007
- kind: z.literal("ready-proof-pr-mismatch"),
1008
- proofPr: z.number().int().positive(),
1009
- requestedPr: z.number().int().positive()
1010
- }),
1011
- z.object({
1012
- blockingReasons: z.array(z.string()),
1013
- kind: z.literal("ready-proof-not-ready"),
1014
- status: z.string().min(1)
1015
- })
1016
- ]);
1017
- const PR_MERGE_CHECK_SCHEMA_VERSION = 1;
1018
- const prMergeCheckProofSchema = z.object({
1019
- blockingReasons: z.array(z.string()),
1020
- command: z.literal("patronage-factory pr:merge-check"),
1021
- followUp: followUpActionSchema.optional(),
1022
- identity: mergeGuardIdentitySchema,
1023
- liveHeadSha: z.string().regex(/^[0-9a-f]{40}$/u).optional(),
1024
- notices: z.array(z.string()).optional(),
1025
- pr: z.number().int().positive(),
1026
- schemaVersion: z.literal(1),
1027
- status: z.enum(["pass", "fail"]),
1028
- waivedDemands: z.array(waivedDemandSchema).optional(),
1029
- worktreeHeldBranch: z.object({
1030
- branch: z.string().min(1),
1031
- worktreePath: z.string().min(1)
1032
- }).optional()
1033
- });
1034
- const requiredCheckScopeSchema = z.object({
1035
- classifications: z.array(z.enum(DIFF_CLASSIFICATIONS)).min(1).optional(),
1036
- labels: z.array(z.string().min(1)).min(1).optional()
1037
- }).strict().superRefine((scope, context) => {
1038
- if (scope.labels === void 0 && scope.classifications === void 0) context.addIssue({
1039
- code: "custom",
1040
- message: "requiredChecks scope must declare at least one condition (labels and/or classifications)."
1041
- });
1042
- });
995
+ const requiredCheckScopeSchema = z.object({ classifications: z.array(z.enum(DIFF_CLASSIFICATIONS)).min(1) }).strict();
1043
996
  const readinessRepairSchema = z.object({
1044
997
  action: z.string().min(1),
1045
998
  code: z.enum([
@@ -1214,21 +1167,36 @@ const managedReadinessLedgerSchema = z.object({
1214
1167
  verifiedHeadSha: z.string().optional()
1215
1168
  })
1216
1169
  });
1217
- const PR_READY_SCHEMA_VERSION = 2;
1170
+ const PR_READY_SCHEMA_VERSION = 3;
1218
1171
  /**
1219
- * The pr:ready proof versions a reader still accepts. `pr:ready` emits v2 only
1220
- * (#391) — one current contract — but v1 events were spooled before the bump
1221
- * and HQ must ingest them without degrading, so the wire schema parses both.
1172
+ * The pr:ready proof versions a reader still accepts. `pr:ready` emits v3 only
1173
+ * (#477) — one current contract — but v1 and v2 events were spooled before the
1174
+ * bumps and HQ must ingest them without degrading, so the wire schema parses
1175
+ * all three.
1222
1176
  */
1223
- const SUPPORTED_PR_READY_SCHEMA_VERSIONS = [1, 2];
1177
+ const SUPPORTED_PR_READY_SCHEMA_VERSIONS = [
1178
+ 1,
1179
+ 2,
1180
+ 3
1181
+ ];
1224
1182
  const prReadySchemaVersionSchema = z.number().refine((value) => SUPPORTED_PR_READY_SCHEMA_VERSIONS.includes(value), { message: `schemaVersion must be one of: ${SUPPORTED_PR_READY_SCHEMA_VERSIONS.join(", ")}` });
1225
1183
  const prReadyProofSchema = z.object({
1184
+ arming: z.object({
1185
+ detail: z.string().min(1).optional(),
1186
+ headSha: z.string().regex(/^[0-9a-f]{40}$/u),
1187
+ outcome: z.enum([
1188
+ "armed",
1189
+ "merged",
1190
+ "not-armed"
1191
+ ])
1192
+ }).optional(),
1226
1193
  blockedReasons: blockedReasonsSchema.optional(),
1227
1194
  blockingReasons: z.array(z.string()),
1228
1195
  command: z.literal("patronage-factory pr:ready"),
1229
1196
  followUp: followUpActionSchema.optional(),
1230
1197
  humanBlockingReasons: z.array(z.string()).default([]),
1231
1198
  ledger: managedReadinessLedgerSchema,
1199
+ notices: z.array(z.string().min(1)).optional(),
1232
1200
  profileBlobSha: z.string().regex(/^[0-9a-f]{40}$/u).optional(),
1233
1201
  profilePath: z.string().min(1).optional(),
1234
1202
  repairs: z.array(readinessRepairSchema).default([]),
@@ -1238,7 +1206,8 @@ const prReadyProofSchema = z.object({
1238
1206
  "ready",
1239
1207
  "blocked",
1240
1208
  "slice-ready/not-final"
1241
- ])
1209
+ ]),
1210
+ waivedDemands: z.array(waivedDemandSchema).optional()
1242
1211
  }).superRefine((proof, context) => {
1243
1212
  if (proof.schemaVersion < 2) {
1244
1213
  if (proof.blockedReasons !== void 0) context.addIssue({
@@ -1254,4 +1223,4 @@ const prReadyProofSchema = z.object({
1254
1223
  })) context.addIssue(issue);
1255
1224
  });
1256
1225
  //#endregion
1257
- export { BLOCKED_REASONS_MAX, BLOCKED_REASON_DETAIL_MAX, BOUNDARY_CHECK_SCHEMA_VERSION, BOUNDARY_REVIEW_PROOF_KIND, EVIDENCE_ENVELOPE_SCHEMA_VERSION, PR_MERGE_CHECK_SCHEMA_VERSION, PR_READY_SCHEMA_VERSION, PR_REVIEW_SCHEMA_VERSION, RETRO_ENVELOPE_SCHEMA_VERSION, RETRO_ENVELOPE_VALIDATORS, RETRO_ENVELOPE_WIRE_BOUNDS, SUPPORTED_PR_READY_SCHEMA_VERSIONS, SUPPORTED_PR_VERIFY_SCHEMA_VERSIONS, SUPPORTED_RETRO_ENVELOPE_SCHEMA_VERSIONS, blockedReasonSchema, blockedReasonsSchema, boundaryCheckProofSchema, boundaryReviewProofSchema, closeoutArtifactSchema, evidenceEnvelopeSchema, prMergeCheckProofSchema, prReadyProofSchema, prReviewProofSchema, prVerifyProofSchema, retroEnvelopeV1Schema, retroEpicReference, waivedDemandSchema };
1226
+ export { BLOCKED_REASONS_MAX, BLOCKED_REASON_DETAIL_MAX, BOUNDARY_CHECK_SCHEMA_VERSION, BOUNDARY_REVIEW_PROOF_KIND, EVIDENCE_ENVELOPE_SCHEMA_VERSION, PR_READY_SCHEMA_VERSION, PR_REVIEW_SCHEMA_VERSION, RETRO_ENVELOPE_SCHEMA_VERSION, RETRO_ENVELOPE_VALIDATORS, RETRO_ENVELOPE_WIRE_BOUNDS, SUPPORTED_PR_READY_SCHEMA_VERSIONS, SUPPORTED_PR_VERIFY_SCHEMA_VERSIONS, SUPPORTED_RETRO_ENVELOPE_SCHEMA_VERSIONS, blockedReasonSchema, blockedReasonsSchema, boundaryCheckProofSchema, boundaryReviewProofSchema, closeoutArtifactSchema, evidenceEnvelopeSchema, prReadyProofSchema, prReviewProofSchema, prVerifyProofSchema, retroEnvelopeV1Schema, retroEpicReference, waivedDemandSchema };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patronage/software-factory",
3
- "version": "0.25.0",
3
+ "version": "0.30.0-alpha.1",
4
4
  "description": "Shared Patronage software factory CLI and project-profile validation tools",
5
5
  "license": "MIT",
6
6
  "repository": {