Skip to content

Commit 9701725

Browse files
committed
refactor(sections): move the plan lockstep types beside KeyErasedPlan and name FamilyPlan KeyedPlan
FamilyPlan, WidePlan, WidePlanAt, Invariant, and PlanMisfits lived in src/sections/shared/keyed-values.ts, the secrets and variables family scaffolding, and the setup factory in setup-section.ts had to import a "Family" vocabulary from a family module to prove its one plan the same way. The five types now sit after KeyErasedPlan in src/sections/contract/plan.ts, the module that already owns PlanContext, PlannedOp, SectionPlan, and the key-erasure the lockstep compares through. FamilyPlan is renamed KeyedPlan: one section's plan() under its own key brand, the counterpart KeyErasedPlan strips. The other four keep their names and bodies. keyed-values.ts keeps no re-export and drops the imports only the moved types used. repo-secrets.ts, repo-variables.ts, and setup-section.ts import the three public types from the contract. KeyErasedPlan loses its export keyword since nothing outside plan.ts reads it now.
1 parent 5a704a3 commit 9701725

5 files changed

Lines changed: 74 additions & 67 deletions

File tree

‎src/sections/contract/plan.ts‎

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,13 @@ import type {
2424
GraphqlVariablesOf,
2525
} from "./graphql.js";
2626
import { parseLive } from "./live.js";
27-
import type { EndpointDict, GraphqlDict, SectionContext, SectionMeta } from "./module.js";
27+
import type {
28+
EndpointDict,
29+
GraphqlDict,
30+
SectionContext,
31+
SectionMeta,
32+
ValidatedInput,
33+
} from "./module.js";
2834
import {
2935
call,
3036
callGraphql,
@@ -358,13 +364,54 @@ export interface PlanContext<
358364
* A plan handler with its context's key brand erased: a shared handler serving several sections is
359365
* compared to each branded per-key signature through this (repo-secrets, repo-variables, setup-section).
360366
*/
361-
export type KeyErasedPlan<P> = P extends (
367+
type KeyErasedPlan<P> = P extends (
362368
ctx: PlanContext<infer E, infer G, infer _K>,
363369
declared: infer D,
364370
) => infer R
365371
? (ctx: PlanContext<E, G>, declared: D) => R
366372
: never;
367373

374+
/**
375+
* One section's plan() under its own key brand, over exactly its own dictionary and declared value (the
376+
* registry's exactness lockstep).
377+
*/
378+
export type KeyedPlan<K extends SectionKey, E extends EndpointDict> = (
379+
ctx: PlanContext<E, GraphqlDict, K>,
380+
declared: ValidatedInput<K>,
381+
) => Promise<Result<SectionPlan<PlannedOp<E>>, SectionFailure>>;
382+
383+
/**
384+
* The plan a factory file writes ONCE over its wide dictionary (every route the union over the sections it
385+
* serves): inside the generic factory the section is unresolved, so the contract's role derivations only
386+
* resolve over this view. The brand on `declared` names the section it is called as.
387+
*/
388+
export type WidePlan<Keys extends SectionKey, Wide extends EndpointDict> = <F extends Keys>(
389+
ctx: PlanContext<Wide>,
390+
declared: ValidatedInput<F>,
391+
) => Promise<Result<SectionPlan<PlannedOp<Wide>>, SectionFailure>>;
392+
393+
type WidePlanAt<F extends SectionKey, Wide extends EndpointDict> = (
394+
ctx: PlanContext<Wide>,
395+
declared: ValidatedInput<F>,
396+
) => Promise<Result<SectionPlan<PlannedOp<Wide>>, SectionFailure>>;
397+
398+
type Invariant<A, B> = [A] extends [B] ? ([B] extends [A] ? true : false) : false;
399+
400+
/**
401+
* The sections whose own plan signature the wide plan is NOT, key brand aside: a factory file pins it to
402+
* never, so a role the wide view carries and a section's dictionary does not (or the reverse) fails to compile
403+
* there instead of losing role checking silently.
404+
*/
405+
export type PlanMisfits<
406+
Keys extends SectionKey,
407+
Wide extends EndpointDict,
408+
Table extends { readonly [F in Keys]: Wide },
409+
> = {
410+
[K in Keys]: Invariant<WidePlanAt<K, Wide>, KeyErasedPlan<KeyedPlan<K, Table[K]>>> extends true
411+
? never
412+
: K;
413+
}[Keys];
414+
368415
/** The run's on-missing-permission input: how a read the token is denied classifies. */
369416
export type OnMissingPermission = "fail" | "warn";
370417

‎src/sections/shared/keyed-values.ts‎

Lines changed: 5 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
/**
22
* The scaffolding the repo-scoped secret families (./repo-secrets.ts) and variable families (./repo-variables.ts)
3-
* share: what a section supplies, the undeclared-policy unwrap, the knobbed snapshot wrap, the wide plan every
4-
* family of a kind is served by, and the lockstep proving it is each family's own plan. What a value IS (sealed
5-
* and write-only, or readable and compared) stays in the family file: it decides the routes, the plan scope, and
6-
* the read-back, so those are written once per kind, not once per section. The plan types and the lockstep are
7-
* not keyed-values specific: the setup factory (./setup-section.ts) proves its one plan the same way.
3+
* share: what a section supplies, the undeclared-policy unwrap, and the knobbed snapshot wrap. What a value IS
4+
* (sealed and write-only, or readable and compared) stays in the family file: it decides the routes, the plan
5+
* scope, and the read-back, so those are written once per kind, not once per section. The wide plan a family file
6+
* writes and the lockstep proving it is each family's own plan are the contract's (../contract/plan.ts).
87
*/
98

109
import type { Result } from "neverthrow";
@@ -14,20 +13,11 @@ import type { SectionFailure } from "../contract/errors.js";
1413
import {
1514
defaultUndeclaredPolicy,
1615
type EndpointDict,
17-
type GraphqlDict,
1816
type SectionMeta,
1917
undeclaredPolicy,
20-
type ValidatedInput,
2118
} from "../contract/module.js";
2219
import type { PatResource } from "../contract/permissions.js";
23-
import type {
24-
KeyErasedPlan,
25-
PlanContext,
26-
PlannedOp,
27-
Read,
28-
SectionPlan,
29-
SnapshotContext,
30-
} from "../contract/plan.js";
20+
import type { Read, SnapshotContext } from "../contract/plan.js";
3121
import { knobbedSnapshot } from "./snapshot-helpers.js";
3222

3323
export interface KeyedValuesFamily<K extends SectionKey> {
@@ -40,44 +30,6 @@ export interface KeyedValuesFamily<K extends SectionKey> {
4030

4131
export type Declared<Entry> = Entry[] | UndeclaredPolicyList<Entry>;
4232

43-
/** One family's plan() over exactly its own dictionary and declared value (the registry's exactness lockstep). */
44-
export type FamilyPlan<K extends SectionKey, E extends EndpointDict> = (
45-
ctx: PlanContext<E, GraphqlDict, K>,
46-
declared: ValidatedInput<K>,
47-
) => Promise<Result<SectionPlan<PlannedOp<E>>, SectionFailure>>;
48-
49-
/**
50-
* The plan a family file writes ONCE over its wide dictionary (every route the union over the kind's
51-
* segments): inside the generic factory the segment is unresolved, so the contract's role derivations only
52-
* resolve over this view. The brand on `declared` names the family it is called as.
53-
*/
54-
export type WidePlan<Keys extends SectionKey, Wide extends EndpointDict> = <F extends Keys>(
55-
ctx: PlanContext<Wide>,
56-
declared: ValidatedInput<F>,
57-
) => Promise<Result<SectionPlan<PlannedOp<Wide>>, SectionFailure>>;
58-
59-
type WidePlanAt<F extends SectionKey, Wide extends EndpointDict> = (
60-
ctx: PlanContext<Wide>,
61-
declared: ValidatedInput<F>,
62-
) => Promise<Result<SectionPlan<PlannedOp<Wide>>, SectionFailure>>;
63-
64-
type Invariant<A, B> = [A] extends [B] ? ([B] extends [A] ? true : false) : false;
65-
66-
/**
67-
* The sections whose own plan signature the wide plan is NOT, key brand aside: a factory file pins it to
68-
* never, so a role the wide view carries and a section's dictionary does not (or the reverse) fails to compile
69-
* there instead of losing role checking silently.
70-
*/
71-
export type PlanMisfits<
72-
Keys extends SectionKey,
73-
Wide extends EndpointDict,
74-
Table extends { readonly [F in Keys]: Wide },
75-
> = {
76-
[K in Keys]: Invariant<WidePlanAt<K, Wide>, KeyErasedPlan<FamilyPlan<K, Table[K]>>> extends true
77-
? never
78-
: K;
79-
}[Keys];
80-
8133
export function knobbedEntries<Entry>(
8234
meta: SectionMeta<UndeclaredPolicySection>,
8335
declared: Declared<Entry>,

‎src/sections/shared/repo-secrets.ts‎

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,19 @@ import {
2424
type SectionSnapshot,
2525
} from "../contract/module.js";
2626
import type { PatResource } from "../contract/permissions.js";
27-
import type { PlannedOp, SnapshotContext } from "../contract/plan.js";
27+
import type {
28+
KeyedPlan,
29+
PlanMisfits,
30+
PlannedOp,
31+
SnapshotContext,
32+
WidePlan,
33+
} from "../contract/plan.js";
2834
import { DependabotSecretConfig } from "../dependabot_secrets/schema.js";
2935
import {
3036
type Declared,
31-
type FamilyPlan,
3237
type KeyedValuesFamily,
3338
knobbedEntries,
34-
type PlanMisfits,
3539
snapshotOf,
36-
type WidePlan,
3740
} from "./keyed-values.js";
3841
import { knobbed, routed, type sealedSecretConfig } from "./schema-helpers.js";
3942
import {
@@ -117,7 +120,7 @@ type WideEndpoints = RepoSecretsEndpoints<SecretsSegment>;
117120

118121
/** One family's plan(), indexed by K so the generic factory can assign its one WidePlan to it. */
119122
type RepoSecretsPlan<K extends RepoSecretsKey> = {
120-
[F in RepoSecretsKey]: FamilyPlan<F, SecretsTable[F]>;
123+
[F in RepoSecretsKey]: KeyedPlan<F, SecretsTable[F]>;
121124
}[K];
122125

123126
type _WidePlanIsEveryFamilyPlan = MustBeNever<

‎src/sections/shared/repo-variables.ts‎

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,18 @@ import {
2020
type SectionSnapshot,
2121
} from "../contract/module.js";
2222
import type { PatResource } from "../contract/permissions.js";
23-
import type { PlannedOp, SnapshotContext } from "../contract/plan.js";
23+
import type {
24+
KeyedPlan,
25+
PlanMisfits,
26+
PlannedOp,
27+
SnapshotContext,
28+
WidePlan,
29+
} from "../contract/plan.js";
2430
import {
2531
type Declared,
26-
type FamilyPlan,
2732
type KeyedValuesFamily,
2833
knobbedEntries,
29-
type PlanMisfits,
3034
snapshotOf,
31-
type WidePlan,
3235
} from "./keyed-values.js";
3336
import { knobbed, routed } from "./schema-helpers.js";
3437
import { projectOntoSchema } from "./snapshot-helpers.js";
@@ -105,7 +108,7 @@ type WideEndpoints = RepoVariablesEndpoints<VariablesSegment>;
105108

106109
/** One family's plan(), indexed by K so the generic factory can assign its one WidePlan to it. */
107110
type RepoVariablesPlan<K extends RepoVariablesKey> = {
108-
[F in RepoVariablesKey]: FamilyPlan<F, VariablesTable[F]>;
111+
[F in RepoVariablesKey]: KeyedPlan<F, VariablesTable[F]>;
109112
}[K];
110113

111114
type _WidePlanIsEveryFamilyPlan = MustBeNever<

‎src/sections/shared/setup-section.ts‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@ import { type GraphqlDict, requirePlainMapping, type SectionSnapshot } from "../
2121
import type { SectionPermission } from "../contract/permissions.js";
2222
import {
2323
hasDrift,
24+
type KeyedPlan,
25+
type PlanMisfits,
2426
type PlannedOp,
2527
type SectionPlan,
2628
type SnapshotContext,
29+
type WidePlan,
2730
} from "../contract/plan.js";
28-
import type { FamilyPlan, PlanMisfits, WidePlan } from "./keyed-values.js";
2931
import { type SetupLanguages, undeclarableLanguages } from "./setup-schema.js";
3032
import { leftOutOfSnapshot, projectOntoSchema } from "./snapshot-helpers.js";
3133

@@ -76,7 +78,7 @@ type SetupTable = { readonly [F in SetupKey]: SetupEndpoints<F> };
7678

7779
/** One setup's plan(), indexed by K so the factory's one WidePlan can be assigned to it. */
7880
type SetupPlan<K extends SetupKey> = {
79-
[F in SetupKey]: FamilyPlan<F, SetupTable[F]>;
81+
[F in SetupKey]: KeyedPlan<F, SetupTable[F]>;
8082
}[K];
8183

8284
type WideEndpoints = SetupEndpoints<SetupKey>;

0 commit comments

Comments
 (0)