@patronage/software-factory 0.23.0 → 0.25.0

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
@@ -19,6 +19,32 @@ interface WaivedDemand {
19
19
  }
20
20
  declare const waivedDemandSchema: z.ZodType<WaivedDemand>;
21
21
  //#endregion
22
+ //#region src/blocked-reasons.d.ts
23
+ /**
24
+ * The wire bound on one `detail`. A blocked proof carries one short sentence
25
+ * per demand, never a transcript: HQ's ingest cap is 256 KB and this field
26
+ * must stay far under it even when a candidate blocks on every gate at once.
27
+ */
28
+ declare const BLOCKED_REASON_DETAIL_MAX = 280;
29
+ /**
30
+ * The wire bound on how many demands one proof may name. Well past any real
31
+ * candidate (there are a dozen fixed demands plus the profile's checks and the
32
+ * live human blockers) and, with the detail bound, keeps the whole field two
33
+ * orders of magnitude under the ingest cap. Bounded here rather than trimmed
34
+ * downstream: HQ rejects an over-long list loudly instead of storing a quietly
35
+ * truncated one.
36
+ */
37
+ declare const BLOCKED_REASONS_MAX = 100;
38
+ declare const blockedReasonSchema: z.ZodObject<{
39
+ code: z.ZodString;
40
+ detail: z.ZodString;
41
+ }, z.core.$strip>;
42
+ declare const blockedReasonsSchema: z.ZodArray<z.ZodObject<{
43
+ code: z.ZodString;
44
+ detail: z.ZodString;
45
+ }, z.core.$strip>>;
46
+ type BlockedReason = z.infer<typeof blockedReasonSchema>;
47
+ //#endregion
22
48
  //#region src/boundary-review-proof.d.ts
