@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 +46 -25
- package/dist/index.js +149 -32
- package/dist/schemas.d.ts +2 -2
- package/package.json +3 -3
- /package/{CONTEXT.md → GLOSSARY.md} +0 -0
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 (
|
|
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 (
|
|
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
|
-
/**
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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 `
|
|
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.
|
|
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 `
|
|
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 `
|
|
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
|
|
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 (
|
|
9670
|
-
const
|
|
9671
|
-
|
|
9672
|
-
|
|
9673
|
-
|
|
9674
|
-
|
|
9675
|
-
|
|
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,
|
|
14610
|
-
*
|
|
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 `
|
|
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({
|
|
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) =>
|
|
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`,
|
|
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 ({
|
|
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",
|
|
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(
|
|
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 ? ({
|
|
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 (
|
|
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 (
|
|
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.
|
|
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
|
-
"
|
|
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
|
+
"@patronage/factory-ci": "1.0.0-alpha.41"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/node": "24.13.3",
|
|
File without changes
|