@patronage/software-factory 1.0.0-alpha.3 → 1.0.0-alpha.30

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
@@ -1,8 +1,98 @@
1
- import { existsSync, readFileSync, rmSync } from "node:fs";
2
1
  import { Command } from "commander";
3
2
  import { z } from "zod";
4
- import { readFile } from "node:fs/promises";
3
+ import { existsSync, readFileSync, rmSync } from "node:fs";
4
+ import { PreviewProofRegistration } from "@patronage/factory-ci";
5
5
 
6
+ //#region src/review-rungs.d.ts
7
+ declare const EVIDENCE_REVIEW_RUNGS: readonly ["independent-model", "oracle", "human"];
8
+ type EvidenceReviewRung = (typeof EVIDENCE_REVIEW_RUNGS)[number];
9
+ declare namespace boundary_manifest_d_exports {
10
+ export { BOUNDARY_CLOSEOUT_DEFAULT_RUNG, BOUNDARY_MANIFEST_SCHEMA_VERSION, BoundaryManifest, BoundaryManifestExtraction, BoundaryManifestParse, FACTORY_BOUNDARY_FENCE_LANG, boundaryManifestSchema, closeoutRungFor, extractBoundaryManifestBlock, manifestContentHash, parseBoundaryManifest, rungMeetsMinimum, specContentHash };
11
+ }
12
+ declare const FACTORY_BOUNDARY_FENCE_LANG = "factory-boundary";
13
+ declare const BOUNDARY_MANIFEST_SCHEMA_VERSION = 1;
14
+ declare const BOUNDARY_CLOSEOUT_DEFAULT_RUNG: EvidenceReviewRung;
15
+ declare const rungMeetsMinimum: (rung: EvidenceReviewRung, minimum: EvidenceReviewRung) => boolean;
16
+ declare const boundaryManifestBaseSchema: z.ZodObject<{
17
+ boundary: z.ZodString;
18
+ closeout: z.ZodOptional<z.ZodObject<{
19
+ review: z.ZodEnum<{
20
+ oracle: "oracle";
21
+ "independent-model": "independent-model";
22
+ human: "human";
23
+ }>;
24
+ }, z.core.$loose>>;
25
+ declaredBy: z.ZodString;
26
+ integrationBranch: z.ZodOptional<z.ZodString>;
27
+ schemaVersion: z.ZodLiteral<1>;
28
+ topology: z.ZodEnum<{
29
+ flagged: "flagged";
30
+ "each-to-main": "each-to-main";
31
+ stacked: "stacked";
32
+ "each-to-epic": "each-to-epic";
33
+ }>;
34
+ waves: z.ZodArray<z.ZodObject<{
35
+ autoMerge: z.ZodOptional<z.ZodBoolean>;
36
+ issues: z.ZodArray<z.ZodNumber>;
37
+ name: z.ZodString;
38
+ review: z.ZodEnum<{
39
+ oracle: "oracle";
40
+ "independent-model": "independent-model";
41
+ human: "human";
42
+ }>;
43
+ }, z.core.$loose>>;
44
+ }, z.core.$loose>;
45
+ declare const boundaryManifestSchema: z.ZodObject<{
46
+ boundary: z.ZodString;
47
+ closeout: z.ZodOptional<z.ZodObject<{
48
+ review: z.ZodEnum<{
49
+ oracle: "oracle";
50
+ "independent-model": "independent-model";
51
+ human: "human";
52
+ }>;
53
+ }, z.core.$loose>>;
54
+ declaredBy: z.ZodString;
55
+ integrationBranch: z.ZodOptional<z.ZodString>;
56
+ schemaVersion: z.ZodLiteral<1>;
57
+ topology: z.ZodEnum<{
58
+ flagged: "flagged";
59
+ "each-to-main": "each-to-main";
60
+ stacked: "stacked";
61
+ "each-to-epic": "each-to-epic";
62
+ }>;
63
+ waves: z.ZodArray<z.ZodObject<{
64
+ autoMerge: z.ZodOptional<z.ZodBoolean>;
65
+ issues: z.ZodArray<z.ZodNumber>;
66
+ name: z.ZodString;
67
+ review: z.ZodEnum<{
68
+ oracle: "oracle";
69
+ "independent-model": "independent-model";
70
+ human: "human";
71
+ }>;
72
+ }, z.core.$loose>>;
73
+ }, z.core.$loose>;
74
+ type BoundaryManifest = z.infer<typeof boundaryManifestBaseSchema>;
75
+ type BoundaryManifestExtraction = {
76
+ ok: true;
77
+ blockText: string;
78
+ } | {
79
+ ok: false;
80
+ error: string;
81
+ };
82
+ declare const extractBoundaryManifestBlock: (issueBody: string) => BoundaryManifestExtraction;
83
+ declare const manifestContentHash: (blockText: string) => string;
84
+ declare const specContentHash: (issueBody: string) => string;
85
+ type BoundaryManifestParse = {
86
+ ok: true;
87
+ manifest: BoundaryManifest;
88
+ manifestHash: string;
89
+ } | {
90
+ ok: false;
91
+ error: string;
92
+ };
93
+ declare const parseBoundaryManifest: (issueBody: string) => BoundaryManifestParse;
94
+ declare const closeoutRungFor: (manifest: BoundaryManifest) => EvidenceReviewRung;
95
+ //#endregion
6
96
  //#region src/github-issue-comments.d.ts
