@patronage/software-factory 0.30.0-alpha.1 → 0.30.0-beta.3

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.js CHANGED
@@ -19,34 +19,28 @@ const DEMAND_KEYS = {
19
19
  boundaryWave: "boundary-wave",
20
20
  /** The PR is still a draft. */
21
21
  draft: "draft",
22
- /** The candidate is not the intended final human review point. */
23
- finalReviewPoint: "final-review-point",
24
22
  /** GitHub's own check rollup for the candidate head. */
25
23
  githubChecks: "github-checks",
26
24
  /** Local HEAD and the GitHub PR head must be the same commit. */
27
25
  headIdentity: "head-identity",
28
- /** An unhandled post-readiness human comment or review submission. */
26
+ /** GitHub's live aggregate review decision is CHANGES_REQUESTED. */
29
27
  humanBlocker: "human-blocker",
30
28
  /** The repository-wide merge freeze. */
31
29
  mergeFreeze: "merge-freeze",
32
30
  /** GitHub's mergeability / merge-state rollup. */
33
31
  mergeState: "merge-state",
34
32
  /**
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.
33
+ * Retired readiness demand, retained solely to parse historical v3 proofs
34
+ * and their HQ payloads. No current command emits it: GitHub approval is
35
+ * neither a review-rung authority nor a scheduling requirement.
38
36
  */
39
37
  nativeApproval: "native-approval",
40
- /** The PR body's required rendered sections. */
41
- prBodySections: "pr-body-sections",
42
38
  /** A current, head-bound, passing typed `pr:verify` proof. */
43
39
  prVerify: "pr-verify",
44
40
  /** The profile-resolved review ladder policy. */
45
41
  reviewLadder: "review-ladder",
46
42
  /** Unresolved GitHub review threads. */
47
- reviewThreads: "review-threads",
48
- /** An explicit trivial waiver that the diff does not support. */
49
- trivialWaiver: "trivial-waiver"
43
+ reviewThreads: "review-threads"
50
44
  };
51
45
  /** The families whose instances are named by a resolved value. */
