From 281c2a8a94949958b6c1878d55b6d82703634631 Mon Sep 17 00:00:00 2001 From: Elizabeth W Date: Mon, 25 May 2026 20:15:26 -0600 Subject: [PATCH] edits from review skill, merged policies, moved brand constructors --- src/contexts/ingest-snapshot/index.ts | 12 +-- .../ingest-snapshot/models/factories.ts | 38 +-------- src/contexts/ingest-snapshot/models/ops.ts | 77 +++++++++++++++---- .../policies/decideSnapshotIngest.ts | 56 +++++++++++--- .../ingest-snapshot/policies/segments.ts | 44 ----------- .../ingest-snapshot/policies/selection.ts | 47 ----------- test/ingestSnapshot.test.ts | 21 +++-- 7 files changed, 124 insertions(+), 171 deletions(-) delete mode 100644 src/contexts/ingest-snapshot/policies/segments.ts delete mode 100644 src/contexts/ingest-snapshot/policies/selection.ts diff --git a/src/contexts/ingest-snapshot/index.ts b/src/contexts/ingest-snapshot/index.ts index e6af2bb..4e572eb 100644 --- a/src/contexts/ingest-snapshot/index.ts +++ b/src/contexts/ingest-snapshot/index.ts @@ -19,21 +19,23 @@ export type { TrustedBundleLocation, RunIdentity, } from "./models/shared.js" +export { + makeSnapshotIdentity, + makeTaintedBundleInput, + makeTaintedBundleLocation, + makeVerifiedPreviousRunManifest, +} from "./models/factories.js" export { makeAstNodeKind, makeNormalizedHash, makeRawHash, makeRunIdentity, makeShapeHash, - makeSnapshotIdentity, - makeTaintedBundleInput, - makeTaintedBundleLocation, makeTrustedCanonicalProjectionPath, makeTrustedManifestPath, makeTrustedSegmentsPath, makeTrustedSummaryPath, - makeVerifiedPreviousRunManifest, -} from "./models/factories.js" +} from "./models/ops.js" export { workflow } from "./workflows/ingestSnapshot.js" export { apply, diff --git a/src/contexts/ingest-snapshot/models/factories.ts b/src/contexts/ingest-snapshot/models/factories.ts index bfb50ba..27b0a20 100644 --- a/src/contexts/ingest-snapshot/models/factories.ts +++ b/src/contexts/ingest-snapshot/models/factories.ts @@ -1,47 +1,19 @@ import type { - DerivedRunIdentity, Error, IngestFailureReason, TaintedBundleInput, VerifiedPreviousRunManifest, } from "./types.js" import type { - AstNodeKind, - NormalizedHash, - RawHash, - RunIdentity, RunManifest, - ShapeHash, SnapshotIdentity, TaintedBundleLocation, - TrustedBundleLocation, - TrustedCanonicalProjectionPath, - TrustedManifestPath, - TrustedSegmentsPath, - TrustedSummaryPath, } from "./shared.js" -const asBrand = (value: string): T => value as T - -export const makeSnapshotIdentity = (value: string): SnapshotIdentity => asBrand(value) +export const makeSnapshotIdentity = (value: string): SnapshotIdentity => + value as SnapshotIdentity export const makeTaintedBundleLocation = (value: string): TaintedBundleLocation => - asBrand(value) -export const makeTrustedBundleLocation = (value: string): TrustedBundleLocation => - asBrand(value) -export const makeRunIdentity = (value: string): RunIdentity => asBrand(value) -export const makeAstNodeKind = (value: string): AstNodeKind => asBrand(value) -export const makeRawHash = (value: string): RawHash => asBrand(value) -export const makeNormalizedHash = (value: string): NormalizedHash => asBrand(value) -export const makeShapeHash = (value: string): ShapeHash => asBrand(value) -export const makeTrustedManifestPath = (value: string): TrustedManifestPath => - asBrand(value) -export const makeTrustedSegmentsPath = (value: string): TrustedSegmentsPath => - asBrand(value) -export const makeTrustedCanonicalProjectionPath = ( - value: string, -): TrustedCanonicalProjectionPath => asBrand(value) -export const makeTrustedSummaryPath = (value: string): TrustedSummaryPath => - asBrand(value) + value as TaintedBundleLocation export const makeVerifiedPreviousRunManifest = ( manifest: RunManifest, @@ -51,10 +23,6 @@ export const makeTaintedBundleInput = ( location: TaintedBundleLocation, ): TaintedBundleInput => ({ _tag: "TaintedBundleInput", location }) -export const makeDerivedRunIdentity = ( - value: RunIdentity, -): DerivedRunIdentity => ({ _tag: "DerivedRunIdentity", value }) - export const foldFailure = ( snapshotIdentity: SnapshotIdentity, reason: IngestFailureReason, diff --git a/src/contexts/ingest-snapshot/models/ops.ts b/src/contexts/ingest-snapshot/models/ops.ts index 10f4bbe..f5cb17f 100644 --- a/src/contexts/ingest-snapshot/models/ops.ts +++ b/src/contexts/ingest-snapshot/models/ops.ts @@ -2,36 +2,48 @@ import { Either } from "effect" import { isNonEmptyString, + type AstNodeKind, + type NormalizedHash, + type RawHash, type RunIdentity, type SegmentRecord, type SelectedSnapshot, + type ShapeHash, type SnapshotIdentity, + type TrustedBundleLocation, type TrustedCanonicalProjectionPath, type TrustedManifestPath, type TrustedSegmentsPath, type TrustedSummaryPath, } from "./shared.js" -import { - foldFailure, - makeAstNodeKind, - makeDerivedRunIdentity, - makeNormalizedHash, - makeRawHash, - makeRunIdentity, - makeShapeHash, - makeTrustedBundleLocation, - makeTrustedCanonicalProjectionPath, - makeTrustedManifestPath, - makeTrustedSegmentsPath, - makeTrustedSummaryPath, -} from "./factories.js" +import { foldFailure } from "./factories.js" import type { DerivedRunIdentity, Error, + IngestableSnapshot, RequiredArtifact, TaintedBundleInput, + TrustedSnapshotSelected, } from "./types.js" +export const makeTrustedBundleLocation = (value: string): TrustedBundleLocation => + value as TrustedBundleLocation +export const makeRunIdentity = (value: string): RunIdentity => value as RunIdentity +export const makeAstNodeKind = (value: string): AstNodeKind => value as AstNodeKind +export const makeRawHash = (value: string): RawHash => value as RawHash +export const makeNormalizedHash = (value: string): NormalizedHash => + value as NormalizedHash +export const makeShapeHash = (value: string): ShapeHash => value as ShapeHash +export const makeTrustedManifestPath = (value: string): TrustedManifestPath => + value as TrustedManifestPath +export const makeTrustedSegmentsPath = (value: string): TrustedSegmentsPath => + value as TrustedSegmentsPath +export const makeTrustedCanonicalProjectionPath = ( + value: string, +): TrustedCanonicalProjectionPath => value as TrustedCanonicalProjectionPath +export const makeTrustedSummaryPath = (value: string): TrustedSummaryPath => + value as TrustedSummaryPath + const parseBundleLocationText = (location: string): string | null => { const trimmedLocation = location.trim() return trimmedLocation.length === 0 || !trimmedLocation.includes("/") @@ -63,19 +75,19 @@ const decideSegmentRecordFailure = ( export const parseBundleLocation = ( snapshotIdentity: SnapshotIdentity, input: TaintedBundleInput, -): Either.Either, Error> => { +): Either.Either => { const location = parseBundleLocationText(input.location as string) return location === null ? Either.left(foldFailure(snapshotIdentity, "BundleNotParseable")) : Either.right(makeTrustedBundleLocation(location)) } -export const applyRunIdentityRules = ( +const deriveRunIdentity = ( selectedSnapshot: SelectedSnapshot, ): Either.Either => { const snapshotIdentity = selectedSnapshot.SnapshotIdentity as string return isNonEmptyString(snapshotIdentity) - ? Either.right(makeDerivedRunIdentity(makeRunIdentity(`run:${snapshotIdentity}`))) + ? Either.right({ _tag: "DerivedRunIdentity", value: makeRunIdentity(`run:${snapshotIdentity}`) }) : Either.left( foldFailure( selectedSnapshot.SnapshotIdentity, @@ -136,6 +148,37 @@ export const validateRequiredArtifacts = ( ) } +export const decideIngestableSnapshot = ( + trustedSnapshot: TrustedSnapshotSelected, +): Either.Either => + Either.flatMap(deriveRunIdentity(trustedSnapshot.SelectedSnapshot), (derivedRunIdentity) => + Either.flatMap(validateSegmentRecords(trustedSnapshot.SelectedSnapshot), (segmentRecords) => + Either.flatMap( + validateBoundaryProofs( + trustedSnapshot.SelectedSnapshot.SnapshotIdentity, + segmentRecords, + ), + (boundaryProofs) => + Either.map( + validateRequiredArtifacts( + trustedSnapshot.SelectedSnapshot.SnapshotIdentity, + trustedSnapshot.RequiredArtifacts, + segmentRecords, + ), + () => ({ + _tag: "IngestableSnapshot" as const, + RunIdentity: derivedRunIdentity.value, + SelectedSnapshot: trustedSnapshot.SelectedSnapshot, + PreviousRunManifest: trustedSnapshot.PreviousRunManifest, + SegmentRecords: segmentRecords, + BoundaryProofs: boundaryProofs, + RequiredArtifacts: trustedSnapshot.RequiredArtifacts, + }), + ), + ), + ), + ) + export const deriveRequiredArtifactPaths = ( runIdentity: RunIdentity, ): { diff --git a/src/contexts/ingest-snapshot/policies/decideSnapshotIngest.ts b/src/contexts/ingest-snapshot/policies/decideSnapshotIngest.ts index 521960f..3b4036e 100644 --- a/src/contexts/ingest-snapshot/policies/decideSnapshotIngest.ts +++ b/src/contexts/ingest-snapshot/policies/decideSnapshotIngest.ts @@ -1,20 +1,58 @@ import { Either } from "effect" -import { deriveRequiredArtifactPaths } from "../models/ops.js" +import { foldFailure, makeVerifiedPreviousRunManifest } from "../models/factories.js" +import { + decideIngestableSnapshot, + deriveRequiredArtifactPaths, + parseBundleLocation, +} from "../models/ops.js" import type { AwaitingTrustedBundle, + Error, Event, IngestableSnapshot, IngestUpstreamSnapshot, State, + TrustedSnapshotSelected, UpstreamSnapshotIngested, } from "../models/types.js" import type { RunManifest } from "../models/shared.js" -import { decideIngestableSnapshot } from "./segments.js" -import { - selectTrustedSnapshot, - validatePreviousRunManifest, -} from "./selection.js" + +export const validatePreviousRunManifest = ( + manifest: RunManifest, +): Either.Either, Error> => + manifest.ManifestPath && manifest.SegmentsPath && manifest.CanonicalProjectionPath + ? Either.right(makeVerifiedPreviousRunManifest(manifest)) + : Either.left( + foldFailure(manifest.SnapshotIdentity, "PreviousRunManifestNotVerified"), + ) + +const selectTrustedSnapshot = ( + state: State, + command: IngestUpstreamSnapshot, +): Either.Either => { + if (state._tag !== "AwaitingTrustedBundle") { + return Either.left( + foldFailure(command.SnapshotIdentity, "RunIdentityCouldNotBeDerived"), + ) + } + + return Either.map( + parseBundleLocation(command.SnapshotIdentity, command.BundleInput), + (bundleLocation) => ({ + _tag: "TrustedSnapshotSelected" as const, + SelectedSnapshot: { + SnapshotIdentity: command.SnapshotIdentity, + BundleLocation: bundleLocation, + SnapshotMetadata: command.SnapshotMetadata, + }, + PreviousRunManifest: command.PreviousRunManifest, + RequiredArtifacts: state.RequiredArtifacts, + MaxBundleBytes: state.MaxBundleBytes, + ParseBudget: state.ParseBudget, + }), + ) +} export const emitSnapshotIngested = ( ingestableSnapshot: IngestableSnapshot, @@ -71,8 +109,4 @@ export const makeAwaitingTrustedBundle = ( ...overrides, }) -export { - decideIngestableSnapshot, - selectTrustedSnapshot, - validatePreviousRunManifest, -} +export { decideIngestableSnapshot } diff --git a/src/contexts/ingest-snapshot/policies/segments.ts b/src/contexts/ingest-snapshot/policies/segments.ts deleted file mode 100644 index e42196f..0000000 --- a/src/contexts/ingest-snapshot/policies/segments.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Either } from "effect" - -import { - applyRunIdentityRules, - validateBoundaryProofs, - validateRequiredArtifacts, - validateSegmentRecords, -} from "../models/ops.js" -import type { - Error, - IngestableSnapshot, - TrustedSnapshotSelected, -} from "../models/types.js" - -export const decideIngestableSnapshot = ( - trustedSnapshot: TrustedSnapshotSelected, -): Either.Either => - Either.flatMap(applyRunIdentityRules(trustedSnapshot.SelectedSnapshot), (derivedRunIdentity) => - Either.flatMap(validateSegmentRecords(trustedSnapshot.SelectedSnapshot), (segmentRecords) => - Either.flatMap( - validateBoundaryProofs( - trustedSnapshot.SelectedSnapshot.SnapshotIdentity, - segmentRecords, - ), - (boundaryProofs) => - Either.map( - validateRequiredArtifacts( - trustedSnapshot.SelectedSnapshot.SnapshotIdentity, - trustedSnapshot.RequiredArtifacts, - segmentRecords, - ), - () => ({ - _tag: "IngestableSnapshot" as const, - RunIdentity: derivedRunIdentity.value, - SelectedSnapshot: trustedSnapshot.SelectedSnapshot, - PreviousRunManifest: trustedSnapshot.PreviousRunManifest, - SegmentRecords: segmentRecords, - BoundaryProofs: boundaryProofs, - RequiredArtifacts: trustedSnapshot.RequiredArtifacts, - }), - ), - ), - ), - ) diff --git a/src/contexts/ingest-snapshot/policies/selection.ts b/src/contexts/ingest-snapshot/policies/selection.ts deleted file mode 100644 index 47f8844..0000000 --- a/src/contexts/ingest-snapshot/policies/selection.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Either } from "effect" - -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, -): Either.Either, Error> => - manifest.ManifestPath && manifest.SegmentsPath && manifest.CanonicalProjectionPath - ? Either.right(makeVerifiedPreviousRunManifest(manifest)) - : Either.left( - foldFailure(manifest.SnapshotIdentity, "PreviousRunManifestNotVerified"), - ) - -export const selectTrustedSnapshot = ( - state: State, - command: IngestUpstreamSnapshot, -): Either.Either => { - if (state._tag !== "AwaitingTrustedBundle") { - return Either.left( - foldFailure(command.SnapshotIdentity, "RunIdentityCouldNotBeDerived"), - ) - } - - return Either.map( - parseBundleLocation(command.SnapshotIdentity, command.BundleInput), - (bundleLocation) => ({ - _tag: "TrustedSnapshotSelected" as const, - SelectedSnapshot: { - SnapshotIdentity: command.SnapshotIdentity, - BundleLocation: bundleLocation, - SnapshotMetadata: command.SnapshotMetadata, - }, - PreviousRunManifest: command.PreviousRunManifest, - RequiredArtifacts: state.RequiredArtifacts, - MaxBundleBytes: state.MaxBundleBytes, - ParseBudget: state.ParseBudget, - }), - ) -} diff --git a/test/ingestSnapshot.test.ts b/test/ingestSnapshot.test.ts index 43a5d84..b194a02 100644 --- a/test/ingestSnapshot.test.ts +++ b/test/ingestSnapshot.test.ts @@ -3,11 +3,7 @@ import { describe, expect, it } from "vitest" import { type IngestUpstreamSnapshot, - makeAstNodeKind, - makeNormalizedHash, - makeRawHash, makeRunIdentity, - makeShapeHash, makeSnapshotIdentity, makeTaintedBundleInput, makeTaintedBundleLocation, @@ -42,9 +38,9 @@ describe("ingestSnapshot workflow", () => { const event = await Effect.runPromise(workflow(makeCommand())) expect(event._tag).toBe("UpstreamSnapshotIngested") - expect(event.payload.RunManifest.RunIdentity).toBe(makeRunIdentity("run:snapshot-001")) + expect(event.payload.RunManifest.RunIdentity).toBe("run:snapshot-001") expect(event.payload.RunManifest.ManifestPath).toBe( - makeTrustedManifestPath("runs/run:snapshot-001/manifest.json"), + "runs/run:snapshot-001/manifest.json", ) expect(event.payload.SegmentRecords).toHaveLength(1) }) @@ -71,10 +67,10 @@ describe("ingestSnapshot workflow", () => { expect(nextState._tag).toBe("SnapshotIngested") if (nextState._tag === "SnapshotIngested") { expect(nextState.RunManifest.CanonicalProjectionPath).toBe( - makeTrustedCanonicalProjectionPath("runs/run:snapshot-001/canonical.ts"), + "runs/run:snapshot-001/canonical.ts", ) expect(nextState.SummaryPath).toBe( - makeTrustedSummaryPath("runs/run:snapshot-001/summary.json"), + "runs/run:snapshot-001/summary.json", ) } } @@ -115,12 +111,13 @@ describe("ingestSnapshot workflow", () => { expect(event.payload.SegmentRecords[0]).toMatchObject({ SegmentId: "snapshot-001:root", - AstNodeKind: makeAstNodeKind("Program"), + AstNodeKind: "Program", Hashes: { - RawHash: makeRawHash("raw:snapshot-001"), - NormalizedHash: makeNormalizedHash("normalized:snapshot-001"), - ShapeHash: makeShapeHash("shape:snapshot-001"), + RawHash: "raw:snapshot-001", + NormalizedHash: "normalized:snapshot-001", + ShapeHash: "shape:snapshot-001", }, }) + expect(event.payload.SegmentRecords[0]?.Hashes.RawHash).toBe("raw:snapshot-001") }) })