23
49
  declare const boundaryReviewProofBaseSchema: z.ZodObject<{
24
50
  boundary: z.ZodString;
@@ -551,7 +577,15 @@ type ManagedReadinessLedger = z.infer<typeof managedReadinessLedgerSchema>;
551
577
  //#endregion
552
578
  //#region src/pr-ready.d.ts
553
579
  interface PrReadyProof {
554
- schemaVersion: 1;
580
+ schemaVersion: 2;
581
+ /**
582
+ * Why this run blocked, one entry per refusing demand (#391): `code` is the
583
+ * demand key from the resolver's vocabulary, `detail` the one-sentence
584
+ * refusal. Same refusals as `blockingReasons`, in the same order — the
585
+ * analyzable projection of a flat string list, so a wall of blocked proofs
586
+ * on one PR can be counted by cause. Absent when nothing blocked.
587
+ */
588
+ blockedReasons?: BlockedReason[];
555
589
  blockingReasons: string[];
556
590
  humanBlockingReasons: string[];
557
591
  command: "patronage-factory pr:ready";
@@ -1312,8 +1346,18 @@ declare const prMergeCheckProofSchema: z.ZodObject<{
1312
1346
  worktreePath: z.ZodString;
1313
1347
  }, z.core.$strip>>;
1314
1348
  }, z.core.$strip>;
1315
- declare const PR_READY_SCHEMA_VERSION = 1;
1349
+ declare const PR_READY_SCHEMA_VERSION = 2;
1350
+ /**
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.
1354
+ */
1355
+ declare const SUPPORTED_PR_READY_SCHEMA_VERSIONS: readonly [1, 2];
1316
1356
  declare const prReadyProofSchema: z.ZodObject<{
1357
+ blockedReasons: z.ZodOptional<z.ZodArray<z.ZodObject<{
1358
+ code: z.ZodString;
1359
+ detail: z.ZodString;
1360
+ }, z.core.$strip>>>;
1317
1361
  blockingReasons: z.ZodArray<z.ZodString>;
1318
1362
  command: z.ZodLiteral<"patronage-factory pr:ready">;
1319
1363
  followUp: z.ZodOptional<z.ZodObject<{
@@ -1629,7 +1673,7 @@ declare const prReadyProofSchema: z.ZodObject<{
1629
1673
  command: z.ZodString;
1630
1674
  }, z.core.$strip>>>;
1631
1675
  repository: z.ZodOptional<z.ZodString>;
1632
- schemaVersion: z.ZodLiteral<1>;
1676
+ schemaVersion: z.ZodNumber & z.ZodType<1 | 2, number, z.core.$ZodTypeInternals<1 | 2, number>>;
1633
1677
  status: z.ZodEnum<{
1634
1678
  ready: "ready";
1635
1679
  blocked: "blocked";
@@ -1637,4 +1681,4 @@ declare const prReadyProofSchema: z.ZodObject<{
1637
1681
  }>;
1638
1682
  }, z.core.$strip>;
1639
1683
  //#endregion
1640
- export { BOUNDARY_CHECK_SCHEMA_VERSION, BOUNDARY_REVIEW_PROOF_KIND, 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_VERIFY_SCHEMA_VERSIONS, SUPPORTED_RETRO_ENVELOPE_SCHEMA_VERSIONS, type WaivedDemand, boundaryCheckProofSchema, boundaryReviewProofSchema, closeoutArtifactSchema, evidenceEnvelopeSchema, prMergeCheckProofSchema, prReadyProofSchema, prReviewProofSchema, prVerifyProofSchema, retroEnvelopeV1Schema, retroEpicReference, waivedDemandSchema };
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 };
package/dist/schemas.js CHANGED
@@ -1,21 +1,217 @@
1
1
  import { z } from "zod";
2
+ //#region src/review-rungs.ts
3
+ const EVIDENCE_REVIEW_RUNGS$1 = [
4
+ "independent-model",
5
+ "oracle",
6
+ "human"
7
+ ];
8
+ Object.fromEntries(EVIDENCE_REVIEW_RUNGS$1.map((rung, index) => [rung, index]));
9
+ //#endregion
10
+ //#region src/demand-keys.ts
11
+ /** The demands that exist at most once per candidate. */
12
+ const DEMAND_KEYS = {
13
+ /** The PR is still a draft. */
14
+ draft: "draft",
15
+ /** The candidate is not the intended final human review point. */
16
+ finalReviewPoint: "final-review-point",
17
+ /** GitHub's own check rollup for the candidate head. */
18
+ githubChecks: "github-checks",
19
+ /** Local HEAD and the GitHub PR head must be the same commit. */
20
+ headIdentity: "head-identity",
21
+ /** An unhandled post-readiness human comment or review submission. */
22
+ humanBlocker: "human-blocker",
23
+ /** The repository-wide merge freeze. */
24
+ mergeFreeze: "merge-freeze",
25
+ /** GitHub's mergeability / merge-state rollup. */
26
+ mergeState: "merge-state",
27
+ /** The PR body's required rendered sections. */
28
+ prBodySections: "pr-body-sections",
29
+ /** A current, head-bound, passing typed `pr:verify` proof. */
30
+ prVerify: "pr-verify",
31
+ /** The profile-resolved review ladder policy. */
32
+ reviewLadder: "review-ladder",
33
+ /** Unresolved GitHub review threads. */
34
+ reviewThreads: "review-threads",
35
+ /** An explicit trivial waiver that the diff does not support. */
36
+ trivialWaiver: "trivial-waiver"
37
+ };
38
+ /** The families whose instances are named by a resolved value. */
39
+ const QUALIFIED_DEMAND_FAMILIES = [
40
+ "required-check",
41
+ "review-mode",
42
+ "review-rung"
43
+ ];
44
+ const QUALIFIER_PATTERN = /^[A-Za-z0-9._%/-]{1,64}$/u;
45
+ const percentEncode = (character) => {
46
+ const code = character.codePointAt(0) ?? 0;
47
+ if (code >= 55296 && code <= 57343) return `%u${code.toString(16).toUpperCase().padStart(4, "0")}`;
48
+ return [...new TextEncoder().encode(character)].map((byte) => `%${byte.toString(16).toUpperCase().padStart(2, "0")}`).join("");
49
+ };
50
+ /**
51
+ * Express a resolved value as a qualifier. Percent-encoding, not scrubbing:
52
+ * the mapping is injective, so two differently named required checks can never
53
+ * collapse into one key — which would let one operator waiver silently cover a
54
+ * demand nobody waived, and make HQ count two causes as one.
55
+ *
56
+ * Deterministic in both directions of use: the key a `pr:ready` proof records
57
+ * is the key a `pr:merge-check` waiver matches.
58
+ */
59
+ const demandQualifier = (value) => value.replaceAll(/[^A-Za-z0-9._/-]/gu, percentEncode);
60
+ const FIXED_DEMAND_KEYS = Object.values(DEMAND_KEYS);
61
+ /** The review modes a profile can resolve, and therefore demand. */
62
+ const REVIEW_MODE_DEMAND_VALUES = ["correctness", "security"];
63
+ const escapePattern = /%(?:u[0-9A-F]{4}|[0-9A-F]{2})/gu;
64
+ /**
65
+ * Reverse `demandQualifier`. A qualifier is canonical exactly when encoding
66
+ * its decoded form reproduces it — which rejects both malformed escapes and
67
+ * noncanonical aliases like `%41` for `A`. Returns undefined when the
68
+ * qualifier cannot have been minted here.
69
+ */
70
+ const decodeQualifier = (qualifier) => {
71
+ const bytes = [];
72
+ let decoded = "";
73
+ let index = 0;
74
+ const flush = () => {
75
+ if (bytes.length === 0) return true;
76
+ try {
77
+ decoded += new TextDecoder("utf-8", {
78
+ fatal: true,
79
+ ignoreBOM: true
80
+ }).decode(Uint8Array.from(bytes));
81
+ } catch {
82
+ return false;
83
+ }
84
+ bytes.length = 0;
85
+ return true;
86
+ };
87
+ while (index < qualifier.length) {
88
+ const character = qualifier[index];
89
+ if (character !== "%") {
90
+ if (!flush()) return;
91
+ decoded += character;
92
+ index += 1;
93
+ continue;
94
+ }
95
+ escapePattern.lastIndex = index;
96
+ const escape = escapePattern.exec(qualifier);
97
+ if (!escape || escape.index !== index) return;
98
+ if (escape[0][1] === "u") {
99
+ if (!flush()) return;
100
+ decoded += String.fromCodePoint(Number.parseInt(escape[0].slice(2), 16));
101
+ } else bytes.push(Number.parseInt(escape[0].slice(1), 16));
102
+ index += escape[0].length;
103
+ }
104
+ return flush() ? decoded : void 0;
105
+ };
106
+ const qualifierIsMintable = (family, qualifier) => {
107
+ if (!QUALIFIER_PATTERN.test(qualifier)) return false;
108
+ const decoded = decodeQualifier(qualifier);
109
+ if (decoded === void 0 || demandQualifier(decoded) !== qualifier) return false;
110
+ if (family === "review-rung") return EVIDENCE_REVIEW_RUNGS$1.includes(decoded);
111
+ if (family === "review-mode") return REVIEW_MODE_DEMAND_VALUES.includes(decoded);
112
+ return true;
113
+ };
114
+ /**
115
+ * A demand key from the closed vocabulary: a known unqualified family, or a
116
+ * known qualified family with a qualifier this module could actually have
117
+ * minted. Closed on purpose — an invented family, an unresolvable rung, or a
118
+ * noncanonical encoding would be indistinguishable from a typo to anyone
119
+ * counting causes, which is the whole point of recording codes.
120
+ */
121
+ const demandKeySchema = z.string().refine((value) => {
122
+ if (FIXED_DEMAND_KEYS.includes(value)) return true;
123
+ const separator = value.indexOf(":");
124
+ if (separator === -1) return false;
125
+ const family = value.slice(0, separator);
126
+ return QUALIFIED_DEMAND_FAMILIES.includes(family) && qualifierIsMintable(family, value.slice(separator + 1));
127
+ }, { message: `a demand key is one of ${FIXED_DEMAND_KEYS.join(", ")} or a resolvable ${QUALIFIED_DEMAND_FAMILIES.join(" / ")} key` });
128
+ /**
129
+ * The key shape an operator may *name* in a waiver: syntactic, not closed.
130
+ *
131
+ * Deliberately distinct from `demandKeySchema` above, which is what a proof's
132
+ * reason codes must come from. A waiver store is durable operator evidence
133
+ * written before today's vocabulary existed, so tightening its validation
134
+ * 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`
136
+ * reports it as an unapplied waiver — so nothing is admitted by accepting it.
137
+ */
138
+ 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).");
139
+ //#endregion
140
+ //#region src/blocked-reasons.ts
141
+ /**
142
+ * The wire bound on one `detail`. A blocked proof carries one short sentence
143
+ * per demand, never a transcript: HQ's ingest cap is 256 KB and this field
144
+ * must stay far under it even when a candidate blocks on every gate at once.
145
+ */
146
+ const BLOCKED_REASON_DETAIL_MAX = 280;
147
+ /**
148
+ * The wire bound on how many demands one proof may name. Well past any real
149
+ * candidate (there are a dozen fixed demands plus the profile's checks and the
150
+ * live human blockers) and, with the detail bound, keeps the whole field two
151
+ * orders of magnitude under the ingest cap. Bounded here rather than trimmed
152
+ * downstream: HQ rejects an over-long list loudly instead of storing a quietly
153
+ * truncated one.
154
+ */
155
+ const BLOCKED_REASONS_MAX = 100;
156
+ /** One refusal sentence: single line, trimmed, bounded. */
157
+ const blockedReasonDetailSchema = z.string().min(1).max(280).refine((value) => value.trim().length > 0, { message: "must not be blank" }).refine((value) => !/[\r\n]/u.test(value), { message: "must be one line, not a multi-line payload" });
158
+ const blockedReasonSchema = z.object({
159
+ code: demandKeySchema,
160
+ detail: blockedReasonDetailSchema
161
+ });
162
+ const blockedReasonsSchema = z.array(blockedReasonSchema).max(100);
163
+ /** Fit one refusal sentence to the wire bound without losing its head. */
164
+ const blockedReasonDetail = (reason) => {
165
+ const line = reason.replaceAll(/\s+/gu, " ").trim();
166
+ return line.length <= 280 ? line : `${line.slice(0, 279)}…`;
167
+ };
168
+ const blockedReasonIssue = (message) => [{
169
+ code: "custom",
170
+ message,
171
+ path: ["blockedReasons"]
172
+ }];
173
+ /**
174
+ * The invariant every reader enforces, shared by the emitting schema and the
175
+ * wire schema so it is one rule rather than two that can drift. It is the
176
+ * producer's state machine, written down:
177
+ *
178
+ * - `ready` refused nothing, so it carries neither projection, and it is the
179
+ * final review point;
180
+ * - `slice-ready/not-final` was held back by exactly one demand — being a
181
+ * slice — and names it;
182
+ * - `blocked` refused something other than being a slice, and says so;
183
+ * - whichever it is, `blockedReasons` names every refusal listed in
184
+ * `blockingReasons`, in the same order, as the bounded form of that sentence.
185
+ *
186
+ * Naming the slice demand and the ledger's `finalReviewPoint` are the same
187
+ * fact, so a proof that says one and not the other is refused.
188
+ */
189
+ const blockedReasonIssues = (proof) => {
190
+ const named = proof.blockedReasons ?? [];
191
+ const reasons = proof.blockingReasons ?? [];
192
+ const slice = DEMAND_KEYS.finalReviewPoint;
193
+ const namesSlice = named.some((reason) => reason.code === slice);
194
+ if (proof.status === "ready") {
195
+ if (named.length > 0 || reasons.length > 0) return blockedReasonIssue("a ready pr:ready proof must carry no blocking reasons");
196
+ } else if (proof.status === "slice-ready/not-final") {
197
+ if (named.length !== 1 || !namesSlice) return blockedReasonIssue(`a slice-ready/not-final pr:ready proof is held back by exactly one demand, ${slice}`);
198
+ } else if (reasons.length === 0) return blockedReasonIssue("a blocked pr:ready proof must record what blocked it");
199
+ 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}`);
200
+ 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`);
201
+ if (named.length !== reasons.length) return blockedReasonIssue(`blockedReasons must name every blocking reason: ${reasons.length} reason(s), ${named.length} named`);
202
+ const drifted = named.findIndex((reason, index) => reason.detail !== blockedReasonDetail(reasons[index]));
203
+ return drifted === -1 ? [] : blockedReasonIssue(`blockedReasons[${drifted}] does not carry blocking reason ${drifted}; the two projections must tell one story`);
204
+ };
205
+ //#endregion
2
206
  //#region src/demand-waiver.ts
