diff --git a/src/contexts/ingest-snapshot/index.ts b/src/contexts/ingest-snapshot/index.ts index e6943f8..e6af2bb 100644 --- a/src/contexts/ingest-snapshot/index.ts +++ b/src/contexts/ingest-snapshot/index.ts @@ -1,13 +1,44 @@ -export * from "./models/shared.js" -export * from "./models/types.js" -export * from "./models/factories.js" -export * from "./models/ops.js" -export * from "./policies/selection.js" -export * from "./policies/segments.js" - +export type { + Error, + Event, + IngestUpstreamSnapshot, + State, + UpstreamSnapshotIngested, + SnapshotIngestHardStopped, + AwaitingTrustedBundle, + TrustedSnapshotSelected, + IngestableSnapshot, +} from "./models/types.js" +export type { + RunManifest, + SegmentRecord, + SelectedSnapshot, + SnapshotIdentity, + SnapshotMetadata, + TaintedBundleLocation, + TrustedBundleLocation, + RunIdentity, +} from "./models/shared.js" +export { + makeAstNodeKind, + makeNormalizedHash, + makeRawHash, + makeRunIdentity, + makeShapeHash, + makeSnapshotIdentity, + makeTaintedBundleInput, + makeTaintedBundleLocation, + makeTrustedCanonicalProjectionPath, + makeTrustedManifestPath, + makeTrustedSegmentsPath, + makeTrustedSummaryPath, + makeVerifiedPreviousRunManifest, +} from "./models/factories.js" export { workflow } from "./workflows/ingestSnapshot.js" export { apply, decide, - makeAwaitingSnapshotSelection, + emitSnapshotIngested, + makeAwaitingTrustedBundle, + validatePreviousRunManifest, } from "./policies/decideSnapshotIngest.js" diff --git a/src/contexts/ingest-snapshot/models/types.ts b/src/contexts/ingest-snapshot/models/types.ts index 86dbbc9..46801a5 100644 --- a/src/contexts/ingest-snapshot/models/types.ts +++ b/src/contexts/ingest-snapshot/models/types.ts @@ -68,8 +68,8 @@ export type Error = { readonly payload: SnapshotIngestHardStopped } -export type AwaitingSnapshotSelection = { - readonly _tag: "AwaitingSnapshotSelection" +export type AwaitingTrustedBundle = { + readonly _tag: "AwaitingTrustedBundle" readonly RunIdentityRulesDescription: string readonly BoundaryRulesDescription: string readonly RequiredArtifacts: ReadonlyArray @@ -77,8 +77,8 @@ export type AwaitingSnapshotSelection = { readonly ParseBudget: number } -export type SnapshotReady = { - readonly _tag: "SnapshotReady" +export type TrustedSnapshotSelected = { + readonly _tag: "TrustedSnapshotSelected" readonly SelectedSnapshot: SelectedSnapshot readonly PreviousRunManifest: VerifiedPreviousRunManifest | null readonly RequiredArtifacts: ReadonlyArray @@ -86,8 +86,8 @@ export type SnapshotReady = { readonly ParseBudget: number } -export type DeterministicSegmentsReady = { - readonly _tag: "DeterministicSegmentsReady" +export type IngestableSnapshot = { + readonly _tag: "IngestableSnapshot" readonly RunIdentity: RunIdentity readonly SelectedSnapshot: SelectedSnapshot readonly PreviousRunManifest: VerifiedPreviousRunManifest | null @@ -97,7 +97,7 @@ export type DeterministicSegmentsReady = { } export type State = - | AwaitingSnapshotSelection - | SnapshotReady - | DeterministicSegmentsReady + | AwaitingTrustedBundle + | TrustedSnapshotSelected + | IngestableSnapshot | ({ readonly _tag: "SnapshotIngested" } & UpstreamSnapshotIngested) diff --git a/src/contexts/ingest-snapshot/policies/decideSnapshotIngest.ts b/src/contexts/ingest-snapshot/policies/decideSnapshotIngest.ts index 059e9d9..521960f 100644 --- a/src/contexts/ingest-snapshot/policies/decideSnapshotIngest.ts +++ b/src/contexts/ingest-snapshot/policies/decideSnapshotIngest.ts @@ -1,31 +1,29 @@ import { Either } from "effect" +import { deriveRequiredArtifactPaths } from "../models/ops.js" +import type { + AwaitingTrustedBundle, + Event, + IngestableSnapshot, + IngestUpstreamSnapshot, + State, + UpstreamSnapshotIngested, +} from "../models/types.js" +import type { RunManifest } from "../models/shared.js" +import { decideIngestableSnapshot } from "./segments.js" import { - type AwaitingSnapshotSelection, - type DeterministicSegmentsReady, - type Event, - type IngestUpstreamSnapshot, - type RunManifest, - type State, - type UpstreamSnapshotIngested, - deriveRequiredArtifactPaths, -} from "../index.js" -import { decideSegmentRecords } from "./segments.js" -import { + selectTrustedSnapshot, validatePreviousRunManifest, - validateSnapshotSelection, } from "./selection.js" -const toEvent = ( - deterministicSegmentsReady: DeterministicSegmentsReady, +export const emitSnapshotIngested = ( + ingestableSnapshot: IngestableSnapshot, ): Event => { - const artifactPaths = deriveRequiredArtifactPaths( - deterministicSegmentsReady.RunIdentity, - ) + const artifactPaths = deriveRequiredArtifactPaths(ingestableSnapshot.RunIdentity) const runManifest: RunManifest = { - RunIdentity: deterministicSegmentsReady.RunIdentity, - SnapshotIdentity: deterministicSegmentsReady.SelectedSnapshot.SnapshotIdentity, + RunIdentity: ingestableSnapshot.RunIdentity, + SnapshotIdentity: ingestableSnapshot.SelectedSnapshot.SnapshotIdentity, ManifestPath: artifactPaths.ManifestPath, SegmentsPath: artifactPaths.SegmentsPath, CanonicalProjectionPath: artifactPaths.CanonicalProjectionPath, @@ -34,7 +32,7 @@ const toEvent = ( const payload: UpstreamSnapshotIngested = { RunManifest: runManifest, - SegmentRecords: deterministicSegmentsReady.SegmentRecords, + SegmentRecords: ingestableSnapshot.SegmentRecords, CanonicalProjectionPath: artifactPaths.CanonicalProjectionPath, SummaryPath: artifactPaths.SummaryPath, } @@ -46,8 +44,8 @@ export const decide = ( state: State, command: IngestUpstreamSnapshot, ) => - Either.flatMap(validateSnapshotSelection(state, command), (snapshotReady) => - Either.map(decideSegmentRecords(snapshotReady), toEvent), + Either.flatMap(selectTrustedSnapshot(state, command), (trustedSnapshot) => + Either.map(decideIngestableSnapshot(trustedSnapshot), emitSnapshotIngested), ) export const apply = (_state: State, event: Event): State => { @@ -57,10 +55,10 @@ export const apply = (_state: State, event: Event): State => { } } -export const makeAwaitingSnapshotSelection = ( - overrides: Partial = {}, -): AwaitingSnapshotSelection => ({ - _tag: "AwaitingSnapshotSelection", +export const makeAwaitingTrustedBundle = ( + overrides: Partial = {}, +): AwaitingTrustedBundle => ({ + _tag: "AwaitingTrustedBundle", RunIdentityRulesDescription: "derive from snapshot identity", BoundaryRulesDescription: "require at least one deterministic boundary proof", RequiredArtifacts: [ @@ -73,4 +71,8 @@ export const makeAwaitingSnapshotSelection = ( ...overrides, }) -export { decideSegmentRecords, validatePreviousRunManifest, validateSnapshotSelection } +export { + decideIngestableSnapshot, + selectTrustedSnapshot, + validatePreviousRunManifest, +} diff --git a/src/contexts/ingest-snapshot/policies/segments.ts b/src/contexts/ingest-snapshot/policies/segments.ts index 6c42600..e42196f 100644 --- a/src/contexts/ingest-snapshot/policies/segments.ts +++ b/src/contexts/ingest-snapshot/policies/segments.ts @@ -1,40 +1,42 @@ import { Either } from "effect" import { - type DeterministicSegmentsReady, - type Error, - type SnapshotReady, applyRunIdentityRules, validateBoundaryProofs, validateRequiredArtifacts, validateSegmentRecords, -} from "../index.js" +} from "../models/ops.js" +import type { + Error, + IngestableSnapshot, + TrustedSnapshotSelected, +} from "../models/types.js" -export const decideSegmentRecords = ( - snapshotReady: SnapshotReady, -): Either.Either => - Either.flatMap(applyRunIdentityRules(snapshotReady.SelectedSnapshot), (derivedRunIdentity) => - Either.flatMap(validateSegmentRecords(snapshotReady.SelectedSnapshot), (segmentRecords) => +export const decideIngestableSnapshot = ( + trustedSnapshot: TrustedSnapshotSelected, +): Either.Either => + Either.flatMap(applyRunIdentityRules(trustedSnapshot.SelectedSnapshot), (derivedRunIdentity) => + Either.flatMap(validateSegmentRecords(trustedSnapshot.SelectedSnapshot), (segmentRecords) => Either.flatMap( validateBoundaryProofs( - snapshotReady.SelectedSnapshot.SnapshotIdentity, + trustedSnapshot.SelectedSnapshot.SnapshotIdentity, segmentRecords, ), (boundaryProofs) => Either.map( validateRequiredArtifacts( - snapshotReady.SelectedSnapshot.SnapshotIdentity, - snapshotReady.RequiredArtifacts, + trustedSnapshot.SelectedSnapshot.SnapshotIdentity, + trustedSnapshot.RequiredArtifacts, segmentRecords, ), () => ({ - _tag: "DeterministicSegmentsReady" as const, + _tag: "IngestableSnapshot" as const, RunIdentity: derivedRunIdentity.value, - SelectedSnapshot: snapshotReady.SelectedSnapshot, - PreviousRunManifest: snapshotReady.PreviousRunManifest, + SelectedSnapshot: trustedSnapshot.SelectedSnapshot, + PreviousRunManifest: trustedSnapshot.PreviousRunManifest, SegmentRecords: segmentRecords, BoundaryProofs: boundaryProofs, - RequiredArtifacts: snapshotReady.RequiredArtifacts, + RequiredArtifacts: trustedSnapshot.RequiredArtifacts, }), ), ), diff --git a/src/contexts/ingest-snapshot/policies/selection.ts b/src/contexts/ingest-snapshot/policies/selection.ts index c2ee652..47f8844 100644 --- a/src/contexts/ingest-snapshot/policies/selection.ts +++ b/src/contexts/ingest-snapshot/policies/selection.ts @@ -1,15 +1,14 @@ import { Either } from "effect" -import { - type Error, - type IngestUpstreamSnapshot, - type RunManifest, - type SnapshotReady, - type State, - foldFailure, - makeVerifiedPreviousRunManifest, - parseBundleLocation, -} from "../index.js" +import { foldFailure, makeVerifiedPreviousRunManifest } from "../models/factories.js" +import { parseBundleLocation } from "../models/ops.js" +import type { + Error, + IngestUpstreamSnapshot, + State, + TrustedSnapshotSelected, +} from "../models/types.js" +import type { RunManifest } from "../models/shared.js" export const validatePreviousRunManifest = ( manifest: RunManifest, @@ -20,11 +19,11 @@ export const validatePreviousRunManifest = ( foldFailure(manifest.SnapshotIdentity, "PreviousRunManifestNotVerified"), ) -export const validateSnapshotSelection = ( +export const selectTrustedSnapshot = ( state: State, command: IngestUpstreamSnapshot, -): Either.Either => { - if (state._tag !== "AwaitingSnapshotSelection") { +): Either.Either => { + if (state._tag !== "AwaitingTrustedBundle") { return Either.left( foldFailure(command.SnapshotIdentity, "RunIdentityCouldNotBeDerived"), ) @@ -33,7 +32,7 @@ export const validateSnapshotSelection = ( return Either.map( parseBundleLocation(command.SnapshotIdentity, command.BundleInput), (bundleLocation) => ({ - _tag: "SnapshotReady" as const, + _tag: "TrustedSnapshotSelected" as const, SelectedSnapshot: { SnapshotIdentity: command.SnapshotIdentity, BundleLocation: bundleLocation, diff --git a/src/contexts/ingest-snapshot/workflows/ingestSnapshot.ts b/src/contexts/ingest-snapshot/workflows/ingestSnapshot.ts index b93e53a..13506ec 100644 --- a/src/contexts/ingest-snapshot/workflows/ingestSnapshot.ts +++ b/src/contexts/ingest-snapshot/workflows/ingestSnapshot.ts @@ -1,17 +1,19 @@ import { Effect, Either } from "effect" +import type { + Error, + Event, + IngestUpstreamSnapshot, + State, +} from "../models/types.js" import { - type Error, - type Event, - type IngestUpstreamSnapshot, - type State, decide, - makeAwaitingSnapshotSelection, -} from "../index.js" + makeAwaitingTrustedBundle, +} from "../policies/decideSnapshotIngest.js" export const workflow = ( command: IngestUpstreamSnapshot, - state: State = makeAwaitingSnapshotSelection(), + state: State = makeAwaitingTrustedBundle(), ): Effect.Effect => Effect.gen(function* () { const decision = decide(state, command) diff --git a/test/ingestSnapshot.test.ts b/test/ingestSnapshot.test.ts index 7c57ece..43a5d84 100644 --- a/test/ingestSnapshot.test.ts +++ b/test/ingestSnapshot.test.ts @@ -20,7 +20,7 @@ import { import { apply, decide, - makeAwaitingSnapshotSelection, + makeAwaitingTrustedBundle, validatePreviousRunManifest, workflow, } from "../src/contexts/ingest-snapshot/index.js" @@ -51,7 +51,7 @@ describe("ingestSnapshot workflow", () => { it("hard-stops when the bundle location is not parseable", () => { const result = decide( - makeAwaitingSnapshotSelection(), + makeAwaitingTrustedBundle(), makeCommand({ BundleInput: makeTaintedBundleInput(makeTaintedBundleLocation("not-a-path")), }), @@ -64,10 +64,10 @@ describe("ingestSnapshot workflow", () => { }) it("applies the ingested event into SnapshotIngested state", () => { - const result = decide(makeAwaitingSnapshotSelection(), makeCommand()) + const result = decide(makeAwaitingTrustedBundle(), makeCommand()) expect(Either.isRight(result)).toBe(true) if (Either.isRight(result)) { - const nextState = apply(makeAwaitingSnapshotSelection(), result.right) + const nextState = apply(makeAwaitingTrustedBundle(), result.right) expect(nextState._tag).toBe("SnapshotIngested") if (nextState._tag === "SnapshotIngested") { expect(nextState.RunManifest.CanonicalProjectionPath).toBe(