@patronage/software-factory 1.0.0-alpha.29 → 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/README.md CHANGED
@@ -24,11 +24,13 @@ The package publishes to public npm as `@patronage/software-factory` under MIT.
24
24
 
25
25
  Internal architectural packages live under `src/packages/`. Read the package root's `README.md` before editing one. Import only entry points explicitly declared by `dependency-cruiser.config.mjs`; package implementation and fixtures are private. See ADR 0007 (`docs/adr/0007-factory-internal-deep-packages-enforce-module-seams.md` in the source repository).
26
26
 
27
+ A public export leaves this package only with a named supported-consumer account, under the criteria in that ADR's 2026-09-04 amendment. `api:check` reports declaration drift, and it passes a breaking removal through whenever the version opens a break window, so it is a notice rather than the control. The control is that amendment plus `src/public-consumer-surface.test.ts`, which names every export the audited consumers import and fails when one goes. The amendment also lists the retained surface — the exports that stay without a current importer — and the reason each group stays.
28
+
27
29
  ## Releases
28
30
 
29
- This is the release checklist. It lives here and nowhere else; the repository runbook links to it rather than restating it. Every epic or close-out sweep ends in an attended release do not let merged work accumulate untagged.
31
+ This is the release checklist. It lives here and nowhere else; the repository runbook links to it rather than restating it. Do not let merged work accumulate untagged: merged work that no release-owning boundary carries rides the next attended release.
30
32
 
31
- Releases are attended and hand-cut. Nothing in the factory publishes, tags, or releases on its own, and no step below may be automated as a drive-by.
33
+ Releases are attended and hand-cut. Nothing in the factory publishes, tags, or releases on its own, and no step below may be automated as a drive-by. Delivery closeout (`boundary:check --final`, then `factory:closeout` on the epic) is a separate act with a separate owner: it closes the epic and releases nothing. Only a release-owning boundary carries a release, and one issue at a time holds that authority for a given version. A docs-only or non-release-owning runtime boundary closes without a bump and waits for the next attended cut. The admission skill's [closeout reference](../skills/patronage-software-factory-admission/references/epic-closeout.md#delivery-closeout-is-not-a-release) states the same split from the closeout side.
32
34
 
33
35
  The factory family has one version posture (ADR 0026, `docs/adr/0026-factory-family-version-lines-move-in-lockstep.md` in the source repository): `@patronage/factory-ci` moves in lockstep majors with this CLI. From factory-ci's first release in the CLI's current series onward, majors and prerelease series move together while patch and prerelease increments stay independent per package. A consumer pins a factory-ci from the same major/prerelease series as its CLI; there is no compatibility matrix. Until that first lockstep release, factory-ci's published 0.x line is the named pre-adoption state and pairs with any CLI version. `@patronage/alchemy-d1-state` keeps independent SemVer. Lockstep is a rule the maintainer follows when cutting releases, never automation.
34
36
 
package/dist/index.d.ts CHANGED
@@ -611,8 +611,6 @@ type PolicyResolution = z.infer<typeof policyResolutionSchema>;
611
611
  type ReviewFindingSeverity = "critical" | "high" | "medium" | "low" | "unknown";
612
612
  type ReviewFindingCategory = "correctness" | "safety" | "coordination" | "maintainability" | "unknown";
613
613
  declare const REVIEW_SEVERITIES: readonly ["critical", "high", "medium", "low", "unknown"];
614
- declare const resolveReviewFindingSeverity: (priority?: string) => ReviewFindingSeverity;
615
- declare const resolveReviewFindingCategory: (category?: string) => ReviewFindingCategory;
616
614
  declare const FINDING_DISPOSITIONS: readonly ["open", "fixed-in-thread", "follow-up-filed", "waived", "stale-repeat", "rerun-noise"];
617
615
  type FindingDisposition = (typeof FINDING_DISPOSITIONS)[number];
618
616
  interface ReviewFindingAttributes {
@@ -628,17 +626,11 @@ interface ReviewFindingAttributes {
628
626
  };
629
627
  title: string;
630
628
  }
631
- type BlockingResolvableFinding = Pick<ReviewFindingAttributes, "blockingAfterCap" | "category" | "priority">;
632
- declare const resolveFindingBlocking: (finding: BlockingResolvableFinding, disposition?: FindingDisposition) => boolean;
633
629
  interface ReviewLadderPolicy {
634
630
  gate: {
635
631
  cap: number;
636
632
  };
637
- interior: {
638
- cap: number;
639
- };
640
633
  }
641
- declare const resolveReviewLadderPolicy: () => ReviewLadderPolicy;
642
634
  //#endregion
643
635
  //#region src/review-ladder-ledger.d.ts
644
636
  type LadderCycleStage = "interior" | "gate";
@@ -668,18 +660,6 @@ interface FindingLedgerEntry extends ReviewFindingAttributes {
668
660
  reopenedCount: number;
669
661
  staleRepeatCount: number;
670
662
  }
671
- declare const findingKey: (finding: {
672
- citedSpan?: string;
673
- file?: string;
674
- prescribedAction?: string;
675
- title?: string;
676
- }) => string;
677
- declare const openLadderFindings: (ledger: FindingLedgerEntry[]) => FindingLedgerEntry[];
678
- declare const blockingLadderFindings: (ledger: FindingLedgerEntry[]) => FindingLedgerEntry[];
679
- declare const staleRepeatLadderFindings: (ledger: FindingLedgerEntry[]) => FindingLedgerEntry[];
680
- declare const inferFixedInThreadDispositions: (ledger: FindingLedgerEntry[], findings: readonly LadderFindingReport[], options?: {
681
- sameHeadAsPriorCycle?: boolean;
682
- }) => LadderDispositionDeclaration[];
683
663
  //#endregion
684
664
  //#region src/review-ladder.d.ts
685
665
  type ReviewLadderExecutedStage = "interior" | "gate";
@@ -709,47 +689,29 @@ interface ReviewLadderCycle {
709
689
  stage: LadderCycleStage;
710
690
  usage?: LadderUsageReport;
711
691
  }
