edits from review skill, merged policies, moved brand constructors
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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 = <T>(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,
|
||||
|
||||
@@ -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<ReturnType<typeof makeTrustedBundleLocation>, Error> => {
|
||||
): Either.Either<TrustedBundleLocation, Error> => {
|
||||
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<DerivedRunIdentity, Error> => {
|
||||
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<IngestableSnapshot, Error> =>
|
||||
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,
|
||||
): {
|
||||
|
||||
@@ -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<ReturnType<typeof makeVerifiedPreviousRunManifest>, 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<TrustedSnapshotSelected, Error> => {
|
||||
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 }
|
||||
|
||||
@@ -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<IngestableSnapshot, Error> =>
|
||||
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,
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
@@ -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<ReturnType<typeof makeVerifiedPreviousRunManifest>, 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<TrustedSnapshotSelected, Error> => {
|
||||
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,
|
||||
}),
|
||||
)
|
||||
}
|
||||
@@ -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")
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user