@patronage/software-factory 1.0.0-alpha.40 → 1.0.0-alpha.41

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/index.d.ts CHANGED
@@ -239,8 +239,8 @@ declare const boundaryReviewProofBaseSchema: z.ZodObject<{
239
239
  mergedSha: z.ZodOptional<z.ZodString>;
240
240
  pr: z.ZodNumber;
241
241
  state: z.ZodEnum<{
242
- merged: "merged";
243
242
  open: "open";
243
+ merged: "merged";
244
244
  }>;
245
245
  wave: z.ZodOptional<z.ZodString>;
246
246
  }, z.core.$loose>>;
@@ -283,8 +283,8 @@ declare const boundaryReviewProofSchema: z.ZodObject<{
283
283
  mergedSha: z.ZodOptional<z.ZodString>;
284
284
  pr: z.ZodNumber;
285
285
  state: z.ZodEnum<{
286
- merged: "merged";
287
286
  open: "open";
287
+ merged: "merged";
288
288
  }>;
289
289
  wave: z.ZodOptional<z.ZodString>;
290
290
  }, z.core.$loose>>;
@@ -796,7 +796,7 @@ interface LadderCycleRef {
796
796
  stage: LadderCycleStage;
797
797
  }
798
798
  type LadderFindingReport = ReviewFindingAttributes;