712
- interface LadderInteriorCapTransition {
713
- cap: number;
714
- kind: "interior-cap-reached";
715
- }
716
- interface LadderGateCapTransition {
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 {
717
696
  blockingFindings: string[];
718
697
  cap: number;
719
- kind: "gate-cap-exhausted";
698
+ kind: Extract<LadderForcedTransitionKind, "gate-cap-exhausted">;
720
699
  }
721
- type LadderForcedTransition = LadderGateCapTransition | LadderInteriorCapTransition;
722
- interface LadderRunInteriorCycleAction {
700
+ type LadderNextAction = {
723
701
  cycle: number;
724
- kind: "run-interior-cycle";
725
- }
726
- type LadderGateNextAction = {
727
- cycle: number;
728
- kind: "run-gate-cycle";
729
- } | {
730
- kind: "accept-nonblocking-findings";
731
- } | {
732
- kind: "escalate-to-triage";
702
+ kind: Extract<LadderNextActionKind, "run-gate-cycle">;
733
703
  } | {
734
- kind: "ready-for-human";
735
- };
736
- type LadderPosition = {
737
- forcedTransition?: LadderGateCapTransition;
738
- nextAction: LadderGateNextAction;
739
- stage: "gate";
704
+ kind: Extract<LadderNextActionKind, "accept-nonblocking-findings">;
740
705
  } | {
741
- forcedTransition?: LadderInteriorCapTransition;
742
- nextAction: {
743
- kind: "advance-to-gate";
744
- };
745
- stage: "interior-complete";
706
+ kind: Extract<LadderNextActionKind, "escalate-to-triage">;
746
707
  } | {
747
- forcedTransition?: never;
748
- nextAction: LadderRunInteriorCycleAction;
749
- stage: "interior";
708
+ kind: Extract<LadderNextActionKind, "ready-for-human">;
750
709
  };
751
- type LadderNextAction = LadderPosition["nextAction"];
752
- type ReviewLadderStage = LadderPosition["stage"];
710
+ interface LadderPosition {
711
+ forcedTransition?: LadderForcedTransition;
712
+ nextAction: LadderNextAction;
713
+ stage: Extract<ReviewLadderStage, "gate">;
714
+ }
753
715
  interface ReviewLadderStageEvent {
754
716
  cycle: number;
755
717
  cyclesToClean?: number;
@@ -769,28 +731,15 @@ interface ReviewLadderStageEvent {
769
731
  type: "review-ladder-stage";
770
732
  usage?: LadderUsageReport;
771
733
  }
772
- interface LadderDiagnostic {
773
- code: "interior-cycles-unrecorded";
774
- message: string;
775
- }
776
734
  type ReviewLadderEvaluation = LadderPosition & {
777
735
  cycleCounts: {
778
736
  gate: number;
779
737
  interior: number;
780
738
  };
781
- diagnostics: LadderDiagnostic[];
782
739
  event?: ReviewLadderStageEvent;
783
740
  ledger: FindingLedgerEntry[];
784
741
  unmatchedDispositions: LadderDispositionDeclaration[];
785
742
  };
786
- interface EvaluateReviewLadderInput {
787
- cycles: ReviewLadderCycle[];
788
- policy: ReviewLadderPolicy;
789
- }
790
- declare const evaluateReviewLadder: ({
791
- cycles,
792
- policy
793
- }: EvaluateReviewLadderInput) => ReviewLadderEvaluation;
794
743
  //#endregion
795
744
  //#region src/pr-readiness/ladder-proof-state.d.ts
796
745
  interface PrReviewLadderState {
@@ -807,8 +756,8 @@ interface ReviewLadderSummaryState {
807
756
  gate: number;
808
757
  interior: number;
809
758
  };
810
- forcedTransition?: LadderForcedTransition["kind"];
811
- nextAction: LadderNextAction["kind"];
759
+ forcedTransition?: LadderForcedTransitionKind;
760
+ nextAction: LadderNextActionKind;
812
761
  stage: ReviewLadderStage;
813
762
  }
814
763
  interface ReviewLadderSnapshot {
@@ -1360,8 +1309,8 @@ declare const mergeFreezeStateSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
1360
1309
  generationId: z.ZodNumber;
1361
1310
  headSha: z.ZodString;
1362
1311
  outcome: z.ZodEnum<{
1363
- active: "active";
1364
1312
  stale: "stale";
1313
+ active: "active";
1365
1314
  }>;
1366
1315
  reason: z.ZodString;
1367
1316
  recordedAt: z.ZodISODateTime;
@@ -1583,12 +1532,12 @@ declare const managedReadinessLedgerSchema: z.ZodObject<{
1583
1532
  "interior-cap-reached": "interior-cap-reached";
1584
1533
  }>>;
1585
1534
  nextAction: z.ZodEnum<{
1535
+ "run-interior-cycle": "run-interior-cycle";
1536
+ "advance-to-gate": "advance-to-gate";
1586
1537
  "run-gate-cycle": "run-gate-cycle";
1587
1538
  "accept-nonblocking-findings": "accept-nonblocking-findings";
1588
1539
  "escalate-to-triage": "escalate-to-triage";
1589
1540
  "ready-for-human": "ready-for-human";
1590
- "advance-to-gate": "advance-to-gate";
1591
- "run-interior-cycle": "run-interior-cycle";
1592
1541
  }>;
1593
1542
  stage: z.ZodEnum<{
1594
1543
  interior: "interior";
@@ -1609,9 +1558,9 @@ declare const managedReadinessLedgerSchema: z.ZodObject<{
1609
1558
  reviewedPatchId: z.ZodOptional<z.ZodString>;
1610
1559
  status: z.ZodEnum<{
1611
1560
  "not-required": "not-required";
1612
- stale: "stale";
1613
1561
  blocked: "blocked";
1614
1562
  current: "current";
1563
+ stale: "stale";
1615
1564
  missing: "missing";
1616
1565
  }>;
1617
1566
  }, z.core.$strip>;
@@ -1621,9 +1570,9 @@ declare const managedReadinessLedgerSchema: z.ZodObject<{
1621
1570
  reviewedPatchId: z.ZodOptional<z.ZodString>;
1622
1571
  status: z.ZodEnum<{
1623
1572
  "not-required": "not-required";
1624
- stale: "stale";
1625
1573
  blocked: "blocked";
1626
1574
  current: "current";
1575
+ stale: "stale";
1627
1576
  missing: "missing";
1628
1577
  }>;
1629
1578
  }, z.core.$strip>>;
@@ -2732,9 +2681,9 @@ declare const loadEvidenceEnvelopes: (cwd: string) => LoadedEvidenceEnvelope[];
2732
2681
  declare const REVIEW_STATUS_VALUES: readonly ["not-required", "current", "stale", "missing", "blocked"];
2733
2682
  declare const reviewStatusSchema: z.ZodEnum<{
2734
2683
  "not-required": "not-required";
2735
- stale: "stale";
2736
2684
  blocked: "blocked";
2737
2685
  current: "current";
2686
+ stale: "stale";
2738
2687
  missing: "missing";
2739
2688
  }>;
2740
2689
  type ReviewStatus = z.infer<typeof reviewStatusSchema>;
@@ -2818,7 +2767,7 @@ declare const reviewProofFor: (proof: PrReviewProof | undefined, kind: PrReviewK
2818
2767
  patchId: string;
2819
2768
  }) => ReviewProofClaim;
2820
2769
  declare namespace review_proof_d_exports {
2821
- 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 };
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 };
2822
2771
  }
2823
2772
  declare const PR_REVIEW_SCHEMA_VERSION = 2;
2824
2773
  declare const PR_REVIEW_FINDING_PROVENANCE_VERSION = 1;
@@ -2830,7 +2779,6 @@ declare const prReviewResultSchema: z.ZodType<PrReviewResult>;
2830
2779
  declare const prReviewProofSchema: z.ZodType<PrReviewProof>;
2831
2780
  declare const validatePrReviewResult: (value: unknown) => PrReviewResult;
2832
2781
  declare const validatePrReviewProof: (value: unknown) => PrReviewProof;
2833
- declare const readPrReviewProof: (filePath: string) => PrReviewProof;
2834
2782
  declare const PR_REVIEW_PROOF_DESCRIPTOR: ProofDescriptor<PrReviewProof>;
2835
2783
  //#endregion
2836
2784
  //#region src/schemas.d.ts
@@ -3986,8 +3934,8 @@ declare const FACTORY_TRACE_EVENT_DEFINITIONS: readonly [DefinedTraceEvent<"revi
3986
3934
  interiorCycle: z.ZodOptional<z.ZodNumber>;
3987
3935
  observedAt: z.ZodString;
3988
3936
  purpose: z.ZodEnum<{
3989
- code: "code";
3990
3937
  review: "review";
3938
+ code: "code";
3991
3939
  }>;
3992
3940
  slotResolution: z.ZodObject<{
3993
3941
  effort: z.ZodEnum<{
@@ -4065,8 +4013,8 @@ declare const FACTORY_TRACE_EVENT_DEFINITIONS: readonly [DefinedTraceEvent<"revi
4065
4013
  interiorCycle: z.ZodOptional<z.ZodNumber>;
4066
4014
  observedAt: z.ZodString;
4067
4015
  purpose: z.ZodEnum<{
4068
- code: "code";
4069
4016
  review: "review";
4017
+ code: "code";
4070
4018
  }>;
4071
4019
  slotResolution: z.ZodObject<{
4072
4020
  effort: z.ZodEnum<{
@@ -4135,8 +4083,8 @@ declare const FACTORY_TRACE_EVENT_DEFINITIONS: readonly [DefinedTraceEvent<"revi
4135
4083
  interiorCycle: z.ZodOptional<z.ZodNumber>;
4136
4084
  observedAt: z.ZodString;
4137
4085
  purpose: z.ZodEnum<{
4138
- code: "code";
4139
4086
  review: "review";
4087
+ code: "code";
4140
4088
  }>;
4141
4089
  slotResolution: z.ZodObject<{
4142
4090
  effort: z.ZodEnum<{
@@ -4208,7 +4156,7 @@ declare const FACTORY_TRACE_EVENT_DEFINITIONS: readonly [DefinedTraceEvent<"revi
4208
4156
  exitCode: number | null;
4209
4157
  harness: string;
4210
4158
  observedAt: string;
4211
- purpose: "code" | "review";
4159
+ purpose: "review" | "code";
4212
4160
  slotResolution: {
4213
4161
  effort: "high" | "low" | "medium" | "xhigh";
4214
4162
  engine: string;
@@ -4562,13 +4510,13 @@ declare const evaluateReadiness: (input: EvaluationInput) => {
4562
4510
  reviews: {
4563
4511
  correctness: {
4564
4512
  required: boolean;
4565
- status: "not-required" | "stale" | "blocked" | "current" | "missing";
4513
+ status: "not-required" | "blocked" | "current" | "stale" | "missing";
4566
4514
  reviewedHeadSha?: string | undefined;
4567
4515
  reviewedPatchId?: string | undefined;
4568
4516
  };
4569
4517
  security?: {
4570
4518
  required: boolean;
4571
- status: "not-required" | "stale" | "blocked" | "current" | "missing";
4519
+ status: "not-required" | "blocked" | "current" | "stale" | "missing";
4572
4520
  reviewedHeadSha?: string | undefined;
4573
4521
  reviewedPatchId?: string | undefined;
4574
4522
  } | undefined;
@@ -4630,7 +4578,7 @@ declare const evaluateReadiness: (input: EvaluationInput) => {
4630
4578
  gate: number;
4631
4579
  interior: number;
4632
4580
  };
4633
- nextAction: "run-gate-cycle" | "accept-nonblocking-findings" | "escalate-to-triage" | "ready-for-human" | "advance-to-gate" | "run-interior-cycle";
4581
+ nextAction: "run-interior-cycle" | "advance-to-gate" | "run-gate-cycle" | "accept-nonblocking-findings" | "escalate-to-triage" | "ready-for-human";
4634
4582
  stage: "interior" | "gate" | "interior-complete";
4635
4583
  forcedTransition?: "gate-cap-exhausted" | "interior-cap-reached" | undefined;
4636
4584
  } | undefined;
@@ -4921,52 +4869,6 @@ declare const assembleReviewPrompt: ({
4921
4869
  waveRung
4922
4870
  }: AssembleReviewPromptInput, dependencies?: AssembleReviewPromptDependencies) => AssembledReviewPrompt;
4923
4871
  //#endregion
4924
- //#region src/review-ladder-trace.d.ts
4925
- interface ReviewLadderTraceIdentity {
4926
- issue?: number;
4927
- pr?: number;
4928
- repo: string;
4929
- threadId?: string;
4930
- workerId?: string;
4931
- }
4932
- interface ReviewLadderStageTraceWriteResult {
4933
- errorMessage?: string;
4934
- filePath?: string;
4935
- mirrorDiagnostics: TraceMirrorDiagnostic[];
4936
- ok: boolean;
4937
- }
4938
- declare const buildReviewLadderStageTraceEvent: ({
4939
- createdAt,
4940
- event,
4941
- headSha,
4942
- identity,
4943
- patchId
4944
- }: {
4945
- createdAt?: string;
4946
- event: ReviewLadderStageEvent;
4947
- headSha?: string;
4948
- identity: ReviewLadderTraceIdentity;
4949
- patchId?: string;
4950
- }) => FactoryTraceEvent;
4951
- declare const appendReviewLadderStageTraceEvent: ({
4952
- createdAt,
4953
- event,
4954
- headSha,
4955
- identity,
4956
- mirror,
4957
- patchId,
4958
- repoRoot
4959
- }: {
4960
- createdAt?: string;
4961
- event: ReviewLadderStageEvent;
4962
- headSha?: string;
4963
- identity: ReviewLadderTraceIdentity;
4964
- mirror?: TraceSink;
4965
- patchId?: string;
4966
- repoRoot: string;
4967
- }) => AppendFactoryTraceEventResult;
4968
- declare const tryAppendReviewLadderStageTraceEvent: (input: Parameters<typeof appendReviewLadderStageTraceEvent>[0]) => ReviewLadderStageTraceWriteResult;
4969
- //#endregion
4970
4872
  //#region src/verification-run-context.d.ts
4971
4873
  declare const FACTORY_BASE_REF_ENV = "FACTORY_BASE_REF";
4972
4874
  declare const FACTORY_CHANGED_FILES_ENV = "FACTORY_CHANGED_FILES";
@@ -5112,4 +5014,4 @@ declare function createProgram(options?: CreateProgramOptions): Command;
5112
5014
  */
5113
5015
  declare function run(argv?: string[], cliEntry?: string): Promise<void>;
5114
5016
  //#endregion
5115
- 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 FindingDisposition, type FindingLedgerEntry, type FollowUpAction, FollowUpActionSchema, type GitHubCheckRunMergeFreezeApi, type ImpactScopeDecision, type ImpactScopeSurface, type IssueReviewFocus, type LadderDispositionDeclaration, 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 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 ReviewLadderCycle, type ReviewLadderEvaluation, type ReviewLadderPolicy, type ReviewLadderStageEvent, type ReviewLadderTraceIdentity, 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, appendReviewLadderStageTraceEvent, appendWithTraceSinks, applyDemandWaiver, assembleReviewPrompt, assertFactoryPrStatusIdentity, assertWorkerCheckoutAllowed, authorizeDemandWaiver, batteryScopeSummaryLines, blockingLadderFindings, boundary_manifest_d_exports as boundaryManifest, boundary_review_proof_d_exports as boundaryReviewProof, buildEpicStructureEvent, buildEpicStructurePayload, buildEvidenceEnvelope, buildReviewGateNotRequiredTraceEvent, buildReviewLadderStageTraceEvent, comment_provenance_d_exports as commentProvenance, createGitHubCheckRunMergeFreezeStore, createLocalJsonlTraceSink, createProgram, createVerificationRunContext, doctorProjectProfile, epicStructureEventId, evaluateReviewLadder, evidenceEnvelopeFilename, findingKey, followUpFromArgv, impactStampScopeDecision, inferFixedInThreadDispositions, isProductionHqUrl, loadProjectProfile, normalizeIssueComments, openLadderFindings, 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, readPrReviewProof, refreshFactoryPrStatusHud, refreshFactoryPrStatusHudSafely, renderFactoryPrStatusHud, resolveFactoryRepository, resolveFindingBlocking, resolveReviewFindingCategory, resolveReviewFindingSeverity, resolveReviewLadderPolicy, resolveTraceWriteSinks, 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, validatePreviewLifecyclePlan, 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 };
package/dist/index.js CHANGED
@@ -18,7 +18,7 @@ import { FACTORY_APP_BROKER_ORIGIN, FACTORY_APP_BROKER_PATH, FACTORY_CURSOR_OIDC
18
18
  import http from "node:http";
19
19
  import { pathToFileURL } from "node:url";
20
20
  //#region package.json
21
- var version = "1.0.0-alpha.29";
21
+ var version = "1.0.0-alpha.30";
22
22
  //#endregion
23
23
  //#region src/cli-entry.ts
24
24
  /**
@@ -1694,6 +1694,24 @@ function assertCleanWorktreeForProof({ changedFiles, cwd, dirtyMessage, statusPo
1694
1694
  if (offendingLines.length > 0) throw new Error(`${dirtyMessage}\n${offendingLines.join("\n")}`);
1695
1695
  }
1696
1696
  //#endregion
1697
+ //#region src/battery-shell-command.ts
1698
+ /** Quotes one argument for a POSIX shell, including embedded single quotes. */
1699
+ function singleQuote(value) {
1700
+ return `'${value.replaceAll("'", String.raw`'\''`)}'`;
1701
+ }
1702
+ /**
1703
+ * Wraps a verification command so a login shell cannot demote the Node the
1704
+ * factory CLI is running on.
1705
+ *
1706
+ * `nodeBinDir` is the directory holding the running Node executable, so the
1707
+ * battery and the CLI always agree. The prefix is a separate line rather than a
1708
+ * `;` join: the command is profile-authored text that may already contain `&&`,
1709
+ * `;`, or a trailing comment, and a newline composes with all three.
1710
+ */
1711
+ function withPinnedNodeOnPath(command, nodeBinDir) {
1712
+ return `export PATH=${singleQuote(nodeBinDir)}:"$PATH"\n${command}`;
1713
+ }
1714
+ //#endregion
1697
1715
  //#region src/candidate-identity.ts
1698
1716
  /**
1699
1717
  * The same fallback for a patch id taken at an explicit ref rather than at
@@ -2459,12 +2477,8 @@ const resolveFindingBlocking = (finding, disposition = "open") => {
2459
2477
  const severity = resolveReviewFindingSeverity(finding.priority);
2460
2478
  return severity === "critical" || severity === "high" || severity === "unknown";
2461
2479
  };
2462
- const DEFAULT_INTERIOR_REVIEW_CAP = 0;
2463
2480
  const FACTORY_REVIEW_CYCLE_CAP = 5;
2464
- const resolveReviewLadderPolicy = () => ({
2465
- gate: { cap: FACTORY_REVIEW_CYCLE_CAP },
2466
- interior: { cap: DEFAULT_INTERIOR_REVIEW_CAP }
2467
- });
2481
+ const resolveReviewLadderPolicy = () => ({ gate: { cap: FACTORY_REVIEW_CYCLE_CAP } });
2468
2482
  //#endregion
2469
2483
  //#region src/sha256-hex.ts
2470
2484
  const ROUND_CONSTANTS = new Uint32Array([
@@ -3879,7 +3893,7 @@ const validatedIngestEndpoint = (value) => {
3879
3893
  const origin = validatedEndpoint(value);
3880
3894
  return origin === void 0 ? void 0 : new URL(HQ_INGEST_PATH, origin.origin);
3881
3895
  };
3882
- const retainRetryEntry = async (layout, entry, dependencies, deadline, options = {}) => {
3896
+ const retainRetryEntry = async (layout, entry, dependencies, deadline) => {
3883
3897
  let customAppend;
3884
3898
  try {
3885
3899
  customAppend = dependencies.appendJournal;
@@ -3894,17 +3908,11 @@ const retainRetryEntry = async (layout, entry, dependencies, deadline, options =
3894
3908
  return "failed";
3895
3909
  }
3896
3910
  const target = path.join(path.resolve(layout.root, ...layout.segments), `${randomUUID()}-${spoolFileName(entry)}`);
3897
- if (options.awaitCustom !== true) {
3898
- setImmediate(async () => {
3899
- try {
3900
- await customAppend(target, row);
3901
- } catch {}
3902
- }).unref();
3903
- return;
3904
- }
3905
- const outcome = await settleWithin((async () => customAppend(target, row))(), remainingMs(deadline));
3906
- if (outcome.status === "fulfilled") return;
3907
- return outcome.status === "timed-out" ? "timed-out" : "failed";
3911
+ setImmediate(async () => {
3912
+ try {
3913
+ await customAppend(target, row);
3914
+ } catch {}
3915
+ }).unref();
3908
3916
  };
3909
3917
  const projectInputForHqIngest = async (input, deadline) => {
3910
3918
  let profilePath;
@@ -3927,94 +3935,6 @@ const projectInputForHqIngest = async (input, deadline) => {
3927
3935
  ...input.subject === void 0 ? {} : { subject: input.subject }
3928
3936
  };
3929
3937
  };
3930
- async function handoffHqIngest(input, dependencies, setupDeadline) {
3931
- let config;
3932
- try {
3933
- if (!input.profile.hq?.enabled) return "skipped";
3934
- config = input.profile.hq;
3935
- } catch {
3936
- return "skipped";
3937
- }
3938
- const endpoint = validatedIngestEndpoint(config.endpoint);
3939
- if (!endpoint) {
3940
- await reportDiagnostic(dependencies, setupDeadline, "profile endpoint must be an HTTPS origin without embedded credentials", "HQ ingest skipped");
3941
- return "skipped";
3942
- }
3943
- let env;
3944
- try {
3945
- env = dependencies.env ?? process.env;
3946
- } catch {
3947
- await reportDiagnostic(dependencies, setupDeadline, "operator configuration is unavailable", "HQ ingest skipped");
3948
- return "skipped";
3949
- }
3950
- if (!(await loadAllowedOrigins(env, setupDeadline)).includes(endpoint.origin)) {
3951
- await reportDiagnostic(dependencies, setupDeadline, `endpoint origin ${endpoint.origin} is not authorized by hqAllowedOrigins in the operator user config`, "HQ ingest skipped");
3952
- return "skipped";
3953
- }
3954
- const flushDeadline = performance.now() + journalFlushBudgetFor(dependencies);
3955
- const now = dependencies.now ?? (() => /* @__PURE__ */ new Date());
3956
- const makeEventId = dependencies.randomUUID ?? randomUUID;
3957
- let event;
3958
- let dropped = false;
3959
- let reason = "closeout-advisory-handoff";
3960
- try {
3961
- const projectedPayload = await loadBoundedPayload(input, setupDeadline);
3962
- const eventId = makeEventId();
3963
- const observedAt = now().toISOString();
3964
- const repository = {
3965
- owner: input.profile.repository.owner,
3966
- repo: input.profile.repository.name
3967
- };
3968
- if (projectedPayload.status === "dropped") {
3969
- dropped = true;
3970
- const { reason: projectionReason } = projectedPayload;
3971
- reason = projectionReason;
3972
- const subject = inferredSubject(input, {});
3973
- event = {
3974
- eventId,
3975
- kind: input.kind,
3976
- observedAt,
3977
- repository,
3978
- schemaVersion: 1,
3979
- ...subject === void 0 ? {} : { subject }
3980
- };
3981
- } else {
3982
- const subject = inferredSubject(input, projectedPayload.value);
3983
- event = {
3984
- eventId,
3985
- kind: input.kind,
3986
- observedAt,
3987
- payload: projectedPayload.value,
3988
- repository,
3989
- schemaVersion: projectedPayload.value.schemaVersion,
3990
- ...subject === void 0 ? {} : { subject }
3991
- };
3992
- }
3993
- } catch {
3994
- await reportDiagnostic(dependencies, flushDeadline, "closeout advisory handoff could not construct an event");
3995
- return "held";
3996
- }
3997
- if (dropped || event === void 0) return "held";
3998
- let failedAt;
3999
- try {
4000
- failedAt = now().toISOString();
4001
- } catch {
4002
- failedAt = "unknown";
4003
- }
4004
- const retryEntry = {
4005
- endpoint: endpoint.href,
4006
- event,
4007
- failedAt,
4008
- reason
4009
- };
4010
- const writeLayout = repositorySpoolLayout({
4011
- owner: input.profile.repository.owner,
4012
- repo: input.profile.repository.name
4013
- }, env);
4014
- const journalFailure = dependencies.appendJournal === void 0 ? await appendCloseoutSpool(writeLayout, retryEntry, flushDeadline) : await retainRetryEntry(writeLayout, retryEntry, dependencies, flushDeadline, { awaitCustom: true });
4015
- if (journalFailure) await reportDiagnostic(dependencies, flushDeadline, `closeout advisory handoff local spool ${journalFailure}`);
4016
- return journalFailure === void 0 && !dropped ? "deferred" : "held";
4017
- }
4018
3938
  /**
4019
3939
  * A bounded read of the ingest receipt body. Only the explicit drain asks for
4020
3940
  * it: the gate path must not add a body read to its transport leg. Nothing but
@@ -4767,28 +4687,6 @@ function enqueueProjectHqIngest(input, dependencies = {}) {
4767
4687
  return Promise.resolve("skipped");
4768
4688
  }
4769
4689
  }
4770
- /**
4771
- * Persists an advisory closeout event for a later normal HQ sink drain. Unlike
4772
- * enqueueProjectHqIngest, this never starts a network request or enters the
4773
- * process-exit lifecycle registry, so local closeout cannot wait on HQ.
4774
- */
4775
- async function deferProjectHqIngestDirect(input, dependencies) {
4776
- try {
4777
- const setupDeadline = performance.now() + timeoutFor(dependencies);
4778
- const projectInput = await projectInputForHqIngest(input, setupDeadline);
4779
- if (projectInput === void 0) return "skipped";
4780
- return await handoffHqIngest(projectInput, dependencies, setupDeadline);
4781
- } catch {
4782
- return "held";
4783
- }
4784
- }
4785
- const hasCloseoutHandoffCustomization = (dependencies) => {
4786
- try {
4787
- return Reflect.ownKeys(dependencies).length > 0;
4788
- } catch {
4789
- return true;
4790
- }
4791
- };
4792
4690
  const ISOLATED_CLOSEOUT_FS_WORKER_SOURCE = String.raw`
4793
4691
  const crypto = require("node:crypto");
4794
4692
  const fs = require("node:fs");
@@ -5045,8 +4943,8 @@ const runCloseoutFsWorker = async (data, budgetMs) => {
5045
4943
  });
5046
4944
  };
5047
4945
  const isIsolatedReadResult = (value) => value !== null && typeof value === "object" && value.status === "read";
5048
- const deferProjectHqIngestIsolated = async (input) => {
5049
- const setupDeadline = performance.now() + timeoutFor({ env: process.env });
4946
+ const deferProjectHqIngestIsolated = async (input, env) => {
4947
+ const setupDeadline = performance.now() + timeoutFor({ env });
5050
4948
  let profilePath;
5051
4949
  try {
5052
4950
  profilePath = input.profilePath ? path.resolve(input.cwd, input.profilePath) : defaultProfilePath(input.cwd);
@@ -5071,7 +4969,7 @@ const deferProjectHqIngestIsolated = async (input) => {
5071
4969
  let configPath;
5072
4970
  let payloadPath;
5073
4971
  try {
5074
- configPath = defaultUserConfigPath(process.env);
4972
+ configPath = defaultUserConfigPath(env);
5075
4973
  payloadPath = input.payloadJson === void 0 && input.payloadPath !== void 0 ? path.resolve(input.cwd, input.payloadPath) : void 0;
5076
4974
  } catch {
5077
4975
  return "skipped";
@@ -5131,19 +5029,34 @@ const deferProjectHqIngestIsolated = async (input) => {
5131
5029
  const layout = repositorySpoolLayout({
5132
5030
  owner: parsedProfile.repository.owner,
5133
5031
  repo: parsedProfile.repository.name
5134
- }, process.env);
5032
+ }, env);
5135
5033
  const persisted = await runCloseoutFsWorker({
5136
5034
  body,
5137
5035
  eventId,
5138
5036
  root: layout.root,
5139
5037
  segments: layout.segments,
5140
5038
  type: "persist"
5141
- }, journalFlushBudgetFor({ env: process.env }));
5039
+ }, journalFlushBudgetFor({ env }));
5142
5040
  return persisted !== null && typeof persisted === "object" && persisted.status === "persisted" ? "deferred" : "held";
5143
5041
  };
5042
+ /**
5043
+ * Persists an advisory closeout event for a later normal HQ sink drain. Unlike
5044
+ * enqueueProjectHqIngest, this never starts a network request or enters the
5045
+ * process-exit lifecycle registry, so local closeout cannot wait on HQ.
5046
+ *
5047
+ * There is one persistence implementation and it always runs in an unreferenced
5048
+ * worker, so no caller can select a main-thread variant whose durability and
5049
+ * confinement guarantees are proved separately. The only seam is the operator
5050
+ * environment the worker's budgets and spool location are read from.
5051
+ */
5144
5052
  async function deferProjectHqIngest(input, dependencies = {}) {
5145
- if (!hasCloseoutHandoffCustomization(dependencies)) return deferProjectHqIngestIsolated(input);
5146
- return deferProjectHqIngestDirect(input, dependencies);
5053
+ let env;
5054
+ try {
5055
+ env = dependencies.env ?? process.env;
5056
+ } catch {
5057
+ return "skipped";
5058
+ }
5059
+ return deferProjectHqIngestIsolated(input, env);
5147
5060
  }
5148
5061
  //#endregion
5149
5062
  //#region src/evidence-freshness.ts
@@ -8204,7 +8117,7 @@ function defaultPrVerifyGit() {
8204
8117
  mergeBaseSha,
8205
8118
  recognizeCatchUp: recognizeCatchUpCandidate,
8206
8119
  runVerificationCommand(command, cwd, env) {
8207
- return verificationOutcomeOf(runInheritedTee("bash", ["-lc", command], cwd, env));
8120
+ return verificationOutcomeOf(runInheritedTee("bash", ["-lc", withPinnedNodeOnPath(command, path.dirname(process.execPath))], cwd, env));
8208
8121
  },
8209
8122
  showFileAtRef,
8210
8123
  stablePatchId: runStablePatchId,
@@ -9024,29 +8937,7 @@ const ladderCycleRefsFor = (cycles) => {
9024
8937
  };
9025
8938
  });
9026
8939
  };
9027
- const interiorPosition = ({ interiorCount, openFindings, policy }) => {
9028
- const { cap } = policy.interior;
9029
- if (interiorCount > 0 && openFindings.length === 0) return {
9030
- nextAction: { kind: "advance-to-gate" },
9031
- stage: "interior-complete"
9032
- };
9033
- if (interiorCount >= cap) return {
9034
- forcedTransition: {
9035
- cap,
9036
- kind: "interior-cap-reached"
9037
- },
9038
- nextAction: { kind: "advance-to-gate" },
9039
- stage: "interior-complete"
9040
- };
9041
- return {
9042
- nextAction: {
9043
- cycle: interiorCount + 1,
9044
- kind: "run-interior-cycle"
9045
- },
9046
- stage: "interior"
9047
- };
9048
- };
9049
- const gatePosition = ({ blockingFindings, gateCount, openFindings, policy }) => {
8940
+ const resolveLadderPosition = ({ blockingFindings, gateCount, openFindings, policy }) => {
9050
8941
  const { cap } = policy.gate;
9051
8942
  if (gateCount === 0) return {
9052
8943
  nextAction: {
@@ -9080,21 +8971,11 @@ const gatePosition = ({ blockingFindings, gateCount, openFindings, policy }) =>
9080
8971
  stage: "gate"
9081
8972
  };
9082
8973
  };
9083
- const resolveLadderPosition = ({ blockingFindings, gateCount, interiorCount, openFindings, policy }) => gateCount > 0 || policy.interior.cap === 0 ? gatePosition({
9084
- blockingFindings,
9085
- gateCount,
9086
- openFindings,
9087
- policy
9088
- }) : interiorPosition({
9089
- interiorCount,
9090
- openFindings,
9091
- policy
9092
- });
9093
- const executedStageFor = (ref, _policy) => {
8974
+ const executedStageFor = (ref) => {
9094
8975
  if (ref.stage === "gate") return "gate";
9095
8976
  return "interior";
9096
8977
  };
9097
- const eventFor = ({ cycles, openFindings, blockingFindings, policy, position, staleRepeats, refs }) => {
8978
+ const eventFor = ({ cycles, openFindings, blockingFindings, position, staleRepeats, refs }) => {
9098
8979
  const latest = cycles.at(-1);
9099
8980
  const latestRef = refs.at(-1);
9100
8981
  if (!latest || !latestRef) return;
@@ -9113,7 +8994,7 @@ const eventFor = ({ cycles, openFindings, blockingFindings, policy, position, st
9113
8994
  ...latest.model === void 0 ? {} : { model: latest.model },
9114
8995
  payloadVersion: 1,
9115
8996
  ...latest.session ? { session: latest.session } : {},
9116
- stage: executedStageFor(latestRef, policy),
8997
+ stage: executedStageFor(latestRef),
9117
8998
  type: "review-ladder-stage",
9118
8999
  ...latest.usage ? { usage: latest.usage } : {}
9119
9000
  };
@@ -9130,26 +9011,19 @@ const evaluateReviewLadder = ({ cycles, policy }) => {
9130
9011
  const position = resolveLadderPosition({
9131
9012
  blockingFindings,
9132
9013
  gateCount,
9133
- interiorCount,
9134
9014
  openFindings,
9135
9015
  policy
9136
9016
  });
9137
- const diagnostics = policy.interior.cap > 0 && interiorCount === 0 && gateCount > 0 ? [{
9138
- code: "interior-cycles-unrecorded",
9139
- message: `Ladder policy configures an interior loop (cap ${policy.interior.cap}) but the history contains no interior cycles; the gate is proceeding without interior evidence.`
9140
- }] : [];
9141
9017
  return {
9142
9018
  ...position,
9143
9019
  cycleCounts: {
9144
9020
  gate: gateCount,
9145
9021
  interior: interiorCount
9146
9022
  },
9147
- diagnostics,
9148
9023
  event: eventFor({
9149
9024
  blockingFindings,
9150
9025
  cycles,
9151
9026
  openFindings,
9152
- policy,
9153
9027
  position,
9154
9028
  refs,
9155
9029
  staleRepeats
@@ -9325,7 +9199,6 @@ var review_proof_exports = /* @__PURE__ */ __exportAll({
9325
9199
  prReviewFindingSchema: () => prReviewFindingSchema,
9326
9200
  prReviewProofSchema: () => prReviewProofSchema,
9327
9201
  prReviewResultSchema: () => prReviewResultSchema,
9328
- readPrReviewProof: () => readPrReviewProof,
9329
9202
  resolveReviewAcceptance: () => resolveReviewAcceptance,
9330
9203
  resolveReviewTerminalState: () => resolveReviewTerminalState,
9331
9204
  resolveReviewTerminalStateAcrossReviews: () => resolveReviewTerminalStateAcrossReviews,
@@ -9451,7 +9324,6 @@ const validatePrReviewProof = (value) => {
9451
9324
  }
9452
9325
  return parsed.data;
9453
9326
  };
9454
- const readPrReviewProof = (filePath) => readProofFromPath(validatePrReviewProof, filePath);
9455
9327
  const PR_REVIEW_PROOF_DESCRIPTOR = {
9456
9328
  defaultPath: DEFAULT_PR_REVIEW_PROOF_PATH,
9457
9329
  label: "pr:review proof",
@@ -17753,7 +17625,6 @@ function ladderStateForRun({ declaredDispositions, cycle, historical, identity,
17753
17625
  policy
17754
17626
  });
17755
17627
  if (evaluation.unmatchedDispositions.length > 0) throw new Error(`Dispositions were dropped at fold time — they matched no flagged finding in the ladder history: ${evaluation.unmatchedDispositions.map((declaration) => declaration.finding.title).join("; ")}. The fold and the pre-run --dispositions validation disagree; nothing was persisted.`);
17756
- for (const diagnostic of evaluation.diagnostics) console.error(`[${diagnostic.code}] ${diagnostic.message}`);
17757
17628
  return {
17758
17629
  evaluation,
17759
17630
  ladder: { cycles }
@@ -20327,4 +20198,4 @@ async function run(argv = process.argv, cliEntry = factoryCliEntry()) {
20327
20198
  }
20328
20199
  }
20329
20200
  //#endregion
20330
- export { DEFAULT_DEMAND_WAIVER_PATH, DEFAULT_FACTORY_REPOSITORY, DEFAULT_ROOT_SHARED_GLOBS, DemandWaiveRefusalError, EMPTY_TREE_OBJECT_HASH, EPIC_STRUCTURE_NODE_STATUSES, EPIC_STRUCTURE_SCHEMA_VERSION, EpicStructureValidationError, FACTORY_BASE_REF_ENV, FACTORY_CHANGED_FILES_ENV, FACTORY_CHANGED_FILES_FILE_ENV, FactoryCliInvocationSchema, FollowUpActionSchema, MERGE_FREEZE_APP_SLUG, MERGE_FREEZE_CHECK_NAME, PrPublishFollowUpError, REVIEW_FOCUS_SECTION, WorkerCheckoutGuardError, appendReviewLadderStageTraceEvent, appendWithTraceSinks, applyDemandWaiver, assembleReviewPrompt, assertFactoryPrStatusIdentity, assertWorkerCheckoutAllowed, authorizeDemandWaiver, batteryScopeSummaryLines, blockingLadderFindings, boundary_manifest_exports as boundaryManifest, boundary_review_proof_exports as boundaryReviewProof, buildEpicStructureEvent, buildEpicStructurePayload, buildEvidenceEnvelope, buildReviewGateNotRequiredTraceEvent, buildReviewLadderStageTraceEvent, comment_provenance_exports as commentProvenance, createGitHubCheckRunMergeFreezeStore, createLocalJsonlTraceSink, createProgram, createVerificationRunContext, doctorProjectProfile, epicStructureEventId, evaluateReviewLadder, evidenceEnvelopeFilename, findingKey, followUpFromArgv, impactStampScopeDecision, inferFixedInThreadDispositions, isProductionHqUrl, loadProjectProfile, normalizeIssueComments, openLadderFindings, planFactoryPrStatusHud, planPreviewLifecycle, planPublishFollowUp, planVerificationBattery, readiness_evaluation_exports as prReadinessEvaluation, external_evidence_exports as prReadinessExternalEvidence, pr_body_renderer_exports as prReadinessPrBodyRenderer, proof_identity_exports as prReadinessProofIdentity, review_proof_exports as prReadinessReviewProof, status_check_rollup_exports as prReadinessStatusChecks, verification_proof_exports as prReadinessVerificationProof, presentFactoryPrStatusHud, previewLifecycleTargets, publishEpicStructure, readDemandWaivers, readFactoryPrStatusSources, readPrReadyProof, readPrReviewProof, refreshFactoryPrStatusHud, refreshFactoryPrStatusHudSafely, renderFactoryPrStatusHud, resolveFactoryRepository, resolveFindingBlocking, resolveReviewFindingCategory, resolveReviewFindingSeverity, resolveReviewLadderPolicy, resolveTraceWriteSinks, 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, validatePreviewLifecyclePlan, waivedDemandNotice, waivedDemandSchema, worktree_scratch_files_exports as worktreeScratchFiles };
20201
+ export { DEFAULT_DEMAND_WAIVER_PATH, DEFAULT_FACTORY_REPOSITORY, DEFAULT_ROOT_SHARED_GLOBS, DemandWaiveRefusalError, EMPTY_TREE_OBJECT_HASH, EPIC_STRUCTURE_NODE_STATUSES, EPIC_STRUCTURE_SCHEMA_VERSION, EpicStructureValidationError, FACTORY_BASE_REF_ENV, FACTORY_CHANGED_FILES_ENV, FACTORY_CHANGED_FILES_FILE_ENV, FactoryCliInvocationSchema, FollowUpActionSchema, MERGE_FREEZE_APP_SLUG, MERGE_FREEZE_CHECK_NAME, PrPublishFollowUpError, REVIEW_FOCUS_SECTION, WorkerCheckoutGuardError, appendWithTraceSinks, applyDemandWaiver, assembleReviewPrompt, assertFactoryPrStatusIdentity, assertWorkerCheckoutAllowed, authorizeDemandWaiver, batteryScopeSummaryLines, boundary_manifest_exports as boundaryManifest, boundary_review_proof_exports as boundaryReviewProof, buildEpicStructureEvent, buildEpicStructurePayload, buildEvidenceEnvelope, buildReviewGateNotRequiredTraceEvent, comment_provenance_exports as commentProvenance, createGitHubCheckRunMergeFreezeStore, createLocalJsonlTraceSink, createProgram, createVerificationRunContext, doctorProjectProfile, epicStructureEventId, evidenceEnvelopeFilename, followUpFromArgv, impactStampScopeDecision, isProductionHqUrl, loadProjectProfile, normalizeIssueComments, planFactoryPrStatusHud, planPreviewLifecycle, planPublishFollowUp, planVerificationBattery, readiness_evaluation_exports as prReadinessEvaluation, external_evidence_exports as prReadinessExternalEvidence, pr_body_renderer_exports as prReadinessPrBodyRenderer, proof_identity_exports as prReadinessProofIdentity, review_proof_exports as prReadinessReviewProof, status_check_rollup_exports as prReadinessStatusChecks, verification_proof_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_exports as worktreeScratchFiles };
package/dist/schemas.d.ts CHANGED
@@ -432,12 +432,12 @@ declare const managedReadinessLedgerSchema: z.ZodObject<{
432
432
  "interior-cap-reached": "interior-cap-reached";
433
433
  }>>;
434
434
  nextAction: z.ZodEnum<{
435
+ "run-interior-cycle": "run-interior-cycle";
436
+ "advance-to-gate": "advance-to-gate";
435
437
  "run-gate-cycle": "run-gate-cycle";
436
438
  "accept-nonblocking-findings": "accept-nonblocking-findings";
437
439
  "escalate-to-triage": "escalate-to-triage";
438
440
  "ready-for-human": "ready-for-human";
439
- "advance-to-gate": "advance-to-gate";
440
- "run-interior-cycle": "run-interior-cycle";
441
441
  }>;
442
442
  stage: z.ZodEnum<{
443
443
  gate: "gate";
@@ -903,8 +903,8 @@ declare const closeoutArtifactSchema: z.ZodObject<{
903
903
  }, z.core.$strict>;
904
904
  unit: z.ZodEnum<{
905
905
  boolean: "boolean";
906
- text: "text";
907
906
  count: "count";
907
+ text: "text";
908
908
  tokens: "tokens";
909
909
  usd: "usd";
910
910
  }>;
@@ -1201,12 +1201,12 @@ declare const prReadyProofSchema: z.ZodObject<{
1201
1201
  "interior-cap-reached": "interior-cap-reached";
1202
1202
  }>>;
1203
1203
  nextAction: z.ZodEnum<{
1204
+ "run-interior-cycle": "run-interior-cycle";
1205
+ "advance-to-gate": "advance-to-gate";
1204
1206
  "run-gate-cycle": "run-gate-cycle";
1205
1207
  "accept-nonblocking-findings": "accept-nonblocking-findings";
1206
1208
  "escalate-to-triage": "escalate-to-triage";
1207
1209
  "ready-for-human": "ready-for-human";
1208
- "advance-to-gate": "advance-to-gate";
1209
- "run-interior-cycle": "run-interior-cycle";
1210
1210
  }>;
1211
1211
  stage: z.ZodEnum<{
1212
1212
  gate: "gate";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patronage/software-factory",
3
- "version": "1.0.0-alpha.29",
3
+ "version": "1.0.0-alpha.30",
4
4
  "description": "Shared Patronage software factory CLI and project-profile validation tools",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -37,7 +37,7 @@
37
37
  "picomatch": "^4.0.5",
38
38
  "yaml": "^2.9.0",
39
39
  "zod": "4.4.3",
40
- "@patronage/factory-ci": "1.0.0-alpha.29"
40
+ "@patronage/factory-ci": "1.0.0-alpha.30"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/node": "24.13.3",