@patronage/software-factory 1.0.0-alpha.23 → 1.0.0-alpha.24

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
@@ -2,6 +2,7 @@ import { z } from "zod";
2
2
  //#region src/packages/review-prompt-sections/schema.d.ts
3
3
  declare const reviewPromptSectionSchema: z.ZodObject<{
4
4
  provenance: z.ZodEnum<{
5
+ "coding-standards": "coding-standards";
5
6
  "prior-review-ledger": "prior-review-ledger";
6
7
  "issue-review-focus": "issue-review-focus";
7
8
  }>;
@@ -12,6 +13,7 @@ type ReviewPromptSection = z.infer<typeof reviewPromptSectionSchema>;
12
13
  type ReviewPromptSectionProvenance = ReviewPromptSection["provenance"];
13
14
  declare const reviewPromptSectionsSchema: z.ZodArray<z.ZodObject<{
14
15
  provenance: z.ZodEnum<{
16
+ "coding-standards": "coding-standards";
15
17
  "prior-review-ledger": "prior-review-ledger";
16
18
  "issue-review-focus": "issue-review-focus";
17
19
  }>;
@@ -225,21 +227,38 @@ declare const boundaryReviewProofBaseSchema: z.ZodObject<{
225
227
  }, z.core.$loose>;
226
228
  type BoundaryReviewProof = z.infer<typeof boundaryReviewProofBaseSchema>;
227
229
  //#endregion
228
- //#region src/follow-up.d.ts
229
- interface FollowUpAction {
230
- /**
231
- * Machine-safe argv-style array for the obvious next action, e.g.
232
- * ["gh","pr","merge","513","--squash"]. Same shape and field name that
233
- * `factory:delegate --print` emits, so an orchestrating agent can spawn the
234
- * next command without reconstructing a shell string. argv[0] is the
235
- * executable; the rest are literal, already-split arguments.
236
- */
237
- argv: string[];
230
+ //#region src/policy-resolution.d.ts
231
+ /** How a gate resolved the review policy it evaluated a candidate under. */
232
+ declare const policyResolutionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
233
+ basePolicyDigest: z.ZodString;
234
+ baseRefName: z.ZodString;
235
+ candidatePolicyDigest: z.ZodString;
236
+ effectiveDigest: z.ZodString;
237
+ policyBaseSha: z.ZodString;
238
+ reviewPolicyChanged: z.ZodBoolean;
239
+ status: z.ZodLiteral<"authoritative">;
240
+ }, z.core.$strict>, z.ZodObject<{
241
+ baseRefName: z.ZodString;
242
+ reason: z.ZodString;
243
+ status: z.ZodLiteral<"unresolved">;
244
+ }, z.core.$strict>], "status">;
245
+ type PolicyResolution = z.infer<typeof policyResolutionSchema>;
246
+ //#endregion
247
+ //#region src/catch-up-recognition-record.d.ts
248
+ interface CatchUpRecognition {
249
+ /** The ref the candidate targets, as the recognizing command resolved it. */
250
+ baseRef: string;
251
+ /** The live target tip at recognition time; the head's first parent. */
252
+ baseTipSha: string;
253
+ /** The head's second parent: the admitted base-side content merged in. */
254
+ mergedParentSha: string;
238
255
  /**
239
- * Human-readable rendering of {@link argv} for logs and operators. Additive
240
- * to argv, never a substitute for it — argv is the source of truth.
256
+ * The tree `git merge-tree --write-tree` produced for the two parents. It
257
+ * equals the head's own tree; that equality is the faithfulness proof.
241
258
  */
242
- command: string;
259
+ mergedTreeSha: string;
260
+ /** The ref that proves the second parent is admitted content. */
261
+ upstreamRef: string;
243
262
  }
244
263
  //#endregion
245
264
  //#region src/diff-classification.d.ts
@@ -274,6 +293,23 @@ declare const impactStampSchema: z.ZodObject<{
274
293
  }, z.core.$strip>;
275
294
  type ImpactStamp = z.infer<typeof impactStampSchema>;
276
295
  //#endregion
296
+ //#region src/follow-up.d.ts
297
+ interface FollowUpAction {
298
+ /**
299
+ * Machine-safe argv-style array for the obvious next action, e.g.
300
+ * ["gh","pr","merge","513","--squash"]. Same shape and field name that
301
+ * `factory:delegate --print` emits, so an orchestrating agent can spawn the
302
+ * next command without reconstructing a shell string. argv[0] is the
303
+ * executable; the rest are literal, already-split arguments.
304
+ */
305
+ argv: string[];
306
+ /**
307
+ * Human-readable rendering of {@link argv} for logs and operators. Additive
308
+ * to argv, never a substitute for it — argv is the source of truth.
309
+ */
310
+ command: string;
311
+ }
312
+ //#endregion
277
313
  //#region src/pr-verify-mode.d.ts
278
314
  /**
279
315
  * The verification mode `pr:verify` resolved for a run.
@@ -388,12 +424,12 @@ declare const managedReadinessLedgerSchema: z.ZodObject<{
388
424
  "interior-cap-reached": "interior-cap-reached";
389
425
  }>>;
390
426
  nextAction: z.ZodEnum<{
391
- "run-interior-cycle": "run-interior-cycle";
392
- "advance-to-gate": "advance-to-gate";
393
427
  "run-gate-cycle": "run-gate-cycle";
394
428
  "accept-nonblocking-findings": "accept-nonblocking-findings";
395
429
  "escalate-to-triage": "escalate-to-triage";
396
430
  "ready-for-human": "ready-for-human";
431
+ "advance-to-gate": "advance-to-gate";
432
+ "run-interior-cycle": "run-interior-cycle";
397
433
  }>;
398
434
  stage: z.ZodEnum<{
399
435
  gate: "gate";
@@ -461,23 +497,6 @@ type ReadinessRepair = z.infer<typeof readinessRepairSchema>;
461
497
  type ReadinessStatus = "ready" | "blocked";
462
498
  type ManagedReadinessLedger = z.infer<typeof managedReadinessLedgerSchema>;
463
499
  //#endregion
464
- //#region src/catch-up-recognition-record.d.ts
465
- interface CatchUpRecognition {
466
- /** The ref the candidate targets, as the recognizing command resolved it. */
467
- baseRef: string;
468
- /** The live target tip at recognition time; the head's first parent. */
469
- baseTipSha: string;
470
- /** The head's second parent: the admitted base-side content merged in. */
471
- mergedParentSha: string;
472
- /**
473
- * The tree `git merge-tree --write-tree` produced for the two parents. It
474
- * equals the head's own tree; that equality is the faithfulness proof.
475
- */
476
- mergedTreeSha: string;
477
- /** The ref that proves the second parent is admitted content. */
478
- upstreamRef: string;
479
- }
480
- //#endregion
481
500
  //#region src/pr-verify-proof-contract.d.ts