799
- /** One finding as recorded in one cycle (CONTEXT.md: finding occurrence). */
799
+ /** One finding as recorded in one cycle (GLOSSARY.md: finding occurrence). */
800
800
  interface ReviewOccurrenceRecord {
801
801
  address: string;
802
802
  /** The ladder-assigned cycle number the occurrence was recorded in. */
@@ -813,7 +813,7 @@ declare const POLICY_DECLARATION_RULES: readonly ["cycle-2-severity-floor", "ide
813
813
  type PolicyDeclarationRule = (typeof POLICY_DECLARATION_RULES)[number];
814
814
  type DeclarationAuthority = "operator" | "reviewer" | "policy";
815
815
  /**
816
- * A disposition declaration as stored (CONTEXT.md: disposition declaration):
816
+ * A disposition declaration as stored (GLOSSARY.md: disposition declaration):
817
817
  * one occurrence, one disposition, the authority that made it and its
818
818
  * reference (operator, reviewer) or rule (policy).
819
819
  */
@@ -1735,14 +1735,19 @@ interface ExactHeadRunSource {
1735
1735
  //#endregion
1736
1736
  //#region src/merge-freeze.d.ts
1737
1737
  declare const MERGE_FREEZE_CHECK_NAME = "patronage-factory/merge-freeze";
1738
+ /**
1739
+ * The Factory App's slug, as GitHub serves it on the runs the writer posts.
1740
+ * It is not a trust predicate: an App chooses its own slug, so the reader
1741
+ * trusts the pinned numeric App id instead (ADR 0022, #1393).
1742
+ */
1738
1743
  declare const MERGE_FREEZE_APP_SLUG = "patronage-factory";
1739
1744
  declare const mergeFreezeStateSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
1740
1745
  active: z.ZodLiteral<true>;
1741
1746
  generationId: z.ZodNumber;
1742
1747
  headSha: z.ZodString;
1743
1748
  outcome: z.ZodEnum<{
1744
- stale: "stale";
1745
1749
  active: "active";
1750
+ stale: "stale";
1746
1751
  }>;
1747
1752
  reason: z.ZodString;
1748
1753
  recordedAt: z.ZodISODateTime;
@@ -2012,8 +2017,8 @@ declare const managedReadinessLedgerSchema: z.ZodObject<{
2012
2017
  "ready-for-human": "ready-for-human";
2013
2018
  }>;
2014
2019
  stage: z.ZodEnum<{
2015
- gate: "gate";
2016
2020
  interior: "interior";
2021
+ gate: "gate";
2017
2022
  "interior-complete": "interior-complete";
2018
2023
  }>;
2019
2024
  }, z.core.$strip>>;
@@ -2029,10 +2034,10 @@ declare const managedReadinessLedgerSchema: z.ZodObject<{
2029
2034
  reviewedHeadSha: z.ZodOptional<z.ZodString>;
2030
2035
  reviewedPatchId: z.ZodOptional<z.ZodString>;
2031
2036
  status: z.ZodEnum<{
2032
- blocked: "blocked";
2033
2037
  "not-required": "not-required";
2034
- current: "current";
2035
2038
  stale: "stale";
2039
+ blocked: "blocked";
2040
+ current: "current";
2036
2041
  missing: "missing";
2037
2042
  }>;
2038
2043
  }, z.core.$strip>;
@@ -2041,10 +2046,10 @@ declare const managedReadinessLedgerSchema: z.ZodObject<{
2041
2046
  reviewedHeadSha: z.ZodOptional<z.ZodString>;
2042
2047
  reviewedPatchId: z.ZodOptional<z.ZodString>;
2043
2048
  status: z.ZodEnum<{
2044
- blocked: "blocked";
2045
2049
  "not-required": "not-required";
2046
- current: "current";
2047
2050
  stale: "stale";
2051
+ blocked: "blocked";
2052
+ current: "current";
2048
2053
  missing: "missing";
2049
2054
  }>;
2050
2055
  }, z.core.$strip>>;
@@ -3114,10 +3119,10 @@ declare const loadEvidenceEnvelopes: (cwd: string) => LoadedEvidenceEnvelope[];
3114
3119
  //#region src/review-proof-applicability.d.ts
3115
3120
  declare const REVIEW_STATUS_VALUES: readonly ["not-required", "current", "stale", "missing", "blocked"];
3116
3121
  declare const reviewStatusSchema: z.ZodEnum<{
3117
- blocked: "blocked";
3118
3122
  "not-required": "not-required";
3119
- current: "current";
3120
3123
  stale: "stale";
3124
+ blocked: "blocked";
3125
+ current: "current";
3121
3126
  missing: "missing";
3122
3127
  }>;
3123
3128
  type ReviewStatus = z.infer<typeof reviewStatusSchema>;
@@ -3225,8 +3230,8 @@ declare const boundaryCheckProofSchema: z.ZodObject<{
3225
3230
  pr: z.ZodNumber;
3226
3231
  sha: z.ZodString;
3227
3232
  state: z.ZodEnum<{
3228
- merged: "merged";
3229
3233
  open: "open";
3234
+ merged: "merged";
3230
3235
  }>;
3231
3236
  wave: z.ZodString;
3232
3237
  }, z.core.$strip>>;
@@ -3628,6 +3633,12 @@ interface PrVerifyDependencies {
3628
3633
  }
3629
3634
  declare function runPrVerify(args: PrVerifyArgs, dependencies?: PrVerifyDependencies): PrVerifyProof;
3630
3635
  //#endregion
3636
+ //#region src/pull-request-fill.d.ts
3637
+ interface CommitMessage {
3638
+ body: string;
3639
+ subject: string;
3640
+ }
3641
+ //#endregion
3631
3642
  //#region src/pr-publish.d.ts
3632
3643
  type PrPublishArgs = Omit<PrReadyArgs, "pr" | "throwWhenBlocked"> & {
3633
3644
  /** A clean-session findings file to validate into the review proof. */findings?: string;
@@ -3726,6 +3737,12 @@ interface PrPublishDependencies extends PrReadyDependencies {
3726
3737
  ensureVerifyCheckRun?: typeof ensureFactoryCheckRunPublished;
3727
3738
  factoryCliInvocation?: FactoryCliInvocation;
3728
3739
  gh?: GhRunner;
3740
+ /**
3741
+ * The branch's commits into its base, oldest first, that a pull request
3742
+ * publish creates is titled and described from (#1366). Tests only;
3743
+ * production reads them from Git.
3744
+ */
3745
+ pullRequestCommits?: PullRequestCommits;
3729
3746
  github?: PrReadyDependencies["github"] & {
3730
3747
  editPullRequestBody?: (input: {
3731
3748
  body: string;
@@ -3741,7 +3758,10 @@ interface PrPublishDependencies extends PrReadyDependencies {
3741
3758
  * carries the publisher for the verdict it records (#1323).
3742
3759
  */
3743
3760
  runPrReview?: (args: PrReviewArgs, dependencies?: ProducerPublisher) => Promise<PrReviewProof>;
3744
- /** Settles asynchronously scheduled sink work before the handoff drain. */
3761
+ /**
3762
+ * Settles asynchronously scheduled sink work: after a review cycle publish
3763
+ * records from `--findings` (#1382), and before the handoff drain.
3764
+ */
3745
3765
  awaitPendingIngest?: () => Promise<void>;
3746
3766
  /**
3747
3767
  * The handoff drain (#390). Advisory everywhere: publish reports what it
@@ -3767,6 +3787,7 @@ interface PrPublishDependencies extends PrReadyDependencies {
3767
3787
  */
3768
3788
  sleep?: (ms: number) => Promise<void>;
3769
3789
  }
3790
+ type PullRequestCommits = (cwd: string, base: string) => CommitMessage[];
3770
3791
  /**
3771
3792
  * What became of the durable `pr:verify` binding for this publish. Reported in
3772
3793
  * the publish summary: a binding that silently failed to land is
@@ -4059,8 +4080,8 @@ declare const FACTORY_TRACE_EVENT_DEFINITIONS: readonly [DefinedTraceEvent<"revi
4059
4080
  sessionId: z.ZodOptional<z.ZodString>;
4060
4081
  }, z.core.$strict>>;
4061
4082
  stage: z.ZodEnum<{
4062
- gate: "gate";
4063
4083
  interior: "interior";
4084
+ gate: "gate";
4064
4085
  }>;
4065
4086
  usage: z.ZodOptional<z.ZodObject<{
4066
4087
  estimatedCostUsd: z.ZodOptional<z.ZodNumber>;
@@ -4112,8 +4133,8 @@ declare const FACTORY_TRACE_EVENT_DEFINITIONS: readonly [DefinedTraceEvent<"revi
4112
4133
  sessionId: z.ZodOptional<z.ZodString>;
4113
4134
  }, z.core.$strict>>;
4114
4135
  stage: z.ZodEnum<{
4115
- gate: "gate";
4116
4136
  interior: "interior";
4137
+ gate: "gate";
4117
4138
  }>;
4118
4139
  usage: z.ZodOptional<z.ZodObject<{
4119
4140
  estimatedCostUsd: z.ZodOptional<z.ZodNumber>;
@@ -4156,8 +4177,8 @@ declare const FACTORY_TRACE_EVENT_DEFINITIONS: readonly [DefinedTraceEvent<"revi
4156
4177
  sessionId: z.ZodOptional<z.ZodString>;
4157
4178
  }, z.core.$strict>>;
4158
4179
  stage: z.ZodEnum<{
4159
- gate: "gate";
4160
4180
  interior: "interior";
4181
+ gate: "gate";
4161
4182
  }>;
4162
4183
  usage: z.ZodOptional<z.ZodObject<{
4163
4184
  estimatedCostUsd: z.ZodOptional<z.ZodNumber>;
@@ -4187,7 +4208,7 @@ declare const FACTORY_TRACE_EVENT_DEFINITIONS: readonly [DefinedTraceEvent<"revi
4187
4208
  staleRepeats: number;
4188
4209
  };
4189
4210
  observedAt: string;
4190
- stage: "gate" | "interior";
4211
+ stage: "interior" | "gate";
4191
4212
  issue?: number | undefined;
4192
4213
  pr?: number | undefined;
4193
4214
  threadId?: string | undefined;
@@ -4647,13 +4668,13 @@ declare const evaluateReadiness: (input: EvaluationInput) => {
4647
4668
  reviews: {
4648
4669
  correctness: {
4649
4670
  required: boolean;
4650
- status: "blocked" | "not-required" | "current" | "stale" | "missing";
4671
+ status: "not-required" | "stale" | "blocked" | "current" | "missing";
4651
4672
  reviewedHeadSha?: string | undefined;
4652
4673
  reviewedPatchId?: string | undefined;
4653
4674
  };
4654
4675
  security?: {
4655
4676
  required: boolean;
4656
- status: "blocked" | "not-required" | "current" | "stale" | "missing";
4677
+ status: "not-required" | "stale" | "blocked" | "current" | "missing";
4657
4678
  reviewedHeadSha?: string | undefined;
4658
4679
  reviewedPatchId?: string | undefined;
4659
4680
  } | undefined;
@@ -4716,7 +4737,7 @@ declare const evaluateReadiness: (input: EvaluationInput) => {
4716
4737
  interior: number;
4717
4738
  };
4718
4739
  nextAction: "run-interior-cycle" | "advance-to-gate" | "run-gate-cycle" | "accept-nonblocking-findings" | "escalate-to-triage" | "ready-for-human";
4719
- stage: "gate" | "interior" | "interior-complete";
4740
+ stage: "interior" | "gate" | "interior-complete";
4720
4741
  forcedTransition?: "gate-cap-exhausted" | "interior-cap-reached" | undefined;
4721
4742
  } | undefined;
4722
4743
  reviewRuns?: PrReviewResult[] | undefined;
@@ -4766,13 +4787,13 @@ declare const evaluateReadiness: (input: EvaluationInput) => {
4766
4787
  reviews: {
4767
4788
  correctness: {
4768
4789
  required: boolean;
4769
- status: "blocked" | "not-required" | "current" | "stale" | "missing";
4790
+ status: "not-required" | "stale" | "blocked" | "current" | "missing";
4770
4791
  reviewedHeadSha?: string | undefined;
4771
4792
  reviewedPatchId?: string | undefined;
4772
4793
  };
4773
4794
  security?: {
4774
4795
  required: boolean;
4775
- status: "blocked" | "not-required" | "current" | "stale" | "missing";
4796
+ status: "not-required" | "stale" | "blocked" | "current" | "missing";
4776
4797
  reviewedHeadSha?: string | undefined;
4777
4798
  reviewedPatchId?: string | undefined;
4778
4799
  } | undefined;
@@ -4835,7 +4856,7 @@ declare const evaluateReadiness: (input: EvaluationInput) => {
4835
4856
  interior: number;
4836
4857
  };
4837
4858
  nextAction: "run-interior-cycle" | "advance-to-gate" | "run-gate-cycle" | "accept-nonblocking-findings" | "escalate-to-triage" | "ready-for-human";
4838
- stage: "gate" | "interior" | "interior-complete";
4859
+ stage: "interior" | "gate" | "interior-complete";
4839
4860
  forcedTransition?: "gate-cap-exhausted" | "interior-cap-reached" | undefined;
4840
4861
  } | undefined;
4841
4862
  reviewRuns?: PrReviewResult[] | undefined;
@@ -4927,7 +4948,7 @@ declare const EPIC_STRUCTURE_SCHEMA_VERSION = 1;
4927
4948
  /**
4928
4949
  * DAG-node PLANNING statuses — the planning-plane vocabulary a planner authors
4929
4950
  * on a `dag.yml` node. Carried forward by ADR 0018 and defined by the epic
4930
- * skill (`reference/epic-artifacts.md`) and both `CONTEXT.md` glossaries.
4951
+ * skill (`reference/epic-artifacts.md`) and both `GLOSSARY.md` glossaries.
4931
4952
  *
4932
4953
  * A DAG node is a unit of *plan*; an HQ lane is a unit of *runtime execution*.
4933
4954
  * These are two planes with two vocabularies and must not be conflated — the
package/dist/index.js CHANGED
@@ -22,7 +22,7 @@ import { AsyncLocalStorage } from "node:async_hooks";
22
22
  import { pathToFileURL } from "node:url";
23
23
  //#region package.json
24
24
  var name = "@patronage/software-factory";
25
- var version = "1.0.0-alpha.40";
25
+ var version = "1.0.0-alpha.41";
26
26
  //#endregion
27
27
  //#region src/git-globals-parse.ts
28
28
  const VALUE_TAKING_GIT_OPTIONS = new Set([
@@ -4353,7 +4353,7 @@ function resolveCandidateIdentity({ base, cwd, git }) {
4353
4353
  * and `resolveCandidateIdentity`'s own 40-character object-id check would
4354
4354
  * reject a legitimate 64-character patch id from a SHA-256 repository, which
4355
4355
  * the original direct call never rejected. This is a narrower view over the
4356
- * same owned machine — not a second primitive and not a new `CONTEXT.md`
4356
+ * same owned machine — not a second primitive and not a new `GLOSSARY.md`
4357
4357
  * entry.
4358
4358
  *
4359
4359
  * Takes the primitive itself, not a `git` object to read it off: the original
@@ -7305,7 +7305,7 @@ const headShaMatches = (recorded, candidate) => Boolean(recorded.headSha && cand
7305
7305
  * describes the candidate.
7306
7306
  *
7307
7307
  * Time is not an input and never will be: adding one would contradict the
7308
- * `freshness` definition in root `CONTEXT.md`.
7308
+ * `freshness` definition in root `GLOSSARY.md`.
7309
7309
  */
7310
7310
  function evidenceFresh({ candidate, recorded, rule }) {
7311
7311
  if (patchIdMatches(recorded, candidate)) return true;
@@ -9632,6 +9632,64 @@ const completeCheckRunPages = (pages) => {
9632
9632
  const runs = pages.flatMap((page) => page.check_runs);
9633
9633
  return pages.every((page) => page.total_count === runs.length) ? runs : void 0;
9634
9634
  };
9635
+ /** The same bound payload with the same status and conclusion. */
9636
+ const sameVerdict = (one, other) => one.payload !== void 0 && (one.run.status ?? "") === (other.run.status ?? "") && (one.run.conclusion ?? "") === (other.run.conclusion ?? "") && isDeepStrictEqual(one.payload, other.payload);
9637
+ /**
9638
+ * The newest generation of the `pr:verify` proof at one head (#1409), or
9639
+ * nothing when no single generation can be trusted. It is the rule #1408 gave
9640
+ * the proof resume (`proof-resume.ts`, since reverted by #1411), applied to
9641
+ * this reader:
9642
+ *
9643
+ * - A run whose bound payload transports a typed proof is ordered at the
9644
+ * `endedAt` that proof records, never by when it reached GitHub. Runs that
9645
+ * carry the same such payload with the same status and conclusion are one
9646
+ * generation posted more than once (`pr:verify` posts, `pr:publish`
9647
+ * re-posts), so an older pass re-posted after a newer failure does not
9648
+ * outrank it, and the normal post plus re-post is not a tie.
9649
+ * - Any other run is its own generation at its `started_at`: no bound payload,
9650
+ * or a proof over the text cap that travels without its typed proof. The
9651
+ * factory records a proof before it posts it, so that is the latest its
9652
+ * proof could have been recorded, and it still vetoes every pass recorded
9653
+ * before it was posted.
9654
+ * - Such a run carries no generation identity, so it is never grouped. Two
9655
+ * separate executions with the same command names and verdict post the same
9656
+ * compact payload, and so does a re-post. When the newest generation is one
9657
+ * of these and repeats another run's verdict (`sameVerdict`), it could be a
9658
+ * re-post of an older verdict or a new one, and nothing is trusted. Proofs
9659
+ * that size are rare, so refusing costs one fresh verification.
9660
+ * - Two different generations at the newest instant refuse, by the shared
9661
+ * sequencing owner's rule.
9662
+ *
9663
+ * Factory-ci's hosted proof-reuse gate applies the same rule in jq.
9664
+ */
9665
+ const newestVerifyProofGeneration = (runs, bound) => {
9666
+ const generations = [];
9667
+ for (const run of runs) {
9668
+ const parsed = parsePrVerifyCheckPayload(run.output?.text) ?? parsePrVerifyCheckPayload(run.output?.summary);
9669
+ const payload = run.head_sha === bound.sha && parsed?.headSha === bound.sha && parsed.repository === bound.repository ? parsed : void 0;
9670
+ const recordedMs = generationOrderMs(payload?.verificationProof?.endedAt);
9671
+ if (payload === void 0 || !Number.isFinite(recordedMs)) {
9672
+ generations.push({
9673
+ orderMs: generationOrderMs(run.started_at),
9674
+ ...payload === void 0 ? {} : { payload },
9675
+ recorded: false,
9676
+ run
9677
+ });
9678
+ continue;
9679
+ }
9680
+ const generation = {
9681
+ orderMs: recordedMs,
9682
+ payload,
9683
+ recorded: true,
9684
+ run
9685
+ };
9686
+ if (!generations.some((earlier) => earlier.recorded && sameVerdict(earlier, generation))) generations.push(generation);
9687
+ }
9688
+ const selected = selectNewestGeneration(generations);
9689
+ if (selected.kind !== "newest") return;
9690
+ const newest = selected.generation;
9691
+ return !newest.recorded && newest.payload !== void 0 && generations.some((generation) => generation !== newest && sameVerdict(generation, newest)) ? void 0 : newest;
9692
+ };
9635
9693
  /**
9636
9694
  * Read the machine-readable `pr:verify` binding for one commit (#247).
9637
9695
  *
@@ -9659,20 +9717,18 @@ function fetchPrVerifyProofBinding({ expectedAppId, githubApp, owner, repo, sha,
9659
9717
  }
9660
9718
  const runs = completeCheckRunPages(pages);
9661
9719
  if (!runs) return;
9662
- const ordered = runs.filter((run) => run?.name === checkName && checkRunProducedByFactoryApp({
9720
+ const owned = runs.filter((run) => run?.name === checkName && checkRunProducedByFactoryApp({
9663
9721
  app: run.app,
9664
9722
  expectedAppId: resolvedAppId
9665
- })).map((run) => ({
9666
- orderMs: generationOrderMs(run.started_at),
9667
- run
9668
9723
  }));
9669
- if (ordered.some(({ orderMs }) => !Number.isFinite(orderMs))) return;
9670
- const selected = selectNewestGeneration(ordered);
9671
- if (selected.kind !== "newest") return;
9672
- const { run } = selected.generation;
9673
- if (run.status !== "completed" || run.head_sha !== sha) return;
9674
- const payload = parsePrVerifyCheckPayload(run.output?.text) ?? parsePrVerifyCheckPayload(run.output?.summary);
9675
- if (!payload || payload.headSha !== sha || payload.repository !== `${owner}/${repo}`) return;
9724
+ if (owned.some((run) => !Number.isFinite(generationOrderMs(run.started_at)))) return;
9725
+ const newest = newestVerifyProofGeneration(owned, {
9726
+ repository: `${owner}/${repo}`,
9727
+ sha
9728
+ });
9729
+ if (newest === void 0) return;
9730
+ const { payload, run } = newest;
9731
+ if (run.status !== "completed" || !payload) return;
9676
9732
  const producer = checkRunProducedByFactoryApp({
9677
9733
  app: run.app,
9678
9734
  expectedAppId: resolvedAppId
@@ -14606,8 +14662,9 @@ function buildEpicCloseoutReport(input) {
14606
14662
  *
14607
14663
  * `factory:closeout` reads the lane's native at-rest provider logs by its
14608
14664
  * session join keys and records what they say as closeout metric rows. The
14609
- * rows land in the one local closeout markdown, which is the read path the
14610
- * `patronage-software-factory-lookback` skill uses.
14665
+ * rows land in the one local closeout markdown, and the closeout artifact
14666
+ * carries them to HQ as an advisory handoff. The weekly look-back no longer
14667
+ * reads token cost (#1433).
14611
14668
  *
14612
14669
  * Harvest NEVER throws: a missing or unreadable log degrades to an absent
14613
14670
  * family plus a data gap, so telemetry content can never fail the closeout.
@@ -16686,7 +16743,7 @@ const EPIC_STRUCTURE_SCHEMA_VERSION = 1;
16686
16743
  /**
16687
16744
  * DAG-node PLANNING statuses — the planning-plane vocabulary a planner authors
16688
16745
  * on a `dag.yml` node. Carried forward by ADR 0018 and defined by the epic
16689
- * skill (`reference/epic-artifacts.md`) and both `CONTEXT.md` glossaries.
16746
+ * skill (`reference/epic-artifacts.md`) and both `GLOSSARY.md` glossaries.
16690
16747
  *
16691
16748
  * A DAG node is a unit of *plan*; an HQ lane is a unit of *runtime execution*.
16692
16749
  * These are two planes with two vocabularies and must not be conflated — the
@@ -17756,6 +17813,11 @@ function armAutoMerge(input, dependencies = {}) {
17756
17813
  //#endregion
17757
17814
  //#region src/merge-freeze.ts
17758
17815
  const MERGE_FREEZE_CHECK_NAME = "patronage-factory/merge-freeze";
17816
+ /**
17817
+ * The Factory App's slug, as GitHub serves it on the runs the writer posts.
17818
+ * It is not a trust predicate: an App chooses its own slug, so the reader
17819
+ * trusts the pinned numeric App id instead (ADR 0022, #1393).
17820
+ */
17759
17821
  const MERGE_FREEZE_APP_SLUG = "patronage-factory";
17760
17822
  const MERGE_FREEZE_SCHEMA_VERSION = 1;
17761
17823
  const CHECK_RUNS_PER_PAGE$1 = 100;
@@ -17806,7 +17868,10 @@ function validateMergeFreezeState(value) {
17806
17868
  return mergeFreezeStateSchema.parse(value);
17807
17869
  }
17808
17870
  const mergeFreezeCheckRunListItemSchema = z.object({
17809
- app: z.object({ slug: z.literal(MERGE_FREEZE_APP_SLUG) }),
17871
+ app: z.object({
17872
+ id: z.number(),
17873
+ slug: z.string().nullable().optional()
17874
+ }),
17810
17875
  conclusion: z.enum([
17811
17876
  "failure",
17812
17877
  "neutral",
@@ -17856,7 +17921,14 @@ const commitParentsSchema = z.object({
17856
17921
  sha: shaSchema$2
17857
17922
  });
17858
17923
  function selectListedMergeFreezeGeneration(listed, expectedHeadSha) {
17859
- const runs = z.object({ check_runs: z.array(z.unknown()) }).parse(listed).check_runs.map((run) => mergeFreezeCheckRunListItemSchema.parse(run));
17924
+ const runs = z.object({ check_runs: z.array(z.unknown()) }).parse(listed).check_runs.map((run) => {
17925
+ const listedRun = mergeFreezeCheckRunListItemSchema.parse(run);
17926
+ if (!checkRunProducedByFactoryApp({
17927
+ app: listedRun.app,
17928
+ expectedAppId: FACTORY_PROOF_GATE_APP_ID
17929
+ })) throw new Error(`${MERGE_FREEZE_CHECK_NAME} check run ${listedRun.id} was not written by the pinned Factory App ${FACTORY_PROOF_GATE_APP_ID}.`);
17930
+ return listedRun;
17931
+ });
17860
17932
  if (runs.length === 0) return { kind: "missing" };
17861
17933
  const selected = selectNewestGeneration(runs.map((run) => ({
17862
17934
  orderMs: generationOrderMs(run.started_at),
@@ -22143,6 +22215,35 @@ const admittedPullRequestBodyEdit = (admission) => async ({ body, owner, repo, p
22143
22215
  repo
22144
22216
  }), process.cwd(), extraEnv === void 0 ? {} : { extraEnv });
22145
22217
  };
22218
+ /**
22219
+ * `gh pr create` for the draft (#1366). With a base, the title and body come
22220
+ * from the branch's commits, built as the Cursor VM's REST create builds them
22221
+ * (#1327). gh's own `--fill` keeps only the commit subjects once a branch has
22222
+ * two commits, which dropped every `Closes #N` line in a commit body, and
22223
+ * membership derives from those lines. With no base there is no range to
22224
+ * read, so gh fills from the repository default branch, every commit body
22225
+ * included (`--fill-verbose`).
22226
+ */
22227
+ const ghArgsForPullRequestCreate = ({ base, commits, cwd }) => {
22228
+ if (base === void 0) return [
22229
+ "pr",
22230
+ "create",
22231
+ "--draft",
22232
+ "--fill-verbose"
22233
+ ];
22234
+ const { body, title } = pullRequestFill(commits(cwd, base));
22235
+ return [
22236
+ "pr",
22237
+ "create",
22238
+ "--draft",
22239
+ "--title",
22240
+ title,
22241
+ "--body",
22242
+ body,
22243
+ "--base",
22244
+ base
22245
+ ];
22246
+ };
22146
22247
  /** The REST create a Cursor VM uses in place of `gh pr create` (#1327). */
22147
22248
  const ghApiArgsForPullRequestCreate = ({ base, body, head, owner, repo, title }) => [
22148
22249
  "api",
@@ -22169,13 +22270,18 @@ const ghApiArgsForPullRequestCreate = ({ base, body, head, owner, repo, title })
22169
22270
  * reads both branch refs, which is why the admission scope carries
22170
22271
  * `contents: read` (#1375). The title and body come from the branch's
22171
22272
  * commits, and the head is the already-pushed branch, so nothing is pushed.
22172
- * Off a Cursor VM the call is `gh pr create`, unchanged.
22273
+ * Off a Cursor VM the call is `gh pr create`, with the same title and body
22274
+ * (#1366).
22173
22275
  */
22174
- const admittedPullRequestCreate = (admission, repository) => async ({ args, base, branch, cwd }) => {
22276
+ const admittedPullRequestCreate = (admission, repository, commits) => async ({ base, branch, cwd }) => {
22175
22277
  const extraEnv = await admission.ghEnv("create-pull-request", repository);
22176
- if (extraEnv === void 0) return runCapture("gh", args, cwd).stdout;
22278
+ if (extraEnv === void 0) return runCapture("gh", ghArgsForPullRequestCreate({
22279
+ base,
22280
+ commits,
22281
+ cwd
22282
+ }), cwd).stdout;
22177
22283
  if (base === void 0) throw new Error("pr:publish on a Cursor VM needs a base branch to create the pull request against, and none was passed or recorded. Run pr:verify, which records its base, or pass --base.");
22178
- const { body, title } = pullRequestFill(commitsSinceBase(cwd, base));
22284
+ const { body, title } = pullRequestFill(commits(cwd, base));
22179
22285
  return runCapture("gh", ghApiArgsForPullRequestCreate({
22180
22286
  base,
22181
22287
  body,
@@ -22194,9 +22300,14 @@ const admittedPullRequestCreate = (admission, repository) => async ({ args, base
22194
22300
  */
22195
22301
  const publishGithubAdapters = (dependencies, repository) => {
22196
22302
  const admission = dependencies.admission ?? processAdmissionCredential;
22303
+ const commits = dependencies.pullRequestCommits ?? commitsSinceBase;
22197
22304
  const injectedGh = dependencies.gh;
22198
22305
  return {
22199
- create: injectedGh ? ({ args, cwd }) => injectedGh(args, cwd) : admittedPullRequestCreate(admission, repository),
22306
+ create: injectedGh ? ({ base, cwd }) => injectedGh(ghArgsForPullRequestCreate({
22307
+ base,
22308
+ commits,
22309
+ cwd
22310
+ }), cwd) : admittedPullRequestCreate(admission, repository, commits),
22200
22311
  github: dependencies.github ?? {
22201
22312
  ...defaultPrReadyGithub(),
22202
22313
  editPullRequestBody: admittedPullRequestBodyEdit(admission)
@@ -22289,15 +22400,7 @@ async function discoverOrCreatePullRequest({ args, branch, create, cwd, gh, revi
22289
22400
  reviewProofPath,
22290
22401
  verifyProofPath
22291
22402
  });
22292
- const createArgs = [
22293
- "pr",
22294
- "create",
22295
- "--draft",
22296
- "--fill"
22297
- ];
22298
- if (creationBase !== void 0) createArgs.push("--base", creationBase);
22299
22403
  await create({
22300
- args: createArgs,
22301
22404
  base: creationBase,
22302
22405
  branch,
22303
22406
  cwd
@@ -22469,6 +22572,18 @@ async function ensureVerifyProof({ args, cwd, dependencies, headSha, pr, verifyP
22469
22572
  };
22470
22573
  }
22471
22574
  const reviewNotRequired = (proof) => proof.reviewRequirement?.status === "not-required";
22575
+ /**
22576
+ * Let the `pr-review-proof` event a cycle recorded from `--findings` reach HQ
22577
+ * or the spool before publish goes on (#1382). The sink's setup budget starts
22578
+ * when `pr:review` enqueues the event, and its first step waits for the event
22579
+ * loop. Standalone `pr:review` exits next, so the loop is free. Publish goes
22580
+ * straight on to synchronous `gh` calls, which held the loop past that budget,
22581
+ * so the sink gave up before spooling anything. Bounded by the sink's own
22582
+ * budgets.
22583
+ */
22584
+ const settleRecordedReviewEvent = async (dependencies) => {
22585
+ await (dependencies.awaitPendingIngest ?? awaitPendingHqIngest)();
22586
+ };
22472
22587
  async function ensureReviewProof({ args, cwd, dependencies, currentReviewIdentity, pr, reviewProofPath }) {
22473
22588
  const proof = readOptionalReviewProof(cwd, reviewProofPath);
22474
22589
  const ladderPolicy = resolveReviewLadderPolicy();
@@ -22497,9 +22612,11 @@ async function ensureReviewProof({ args, cwd, dependencies, currentReviewIdentit
22497
22612
  verifyProof: args.verifyProof
22498
22613
  }, publisher.dependencies);
22499
22614
  } catch (error) {
22615
+ await settleRecordedReviewEvent(dependencies);
22500
22616
  await publisher.post()?.settled;
22501
22617
  throw error;
22502
22618
  }
22619
+ await settleRecordedReviewEvent(dependencies);
22503
22620
  const producerPost = publisher.post();
22504
22621
  return {
22505
22622
  ...producerPost === void 0 ? {} : { producerPost },
package/dist/schemas.d.ts CHANGED
@@ -66,7 +66,7 @@ type EvidenceReviewRung = (typeof EVIDENCE_REVIEW_RUNGS)[number];
66
66
  //#region src/review-ladder-ledger.d.ts
67
67
  type LadderCycleStage = "interior" | "gate";
68
68
  type LadderFindingReport = ReviewFindingAttributes;
69
- /** One finding as recorded in one cycle (CONTEXT.md: finding occurrence). */
69
+ /** One finding as recorded in one cycle (GLOSSARY.md: finding occurrence). */
70
70
  interface ReviewOccurrenceRecord {
71
71
  address: string;
72
72
  /** The ladder-assigned cycle number the occurrence was recorded in. */
@@ -82,7 +82,7 @@ interface ReviewOccurrenceRecord {
82
82
  declare const POLICY_DECLARATION_RULES: readonly ["cycle-2-severity-floor", "identity-repeat"];
83
83
  type PolicyDeclarationRule = (typeof POLICY_DECLARATION_RULES)[number];
84
84
  /**
85
- * A disposition declaration as stored (CONTEXT.md: disposition declaration):
85
+ * A disposition declaration as stored (GLOSSARY.md: disposition declaration):
86
86
  * one occurrence, one disposition, the authority that made it and its
87
87
  * reference (operator, reviewer) or rule (policy).
88
88
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patronage/software-factory",
3
- "version": "1.0.0-alpha.40",
3
+ "version": "1.0.0-alpha.41",
4
4
  "description": "Shared Patronage software factory CLI and project-profile validation tools",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -15,7 +15,7 @@
15
15
  "files": [
16
16
  "dist",
17
17
  "README.md",
18
- "CONTEXT.md"
18
+ "GLOSSARY.md"
19
19
  ],
20
20
  "type": "module",
21
21
  "exports": {
@@ -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.40"
40
+ "@patronage/factory-ci": "1.0.0-alpha.41"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/node": "24.13.3",
File without changes