@patronage/software-factory 1.0.0-alpha.21 → 1.0.0-alpha.22

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/README.md CHANGED
@@ -66,7 +66,7 @@ Generated production workflows may call `psf production:impact --before <sha> --
66
66
 
67
67
  Generated pull-request workflows may call `psf candidate:impact --base <sha> --head <sha> --github-output <path>` to route Candidate verification surfaces. The command evaluates the same profile impact declarations and pnpm dependency graph from the exact base/head identity, diffed from their merge base; it is the candidate-named sibling of `production:impact` and replaces repository-owned path filters, never adds a second matcher. The `head` commit must be the checked-out `HEAD`, and both commits must be reachable (`fetch-depth: 0`). Every doubt path — unreadable identity, malformed or unsupported graph data, an unowned profile change, a working-tree profile that differs from the head commit, or classifier refusal — fails closed and leaves every declared target demanded. `production:impact` keeps its merge-push `before`/`after` contract unchanged.
68
68
 
69
- For factory workflow, install the four canonical skills from the repository:
69
+ For factory workflow, install the four canonical skills as the `patronage-software-factory` host plugin (Claude Code, Codex, or Cursor; see [`skills/README.md`](../skills/README.md)). Cloud agents that cannot load host plugins fall back to:
70
70
 
71
71
  ```bash
72
72
  npx skills add https://github.com/patronage/software-factory -g --all