482
501
  declare const SUPPORTED_PR_VERIFY_SCHEMA_VERSIONS: readonly [1, 2, 3, 4];
483
502
  type PrVerifySchemaVersion = (typeof SUPPORTED_PR_VERIFY_SCHEMA_VERSIONS)[number];
@@ -713,6 +732,13 @@ interface PrReadyProof {
713
732
  * waived demand reads to a human. Absent when there are none.
714
733
  */
715
734
  notices?: string[];
735
+ /**
736
+ * The policy identity readiness resolved review demand under (#922): the
737
+ * base ref, its live tip, and the digests of the base, candidate, and merged
738
+ * review policies. Optional on the wire and additive — this is a new record
739
+ * on an unchanged contract, so no schema version moves.
740
+ */
741
+ policyResolution?: PolicyResolution;
716
742
  /** Committed profile blob evaluated by readiness. Required for merge. */
717
743
  profileBlobSha?: string;
718
744
  /** Checkout-relative committed profile path evaluated by readiness. */
@@ -1086,20 +1112,18 @@ declare const prReadyProofSchema: z.ZodObject<{
1086
1112
  forcedTransition: z.ZodOptional<z.ZodEnum<{
1087
1113
  "gate-cap-exhausted": "gate-cap-exhausted";
1088
1114
  "interior-cap-reached": "interior-cap-reached";
1089
- "interior-takeover": "interior-takeover";
1090
1115
  }>>;
1091
1116
  nextAction: z.ZodEnum<{
1092
- "run-interior-cycle": "run-interior-cycle";
1093
- "advance-to-gate": "advance-to-gate";
1094
1117
  "run-gate-cycle": "run-gate-cycle";
1095
1118
  "accept-nonblocking-findings": "accept-nonblocking-findings";
1096
1119
  "escalate-to-triage": "escalate-to-triage";
1097
1120
  "ready-for-human": "ready-for-human";
1121
+ "advance-to-gate": "advance-to-gate";
1122
+ "run-interior-cycle": "run-interior-cycle";
1098
1123
  }>;
1099
1124
  stage: z.ZodEnum<{
1100
1125
  gate: "gate";
1101
1126
  interior: "interior";
1102
- "interior-takeover": "interior-takeover";
1103
1127
  "interior-complete": "interior-complete";
1104
1128
  }>;
1105
1129
  }, z.core.$strip>>;
@@ -1166,6 +1190,19 @@ declare const prReadyProofSchema: z.ZodObject<{
1166
1190
  }, z.core.$strict>], "prVerify">;