52
46
  const QUALIFIED_DEMAND_FAMILIES = [
@@ -188,29 +182,18 @@ const blockedReasonIssue = (message) => [{
188
182
  * wire schema so it is one rule rather than two that can drift. It is the
189
183
  * producer's state machine, written down:
190
184
  *
191
- * - `ready` refused nothing, so it carries neither projection, and it is the
192
- * final review point;
193
- * - `slice-ready/not-final` was held back by exactly one demand — being a
194
- * slice — and names it;
195
- * - `blocked` refused something other than being a slice, and says so;
185
+ * - `ready` refused nothing, so it carries neither projection;
186
+ * - `blocked` refused something and says so;
196
187
  * - whichever it is, `blockedReasons` names every refusal listed in
197
188
  * `blockingReasons`, in the same order, as the bounded form of that sentence.
198
189
  *
199
- * Naming the slice demand and the ledger's `finalReviewPoint` are the same
200
- * fact, so a proof that says one and not the other is refused.
201
190
  */
202
191
  const blockedReasonIssues = (proof) => {
203
192
  const named = proof.blockedReasons ?? [];
204
193
  const reasons = proof.blockingReasons ?? [];
205
- const slice = DEMAND_KEYS.finalReviewPoint;
206
- const namesSlice = named.some((reason) => reason.code === slice);
207
194
  if (proof.status === "ready") {
208
195
  if (named.length > 0 || reasons.length > 0) return blockedReasonIssue("a ready pr:ready proof must carry no blocking reasons");
209
- } else if (proof.status === "slice-ready/not-final") {
210
- if (named.length !== 1 || !namesSlice) return blockedReasonIssue(`a slice-ready/not-final pr:ready proof is held back by exactly one demand, ${slice}`);
211
196
  } else if (reasons.length === 0) return blockedReasonIssue("a blocked pr:ready proof must record what blocked it");
212
- else if (named.length > 0 && !named.some((r) => r.code !== slice)) return blockedReasonIssue(`a blocked pr:ready proof must name a demand other than ${slice}`);
213
- if (proof.finalReviewPoint !== void 0 && namesSlice === proof.finalReviewPoint) return blockedReasonIssue(`naming ${slice} and the ledger's finalReviewPoint are the same fact; this proof says both`);
214
197
  if (named.length !== reasons.length) return blockedReasonIssue(`blockedReasons must name every blocking reason: ${reasons.length} reason(s), ${named.length} named`);
215
198
  const drifted = named.findIndex((reason, index) => reason.detail !== blockedReasonDetail(reasons[index]));
216
199
  return drifted === -1 ? [] : blockedReasonIssue(`blockedReasons[${drifted}] does not carry blocking reason ${drifted}; the two projections must tell one story`);
@@ -228,7 +211,7 @@ const demandWaiverSchema = z.object({
228
211
  operator: z.string().trim().min(1),
229
212
  rationale: z.string().trim().min(1),
230
213
  recordedAt: z.iso.datetime(),
231
- session: z.string().trim().min(1)
214
+ session: z.string().trim().min(1).optional()
232
215
  });
233
216
  z.object({
234
217
  command: z.literal("patronage-factory demand:waive"),
@@ -240,9 +223,12 @@ const waivedDemandSchema = z.object({
240
223
  operator: z.string().trim().min(1),
241
224
  rationale: z.string().trim().min(1),
242
225
  recordedAt: z.iso.datetime(),
243
- session: z.string().trim().min(1),
226
+ session: z.string().trim().min(1).optional(),
244
227
  unmetReasons: z.array(z.string().min(1)).min(1)
245
228
  });
229
+ const LEGACY_CLOSEOUT_SCHEMA_VERSION = 3;
230
+ /** Current writer plus retained reader versions accepted at ingest. */
231
+ const SUPPORTED_CLOSEOUT_SCHEMA_VERSIONS = [LEGACY_CLOSEOUT_SCHEMA_VERSION, 4];
246
232
  const MAX_CLOSEOUT_ROWS = 1e3;
247
233
  const IdentifierSchema = z.string().min(1).max(500);
248
234
  const NarrativeSchema = z.string().min(1).max(1e4);
@@ -254,11 +240,15 @@ const CloseoutLandingSpotSchema = z.enum([
254
240
  "skill",
255
241
  "ADR"
256
242
  ]);
257
- const CloseoutSourceSchema = z.object({
243
+ const CurrentCloseoutSourceSchema = z.object({
244
+ detail: NarrativeSchema,
245
+ kind: z.literal("boundary-thermo-attestation")
246
+ }).strict();
247
+ const LegacyCloseoutSourceSchema = z.object({
258
248
  detail: NarrativeSchema,
259
249
  kind: z.enum(["interior-telemetry", "boundary-thermo-attestation"])
260
250
  }).strict();
261
- const CloseoutScopingSchema = z.object({
251
+ const LegacyCloseoutScopingSchema = z.object({
262
252
  epic: IdentifierSchema,
263
253
  issueFilter: z.number().int().positive().optional(),
264
254
  prFilter: z.number().int().positive().optional(),
@@ -270,9 +260,13 @@ const CloseoutScopingSchema = z.object({
270
260
  }).strict()
271
261
  }).strict();
272
262
  const CloseoutBudgetSchema = z.object({
263
+ note: NarrativeSchema,
264
+ tier: z.literal("overseer")
265
+ }).strict();
266
+ const LegacyCloseoutBudgetSchema = z.object({
273
267
  interiorSourcesConsumed: z.number().int().nonnegative(),
274
268
  note: NarrativeSchema,
275
- scoping: CloseoutScopingSchema.optional(),
269
+ scoping: LegacyCloseoutScopingSchema.optional(),
276
270
  tier: z.literal("overseer")
277
271
  }).strict();
278
272
  const BoundaryThermoAttestationSchema = z.object({
@@ -284,7 +278,23 @@ const BoundaryThermoAttestationSchema = z.object({
284
278
  const CloseoutMetricRowSchema = z.object({
285
279
  label: IdentifierSchema,
286
280
  metric: IdentifierSchema,
287
- source: CloseoutSourceSchema,
281
+ source: CurrentCloseoutSourceSchema,
282
+ unit: z.enum([
283
+ "count",
284
+ "boolean",
285
+ "text"
286
+ ]),
287
+ value: z.union([
288
+ z.number(),
289
+ NarrativeSchema,
290
+ z.boolean(),
291
+ z.null()
292
+ ])
293
+ }).strict();
294
+ const LegacyCloseoutMetricRowSchema = z.object({
295
+ label: IdentifierSchema,
296
+ metric: IdentifierSchema,
297
+ source: LegacyCloseoutSourceSchema,
288
298
  unit: z.enum([
289
299
  "tokens",
290
300
  "usd",
@@ -305,14 +315,21 @@ const CloseoutLessonSchema = z.object({
305
315
  landingSpot: CloseoutLandingSpotSchema,
306
316
  lesson: NarrativeSchema,
307
317
  rationale: NarrativeSchema.optional(),
308
- source: CloseoutSourceSchema.optional()
318
+ source: CurrentCloseoutSourceSchema.optional()
319
+ }).strict();
320
+ const LegacyCloseoutLessonSchema = z.object({
321
+ id: IdentifierSchema,
322
+ landingSpot: CloseoutLandingSpotSchema,
323
+ lesson: NarrativeSchema,
324
+ rationale: NarrativeSchema.optional(),
325
+ source: LegacyCloseoutSourceSchema.optional()
309
326
  }).strict();
310
327
  const CloseoutBlindspotSchema = z.object({
311
328
  id: IdentifierSchema,
312
329
  note: NarrativeSchema,
313
330
  reason: NarrativeSchema.optional()
314
331
  }).strict();
315
- const CloseoutLedgerRowSchema = z.object({
332
+ const closeoutLedgerRowSchema = (schemaVersion) => z.object({
316
333
  detail: NarrativeSchema.optional(),
317
334
  epic: IdentifierSchema,
318
335
  generatedAt: z.iso.datetime(),
@@ -324,7 +341,7 @@ const CloseoutLedgerRowSchema = z.object({
324
341
  "lesson",
325
342
  "blindspot"
326
343
  ]),
327
- schemaVersion: z.literal(3),
344
+ schemaVersion: z.literal(schemaVersion),
328
345
  source: NarrativeSchema,
329
346
  unit: IdentifierSchema.optional(),
330
347
  value: z.union([
@@ -333,19 +350,38 @@ const CloseoutLedgerRowSchema = z.object({
333
350
  z.null()
334
351
  ])
335
352
  }).strict();
336
- /** Strict, bounded runtime transport contract emitted by factory:closeout. */
337
- const closeoutArtifactSchema = z.object({
353
+ const CloseoutLedgerRowSchema = closeoutLedgerRowSchema(4);
354
+ const LegacyCloseoutLedgerRowSchema = closeoutLedgerRowSchema(LEGACY_CLOSEOUT_SCHEMA_VERSION);
355
+ const closeoutArtifactShape = (input) => z.object({
338
356
  boundaryThermo: BoundaryThermoAttestationSchema,
339
- budget: CloseoutBudgetSchema,
357
+ budget: input.budget,
340
358
  couldNotSee: z.array(CloseoutBlindspotSchema).min(1).max(MAX_CLOSEOUT_ROWS),
341
359
  epic: IdentifierSchema,
342
360
  generatedAt: z.iso.datetime(),
343
- ledgerRows: z.array(CloseoutLedgerRowSchema).max(MAX_CLOSEOUT_ROWS),
344
- lessons: z.array(CloseoutLessonSchema).max(MAX_CLOSEOUT_ROWS),
345
- metrics: z.array(CloseoutMetricRowSchema).max(MAX_CLOSEOUT_ROWS),
361
+ ledgerRows: z.array(input.ledgerRows).max(MAX_CLOSEOUT_ROWS),
362
+ lessons: z.array(input.lessons).max(MAX_CLOSEOUT_ROWS),
363
+ metrics: z.array(input.metrics).max(MAX_CLOSEOUT_ROWS),
346
364
  repo: RepoSchema,
347
- schemaVersion: z.literal(3)
365
+ schemaVersion: z.literal(input.schemaVersion)
348
366
  }).strict();
367
+ /** Strict, bounded runtime transport contract emitted by factory:closeout. */
368
+ const closeoutArtifactSchema = closeoutArtifactShape({
369
+ budget: CloseoutBudgetSchema,
370
+ ledgerRows: CloseoutLedgerRowSchema,
371
+ lessons: CloseoutLessonSchema,
372
+ metrics: CloseoutMetricRowSchema,
373
+ schemaVersion: 4
374
+ });
375
+ /** Reader-only compatibility for closeout artifacts written before #554. */
376
+ const legacyCloseoutArtifactSchema = closeoutArtifactShape({
377
+ budget: LegacyCloseoutBudgetSchema,
378
+ ledgerRows: LegacyCloseoutLedgerRowSchema,
379
+ lessons: LegacyCloseoutLessonSchema,
380
+ metrics: LegacyCloseoutMetricRowSchema,
381
+ schemaVersion: LEGACY_CLOSEOUT_SCHEMA_VERSION
382
+ });
383
+ /** Accept current output and retained v3 artifacts when reading or replaying. */
384
+ const closeoutArtifactReadSchema = z.union([closeoutArtifactSchema, legacyCloseoutArtifactSchema]);
349
385
  //#endregion
350
386
  //#region src/retro-envelope.ts
351
387
  /**
@@ -523,11 +559,6 @@ const RetroCycleCountersSchema = z.object({
523
559
  thermoFixRounds: nonNegInt
524
560
  }).strict();
525
561
  const RetroOutcomeSchema = z.object({
526
- mergeCheck: z.enum([
527
- "pass",
528
- "fail",
529
- "not-run"
530
- ]).optional(),
531
562
  status: z.enum([
532
563
  "success",
533
564
  "blocked",
@@ -731,11 +762,7 @@ const PR_REVIEW_SCHEMA_VERSION = 2;
731
762
  const PR_REVIEW_FINDING_PROVENANCE_VERSION = 1;
732
763
  const nonBlankString = z.string().refine((value) => value.trim().length > 0, { message: "must not be blank" });
733
764
  const parseableDateString = z.string().refine((value) => Number.isFinite(Date.parse(value)), { message: "must be a parseable date string" });
734
- const reviewPromptSectionProvenances = [
735
- "prior-review-ledger",
736
- "profile-standing-checklist",
737
- "issue-review-focus"
738
- ];
765
+ const reviewPromptSectionProvenances = ["prior-review-ledger", "issue-review-focus"];
739
766
  const reviewPromptSectionSchema = z.object({
740
767
  provenance: z.enum(reviewPromptSectionProvenances),
741
768
  source: nonBlankString,
@@ -1009,6 +1036,18 @@ const reviewStateSchema = z.object({
1009
1036
  reviewedPatchId: z.string().optional(),
1010
1037
  status: z.enum(REVIEW_STATUS_VALUES)
1011
1038
  });
1039
+ const historicalPostReadinessCommentSchema = z.object({
1040
+ author: z.string().min(1),
1041
+ createdAt: z.string().min(1),
1042
+ summary: z.string().min(1),
1043
+ url: z.string().min(1)
1044
+ });
1045
+ const historicalHandledHumanCommentSchema = z.object({
1046
+ clearedAt: z.string().min(1).optional(),
1047
+ sessionId: z.string().min(1).optional(),
1048
+ source: z.enum(["check-run", "cli"]),
1049
+ url: z.string().min(1)
1050
+ });
1012
1051
  const managedReadinessLedgerSchema = z.object({
1013
1052
  baseSha: z.string().regex(/^[0-9a-f]{40}$/u),
1014
1053
  blockingReasons: z.array(z.string()),
@@ -1026,9 +1065,8 @@ const managedReadinessLedgerSchema = z.object({
1026
1065
  "out-of-scope"
1027
1066
  ])
1028
1067
  })).optional(),
1029
- finalReviewPoint: z.boolean(),
1068
+ finalReviewPoint: z.boolean().optional(),
1030
1069
  github: z.object({
1031
- currentWithBase: z.boolean(),
1032
1070
  draft: z.boolean(),
1033
1071
  mergeStateStatus: z.string(),
1034
1072
  mergeable: z.string(),
@@ -1039,47 +1077,20 @@ const managedReadinessLedgerSchema = z.object({
1039
1077
  "none",
1040
1078
  "unknown"
1041
1079
  ]),
1080
+ reviewDecision: z.string().nullable().optional(),
1042
1081
  unresolvedReviewThreads: z.number().int().nonnegative()
1043
1082
  }),
1044
1083
  handledCommentsProducer: z.object({
1045
1084
  identity: z.string().min(1),
1046
1085
  mode: z.enum(["app", "commit-status"])
1047
1086
  }).optional(),
1048
- handledHumanComments: z.array(z.object({
1049
- clearedAt: z.string().min(1).optional(),
1050
- sessionId: z.string().min(1).optional(),
1051
- source: z.enum(["check-run", "cli"]),
1052
- url: z.string().min(1)
1053
- })).optional(),
1087
+ handledHumanComments: z.array(historicalHandledHumanCommentSchema).optional(),
1054
1088
  headSha: z.string().regex(/^[0-9a-f]{40}$/u),
1055
1089
  mergeBaseSha: z.string().regex(/^[0-9a-f]{40}$/u).optional(),
1056
1090
  patchId: z.string().regex(/^[0-9a-f]{40,64}$/u),
1057
- postReadinessHumanComments: z.array(z.object({
1058
- author: z.string().min(1),
1059
- createdAt: z.string().min(1),
1060
- summary: z.string().min(1),
1061
- url: z.string().min(1)
1062
- })).optional(),
1091
+ postReadinessHumanComments: z.array(historicalPostReadinessCommentSchema).optional(),
1092
+ postReadinessHumanReviews: z.array(historicalPostReadinessCommentSchema).optional(),
1063
1093
  pr: z.number().int().positive(),
1064
- previewDeploy: z.object({
1065
- adminUrl: z.string().optional(),
1066
- apiHealthUrl: z.string().optional(),
1067
- headSha: z.string().optional(),
1068
- localPreviewProof: z.unknown().optional(),
1069
- localProofPath: z.string().optional(),
1070
- proofSource: z.enum(["github-actions", "local-self-certified"]).optional(),
1071
- publicUrl: z.string().optional(),
1072
- seedStatus: z.enum([
1073
- "passed",
1074
- "failed",
1075
- "skipped",
1076
- "unknown"
1077
- ]),
1078
- stage: z.string().optional(),
1079
- timingsMs: z.record(z.string(), z.number().optional()).optional(),
1080
- workflowRunUrl: z.string().optional()
1081
- }).optional(),
1082
- previewDeployRequired: z.boolean(),
1083
1094
  repairs: z.array(readinessRepairSchema).default([]),
1084
1095
  reviewCycleState: z.object({
1085
1096
  autoBlockingFindings: z.number().int().nonnegative(),
@@ -1152,7 +1163,7 @@ const managedReadinessLedgerSchema = z.object({
1152
1163
  "slice",
1153
1164
  "rollup",
1154
1165
  "merge-gate prerequisite"
1155
- ]),
1166
+ ]).optional(),
1156
1167
  verification: z.object({
1157
1168
  command: z.literal("patronage-factory pr:verify"),
1158
1169
  docsOnlyDeltaAccepted: z.boolean().optional(),
@@ -1217,10 +1228,7 @@ const prReadyProofSchema = z.object({
1217
1228
  });
1218
1229
  return;
1219
1230
  }
1220
- for (const issue of blockedReasonIssues({
1221
- ...proof,
1222
- finalReviewPoint: proof.ledger.finalReviewPoint
1223
- })) context.addIssue(issue);
1231
+ for (const issue of blockedReasonIssues({ ...proof })) context.addIssue(issue);
1224
1232
  });
1225
1233
  //#endregion
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 };
1234
+ 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_CLOSEOUT_SCHEMA_VERSIONS, SUPPORTED_PR_READY_SCHEMA_VERSIONS, SUPPORTED_PR_VERIFY_SCHEMA_VERSIONS, SUPPORTED_RETRO_ENVELOPE_SCHEMA_VERSIONS, blockedReasonSchema, blockedReasonsSchema, boundaryCheckProofSchema, boundaryReviewProofSchema, closeoutArtifactReadSchema, closeoutArtifactSchema, evidenceEnvelopeSchema, legacyCloseoutArtifactSchema, 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.30.0-alpha.1",
3
+ "version": "0.30.0-beta.3",
4
4
  "description": "Shared Patronage software factory CLI and project-profile validation tools",
5
5
  "license": "MIT",
6
6
  "repository": {