package/dist/index.d.ts CHANGED
@@ -1423,9 +1423,9 @@ declare const managedReadinessLedgerSchema: z.ZodObject<{
1423
1423
  reviewedHeadSha: z.ZodOptional<z.ZodString>;
1424
1424
  reviewedPatchId: z.ZodOptional<z.ZodString>;
1425
1425
  status: z.ZodEnum<{
1426
+ blocked: "blocked";
1426
1427
  "not-required": "not-required";
1427
1428
  stale: "stale";
1428
- blocked: "blocked";
1429
1429
  current: "current";
1430
1430
  missing: "missing";
1431
1431
  }>;
@@ -1435,9 +1435,9 @@ declare const managedReadinessLedgerSchema: z.ZodObject<{
1435
1435
  reviewedHeadSha: z.ZodOptional<z.ZodString>;
1436
1436
  reviewedPatchId: z.ZodOptional<z.ZodString>;
1437
1437
  status: z.ZodEnum<{
1438
+ blocked: "blocked";
1438
1439
  "not-required": "not-required";
1439
1440
  stale: "stale";
1440
- blocked: "blocked";
1441
1441
  current: "current";
1442
1442
  missing: "missing";
1443
1443
  }>;
@@ -2415,9 +2415,9 @@ declare const loadEvidenceEnvelopes: (cwd: string) => LoadedEvidenceEnvelope[];
2415
2415
  //#region src/review-proof-applicability.d.ts
2416
2416
  declare const REVIEW_STATUS_VALUES: readonly ["not-required", "current", "stale", "missing", "blocked"];
2417
2417
  declare const reviewStatusSchema: z.ZodEnum<{
2418
+ blocked: "blocked";
2418
2419
  "not-required": "not-required";
2419
2420
  stale: "stale";
2420
- blocked: "blocked";
2421
2421
  current: "current";
2422
2422
  missing: "missing";
2423
2423
  }>;
@@ -2566,8 +2566,8 @@ declare const boundaryCheckProofSchema: z.ZodObject<{
2566
2566
  value: z.ZodString;
2567
2567
  }, z.core.$strip>>;
2568
2568
  status: z.ZodEnum<{
2569
- ready: "ready";
2570
2569
  blocked: "blocked";
2570
+ ready: "ready";
2571
2571
  }>;
2572
2572
  }, z.core.$strip>;
2573
2573
  type BoundaryCheckProofRecord = z.infer<typeof boundaryCheckProofSchema>;
@@ -2582,6 +2582,14 @@ interface BoundaryCheckGithub {
2582
2582
  interface BoundaryCheckArgs {
2583
2583
  cwd?: string;
2584
2584
  epic: number;
2585
+ /**
2586
+ * Closeout-final mode (#853): a manifest-declared issue whose closing-PR
2587
+ * set is empty is a blocking reason, not a notice. Off by default so the
2588
+ * interior boundary review (run before the terminal release PR exists,
2589
+ * e.g. epic #842's own review of #844) keeps working; the epic closeout
2590
+ * step turns this on as the last check before factory:closeout.
2591
+ */
2592
+ final?: boolean;
2585
2593
  json?: boolean;
2586
2594
  output?: string;
2587
2595
  repo?: string;
@@ -4147,13 +4155,13 @@ declare const evaluateReadiness: (input: EvaluationInput) => {
4147
4155
  reviews: {
4148
4156
  correctness: {
4149
4157
  required: boolean;
4150
- status: "not-required" | "stale" | "blocked" | "current" | "missing";
4158
+ status: "blocked" | "not-required" | "stale" | "current" | "missing";
4151
4159
  reviewedHeadSha?: string | undefined;
4152
4160
  reviewedPatchId?: string | undefined;
4153
4161
  };
4154
4162
  security?: {
4155
4163
  required: boolean;
4156
- status: "not-required" | "stale" | "blocked" | "current" | "missing";
4164
+ status: "blocked" | "not-required" | "stale" | "current" | "missing";
4157
4165
  reviewedHeadSha?: string | undefined;
4158
4166
  reviewedPatchId?: string | undefined;
4159
4167
  } | undefined;
package/dist/index.js CHANGED
@@ -17,7 +17,7 @@ import { parse } from "yaml";
17
17
  import { FACTORY_PROOF_GATE_APP_ID, FACTORY_PROOF_GATE_STEP_NAME, GitHubApiError, mintInstallationToken, previewProofInventory, productionImpactTargetOutput, readVitestProfileDocument } from "@patronage/factory-ci";
18
18
  import { promisify } from "node:util";
19
19
  //#region package.json
20
- var version = "1.0.0-alpha.21";
20
+ var version = "1.0.0-alpha.22";
21
21
  //#endregion
22
22
  //#region src/review-rungs.ts
23
23
  const EVIDENCE_REVIEW_RUNGS$1 = [
@@ -162,10 +162,11 @@ const DEFAULT_TERMINAL_BASE = "main";
162
162
  *
163
163
  * A PR that closed without merging contributes NO closing link (#821): it
164
164
  * carried nothing into the boundary, so it is not a member and cannot fail
165
- * one. The dropped link is recorded on the issue. Closeout blocks only on
166
- * that flavor: an issue whose carriers all closed without merging. A declared
167
- * issue that never had any closing link is reported as a notice, not a
168
- * blocking reason (open question: #853).
165
+ * one. The dropped link is recorded on the issue. Closeout blocks by default
166
+ * only on that flavor: an issue whose carriers all closed without merging. A
167
+ * declared issue that never had any closing link is reported as a notice,
168
+ * not a blocking reason except under boundary:check --final, which blocks
169
+ * on that flavor too (#853).
169
170
  */
170
171
  const buildBoundaryMembershipGraph = (manifest, fetchClosingPullRequests) => {
171
172
  const memberships = [];
@@ -5439,10 +5440,12 @@ function runBoundaryCheck(args, dependencies = {}) {
5439
5440
  selected
5440
5441
  });
5441
5442
  const uncoveredIssueReasons = graph.unlinkedIssues.flatMap((entry) => entry.closedWithoutMerge === void 0 ? [] : [`issue #${entry.issue} (wave ${entry.wave}) is uncovered: its only closing link(s) ${entry.closedWithoutMerge.map((pr) => `PR #${pr}`).join(", ")} closed without merging`]);
5443
+ const finalUncoveredIssueReasons = args.final ? graph.unlinkedIssues.flatMap((entry) => entry.closedWithoutMerge === void 0 ? [`issue #${entry.issue} (wave ${entry.wave}) has no linked closing PR; --final requires every declared issue to be covered before closeout`] : []) : [];
5442
5444
  blockingReasons.unshift(...boundaryTopologyReasons({
5443
5445
  manifest: parsed.manifest,
5444
5446
  pullRequests: computed.pullRequests
5445
- }), ...uncoveredIssueReasons);
5447
+ }), ...uncoveredIssueReasons, ...finalUncoveredIssueReasons);
5448
+ const specHashNotices = selected?.proof.specHash !== void 0 && selected.proof.specHash.value !== specHash ? [`boundary-review proof spec sha256 ${selected.proof.specHash.value} does not match current epic spec sha256 ${specHash}; use the specHash from the blocked boundary:check record instead of hashing shell-rendered output`] : [];
5446
5449
  record = {
5447
5450
  blockingReasons,
5448
5451
  boundary: parsed.manifest.boundary,
@@ -5454,7 +5457,7 @@ function runBoundaryCheck(args, dependencies = {}) {
5454
5457
  algo: "sha256",
5455
5458
  value: parsed.manifestHash
5456
5459
  },
5457
- notices: computed.notices,
5460
+ notices: [...computed.notices, ...specHashNotices],
5458
5461
  repo,
5459
5462
  ...selected ? { reviewProof: {
5460
5463
  ...selected.commentId === void 0 ? {} : { commentId: selected.commentId },
@@ -6203,7 +6206,7 @@ const renderReport = (record) => {
6203
6206
  return `${lines.join("\n")}\n`;
6204
6207
  };
6205
6208
  function createBoundaryCheckCommand(output, action) {
6206
- return markCwdOptionDefault(new Command("boundary:check").description("Boundary readiness gate (T8): require a membership-fresh boundary-review proof at the declared closeout rung. Blocks closeout/enablement, never merge.").requiredOption("--epic <number>", "issue number carrying the factory-boundary manifest, which may be the work issue itself (#789)", positiveInteger$1("--epic")).option("--repo <owner/name>", "GitHub repository (default: resolved from --cwd)").option("--cwd <path>", "repository working directory", collectCwdOption).option("--output <path>", "write an additional proof copy to this path").option("--profile <path>", "path to the project profile JSON file").option("--json", "print the full proof record as JSON").action(withGateTiming({
6209
+ return markCwdOptionDefault(new Command("boundary:check").description("Boundary readiness gate (T8): require a membership-fresh boundary-review proof at the declared closeout rung. Blocks closeout/enablement, never merge.").requiredOption("--epic <number>", "issue number carrying the factory-boundary manifest, which may be the work issue itself (#789)", positiveInteger$1("--epic")).option("--repo <owner/name>", "GitHub repository (default: resolved from --cwd)").option("--cwd <path>", "repository working directory", collectCwdOption).option("--output <path>", "write an additional proof copy to this path").option("--profile <path>", "path to the project profile JSON file").option("--json", "print the full proof record as JSON").option("--final", "closeout-final mode (#853): a declared issue with no closing PR blocks instead of only noticing. Run as the last check before factory:closeout.").action(withGateTiming({
6207
6210
  gate: "boundary:check",
6208
6211
  resolveLedgerRoot: (options) => resolveCwdOption(options.cwd),
6209
6212
  stderr: output.stderr
@@ -6213,7 +6216,8 @@ function createBoundaryCheckCommand(output, action) {
6213
6216
  epic: options.epic,
6214
6217
  ...options.repo ? { repo: options.repo } : {},
6215
6218
  ...options.output ? { output: options.output } : {},
6216
- ...options.json ? { json: true } : {}
6219
+ ...options.json ? { json: true } : {},
6220
+ ...options.final ? { final: true } : {}
6217
6221
  };
6218
6222
  const record = action ? action(args) : runBoundaryCheck(args);
6219
6223
  output.stdout.write(options.json ? `${JSON.stringify(record, null, 2)}\n` : renderReport(record));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patronage/software-factory",
3
- "version": "1.0.0-alpha.21",
3
+ "version": "1.0.0-alpha.22",
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.21"
40
+ "@patronage/factory-ci": "1.0.0-alpha.22"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/node": "24.13.3",
@@ -52,8 +52,7 @@
52
52
  "tsx": "4.23.1",
53
53
  "typescript": "5.9.3",
54
54
  "ultracite": "7.10.5",
55
- "vitest": "4.1.10",
56
- "vitest-evals": "0.14.0"
55
+ "vitest": "4.1.10"
57
56
  },
58
57
  "engines": {
59
58
  "node": "^24.0.0"
@@ -70,10 +69,6 @@
70
69
  "precoverage": "bash ../scripts/ensure-worktree-bootstrap.sh",
71
70
  "coverage": "vitest run --coverage",
72
71
  "docs:reference": "tsx scripts/update-command-reference.ts",
73
- "eval:review": "tsx evals/review-prompts/track-b/reviewRunner.ts",
74
- "eval:review:report": "tsx evals/review-prompts/track-b/reviewReport.ts",
75
- "eval:review:rescore": "tsx evals/review-prompts/track-b/rescore.ts",
76
- "eval:review:run": "vitest run --config evals/review-prompts/vitest.eval.config.ts",
77
72
  "pack:smoke": "bash scripts/pack-smoke.sh",
78
73
  "profile:schema": "tsx scripts/generate-profile-schema.ts",
79
74
  "pretest": "bash ../scripts/ensure-worktree-bootstrap.sh",