7
97
  interface GithubIssueCommentApi {
8
98
  body: string;
@@ -127,6 +217,120 @@ declare const selectBoundaryReviewProof: (comments: GithubIssueComment[], bounda
127
217
  declare const boundaryReviewProofAuthorsSeen: (comments: GithubIssueComment[], boundary: string) => string[];
128
218
  declare const undispositionedBlockingFindings: (proof: BoundaryReviewProof) => string[];
129
219
  //#endregion
220
+ //#region src/boundary-membership-graph.d.ts
221
+ /** The boundary-manifest wave demand that applies to one pull request. */
222
+ interface WaveReviewDemand {
223
+ autoMerge: boolean;
224
+ review: EvidenceReviewRung;
225
+ wave: string;
226
+ }
227
+ interface BoundaryPullRequestRef {
228
+ baseRefName?: string;
229
+ headRefOid?: string;
230
+ headRefName?: string;
231
+ mergeCommitOid?: string;
232
+ /** GitHub's merge timestamp; the merge-ordering fact topology reads (#821). */
233
+ mergedAt?: string;
234
+ number: number;
235
+ state: "OPEN" | "CLOSED" | "MERGED";
236
+ }
237
+ //#endregion
238
+ //#region src/demand-waiver.d.ts
239
+ declare const DEFAULT_DEMAND_WAIVER_PATH = ".factory-memory/demand-waivers.json";
240
+ /** One recorded operator act: this demand, on this candidate, waived. */
241
+ interface DemandWaiver {
242
+ candidate: {
243
+ headSha: string;
244
+ pr: number;
245
+ };
246
+ demand: string;
247
+ /** The authenticated GitHub account that recorded the waiver. */
248
+ operator: string;
249
+ rationale: string;
250
+ recordedAt: string;
251
+ /** Optional audit metadata; never waiver authority. */
252
+ session?: string;
253
+ }
254
+ interface DemandWaiverStore {
255
+ command: "patronage-factory demand:waive";
256
+ schemaVersion: 1;
257
+ waivers: DemandWaiver[];
258
+ }
259
+ declare const validateDemandWaiverStore: (value: unknown) => DemandWaiverStore;
260
+ /**
261
+ * A demand that was in force, was NOT met, and was waived by the operator.
262
+ *
263
+ * `unmetReasons` is required and non-empty: every reason the demand refused is
264
+ * carried through verbatim. There is no field on this record that could say
265
+ * "satisfied", and no code path constructs one without a refusal to carry.
266
+ */
267
+ interface WaivedDemand {
268
+ demand: string;
269
+ operator: string;
270
+ rationale: string;
271
+ recordedAt: string;
272
+ session?: string;
273
+ /** The demand's refusals at evaluation time, preserved verbatim. */
274
+ unmetReasons: string[];
275
+ }
276
+ declare const waivedDemandSchema: z.ZodType<WaivedDemand>;
277
+ /** The waivers that bind one candidate: same PR, same head. */
278
+ declare const selectWaiversForCandidate: ({
279
+ headSha,
280
+ pr,
281
+ waivers
282
+ }: {
283
+ headSha: string | undefined;
284
+ pr: number;
285
+ waivers: readonly DemandWaiver[];
286
+ }) => DemandWaiver[];
287
+ interface DemandOutcome {
288
+ blockingReasons: string[];
289
+ waived?: WaivedDemand;
290
+ }
291
+ /**
292
+ * Fold one resolved demand's refusals through the operator's waivers.
293
+ *
294
+ * A satisfied demand (no refusals) stays satisfied and the waiver stays inert
295
+ * — a waiver can only ever move a demand from *unmet-and-blocking* to
296
+ * *unmet-and-waived*, never to met.
297
+ */
298
+ declare const applyDemandWaiver: ({
299
+ demand,
300
+ reasons,
301
+ waivers
302
+ }: {
303
+ demand: string;
304
+ reasons: readonly string[];
305
+ waivers: readonly DemandWaiver[];
306
+ }) => DemandOutcome;
307
+ /** How a waived demand reads to a human. Never the word "satisfied". */
308
+ declare const waivedDemandNotice: (waived: WaivedDemand) => string;
309
+ interface DemandWaiverAuthorization {
310
+ operator: string;
311
+ session?: string;
312
+ }
313
+ type AuthorizeDemandWaiverResult = {
314
+ authorization: DemandWaiverAuthorization;
315
+ refusals?: undefined;
316
+ } | {
317
+ authorization?: undefined;
318
+ refusals: string[];
319
+ };
320
+ /**
321
+ * Operator identity, `declaredBy`-style: a named human account, recorded on
322
+ * the waiver and enforced here. Session is optional audit metadata only: it is
323
+ * not credential-backed, so its absence or equality never authorizes or
324
+ * refuses an operator act.
325
+ */
326
+ declare const authorizeDemandWaiver: ({
327
+ authenticatedLogin,
328
+ session
329
+ }: {
330
+ authenticatedLogin: string | undefined;
331
+ session: string | undefined;
332
+ }) => AuthorizeDemandWaiverResult;
333
+ //#endregion
130
334
  //#region src/hq-ingest-sink.d.ts
131
335
  interface HqIngestDependencies {
132
336
  /**
@@ -145,8 +349,6 @@ interface HqIngestDependencies {
145
349
  * `timeoutMs`: see the note there.
146
350
  */
147
351
  journalFlushBudgetMs?: number;
148
- /** @deprecated Legacy sidecars are now streamed directly; retained for API compatibility. */
149
- sidecarReclaimMs?: number;
150
352
  /**
151
353
  * Setup budget for callers that own the process lifetime — honored AS GIVEN,
152
354
  * above the `DEFAULT_HQ_INGEST_TIMEOUT_MS` ceiling that clamps `timeoutMs`.
@@ -182,14 +384,17 @@ interface HqSpoolEntryOutcome {
182
384
  detail?: string;
183
385
  eventId: string;
184
386
  kind: string;
387
+ /**
388
+ * `true` when HQ refused the content as schema-invalid (HTTP 422, #739).
389
+ * The same bytes get the same verdict on every retry under the current
390
+ * ingest schema, so retrying without a schema change cannot succeed.
391
+ * Distinct from `undeliverable`: an HQ schema fix can still admit these
392
+ * bytes, so eviction is an operator decision (`hq:flush --evict-permanent`),
393
+ * never automatic.
394
+ */
395
+ permanent?: boolean;
185
396
  spool: string;
186
397
  /**
187
- * `migrated` belongs to the legacy JSONL journal only: the row was moved
188
- * into the current spool without being delivered. The spool pass that runs
189
- * after it in the same drain supersedes that line with a real outcome when
190
- * it gets to the row; a `migrated` line that survives the run means the row
191
- * is still waiting.
192
- *
193
398
  * `undeliverable` is the one terminal verdict (#445). Every other status
194
399
  * describes a moment: HQ was unreachable, HQ refused this content today, the
195
400
  * row moved. Retrying is meaningful for all of them. A wrong-origin entry is
@@ -198,15 +403,20 @@ interface HqSpoolEntryOutcome {
198
403
  * run. Leaving it spooled asks the operator to retry something that provably
199
404
  * cannot succeed, and the count it inflates is the one doctor goes red on.
200
405
  */
201
- status: "delivered" | "duplicate" | "migrated" | "rejected" | "undeliverable" | "unreachable";
406
+ status: "delivered" | "duplicate" | "rejected" | "undeliverable" | "unreachable";
202
407
  }
203
408
  interface HqSpoolFlushInput {
204
409
  clientId: string;
205
410
  clientSecret: string;
206
- /** Repository root whose legacy `.factory-memory` spool is also drained. */
207
- cwd: string;
208
411
  /** The profile's HQ origin; entries recorded against another are refused. */
209
412
  endpoint: string;
413
+ /**
414
+ * Disposition schema-permanent rejections (HTTP 422) in place with the
415
+ * `.undeliverable` suffix instead of retaining them (#739). Operator
416
+ * opt-in: a later HQ schema fix can still admit the same bytes, so the
417
+ * drain never evicts on its own.
418
+ */
419
+ evictPermanentRejections?: boolean;
210
420
  /** Operator-named spool directories; replaces the default two locations. */
211
421
  explicitDirectories?: string[];
212
422
  repository: HqSpoolRepository;
@@ -239,13 +449,13 @@ interface HqSpoolFlushSummary {
239
449
  interface HqSpoolWorkCount {
240
450
  /**
241
451
  * The earliest moment learned across pending spool files (their own write
242
- * time) and legacy journal rows (their own `failedAt`). Absent only when
452
+ * time). Absent only when
243
453
  * `pending` is `0`, or when every timestamp source was unreadable within
244
454
  * budget — an estimate for doctor's remediation message (#394), never a
245
455
  * precise audit trail.
246
456
  */
247
457
  oldestQueuedAt?: string;
248
- /** Spooled events and replayable journals waiting in the locations below. */
458
+ /** Spooled events waiting in the locations below. */
249
459
  pending: number;
250
460
  /** Locations that exist and hold spooled work. */
251
461
  spools: string[];
@@ -266,7 +476,7 @@ interface HqSpoolWorkCount {
266
476
  * same locations `flushHqSpool` drains are inspected here, read-only: no
267
477
  * directory is created, nothing is secured, and nothing is delivered.
268
478
  */
269
- declare function countHqSpoolWork(input: Pick<HqSpoolFlushInput, "cwd" | "explicitDirectories" | "repository">, dependencies?: {
479
+ declare function countHqSpoolWork(input: Pick<HqSpoolFlushInput, "explicitDirectories" | "repository">, dependencies?: {
270
480
  budgetMs?: number;
271
481
  env?: NodeJS.ProcessEnv;
272
482
  }): Promise<HqSpoolWorkCount>;
@@ -275,7 +485,7 @@ interface HqSpoolOrphan {
275
485
  /** The `hq-retry-spool` directory itself, ready to pass to `--dir`. */
276
486
  directory: string;
277
487
  oldestQueuedAt?: string;
278
- /** Spooled events and journal rows waiting there. */
488
+ /** Spooled events waiting there. */
279
489
  pending: number;
280
490
  /**
281
491
  * The location exists but could not be listed. As everywhere else in this
@@ -358,101 +568,270 @@ declare function sweepHqSpoolOrphans(input: {
358
568
  env?: NodeJS.ProcessEnv;
359
569
  }): Promise<HqSpoolOrphanSweep>;
360
570
  //#endregion
361
- //#region src/demand-waiver.d.ts
362
- declare const DEFAULT_DEMAND_WAIVER_PATH = ".factory-memory/demand-waivers.json";
363
- /** One recorded operator act: this demand, on this candidate, waived. */
364
- interface DemandWaiver {
365
- candidate: {
366
- headSha: string;
367
- pr: number;
571
+ //#region src/packages/review-prompt-sections/schema.d.ts
572
+ declare const reviewPromptSectionSchema: z.ZodObject<{
573
+ provenance: z.ZodEnum<{
574
+ "coding-standards": "coding-standards";
575
+ "prior-review-ledger": "prior-review-ledger";
576
+ "issue-review-focus": "issue-review-focus";
577
+ }>;
578
+ source: z.ZodString;
579
+ text: z.ZodString;
580
+ }, z.core.$strict>;
581
+ type ReviewPromptSection = z.infer<typeof reviewPromptSectionSchema>;
582
+ type ReviewPromptSectionProvenance = ReviewPromptSection["provenance"];
583
+ declare const reviewPromptSectionsSchema: z.ZodArray<z.ZodObject<{
584
+ provenance: z.ZodEnum<{
585
+ "coding-standards": "coding-standards";
586
+ "prior-review-ledger": "prior-review-ledger";
587
+ "issue-review-focus": "issue-review-focus";
588
+ }>;
589
+ source: z.ZodString;
590
+ text: z.ZodString;
591
+ }, z.core.$strict>>;
592
+ //#endregion
593
+ //#region src/policy-resolution.d.ts
594
+ /** How a gate resolved the review policy it evaluated a candidate under. */
595
+ declare const policyResolutionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
596
+ basePolicyDigest: z.ZodString;
597
+ baseRefName: z.ZodString;
598
+ candidatePolicyDigest: z.ZodString;
599
+ effectiveDigest: z.ZodString;
600
+ policyBaseSha: z.ZodString;
601
+ reviewPolicyChanged: z.ZodBoolean;
602
+ status: z.ZodLiteral<"authoritative">;
603
+ }, z.core.$strict>, z.ZodObject<{
604
+ baseRefName: z.ZodString;
605
+ reason: z.ZodString;
606
+ status: z.ZodLiteral<"unresolved">;
607
+ }, z.core.$strict>], "status">;
608
+ type PolicyResolution = z.infer<typeof policyResolutionSchema>;
609
+ //#endregion
610
+ //#region src/review-ladder-policy.d.ts
611
+ type ReviewFindingSeverity = "critical" | "high" | "medium" | "low" | "unknown";
612
+ type ReviewFindingCategory = "correctness" | "safety" | "coordination" | "maintainability" | "unknown";
613
+ declare const REVIEW_SEVERITIES: readonly ["critical", "high", "medium", "low", "unknown"];
614
+ declare const FINDING_DISPOSITIONS: readonly ["open", "fixed-in-thread", "follow-up-filed", "waived", "stale-repeat", "rerun-noise"];
615
+ type FindingDisposition = (typeof FINDING_DISPOSITIONS)[number];
616
+ interface ReviewFindingAttributes {
617
+ blockingAfterCap?: boolean;
618
+ category?: string;
619
+ citedSpan?: string;
620
+ file?: string;
621
+ prescribedAction?: string;
622
+ priority?: string;
623
+ supersedes?: {
624
+ file?: string;
625
+ title: string;
368
626
  };
369
- demand: string;
370
- /** The authenticated GitHub account that recorded the waiver. */
371
- operator: string;
372
- rationale: string;
373
- recordedAt: string;
374
- /** Optional audit metadata; never waiver authority. */
375
- session?: string;
627
+ title: string;
376
628
  }
377
- interface DemandWaiverStore {
378
- command: "patronage-factory demand:waive";
379
- schemaVersion: 1;
380
- waivers: DemandWaiver[];
629
+ interface ReviewLadderPolicy {
630
+ gate: {
631
+ cap: number;
632
+ };
381
633
  }
382
- declare const validateDemandWaiverStore: (value: unknown) => DemandWaiverStore;
383
- /**
384
- * A demand that was in force, was NOT met, and was waived by the operator.
385
- *
386
- * `unmetReasons` is required and non-empty: every reason the demand refused is
387
- * carried through verbatim. There is no field on this record that could say
388
- * "satisfied", and no code path constructs one without a refusal to carry.
389
- */
390
- interface WaivedDemand {
391
- demand: string;
392
- operator: string;
393
- rationale: string;
394
- recordedAt: string;
395
- session?: string;
396
- /** The demand's refusals at evaluation time, preserved verbatim. */
397
- unmetReasons: string[];
634
+ //#endregion
635
+ //#region src/review-ladder-ledger.d.ts
636
+ type LadderCycleStage = "interior" | "gate";
637
+ interface LadderCycleRef {
638
+ cycle: number;
639
+ stage: LadderCycleStage;
398
640
  }
399
- declare const waivedDemandSchema: z.ZodType<WaivedDemand>;
400
- /** The waivers that bind one candidate: same PR, same head. */
401
- declare const selectWaiversForCandidate: ({
402
- headSha,
403
- pr,
404
- waivers
405
- }: {
406
- headSha: string | undefined;
407
- pr: number;
408
- waivers: readonly DemandWaiver[];
409
- }) => DemandWaiver[];
410
- interface DemandOutcome {
411
- blockingReasons: string[];
412
- waived?: WaivedDemand;
641
+ type LadderFindingReport = ReviewFindingAttributes;
642
+ type DeclarableFindingDisposition = Exclude<FindingDisposition, "open" | "stale-repeat" | "rerun-noise">;
643
+ interface LadderDispositionDeclaration {
644
+ disposition: DeclarableFindingDisposition;
645
+ finding: {
646
+ file?: string;
647
+ title: string;
648
+ };
649
+ findingReport?: LadderFindingReport;
650
+ reference?: string;
413
651
  }
414
- /**
415
- * Fold one resolved demand's refusals through the operator's waivers.
416
- *
417
- * A satisfied demand (no refusals) stays satisfied and the waiver stays inert
418
- * — a waiver can only ever move a demand from *unmet-and-blocking* to
419
- * *unmet-and-waived*, never to met.
420
- */
421
- declare const applyDemandWaiver: ({
422
- demand,
423
- reasons,
424
- waivers
425
- }: {
426
- demand: string;
427
- reasons: readonly string[];
428
- waivers: readonly DemandWaiver[];
429
- }) => DemandOutcome;
430
- /** How a waived demand reads to a human. Never the word "satisfied". */
431
- declare const waivedDemandNotice: (waived: WaivedDemand) => string;
432
- interface DemandWaiverAuthorization {
433
- operator: string;
434
- session?: string;
652
+ interface FindingLedgerEntry extends ReviewFindingAttributes {
653
+ disposition: FindingDisposition;
654
+ firstFlagged: LadderCycleRef;
655
+ flagCount: number;
656
+ key: string;
657
+ lastFlagged: LadderCycleRef;
658
+ priorDisposition?: FindingDisposition;
659
+ reference?: string;
660
+ reopenedCount: number;
661
+ staleRepeatCount: number;
435
662
  }
436
- type AuthorizeDemandWaiverResult = {
437
- authorization: DemandWaiverAuthorization;
438
- refusals?: undefined;
663
+ //#endregion
664
+ //#region src/review-ladder.d.ts
665
+ type ReviewLadderExecutedStage = "interior" | "gate";
666
+ interface LadderSessionAttribution {
667
+ orchestrationMode?: "autonomous" | "manual";
668
+ resumedSession?: boolean;
669
+ runtime?: string;
670
+ sessionId?: string;
671
+ }
672
+ interface LadderUsageReport {
673
+ estimatedCostUsd?: number;
674
+ source?: string;
675
+ totalTokens?: number;
676
+ }
677
+ interface ReviewLadderCycle {
678
+ dispositions?: LadderDispositionDeclaration[];
679
+ engine?: string;
680
+ findings: LadderFindingReport[];
681
+ identity?: {
682
+ headSha: string;
683
+ patchId: string;
684
+ };
685
+ historical?: true;
686
+ model?: string;
687
+ correlatedRerun?: boolean;
688
+ session?: LadderSessionAttribution;
689
+ stage: LadderCycleStage;
690
+ usage?: LadderUsageReport;
691
+ }
692
+ type LadderNextActionKind = "run-interior-cycle" | "advance-to-gate" | "run-gate-cycle" | "accept-nonblocking-findings" | "escalate-to-triage" | "ready-for-human";
693
+ type ReviewLadderStage = "interior" | "interior-complete" | "gate";
694
+ type LadderForcedTransitionKind = "gate-cap-exhausted" | "interior-cap-reached";
695
+ interface LadderForcedTransition {
696
+ blockingFindings: string[];
697
+ cap: number;
698
+ kind: Extract<LadderForcedTransitionKind, "gate-cap-exhausted">;
699
+ }
700
+ type LadderNextAction = {
701
+ cycle: number;
702
+ kind: Extract<LadderNextActionKind, "run-gate-cycle">;
439
703
  } | {
440
- authorization?: undefined;
441
- refusals: string[];
704
+ kind: Extract<LadderNextActionKind, "accept-nonblocking-findings">;
705
+ } | {
706
+ kind: Extract<LadderNextActionKind, "escalate-to-triage">;
707
+ } | {
708
+ kind: Extract<LadderNextActionKind, "ready-for-human">;
442
709
  };
443
- /**
444
- * Operator identity, `declaredBy`-style: a named human account, recorded on
445
- * the waiver and enforced here. Session is optional audit metadata only: it is
446
- * not credential-backed, so its absence or equality never authorizes or
447
- * refuses an operator act.
448
- */
449
- declare const authorizeDemandWaiver: ({
450
- authenticatedLogin,
451
- session
452
- }: {
453
- authenticatedLogin: string | undefined;
454
- session: string | undefined;
455
- }) => AuthorizeDemandWaiverResult;
710
+ interface LadderPosition {
711
+ forcedTransition?: LadderForcedTransition;
712
+ nextAction: LadderNextAction;
713
+ stage: Extract<ReviewLadderStage, "gate">;
714
+ }
715
+ interface ReviewLadderStageEvent {
716
+ cycle: number;
717
+ cyclesToClean?: number;
718
+ engine?: string;
719
+ findingsSummary: {
720
+ blocking: number;
721
+ bySeverity: Record<ReviewFindingSeverity, number>;
722
+ flagged: number;
723
+ open: number;
724
+ staleRepeats: number;
725
+ };
726
+ forcedTransition?: LadderForcedTransition["kind"];
727
+ model?: string;
728
+ payloadVersion: 1;
729
+ session?: LadderSessionAttribution;
730
+ stage: ReviewLadderExecutedStage;
731
+ type: "review-ladder-stage";
732
+ usage?: LadderUsageReport;
733
+ }
734
+ type ReviewLadderEvaluation = LadderPosition & {
735
+ cycleCounts: {
736
+ gate: number;
737
+ interior: number;
738
+ };
739
+ event?: ReviewLadderStageEvent;
740
+ ledger: FindingLedgerEntry[];
741
+ unmatchedDispositions: LadderDispositionDeclaration[];
742
+ };
743
+ //#endregion
744
+ //#region src/pr-readiness/ladder-proof-state.d.ts
745
+ interface PrReviewLadderState {
746
+ cycles: ReviewLadderCycle[];
747
+ }
748
+ interface OpenCycleState {
749
+ autoBlockingFindings: number;
750
+ blockingEntries: ReviewFindingAttributes[];
751
+ openEntries: ReviewFindingAttributes[];
752
+ staleRepeatFindings?: number;
753
+ }
754
+ interface ReviewLadderSummaryState {
755
+ cycleCounts: {
756
+ gate: number;
757
+ interior: number;
758
+ };
759
+ forcedTransition?: LadderForcedTransitionKind;
760
+ nextAction: LadderNextActionKind;
761
+ stage: ReviewLadderStage;
762
+ }
763
+ interface ReviewLadderSnapshot {
764
+ cycleState: OpenCycleState;
765
+ evaluation: ReviewLadderEvaluation;
766
+ ledger: FindingLedgerEntry[];
767
+ policyGateCap: number;
768
+ summary: ReviewLadderSummaryState;
769
+ }
770
+ type ReviewEpochMode = {
771
+ kind: "ladder";
772
+ ladder: PrReviewLadderState;
773
+ snapshot?: ReviewLadderSnapshot;
774
+ } | {
775
+ kind: "declared-window";
776
+ };
777
+ //#endregion
778
+ //#region src/pr-readiness/review-proof-types.d.ts
779
+ type PrReviewKind = "correctness" | "security";
780
+ type PrReviewMode = PrReviewKind | "all";
781
+ type PrReviewOutcome = "passed" | "failed" | "error";
782
+ interface PrReviewStageResolution {
783
+ model: string;
784
+ sessionId: string;
785
+ }
786
+ //#endregion
787
+ //#region src/pr-readiness/review-proof-shape.d.ts
788
+ interface PrReviewFinding extends ReviewFindingAttributes {
789
+ body: string;
790
+ category?: ReviewFindingCategory;
791
+ line?: number;
792
+ protocolFinding?: true;
793
+ }
794
+ interface PrReviewResult {
795
+ kind: PrReviewKind;
796
+ startedAt: string;
797
+ endedAt: string;
798
+ durationMs: number;
799
+ model?: string;
800
+ producer?: string;
801
+ rung?: EvidenceReviewRung;
802
+ sessionId?: string;
803
+ outcome: PrReviewOutcome;
804
+ issuesFlagged: number;
805
+ summary: string;
806
+ findings: PrReviewFinding[];
807
+ typedVerdict?: boolean;
808
+ verdictSource?: "footer" | "recovered";
809
+ promptSections?: ReviewPromptSection[];
810
+ }
811
+ interface PrReviewProof {
812
+ schemaVersion: 2;
813
+ findingProvenanceVersion: 1;
814
+ base: string;
815
+ headSha: string;
816
+ patchId: string;
817
+ reviewCycle?: number;
818
+ maxReviewCycles?: number;
819
+ changedFiles: string[];
820
+ cleanedPaths: string[];
821
+ ladder?: PrReviewLadderState;
822
+ /**
823
+ * The policy identity this review run resolved its demanded kinds under
824
+ * (#922 Slice B). Optional: a run that could not reach the authority records
825
+ * the refusal instead, and `pr:ready` decides what an unresolved or
826
+ * disagreeing identity means for admission.
827
+ */
828
+ policyResolution?: PolicyResolution;
829
+ reviewRequirement?: {
830
+ reason: "no-applicable-mode" | "faithful-merge";
831
+ status: "not-required";
832
+ };
833
+ reviews: PrReviewResult[];
834
+ }
456
835
  //#endregion
457
836
  //#region src/blocked-reasons.d.ts
458
837
  declare const blockedReasonSchema: z.ZodObject<{
@@ -488,44 +867,10 @@ interface CheckoutRepository {
488
867
  owner: string;
489
868
  }
490
869
  //#endregion
491
- //#region src/follow-up.d.ts
492
- interface FactoryCliInvocation {
493
- /** Runtime arguments ending with the factory CLI entry module. */
494
- argvPrefix: string[];
495
- executable: string;
496
- }
497
- declare const FactoryCliInvocationSchema: z.ZodType<FactoryCliInvocation>;
498
- interface FollowUpAction {
499
- /**
500
- * Machine-safe argv-style array for the obvious next action, e.g.
501
- * ["gh","pr","merge","513","--squash"]. Same shape and field name that
502
- * `factory:delegate --print` emits, so an orchestrating agent can spawn the
503
- * next command without reconstructing a shell string. argv[0] is the
504
- * executable; the rest are literal, already-split arguments.
505
- */
506
- argv: string[];
507
- /**
508
- * Human-readable rendering of {@link argv} for logs and operators. Additive
509
- * to argv, never a substitute for it — argv is the source of truth.
510
- */
511
- command: string;
512
- }
513
- /**
514
- * Build a {@link FollowUpAction} from a literal argv array. The `command`
515
- * string is derived from argv so the two never drift.
516
- */
517
- declare const followUpFromArgv: (argv: string[]) => FollowUpAction;
518
- /** Canonical zod schema for the optional follow-up field on JSON outputs. */
519
- declare const FollowUpActionSchema: z.ZodType<FollowUpAction>;
520
- //#endregion
521
- //#region src/diff-classification.d.ts
522
- declare const DIFF_CLASSIFICATIONS: readonly ["docs/process-only", "trivial", "non-trivial"];
523
- type DiffClassification = (typeof DIFF_CLASSIFICATIONS)[number];
524
- //#endregion
525
870
  //#region src/profile.d.ts
526
871
  declare const DEFAULT_FACTORY_REPOSITORY = "unknown/unknown";
527
- /** The one profile shape this build accepts (ADR 0023, #318, #351). */
528
- declare const PROFILE_SCHEMA_VERSION = 5;
872
+ /** The one profile shape this build accepts (ADR 0023, #318, #351, #742). */
873
+ declare const PROFILE_SCHEMA_VERSION = 6;
529
874
  declare const factoryProjectProfileSchema: z.ZodObject<{
530
875
  $schema: z.ZodOptional<z.ZodString>;
531
876
  extensions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
@@ -534,18 +879,17 @@ declare const factoryProjectProfileSchema: z.ZodObject<{
534
879
  endpoint: z.ZodIntersection<z.ZodString, z.ZodString>;
535
880
  }, z.core.$strict>>;
536
881
  impact: z.ZodOptional<z.ZodObject<{
882
+ inert: z.ZodOptional<z.ZodArray<z.ZodString>>;
537
883
  targets: z.ZodArray<z.ZodObject<{
538
884
  importers: z.ZodArray<z.ZodString>;
539
885
  name: z.ZodString;
540
886
  paths: z.ZodOptional<z.ZodArray<z.ZodString>>;
541
887
  }, z.core.$strict>>;
542
888
  }, z.core.$strict>>;
543
- proof: z.ZodObject<{
544
- classificationPolicy: z.ZodObject<{
545
- docsOnly: z.ZodDefault<z.ZodArray<z.ZodString>>;
546
- trivial: z.ZodDefault<z.ZodArray<z.ZodString>>;
547
- }, z.core.$strict>;
548
- }, z.core.$strict>;
889
+ lifecycleContract: z.ZodOptional<z.ZodObject<{
890
+ command: z.ZodString;
891
+ jobName: z.ZodOptional<z.ZodString>;
892
+ }, z.core.$strict>>;
549
893
  repository: z.ZodObject<{
550
894
  name: z.ZodString;
551
895
  owner: z.ZodString;
@@ -554,7 +898,6 @@ declare const factoryProjectProfileSchema: z.ZodObject<{
554
898
  name: z.ZodString;
555
899
  scope: z.ZodOptional<z.ZodObject<{
556
900
  classifications: z.ZodArray<z.ZodEnum<{
557
- trivial: "trivial";
558
901
  "docs/process-only": "docs/process-only";
559
902
  "non-trivial": "non-trivial";
560
903
  }>>;
@@ -565,7 +908,7 @@ declare const factoryProjectProfileSchema: z.ZodObject<{
565
908
  paths: z.ZodArray<z.ZodString>;
566
909
  }, z.core.$strict>>;
567
910
  }, z.core.$strict>>;
568
- schemaVersion: z.ZodLiteral<5>;
911
+ schemaVersion: z.ZodLiteral<6>;
569
912
  verification: z.ZodObject<{
570
913
  commands: z.ZodArray<z.ZodObject<{
571
914
  command: z.ZodString;
@@ -593,6 +936,257 @@ interface LoadProjectProfileResult {
593
936
  }
594
937
  declare function loadProjectProfile(input?: LoadProjectProfileInput): LoadProjectProfileResult;
595
938
  //#endregion
939
+ //#region src/catch-up-recognition-record.d.ts
940
+ interface CatchUpRecognition {
941
+ /** The ref the candidate targets, as the recognizing command resolved it. */
942
+ baseRef: string;
943
+ /** The live target tip at recognition time; the head's first parent. */
944
+ baseTipSha: string;
945
+ /** The head's second parent: the admitted base-side content merged in. */
946
+ mergedParentSha: string;
947
+ /**
948
+ * The tree `git merge-tree --write-tree` produced for the two parents. It
949
+ * equals the head's own tree; that equality is the faithfulness proof.
950
+ */
951
+ mergedTreeSha: string;
952
+ /** The ref that proves the second parent is admitted content. */
953
+ upstreamRef: string;
954
+ }
955
+ //#endregion
956
+ //#region src/diff-classification.d.ts
957
+ declare const DIFF_CLASSIFICATIONS: readonly ["docs/process-only", "trivial", "non-trivial"];
958
+ type DiffClassification = (typeof DIFF_CLASSIFICATIONS)[number];
959
+ //#endregion
960
+ //#region src/impact-stamp.d.ts
961
+ /**
962
+ * The recorded stamp. `targets` satisfies the completeness invariant: every
963
+ * target the profile declares is present, each with its exact basis — never
964
+ * silently absent. `basis: "conservative"` means an unmodelled or unprovable
965
+ * input widened every target to full impact.
966
+ */
967
+ declare const impactStampSchema: z.ZodObject<{
968
+ basis: z.ZodEnum<{
969
+ "target-scoped": "target-scoped";
970
+ conservative: "conservative";
971
+ }>;
972
+ inertPaths: z.ZodDefault<z.ZodArray<z.ZodString>>;
973
+ reasons: z.ZodArray<z.ZodString>;
974
+ stampVersion: z.ZodLiteral<4>;
975
+ targets: z.ZodArray<z.ZodObject<{
976
+ basis: z.ZodString;
977
+ impact: z.ZodEnum<{
978
+ affected: "affected";
979
+ "not-affected": "not-affected";
980
+ }>;
981
+ name: z.ZodString;
982
+ subscribedPaths: z.ZodArray<z.ZodString>;
983
+ }, z.core.$strip>>;
984
+ unsubscribedPaths: z.ZodArray<z.ZodString>;
985
+ }, z.core.$strip>;
986
+ type ImpactStamp = z.infer<typeof impactStampSchema>;
987
+ /**
988
+ * The surfaces that consume the stamp. One classification, consumed
989
+ * everywhere (#430): every surface routes through
990
+ * {@link impactStampScopeDecision}, so no surface can be more trusting than
991
+ * another, and no surface re-derives path rules of its own. The value only
992
+ * selects the wording of the conservative floor a refusal falls back to.
993
+ */
994
+ declare const IMPACT_SCOPE_SURFACES: {
995
+ readonly demand: "full demand floor";
996
+ readonly "preview-lifecycle": "full preview-lifecycle floor";
997
+ readonly "verification-battery": "full verification-battery floor";
998
+ };
999
+ type ImpactScopeSurface = keyof typeof IMPACT_SCOPE_SURFACES;
1000
+ interface ImpactScopeDecision {
1001
+ reason: string;
1002
+ /** True ⇒ this target's work is provably unreachable and may be released. */
1003
+ scoped: boolean;
1004
+ }
1005
+ /**
1006
+ * Whether a trusted stamp RELEASES one target-scoped unit of work — an
1007
+ * external proof demand (#542 wave 2), a verification-battery command, or a
1008
+ * preview (Alchemy) lifecycle stack (#430 wave 3).
1009
+ *
1010
+ * The only release path is a `target-scoped` stamp of exactly this build's
1011
+ * stamp version whose target entry for exactly this name is provably
1012
+ * `not-affected`. Every other input — no trusted stamp, an unknown stamp
1013
+ * version, a conservative stamp, a name the stamp does not classify, or an
1014
+ * `affected` verdict — keeps today's full-work floor. Work only ever gets
1015
+ * released, never added or satisfied: this function can withdraw a demand, it
1016
+ * can never certify one.
1017
+ *
1018
+ * Identity binding is the CALLER's precondition: pass only a stamp computed
1019
+ * for, or read from a pr:verify proof bound to, the current candidate (see
1020
+ * `trustedImpactStamp` in `pr-readiness/verification-proof.ts`); pass
1021
+ * `undefined` otherwise.
1022
+ */
1023
+ declare const impactStampScopeDecision: ({
1024
+ stamp,
1025
+ surface,
1026
+ targetName
1027
+ }: {
1028
+ stamp: ImpactStamp | undefined;
1029
+ surface: ImpactScopeSurface;
1030
+ targetName: string;
1031
+ }) => ImpactScopeDecision;
1032
+ //#endregion
1033
+ //#region src/required-check-policy.d.ts
1034
+ declare const EVIDENCE_CHECK_TYPES: readonly ["review", "verify"];
1035
+ type EvidenceCheckType = (typeof EVIDENCE_CHECK_TYPES)[number];
1036
+ declare const requiredCheckScopeSchema: z.ZodObject<{
1037
+ classifications: z.ZodArray<z.ZodEnum<{
1038
+ "docs/process-only": "docs/process-only";
1039
+ trivial: "trivial";
1040
+ "non-trivial": "non-trivial";
1041
+ }>>;
1042
+ }, z.core.$strict>;
1043
+ type RequiredCheckScope = z.infer<typeof requiredCheckScopeSchema>;
1044
+ interface RequiredCheckScopeContext {
1045
+ catchUpRecognition?: CatchUpRecognition;
1046
+ classification: DiffClassification | undefined;
1047
+ impactStamp?: ImpactStamp;
1048
+ }
1049
+ interface ScopeDecision {
1050
+ inScope: boolean;
1051
+ reason: string;
1052
+ }
1053
+ declare const requiredCheckInScope: ({
1054
+ context,
1055
+ scope
1056
+ }: {
1057
+ context: RequiredCheckScopeContext;
1058
+ scope?: RequiredCheckScope;
1059
+ }) => ScopeDecision;
1060
+ interface RequiredCheck {
1061
+ name: string;
1062
+ checkType: EvidenceCheckType;
1063
+ scope?: RequiredCheckScope;
1064
+ }
1065
+ //#endregion
1066
+ //#region src/demand-resolution.d.ts
1067
+ /**
1068
+ * The two GitHub reads that make the base policy authoritative: the live tip of
1069
+ * a branch, and one file's content at an exact commit. Injectable so tests can
1070
+ * state what the authority says; an absent implementation is the real read, so
1071
+ * an unstated authority is a refusal rather than a silent pass.
1072
+ */
1073
+ interface BaseReviewPolicyAuthority {
1074
+ branchTipSha: (input: {
1075
+ branch: string;
1076
+ cwd: string;
1077
+ repository: CheckoutRepository;
1078
+ }) => string;
1079
+ profileContentAtRef: (input: {
1080
+ cwd: string;
1081
+ profilePath: string;
1082
+ ref: string;
1083
+ repository: CheckoutRepository;
1084
+ }) => string;
1085
+ }
1086
+ /**
1087
+ * The pull request whose base ref is the authority, as the resolving stage
1088
+ * knows it (#922 Slice B).
1089
+ *
1090
+ * `pr:ready` is handed a PR number and reads the record; `pr:verify` and
1091
+ * `pr:review` run in the authoring checkout and look the PR up from the branch,
1092
+ * which can legitimately find nothing. `isCrossRepository` stays `unknown` for
1093
+ * the reason the reader below states: an unstated fork answer is not a "no".
1094
+ */
1095
+ interface CandidatePullRequestPolicyContext {
1096
+ baseRefName: string;
1097
+ isCrossRepository: unknown;
1098
+ }
1099
+ /** What a stage found when it looked for the pull request that owns this branch. */
1100
+ type CandidatePullRequestLookup = {
1101
+ pullRequest: CandidatePullRequestPolicyContext;
1102
+ status: "found";
1103
+ } | {
1104
+ reason: string;
1105
+ status: "unavailable";
1106
+ };
1107
+ //#endregion
1108
+ //#region src/follow-up.d.ts
1109
+ interface FactoryCliInvocation {
1110
+ /** Runtime arguments ending with the factory CLI entry module. */
1111
+ argvPrefix: string[];
1112
+ executable: string;
1113
+ }
1114
+ declare const FactoryCliInvocationSchema: z.ZodType<FactoryCliInvocation>;
1115
+ interface FollowUpAction {
1116
+ /**
1117
+ * Machine-safe argv-style array for the obvious next action, e.g.
1118
+ * ["gh","pr","merge","513","--squash"]. Same shape and field name that
1119
+ * `factory:delegate --print` emits, so an orchestrating agent can spawn the
1120
+ * next command without reconstructing a shell string. argv[0] is the
1121
+ * executable; the rest are literal, already-split arguments.
1122
+ */
1123
+ argv: string[];
1124
+ /**
1125
+ * Human-readable rendering of {@link argv} for logs and operators. Additive
1126
+ * to argv, never a substitute for it — argv is the source of truth.
1127
+ */
1128
+ command: string;
1129
+ }
1130
+ /**
1131
+ * Build a {@link FollowUpAction} from a literal argv array. The `command`
1132
+ * string is derived from argv so the two never drift.
1133
+ */
1134
+ declare const followUpFromArgv: (argv: string[]) => FollowUpAction;
1135
+ /** Canonical zod schema for the optional follow-up field on JSON outputs. */
1136
+ declare const FollowUpActionSchema: z.ZodType<FollowUpAction>;
1137
+ //#endregion
1138
+ //#region src/user-config.d.ts
1139
+ declare const githubAppConfigSchema: z.ZodObject<{
1140
+ appId: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
1141
+ installationId: z.ZodOptional<z.ZodNumber>;
1142
+ privateKeyPath: z.ZodString;
1143
+ }, z.core.$strip>;
1144
+ type GithubAppConfig = z.infer<typeof githubAppConfigSchema>;
1145
+ declare const factoryUserConfigSchema: z.ZodObject<{
1146
+ githubApp: z.ZodOptional<z.ZodObject<{
1147
+ appId: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
1148
+ installationId: z.ZodOptional<z.ZodNumber>;
1149
+ privateKeyPath: z.ZodString;
1150
+ }, z.core.$strip>>;
1151
+ hqAllowedOrigins: z.ZodOptional<z.ZodArray<z.ZodString>>;
1152
+ hqIngestCredentials: z.ZodOptional<z.ZodObject<{
1153
+ clientIdRef: z.ZodString;
1154
+ clientSecretRef: z.ZodString;
1155
+ }, z.core.$strip>>;
1156
+ schemaVersion: z.ZodLiteral<2>;
1157
+ }, z.core.$strip>;
1158
+ type FactoryUserConfig = z.infer<typeof factoryUserConfigSchema>;
1159
+ interface LoadUserConfigResult {
1160
+ path: string;
1161
+ config: FactoryUserConfig;
1162
+ ignoredKeys?: string[];
1163
+ }
1164
+ //#endregion
1165
+ //#region src/github-app-access.d.ts
1166
+ interface FactoryAppAccessDependencies {
1167
+ env?: NodeJS.ProcessEnv;
1168
+ existsSync?: (path: string) => boolean;
1169
+ exchangeBroker?: (input: {
1170
+ fetch?: typeof fetch;
1171
+ oidc: string;
1172
+ owner: string;
1173
+ repo: string;
1174
+ timeoutMs?: number;
1175
+ url?: string;
1176
+ }) => Promise<string>;
1177
+ fetch?: typeof fetch;
1178
+ githubApp?: GithubAppConfig;
1179
+ mintCursorOidc?: (input: {
1180
+ audience?: string;
1181
+ socketPath?: string;
1182
+ timeoutMs?: number;
1183
+ }) => Promise<string>;
1184
+ now?: () => number;
1185
+ timeoutMs?: number;
1186
+ token?: string;
1187
+ transportAttempts?: number;
1188
+ }
1189
+ //#endregion
596
1190
  //#region src/pr-verify-mode.d.ts
597
1191
  /**
598
1192
  * The verification mode `pr:verify` resolved for a run.
@@ -629,38 +1223,9 @@ interface PostCommitStatusInput {
629
1223
  }
630
1224
  type PostCommitStatus = (input: PostCommitStatusInput) => void;
631
1225
  //#endregion
632
- //#region src/user-config.d.ts
633
- declare const githubAppConfigSchema: z.ZodObject<{
634
- appId: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
635
- installationId: z.ZodOptional<z.ZodNumber>;
636
- privateKeyPath: z.ZodString;
637
- }, z.core.$strip>;
638
- type GithubAppConfig = z.infer<typeof githubAppConfigSchema>;
639
- declare const factoryUserConfigSchema: z.ZodObject<{
640
- githubApp: z.ZodOptional<z.ZodObject<{
641
- appId: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
642
- installationId: z.ZodOptional<z.ZodNumber>;
643
- privateKeyPath: z.ZodString;
644
- }, z.core.$strip>>;
645
- hqAllowedOrigins: z.ZodOptional<z.ZodArray<z.ZodString>>;
646
- hqIngestCredentials: z.ZodOptional<z.ZodObject<{
647
- clientIdRef: z.ZodString;
648
- clientSecretRef: z.ZodString;
649
- }, z.core.$strip>>;
650
- schemaVersion: z.ZodLiteral<2>;
651
- }, z.core.$strip>;
652
- type FactoryUserConfig = z.infer<typeof factoryUserConfigSchema>;
653
- interface LoadUserConfigResult {
654
- path: string;
655
- config: FactoryUserConfig;
656
- ignoredKeys?: string[];
657
- }
658
- //#endregion
659
1226
  //#region src/github-check-runs.d.ts
660
1227
  declare const FACTORY_CHECK_NAMES: {
661
- readonly boundary: "patronage-factory/boundary";
662
1228
  readonly "pr-ready": "patronage-factory/pr-ready";
663
- readonly "pr-review": "patronage-factory/pr-review";
664
1229
  readonly "pr-verify": "patronage-factory/pr-verify";
665
1230
  };
666
1231
  type FactoryCheckGate = keyof typeof FACTORY_CHECK_NAMES;
@@ -675,12 +1240,6 @@ interface PublishFactoryCheckInput {
675
1240
  * `hqLaneRefBaseUrlFromProfile` — the same source as the HQ gate sink.
676
1241
  */
677
1242
  hqLaneBaseUrl?: string;
678
- /**
679
- * Explicit issue/PR number for the HQ lane ref, used when the check run is not
680
- * PR-scoped (e.g. an epic boundary check keyed by its epic issue). Falls back
681
- * to `pr`, then to the checkout's PR, when omitted.
682
- */
683
- laneRefNumber?: number;
684
1243
  owner: string;
685
1244
  pr?: number;
686
1245
  proof: unknown;
@@ -688,10 +1247,7 @@ interface PublishFactoryCheckInput {
688
1247
  sha: string;
689
1248
  status?: "completed" | "in_progress";
690
1249
  }
691
- interface CheckRunDependencies {
692
- fetch?: typeof fetch;
693
- githubApp?: GithubAppConfig;
694
- now?: () => number;
1250
+ interface CheckRunDependencies extends FactoryAppAccessDependencies {
695
1251
  postCommitStatus?: PostCommitStatus;
696
1252
  resolveDetailsUrl?: (input: PublishFactoryCheckInput) => Promise<string> | string;
697
1253
  /**
@@ -706,18 +1262,18 @@ interface CheckRunDependencies {
706
1262
  };
707
1263
  /** Injectable delay for the bounded retry (tests only). */
708
1264
  sleep?: (ms: number) => Promise<void>;
709
- /** Overrides GITHUB_PUBLISH_TIMEOUT_MS for the App fetch calls (tests only). */
710
- timeoutMs?: number;
711
1265
  }
712
1266
  /**
713
1267
  * Publish a factory check run and *wait* for it, so a caller that has just made
714
1268
  * the head SHA visible on GitHub (pushed the branch, created the PR) can make
715
1269
  * the proof reliably present for that SHA before it returns (#247).
716
1270
  *
717
- * Never throws and never posts a commit-status fallback: the commit status is a
718
- * human-readable mirror, not a proof surface, so a caller that needs an
719
- * App-verified check run must be told plainly whether it got one. Returns
720
- * `true` only when the App-owned check run landed.
1271
+ * Never posts a commit-status fallback: the commit status is a human-readable
1272
+ * mirror, not a proof surface, so a caller that needs an App-verified check
1273
+ * run must be told plainly whether it got one. Returns `true` only when the
1274
+ * App-owned check run landed. Throws when Factory App access is fail-closed
1275
+ * (missing mint or Cursor OIDC exchange, #949): `pr:ready` must not notice
1276
+ * that miss and exit 0. An optional-App skip still returns `false`.
721
1277
  *
722
1278
  * "Landed" means GitHub serves it, not that the POST was accepted (#520). On
723
1279
  * PR #519 the POST was accepted, `pr:ready` reported ready and armed, and the
@@ -753,8 +1309,8 @@ declare const mergeFreezeStateSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
753
1309
  generationId: z.ZodNumber;
754
1310
  headSha: z.ZodString;
755
1311
  outcome: z.ZodEnum<{
756
- active: "active";
757
1312
  stale: "stale";
1313
+ active: "active";
758
1314
  }>;
759
1315
  reason: z.ZodString;
760
1316
  recordedAt: z.ZodISODateTime;
@@ -786,30 +1342,61 @@ interface MergeFreezeStoreInput {
786
1342
  interface MergeFreezeStore {
787
1343
  read: (input: MergeFreezeStoreInput) => unknown;
788
1344
  }
1345
+ /**
1346
+ * The run identity that proves a generation is settling because it is running.
1347
+ */
1348
+ interface RunningMergeFreezeWitness {
1349
+ /** The base tip the running generation was created on. */
1350
+ headSha: string;
1351
+ /** The running `patronage-factory/merge-freeze` check-run id. */
1352
+ runId: number;
1353
+ }
1354
+ /**
1355
+ * The evidence that a generation is settling because it is still owed (#521).
1356
+ */
1357
+ interface AwaitedMergeFreezeWitness {
1358
+ /** The base tip whose generation is awaited. */
1359
+ headSha: string;
1360
+ /** The immediate parent whose settled generation proves the writer runs. */
1361
+ parentSha: string;
1362
+ /** The source-pinned hosted verify run that owes the generation. */
1363
+ verifyRunId: number;
1364
+ /** That run's status. A completed run owes nothing, so it is not settling. */
1365
+ verifyStatus: "in_progress" | "queued";
1366
+ }
1367
+ /**
1368
+ * The two settling phases, each with the witness that proves it (#890).
1369
+ *
1370
+ * `phase` replaces an optional `running` field that made one situation two:
1371
+ * the field's presence, not the situation, decided how readers behaved. Each
1372
+ * phase now carries exactly the witness its own rule needs.
1373
+ */
1374
+ type SettlingMergeFreezeGeneration = {
1375
+ kind: "settling";
1376
+ phase: "running-generation";
1377
+ reason: string;
1378
+ witness: RunningMergeFreezeWitness;
1379
+ } | {
1380
+ kind: "settling";
1381
+ phase: "awaiting-generation";
1382
+ reason: string;
1383
+ witness: AwaitedMergeFreezeWitness;
1384
+ };
789
1385
  /**
790
1386
  * The freeze generation as a readiness decision needs to see it (#477).
791
1387
  *
792
- * `read` above collapses three different situations into one refusal, because
793
- * merge time treated all of them as "do not merge". Readiness distinguishes
794
- * them: a settled generation is the writer's verdict, a **settling** one is the
795
- * window between a merge landing and its merge-target Verify completing (a
796
- * running generation, or a missing generation proven by the immediately prior
797
- * settled tip plus a current source-pinned verify run), and an **unreadable**
798
- * one is ambiguous, malformed, foreign-App, or unavailable state. Same
799
- * selection, same pinned App, same `started_at` ordering — only the reporting
800
- * is finer.
1388
+ * `read` below collapses every situation short of a verdict into one refusal,
1389
+ * because merge time treats all of them as "do not merge". Readiness
1390
+ * distinguishes them: a settled generation is the writer's verdict, a
1391
+ * **settling** one is the window between a merge landing and its merge-target
1392
+ * Verify completing, and an **unreadable** one is ambiguous, malformed,
1393
+ * foreign-App, or unavailable state. Same selection, same pinned App, same
1394
+ * `started_at` ordering — only the reporting is finer.
801
1395
  */
802
1396
  type MergeFreezeGeneration = {
803
1397
  kind: "settled";
804
1398
  state: MergeFreezeState;
805
- } | {
806
- kind: "settling";
807
- reason: string;
808
- running?: {
809
- headSha: string;
810
- id: number;
811
- };
812
- } | {
1399
+ } | SettlingMergeFreezeGeneration | {
813
1400
  kind: "unreadable";
814
1401
  reason: string;
815
1402
  };
@@ -817,6 +1404,13 @@ type MergeFreezeGeneration = {
817
1404
  interface MergeFreezeAuthority extends MergeFreezeStore {
818
1405
  readGeneration: (input: MergeFreezeStoreInput) => MergeFreezeGeneration;
819
1406
  }
1407
+ interface GitHubCheckRunMergeFreezeApi {
1408
+ list: (input: MergeFreezeStoreInput & {
1409
+ name: string;
1410
+ }) => unknown;
1411
+ parent?: (input: MergeFreezeStoreInput) => unknown;
1412
+ }
1413
+ declare function createGitHubCheckRunMergeFreezeStore(api: GitHubCheckRunMergeFreezeApi): MergeFreezeAuthority;
820
1414
  //#endregion
821
1415
  //#region src/pr-proof-io.d.ts
822
1416
  interface ProofDescriptor<T> {
@@ -826,553 +1420,929 @@ interface ProofDescriptor<T> {
826
1420
  parse: (raw: unknown) => T;
827
1421
  }
828
1422
  //#endregion
829
- //#region src/packages/review-prompt-sections/schema.d.ts
830
- declare const reviewPromptSectionSchema: z.ZodObject<{
831
- provenance: z.ZodEnum<{
832
- "prior-review-ledger": "prior-review-ledger";
833
- "issue-review-focus": "issue-review-focus";
1423
+ //#region src/pr-readiness/readiness-ledger.d.ts
1424
+ /**
1425
+ * Ledger schema version 2 (#894): `verification` is a tagged union on
1426
+ * `prVerify` and `externalChecks` no longer echoes `inScope`. Version 1
1427
+ * ledgers are not read — the pre-1.0 posture keeps one shape per contract, so
1428
+ * there is no compat reader here.
1429
+ */
1430
+ declare const SCHEMA_VERSION = 2;
1431
+ declare const READINESS_REPAIR_CODES: readonly ["undraft-pr", "await-post-undraft-checks"];
1432
+ declare const readinessRepairSchema: z.ZodObject<{
1433
+ action: z.ZodString;
1434
+ code: z.ZodEnum<{
1435
+ "undraft-pr": "undraft-pr";
1436
+ "await-post-undraft-checks": "await-post-undraft-checks";
834
1437
  }>;
835
- source: z.ZodString;
836
- text: z.ZodString;
837
- }, z.core.$strict>;
838
- type ReviewPromptSection = z.infer<typeof reviewPromptSectionSchema>;
839
- type ReviewPromptSectionProvenance = ReviewPromptSection["provenance"];
840
- declare const reviewPromptSectionsSchema: z.ZodArray<z.ZodObject<{
841
- provenance: z.ZodEnum<{
842
- "prior-review-ledger": "prior-review-ledger";
843
- "issue-review-focus": "issue-review-focus";
1438
+ command: z.ZodString;
1439
+ }, z.core.$strip>;
1440
+ declare const managedReadinessLedgerSchema: z.ZodObject<{
1441
+ baseSha: z.ZodString;
1442
+ blockingReasons: z.ZodArray<z.ZodString>;
1443
+ classification: z.ZodEnum<{
1444
+ "docs/process-only": "docs/process-only";
1445
+ trivial: "trivial";
1446
+ "non-trivial": "non-trivial";
844
1447
  }>;
845
- source: z.ZodString;
846
- text: z.ZodString;
847
- }, z.core.$strict>>;
848
- //#endregion
849
- //#region src/review-ladder-policy.d.ts
850
- type ReviewFindingSeverity = "critical" | "high" | "medium" | "low" | "unknown";
851
- type ReviewFindingCategory = "correctness" | "safety" | "coordination" | "maintainability" | "unknown";
852
- declare const REVIEW_SEVERITIES: readonly ["critical", "high", "medium", "low", "unknown"];
853
- declare const resolveReviewFindingSeverity: (priority?: string) => ReviewFindingSeverity;
854
- declare const resolveReviewFindingCategory: (category?: string) => ReviewFindingCategory;
855
- declare const FINDING_DISPOSITIONS: readonly ["open", "fixed-in-thread", "follow-up-filed", "waived", "stale-repeat", "rerun-noise"];
856
- type FindingDisposition = (typeof FINDING_DISPOSITIONS)[number];
857
- interface ReviewFindingAttributes {
858
- blockingAfterCap?: boolean;
859
- category?: string;
860
- citedSpan?: string;
861
- file?: string;
862
- prescribedAction?: string;
863
- priority?: string;
864
- supersedes?: {
865
- file?: string;
866
- title: string;
867
- };
868
- title: string;
1448
+ externalChecks: z.ZodOptional<z.ZodArray<z.ZodObject<{
1449
+ checkType: z.ZodEnum<{
1450
+ review: "review";
1451
+ verify: "verify";
1452
+ }>;
1453
+ name: z.ZodString;
1454
+ reason: z.ZodOptional<z.ZodString>;
1455
+ scope: z.ZodOptional<z.ZodObject<{
1456
+ classifications: z.ZodArray<z.ZodEnum<{
1457
+ "docs/process-only": "docs/process-only";
1458
+ trivial: "trivial";
1459
+ "non-trivial": "non-trivial";
1460
+ }>>;
1461
+ }, z.core.$strict>>;
1462
+ scopeReason: z.ZodString;
1463
+ status: z.ZodEnum<{
1464
+ satisfied: "satisfied";
1465
+ unmet: "unmet";
1466
+ "out-of-scope": "out-of-scope";
1467
+ }>;
1468
+ }, z.core.$strip>>>;
1469
+ github: z.ZodObject<{
1470
+ draft: z.ZodBoolean;
1471
+ mergeStateStatus: z.ZodString;
1472
+ mergeable: z.ZodString;
1473
+ requiredChecks: z.ZodEnum<{
1474
+ unknown: "unknown";
1475
+ pending: "pending";
1476
+ passed: "passed";
1477
+ failed: "failed";
1478
+ none: "none";
1479
+ }>;
1480
+ reviewDecision: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1481
+ unresolvedReviewThreads: z.ZodNumber;
1482
+ }, z.core.$strip>;
1483
+ headSha: z.ZodString;
1484
+ mergeBaseSha: z.ZodOptional<z.ZodString>;
1485
+ patchId: z.ZodString;
1486
+ pr: z.ZodNumber;
1487
+ repairs: z.ZodDefault<z.ZodArray<z.ZodObject<{
1488
+ action: z.ZodString;
1489
+ code: z.ZodEnum<{
1490
+ "undraft-pr": "undraft-pr";
1491
+ "await-post-undraft-checks": "await-post-undraft-checks";
1492
+ }>;
1493
+ command: z.ZodString;
1494
+ }, z.core.$strip>>>;
1495
+ reviewCycleState: z.ZodOptional<z.ZodObject<{
1496
+ autoBlockingFindings: z.ZodNumber;
1497
+ countsBySeverity: z.ZodObject<{
1498
+ critical: z.ZodNumber;
1499
+ high: z.ZodNumber;
1500
+ low: z.ZodNumber;
1501
+ medium: z.ZodNumber;
1502
+ unknown: z.ZodNumber;
1503
+ }, z.core.$strip>;
1504
+ highestBlockingSeverity: z.ZodOptional<z.ZodEnum<{
1505
+ unknown: "unknown";
1506
+ critical: "critical";
1507
+ high: "high";
1508
+ low: "low";
1509
+ medium: "medium";
1510
+ }>>;
1511
+ highestOpenSeverity: z.ZodOptional<z.ZodEnum<{
1512
+ unknown: "unknown";
1513
+ critical: "critical";
1514
+ high: "high";
1515
+ low: "low";
1516
+ medium: "medium";
1517
+ }>>;
1518
+ maxReviewCycles: z.ZodOptional<z.ZodNumber>;
1519
+ nonBlockingFindings: z.ZodNumber;
1520
+ openFindings: z.ZodNumber;
1521
+ reviewCycle: z.ZodOptional<z.ZodNumber>;
1522
+ staleRepeatFindings: z.ZodOptional<z.ZodNumber>;
1523
+ windowExhausted: z.ZodBoolean;
1524
+ }, z.core.$strip>>;
1525
+ reviewLadder: z.ZodOptional<z.ZodObject<{
1526
+ cycleCounts: z.ZodObject<{
1527
+ gate: z.ZodNumber;
1528
+ interior: z.ZodNumber;
1529
+ }, z.core.$strip>;
1530
+ forcedTransition: z.ZodOptional<z.ZodEnum<{
1531
+ "gate-cap-exhausted": "gate-cap-exhausted";
1532
+ "interior-cap-reached": "interior-cap-reached";
1533
+ }>>;
1534
+ nextAction: z.ZodEnum<{
1535
+ "run-interior-cycle": "run-interior-cycle";
1536
+ "advance-to-gate": "advance-to-gate";
1537
+ "run-gate-cycle": "run-gate-cycle";
1538
+ "accept-nonblocking-findings": "accept-nonblocking-findings";
1539
+ "escalate-to-triage": "escalate-to-triage";
1540
+ "ready-for-human": "ready-for-human";
1541
+ }>;
1542
+ stage: z.ZodEnum<{
1543
+ interior: "interior";
1544
+ gate: "gate";
1545
+ "interior-complete": "interior-complete";
1546
+ }>;
1547
+ }, z.core.$strip>>;
1548
+ reviewRuns: z.ZodOptional<z.ZodArray<z.ZodType<PrReviewResult, unknown, z.core.$ZodTypeInternals<PrReviewResult, unknown>>>>;
1549
+ reviewTerminalState: z.ZodOptional<z.ZodEnum<{
1550
+ blocked: "blocked";
1551
+ "accepted-with-findings": "accepted-with-findings";
1552
+ clean: "clean";
1553
+ }>>;
1554
+ reviews: z.ZodObject<{
1555
+ correctness: z.ZodObject<{
1556
+ required: z.ZodBoolean;
1557
+ reviewedHeadSha: z.ZodOptional<z.ZodString>;
1558
+ reviewedPatchId: z.ZodOptional<z.ZodString>;
1559
+ status: z.ZodEnum<{
1560
+ "not-required": "not-required";
1561
+ blocked: "blocked";
1562
+ current: "current";
1563
+ stale: "stale";
1564
+ missing: "missing";
1565
+ }>;
1566
+ }, z.core.$strip>;
1567
+ security: z.ZodOptional<z.ZodObject<{
1568
+ required: z.ZodBoolean;
1569
+ reviewedHeadSha: z.ZodOptional<z.ZodString>;
1570
+ reviewedPatchId: z.ZodOptional<z.ZodString>;
1571
+ status: z.ZodEnum<{
1572
+ "not-required": "not-required";
1573
+ blocked: "blocked";
1574
+ current: "current";
1575
+ stale: "stale";
1576
+ missing: "missing";
1577
+ }>;
1578
+ }, z.core.$strip>>;
1579
+ }, z.core.$strip>;
1580
+ schemaVersion: z.ZodLiteral<2>;
1581
+ verification: z.ZodDiscriminatedUnion<[z.ZodObject<{
1582
+ command: z.ZodLiteral<"patronage-factory pr:verify">;
1583
+ prVerify: z.ZodLiteral<"missing">;
1584
+ }, z.core.$strict>, z.ZodObject<{
1585
+ command: z.ZodLiteral<"patronage-factory pr:verify">;
1586
+ prVerify: z.ZodLiteral<"stale">;
1587
+ verifiedHeadSha: z.ZodString;
1588
+ }, z.core.$strict>, z.ZodObject<{
1589
+ command: z.ZodLiteral<"patronage-factory pr:verify">;
1590
+ prVerify: z.ZodLiteral<"passed-via-head">;
1591
+ verifiedHeadSha: z.ZodString;
1592
+ }, z.core.$strict>, z.ZodObject<{
1593
+ command: z.ZodLiteral<"patronage-factory pr:verify">;
1594
+ docsOnlyVerifiedHeadSha: z.ZodString;
1595
+ prVerify: z.ZodLiteral<"docs-only-delta">;
1596
+ verifiedHeadSha: z.ZodOptional<z.ZodString>;
1597
+ }, z.core.$strict>, z.ZodObject<{
1598
+ command: z.ZodLiteral<"patronage-factory pr:verify">;
1599
+ prVerify: z.ZodLiteral<"trivial-delta">;
1600
+ trivialVerifiedHeadSha: z.ZodString;
1601
+ verifiedHeadSha: z.ZodOptional<z.ZodString>;
1602
+ }, z.core.$strict>], "prVerify">;
1603
+ }, z.core.$strip>;
1604
+ type ReadinessRepair = z.infer<typeof readinessRepairSchema>;
1605
+ type ReadinessStatus = "ready" | "blocked";
1606
+ type ManagedReadinessLedger = z.infer<typeof managedReadinessLedgerSchema>;
1607
+ declare function validateManagedReadinessLedger(value: unknown): ManagedReadinessLedger;
1608
+ declare namespace status_check_rollup_d_exports {
1609
+ export { CheckState, HOSTED_VERIFY_CHECK_NAME, HOSTED_VERIFY_DRAFT_CHECK_NAME, StatusCheckRollup, hostedVerifyCheckState, isDraftHostedVerifyCheck, isExcludedFromAdmissionChecks, isFactoryReadyCheck, isHostedVerifyCheck, isSupersededHostedVerifyCheck, pendingCheckNames, statusCheckState };
869
1610
  }
870
- type BlockingResolvableFinding = Pick<ReviewFindingAttributes, "blockingAfterCap" | "category" | "priority">;
871
- declare const resolveFindingBlocking: (finding: BlockingResolvableFinding, disposition?: FindingDisposition) => boolean;
872
- interface ReviewLadderPolicy {
873
- gate: {
874
- cap: number;
875
- };
876
- interior: {
877
- cap: number;
878
- };
1611
+ type CheckState = "passed" | "failed" | "pending" | "none" | "unknown";
1612
+ interface StatusCheckRollup {
1613
+ __typename?: string;
1614
+ completedAt?: string;
1615
+ conclusion?: string;
1616
+ context?: string;
1617
+ name?: string;
1618
+ startedAt?: string;
1619
+ state?: string;
1620
+ status?: string;
1621
+ workflowName?: string;
879
1622
  }
880
- declare const resolveReviewLadderPolicy: () => ReviewLadderPolicy;
881
- //#endregion
882
- //#region src/review-rungs.d.ts
883
- declare const EVIDENCE_REVIEW_RUNGS: readonly ["independent-model", "oracle", "human"];
884
- type EvidenceReviewRung = (typeof EVIDENCE_REVIEW_RUNGS)[number];
885
- //#endregion
886
- //#region src/review-ladder-ledger.d.ts
887
- type LadderCycleStage = "interior" | "gate";
888
- interface LadderCycleRef {
889
- cycle: number;
890
- stage: LadderCycleStage;
891
- }
892
- type LadderFindingReport = ReviewFindingAttributes;
893
- type DeclarableFindingDisposition = Exclude<FindingDisposition, "open" | "stale-repeat" | "rerun-noise">;
894
- interface LadderDispositionDeclaration {
895
- disposition: DeclarableFindingDisposition;
896
- finding: {
897
- file?: string;
898
- title: string;
899
- };
900
- findingReport?: LadderFindingReport;
901
- reference?: string;
1623
+ declare const isFactoryReadyCheck: (check: StatusCheckRollup) => boolean;
1624
+ /**
1625
+ * The hosted verification gate's context name — the branch ruleset's other
1626
+ * source-pinned required check, alongside `patronage-factory/pr-ready`. One
1627
+ * name across the fleet because one generator emits the workflow that posts
1628
+ * it (ADR 0016, 2026-07-31 amendment).
1629
+ */
1630
+ declare const HOSTED_VERIFY_CHECK_NAME = "verify";
1631
+ /**
1632
+ * Is this rollup entry the hosted `verify` gate, from the producer the
1633
+ * ruleset pins it to?
1634
+ *
1635
+ * `workflowName` is the producer signal the rollup actually carries: GitHub
1636
+ * Actions check runs name their workflow, App-posted check runs come back with
1637
+ * an empty one, and a user-token commit status arrives as a `context` with no
1638
+ * `name` at all. Epic #473 wave 2 measured that a same-named check from the
1639
+ * wrong writer is as inert as no check at all, so matching the name alone
1640
+ * would accept exactly the thing the pin rejects.
1641
+ */
1642
+ declare const isHostedVerifyCheck: (check: StatusCheckRollup) => boolean;
1643
+ /**
1644
+ * The name the hosted summary job takes on a DRAFT head (#1045).
1645
+ *
1646
+ * The workflow renames that job so the pinned `verify` context does not exist
1647
+ * while the candidate is a draft. The generator that emits the workflow owns
1648
+ * the literal; this is the reader's copy of it, and
1649
+ * `software-factory-hq/alchemy/verify-workflow.test.ts` pins the two equal.
1650
+ */
1651
+ declare const HOSTED_VERIFY_DRAFT_CHECK_NAME = "verify (draft)";
1652
+ /**
1653
+ * Is this the draft-head summary run's residue?
1654
+ *
1655
+ * The draft run and the `ready_for_review` run land on the SAME head SHA, and
1656
+ * they post two different contexts — `verify (draft)` and `verify` — which
1657
+ * `effectiveChecks` keys separately and therefore never collapses. The Verify
1658
+ * workflow cancels an in-flight pull-request run when the next one starts, and
1659
+ * `ready_for_review` IS the next one, so undrafting typically cancels the
1660
+ * draft run mid-flight. That leaves a CANCELLED `verify (draft)` row sitting
1661
+ * next to a green `verify` on the admitted head.
1662
+ *
1663
+ * GitHub does not care: the branch ruleset pins `verify` alone. The factory's
1664
+ * own rollup read would: `CANCELLED` is a failed state, so the candidate's
1665
+ * `requiredChecks` would read `failed` forever and no push-free repair could
1666
+ * clear it. The draft run is a superseded generation of the summary job the
1667
+ * `verify` row already answers for, so admission does not judge it.
1668
+ */
1669
+ declare const isDraftHostedVerifyCheck: (check: StatusCheckRollup) => boolean;
1670
+ /**
1671
+ * The rollup rows an admission read must not judge: the factory's own branded
1672
+ * checks (it would be judging itself) and the draft-head summary residue
1673
+ * above.
1674
+ */
1675
+ declare const isExcludedFromAdmissionChecks: (check: StatusCheckRollup) => boolean;
1676
+ /**
1677
+ * The hosted `verify` gate's state on this head, read by presence (#477).
1678
+ *
1679
+ * This is the one rollup question the rollup can answer honestly. Wave 2
1680
+ * measured that GitHub omits an *unsatisfied pinned requirement* from
1681
+ * `statusCheckRollup` entirely — there is no "expected" or "missing" row — so
1682
+ * a green rollup is not evidence of mergeability. What the rollup does report
1683
+ * faithfully is the checks that ran. Asking whether this specific check ran,
1684
+ * and passed, on this head turns the rollup's silence from a false green into
1685
+ * a named refusal: `"none"` means the pinned requirement is unsatisfied and
1686
+ * nothing else in the rollup would have said so.
1687
+ */
1688
+ declare const hostedVerifyCheckState: (rollup: StatusCheckRollup[] | undefined) => CheckState;
1689
+ /**
1690
+ * The names of the runs `statusCheckState` would count as pending, in the
1691
+ * order the rollup reports them.
1692
+ *
1693
+ * Same reader, same collapsing of superseded generations — this only says
1694
+ * *which* runs hold the head open, so a caller that waits on them can name
1695
+ * them. A run with no context and no name is reported as `unnamed check`
1696
+ * rather than dropped: a wait must not look settled because one row was
1697
+ * unprintable.
1698
+ */
1699
+ declare const pendingCheckNames: (rollup: StatusCheckRollup[] | undefined, exclude?: (check: StatusCheckRollup) => boolean) => string[];
1700
+ declare const statusCheckState: (rollup: StatusCheckRollup[] | undefined, exclude?: (check: StatusCheckRollup) => boolean) => CheckState;
1701
+ /**
1702
+ * Is this a hosted `verify` check run that GitHub started before `cutoffIso`?
1703
+ * (#1045)
1704
+ *
1705
+ * A caller that waits for `verify` on a head it just changed the state of —
1706
+ * `pr:publish` undrafting a candidate — must not accept the run that was
1707
+ * already there. #1034's history is the shape: a draft head carried a `verify`
1708
+ * that had run nothing, the wait saw it as terminal on its first attempt, and
1709
+ * readiness read `passed` about two minutes before the `ready_for_review` run
1710
+ * created its own check runs. The same shape is reachable from any superseded
1711
+ * `verify` generation still on the head.
1712
+ *
1713
+ * Fail CLOSED on an unreadable timestamp: a `verify` row that cannot be shown
1714
+ * to be newer than the cutoff is treated as superseded. The wait is bounded,
1715
+ * so the cost of that refusal is one timeout that falls through to the
1716
+ * caller's existing behaviour; the cost of failing open is the false green
1717
+ * this exists to remove.
1718
+ */
1719
+ declare const isSupersededHostedVerifyCheck: (check: StatusCheckRollup, cutoffIso: string) => boolean;
1720
+ //#endregion
1721
+ //#region src/github-client.d.ts
1722
+ /** Read a branch tip from GitHub rather than a checkout's cached remote ref. */
1723
+ declare const fetchGitHubBranchTipSha: (repository: CheckoutRepository, branch: string, cwd: string) => string;
1724
+ //#endregion
1725
+ //#region src/github-app-client.d.ts
1726
+ interface FactoryAppRequest {
1727
+ body?: unknown;
1728
+ headers?: Readonly<Record<string, string>>;
1729
+ method: "DELETE" | "GET" | "PATCH" | "POST";
1730
+ owner: string;
1731
+ path: string;
1732
+ repo: string;
902
1733
  }
903
- interface FindingLedgerEntry extends ReviewFindingAttributes {
904
- disposition: FindingDisposition;
905
- firstFlagged: LadderCycleRef;
906
- flagCount: number;
907
- key: string;
908
- lastFlagged: LadderCycleRef;
909
- priorDisposition?: FindingDisposition;
910
- reference?: string;
911
- reopenedCount: number;
912
- staleRepeatCount: number;
1734
+ interface FactoryAppExchange<T = unknown> {
1735
+ readonly etag?: string;
1736
+ readonly json: T;
1737
+ readonly status: number;
913
1738
  }
914
- declare const findingKey: (finding: {
915
- citedSpan?: string;
916
- file?: string;
917
- prescribedAction?: string;
918
- title?: string;
919
- }) => string;
920
- declare const openLadderFindings: (ledger: FindingLedgerEntry[]) => FindingLedgerEntry[];
921
- declare const blockingLadderFindings: (ledger: FindingLedgerEntry[]) => FindingLedgerEntry[];
922
- declare const staleRepeatLadderFindings: (ledger: FindingLedgerEntry[]) => FindingLedgerEntry[];
923
- declare const inferFixedInThreadDispositions: (ledger: FindingLedgerEntry[], findings: readonly LadderFindingReport[], options?: {
924
- sameHeadAsPriorCycle?: boolean;
925
- }) => LadderDispositionDeclaration[];
926
1739
  //#endregion
927
- //#region src/review-ladder.d.ts
928
- type ReviewLadderExecutedStage = "interior" | "gate";
929
- interface LadderSessionAttribution {
930
- orchestrationMode?: "autonomous" | "manual";
931
- resumedSession?: boolean;
932
- runtime?: string;
933
- sessionId?: string;
934
- }
935
- interface LadderUsageReport {
936
- estimatedCostUsd?: number;
937
- source?: string;
938
- totalTokens?: number;
1740
+ //#region src/github-pr-status-comment.d.ts
1741
+ interface UpsertFactoryPrStatusCommentInput {
1742
+ body: string;
1743
+ /** ISO instant at which this presentation was observed. */
1744
+ observedAt?: string;
1745
+ owner: string;
1746
+ pr: number;
1747
+ repo: string;
939
1748
  }
940
- interface ReviewLadderCycle {
941
- dispositions?: LadderDispositionDeclaration[];
942
- engine?: string;
943
- findings: LadderFindingReport[];
944
- identity?: {
945
- headSha: string;
946
- patchId: string;
947
- };
948
- model?: string;
949
- correlatedRerun?: boolean;
950
- session?: LadderSessionAttribution;
951
- stage: LadderCycleStage;
952
- usage?: LadderUsageReport;
1749
+ interface UpsertFactoryPrStatusCommentDependencies {
1750
+ request?: (input: FactoryAppRequest) => Promise<FactoryAppExchange>;
1751
+ requestJson?: (input: FactoryAppRequest) => Promise<unknown>;
953
1752
  }
954
- interface LadderInteriorCapTransition {
955
- cap: number;
956
- kind: "interior-cap-reached";
1753
+ interface UpsertFactoryPrStatusCommentResult {
1754
+ action: "created" | "updated";
1755
+ commentId: number;
1756
+ url: string;
957
1757
  }
958
- interface LadderGateCapTransition {
959
- blockingFindings: string[];
960
- cap: number;
961
- kind: "gate-cap-exhausted";
1758
+ declare function upsertFactoryPrStatusComment(input: UpsertFactoryPrStatusCommentInput, dependencies?: UpsertFactoryPrStatusCommentDependencies): Promise<UpsertFactoryPrStatusCommentResult>;
1759
+ //#endregion
1760
+ //#region src/pr-verify-proof-contract.d.ts
1761
+ /**
1762
+ * The pr:verify proof versions a reader accepts: the current one only (#920
1763
+ * item 1). #917 narrowed the pr:ready reader the same way. A pr:verify proof
1764
+ * is per-candidate and short-lived — it is rewritten on every head — so no
1765
+ * stored v1–v3 proof can outlive the release that drops it. Pre-1.0 posture
1766
+ * applies: one current contract, no compat reader. A consumer on an older
1767
+ * factory must adopt this release before HQ ingests its pr:verify proofs.
1768
+ */
1769
+ declare const SUPPORTED_PR_VERIFY_SCHEMA_VERSIONS: readonly [4];
1770
+ type PrVerifySchemaVersion = (typeof SUPPORTED_PR_VERIFY_SCHEMA_VERSIONS)[number];
1771
+ interface PrVerifyCommandResult {
1772
+ command: string;
1773
+ description: string;
1774
+ /**
1775
+ * Epic #550 wave 3 (#430): the profile's declared impact target for this
1776
+ * command, recorded from v4 on. It is the proof's own command→target
1777
+ * mapping: a `notRequiredCommands` entry must name the target recorded HERE
1778
+ * for the same command, so a withholding cannot point at whichever released
1779
+ * target happens to be convenient. Absent for a command the profile does
1780
+ * not scope.
1781
+ */
1782
+ impactTarget?: string;
1783
+ name: string;
1784
+ scope: "docs-only" | "trivial" | "full";
962
1785
  }
963
- type LadderForcedTransition = LadderGateCapTransition | LadderInteriorCapTransition;
964
- interface LadderRunInteriorCycleAction {
965
- cycle: number;
966
- kind: "run-interior-cycle";
1786
+ /**
1787
+ * One failing test a verification command reported (#1035).
1788
+ *
1789
+ * The proof keeps the failing test's IDENTITY and its failure CLASS, and
1790
+ * nothing else. That is enough to decide retry-or-fix — a `timeout` under
1791
+ * machine load is a flake, an `assertion` is a real break — without rerunning
1792
+ * the aggregate to read a title off the console.
1793
+ *
1794
+ * It deliberately keeps no raw output tail and no error message body. This
1795
+ * payload is transmitted to HQ ingest, and arbitrary command output can carry
1796
+ * secrets (an echoed environment, a connection string inside a stack frame). A
1797
+ * file path, a test title, and a closed `kind` enum cannot. The cost is the
1798
+ * assertion diff and the stack frames: they help you FIX a failure, and the
1799
+ * operator still reads them from the run's own console output.
1800
+ */
1801
+ interface PrVerifyTestFailure {
1802
+ /** The test file the reporter named, as the reporter wrote it. */
1803
+ file: string;
1804
+ /**
1805
+ * The failure class. `timeout` is the test-timeout error vitest raises at
1806
+ * its own ceiling; `assertion` is a failed expectation; `error` is every
1807
+ * other thrown failure.
1808
+ */
1809
+ kind: "assertion" | "error" | "timeout";
1810
+ /** The full test title, suite names included, as the reporter wrote it. */
1811
+ title: string;
967
1812
  }
968
- type LadderGateNextAction = {
969
- cycle: number;
970
- kind: "run-gate-cycle";
971
- } | {
972
- kind: "accept-nonblocking-findings";
973
- } | {
974
- kind: "escalate-to-triage";
975
- } | {
976
- kind: "ready-for-human";
977
- };
978
- type LadderPosition = {
979
- forcedTransition?: LadderGateCapTransition;
980
- nextAction: LadderGateNextAction;
981
- stage: "gate";
982
- } | {
983
- forcedTransition?: LadderInteriorCapTransition;
984
- nextAction: {
985
- kind: "advance-to-gate";
986
- };
987
- stage: "interior-complete";
988
- } | {
989
- forcedTransition?: never;
990
- nextAction: LadderRunInteriorCycleAction;
991
- stage: "interior";
992
- };
993
- type LadderNextAction = LadderPosition["nextAction"];
994
- type ReviewLadderStage = LadderPosition["stage"];
995
- interface ReviewLadderStageEvent {
996
- cycle: number;
997
- cyclesToClean?: number;
998
- engine?: string;
999
- findingsSummary: {
1000
- blocking: number;
1001
- bySeverity: Record<ReviewFindingSeverity, number>;
1002
- flagged: number;
1003
- open: number;
1004
- staleRepeats: number;
1813
+ interface PrVerifyExecutedCommand {
1814
+ command: string;
1815
+ counts?: {
1816
+ testFiles?: number;
1817
+ tests?: number;
1005
1818
  };
1006
- forcedTransition?: LadderForcedTransition["kind"];
1007
- model?: string;
1008
- payloadVersion: 1;
1009
- session?: LadderSessionAttribution;
1010
- stage: ReviewLadderExecutedStage;
1011
- type: "review-ladder-stage";
1012
- usage?: LadderUsageReport;
1819
+ durationMs: number;
1820
+ exitCode: number;
1821
+ /**
1822
+ * The failing tests this command reported (#1035). Present only when the
1823
+ * command produced parseable failures, so a passing command's record is
1824
+ * byte-identical to the one it wrote before this field existed.
1825
+ */
1826
+ failures?: PrVerifyTestFailure[];
1827
+ name: string;
1828
+ scope: "docs-only" | "trivial" | "full";
1013
1829
  }
1014
- interface LadderDiagnostic {
1015
- code: "interior-cycles-unrecorded";
1016
- message: string;
1830
+ /**
1831
+ * Epic #550 wave 3 (#430): a verification command the impact stamp proved this
1832
+ * candidate cannot reach, so the battery did not run it.
1833
+ *
1834
+ * The completeness invariant lives in the pairing: `verificationCommands`
1835
+ * records every command the resolved mode selected, `executedCommands` records
1836
+ * what ran, and this list records the rest WITH the stamp's own basis. A
1837
+ * withheld stack is therefore never silently absent from the proof — it is
1838
+ * present, named, and explained.
1839
+ */
1840
+ interface PrVerifyNotRequiredCommand {
1841
+ basis: string;
1842
+ impactTarget: string;
1843
+ name: string;
1017
1844
  }
1018
- type ReviewLadderEvaluation = LadderPosition & {
1019
- cycleCounts: {
1020
- gate: number;
1021
- interior: number;
1022
- };
1023
- diagnostics: LadderDiagnostic[];
1024
- event?: ReviewLadderStageEvent;
1025
- ledger: FindingLedgerEntry[];
1026
- unmatchedDispositions: LadderDispositionDeclaration[];
1027
- };
1028
- interface EvaluateReviewLadderInput {
1029
- cycles: ReviewLadderCycle[];
1030
- policy: ReviewLadderPolicy;
1845
+ /**
1846
+ * Epic #758 (#762): a consumer package a stamp-scoped selection skipped, and
1847
+ * why. Bound to the proof's stamp identity — refused when the proof records no
1848
+ * stamp. The factory does not write this list; consumers do.
1849
+ */
1850
+ interface PrVerifyNotDemandedRecord {
1851
+ basis: string;
1852
+ name: string;
1031
1853
  }
1032
- declare const evaluateReviewLadder: ({
1033
- cycles,
1034
- policy
1035
- }: EvaluateReviewLadderInput) => ReviewLadderEvaluation;
1036
- //#endregion
1037
- //#region src/pr-readiness/ladder-proof-state.d.ts
1038
- interface PrReviewLadderState {
1039
- cycles: ReviewLadderCycle[];
1854
+ interface PrVerifyProof {
1855
+ schemaVersion: PrVerifySchemaVersion;
1856
+ authoringSession: string;
1857
+ base: string;
1858
+ baselineFullProofs?: {
1859
+ base: string;
1860
+ changedFiles: string[];
1861
+ headSha: string;
1862
+ profilePath: string;
1863
+ projectKey: string;
1864
+ repository: string;
1865
+ }[];
1866
+ catchUpRecognition?: CatchUpRecognition;
1867
+ changedFiles: string[];
1868
+ classification: DiffClassification;
1869
+ classificationReasons: string[];
1870
+ command: "patronage-factory pr:verify";
1871
+ durationMs: number;
1872
+ endedAt: string;
1873
+ executedCommands?: PrVerifyExecutedCommand[];
1874
+ headSha: string;
1875
+ impactStamp?: ImpactStamp;
1876
+ mode: ResolvedPrVerifyMode;
1877
+ mergeBaseSha?: string;
1878
+ notDemandedRecords?: PrVerifyNotDemandedRecord[];
1879
+ notRequiredCommands?: PrVerifyNotRequiredCommand[];
1880
+ outcome?: "aborted" | "passed";
1881
+ patchId?: string;
1882
+ /**
1883
+ * The review policy identity this verification run resolved (#922 Slice B).
1884
+ *
1885
+ * Verification demands no review mode of its own. It records the identity so
1886
+ * `pr:ready` can see whether the stage that produced this proof judged the
1887
+ * candidate under the same policy readiness resolves. Optional, and normally
1888
+ * `unresolved` on the first run of a branch: a candidate is verified before
1889
+ * it has a pull request, and there is no authority to read without one.
1890
+ */
1891
+ policyResolution?: PolicyResolution;
1892
+ profilePath: string;
1893
+ projectKey: string;
1894
+ repository: string;
1895
+ startedAt: string;
1896
+ verificationCommands: PrVerifyCommandResult[];
1040
1897
  }
1041
- interface OpenCycleState {
1042
- autoBlockingFindings: number;
1043
- blockingEntries: ReviewFindingAttributes[];
1044
- openEntries: ReviewFindingAttributes[];
1045
- staleRepeatFindings?: number;
1898
+ type PrVerifyBaselineFullProof = NonNullable<PrVerifyProof["baselineFullProofs"]>[number];
1899
+ declare function validatePrVerifyProof(value: unknown): PrVerifyProof;
1900
+ declare namespace verification_proof_d_exports {
1901
+ export { PrVerifyBaselineFullProof, PrVerifyCommandResult, PrVerifyExecutedCommand, PrVerifyNotDemandedRecord, PrVerifyNotRequiredCommand, PrVerifyProof, PrVerifySchemaVersion, PrVerifyTestFailure, ResolvedPrVerifyMode, SUPPORTED_PR_VERIFY_SCHEMA_VERSIONS, VerificationHeadShas, VerificationProofState, VerifiedHeadShas, prVerifyFullHeadShasForDiff, prVerifyProofHeadShas, readPrVerifyProof, resolveVerifyProofApplicability, trustedCatchUpRecognition, trustedImpactStamp, validatePrVerifyProof, verificationProofApplicabilityFor, verificationProofBlockingReason, verificationProofForReadiness, verificationProofStateFor, verifyProofIdentityMatches, verifyProofPassed };
1046
1902
  }
1047
- interface ReviewLadderSummaryState {
1048
- cycleCounts: {
1049
- gate: number;
1050
- interior: number;
1051
- };
1052
- forcedTransition?: LadderForcedTransition["kind"];
1053
- nextAction: LadderNextAction["kind"];
1054
- stage: ReviewLadderStage;
1055
- }
1056
- interface ReviewLadderSnapshot {
1057
- cycleState: OpenCycleState;
1058
- evaluation: ReviewLadderEvaluation;
1059
- ledger: FindingLedgerEntry[];
1060
- policyGateCap: number;
1061
- summary: ReviewLadderSummaryState;
1903
+ interface VerifiedHeadShas {
1904
+ docsOnlyVerifiedHeadShas: string[];
1905
+ trivialVerifiedHeadShas: string[];
1906
+ verifiedHeadShas: string[];
1062
1907
  }
1063
- type ReviewEpochMode = {
1064
- kind: "ladder";
1065
- ladder: PrReviewLadderState;
1066
- snapshot?: ReviewLadderSnapshot;
1908
+ type VerificationHeadShas = {
1909
+ explicitFailure: true;
1910
+ } | VerifiedHeadShas;
1911
+ declare function readPrVerifyProof(filePath: string): PrVerifyProof;
1912
+ declare const verifyProofPassed: (proof: PrVerifyProof) => boolean;
1913
+ declare const prVerifyProofHeadShas: (proof: PrVerifyProof | undefined, creditedHeadSha?: string) => VerifiedHeadShas;
1914
+ declare const verifyProofIdentityMatches: ({
1915
+ currentIdentity,
1916
+ proof
1917
+ }: {
1918
+ currentIdentity?: {
1919
+ patchId: string;
1920
+ mergeBaseSha?: string;
1921
+ };
1922
+ proof?: PrVerifyProof;
1923
+ }) => boolean;
1924
+ /**
1925
+ * Wave-2 consumption (#542): the recorded impact stamp, released for demand
1926
+ * resolution ONLY when it is identity-bound to the current candidate — the
1927
+ * proof passed, and its recorded headSha AND patchId both name exactly this
1928
+ * candidate (the same identities the proof already binds). Everything else —
1929
+ * no proof, an aborted run, a stale head, a moved patch id, a pre-stamp proof
1930
+ * — returns `undefined`, and the consumer keeps today's full-demand floor.
1931
+ *
1932
+ * Deliberately stricter than verify-once applicability (which tolerates a
1933
+ * head-only or patch-id-only match): a stamp narrows external demands, so it
1934
+ * is trusted only on an exact double binding, fail closed.
1935
+ */
1936
+ declare const trustedImpactStamp: ({
1937
+ candidate,
1938
+ proof
1939
+ }: {
1940
+ candidate: {
1941
+ headSha: string;
1942
+ patchId: string;
1943
+ };
1944
+ proof: PrVerifyProof | undefined;
1945
+ }) => ImpactStamp | undefined;
1946
+ /**
1947
+ * #833: the recorded catch-up recognition, consumed ONLY when it is
1948
+ * identity-bound to the current candidate under exactly the rules
1949
+ * `trustedImpactStamp` applies — the proof passed, and its recorded
1950
+ * headSha AND patchId both name this candidate. The recognition withdraws
1951
+ * review and preview demands, so it earns the same strict double binding and
1952
+ * the same fail-closed answer (`undefined`) on every other state.
1953
+ */
1954
+ declare const trustedCatchUpRecognition: ({
1955
+ candidate,
1956
+ proof
1957
+ }: {
1958
+ candidate: {
1959
+ headSha: string;
1960
+ patchId: string;
1961
+ };
1962
+ proof: PrVerifyProof | undefined;
1963
+ }) => CatchUpRecognition | undefined;
1964
+ declare const prVerifyFullHeadShasForDiff: ({
1965
+ docsOnlyDeltaAcceptedSince,
1966
+ files,
1967
+ proof
1968
+ }: {
1969
+ docsOnlyDeltaAcceptedSince?: (baselineHeadSha: string) => boolean;
1970
+ files: string[];
1971
+ proof: PrVerifyProof;
1972
+ }) => string[];
1973
+ type VerificationProofState = {
1974
+ kind: "typed-aborted";
1975
+ proof: PrVerifyProof;
1067
1976
  } | {
1068
- kind: "declared-window";
1977
+ kind: "typed-missing";
1978
+ path: string;
1979
+ reason: "enoent" | "invalid";
1980
+ message?: string;
1981
+ } | {
1982
+ kind: "typed";
1983
+ headShas: VerifiedHeadShas;
1984
+ proof: PrVerifyProof;
1985
+ } | {
1986
+ kind: "typed-diff-mismatch";
1987
+ mode: ResolvedPrVerifyMode;
1069
1988
  };
1989
+ declare const verificationProofStateFor: ({
1990
+ proof,
1991
+ proofMatchesCurrentDiff,
1992
+ proofPath
1993
+ }: {
1994
+ proof?: PrVerifyProof;
1995
+ proofMatchesCurrentDiff?: boolean;
1996
+ proofPath?: string;
1997
+ }) => VerificationProofState;
1998
+ declare const verificationProofApplicabilityFor: ({
1999
+ docsOnlyDeltaAcceptedSince,
2000
+ explicitProof,
2001
+ files,
2002
+ headSha,
2003
+ currentIdentity,
2004
+ proof,
2005
+ proofPath,
2006
+ proofReadError
2007
+ }: {
2008
+ docsOnlyDeltaAcceptedSince?: (baselineHeadSha: string) => boolean;
2009
+ explicitProof: boolean;
2010
+ files: string[];
2011
+ headSha: string;
2012
+ currentIdentity?: {
2013
+ patchId: string;
2014
+ mergeBaseSha?: string;
2015
+ };
2016
+ proof?: PrVerifyProof;
2017
+ proofPath?: string;
2018
+ proofReadError?: unknown;
2019
+ }) => {
2020
+ fullVerifiedHeadShas: never[];
2021
+ verificationProof: VerificationProofState;
2022
+ } | {
2023
+ fullVerifiedHeadShas: string[];
2024
+ verificationProof: {
2025
+ headShas: VerifiedHeadShas;
2026
+ kind: "typed";
2027
+ proof: PrVerifyProof;
2028
+ };
2029
+ };
2030
+ declare const resolveVerifyProofApplicability: ({
2031
+ proofPath,
2032
+ explicitProof,
2033
+ docsOnlyDeltaAcceptedSince,
2034
+ files,
2035
+ headSha,
2036
+ currentVerifyIdentityForBase,
2037
+ preread
2038
+ }: {
2039
+ proofPath: string;
2040
+ explicitProof: boolean;
2041
+ docsOnlyDeltaAcceptedSince?: (baselineHeadSha: string) => boolean;
2042
+ files: string[];
2043
+ headSha: string;
2044
+ currentVerifyIdentityForBase?: (base: string) => {
2045
+ patchId: string;
2046
+ mergeBaseSha?: string;
2047
+ };
2048
+ preread?: {
2049
+ proof?: PrVerifyProof;
2050
+ error?: unknown;
2051
+ };
2052
+ }) => {
2053
+ fullVerifiedHeadShas: never[];
2054
+ verificationProof: VerificationProofState;
2055
+ } | {
2056
+ fullVerifiedHeadShas: string[];
2057
+ verificationProof: {
2058
+ headShas: VerifiedHeadShas;
2059
+ kind: "typed";
2060
+ proof: PrVerifyProof;
2061
+ };
2062
+ };
2063
+ declare const verificationProofForReadiness: (state: VerificationProofState) => VerificationHeadShas;
2064
+ declare const verificationProofBlockingReason: (state: VerificationProofState) => string | undefined;
1070
2065
  //#endregion
1071
- //#region src/pr-readiness/review-proof-types.d.ts
1072
- type PrReviewKind = "correctness" | "security";
1073
- type PrReviewMode = PrReviewKind | "all";
1074
- type PrReviewOutcome = "passed" | "failed" | "error";
1075
- interface PrReviewStageResolution {
1076
- model: string;
1077
- sessionId: string;
1078
- }
1079
- //#endregion
1080
- //#region src/pr-readiness/review-proof-shape.d.ts
1081
- interface PrReviewFinding extends ReviewFindingAttributes {
1082
- body: string;
1083
- category?: ReviewFindingCategory;
1084
- line?: number;
1085
- protocolFinding?: true;
2066
+ //#region src/preview-lifecycle.d.ts
2067
+ type PreviewDisposition = "deploy" | "not-required";
2068
+ interface PreviewTargetPlan {
2069
+ basis: string;
2070
+ disposition: PreviewDisposition;
2071
+ name: string;
1086
2072
  }
1087
- interface PrReviewResult {
1088
- kind: PrReviewKind;
1089
- startedAt: string;
1090
- endedAt: string;
1091
- durationMs: number;
1092
- model?: string;
1093
- producer?: string;
1094
- rung?: EvidenceReviewRung;
1095
- sessionId?: string;
1096
- outcome: PrReviewOutcome;
1097
- issuesFlagged: number;
1098
- summary: string;
1099
- findings: PrReviewFinding[];
1100
- typedVerdict?: boolean;
1101
- verdictSource?: "footer" | "recovered";
1102
- promptSections?: ReviewPromptSection[];
2073
+ interface PreviewLifecyclePlan {
2074
+ /** The declared preview stacks to deploy, in declaration order. */
2075
+ deploy: string[];
2076
+ /** The withheld stacks, in declaration order. */
2077
+ notRequired: PreviewTargetPlan[];
2078
+ /** Whether a trusted, identity-bound stamp was available at all. */
2079
+ stampTrusted: boolean;
2080
+ /** Every declared preview target with its disposition, in declaration order. */
2081
+ targets: PreviewTargetPlan[];
1103
2082
  }
1104
- interface PrReviewProof {
1105
- schemaVersion: 2;
1106
- findingProvenanceVersion: 1;
1107
- base: string;
1108
- headSha: string;
1109
- patchId: string;
1110
- reviewCycle?: number;
1111
- maxReviewCycles?: number;
1112
- changedFiles: string[];
1113
- cleanedPaths: string[];
1114
- ladder?: PrReviewLadderState;
1115
- reviewRequirement?: {
1116
- reason: "no-applicable-mode";
1117
- status: "not-required";
2083
+ /** Validate a serialized plan without deriving or changing its dispositions. */
2084
+ declare const validatePreviewLifecyclePlan: (value: unknown) => PreviewLifecyclePlan;
2085
+ /**
2086
+ * Structural subset of the profile: the impact declarations plus the external
2087
+ * demand list. Structural rather than a `Pick` so this module does not import
2088
+ * `profile.ts`.
2089
+ */
2090
+ interface PreviewLifecycleProfile {
2091
+ impact?: {
2092
+ targets: {
2093
+ name: string;
2094
+ }[];
1118
2095
  };
1119
- reviews: PrReviewResult[];
2096
+ requiredChecks?: {
2097
+ name: string;
2098
+ }[];
1120
2099
  }
1121
- //#endregion
1122
- //#region src/pr-readiness/readiness-ledger.d.ts
1123
- declare const SCHEMA_VERSION = 1;
1124
- declare const READINESS_REPAIR_CODES: readonly ["undraft-pr", "await-post-undraft-checks"];
1125
- declare const readinessRepairSchema: z.ZodObject<{
1126
- action: z.ZodString;
1127
- code: z.ZodEnum<{
1128
- "undraft-pr": "undraft-pr";
1129
- "await-post-undraft-checks": "await-post-undraft-checks";
1130
- }>;
1131
- command: z.ZodString;
1132
- }, z.core.$strip>;
1133
- declare const managedReadinessLedgerSchema: z.ZodObject<{
1134
- baseSha: z.ZodString;
1135
- blockingReasons: z.ZodArray<z.ZodString>;
1136
- classification: z.ZodEnum<{
1137
- trivial: "trivial";
1138
- "docs/process-only": "docs/process-only";
1139
- "non-trivial": "non-trivial";
1140
- }>;
1141
- externalChecks: z.ZodOptional<z.ZodArray<z.ZodObject<{
1142
- checkType: z.ZodEnum<{
1143
- review: "review";
1144
- verify: "verify";
1145
- }>;
1146
- inScope: z.ZodBoolean;
1147
- name: z.ZodString;
1148
- reason: z.ZodOptional<z.ZodString>;
1149
- scope: z.ZodOptional<z.ZodObject<{
1150
- classifications: z.ZodArray<z.ZodEnum<{
1151
- trivial: "trivial";
1152
- "docs/process-only": "docs/process-only";
1153
- "non-trivial": "non-trivial";
1154
- }>>;
1155
- }, z.core.$strict>>;
1156
- scopeReason: z.ZodString;
1157
- status: z.ZodEnum<{
1158
- satisfied: "satisfied";
1159
- unmet: "unmet";
1160
- "out-of-scope": "out-of-scope";
1161
- }>;
1162
- }, z.core.$strip>>>;
1163
- github: z.ZodObject<{
1164
- draft: z.ZodBoolean;
1165
- mergeStateStatus: z.ZodString;
1166
- mergeable: z.ZodString;
1167
- requiredChecks: z.ZodEnum<{
1168
- unknown: "unknown";
1169
- pending: "pending";
1170
- passed: "passed";
1171
- failed: "failed";
1172
- none: "none";
1173
- }>;
1174
- reviewDecision: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1175
- unresolvedReviewThreads: z.ZodNumber;
1176
- }, z.core.$strip>;
1177
- headSha: z.ZodString;
1178
- mergeBaseSha: z.ZodOptional<z.ZodString>;
1179
- patchId: z.ZodString;
1180
- pr: z.ZodNumber;
1181
- repairs: z.ZodDefault<z.ZodArray<z.ZodObject<{
1182
- action: z.ZodString;
1183
- code: z.ZodEnum<{
1184
- "undraft-pr": "undraft-pr";
1185
- "await-post-undraft-checks": "await-post-undraft-checks";
1186
- }>;
1187
- command: z.ZodString;
1188
- }, z.core.$strip>>>;
1189
- reviewCycleState: z.ZodOptional<z.ZodObject<{
1190
- autoBlockingFindings: z.ZodNumber;
1191
- countsBySeverity: z.ZodObject<{
1192
- critical: z.ZodNumber;
1193
- high: z.ZodNumber;
1194
- low: z.ZodNumber;
1195
- medium: z.ZodNumber;
1196
- unknown: z.ZodNumber;
1197
- }, z.core.$strip>;
1198
- highestBlockingSeverity: z.ZodOptional<z.ZodEnum<{
1199
- unknown: "unknown";
1200
- critical: "critical";
1201
- high: "high";
1202
- low: "low";
1203
- medium: "medium";
1204
- }>>;
1205
- highestOpenSeverity: z.ZodOptional<z.ZodEnum<{
1206
- unknown: "unknown";
1207
- critical: "critical";
1208
- high: "high";
1209
- low: "low";
1210
- medium: "medium";
1211
- }>>;
1212
- maxReviewCycles: z.ZodOptional<z.ZodNumber>;
1213
- nonBlockingFindings: z.ZodNumber;
1214
- openFindings: z.ZodNumber;
1215
- reviewCycle: z.ZodOptional<z.ZodNumber>;
1216
- staleRepeatFindings: z.ZodOptional<z.ZodNumber>;
1217
- windowExhausted: z.ZodBoolean;
1218
- }, z.core.$strip>>;
1219
- reviewLadder: z.ZodOptional<z.ZodObject<{
1220
- cycleCounts: z.ZodObject<{
1221
- gate: z.ZodNumber;
1222
- interior: z.ZodNumber;
1223
- }, z.core.$strip>;
1224
- forcedTransition: z.ZodOptional<z.ZodEnum<{
1225
- "gate-cap-exhausted": "gate-cap-exhausted";
1226
- "interior-cap-reached": "interior-cap-reached";
1227
- }>>;
1228
- nextAction: z.ZodEnum<{
1229
- "run-gate-cycle": "run-gate-cycle";
1230
- "accept-nonblocking-findings": "accept-nonblocking-findings";
1231
- "escalate-to-triage": "escalate-to-triage";
1232
- "ready-for-human": "ready-for-human";
1233
- "advance-to-gate": "advance-to-gate";
1234
- "run-interior-cycle": "run-interior-cycle";
1235
- }>;
1236
- stage: z.ZodEnum<{
1237
- gate: "gate";
1238
- interior: "interior";
1239
- "interior-complete": "interior-complete";
1240
- }>;
1241
- }, z.core.$strip>>;
1242
- reviewRuns: z.ZodOptional<z.ZodArray<z.ZodType<PrReviewResult, unknown, z.core.$ZodTypeInternals<PrReviewResult, unknown>>>>;
1243
- reviewTerminalState: z.ZodOptional<z.ZodEnum<{
1244
- blocked: "blocked";
1245
- "accepted-with-findings": "accepted-with-findings";
1246
- clean: "clean";
1247
- }>>;
1248
- reviews: z.ZodObject<{
1249
- correctness: z.ZodObject<{
1250
- required: z.ZodBoolean;
1251
- reviewedHeadSha: z.ZodOptional<z.ZodString>;
1252
- reviewedPatchId: z.ZodOptional<z.ZodString>;
1253
- status: z.ZodEnum<{
1254
- blocked: "blocked";
1255
- stale: "stale";
1256
- "not-required": "not-required";
1257
- current: "current";
1258
- missing: "missing";
1259
- }>;
1260
- }, z.core.$strip>;
1261
- security: z.ZodOptional<z.ZodObject<{
1262
- required: z.ZodBoolean;
1263
- reviewedHeadSha: z.ZodOptional<z.ZodString>;
1264
- reviewedPatchId: z.ZodOptional<z.ZodString>;
1265
- status: z.ZodEnum<{
1266
- blocked: "blocked";
1267
- stale: "stale";
1268
- "not-required": "not-required";
1269
- current: "current";
1270
- missing: "missing";
1271
- }>;
1272
- }, z.core.$strip>>;
1273
- }, z.core.$strip>;
1274
- schemaVersion: z.ZodLiteral<1>;
1275
- verification: z.ZodObject<{
1276
- command: z.ZodLiteral<"patronage-factory pr:verify">;
1277
- docsOnlyDeltaAccepted: z.ZodOptional<z.ZodBoolean>;
1278
- docsOnlyVerifiedHeadSha: z.ZodOptional<z.ZodString>;
1279
- prVerify: z.ZodEnum<{
1280
- stale: "stale";
1281
- passed: "passed";
1282
- missing: "missing";
1283
- }>;
1284
- trivialDeltaAccepted: z.ZodOptional<z.ZodBoolean>;
1285
- trivialVerifiedHeadSha: z.ZodOptional<z.ZodString>;
1286
- verifiedHeadSha: z.ZodOptional<z.ZodString>;
1287
- }, z.core.$strip>;
1288
- }, z.core.$strip>;
1289
- type ReadinessRepair = z.infer<typeof readinessRepairSchema>;
1290
- type ReadinessStatus = "ready" | "blocked";
1291
- type ManagedReadinessLedger = z.infer<typeof managedReadinessLedgerSchema>;
1292
- declare function validateManagedReadinessLedger(value: unknown): ManagedReadinessLedger;
1293
- declare namespace status_check_rollup_d_exports {
1294
- export { CheckState, HOSTED_VERIFY_CHECK_NAME, StatusCheckRollup, hostedVerifyCheckState, isFactoryReadyCheck, isHostedVerifyCheck, statusCheckState };
1295
- }
1296
- type CheckState = "passed" | "failed" | "pending" | "none" | "unknown";
1297
- interface StatusCheckRollup {
1298
- __typename?: string;
1299
- completedAt?: string;
1300
- conclusion?: string;
1301
- context?: string;
1302
- name?: string;
1303
- startedAt?: string;
1304
- state?: string;
1305
- status?: string;
1306
- workflowName?: string;
1307
- }
1308
- declare const isFactoryReadyCheck: (check: StatusCheckRollup) => boolean;
1309
- /**
1310
- * The hosted verification gate's context name — the branch ruleset's other
1311
- * source-pinned required check, alongside `patronage-factory/pr-ready`. One
1312
- * name across the fleet because one generator emits the workflow that posts
1313
- * it (ADR 0016, 2026-07-31 amendment).
1314
- */
1315
- declare const HOSTED_VERIFY_CHECK_NAME = "verify";
1316
2100
  /**
1317
- * Is this rollup entry the hosted `verify` gate, from the producer the
1318
- * ruleset pins it to?
2101
+ * The declared preview stacks: impact targets that are ALSO declared required
2102
+ * checks — i.e. targets whose proof is produced externally, which is exactly
2103
+ * what a preview producer is.
1319
2104
  *
1320
- * `workflowName` is the producer signal the rollup actually carries: GitHub
1321
- * Actions check runs name their workflow, App-posted check runs come back with
1322
- * an empty one, and a user-token commit status arrives as a `context` with no
1323
- * `name` at all. Epic #473 wave 2 measured that a same-named check from the
1324
- * wrong writer is as inert as no check at all, so matching the name alone
1325
- * would accept exactly the thing the pin rejects.
2105
+ * Deriving the list from the two existing declarations rather than adding a
2106
+ * third is what makes lifecycle and demand unable to disagree: the stacks this
2107
+ * plan can withhold are precisely the demands wave 2 can release, so a stack
2108
+ * can never be skipped while its proof stays demanded.
1326
2109
  */
1327
- declare const isHostedVerifyCheck: (check: StatusCheckRollup) => boolean;
2110
+ declare const previewLifecycleTargets: (profile: PreviewLifecycleProfile) => string[];
1328
2111
  /**
1329
- * The hosted `verify` gate's state on this head, read by presence (#477).
2112
+ * Plan the preview lifecycle for one candidate.
1330
2113
  *
1331
- * This is the one rollup question the rollup can answer honestly. Wave 2
1332
- * measured that GitHub omits an *unsatisfied pinned requirement* from
1333
- * `statusCheckRollup` entirely — there is no "expected" or "missing" row — so
1334
- * a green rollup is not evidence of mergeability. What the rollup does report
1335
- * faithfully is the checks that ran. Asking whether this specific check ran,
1336
- * and passed, on this head turns the rollup's silence from a false green into
1337
- * a named refusal: `"none"` means the pinned requirement is unsatisfied and
1338
- * nothing else in the rollup would have said so.
2114
+ * Trust is resolved here through the SAME identity gate demand release uses
2115
+ * (`trustedImpactStamp`): the proof must have passed and must bind both the
2116
+ * candidate's headSha and its patchId. A stale, aborted, absent, or
2117
+ * differently-bound proof yields no stamp, and every declared stack is planned
2118
+ * for deploy. Total over its INPUTS — no proof, stamp, or profile can make it
2119
+ * throw. A malformed CALL is the deliberate exception: omitting
2120
+ * `vetoedTargets` is API misuse, not data doubt, and throws.
1339
2121
  */
1340
- declare const hostedVerifyCheckState: (rollup: StatusCheckRollup[] | undefined) => CheckState;
1341
- declare const statusCheckState: (rollup: StatusCheckRollup[] | undefined, exclude?: (check: StatusCheckRollup) => boolean) => CheckState;
1342
- //#endregion
1343
- //#region src/pr-ready.d.ts
1344
- interface PrReadyArgs extends LoadProjectProfileInput {
1345
- authoringSessionIds?: string[];
1346
- base: string;
1347
- epic?: number;
1348
- json?: boolean;
1349
- output?: string;
1350
- report?: boolean;
1351
- pr: number;
1352
- reviewProof?: string;
1353
- throwWhenBlocked?: boolean;
1354
- verifyProof?: string;
1355
- }
1356
- interface GitHubPullRequest {
2122
+ declare const planPreviewLifecycle: ({
2123
+ candidate,
2124
+ profile,
2125
+ proof,
2126
+ vetoedTargets
2127
+ }: {
2128
+ candidate: {
2129
+ headSha: string;
2130
+ patchId: string;
2131
+ };
2132
+ profile: PreviewLifecycleProfile;
2133
+ proof: PrVerifyProof | undefined;
1357
2134
  /**
1358
- * GitHub's live auto-merge enablement, or `null` when nothing is scheduled.
2135
+ * Stack names with a current, candidate-bound FAILING envelope. Scoping is
2136
+ * withheld for these whatever the stamp says — the same veto demand release
2137
+ * applies, and for the same reason: a withheld stack is a stack that can
2138
+ * never re-emit the envelope its standing demand needs. Callers hold the
2139
+ * checkout context, so they resolve the set with `boundFailingCheckNames`
2140
+ * and pass it in; this module stays pure.
1359
2141
  *
1360
- * Required, not optional (#515 review). `gh pr view --json autoMergeRequest`
1361
- * always returns the key — explicitly `null` when nothing is scheduled — and
1362
- * errors loudly on a field name it does not know, so there is no shape where
1363
- * the real CLI omits it. But `fetchPullRequest` is injectable, and an
1364
- * implementation that left the field out would silently disable the
1365
- * `boundary-wave` refusal that stops an epicless run from greening a
1366
- * candidate GitHub is already scheduled to merge. Requiring it makes the
1367
- * compiler enforce what `gh` already promises.
2142
+ * REQUIRED, with no default, on purpose: a defaulted `[]` reads the same
2143
+ * whether the caller inspected the envelopes or never looked, and this seam
2144
+ * exists precisely for EXTERNAL preview producers — the callers most likely
2145
+ * to skip the lookup. Pass the result of `boundFailingCheckNames`; pass `[]`
2146
+ * only to mean "inspected the envelopes and found no bound failure".
2147
+ *
2148
+ * Deliberately visible to `api:check` as a breaking signature change
2149
+ * (pre-1.0, no external callers yet).
1368
2150
  */
1369
- autoMergeRequest: {
2151
+ vetoedTargets: readonly string[];
2152
+ }) => PreviewLifecyclePlan;
2153
+ //#endregion
2154
+ //#region src/pr-status-hud.d.ts
2155
+ type FactoryPrStatusCheckName = "patronage-factory/merge-freeze" | "patronage-factory/pr-ready" | "patronage-factory/pr-verify";
2156
+ interface CompletedFactoryCheckSnapshot {
2157
+ readonly completedAt: string;
2158
+ readonly conclusion: string;
2159
+ readonly detailsUrl?: string;
2160
+ readonly headSha: string;
2161
+ readonly name: FactoryPrStatusCheckName;
2162
+ }
2163
+ interface FailedPreviewSnapshot {
2164
+ readonly completedAt: string;
2165
+ readonly conclusion: string;
2166
+ readonly detailsUrl?: string;
2167
+ readonly headSha: string;
2168
+ readonly name: string;
2169
+ }
2170
+ interface FactoryPrStatusSources {
2171
+ /** Live PR base ref name observed with the sources. Identity, not a SHA. */
2172
+ readonly baseRefName?: string;
2173
+ readonly baseSha: string;
2174
+ readonly checks: Readonly<Partial<Record<FactoryPrStatusCheckName, CompletedFactoryCheckSnapshot>>>;
2175
+ readonly previewFailures?: Readonly<Partial<Record<string, FailedPreviewSnapshot>>>;
2176
+ readonly previewRegistrations: readonly PreviewProofRegistration[];
2177
+ }
2178
+ interface RenderFactoryPrStatusHudInput extends FactoryPrStatusSources {
2179
+ readonly headSha: string;
2180
+ readonly plan: PreviewLifecyclePlan;
2181
+ readonly planHeadSha: string;
2182
+ readonly pr: number;
2183
+ /** ISO instant at which the presentation sources were observed. */
2184
+ readonly renderedAt: string;
2185
+ }
2186
+ interface PresentFactoryPrStatusHudInput {
2187
+ readonly headSha: string;
2188
+ readonly owner: string;
2189
+ readonly plan: PreviewLifecyclePlan;
2190
+ readonly planHeadSha: string;
2191
+ readonly pr: number;
2192
+ readonly renderedAt?: string;
2193
+ readonly repo: string;
2194
+ }
2195
+ interface PresentFactoryPrStatusHudDependencies {
2196
+ /**
2197
+ * Read only `previewProofInventory.list` registrations and completed,
2198
+ * Factory-App-owned check snapshots. PR comment bodies are not an evidence
2199
+ * source and are deliberately absent from this contract.
2200
+ */
2201
+ readonly readSources: (input: {
2202
+ headSha: string;
2203
+ owner: string;
2204
+ pr: number;
2205
+ previewTargets?: readonly string[];
2206
+ repo: string;
2207
+ }) => Promise<FactoryPrStatusSources>;
2208
+ /**
2209
+ * Recheck the pulls identity immediately before mutating the sticky HUD.
2210
+ * Happy path reads `/pulls/:n` only; git-ref is fetched to decorate a
2211
+ * head-moved error, not as a second identity endpoint.
2212
+ */
2213
+ readonly assertCurrentIdentity: (input: {
2214
+ baseRefName?: string; /** Retained for rendering/callers; identity compares base ref name. */
2215
+ baseSha?: string;
2216
+ headSha: string;
2217
+ owner: string;
2218
+ pr: number;
2219
+ repo: string;
2220
+ }) => Promise<void>;
2221
+ readonly upsert?: typeof upsertFactoryPrStatusComment;
2222
+ }
2223
+ interface ReadFactoryPrStatusSourcesInput {
2224
+ readonly headSha: string;
2225
+ /**
2226
+ * Contents-read token for `previewProofInventory.list` and the live
2227
+ * `git/ref/heads/<base>` tip. Both need `contents: read`; the Factory App
2228
+ * token has none, so pass a workflow `GITHUB_TOKEN` (#825, #908). The
2229
+ * inventory list falls back to `token`. The base tip has no HTTP fallback:
2230
+ * without this token it is read through `gh`.
2231
+ */
2232
+ readonly inventoryToken?: string;
2233
+ readonly owner: string;
2234
+ readonly pr: number;
2235
+ /**
2236
+ * Demanded preview stack names from the lifecycle plan. Used only to look up
2237
+ * a completed unsuccessful check run when inventory has no registration.
2238
+ */
2239
+ readonly previewTargets?: readonly string[];
2240
+ readonly repo: string;
2241
+ /** Factory App installation token, normally minted by the presentation job. */
2242
+ readonly token: string;
2243
+ }
2244
+ interface ReadFactoryPrStatusSourcesDependencies {
2245
+ readonly fetch?: typeof fetch;
2246
+ /**
2247
+ * Local base-tip reader used when no `inventoryToken` exists. Defaults to
2248
+ * the `gh`-backed reader `pr:ready` already uses.
2249
+ */
2250
+ readonly fetchBranchTipSha?: typeof fetchGitHubBranchTipSha;
2251
+ readonly listPreviewRegistrations?: (input: {
2252
+ owner: string;
2253
+ pr: number;
2254
+ repo: string;
2255
+ token: string;
2256
+ }) => Promise<readonly PreviewProofRegistration[]>;
2257
+ readonly timeoutMs?: number;
2258
+ }
2259
+ declare function renderFactoryPrStatusHud(input: RenderFactoryPrStatusHudInput): string;
2260
+ declare function presentFactoryPrStatusHud(input: PresentFactoryPrStatusHudInput, dependencies: PresentFactoryPrStatusHudDependencies): Promise<UpsertFactoryPrStatusCommentResult>;
2261
+ declare function assertFactoryPrStatusIdentity(input: ReadFactoryPrStatusSourcesInput & {
2262
+ readonly baseRefName?: string; /** Retained for rendering/callers; identity compares base ref name. */
2263
+ readonly baseSha?: string;
2264
+ }, dependencies?: ReadFactoryPrStatusSourcesDependencies): Promise<void>;
2265
+ declare function readFactoryPrStatusSources(input: ReadFactoryPrStatusSourcesInput, dependencies?: ReadFactoryPrStatusSourcesDependencies): Promise<FactoryPrStatusSources>;
2266
+ interface PlanFactoryPrStatusHudInput {
2267
+ readonly cwd: string;
2268
+ readonly headSha: string;
2269
+ readonly mergeBaseSha?: string;
2270
+ readonly patchId?: string;
2271
+ readonly profilePath?: string;
2272
+ }
2273
+ /**
2274
+ * Consume `planPreviewLifecycle` for the current checkout. No second plan is
2275
+ * invented: dispositions are Ready/Skipped from `deploy` vs `not-required`.
2276
+ * Candidate identity is never copied from the proof. Absent independent
2277
+ * identity or an unbound verify proof is the planner's conservative path.
2278
+ */
2279
+ declare function planFactoryPrStatusHud(input: PlanFactoryPrStatusHudInput): PreviewLifecyclePlan;
2280
+ interface RefreshFactoryPrStatusHudInput {
2281
+ readonly cwd: string;
2282
+ readonly headSha: string;
2283
+ /**
2284
+ * Workflow `GITHUB_TOKEN` with `contents: read` for the live git-ref and
2285
+ * preview inventory. The Factory App token cannot read those (#825, #908).
2286
+ */
2287
+ readonly inventoryToken?: string;
2288
+ readonly mergeBaseSha?: string;
2289
+ readonly owner: string;
2290
+ readonly patchId?: string;
2291
+ readonly pr: number;
2292
+ readonly profilePath?: string;
2293
+ readonly repo: string;
2294
+ readonly token?: string;
2295
+ }
2296
+ /** Plan from the checkout and present the App-owned HUD. */
2297
+ declare function refreshFactoryPrStatusHud(input: RefreshFactoryPrStatusHudInput): Promise<UpsertFactoryPrStatusCommentResult>;
2298
+ /**
2299
+ * Presentation must not fail an admission gate. Used after pr:ready publishes
2300
+ * its check so the table is not stuck at first-write.
2301
+ */
2302
+ declare function refreshFactoryPrStatusHudSafely(input: RefreshFactoryPrStatusHudInput, onNotice?: (message: string) => void): Promise<void>;
2303
+ //#endregion
2304
+ //#region src/pr-ready.d.ts
2305
+ interface PrReadyArgs extends LoadProjectProfileInput {
2306
+ authoringSessionIds?: string[];
2307
+ base: string;
2308
+ epic?: number;
2309
+ json?: boolean;
2310
+ output?: string;
2311
+ report?: boolean;
2312
+ pr: number;
2313
+ reviewProof?: string;
2314
+ throwWhenBlocked?: boolean;
2315
+ verifyProof?: string;
2316
+ }
2317
+ interface GitHubPullRequest {
2318
+ /**
2319
+ * GitHub's live auto-merge enablement, or `null` when nothing is scheduled.
2320
+ *
2321
+ * Required, not optional (#515 review). `gh pr view --json autoMergeRequest`
2322
+ * always returns the key — explicitly `null` when nothing is scheduled — and
2323
+ * errors loudly on a field name it does not know, so there is no shape where
2324
+ * the real CLI omits it. But `fetchPullRequest` is injectable, and an
2325
+ * implementation that left the field out would silently disable the
2326
+ * `boundary-wave` refusal that stops an epicless run from greening a
2327
+ * candidate GitHub is already scheduled to merge. Requiring it makes the
2328
+ * compiler enforce what `gh` already promises.
2329
+ */
2330
+ autoMergeRequest: {
1370
2331
  enabledAt?: string;
1371
2332
  } | null;
1372
2333
  baseRefName: string;
1373
2334
  baseRefOid: string;
1374
2335
  body: string;
2336
+ headRefName?: string;
1375
2337
  headRefOid: string;
2338
+ /**
2339
+ * Whether the head branch lives in a different repository from the base
2340
+ * (#922). Required, not optional, for the reason `autoMergeRequest` is: the
2341
+ * trusted checkout names ONE repository, and for a fork PR that is not the
2342
+ * base repository. An implementation that omitted the field would silently
2343
+ * resolve base policy from whichever repository the checkout points at.
2344
+ */
2345
+ isCrossRepository: boolean;
1376
2346
  isDraft: boolean;
1377
2347
  mergeStateStatus: string;
1378
2348
  mergeable: string;
@@ -1398,6 +2368,14 @@ interface PrReadyProof {
1398
2368
  headSha: string;
1399
2369
  outcome: "armed" | "merged" | "not-armed";
1400
2370
  };
2371
+ /**
2372
+ * The authoring session readiness resolved for the review-independence
2373
+ * cross-check (#1037). Recorded so the branded check can print it beside the
2374
+ * review session, model, and producer the ledger already carries — the four
2375
+ * identities a human weighs at merge time. Additive and optional: proofs
2376
+ * written before it carry no field, so no schema version moves.
2377
+ */
2378
+ authoringSession?: string;
1401
2379
  /**
1402
2380
  * Why this run blocked, one entry per refusing demand (#391): `code` is the
1403
2381
  * demand key from the resolver's vocabulary, `detail` the one-sentence
@@ -1432,6 +2410,13 @@ interface PrReadyProof {
1432
2410
  * waived demand reads to a human. Absent when there are none.
1433
2411
  */
1434
2412
  notices?: string[];
2413
+ /**
2414
+ * The policy identity readiness resolved review demand under (#922): the
2415
+ * base ref, its live tip, and the digests of the base, candidate, and merged
2416
+ * review policies. Optional on the wire and additive — this is a new record
2417
+ * on an unchanged contract, so no schema version moves.
2418
+ */
2419
+ policyResolution?: PolicyResolution;
1435
2420
  /** Committed profile blob evaluated by readiness. Required for merge. */
1436
2421
  profileBlobSha?: string;
1437
2422
  /** Checkout-relative committed profile path evaluated by readiness. */
@@ -1455,6 +2440,13 @@ interface PrReadyDependencies {
1455
2440
  * call plus the read-back that says what actually happened.
1456
2441
  */
1457
2442
  armAutoMerge?: (input: ArmAutoMergeInput) => ArmAutoMergeOutcome;
2443
+ /**
2444
+ * Reads the authoritative base review policy (#922): the profile committed at
2445
+ * the live tip of the PR's own base ref. Defaults to the real GitHub reads,
2446
+ * so an unstated authority refuses rather than falling back to candidate
2447
+ * policy — unreadable authority is never absent authority.
2448
+ */
2449
+ basePolicy?: BaseReviewPolicyAuthority;
1458
2450
  github?: {
1459
2451
  fetchClosingPullRequests?: (input: {
1460
2452
  issue: number;
@@ -1496,6 +2488,12 @@ interface PrReadyDependencies {
1496
2488
  publishFinalCheckRun?: (input: Omit<PublishFactoryCheckInput, "status"> & {
1497
2489
  conclusion: "failure" | "success";
1498
2490
  }) => Promise<boolean> | boolean;
2491
+ /**
2492
+ * Re-present the App-owned HUD after this run's ready check is published
2493
+ * so the table is not stuck at first-write. Defaults to a safe refresh
2494
+ * that never fails the gate.
2495
+ */
2496
+ presentStatusHud?: (input: RefreshFactoryPrStatusHudInput) => Promise<void> | void;
1499
2497
  /** Injectable delay for the UNKNOWN-mergeable brief poll (tests). */
1500
2498
  sleep?: (ms: number) => Promise<void>;
1501
2499
  }
@@ -1503,9 +2501,16 @@ interface PrReadyGitDependencies {
1503
2501
  canResolveCommit: (cwd: string, sha: string) => boolean;
1504
2502
  changedFiles: (cwd: string, base: string, headSha?: string) => string[];
1505
2503
  checkoutRepository: (cwd: string) => CheckoutRepository;
2504
+ /**
2505
+ * Bring `refs/heads/<baseRefName>` into the checkout so the live tip
2506
+ * `pr.baseRefOid` can resolve. Optional so fixtures that already resolve
2507
+ * every SHA can omit it.
2508
+ */
2509
+ fetchOriginRef?: (cwd: string, refName: string) => void;
1506
2510
  currentHeadSha: (cwd: string) => string;
1507
2511
  mergeBaseSha: (cwd: string, base: string) => string;
1508
- objectIdAtRef: (cwd: string, ref: string, absolutePath: string) => string | undefined;
2512
+ /** `repositoryRelativePath` is repository-relative, never cwd-relative. */
2513
+ objectIdAtRef: (cwd: string, ref: string, repositoryRelativePath: string) => string | undefined;
1509
2514
  resolveCommitSha: (cwd: string, ref: string) => string | undefined;
1510
2515
  showFileAtRef: (cwd: string, ref: string, absolutePath: string) => string | undefined;
1511
2516
  stablePatchId: (cwd: string, base: string) => string;
@@ -1514,108 +2519,6 @@ declare function validatePrReadyProof(value: unknown): PrReadyProof;
1514
2519
  declare function readPrReadyProof(filePath: string): PrReadyProof;
1515
2520
  declare function runPrReady(args: PrReadyArgs, dependencies?: PrReadyDependencies): Promise<PrReadyProof>;
1516
2521
  //#endregion
1517
- //#region src/impact-stamp.d.ts
1518
- /**
1519
- * The recorded stamp. `targets` satisfies the completeness invariant: every
1520
- * target the profile declares is present, each with its exact basis — never
1521
- * silently absent. `basis: "conservative"` means an unmodelled or unprovable
1522
- * input widened every target to full impact.
1523
- */
1524
- declare const impactStampSchema: z.ZodObject<{
1525
- basis: z.ZodEnum<{
1526
- "target-scoped": "target-scoped";
1527
- conservative: "conservative";
1528
- }>;
1529
- reasons: z.ZodArray<z.ZodString>;
1530
- stampVersion: z.ZodLiteral<2>;
1531
- targets: z.ZodArray<z.ZodObject<{
1532
- basis: z.ZodString;
1533
- impact: z.ZodEnum<{
1534
- affected: "affected";
1535
- "not-affected": "not-affected";
1536
- }>;
1537
- name: z.ZodString;
1538
- }, z.core.$strip>>;
1539
- }, z.core.$strip>;
1540
- type ImpactStamp = z.infer<typeof impactStampSchema>;
1541
- /**
1542
- * The surfaces that consume the stamp. One classification, consumed
1543
- * everywhere (#430): every surface routes through
1544
- * {@link impactStampScopeDecision}, so no surface can be more trusting than
1545
- * another, and no surface re-derives path rules of its own. The value only
1546
- * selects the wording of the conservative floor a refusal falls back to.
1547
- */
1548
- declare const IMPACT_SCOPE_SURFACES: {
1549
- readonly demand: "full demand floor";
1550
- readonly "preview-lifecycle": "full preview-lifecycle floor";
1551
- readonly "verification-battery": "full verification-battery floor";
1552
- };
1553
- type ImpactScopeSurface = keyof typeof IMPACT_SCOPE_SURFACES;
1554
- interface ImpactScopeDecision {
1555
- reason: string;
1556
- /** True ⇒ this target's work is provably unreachable and may be released. */
1557
- scoped: boolean;
1558
- }
1559
- /**
1560
- * Whether a trusted stamp RELEASES one target-scoped unit of work — an
1561
- * external proof demand (#542 wave 2), a verification-battery command, or a
1562
- * preview (Alchemy) lifecycle stack (#430 wave 3).
1563
- *
1564
- * The only release path is a `target-scoped` stamp of exactly this build's
1565
- * stamp version whose target entry for exactly this name is provably
1566
- * `not-affected`. Every other input — no trusted stamp, an unknown stamp
1567
- * version, a conservative stamp, a name the stamp does not classify, or an
1568
- * `affected` verdict — keeps today's full-work floor. Work only ever gets
1569
- * released, never added or satisfied: this function can withdraw a demand, it
1570
- * can never certify one.
1571
- *
1572
- * Identity binding is the CALLER's precondition: pass only a stamp computed
1573
- * for, or read from a pr:verify proof bound to, the current candidate (see
1574
- * `trustedImpactStamp` in `pr-readiness/verification-proof.ts`); pass
1575
- * `undefined` otherwise.
1576
- */
1577
- declare const impactStampScopeDecision: ({
1578
- stamp,
1579
- surface,
1580
- targetName
1581
- }: {
1582
- stamp: ImpactStamp | undefined;
1583
- surface: ImpactScopeSurface;
1584
- targetName: string;
1585
- }) => ImpactScopeDecision;
1586
- //#endregion
1587
- //#region src/required-check-policy.d.ts
1588
- declare const EVIDENCE_CHECK_TYPES: readonly ["review", "verify"];
1589
- type EvidenceCheckType = (typeof EVIDENCE_CHECK_TYPES)[number];
1590
- declare const requiredCheckScopeSchema: z.ZodObject<{
1591
- classifications: z.ZodArray<z.ZodEnum<{
1592
- trivial: "trivial";
1593
- "docs/process-only": "docs/process-only";
1594
- "non-trivial": "non-trivial";
1595
- }>>;
1596
- }, z.core.$strict>;
1597
- type RequiredCheckScope = z.infer<typeof requiredCheckScopeSchema>;
1598
- interface RequiredCheckScopeContext {
1599
- classification: DiffClassification | undefined;
1600
- impactStamp?: ImpactStamp;
1601
- }
1602
- interface ScopeDecision {
1603
- inScope: boolean;
1604
- reason: string;
1605
- }
1606
- declare const requiredCheckInScope: ({
1607
- context,
1608
- scope
1609
- }: {
1610
- context: RequiredCheckScopeContext;
1611
- scope?: RequiredCheckScope;
1612
- }) => ScopeDecision;
1613
- interface RequiredCheck {
1614
- name: string;
1615
- checkType: EvidenceCheckType;
1616
- scope?: RequiredCheckScope;
1617
- }
1618
- //#endregion
1619
2522
  //#region src/factory-session.d.ts
1620
2523
  declare const resolveAuthoringSessionIds: ({
1621
2524
  override,
@@ -1697,587 +2600,186 @@ interface EvidenceCandidateIdentity {
1697
2600
  mergeBaseSha: string;
1698
2601
  }
1699
2602
  declare const evidenceBindingFresh: ({
1700
- candidate,
1701
- envelope
1702
- }: {
1703
- candidate: EvidenceCandidateIdentity;
1704
- envelope: EvidenceEnvelope;
1705
- }) => boolean;
1706
- interface IndependenceResult {
1707
- independent: boolean;
1708
- reason?: "no-session" | "unknown-authoring-identity" | "same-session";
1709
- }
1710
- declare const evidenceReviewIndependence: ({
1711
- authoringSessionIds,
1712
- envelope
1713
- }: {
1714
- authoringSessionIds: string[];
1715
- envelope: EvidenceEnvelope;
1716
- }) => IndependenceResult;
1717
- type LoadedEvidenceEnvelope = {
1718
- ok: true;
1719
- envelope: EvidenceEnvelope;
1720
- path: string;
1721
- } | {
1722
- check?: string;
1723
- error: string;
1724
- ok: false;
1725
- path: string;
1726
- };
1727
- /**
1728
- * Every check name with a current, candidate-bound FAILING envelope on disk.
1729
- *
1730
- * The wave-3 scoping veto input. Callers pass the resolved set to
1731
- * `planVerificationBattery` / `planPreviewLifecycle`, which stay pure — the
1732
- * planners decide, they never read the filesystem.
1733
- *
1734
- * `checkType` is the caller's, not a guess: schema-v5 requiredChecks are
1735
- * verify-only (`resolveProfileRequiredChecks`), so a scoping caller passes
1736
- * `"verify"` and matches exactly the pair wave 2 evaluates.
1737
- */
1738
- declare const boundFailingCheckNames: ({
1739
- candidate,
1740
- checkType,
1741
- envelopes
1742
- }: {
1743
- candidate: EvidenceCandidateIdentity;
1744
- checkType: EvidenceCheckType;
1745
- envelopes: LoadedEvidenceEnvelope[];
1746
- }) => string[];
1747
- interface RequiredCheckEvaluationInput {
1748
- authoringSessionIds: string[];
1749
- candidate: EvidenceCandidateIdentity;
1750
- envelopes: LoadedEvidenceEnvelope[];
1751
- requiredChecks: RequiredCheck[];
1752
- scopeContext: RequiredCheckScopeContext;
1753
- }
1754
- interface RequiredCheckOutcome {
1755
- name: string;
1756
- checkType: EvidenceCheckType;
1757
- status: "satisfied" | "unmet" | "out-of-scope";
1758
- inScope: boolean;
1759
- scopeReason: string;
1760
- scope?: RequiredCheckScope;
1761
- reason?: string;
1762
- matchedPath?: string;
1763
- }
1764
- interface RequiredCheckEvaluation {
1765
- outcomes: RequiredCheckOutcome[];
1766
- blockingReasons: string[];
1767
- }
1768
- declare const evaluateRequiredChecks: ({
1769
- authoringSessionIds,
1770
- candidate,
1771
- envelopes,
1772
- requiredChecks,
1773
- scopeContext
1774
- }: RequiredCheckEvaluationInput) => RequiredCheckEvaluation;
1775
- declare const EVIDENCE_DIR = ".factory-memory/evidence";
1776
- declare const loadEvidenceEnvelopes: (cwd: string) => LoadedEvidenceEnvelope[];
1777
- //#endregion
1778
- //#region src/review-proof-applicability.d.ts
1779
- declare const REVIEW_STATUS_VALUES: readonly ["not-required", "current", "stale", "missing", "blocked"];
1780
- declare const reviewStatusSchema: z.ZodEnum<{
1781
- blocked: "blocked";
1782
- stale: "stale";
1783
- "not-required": "not-required";
1784
- current: "current";
1785
- missing: "missing";
1786
- }>;
1787
- type ReviewStatus = z.infer<typeof reviewStatusSchema>;
1788
- interface CurrentReviewIdentity {
1789
- headSha: string;
1790
- patchId: string;
1791
- }
1792
- declare const reviewStatus: ({
1793
- blocked,
1794
- required,
1795
- reviewedHeadSha,
1796
- reviewedPatchId,
1797
- headSha,
1798
- patchId
1799
- }: CurrentReviewIdentity & {
1800
- blocked?: boolean;
1801
- required: boolean;
1802
- reviewedHeadSha?: string;
1803
- reviewedPatchId?: string;
1804
- }) => ReviewStatus;
1805
- declare namespace proof_identity_d_exports {
1806
- export { CurrentReviewIdentity, REVIEW_STATUS_VALUES, ReviewProofClaim, ReviewStatus, explicitFailureIdentity, isExplicitReviewFailure, isUntypedReviewProof, reviewStatus, reviewStatusSchema, selectReviewProof };
1807
- }
1808
- type ReviewProofClaim = {
1809
- reviewedHeadSha?: string;
1810
- reviewedPatchId?: string;
1811
- untypedVerdict?: boolean;
1812
- } | {
1813
- explicitFailure: true;
1814
- reviewedHeadSha?: string;
1815
- reviewedPatchId?: string;
1816
- untypedVerdict?: boolean;
1817
- };
1818
- declare const isExplicitReviewFailure: (proof: ReviewProofClaim) => proof is {
1819
- explicitFailure: true;
1820
- reviewedHeadSha?: string;
1821
- reviewedPatchId?: string;
1822
- untypedVerdict?: boolean;
1823
- };
1824
- declare const isUntypedReviewProof: (proof: ReviewProofClaim) => proof is {
1825
- untypedVerdict: true;
1826
- reviewedHeadSha?: string;
1827
- reviewedPatchId?: string;
1828
- };
1829
- declare const explicitFailureIdentity: (proof: ReviewProofClaim) => {
1830
- reviewedHeadSha?: string;
1831
- reviewedPatchId?: string;
1832
- };
1833
- declare const selectReviewProof: ({
1834
- reviewProof
1835
- }: {
1836
- reviewProof: ReviewProofClaim;
1837
- }) => {
1838
- reviewedHeadSha?: string;
1839
- reviewedPatchId?: string;
1840
- untypedVerdict?: boolean;
1841
- };
1842
- //#endregion
1843
- //#region src/pr-readiness/review-epoch.d.ts
1844
- interface ReviewCycleState {
1845
- autoBlockingFindings: number;
1846
- countsBySeverity: Record<ReviewFindingSeverity, number>;
1847
- highestBlockingSeverity?: ReviewFindingSeverity;
1848
- highestOpenSeverity?: ReviewFindingSeverity;
1849
- maxReviewCycles?: number;
1850
- nonBlockingFindings: number;
1851
- openFindings: number;
1852
- reviewCycle?: number;
1853
- staleRepeatFindings?: number;
1854
- windowExhausted: boolean;
1855
- }
1856
- declare const reviewCycleStateFor: (proof: Pick<PrReviewProof, "ladder" | "reviewCycle" | "maxReviewCycles" | "reviews">, policy?: ReviewLadderPolicy, adjudicatedLedger?: FindingLedgerEntry[]) => ReviewCycleState;
1857
- type ReviewAcceptance = "accepted-after-cap" | "accepted-clean" | "accepted-through-ladder" | "blocked";
1858
- declare const resolveReviewAcceptance: (proof: PrReviewProof, review: PrReviewResult, policy: ReviewLadderPolicy | undefined) => ReviewAcceptance;
1859
- type ReviewTerminalState = "accepted-with-findings" | "blocked" | "clean";
1860
- declare const resolveReviewTerminalStateForEpoch: (proof: PrReviewProof, review: PrReviewResult, epoch: ReviewEpochMode, adjudicatedLedger?: FindingLedgerEntry[]) => ReviewTerminalState;
1861
- declare const resolveReviewTerminalState: (proof: PrReviewProof, review: PrReviewResult, policy: ReviewLadderPolicy | undefined) => ReviewTerminalState;
1862
- declare const resolveReviewTerminalStateAcrossReviews: (proof: PrReviewProof, epoch: ReviewEpochMode, adjudicatedLedger?: FindingLedgerEntry[]) => ReviewTerminalState | undefined;
1863
- declare const resolveReviewTerminalStateAcrossReviewsForPolicy: (proof: PrReviewProof, policy: ReviewLadderPolicy) => ReviewTerminalState | undefined;
1864
- declare const reviewProofFor: (proof: PrReviewProof | undefined, kind: PrReviewKind, policy: ReviewLadderPolicy | undefined, current?: {
1865
- patchId: string;
1866
- }) => ReviewProofClaim;
1867
- declare namespace review_proof_d_exports {
1868
- export { DEFAULT_PR_REVIEW_MAX_CYCLES, DEFAULT_PR_REVIEW_PROOF_PATH, PR_REVIEW_FINAL_READINESS_NOTICE, PR_REVIEW_FINDING_PROVENANCE_VERSION, PR_REVIEW_PROOF_DESCRIPTOR, PR_REVIEW_SCHEMA_VERSION, PrReviewFinding, PrReviewKind, PrReviewLadderState, PrReviewMode, PrReviewOutcome, PrReviewProof, PrReviewResult, PrReviewStageResolution, REVIEW_SEVERITIES, ReviewAcceptance, ReviewCycleState, ReviewFindingCategory, ReviewFindingSeverity, ReviewTerminalState, prReviewFindingSchema, prReviewProofSchema, prReviewResultSchema, readPrReviewProof, resolveReviewAcceptance, resolveReviewTerminalState, resolveReviewTerminalStateAcrossReviews, resolveReviewTerminalStateAcrossReviewsForPolicy, resolveReviewTerminalStateForEpoch, reviewCycleStateFor, reviewProofFor, validatePrReviewProof, validatePrReviewResult };
1869
- }
1870
- declare const PR_REVIEW_SCHEMA_VERSION = 2;
1871
- declare const PR_REVIEW_FINDING_PROVENANCE_VERSION = 1;
1872
- declare const DEFAULT_PR_REVIEW_PROOF_PATH = ".factory-memory/pr-review.json";
1873
- declare const DEFAULT_PR_REVIEW_MAX_CYCLES = 5;
1874
- declare const PR_REVIEW_FINAL_READINESS_NOTICE = "pr:review is a final readiness proof gate. Run it after local verification and avoid repeated full runs unless the review proof records actionable findings. Default review window: 5 cycles.";
1875
- declare const prReviewFindingSchema: z.ZodType<PrReviewFinding>;
1876
- declare const prReviewResultSchema: z.ZodType<PrReviewResult>;
1877
- declare const prReviewProofSchema: z.ZodType<PrReviewProof>;
1878
- declare const validatePrReviewResult: (value: unknown) => PrReviewResult;
1879
- declare const validatePrReviewProof: (value: unknown) => PrReviewProof;
1880
- declare const readPrReviewProof: (filePath: string) => PrReviewProof;
1881
- declare const PR_REVIEW_PROOF_DESCRIPTOR: ProofDescriptor<PrReviewProof>;
1882
- declare namespace verification_proof_d_exports {
1883
- export { PrVerifyBaselineFullProof, PrVerifyCommandResult, PrVerifyExecutedCommand, PrVerifyNotRequiredCommand, PrVerifyProof, PrVerifySchemaVersion, ResolvedPrVerifyMode, SUPPORTED_PR_VERIFY_SCHEMA_VERSIONS, VerificationHeadShas, VerificationProofState, VerifiedHeadShas, prVerifyFullHeadShasForDiff, prVerifyProofHeadShas, readPrVerifyProof, resolveVerifyProofApplicability, trustedImpactStamp, validatePrVerifyProof, verificationProofApplicabilityFor, verificationProofBlockingReason, verificationProofForReadiness, verificationProofStateFor, verifyProofIdentityMatches, verifyProofPassed };
1884
- }
1885
- interface VerifiedHeadShas {
1886
- docsOnlyVerifiedHeadShas: string[];
1887
- trivialVerifiedHeadShas: string[];
1888
- verifiedHeadShas: string[];
1889
- }
1890
- type VerificationHeadShas = {
1891
- explicitFailure: true;
1892
- } | VerifiedHeadShas;
1893
- declare const SUPPORTED_PR_VERIFY_SCHEMA_VERSIONS: readonly [1, 2, 3, 4];
1894
- type PrVerifySchemaVersion = (typeof SUPPORTED_PR_VERIFY_SCHEMA_VERSIONS)[number];
1895
- interface PrVerifyCommandResult {
1896
- command: string;
1897
- description: string;
1898
- /**
1899
- * Epic #550 wave 3 (#430): the profile's declared impact target for this
1900
- * command, recorded from v4 on. It is the proof's own command→target
1901
- * mapping: a `notRequiredCommands` entry must name the target recorded HERE
1902
- * for the same command, so a withholding cannot point at whichever released
1903
- * target happens to be convenient. Absent for a command the profile does
1904
- * not scope, and for v1–v3 proofs, which predate the field.
1905
- */
1906
- impactTarget?: string;
1907
- name: string;
1908
- scope: "always" | "docs-only" | "trivial" | "full";
1909
- }
1910
- interface PrVerifyExecutedCommand {
1911
- command: string;
1912
- counts?: {
1913
- testFiles?: number;
1914
- tests?: number;
1915
- };
1916
- durationMs: number;
1917
- exitCode: number;
1918
- name: string;
1919
- scope: "always" | "docs-only" | "trivial" | "full";
1920
- }
1921
- /**
1922
- * Epic #550 wave 3 (#430): a verification command the impact stamp proved this
1923
- * candidate cannot reach, so the battery did not run it.
1924
- *
1925
- * The completeness invariant lives in the pairing: `verificationCommands`
1926
- * records every command the resolved mode selected, `executedCommands` records
1927
- * what ran, and this list records the rest WITH the stamp's own basis. A
1928
- * withheld stack is therefore never silently absent from the proof — it is
1929
- * present, named, and explained.
1930
- */
1931
- interface PrVerifyNotRequiredCommand {
1932
- basis: string;
1933
- impactTarget: string;
1934
- name: string;
1935
- }
1936
- interface PrVerifyProof {
1937
- schemaVersion: PrVerifySchemaVersion;
1938
- authoringSession?: string;
1939
- base: string;
1940
- baselineFullProofs?: {
1941
- base: string;
1942
- changedFiles: string[];
1943
- headSha: string;
1944
- profilePath: string;
1945
- projectKey: string;
1946
- repository: string;
1947
- }[];
1948
- changedFiles: string[];
1949
- classification: DiffClassification;
1950
- classificationReasons: string[];
1951
- command: "patronage-factory pr:verify";
1952
- durationMs: number;
1953
- endedAt: string;
1954
- executedCommands?: PrVerifyExecutedCommand[];
1955
- headSha: string;
1956
- impactStamp?: ImpactStamp;
1957
- mode: ResolvedPrVerifyMode;
1958
- mergeBaseSha?: string;
1959
- notRequiredCommands?: PrVerifyNotRequiredCommand[];
1960
- outcome?: "aborted" | "passed";
1961
- patchId?: string;
1962
- profilePath: string;
1963
- projectKey: string;
1964
- repository: string;
1965
- startedAt: string;
1966
- verificationCommands: PrVerifyCommandResult[];
1967
- }
1968
- type PrVerifyBaselineFullProof = NonNullable<PrVerifyProof["baselineFullProofs"]>[number];
1969
- declare function validatePrVerifyProof(value: unknown): PrVerifyProof;
1970
- declare function readPrVerifyProof(filePath: string): PrVerifyProof;
1971
- declare const verifyProofPassed: (proof: PrVerifyProof) => boolean;
1972
- declare const prVerifyProofHeadShas: (proof: PrVerifyProof | undefined, creditedHeadSha?: string) => VerifiedHeadShas;
1973
- declare const verifyProofIdentityMatches: ({
1974
- currentIdentity,
1975
- proof
1976
- }: {
1977
- currentIdentity?: {
1978
- patchId: string;
1979
- mergeBaseSha?: string;
1980
- };
1981
- proof?: PrVerifyProof;
1982
- }) => boolean;
1983
- /**
1984
- * Wave-2 consumption (#542): the recorded impact stamp, released for demand
1985
- * resolution ONLY when it is identity-bound to the current candidate — the
1986
- * proof passed, and its recorded headSha AND patchId both name exactly this
1987
- * candidate (the same identities the proof already binds). Everything else —
1988
- * no proof, an aborted run, a stale head, a moved patch id, a pre-stamp proof
1989
- * — returns `undefined`, and the consumer keeps today's full-demand floor.
1990
- *
1991
- * Deliberately stricter than verify-once applicability (which tolerates a
1992
- * head-only or patch-id-only match): a stamp narrows external demands, so it
1993
- * is trusted only on an exact double binding, fail closed.
1994
- */
1995
- declare const trustedImpactStamp: ({
1996
- candidate,
1997
- proof
1998
- }: {
1999
- candidate: {
2000
- headSha: string;
2001
- patchId: string;
2002
- };
2003
- proof: PrVerifyProof | undefined;
2004
- }) => ImpactStamp | undefined;
2005
- declare const prVerifyFullHeadShasForDiff: ({
2006
- docsOnlyDeltaAcceptedSince,
2007
- files,
2008
- proof
2009
- }: {
2010
- docsOnlyDeltaAcceptedSince?: (baselineHeadSha: string) => boolean;
2011
- files: string[];
2012
- proof: PrVerifyProof;
2013
- }) => string[];
2014
- type VerificationProofState = {
2015
- kind: "typed-aborted";
2016
- proof: PrVerifyProof;
2017
- } | {
2018
- kind: "typed-missing";
2019
- path: string;
2020
- reason: "enoent" | "invalid";
2021
- message?: string;
2022
- } | {
2023
- kind: "typed";
2024
- headShas: VerifiedHeadShas;
2025
- proof: PrVerifyProof;
2026
- } | {
2027
- kind: "typed-diff-mismatch";
2028
- mode: ResolvedPrVerifyMode;
2029
- };
2030
- declare const verificationProofStateFor: ({
2031
- proof,
2032
- proofMatchesCurrentDiff,
2033
- proofPath
2034
- }: {
2035
- proof?: PrVerifyProof;
2036
- proofMatchesCurrentDiff?: boolean;
2037
- proofPath?: string;
2038
- }) => VerificationProofState;
2039
- declare const verificationProofApplicabilityFor: ({
2040
- docsOnlyDeltaAcceptedSince,
2041
- explicitProof,
2042
- files,
2043
- headSha,
2044
- currentIdentity,
2045
- proof,
2046
- proofPath,
2047
- proofReadError
2048
- }: {
2049
- docsOnlyDeltaAcceptedSince?: (baselineHeadSha: string) => boolean;
2050
- explicitProof: boolean;
2051
- files: string[];
2052
- headSha: string;
2053
- currentIdentity?: {
2054
- patchId: string;
2055
- mergeBaseSha?: string;
2056
- };
2057
- proof?: PrVerifyProof;
2058
- proofPath?: string;
2059
- proofReadError?: unknown;
2060
- }) => {
2061
- fullVerifiedHeadShas: never[];
2062
- verificationProof: VerificationProofState;
2063
- } | {
2064
- fullVerifiedHeadShas: string[];
2065
- verificationProof: {
2066
- headShas: VerifiedHeadShas;
2067
- kind: "typed";
2068
- proof: PrVerifyProof;
2069
- };
2070
- };
2071
- declare const resolveVerifyProofApplicability: ({
2072
- proofPath,
2073
- explicitProof,
2074
- docsOnlyDeltaAcceptedSince,
2075
- files,
2076
- headSha,
2077
- currentVerifyIdentityForBase,
2078
- preread
2079
- }: {
2080
- proofPath: string;
2081
- explicitProof: boolean;
2082
- docsOnlyDeltaAcceptedSince?: (baselineHeadSha: string) => boolean;
2083
- files: string[];
2084
- headSha: string;
2085
- currentVerifyIdentityForBase?: (base: string) => {
2086
- patchId: string;
2087
- mergeBaseSha?: string;
2088
- };
2089
- preread?: {
2090
- proof?: PrVerifyProof;
2091
- error?: unknown;
2092
- };
2093
- }) => {
2094
- fullVerifiedHeadShas: never[];
2095
- verificationProof: VerificationProofState;
2603
+ candidate,
2604
+ envelope
2605
+ }: {
2606
+ candidate: EvidenceCandidateIdentity;
2607
+ envelope: EvidenceEnvelope;
2608
+ }) => boolean;
2609
+ interface IndependenceResult {
2610
+ independent: boolean;
2611
+ reason?: "no-session" | "unknown-authoring-identity" | "same-session";
2612
+ }
2613
+ declare const evidenceReviewIndependence: ({
2614
+ authoringSessionIds,
2615
+ envelope
2616
+ }: {
2617
+ authoringSessionIds: string[];
2618
+ envelope: EvidenceEnvelope;
2619
+ }) => IndependenceResult;
2620
+ type LoadedEvidenceEnvelope = {
2621
+ ok: true;
2622
+ envelope: EvidenceEnvelope;
2623
+ path: string;
2096
2624
  } | {
2097
- fullVerifiedHeadShas: string[];
2098
- verificationProof: {
2099
- headShas: VerifiedHeadShas;
2100
- kind: "typed";
2101
- proof: PrVerifyProof;
2102
- };
2625
+ check?: string;
2626
+ error: string;
2627
+ ok: false;
2628
+ path: string;
2103
2629
  };
2104
- declare const verificationProofForReadiness: (state: VerificationProofState) => VerificationHeadShas;
2105
- declare const verificationProofBlockingReason: (state: VerificationProofState) => string | undefined;
2106
- //#endregion
2107
- //#region src/retro-envelope.d.ts
2108
2630
  /**
2109
- * Versioned retro envelope schema (epic #27 wave 2, issue #34).
2110
- *
2111
- * One envelope per lane, built at `factory:closeout` and delivered through the
2112
- * typed gate-sink as the `retro-envelope` ingest kind. Re-derived in TypeScript
2113
- * from the `spike/telemetry-layer2` S5 scratch schema (reference-only, never
2114
- * merged). This module is the single source of truth for the v1 wire shape
2115
- * and its bounds ({@link RETRO_ENVELOPE_WIRE_BOUNDS}) — producer and consumer
2116
- * alike. HQ imports these exports directly from the Worker-safe
2117
- * `@patronage/software-factory/schemas` subpath
2118
- * (`software-factory-hq/src/contracts/retro-schemas.ts`) instead of
2119
- * maintaining a parallel hand-written copy, so there is exactly one wire
2120
- * contract and no drift-detection machinery is needed (issue #350; formerly
2121
- * a hand-written twin plus a 767-line parity test, #46).
2122
- *
2123
- * DESIGN INVARIANT: cross-family token sums must be UNREPRESENTABLE.
2124
- *
2125
- * The two model families use different tokenizers, prices, and accounting
2126
- * conventions, so any token total that spans Claude and GPT is a lie:
2127
- *
2128
- * 1. There is no combined/total token field anywhere in the envelope.
2129
- * 2. `tokenFamilies` is strict — its only keys are `claude` and `gpt`; data
2130
- * cannot smuggle in a third "all"/"combined" slot.
2131
- * 3. The family BLOCKS are structurally different shapes with DIFFERENT keys
2132
- * (claude is a single flat block keyed on freshInput/cacheReadInput/
2133
- * cacheCreationInput; gpt is `{ roles: [...] }`). The exclusive input-tier
2134
- * COUNTS share no key name across families. The residual names shared
2135
- * between the claude block and a gpt ROLE entry are pinned to exactly
2136
- * {costUsd, model, output} (PR #32 advisory): `costUsd` is deliberate —
2137
- * USD is the one cross-family summable unit (rule 4); `model` is an
2138
- * unsummable label; `output` is the same name at DIFFERENT depths (lane
2139
- * block vs per-role entry), frozen by a tripwire test in
2140
- * `retro-envelope.test.ts` so the overlap cannot grow. Renaming `output`
2141
- * is a schemaVersion-2 wire change, deliberately not spent in v1.
2142
- * 4. Cost is per-family USD and nullable. Combined totals are allowed in USD
2143
- * only, and only as a projection-time sum of per-family USD.
2631
+ * Every check name with a current, candidate-bound FAILING envelope on disk.
2144
2632
  *
2145
- * Field names also encode the S2/S3 reader lessons: Claude `freshInput` alone
2146
- * is not prompt size (true input context = freshInput + cacheReadInput +
2147
- * cacheCreationInput, requestId-deduped), and codex `inputInclusiveOfCache`
2148
- * already includes `cachedInput`, so `freshInputDerived` (inclusive − cached)
2149
- * is the only value safe to feed a per-token pricer.
2633
+ * The wave-3 scoping veto input. Callers pass the resolved set to
2634
+ * `planVerificationBattery` / `planPreviewLifecycle`, which stay pure — the
2635
+ * planners decide, they never read the filesystem.
2150
2636
  *
2151
- * COMPLETENESS POSTURE: harvest may have no usable native log for a lane, so
2152
- * `tokenFamilies` may legitimately be absent. The closeout build gate demands
2153
- * a valid envelope, not available telemetry. A families-absent envelope keeps
2154
- * its operator-visible data gaps and is a replayable advisory HQ event, so it
2155
- * never substitutes unavailable usage with zero. The wire shape (field names,
2156
- * types, structure) stays byte-parity with HQ v1.
2157
- */
2158
- declare const RETRO_ENVELOPE_SCHEMA_VERSION = 1;
2159
- declare const retroEnvelopeV1Schema: z.ZodObject<{
2160
- agentRunId: z.ZodString;
2161
- archiveRef: z.ZodOptional<z.ZodString>;
2162
- cycles: z.ZodObject<{
2163
- gateRunsToFirstGreen: z.ZodNumber;
2164
- reviewerFixRounds: z.ZodNumber;
2165
- thermoFixRounds: z.ZodNumber;
2166
- }, z.core.$strict>;
2167
- dataGaps: z.ZodDefault<z.ZodArray<z.ZodString>>;
2168
- gates: z.ZodArray<z.ZodObject<{
2169
- cycle: z.ZodNumber;
2170
- duration: z.ZodNumber;
2171
- gate: z.ZodString;
2172
- outcome: z.ZodEnum<{
2173
- pass: "pass";
2174
- fail: "fail";
2175
- skip: "skip";
2176
- }>;
2177
- startedAt: z.ZodISODateTime;
2178
- }, z.core.$strict>>;
2179
- generatedAt: z.ZodISODateTime;
2180
- interventions: z.ZodObject<{
2181
- count: z.ZodNumber;
2182
- }, z.core.$strict>;
2183
- joinKeys: z.ZodObject<{
2184
- claudeSessionIds: z.ZodDefault<z.ZodArray<z.ZodString>>;
2185
- codexThreadIds: z.ZodDefault<z.ZodArray<z.ZodString>>;
2186
- }, z.core.$strict>;
2187
- kind: z.ZodLiteral<"retro-envelope">;
2188
- outcome: z.ZodOptional<z.ZodObject<{
2189
- status: z.ZodEnum<{
2190
- success: "success";
2191
- fail: "fail";
2192
- blocked: "blocked";
2193
- "ship-with-followups": "ship-with-followups";
2194
- }>;
2195
- verdict: z.ZodOptional<z.ZodString>;
2196
- }, z.core.$strict>>;
2197
- phases: z.ZodArray<z.ZodObject<{
2198
- at: z.ZodISODateTime;
2199
- deltaSec: z.ZodOptional<z.ZodNumber>;
2200
- name: z.ZodString;
2201
- }, z.core.$strict>>;
2202
- refs: z.ZodObject<{
2203
- branch: z.ZodOptional<z.ZodString>;
2204
- epic: z.ZodOptional<z.ZodString>;
2205
- headSha: z.ZodOptional<z.ZodString>;
2206
- issue: z.ZodOptional<z.ZodString>;
2207
- prNumber: z.ZodOptional<z.ZodNumber>;
2208
- }, z.core.$strict>;
2209
- repo: z.ZodObject<{
2210
- name: z.ZodString;
2211
- owner: z.ZodString;
2212
- }, z.core.$strict>;
2213
- schemaVersion: z.ZodLiteral<1>;
2214
- tokenFamilies: z.ZodObject<{
2215
- claude: z.ZodOptional<z.ZodObject<{
2216
- cacheCreationInput: z.ZodNumber;
2217
- cacheReadInput: z.ZodNumber;
2218
- costUsd: z.ZodNullable<z.ZodNumber>;
2219
- family: z.ZodLiteral<"claude">;
2220
- freshInput: z.ZodNumber;
2221
- model: z.ZodString;
2222
- output: z.ZodNumber;
2223
- requests: z.ZodNumber;
2224
- }, z.core.$strict>>;
2225
- gpt: z.ZodOptional<z.ZodObject<{
2226
- family: z.ZodLiteral<"gpt">;
2227
- roles: z.ZodArray<z.ZodObject<{
2228
- cachedInput: z.ZodNumber;
2229
- costUsd: z.ZodNullable<z.ZodNumber>;
2230
- freshInputDerived: z.ZodNumber;
2231
- inputInclusiveOfCache: z.ZodNumber;
2232
- model: z.ZodString;
2233
- output: z.ZodNumber;
2234
- reasoningOutput: z.ZodNumber;
2235
- role: z.ZodString;
2236
- threadId: z.ZodOptional<z.ZodString>;
2237
- }, z.core.$strict>>;
2238
- }, z.core.$strict>>;
2239
- }, z.core.$strict>;
2240
- wallClock: z.ZodObject<{
2241
- endTs: z.ZodISODateTime;
2242
- startTs: z.ZodISODateTime;
2243
- totalSec: z.ZodNumber;
2244
- }, z.core.$strict>;
2245
- }, z.core.$strict>;
2246
- type RetroEnvelope = z.infer<typeof retroEnvelopeV1Schema>;
2247
- /**
2248
- * Versioned payload validators, keyed by schema major. Unknown majors never
2249
- * reach these — {@link parseRetroEnvelope} returns them raw and marked
2250
- * degraded, mirroring HQ's ingest skew posture (stored raw, never dropped).
2637
+ * `checkType` is the caller's, not a guess: schema-v5 requiredChecks are
2638
+ * verify-only (`resolveProfileRequiredChecks`), so a scoping caller passes
2639
+ * `"verify"` and matches exactly the pair wave 2 evaluates.
2251
2640
  */
2252
- declare const RETRO_ENVELOPE_VALIDATORS: Record<number, z.ZodType<RetroEnvelope, unknown>>;
2253
- declare const SUPPORTED_RETRO_ENVELOPE_SCHEMA_VERSIONS: readonly number[];
2254
- /** The `schemaVersion` a candidate declares, or undefined when unreadable. */
2255
- declare const retroEnvelopeSchemaVersionOf: (candidate: unknown) => number | undefined;
2256
- type ParsedRetroEnvelope = {
2257
- disposition: "trusted";
2258
- envelope: RetroEnvelope;
2259
- schemaVersion: number;
2641
+ declare const boundFailingCheckNames: ({
2642
+ candidate,
2643
+ checkType,
2644
+ envelopes
2645
+ }: {
2646
+ candidate: EvidenceCandidateIdentity;
2647
+ checkType: EvidenceCheckType;
2648
+ envelopes: LoadedEvidenceEnvelope[];
2649
+ }) => string[];
2650
+ interface RequiredCheckEvaluationInput {
2651
+ authoringSessionIds: string[];
2652
+ candidate: EvidenceCandidateIdentity;
2653
+ envelopes: LoadedEvidenceEnvelope[];
2654
+ requiredChecks: RequiredCheck[];
2655
+ scopeContext: RequiredCheckScopeContext;
2656
+ }
2657
+ interface RequiredCheckOutcome {
2658
+ name: string;
2659
+ checkType: EvidenceCheckType;
2660
+ status: "satisfied" | "unmet" | "out-of-scope";
2661
+ scopeReason: string;
2662
+ scope?: RequiredCheckScope;
2663
+ reason?: string;
2664
+ matchedPath?: string;
2665
+ }
2666
+ interface RequiredCheckEvaluation {
2667
+ outcomes: RequiredCheckOutcome[];
2668
+ blockingReasons: string[];
2669
+ }
2670
+ declare const evaluateRequiredChecks: ({
2671
+ authoringSessionIds,
2672
+ candidate,
2673
+ envelopes,
2674
+ requiredChecks,
2675
+ scopeContext
2676
+ }: RequiredCheckEvaluationInput) => RequiredCheckEvaluation;
2677
+ declare const EVIDENCE_DIR = ".factory-memory/evidence";
2678
+ declare const loadEvidenceEnvelopes: (cwd: string) => LoadedEvidenceEnvelope[];
2679
+ //#endregion
2680
+ //#region src/review-proof-applicability.d.ts
2681
+ declare const REVIEW_STATUS_VALUES: readonly ["not-required", "current", "stale", "missing", "blocked"];
2682
+ declare const reviewStatusSchema: z.ZodEnum<{
2683
+ "not-required": "not-required";
2684
+ blocked: "blocked";
2685
+ current: "current";
2686
+ stale: "stale";
2687
+ missing: "missing";
2688
+ }>;
2689
+ type ReviewStatus = z.infer<typeof reviewStatusSchema>;
2690
+ interface CurrentReviewIdentity {
2691
+ headSha: string;
2692
+ patchId: string;
2693
+ }
2694
+ declare const reviewStatus: ({
2695
+ blocked,
2696
+ required,
2697
+ reviewedHeadSha,
2698
+ reviewedPatchId,
2699
+ headSha,
2700
+ patchId
2701
+ }: CurrentReviewIdentity & {
2702
+ blocked?: boolean;
2703
+ required: boolean;
2704
+ reviewedHeadSha?: string;
2705
+ reviewedPatchId?: string;
2706
+ }) => ReviewStatus;
2707
+ declare namespace proof_identity_d_exports {
2708
+ export { CurrentReviewIdentity, REVIEW_STATUS_VALUES, ReviewProofClaim, ReviewStatus, explicitFailureIdentity, isExplicitReviewFailure, isUntypedReviewProof, reviewStatus, reviewStatusSchema, selectReviewProof };
2709
+ }
2710
+ type ReviewProofClaim = {
2711
+ reviewedHeadSha?: string;
2712
+ reviewedPatchId?: string;
2713
+ untypedVerdict?: boolean;
2260
2714
  } | {
2261
- disposition: "degraded";
2262
- raw: unknown;
2263
- schemaVersion: number | undefined;
2715
+ explicitFailure: true;
2716
+ reviewedHeadSha?: string;
2717
+ reviewedPatchId?: string;
2718
+ untypedVerdict?: boolean;
2264
2719
  };
2265
- /**
2266
- * Parses a candidate against the versioned validators. A recognized major is
2267
- * validated typed-only (throws on an invalid known-version payload); an unknown
2268
- * major is round-tripped RAW and marked degraded — the retained payload is the
2269
- * exact input object, never a coerced projection. Mirrors the HQ ingest seam so
2270
- * the two sides agree on the skew posture.
2271
- */
2272
- declare const parseRetroEnvelope: (candidate: unknown) => ParsedRetroEnvelope;
2273
- /**
2274
- * Whether harvest recorded at least one token family. This is an operator
2275
- * summary predicate, not a delivery gate: a families-absent envelope remains
2276
- * valid and replayable when its data gaps explain why telemetry is unavailable.
2277
- */
2278
- declare const isRetroEnvelopeWireComplete: (envelope: Pick<RetroEnvelope, "tokenFamilies">) => boolean;
2279
- /** Epic anchor for an envelope: refs.epic, else refs.issue, else the PR. */
2280
- declare const retroEpicReference: (refs: RetroEnvelope["refs"]) => string | undefined;
2720
+ declare const isExplicitReviewFailure: (proof: ReviewProofClaim) => proof is {
2721
+ explicitFailure: true;
2722
+ reviewedHeadSha?: string;
2723
+ reviewedPatchId?: string;
2724
+ untypedVerdict?: boolean;
2725
+ };
2726
+ declare const isUntypedReviewProof: (proof: ReviewProofClaim) => proof is {
2727
+ untypedVerdict: true;
2728
+ reviewedHeadSha?: string;
2729
+ reviewedPatchId?: string;
2730
+ };
2731
+ declare const explicitFailureIdentity: (proof: ReviewProofClaim) => {
2732
+ reviewedHeadSha?: string;
2733
+ reviewedPatchId?: string;
2734
+ };
2735
+ declare const selectReviewProof: ({
2736
+ reviewProof
2737
+ }: {
2738
+ reviewProof: ReviewProofClaim;
2739
+ }) => {
2740
+ reviewedHeadSha?: string;
2741
+ reviewedPatchId?: string;
2742
+ untypedVerdict?: boolean;
2743
+ };
2744
+ //#endregion
2745
+ //#region src/pr-readiness/review-epoch.d.ts
2746
+ interface ReviewCycleState {
2747
+ autoBlockingFindings: number;
2748
+ countsBySeverity: Record<ReviewFindingSeverity, number>;
2749
+ highestBlockingSeverity?: ReviewFindingSeverity;
2750
+ highestOpenSeverity?: ReviewFindingSeverity;
2751
+ maxReviewCycles?: number;
2752
+ nonBlockingFindings: number;
2753
+ openFindings: number;
2754
+ reviewCycle?: number;
2755
+ staleRepeatFindings?: number;
2756
+ windowExhausted: boolean;
2757
+ }
2758
+ declare const reviewCycleStateFor: (proof: Pick<PrReviewProof, "ladder" | "reviewCycle" | "maxReviewCycles" | "reviews">, policy?: ReviewLadderPolicy, adjudicatedLedger?: FindingLedgerEntry[]) => ReviewCycleState;
2759
+ type ReviewAcceptance = "accepted-after-cap" | "accepted-clean" | "accepted-through-ladder" | "blocked";
2760
+ declare const resolveReviewAcceptance: (proof: PrReviewProof, review: PrReviewResult, policy: ReviewLadderPolicy | undefined) => ReviewAcceptance;
2761
+ type ReviewTerminalState = "accepted-with-findings" | "blocked" | "clean";
2762
+ declare const resolveReviewTerminalStateForEpoch: (proof: PrReviewProof, review: PrReviewResult, epoch: ReviewEpochMode, adjudicatedLedger?: FindingLedgerEntry[]) => ReviewTerminalState;
2763
+ declare const resolveReviewTerminalState: (proof: PrReviewProof, review: PrReviewResult, policy: ReviewLadderPolicy | undefined) => ReviewTerminalState;
2764
+ declare const resolveReviewTerminalStateAcrossReviews: (proof: PrReviewProof, epoch: ReviewEpochMode, adjudicatedLedger?: FindingLedgerEntry[]) => ReviewTerminalState | undefined;
2765
+ declare const resolveReviewTerminalStateAcrossReviewsForPolicy: (proof: PrReviewProof, policy: ReviewLadderPolicy) => ReviewTerminalState | undefined;
2766
+ declare const reviewProofFor: (proof: PrReviewProof | undefined, kind: PrReviewKind, policy: ReviewLadderPolicy | undefined, current?: {
2767
+ patchId: string;
2768
+ }) => ReviewProofClaim;
2769
+ declare namespace review_proof_d_exports {
2770
+ export { DEFAULT_PR_REVIEW_MAX_CYCLES, DEFAULT_PR_REVIEW_PROOF_PATH, PR_REVIEW_FINAL_READINESS_NOTICE, PR_REVIEW_FINDING_PROVENANCE_VERSION, PR_REVIEW_PROOF_DESCRIPTOR, PR_REVIEW_SCHEMA_VERSION, PrReviewFinding, PrReviewKind, PrReviewLadderState, PrReviewMode, PrReviewOutcome, PrReviewProof, PrReviewResult, PrReviewStageResolution, REVIEW_SEVERITIES, ReviewAcceptance, ReviewCycleState, ReviewFindingCategory, ReviewFindingSeverity, ReviewTerminalState, prReviewFindingSchema, prReviewProofSchema, prReviewResultSchema, resolveReviewAcceptance, resolveReviewTerminalState, resolveReviewTerminalStateAcrossReviews, resolveReviewTerminalStateAcrossReviewsForPolicy, resolveReviewTerminalStateForEpoch, reviewCycleStateFor, reviewProofFor, validatePrReviewProof, validatePrReviewResult };
2771
+ }
2772
+ declare const PR_REVIEW_SCHEMA_VERSION = 2;
2773
+ declare const PR_REVIEW_FINDING_PROVENANCE_VERSION = 1;
2774
+ declare const DEFAULT_PR_REVIEW_PROOF_PATH = ".factory-memory/pr-review.json";
2775
+ declare const DEFAULT_PR_REVIEW_MAX_CYCLES = 5;
2776
+ declare const PR_REVIEW_FINAL_READINESS_NOTICE = "pr:review is a final readiness proof gate. Run it after local verification and avoid repeated full runs unless the review proof records actionable findings. Default review window: 5 cycles.";
2777
+ declare const prReviewFindingSchema: z.ZodType<PrReviewFinding>;
2778
+ declare const prReviewResultSchema: z.ZodType<PrReviewResult>;
2779
+ declare const prReviewProofSchema: z.ZodType<PrReviewProof>;
2780
+ declare const validatePrReviewResult: (value: unknown) => PrReviewResult;
2781
+ declare const validatePrReviewProof: (value: unknown) => PrReviewProof;
2782
+ declare const PR_REVIEW_PROOF_DESCRIPTOR: ProofDescriptor<PrReviewProof>;
2281
2783
  //#endregion
2282
2784
  //#region src/schemas.d.ts
2283
2785
  declare const boundaryCheckProofSchema: z.ZodObject<{
@@ -2328,28 +2830,46 @@ declare const boundaryCheckProofSchema: z.ZodObject<{
2328
2830
  value: z.ZodString;
2329
2831
  }, z.core.$strip>>;
2330
2832
  status: z.ZodEnum<{
2331
- blocked: "blocked";
2332
2833
  ready: "ready";
2834
+ blocked: "blocked";
2333
2835
  }>;
2334
2836
  }, z.core.$strip>;
2335
2837
  type BoundaryCheckProofRecord = z.infer<typeof boundaryCheckProofSchema>;
2336
2838
  //#endregion
2337
2839
  //#region src/boundary-check.d.ts
2338
- interface BoundaryPullRequestRef {
2339
- headRefOid?: string;
2340
- mergeCommitOid?: string;
2341
- number: number;
2342
- state: "OPEN" | "CLOSED" | "MERGED";
2343
- }
2344
2840
  interface BoundaryCheckGithub {
2345
2841
  fetchIssueBody: (repo: string, issue: number) => string;
2346
2842
  fetchIssueComments: (repo: string, issue: number) => GithubIssueComment[];
2347
2843
  fetchClosingPullRequests: (repo: string, issue: number) => BoundaryPullRequestRef[];
2348
- fetchPullRequest: (repo: string, pr: number) => BoundaryPullRequestRef;
2844
+ fetchPullRequest?: (repo: string, pr: number) => BoundaryPullRequestRef;
2845
+ /**
2846
+ * Child issue state for the close-gate (#901). Required so a stub cannot
2847
+ * skip the gate and look like a pass.
2848
+ */
2849
+ fetchIssueState: (repo: string, issue: number) => "OPEN" | "CLOSED";
2850
+ /**
2851
+ * PRs whose bodies may contribute closing-keyword membership (#901). For
2852
+ * `each-to-epic`, production lists PRs targeting the integration branch.
2853
+ * Branch targeting never joins; only a keyword naming a declared child does.
2854
+ * Required so omitting the channel cannot silently drop it.
2855
+ */
2856
+ listCandidatePullRequests: (repo: string, input: {
2857
+ integrationBranch?: string;
2858
+ }) => (BoundaryPullRequestRef & {
2859
+ body?: string;
2860
+ })[];
2349
2861
  }
2350
2862
  interface BoundaryCheckArgs {
2351
2863
  cwd?: string;
2352
2864
  epic: number;
2865
+ /**
2866
+ * Closeout-final mode (#853): a manifest-declared issue whose closing-PR
2867
+ * set is empty is a blocking reason, not a notice. Off by default so the
2868
+ * interior boundary review (run before the terminal release PR exists,
2869
+ * e.g. epic #842's own review of #844) keeps working; the epic closeout
2870
+ * step turns this on as the last check before factory:closeout.
2871
+ */
2872
+ final?: boolean;
2353
2873
  json?: boolean;
2354
2874
  output?: string;
2355
2875
  repo?: string;
@@ -2357,12 +2877,13 @@ interface BoundaryCheckArgs {
2357
2877
  interface BoundaryCheckDependencies {
2358
2878
  github?: BoundaryCheckGithub;
2359
2879
  hq?: HqIngestDependencies;
2880
+ readWaivers?: (cwd: string) => DemandWaiver[];
2360
2881
  resolveRepo?: (cwd: string) => string;
2361
2882
  }
2362
2883
  declare function runBoundaryCheck(args: BoundaryCheckArgs, dependencies?: BoundaryCheckDependencies): BoundaryCheckProofRecord;
2363
2884
  declare function validateBoundaryCheckProof(value: unknown): BoundaryCheckProofRecord;
2364
2885
  //#endregion
2365
- //#region src/commands/doctor.d.ts
2886
+ //#region src/cli-output.d.ts
2366
2887
  interface CliOutput {
2367
2888
  stderr: Pick<NodeJS.WriteStream, "write">;
2368
2889
  stdout: Pick<NodeJS.WriteStream, "write">;
@@ -2410,32 +2931,6 @@ declare const runDemandWaive: (args: DemandWaiveArgs, dependencies?: DemandWaive
2410
2931
  //#region src/commands/demand-waive.d.ts
2411
2932
  type DemandWaiveAction = (args: DemandWaiveArgs) => DemandWaiver;
2412
2933
  //#endregion
2413
- //#region src/hq-credentials.d.ts
2414
- /**
2415
- * Why a reference did not resolve. Each value names a different remedy, and
2416
- * none of them can be inferred from a value-or-nothing result:
2417
- *
2418
- * - `resolver-missing` — no secret-manager binary on PATH.
2419
- * - `resolver-blocked` — a binary exists but this session may not execute it
2420
- * (a sandbox denying exec). The command belongs outside the sandbox.
2421
- * - `resolver-timeout` — the probe expired: a desktop agent waiting on an
2422
- * approval nobody can give here.
2423
- * - `resolver-refused` — the binary ran and produced no value. Its store is
2424
- * unreachable from this session (a sandbox with no keychain access) or the
2425
- * reference is not readable. These two stay one status on purpose: telling
2426
- * them apart would mean reading resolver output.
2427
- */
2428
- type SecretResolutionFailure = "resolver-blocked" | "resolver-missing" | "resolver-refused" | "resolver-timeout";
2429
- /** A structured resolution outcome. The value travels only when resolved. */
2430
- type SecretResolution = {
2431
- status: "resolved";
2432
- value: string;
2433
- } | {
2434
- status: SecretResolutionFailure;
2435
- };
2436
- /** Resolves a secret reference. Injected so tests stay offline. */
2437
- type SecretReferenceResolver = (reference: string) => SecretResolution;
2438
- //#endregion
2439
2934
  //#region src/hq-flush.d.ts
2440
2935
  /**
2441
2936
  * Spool locations this run did not drain because they sit under an earlier
@@ -2459,12 +2954,34 @@ type HqFlushResult = (HqFlushOrphans & {
2459
2954
  status: "flushed";
2460
2955
  });
2461
2956
  //#endregion
2957
+ //#region src/catch-up-recognition.d.ts
2958
+ type CatchUpRecognitionResult = {
2959
+ recognition: CatchUpRecognition;
2960
+ recognized: true;
2961
+ } | {
2962
+ reasons: string[];
2963
+ recognized: false;
2964
+ };
2965
+ type CatchUpRecognizer = (input: {
2966
+ base: string;
2967
+ cwd: string;
2968
+ }) => CatchUpRecognitionResult;
2969
+ //#endregion
2462
2970
  //#region src/pr-review.d.ts
2463
2971
  interface PrReviewArgs extends LoadProjectProfileInput {
2972
+ assemble?: boolean;
2464
2973
  base: string;
2465
2974
  cycle: number;
2975
+ /**
2976
+ * Issue carrying the factory-boundary manifest, which may be the work issue
2977
+ * itself. `--assemble` uses it to name the review rung the candidate's wave
2978
+ * demands, so the prompt asks for the findings schema the gate accepts
2979
+ * (#1001). It is the same handle `pr:publish` and `pr:ready` take.
2980
+ */
2981
+ epic?: number;
2466
2982
  dispositions?: string;
2467
2983
  findings?: string;
2984
+ historical?: boolean;
2468
2985
  issue?: number;
2469
2986
  mode: PrReviewMode;
2470
2987
  output?: string;
@@ -2472,15 +2989,52 @@ interface PrReviewArgs extends LoadProjectProfileInput {
2472
2989
  }
2473
2990
  interface PrReviewGitDependencies {
2474
2991
  changedFiles: (cwd: string, base: string) => string[];
2992
+ checkoutRepository?: (cwd: string) => CheckoutRepository;
2475
2993
  currentHeadSha: (cwd: string) => string;
2994
+ firstParentCommits?: (cwd: string, base: string) => string[];
2476
2995
  isAncestor: (cwd: string, ancestor: string, descendant: string) => boolean;
2996
+ recognizeCatchUp?: CatchUpRecognizer;
2997
+ repositoryRoot?: (cwd: string) => string;
2998
+ showFileAtRef?: (cwd: string, ref: string, absolutePath: string) => string | undefined;
2477
2999
  stablePatchId: (cwd: string, base: string) => string;
3000
+ stablePatchIdAtRef?: (cwd: string, base: string, ref: string) => string;
2478
3001
  statusPorcelain: (cwd: string) => string;
2479
3002
  }
3003
+ interface PrReviewIssueBodyInput {
3004
+ issue: number;
3005
+ owner: string;
3006
+ repo: string;
3007
+ }
2480
3008
  interface PrReviewDependencies {
3009
+ /**
3010
+ * The authoritative base-policy reader (#922). Injectable for the same
3011
+ * reason `pr:ready` injects it: an unstated authority must be a refusal a
3012
+ * test can state, never a silent pass.
3013
+ */
3014
+ basePolicy?: BaseReviewPolicyAuthority;
3015
+ /**
3016
+ * How the wave resolver reads an issue's closing pull requests (#1001).
3017
+ * Injected for the same reason `fetchIssueBody` is: the wave demand must be
3018
+ * statable in a test without a live repository.
3019
+ */
3020
+ fetchClosingPullRequests?: (input: PrReviewIssueBodyInput) => {
3021
+ number: number;
3022
+ state?: "OPEN" | "CLOSED" | "MERGED";
3023
+ }[];
3024
+ fetchIssueBody?: (input: PrReviewIssueBodyInput) => string;
3025
+ /**
3026
+ * How `--assemble` reads the pull request whose wave demand names the review
3027
+ * rung (#1001). Defaults to the GitHub lookup, and its result is validated
3028
+ * before use, so an injected stub is held to the same shape.
3029
+ */
3030
+ fetchWavePullRequest?: (cwd: string) => unknown;
2481
3031
  git?: PrReviewGitDependencies;
2482
3032
  hq?: HqIngestDependencies;
2483
- publishCheckRun?: (input: PublishFactoryCheckInput) => void;
3033
+ /**
3034
+ * How this run finds the pull request whose base ref is the policy authority
3035
+ * (#922 Slice B). Defaults to the GitHub lookup.
3036
+ */
3037
+ lookupPullRequest?: (cwd: string) => CandidatePullRequestLookup;
2484
3038
  }
2485
3039
  declare function runPrReview(args: PrReviewArgs, dependencies?: PrReviewDependencies): Promise<PrReviewProof>;
2486
3040
  //#endregion
@@ -2493,7 +3047,7 @@ interface CleanInstallResolutionDependencies {
2493
3047
  }
2494
3048
  //#endregion
2495
3049
  //#region src/pr-verify.d.ts
2496
- type PrVerifyMode = "auto" | "docs-only" | "trivial" | "full";
3050
+ type PrVerifyMode = "auto" | "docs-only" | "full";
2497
3051
  interface VerificationCommandOutcome {
2498
3052
  counts?: {
2499
3053
  testFiles?: number;
@@ -2501,6 +3055,8 @@ interface VerificationCommandOutcome {
2501
3055
  };
2502
3056
  durationMs: number;
2503
3057
  exitCode: number;
3058
+ /** The failing tests scraped from this command's output (#1035). */
3059
+ failures?: PrVerifyTestFailure[];
2504
3060
  }
2505
3061
  interface PrVerifyArgs extends LoadProjectProfileInput {
2506
3062
  authoringSession?: string;
@@ -2511,16 +3067,30 @@ interface PrVerifyArgs extends LoadProjectProfileInput {
2511
3067
  }
2512
3068
  interface PrVerifyGitDependencies {
2513
3069
  changedFiles: (cwd: string, base: string) => string[];
3070
+ checkoutRepository?: (cwd: string) => CheckoutRepository;
2514
3071
  currentHeadSha: (cwd: string) => string;
2515
3072
  emptyTreeHash: (cwd: string) => string;
2516
3073
  mergeBaseSha: (cwd: string, base: string) => string;
3074
+ recognizeCatchUp?: CatchUpRecognizer;
2517
3075
  runVerificationCommand: (command: string, cwd: string, env: Record<string, string>) => VerificationCommandOutcome;
2518
3076
  showFileAtRef?: (cwd: string, ref: string, absolutePath: string) => string | undefined;
2519
3077
  statusPorcelain: (cwd: string) => string;
2520
3078
  stablePatchId: (cwd: string, base: string) => string;
2521
3079
  }
2522
3080
  interface PrVerifyDependencies {
3081
+ /**
3082
+ * The authoritative base-policy reader (#922). Injectable for the same
3083
+ * reason `pr:ready` injects it: an unstated authority must be a refusal a
3084
+ * test can state, never a silent pass.
3085
+ */
3086
+ basePolicy?: BaseReviewPolicyAuthority;
2523
3087
  cleanInstall?: CleanInstallResolutionDependencies | false;
3088
+ /**
3089
+ * How this run finds the pull request whose base ref is the policy authority
3090
+ * (#922 Slice B). Defaults to the GitHub lookup; a checkout with no pull
3091
+ * request resolves `unavailable`, which is normal before publication.
3092
+ */
3093
+ lookupPullRequest?: (cwd: string) => CandidatePullRequestLookup;
2524
3094
  env?: NodeJS.ProcessEnv;
2525
3095
  git?: PrVerifyGitDependencies;
2526
3096
  hq?: HqIngestDependencies;
@@ -2623,6 +3193,12 @@ interface PrPublishDependencies extends PrReadyDependencies {
2623
3193
  cwd: string;
2624
3194
  }) => Promise<HqFlushResult>;
2625
3195
  runPrVerify?: (args: PrVerifyArgs) => Promise<PrVerifyProof>;
3196
+ /**
3197
+ * Injectable clock for the promotion instant the hosted-run await measures
3198
+ * `verify` staleness against (#1045; tests only — production reads the real
3199
+ * clock).
3200
+ */
3201
+ now?: () => Date;
2626
3202
  /**
2627
3203
  * Injectable delay for the bounded hosted-run await (#348; tests only —
2628
3204
  * production always waits the real interval).
@@ -2702,6 +3278,28 @@ type PrReadyAction = (args: PrReadyArgs) => Promise<unknown>;
2702
3278
  //#region src/commands/pr-review.d.ts
2703
3279
  type PrReviewAction = (args: PrReviewArgs) => Promise<unknown>;
2704
3280
  //#endregion
3281
+ //#region src/pr-status-hud-command.d.ts
3282
+ interface PrStatusHudArgs {
3283
+ readonly cwd: string;
3284
+ readonly headSha: string;
3285
+ /**
3286
+ * Contents-read token for the preview-proof inventory list and the live
3287
+ * git-ref tip. The App token has no contents permission, so the workflow
3288
+ * `GITHUB_TOKEN` serves those reads (#825, #908).
3289
+ */
3290
+ readonly inventoryToken?: string;
3291
+ readonly owner: string;
3292
+ readonly planPath?: string;
3293
+ readonly pr: number;
3294
+ readonly repo: string;
3295
+ readonly token: string;
3296
+ }
3297
+ type PrStatusHudAction = (args: PrStatusHudArgs) => Promise<{
3298
+ action: string;
3299
+ commentId: number;
3300
+ url: string;
3301
+ }>;
3302
+ //#endregion
2705
3303
  //#region src/packages/trace/implementation/core.d.ts
2706
3304
  declare const FactoryTraceEnvelopeCoreSchema: z.ZodObject<{
2707
3305
  createdAt: z.ZodString;
@@ -2846,6 +3444,7 @@ declare const FACTORY_TRACE_EVENT_DEFINITIONS: readonly [DefinedTraceEvent<"revi
2846
3444
  patchId: z.ZodString;
2847
3445
  reason: z.ZodEnum<{
2848
3446
  "no-applicable-mode": "no-applicable-mode";
3447
+ "faithful-merge": "faithful-merge";
2849
3448
  }>;
2850
3449
  reviewCycle: z.ZodNumber;
2851
3450
  }, z.core.$strict>, readonly [z.ZodObject<{
@@ -2868,6 +3467,7 @@ declare const FACTORY_TRACE_EVENT_DEFINITIONS: readonly [DefinedTraceEvent<"revi
2868
3467
  patchId: z.ZodString;
2869
3468
  reason: z.ZodEnum<{
2870
3469
  "no-applicable-mode": "no-applicable-mode";
3470
+ "faithful-merge": "faithful-merge";
2871
3471
  }>;
2872
3472
  reviewCycle: z.ZodNumber;
2873
3473
  }, z.core.$strict>], {
@@ -2881,6 +3481,7 @@ declare const FACTORY_TRACE_EVENT_DEFINITIONS: readonly [DefinedTraceEvent<"revi
2881
3481
  patchId: z.ZodString;
2882
3482
  reason: z.ZodEnum<{
2883
3483
  "no-applicable-mode": "no-applicable-mode";
3484
+ "faithful-merge": "faithful-merge";
2884
3485
  }>;
2885
3486
  reviewCycle: z.ZodNumber;
2886
3487
  }, z.core.$strict>;
@@ -2898,7 +3499,7 @@ declare const FACTORY_TRACE_EVENT_DEFINITIONS: readonly [DefinedTraceEvent<"revi
2898
3499
  observedAt: string;
2899
3500
  outcome: "not-required";
2900
3501
  patchId: string;
2901
- reason: "no-applicable-mode";
3502
+ reason: "no-applicable-mode" | "faithful-merge";
2902
3503
  reviewCycle: number;
2903
3504
  issue?: number | undefined;
2904
3505
  pr?: number | undefined;
@@ -2949,8 +3550,8 @@ declare const FACTORY_TRACE_EVENT_DEFINITIONS: readonly [DefinedTraceEvent<"revi
2949
3550
  sessionId: z.ZodOptional<z.ZodString>;
2950
3551
  }, z.core.$strict>>;
2951
3552
  stage: z.ZodEnum<{
2952
- gate: "gate";
2953
3553
  interior: "interior";
3554
+ gate: "gate";
2954
3555
  }>;
2955
3556
  usage: z.ZodOptional<z.ZodObject<{
2956
3557
  estimatedCostUsd: z.ZodOptional<z.ZodNumber>;
@@ -3002,8 +3603,8 @@ declare const FACTORY_TRACE_EVENT_DEFINITIONS: readonly [DefinedTraceEvent<"revi
3002
3603
  sessionId: z.ZodOptional<z.ZodString>;
3003
3604
  }, z.core.$strict>>;
3004
3605
  stage: z.ZodEnum<{
3005
- gate: "gate";
3006
3606
  interior: "interior";
3607
+ gate: "gate";
3007
3608
  }>;
3008
3609
  usage: z.ZodOptional<z.ZodObject<{
3009
3610
  estimatedCostUsd: z.ZodOptional<z.ZodNumber>;
@@ -3046,8 +3647,8 @@ declare const FACTORY_TRACE_EVENT_DEFINITIONS: readonly [DefinedTraceEvent<"revi
3046
3647
  sessionId: z.ZodOptional<z.ZodString>;
3047
3648
  }, z.core.$strict>>;
3048
3649
  stage: z.ZodEnum<{
3049
- gate: "gate";
3050
3650
  interior: "interior";
3651
+ gate: "gate";
3051
3652
  }>;
3052
3653
  usage: z.ZodOptional<z.ZodObject<{
3053
3654
  estimatedCostUsd: z.ZodOptional<z.ZodNumber>;
@@ -3077,7 +3678,7 @@ declare const FACTORY_TRACE_EVENT_DEFINITIONS: readonly [DefinedTraceEvent<"revi
3077
3678
  staleRepeats: number;
3078
3679
  };
3079
3680
  observedAt: string;
3080
- stage: "gate" | "interior";
3681
+ stage: "interior" | "gate";
3081
3682
  issue?: number | undefined;
3082
3683
  pr?: number | undefined;
3083
3684
  threadId?: string | undefined;
@@ -3699,74 +4300,6 @@ declare const scanFactoryTraceDiagnostics: ({
3699
4300
  repoRoot,
3700
4301
  to
3701
4302
  }: ScanFactoryTraceDiagnosticsOptions) => FactoryTraceDiagnostic[];
3702
- //#endregion
3703
- //#region src/interior-telemetry/gate-timing.d.ts
3704
- declare const GATE_TIMING_SCHEMA_VERSION = 1;
3705
- type FactoryGateName = "boundary:check" | "factory:closeout" | "pr:ready" | "pr:review" | "pr:verify";
3706
- type GateTimingOutcome = "fail" | "pass";
3707
- interface GateTimingRecord {
3708
- agentRunId: string;
3709
- cycle: number;
3710
- durationMs: number;
3711
- gate: FactoryGateName;
3712
- outcome: GateTimingOutcome;
3713
- schemaVersion: typeof GATE_TIMING_SCHEMA_VERSION;
3714
- startedAt: string;
3715
- startOffsetMs: number;
3716
- }
3717
- //#endregion
3718
- //#region src/retro-envelope-builder.d.ts
3719
- /**
3720
- * Folds a lane's gate-timing ledger (`.factory-memory/gate-timing/<id>.jsonl`,
3721
- * wave-1 PR #33) into a versioned retro envelope at `factory:closeout`.
3722
- *
3723
- * STRUCTURAL INVARIANT (#677 repeat-class rule; PR #35 review cycles 1-2):
3724
- * telemetry CONTENT can never fail the closeout build gate. Every value that
3725
- * reaches the envelope passes through one sanitization seam that makes the
3726
- * output valid BY CONSTRUCTION:
3727
- *
3728
- * - strings are clamped to their wire bounds (truncated, with a data gap when
3729
- * truncation lost information);
3730
- * - numbers must be finite and within plausibility bounds BEFORE any derived
3731
- * arithmetic; an absurd value (1e16 ms duration, year-9999 timestamp) SKIPS
3732
- * its record with a data gap rather than clamping, because clamping would
3733
- * assert a measurement that never happened;
3734
- * - arrays are bounded to their schema maxima (gates[] keeps the most recent);
3735
- * - derived computations (wall clock, cycles) consume only sanitized inputs,
3736
- * so no ledger content can push them outside Date/Number safe ranges.
3737
- *
3738
- * Terminal backstop: the assembled candidate goes through a final schema
3739
- * parse; if that still fails, a minimal-valid envelope (clamped identity,
3740
- * empty gates, a data gap naming the failure) is built and returned instead.
3741
- * `buildRetroEnvelope` therefore never throws for content — the closeout gate
3742
- * can only fail on filesystem errors when persisting.
3743
- */
3744
- interface BuildRetroEnvelopeInput {
3745
- agentRunId: string;
3746
- /** Optional pointer (key/URL) to #8's durable proof archive — never payload. */
3747
- archiveRef?: string;
3748
- dataGaps?: string[];
3749
- generatedAt: Date;
3750
- interventions?: number;
3751
- /** Per-family session identities the lane already records. */
3752
- joinKeys?: {
3753
- claudeSessionIds?: string[];
3754
- codexThreadIds?: string[];
3755
- };
3756
- /** The lane's gate-timing ledger records, in append order. */
3757
- ledger: GateTimingRecord[];
3758
- outcome?: RetroEnvelope["outcome"];
3759
- phases?: RetroEnvelope["phases"];
3760
- refs: RetroEnvelope["refs"];
3761
- repo: RetroEnvelope["repo"];
3762
- /**
3763
- * Token families. They may be absent when native session data is unavailable
3764
- * (valid does not imply available telemetry). When present they satisfy the
3765
- * family invariants.
3766
- */
3767
- tokenFamilies?: RetroEnvelope["tokenFamilies"];
3768
- }
3769
- declare const buildRetroEnvelope: (input: BuildRetroEnvelopeInput) => RetroEnvelope;
3770
4303
  declare namespace comment_provenance_d_exports {
3771
4304
  export { SHA_MATCH_MIN_LENGTH, isBotLogin, sameHeadSha };
3772
4305
  }
@@ -3776,18 +4309,12 @@ declare const sameHeadSha: (left: string, right: string) => boolean;
3776
4309
  //#endregion
3777
4310
  //#region src/doctor-hq-checks.d.ts
3778
4311
  /**
3779
- * Two `doctor` checks that make silent HQ delivery failure loud (#394,
3780
- * epic #389 wave 2).
3781
- *
3782
- * Both consume #414's structured credential resolution rather than inventing
3783
- * a second classification: a sandboxed session that cannot reach the
3784
- * keychain is reported as "cannot resolve credentials here", never as
3785
- * "credentials are wrong" or a silent pass. Both name `psf hq:flush` and
3786
- * `psf pr:publish` as the commands that need a trusted local session.
4312
+ * The `doctor` check that makes silent HQ delivery failure loud (#394,
4313
+ * epic #389 wave 2): the local spool is empty, and no stranded evidence is
4314
+ * waiting under the spool root.
3787
4315
  *
3788
- * Advisory stays advisory: neither check can block anything but doctor's own
3789
- * exit status (epic #389 design decision 4). Absent credentials make the
3790
- * remote check a skip with a printed reason, never a silent pass.
4316
+ * Advisory stays advisory: this check can block nothing but doctor's own exit
4317
+ * status (epic #389 design decision 4).
3791
4318
  */
3792
4319
  type DoctorCheckStatus = "error" | "ok" | "warning";
3793
4320
  interface DoctorCheck {
@@ -3799,12 +4326,6 @@ interface HqSpoolCheckDependencies {
3799
4326
  countSpool?: typeof countHqSpoolWork;
3800
4327
  sweepOrphans?: typeof sweepHqSpoolOrphans;
3801
4328
  }
3802
- interface HqRetroReadbackCheckDependencies {
3803
- fetch?: typeof fetch;
3804
- readFile?: typeof readFile;
3805
- resolve?: SecretReferenceResolver;
3806
- timeoutMs?: number;
3807
- }
3808
4329
  //#endregion
3809
4330
  //#region src/doctor.d.ts
3810
4331
  interface DoctorReport {
@@ -3823,8 +4344,6 @@ interface DoctorProjectProfileInput extends LoadProjectProfileInput {
3823
4344
  base?: string;
3824
4345
  env?: NodeJS.ProcessEnv;
3825
4346
  /** Test seam for the local HQ spool check (#394); production never sets this. */
3826
- hqRetroReadbackDependencies?: HqRetroReadbackCheckDependencies;
3827
- /** Test seam for the remote HQ retro-envelope read-back check (#394). */
3828
4347
  hqSpoolDependencies?: HqSpoolCheckDependencies;
3829
4348
  /**
3830
4349
  * Append the read-only admission checklist (#292): every requirement this
@@ -3913,98 +4432,6 @@ declare const renderPrBodySections: ({
3913
4432
  reviewProof?: PrReviewProof;
3914
4433
  verifyProof?: PrVerifyProof;
3915
4434
  }) => string;
3916
- declare namespace boundary_manifest_d_exports {
3917
- export { BOUNDARY_CLOSEOUT_DEFAULT_RUNG, BOUNDARY_MANIFEST_SCHEMA_VERSION, BoundaryManifest, BoundaryManifestExtraction, BoundaryManifestParse, FACTORY_BOUNDARY_FENCE_LANG, boundaryManifestSchema, closeoutRungFor, extractBoundaryManifestBlock, manifestContentHash, parseBoundaryManifest, rungMeetsMinimum, specContentHash };
3918
- }
3919
- declare const FACTORY_BOUNDARY_FENCE_LANG = "factory-boundary";
3920
- declare const BOUNDARY_MANIFEST_SCHEMA_VERSION = 1;
3921
- declare const BOUNDARY_CLOSEOUT_DEFAULT_RUNG: EvidenceReviewRung;
3922
- declare const rungMeetsMinimum: (rung: EvidenceReviewRung, minimum: EvidenceReviewRung) => boolean;
3923
- declare const boundaryManifestBaseSchema: z.ZodObject<{
3924
- boundary: z.ZodString;
3925
- closeout: z.ZodOptional<z.ZodObject<{
3926
- review: z.ZodEnum<{
3927
- oracle: "oracle";
3928
- "independent-model": "independent-model";
3929
- human: "human";
3930
- }>;
3931
- }, z.core.$loose>>;
3932
- declaredBy: z.ZodString;
3933
- prs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
3934
- schemaVersion: z.ZodLiteral<1>;
3935
- topology: z.ZodEnum<{
3936
- flagged: "flagged";
3937
- "each-to-main": "each-to-main";
3938
- stacked: "stacked";
3939
- }>;
3940
- waves: z.ZodArray<z.ZodObject<{
3941
- autoMerge: z.ZodOptional<z.ZodBoolean>;
3942
- issues: z.ZodArray<z.ZodNumber>;
3943
- name: z.ZodString;
3944
- review: z.ZodEnum<{
3945
- oracle: "oracle";
3946
- "independent-model": "independent-model";
3947
- human: "human";
3948
- }>;
3949
- }, z.core.$loose>>;
3950
- }, z.core.$loose>;
3951
- declare const boundaryManifestSchema: z.ZodObject<{
3952
- boundary: z.ZodString;
3953
- closeout: z.ZodOptional<z.ZodObject<{
3954
- review: z.ZodEnum<{
3955
- oracle: "oracle";
3956
- "independent-model": "independent-model";
3957
- human: "human";
3958
- }>;
3959
- }, z.core.$loose>>;
3960
- declaredBy: z.ZodString;
3961
- prs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
3962
- schemaVersion: z.ZodLiteral<1>;
3963
- topology: z.ZodEnum<{
3964
- flagged: "flagged";
3965
- "each-to-main": "each-to-main";
3966
- stacked: "stacked";
3967
- }>;
3968
- waves: z.ZodArray<z.ZodObject<{
3969
- autoMerge: z.ZodOptional<z.ZodBoolean>;
3970
- issues: z.ZodArray<z.ZodNumber>;
3971
- name: z.ZodString;
3972
- review: z.ZodEnum<{
3973
- oracle: "oracle";
3974
- "independent-model": "independent-model";
3975
- human: "human";
3976
- }>;
3977
- }, z.core.$loose>>;
3978
- }, z.core.$loose>;
3979
- type BoundaryManifest = z.infer<typeof boundaryManifestBaseSchema>;
3980
- type BoundaryManifestExtraction = {
3981
- ok: true;
3982
- blockText: string;
3983
- } | {
3984
- ok: false;
3985
- error: string;
3986
- };
3987
- declare const extractBoundaryManifestBlock: (issueBody: string) => BoundaryManifestExtraction;
3988
- declare const manifestContentHash: (blockText: string) => string;
3989
- declare const specContentHash: (issueBody: string) => string;
3990
- type BoundaryManifestParse = {
3991
- ok: true;
3992
- manifest: BoundaryManifest;
3993
- manifestHash: string;
3994
- } | {
3995
- ok: false;
3996
- error: string;
3997
- };
3998
- declare const parseBoundaryManifest: (issueBody: string) => BoundaryManifestParse;
3999
- declare const closeoutRungFor: (manifest: BoundaryManifest) => EvidenceReviewRung;
4000
- //#endregion
4001
- //#region src/demand-resolution.d.ts
4002
- /** The boundary-manifest wave demand that applies to one pull request. */
4003
- interface WaveReviewDemand {
4004
- autoMerge: boolean;
4005
- review: EvidenceReviewRung;
4006
- wave: string;
4007
- }
4008
4435
  declare namespace readiness_evaluation_d_exports {
4009
4436
  export { CORRECTNESS_UNTYPED_REVIEW_BLOCKER_REASON, DRAFT_BLOCKER_REASON, EvaluationInput, ManagedReadinessLedger, PENDING_CHECKS_BLOCKER_REASON_PREFIX, READINESS_REPAIR_CODES, ReadinessRepair, ReadinessStatus, SCHEMA_VERSION, SECURITY_UNTYPED_REVIEW_BLOCKER_REASON, evaluateReadiness, managedReadinessLedgerSchema, readinessExitCode, readinessRepairSchema, validateManagedReadinessLedger };
4010
4437
  }
@@ -4031,6 +4458,13 @@ interface EvaluationInput {
4031
4458
  mergeStateStatus: string;
4032
4459
  ladderPolicy?: ReviewLadderPolicy;
4033
4460
  reviewModes?: PrReviewKind[];
4461
+ /**
4462
+ * Cross-stage policy-identity refusals resolved at the command boundary
4463
+ * (#922 Slice B), already worded. Evaluation only decides whether they are
4464
+ * in force: a recognized catch-up withdraws every review demand, so it
4465
+ * withdraws these with them.
4466
+ */
4467
+ policyIdentityRefusals?: string[];
4034
4468
  reviewProof?: PrReviewProof;
4035
4469
  verificationProof?: VerificationProofState;
4036
4470
  docsOnlyVerifyBaselineHeadShas?: string[];
@@ -4056,7 +4490,7 @@ declare const evaluateReadiness: (input: EvaluationInput) => {
4056
4490
  ledger: {
4057
4491
  baseSha: string;
4058
4492
  blockingReasons: string[];
4059
- classification: "trivial" | "docs/process-only" | "non-trivial";
4493
+ classification: "docs/process-only" | "trivial" | "non-trivial";
4060
4494
  github: {
4061
4495
  draft: boolean;
4062
4496
  mergeStateStatus: string;
@@ -4076,36 +4510,48 @@ declare const evaluateReadiness: (input: EvaluationInput) => {
4076
4510
  reviews: {
4077
4511
  correctness: {
4078
4512
  required: boolean;
4079
- status: "blocked" | "stale" | "not-required" | "current" | "missing";
4513
+ status: "not-required" | "blocked" | "current" | "stale" | "missing";
4080
4514
  reviewedHeadSha?: string | undefined;
4081
4515
  reviewedPatchId?: string | undefined;
4082
4516
  };
4083
4517
  security?: {
4084
4518
  required: boolean;
4085
- status: "blocked" | "stale" | "not-required" | "current" | "missing";
4519
+ status: "not-required" | "blocked" | "current" | "stale" | "missing";
4086
4520
  reviewedHeadSha?: string | undefined;
4087
4521
  reviewedPatchId?: string | undefined;
4088
4522
  } | undefined;
4089
4523
  };
4090
- schemaVersion: 1;
4524
+ schemaVersion: 2;
4091
4525
  verification: {
4092
4526
  command: "patronage-factory pr:verify";
4093
- prVerify: "stale" | "passed" | "missing";
4094
- docsOnlyDeltaAccepted?: boolean | undefined;
4095
- docsOnlyVerifiedHeadSha?: string | undefined;
4096
- trivialDeltaAccepted?: boolean | undefined;
4097
- trivialVerifiedHeadSha?: string | undefined;
4527
+ prVerify: "missing";
4528
+ } | {
4529
+ command: "patronage-factory pr:verify";
4530
+ prVerify: "stale";
4531
+ verifiedHeadSha: string;
4532
+ } | {
4533
+ command: "patronage-factory pr:verify";
4534
+ prVerify: "passed-via-head";
4535
+ verifiedHeadSha: string;
4536
+ } | {
4537
+ command: "patronage-factory pr:verify";
4538
+ docsOnlyVerifiedHeadSha: string;
4539
+ prVerify: "docs-only-delta";
4540
+ verifiedHeadSha?: string | undefined;
4541
+ } | {
4542
+ command: "patronage-factory pr:verify";
4543
+ prVerify: "trivial-delta";
4544
+ trivialVerifiedHeadSha: string;
4098
4545
  verifiedHeadSha?: string | undefined;
4099
4546
  };
4100
4547
  externalChecks?: {
4101
4548
  checkType: "review" | "verify";
4102
- inScope: boolean;
4103
4549
  name: string;
4104
4550
  scopeReason: string;
4105
4551
  status: "satisfied" | "unmet" | "out-of-scope";
4106
4552
  reason?: string | undefined;
4107
4553
  scope?: {
4108
- classifications: ("trivial" | "docs/process-only" | "non-trivial")[];
4554
+ classifications: ("docs/process-only" | "trivial" | "non-trivial")[];
4109
4555
  } | undefined;
4110
4556
  }[] | undefined;
4111
4557
  mergeBaseSha?: string | undefined;
@@ -4132,8 +4578,8 @@ declare const evaluateReadiness: (input: EvaluationInput) => {
4132
4578
  gate: number;
4133
4579
  interior: number;
4134
4580
  };
4135
- nextAction: "run-gate-cycle" | "accept-nonblocking-findings" | "escalate-to-triage" | "ready-for-human" | "advance-to-gate" | "run-interior-cycle";
4136
- stage: "gate" | "interior" | "interior-complete";
4581
+ nextAction: "run-interior-cycle" | "advance-to-gate" | "run-gate-cycle" | "accept-nonblocking-findings" | "escalate-to-triage" | "ready-for-human";
4582
+ stage: "interior" | "gate" | "interior-complete";
4137
4583
  forcedTransition?: "gate-cap-exhausted" | "interior-cap-reached" | undefined;
4138
4584
  } | undefined;
4139
4585
  reviewRuns?: PrReviewResult[] | undefined;
@@ -4390,12 +4836,21 @@ declare const reviewFocusFromIssueBody: (body: string) => string | undefined;
4390
4836
  interface AssembleReviewPromptInput {
4391
4837
  base: string;
4392
4838
  changedFiles: string[];
4839
+ cwd?: string;
4393
4840
  headSha: string;
4394
4841
  issueFocus?: IssueReviewFocus;
4395
4842
  kind: PrReviewKind;
4396
4843
  patchId: string;
4397
4844
  priorLedgerEntries?: FindingLedgerEntry[];
4398
4845
  profile: FactoryProjectProfile;
4846
+ waveRung?: EvidenceReviewRung;
4847
+ }
4848
+ interface AssembleReviewPromptGitDependencies {
4849
+ repositoryRoot: (cwd: string) => string;
4850
+ showFileAtRef: (cwd: string, ref: string, absolutePath: string) => string | undefined;
4851
+ }
4852
+ interface AssembleReviewPromptDependencies {
4853
+ git?: AssembleReviewPromptGitDependencies;
4399
4854
  }
4400
4855
  interface AssembledReviewPrompt {
4401
4856
  prompt: string;
@@ -4404,59 +4859,43 @@ interface AssembledReviewPrompt {
4404
4859
  declare const assembleReviewPrompt: ({
4405
4860
  base,
4406
4861
  changedFiles,
4862
+ cwd,
4407
4863
  headSha,
4408
4864
  issueFocus,
4409
4865
  kind,
4410
4866
  patchId,
4411
4867
  priorLedgerEntries,
4412
- profile
4413
- }: AssembleReviewPromptInput) => AssembledReviewPrompt;
4868
+ profile,
4869
+ waveRung
4870
+ }: AssembleReviewPromptInput, dependencies?: AssembleReviewPromptDependencies) => AssembledReviewPrompt;
4414
4871
  //#endregion
4415
- //#region src/review-ladder-trace.d.ts
4416
- interface ReviewLadderTraceIdentity {
4417
- issue?: number;
4418
- pr?: number;
4419
- repo: string;
4420
- threadId?: string;
4421
- workerId?: string;
4422
- }
4423
- interface ReviewLadderStageTraceWriteResult {
4424
- errorMessage?: string;
4425
- filePath?: string;
4426
- mirrorDiagnostics: TraceMirrorDiagnostic[];
4427
- ok: boolean;
4428
- }
4429
- declare const buildReviewLadderStageTraceEvent: ({
4430
- createdAt,
4431
- event,
4432
- headSha,
4433
- identity,
4434
- patchId
4435
- }: {
4436
- createdAt?: string;
4437
- event: ReviewLadderStageEvent;
4438
- headSha?: string;
4439
- identity: ReviewLadderTraceIdentity;
4440
- patchId?: string;
4441
- }) => FactoryTraceEvent;
4442
- declare const appendReviewLadderStageTraceEvent: ({
4443
- createdAt,
4444
- event,
4445
- headSha,
4446
- identity,
4447
- mirror,
4448
- patchId,
4449
- repoRoot
4450
- }: {
4451
- createdAt?: string;
4452
- event: ReviewLadderStageEvent;
4453
- headSha?: string;
4454
- identity: ReviewLadderTraceIdentity;
4455
- mirror?: TraceSink;
4456
- patchId?: string;
4457
- repoRoot: string;
4458
- }) => AppendFactoryTraceEventResult;
4459
- declare const tryAppendReviewLadderStageTraceEvent: (input: Parameters<typeof appendReviewLadderStageTraceEvent>[0]) => ReviewLadderStageTraceWriteResult;
4872
+ //#region src/verification-run-context.d.ts
4873
+ declare const FACTORY_BASE_REF_ENV = "FACTORY_BASE_REF";
4874
+ declare const FACTORY_CHANGED_FILES_ENV = "FACTORY_CHANGED_FILES";
4875
+ declare const FACTORY_CHANGED_FILES_FILE_ENV = "FACTORY_CHANGED_FILES_FILE";
4876
+ declare const EMPTY_TREE_OBJECT_HASH = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
4877
+ declare const DEFAULT_ROOT_SHARED_GLOBS: string[];
4878
+ interface VerificationRunContextInput {
4879
+ baseRef: string;
4880
+ changedFiles: string[];
4881
+ fullSuiteBaseRef?: string;
4882
+ rootSharedGlobs?: string[];
4883
+ inlineLimitBytes?: number;
4884
+ tmpDir?: string;
4885
+ }
4886
+ interface VerificationEnv {
4887
+ env: Record<string, string>;
4888
+ cleanup: () => void;
4889
+ }
4890
+ interface VerificationRunContext {
4891
+ readonly baseRef: string;
4892
+ readonly changedFiles: string[];
4893
+ readonly forcesFullSuite: boolean;
4894
+ readonly fullSuiteReasons: string[];
4895
+ buildEnv: () => VerificationEnv;
4896
+ runSummaryLines: () => string[];
4897
+ }
4898
+ declare function createVerificationRunContext(input: VerificationRunContextInput): VerificationRunContext;
4460
4899
  //#endregion
4461
4900
  //#region src/verification-battery.d.ts
4462
4901
  type BatteryDisposition = "executed" | "not-required";
@@ -4535,92 +4974,6 @@ declare const planVerificationBattery: <Command extends BatteryCandidateCommand>
4535
4974
  /** Console lines naming every withheld command and why. Never silent. */
4536
4975
  declare const batteryScopeSummaryLines: (plan: VerificationBatteryPlan<BatteryCandidateCommand>) => string[];
4537
4976
  //#endregion
4538
- //#region src/preview-lifecycle.d.ts
4539
- type PreviewDisposition = "deploy" | "not-required";
4540
- interface PreviewTargetPlan {
4541
- basis: string;
4542
- disposition: PreviewDisposition;
4543
- name: string;
4544
- }
4545
- interface PreviewLifecyclePlan {
4546
- /** The declared preview stacks to deploy, in declaration order. */
4547
- deploy: string[];
4548
- /** The withheld stacks, in declaration order. */
4549
- notRequired: PreviewTargetPlan[];
4550
- /** Whether a trusted, identity-bound stamp was available at all. */
4551
- stampTrusted: boolean;
4552
- /** Every declared preview target with its disposition, in declaration order. */
4553
- targets: PreviewTargetPlan[];
4554
- }
4555
- /**
4556
- * Structural subset of the profile: the impact declarations plus the external
4557
- * demand list. Structural rather than a `Pick` so this module does not import
4558
- * `profile.ts`.
4559
- */
4560
- interface PreviewLifecycleProfile {
4561
- impact?: {
4562
- targets: {
4563
- name: string;
4564
- }[];
4565
- };
4566
- requiredChecks?: {
4567
- name: string;
4568
- }[];
4569
- }
4570
- /**
4571
- * The declared preview stacks: impact targets that are ALSO declared required
4572
- * checks — i.e. targets whose proof is produced externally, which is exactly
4573
- * what a preview producer is.
4574
- *
4575
- * Deriving the list from the two existing declarations rather than adding a
4576
- * third is what makes lifecycle and demand unable to disagree: the stacks this
4577
- * plan can withhold are precisely the demands wave 2 can release, so a stack
4578
- * can never be skipped while its proof stays demanded.
4579
- */
4580
- declare const previewLifecycleTargets: (profile: PreviewLifecycleProfile) => string[];
4581
- /**
4582
- * Plan the preview lifecycle for one candidate.
4583
- *
4584
- * Trust is resolved here through the SAME identity gate demand release uses
4585
- * (`trustedImpactStamp`): the proof must have passed and must bind both the
4586
- * candidate's headSha and its patchId. A stale, aborted, absent, or
4587
- * differently-bound proof yields no stamp, and every declared stack is planned
4588
- * for deploy. Total over its INPUTS — no proof, stamp, or profile can make it
4589
- * throw. A malformed CALL is the deliberate exception: omitting
4590
- * `vetoedTargets` is API misuse, not data doubt, and throws.
4591
- */
4592
- declare const planPreviewLifecycle: ({
4593
- candidate,
4594
- profile,
4595
- proof,
4596
- vetoedTargets
4597
- }: {
4598
- candidate: {
4599
- headSha: string;
4600
- patchId: string;
4601
- };
4602
- profile: PreviewLifecycleProfile;
4603
- proof: PrVerifyProof | undefined;
4604
- /**
4605
- * Stack names with a current, candidate-bound FAILING envelope. Scoping is
4606
- * withheld for these whatever the stamp says — the same veto demand release
4607
- * applies, and for the same reason: a withheld stack is a stack that can
4608
- * never re-emit the envelope its standing demand needs. Callers hold the
4609
- * checkout context, so they resolve the set with `boundFailingCheckNames`
4610
- * and pass it in; this module stays pure.
4611
- *
4612
- * REQUIRED, with no default, on purpose: a defaulted `[]` reads the same
4613
- * whether the caller inspected the envelopes or never looked, and this seam
4614
- * exists precisely for EXTERNAL preview producers — the callers most likely
4615
- * to skip the lookup. Pass the result of `boundFailingCheckNames`; pass `[]`
4616
- * only to mean "inspected the envelopes and found no bound failure".
4617
- *
4618
- * Deliberately visible to `api:check` as a breaking signature change
4619
- * (pre-1.0, no external callers yet).
4620
- */
4621
- vetoedTargets: readonly string[];
4622
- }) => PreviewLifecyclePlan;
4623
- //#endregion
4624
4977
  //#region src/worker-checkout-guard.d.ts
4625
4978
  type CheckoutDirsProbe = (cwd: string) => {
4626
4979
  gitCommonDir: string;
@@ -4647,11 +5000,18 @@ interface CreateProgramOptions {
4647
5000
  prPublish?: PrPublishAction;
4648
5001
  prReady?: PrReadyAction;
4649
5002
  prReview?: PrReviewAction;
5003
+ prStatusHud?: PrStatusHudAction;
4650
5004
  };
4651
5005
  factoryCliInvocation?: FactoryCliInvocation;
4652
5006
  output?: CliOutput;
4653
5007
  }
4654
5008
  declare function createProgram(options?: CreateProgramOptions): Command;
4655
- declare function run(argv?: string[]): Promise<void>;
5009
+ /**
5010
+ * Parse `argv` and run the matching command. `cliEntry` is the path of the
5011
+ * runnable bin module, which follow-up commands spawn; the bin entry passes its
5012
+ * own path. This function never runs itself — `./cli.js` is the only caller
5013
+ * that does (#386).
5014
+ */
5015
+ declare function run(argv?: string[], cliEntry?: string): Promise<void>;
4656
5016
  //#endregion
4657
- export { type AppendFactoryTraceEventResult, type AssembledReviewPrompt, type BatteryCommandDisposition, type BatteryDisposition, type BoundaryCheckArgs, type BoundaryCheckDependencies, type BoundaryCheckProofRecord, type BuildEpicStructureEventInput, type BuildRetroEnvelopeInput, type CloudflareAccessServiceToken, CreateProgramOptions, DEFAULT_DEMAND_WAIVER_PATH, DEFAULT_FACTORY_REPOSITORY, type DagDocument, type DemandWaiveArgs, type DemandWaiveDependencies, DemandWaiveRefusalError, type DemandWaiver, type DemandWaiverStore, EPIC_STRUCTURE_NODE_STATUSES, EPIC_STRUCTURE_SCHEMA_VERSION, type EpicStructureEvent, type EpicStructureGraphPayload, type EpicStructureNodeStatus, EpicStructureValidationError, type EvidenceEmitArgs, type EvidenceEmitDependencies, type EvidenceEmitResult, type FactoryCliInvocation, FactoryCliInvocationSchema, type FactoryProjectProfile, type FactoryTraceDiagnostic, type FactoryTraceEnvelope, type FactoryTraceEvent, type FindingDisposition, type FindingLedgerEntry, type FollowUpAction, FollowUpActionSchema, type ImpactScopeDecision, type ImpactScopeSurface, type IssueReviewFocus, type LadderDispositionDeclaration, MERGE_FREEZE_APP_SLUG, MERGE_FREEZE_CHECK_NAME, type MergeFreezeState, type ParsedRetroEnvelope, type PrPublishArgs, type PrPublishDependencies, PrPublishFollowUpError, type PrPublishFollowUpOutcome, type PrPublishHandoff, type PrPublishResult, type PrReadyArgs, type PrReadyProof, type PreviewDisposition, type PreviewLifecyclePlan, type PreviewTargetPlan, type PublishEpicStructureArgs, type PublishEpicStructureResult, type PublishFollowUpPlan, RETRO_ENVELOPE_SCHEMA_VERSION, RETRO_ENVELOPE_VALIDATORS, REVIEW_FOCUS_SECTION, type RetroEnvelope, type ReviewGateNotRequiredProof, type ReviewGateTraceIdentity, type ReviewLadderCycle, type ReviewLadderEvaluation, type ReviewLadderPolicy, type ReviewLadderStageEvent, type ReviewLadderTraceIdentity, type ReviewPromptSection, type ReviewPromptSectionProvenance, SUPPORTED_RETRO_ENVELOPE_SCHEMA_VERSIONS, type ScanFactoryTraceDiagnosticsOptions, type ScanFactoryTraceOptions, type ScanFactoryTraceResult, type ScopedOutCommand, type TraceMirrorDiagnostic, type TraceSink, type TraceWriteResult, type TraceWriteSinks, type VerificationBatteryPlan, type VerificationReuse, type WaivedDemand, WorkerCheckoutGuardError, type WorkerCloseoutLessonsTraceEvent, appendReviewLadderStageTraceEvent, appendWithTraceSinks, applyDemandWaiver, assembleReviewPrompt, assertWorkerCheckoutAllowed, authorizeDemandWaiver, batteryScopeSummaryLines, blockingLadderFindings, boundary_manifest_d_exports as boundaryManifest, boundary_review_proof_d_exports as boundaryReviewProof, buildEpicStructureEvent, buildEpicStructurePayload, buildEvidenceEnvelope, buildRetroEnvelope, buildReviewGateNotRequiredTraceEvent, buildReviewLadderStageTraceEvent, comment_provenance_d_exports as commentProvenance, createLocalJsonlTraceSink, createProgram, doctorProjectProfile, epicStructureEventId, evaluateReviewLadder, evidenceEnvelopeFilename, findingKey, followUpFromArgv, impactStampScopeDecision, inferFixedInThreadDispositions, isProductionHqUrl, isRetroEnvelopeWireComplete, loadProjectProfile, normalizeIssueComments, openLadderFindings, parseRetroEnvelope, planPreviewLifecycle, planPublishFollowUp, planVerificationBattery, readiness_evaluation_d_exports as prReadinessEvaluation, external_evidence_d_exports as prReadinessExternalEvidence, pr_body_renderer_d_exports as prReadinessPrBodyRenderer, proof_identity_d_exports as prReadinessProofIdentity, review_proof_d_exports as prReadinessReviewProof, status_check_rollup_d_exports as prReadinessStatusChecks, verification_proof_d_exports as prReadinessVerificationProof, previewLifecycleTargets, publishEpicStructure, readDemandWaivers, readPrReadyProof, readPrReviewProof, resolveFactoryRepository, resolveFindingBlocking, resolveReviewFindingCategory, resolveReviewFindingSeverity, resolveReviewLadderPolicy, resolveTraceWriteSinks, retroEnvelopeSchemaVersionOf, retroEnvelopeV1Schema, retroEpicReference, reviewCycleStateFor, reviewFocusFromIssueBody, reviewPromptSectionSchema, reviewPromptSectionsSchema, run, runBoundaryCheck, runDemandWaive, runEvidenceEmit, runPrPublish, runPrReady, runPrReview, runPrVerify, scanFactoryTraceDiagnostics, scanFactoryTraceEvents, selectWaiversForCandidate, staleRepeatLadderFindings, toFactoryTraceEnvelope, tryAppendReviewGateNotRequiredTraceEvent, tryAppendReviewLadderStageTraceEvent, validateBoundaryCheckProof, validateDagDocument, validateDemandWaiverStore, validateFactoryTraceEvent, validateMergeFreezeState, validatePrReadyProof, validatePrReviewProof, validatePrVerifyProof, waivedDemandNotice, waivedDemandSchema, worktree_scratch_files_d_exports as worktreeScratchFiles };
5017
+ export { type AppendFactoryTraceEventResult, type AssembledReviewPrompt, type BatteryCommandDisposition, type BatteryDisposition, type BoundaryCheckArgs, type BoundaryCheckDependencies, type BoundaryCheckProofRecord, type BuildEpicStructureEventInput, type CloudflareAccessServiceToken, type CompletedFactoryCheckSnapshot, CreateProgramOptions, DEFAULT_DEMAND_WAIVER_PATH, DEFAULT_FACTORY_REPOSITORY, DEFAULT_ROOT_SHARED_GLOBS, type DagDocument, type DemandWaiveArgs, type DemandWaiveDependencies, DemandWaiveRefusalError, type DemandWaiver, type DemandWaiverStore, EMPTY_TREE_OBJECT_HASH, EPIC_STRUCTURE_NODE_STATUSES, EPIC_STRUCTURE_SCHEMA_VERSION, type EpicStructureEvent, type EpicStructureGraphPayload, type EpicStructureNodeStatus, EpicStructureValidationError, type EvidenceEmitArgs, type EvidenceEmitDependencies, type EvidenceEmitResult, FACTORY_BASE_REF_ENV, FACTORY_CHANGED_FILES_ENV, FACTORY_CHANGED_FILES_FILE_ENV, type FactoryCliInvocation, FactoryCliInvocationSchema, type FactoryPrStatusCheckName, type FactoryPrStatusSources, type FactoryProjectProfile, type FactoryTraceDiagnostic, type FactoryTraceEnvelope, type FactoryTraceEvent, type FollowUpAction, FollowUpActionSchema, type GitHubCheckRunMergeFreezeApi, type ImpactScopeDecision, type ImpactScopeSurface, type IssueReviewFocus, MERGE_FREEZE_APP_SLUG, MERGE_FREEZE_CHECK_NAME, type MergeFreezeAuthority, type MergeFreezeGeneration, type MergeFreezeState, type MergeFreezeStoreInput, type PlanFactoryPrStatusHudInput, type PrPublishArgs, type PrPublishDependencies, PrPublishFollowUpError, type PrPublishFollowUpOutcome, type PrPublishHandoff, type PrPublishResult, type PrReadyArgs, type PrReadyProof, type PrVerifyProof, type PresentFactoryPrStatusHudDependencies, type PresentFactoryPrStatusHudInput, type PreviewDisposition, type PreviewLifecyclePlan, type PreviewTargetPlan, type PublishEpicStructureArgs, type PublishEpicStructureResult, type PublishFollowUpPlan, REVIEW_FOCUS_SECTION, type ReadFactoryPrStatusSourcesDependencies, type ReadFactoryPrStatusSourcesInput, type RefreshFactoryPrStatusHudInput, type RenderFactoryPrStatusHudInput, type ReviewGateNotRequiredProof, type ReviewGateTraceIdentity, type ReviewPromptSection, type ReviewPromptSectionProvenance, type ScanFactoryTraceDiagnosticsOptions, type ScanFactoryTraceOptions, type ScanFactoryTraceResult, type ScopedOutCommand, type TraceMirrorDiagnostic, type TraceSink, type TraceWriteResult, type TraceWriteSinks, type VerificationBatteryPlan, type VerificationReuse, type VerificationRunContext, type VerificationRunContextInput, type WaivedDemand, WorkerCheckoutGuardError, type WorkerCloseoutLessonsTraceEvent, appendWithTraceSinks, applyDemandWaiver, assembleReviewPrompt, assertFactoryPrStatusIdentity, assertWorkerCheckoutAllowed, authorizeDemandWaiver, batteryScopeSummaryLines, boundary_manifest_d_exports as boundaryManifest, boundary_review_proof_d_exports as boundaryReviewProof, buildEpicStructureEvent, buildEpicStructurePayload, buildEvidenceEnvelope, buildReviewGateNotRequiredTraceEvent, comment_provenance_d_exports as commentProvenance, createGitHubCheckRunMergeFreezeStore, createLocalJsonlTraceSink, createProgram, createVerificationRunContext, doctorProjectProfile, epicStructureEventId, evidenceEnvelopeFilename, followUpFromArgv, impactStampScopeDecision, isProductionHqUrl, loadProjectProfile, normalizeIssueComments, planFactoryPrStatusHud, planPreviewLifecycle, planPublishFollowUp, planVerificationBattery, readiness_evaluation_d_exports as prReadinessEvaluation, external_evidence_d_exports as prReadinessExternalEvidence, pr_body_renderer_d_exports as prReadinessPrBodyRenderer, proof_identity_d_exports as prReadinessProofIdentity, review_proof_d_exports as prReadinessReviewProof, status_check_rollup_d_exports as prReadinessStatusChecks, verification_proof_d_exports as prReadinessVerificationProof, presentFactoryPrStatusHud, previewLifecycleTargets, publishEpicStructure, readDemandWaivers, readFactoryPrStatusSources, readPrReadyProof, refreshFactoryPrStatusHud, refreshFactoryPrStatusHudSafely, renderFactoryPrStatusHud, resolveFactoryRepository, resolveTraceWriteSinks, reviewFocusFromIssueBody, reviewPromptSectionSchema, reviewPromptSectionsSchema, run, runBoundaryCheck, runDemandWaive, runEvidenceEmit, runPrPublish, runPrReady, runPrReview, runPrVerify, scanFactoryTraceDiagnostics, scanFactoryTraceEvents, selectWaiversForCandidate, toFactoryTraceEnvelope, tryAppendReviewGateNotRequiredTraceEvent, validateBoundaryCheckProof, validateDagDocument, validateDemandWaiverStore, validateFactoryTraceEvent, validateMergeFreezeState, validatePrReadyProof, validatePrVerifyProof, validatePreviewLifecyclePlan, waivedDemandNotice, waivedDemandSchema, worktree_scratch_files_d_exports as worktreeScratchFiles };