1167
1191
  }, z.core.$strip>;
1168
1192
  notices: z.ZodOptional<z.ZodArray<z.ZodString>>;
1193
+ policyResolution: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
1194
+ basePolicyDigest: z.ZodString;
1195
+ baseRefName: z.ZodString;
1196
+ candidatePolicyDigest: z.ZodString;
1197
+ effectiveDigest: z.ZodString;
1198
+ policyBaseSha: z.ZodString;
1199
+ reviewPolicyChanged: z.ZodBoolean;
1200
+ status: z.ZodLiteral<"authoritative">;
1201
+ }, z.core.$strict>, z.ZodObject<{
1202
+ baseRefName: z.ZodString;
1203
+ reason: z.ZodString;
1204
+ status: z.ZodLiteral<"unresolved">;
1205
+ }, z.core.$strict>], "status">>;
1169
1206
  profileBlobSha: z.ZodOptional<z.ZodString>;
1170
1207
  profilePath: z.ZodOptional<z.ZodString>;
1171
1208
  repairs: z.ZodDefault<z.ZodArray<z.ZodObject<{
package/dist/schemas.js CHANGED
@@ -2,12 +2,12 @@ import { z } from "zod";
2
2
  import "yaml";
3
3
  import "picomatch";
4
4
  //#region src/review-rungs.ts
5
- const EVIDENCE_REVIEW_RUNGS$1 = [
5
+ const EVIDENCE_REVIEW_RUNGS = [
6
6
  "independent-model",
7
7
  "oracle",
8
8
  "human"
9
9
  ];
10
- Object.fromEntries(EVIDENCE_REVIEW_RUNGS$1.map((rung, index) => [rung, index]));
10
+ Object.fromEntries(EVIDENCE_REVIEW_RUNGS.map((rung, index) => [rung, index]));
11
11
  //#endregion
12
12
  //#region src/demand-keys.ts
13
13
  /** The demands that exist at most once per candidate. */
@@ -116,7 +116,7 @@ const qualifierIsMintable = (family, qualifier) => {
116
116
  if (!QUALIFIER_PATTERN.test(qualifier)) return false;
117
117
  const decoded = decodeQualifier(qualifier);
118
118
  if (decoded === void 0 || demandQualifier(decoded) !== qualifier) return false;
119
- if (family === "review-rung") return EVIDENCE_REVIEW_RUNGS$1.includes(decoded);
119
+ if (family === "review-rung") return EVIDENCE_REVIEW_RUNGS.includes(decoded);
120
120
  if (family === "review-mode") return REVIEW_MODE_DEMAND_VALUES.includes(decoded);
121
121
  return true;
122
122
  };
@@ -234,8 +234,71 @@ const waivedDemandSchema = z.object({
234
234
  unmetReasons: z.array(z.string().min(1)).min(1)
235
235
  });
236
236
  //#endregion
237
+ //#region src/diff-classification.ts
238
+ const DIFF_CLASSIFICATIONS = [
239
+ "docs/process-only",
240
+ "trivial",
241
+ "non-trivial"
242
+ ];
243
+ //#endregion
244
+ //#region src/policy-resolution.ts
245
+ const COMMIT_SHA_PATTERN = /^[0-9a-f]{40}$/u;
246
+ const digestSchema = z.string().regex(/^[0-9a-f]{64}$/u);
247
+ /**
248
+ * The authority resolved: the live tip of the PR's own base ref served a
249
+ * parseable profile, and demand was resolved from the union of that policy and
250
+ * the candidate's.
251
+ *
252
+ * Every identity field is REQUIRED. A cross-stage reader compares these digests
253
+ * to decide whether two stages judged the same candidate under the same policy;
254
+ * an `authoritative` record with a digest missing would read to that reader as
255
+ * "nothing disagrees", which is a silent downgrade of exactly the demand this
256
+ * record exists to protect. `reason` is forbidden here — a resolved authority
257
+ * has nothing to explain.
258
+ */
259
+ const authoritativePolicyResolutionSchema = z.object({
260
+ /** sha256 of the canonical base `review` subtree. */
261
+ basePolicyDigest: digestSchema,
262
+ /** The PR's own base ref, whose live tip is the authority. */
263
+ baseRefName: z.string().min(1),
264
+ /** sha256 of the canonical candidate `review` subtree. */
265
+ candidatePolicyDigest: digestSchema,
266
+ /** sha256 of the merged (base ∪ candidate) protected-path set. */
267
+ effectiveDigest: digestSchema,
268
+ /** The base-ref tip the base policy was read at. */
269
+ policyBaseSha: z.string().regex(COMMIT_SHA_PATTERN),
270
+ /**
271
+ * Whether the candidate's `review` subtree differs from the base's. The
272
+ * digests prove which policies were read; this says whether they agreed,
273
+ * which is the fact that explains a demand the candidate's own profile
274
+ * would not have produced.
275
+ */
276
+ reviewPolicyChanged: z.boolean(),
277
+ status: z.literal("authoritative")
278
+ }).strict();
279
+ /**
280
+ * The authority could not be read, and `reason` says why — required, because an
281
+ * unresolved record with no reason is an unactionable refusal. `pr:ready`
282
+ * refuses before it writes a proof, so a Slice A ready proof never carries one;
283
+ * this member is the recorded form of that refusal for the stages that carry it
284
+ * forward.
285
+ */
286
+ const unresolvedPolicyResolutionSchema = z.object({
287
+ /** The base ref whose policy could not be read. */
288
+ baseRefName: z.string().min(1),
289
+ /** Why the authority is unresolved. */
290
+ reason: z.string().min(1),
291
+ status: z.literal("unresolved")
292
+ }).strict();
293
+ /** How a gate resolved the review policy it evaluated a candidate under. */
294
+ const policyResolutionSchema = z.discriminatedUnion("status", [authoritativePolicyResolutionSchema, unresolvedPolicyResolutionSchema]);
295
+ //#endregion
237
296
  //#region src/packages/review-prompt-sections/schema.ts
238
- const REVIEW_PROMPT_SECTION_PROVENANCES = ["prior-review-ledger", "issue-review-focus"];
297
+ const REVIEW_PROMPT_SECTION_PROVENANCES = [
298
+ "coding-standards",
299
+ "prior-review-ledger",
300
+ "issue-review-focus"
301
+ ];
239
302
  const nonBlankString$1 = z.string().refine((value) => value.trim().length > 0, { message: "must not be blank" });
240
303
  const reviewPromptSectionSchema = z.object({
241
304
  provenance: z.enum(REVIEW_PROMPT_SECTION_PROVENANCES),
@@ -617,6 +680,20 @@ z.array(z.object({
617
680
  }).strict());
618
681
  //#endregion
619
682
  //#region src/review-ladder.ts
683
+ const LADDER_NEXT_ACTION_KINDS = [
684
+ "run-interior-cycle",
685
+ "advance-to-gate",
686
+ "run-gate-cycle",
687
+ "accept-nonblocking-findings",
688
+ "escalate-to-triage",
689
+ "ready-for-human"
690
+ ];
691
+ const LADDER_STAGES = [
692
+ "interior",
693
+ "interior-complete",
694
+ "gate"
695
+ ];
696
+ const LADDER_FORCED_TRANSITION_KINDS = ["gate-cap-exhausted", "interior-cap-reached"];
620
697
  const ladderCycleRefsFor = (cycles) => {
621
698
  let interior = 0;
622
699
  let gate = 0;
@@ -685,7 +762,7 @@ const prReviewResultSchema = z.object({
685
762
  ]),
686
763
  producer: nonBlankString.optional(),
687
764
  promptSections: reviewPromptSectionsSchema.optional(),
688
- rung: z.enum(EVIDENCE_REVIEW_RUNGS$1).optional(),
765
+ rung: z.enum(EVIDENCE_REVIEW_RUNGS).optional(),
689
766
  sessionId: nonBlankString.optional(),
690
767
  startedAt: parseableDateString,
691
768
  summary: z.string().refine((value) => value.trim().length > 0 && value !== "<one sentence>", { message: "summary must not be blank or a placeholder" }),
@@ -751,6 +828,17 @@ const prReviewProofSchema = z.object({
751
828
  });
752
829
  });
753
830
  //#endregion
831
+ //#region src/required-check-policy.ts
832
+ const EVIDENCE_CHECK_TYPES = ["review", "verify"];
833
+ const requiredCheckScopeSchema = z.object({ classifications: z.array(z.enum(DIFF_CLASSIFICATIONS)).min(1) }).strict();
834
+ const reviewStatusSchema = z.enum([
835
+ "not-required",
836
+ "current",
837
+ "stale",
838
+ "missing",
839
+ "blocked"
840
+ ]);
841
+ //#endregion
754
842
  //#region src/review-state.ts
755
843
  const reviewStateIssue = (message, field) => [{
756
844
  code: "custom",
@@ -1228,24 +1316,12 @@ const closeoutArtifactSchema = z.object({
1228
1316
  }).strict();
1229
1317
  //#endregion
1230
1318
  //#region src/schemas.ts
1231
- const EVIDENCE_CHECK_TYPES = ["review", "verify"];
1232
- const EVIDENCE_REVIEW_RUNGS = [
1233
- "independent-model",
1234
- "oracle",
1235
- "human"
1236
- ];
1237
- const DIFF_CLASSIFICATIONS = [
1238
- "docs/process-only",
1239
- "trivial",
1240
- "non-trivial"
1241
- ];
1242
- const REVIEW_STATUS_VALUES = [
1243
- "not-required",
1244
- "current",
1245
- "stale",
1246
- "missing",
1247
- "blocked"
1248
- ];
1319
+ const evidenceCheckTypeSchema = z.enum(EVIDENCE_CHECK_TYPES);
1320
+ const evidenceReviewRungSchema = z.enum(EVIDENCE_REVIEW_RUNGS);
1321
+ const diffClassificationSchema = z.enum(DIFF_CLASSIFICATIONS);
1322
+ const ladderStageSchema = z.enum(LADDER_STAGES);
1323
+ const ladderNextActionSchema = z.enum(LADDER_NEXT_ACTION_KINDS);
1324
+ const ladderForcedTransitionSchema = z.enum(LADDER_FORCED_TRANSITION_KINDS);
1249
1325
  const followUpActionSchema = z.object({
1250
1326
  argv: z.array(z.string()),
1251
1327
  command: z.string()
@@ -1254,7 +1330,7 @@ const EVIDENCE_ENVELOPE_SCHEMA_VERSION = 1;
1254
1330
  const evidenceShaSchema = z.string().regex(/^[0-9a-f]{7,40}$/u, { message: "must be a 7-40 char lowercase hex git SHA" });
1255
1331
  const evidenceEnvelopeSchema = z.object({
1256
1332
  check: z.string().min(1),
1257
- checkType: z.enum(EVIDENCE_CHECK_TYPES),
1333
+ checkType: evidenceCheckTypeSchema,
1258
1334
  findingsPointer: z.string().min(1).optional(),
1259
1335
  headSha: evidenceShaSchema,
1260
1336
  mergeBaseSha: evidenceShaSchema,
@@ -1264,7 +1340,7 @@ const evidenceEnvelopeSchema = z.object({
1264
1340
  policyVersion: z.string().min(1).optional(),
1265
1341
  producer: z.string().min(1),
1266
1342
  requestId: z.string().min(1).optional(),
1267
- rung: z.enum(EVIDENCE_REVIEW_RUNGS).optional(),
1343
+ rung: evidenceReviewRungSchema.optional(),
1268
1344
  schemaVersion: z.literal(1),
1269
1345
  sessionId: z.string().trim().min(1).optional(),
1270
1346
  timestamp: z.iso.datetime().optional()
@@ -1327,7 +1403,7 @@ const boundaryReviewProofSchema = z.object({
1327
1403
  }).passthrough(),
1328
1404
  outcome: z.enum(["pass", "fail"]),
1329
1405
  producer: z.string().min(1),
1330
- rung: z.enum(EVIDENCE_REVIEW_RUNGS),
1406
+ rung: evidenceReviewRungSchema,
1331
1407
  schemaVersion: z.literal(1),
1332
1408
  sessionId: z.string().min(1).optional(),
1333
1409
  specHash: z.object({
@@ -1348,7 +1424,7 @@ const boundaryCheckProofSchema = z.object({
1348
1424
  state: z.enum(["merged", "open"]),
1349
1425
  wave: z.string().min(1)
1350
1426
  })),
1351
- demandedRung: z.enum(EVIDENCE_REVIEW_RUNGS).optional(),
1427
+ demandedRung: evidenceReviewRungSchema.optional(),
1352
1428
  epicIssue: z.number().int().positive(),
1353
1429
  manifestHash: z.object({
1354
1430
  algo: z.literal("sha256"),
@@ -1360,7 +1436,7 @@ const boundaryCheckProofSchema = z.object({
1360
1436
  commentId: z.union([z.string(), z.number()]).optional(),
1361
1437
  commentUrl: z.string().optional(),
1362
1438
  producer: z.string().min(1),
1363
- rung: z.enum(EVIDENCE_REVIEW_RUNGS),
1439
+ rung: evidenceReviewRungSchema,
1364
1440
  sessionId: z.string().min(1).optional(),
1365
1441
  specHash: z.object({
1366
1442
  algo: z.literal("sha256"),
@@ -1375,7 +1451,6 @@ const boundaryCheckProofSchema = z.object({
1375
1451
  }).optional(),
1376
1452
  status: z.enum(["ready", "blocked"])
1377
1453
  });
1378
- const requiredCheckScopeSchema = z.object({ classifications: z.array(z.enum(DIFF_CLASSIFICATIONS)).min(1) }).strict();
1379
1454
  const readinessRepairSchema = z.object({
1380
1455
  action: z.string().min(1),
1381
1456
  code: z.enum([
@@ -1389,7 +1464,7 @@ const reviewStateSchema = z.object({
1389
1464
  required: z.boolean(),
1390
1465
  reviewedHeadSha: z.string().optional(),
1391
1466
  reviewedPatchId: z.string().optional(),
1392
- status: z.enum(REVIEW_STATUS_VALUES)
1467
+ status: reviewStatusSchema
1393
1468
  }).strict().superRefine((state, context) => {
1394
1469
  for (const issue of reviewStateIssues(state)) context.addIssue(issue);
1395
1470
  });
@@ -1410,9 +1485,9 @@ const historicalHandledHumanCommentSchema = z.object({
1410
1485
  const managedReadinessLedgerSchema = z.object({
1411
1486
  baseSha: z.string().regex(/^[0-9a-f]{40}$/u),
1412
1487
  blockingReasons: z.array(z.string()),
1413
- classification: z.enum(DIFF_CLASSIFICATIONS),
1488
+ classification: diffClassificationSchema,
1414
1489
  externalChecks: z.array(z.object({
1415
- checkType: z.enum(EVIDENCE_CHECK_TYPES),
1490
+ checkType: evidenceCheckTypeSchema,
1416
1491
  name: z.string().min(1),
1417
1492
  reason: z.string().optional(),
1418
1493
  scope: requiredCheckScopeSchema.optional(),
@@ -1485,25 +1560,9 @@ const managedReadinessLedgerSchema = z.object({
1485
1560
  gate: z.number().int().nonnegative(),
1486
1561
  interior: z.number().int().nonnegative()
1487
1562
  }),
1488
- forcedTransition: z.enum([
1489
- "gate-cap-exhausted",
1490
- "interior-cap-reached",
1491
- "interior-takeover"
1492
- ]).optional(),
1493
- nextAction: z.enum([
1494
- "run-interior-cycle",
1495
- "advance-to-gate",
1496
- "run-gate-cycle",
1497
- "accept-nonblocking-findings",
1498
- "escalate-to-triage",
1499
- "ready-for-human"
1500
- ]),
1501
- stage: z.enum([
1502
- "interior",
1503
- "interior-takeover",
1504
- "interior-complete",
1505
- "gate"
1506
- ])
1563
+ forcedTransition: ladderForcedTransitionSchema.optional(),
1564
+ nextAction: ladderNextActionSchema,
1565
+ stage: ladderStageSchema
1507
1566
  }).optional(),
1508
1567
  reviewRuns: z.array(prReviewResultSchema).optional(),
1509
1568
  reviewTerminalState: z.enum([
@@ -1580,6 +1639,7 @@ const prReadyProofSchema = z.object({
1580
1639
  humanBlockingReasons: z.array(z.string()).default([]),
1581
1640
  ledger: managedReadinessLedgerSchema,
1582
1641
  notices: z.array(z.string().min(1)).optional(),
1642
+ policyResolution: policyResolutionSchema.optional(),
1583
1643
  profileBlobSha: z.string().regex(/^[0-9a-f]{40}$/u).optional(),
1584
1644
  profilePath: z.string().min(1).optional(),
1585
1645
  repairs: z.array(readinessRepairSchema).default([]),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patronage/software-factory",
3
- "version": "1.0.0-alpha.23",
3
+ "version": "1.0.0-alpha.24",
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.23"
40
+ "@patronage/factory-ci": "1.0.0-alpha.24"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/node": "24.13.3",