3
207
  const DEMAND_WAIVER_SCHEMA_VERSION = 1;
4
208
  const shaSchema = z.string().regex(/^[0-9a-f]{40}$/u);
5
- /**
6
- * A resolved demand's key: a family, optionally qualified by the resolved
7
- * value that makes it this demand *instance* (`review-rung:human`,
8
- * `required-check:core`, `merge-freeze`). The consumer that resolved the
9
- * demand owns the key; this module only matches on it, which is why no
10
- * control name is enumerated here.
11
- */
12
- const demandKeySchema = 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).");
13
209
  const demandWaiverSchema = z.object({
14
210
  candidate: z.object({
15
211
  headSha: shaSchema,
16
212
  pr: z.number().int().positive()
17
213
  }),
18
- demand: demandKeySchema,
214
+ demand: waiverDemandKeySchema,
19
215
  operator: z.string().trim().min(1),
20
216
  rationale: z.string().trim().min(1),
21
217
  recordedAt: z.iso.datetime(),
@@ -27,7 +223,7 @@ z.object({
27
223
  waivers: z.array(demandWaiverSchema)
28
224
  });
29
225
  const waivedDemandSchema = z.object({
30
- demand: demandKeySchema,
226
+ demand: waiverDemandKeySchema,
31
227
  operator: z.string().trim().min(1),
32
228
  rationale: z.string().trim().min(1),
33
229
  recordedAt: z.iso.datetime(),
@@ -1018,8 +1214,16 @@ const managedReadinessLedgerSchema = z.object({
1018
1214
  verifiedHeadSha: z.string().optional()
1019
1215
  })
1020
1216
  });
1021
- const PR_READY_SCHEMA_VERSION = 1;
1217
+ const PR_READY_SCHEMA_VERSION = 2;
1218
+ /**
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.
1222
+ */
1223
+ const SUPPORTED_PR_READY_SCHEMA_VERSIONS = [1, 2];
1224
+ 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(", ")}` });
1022
1225
  const prReadyProofSchema = z.object({
1226
+ blockedReasons: blockedReasonsSchema.optional(),
1023
1227
  blockingReasons: z.array(z.string()),
1024
1228
  command: z.literal("patronage-factory pr:ready"),
1025
1229
  followUp: followUpActionSchema.optional(),
@@ -1029,12 +1233,25 @@ const prReadyProofSchema = z.object({
1029
1233
  profilePath: z.string().min(1).optional(),
1030
1234
  repairs: z.array(readinessRepairSchema).default([]),
1031
1235
  repository: z.string().regex(/^[^/\s]+\/[^/\s]+$/u).optional(),
1032
- schemaVersion: z.literal(1),
1236
+ schemaVersion: prReadySchemaVersionSchema,
1033
1237
  status: z.enum([
1034
1238
  "ready",
1035
1239
  "blocked",
1036
1240
  "slice-ready/not-final"
1037
1241
  ])
1242
+ }).superRefine((proof, context) => {
1243
+ if (proof.schemaVersion < 2) {
1244
+ if (proof.blockedReasons !== void 0) context.addIssue({
1245
+ code: "custom",
1246
+ message: "blockedReasons is a schemaVersion 2 field; a v1 pr:ready proof must not carry it.",
1247
+ path: ["blockedReasons"]
1248
+ });
1249
+ return;
1250
+ }
1251
+ for (const issue of blockedReasonIssues({
1252
+ ...proof,
1253
+ finalReviewPoint: proof.ledger.finalReviewPoint
1254
+ })) context.addIssue(issue);
1038
1255
  });
1039
1256
  //#endregion
1040
- export { 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_VERIFY_SCHEMA_VERSIONS, SUPPORTED_RETRO_ENVELOPE_SCHEMA_VERSIONS, boundaryCheckProofSchema, boundaryReviewProofSchema, closeoutArtifactSchema, evidenceEnvelopeSchema, prMergeCheckProofSchema, prReadyProofSchema, prReviewProofSchema, prVerifyProofSchema, retroEnvelopeV1Schema, retroEpicReference, waivedDemandSchema };
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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patronage/software-factory",
3
- "version": "0.23.0",
3
+ "version": "0.25.0",
4
4
  "description": "Shared Patronage software factory CLI and project-profile validation tools",
5
5
  "license": "MIT",
6
6
  "repository": {