finished refactoring the directory layout, no longer stubs

This commit is contained in:
2026-05-25 02:36:08 -06:00
parent 4f378c3825
commit 5ec088c250
19 changed files with 553 additions and 559 deletions
+7 -1
View File
@@ -4,4 +4,10 @@ export * from "./models/factories.js"
export * from "./models/ops.js"
export * from "./policies/selection.js"
export * from "./policies/segments.js"
export * from "./workflows/ingestSnapshot.js"
export { workflow } from "./workflows/ingestSnapshot.js"
export {
apply,
decide,
makeAwaitingSnapshotSelection,
} from "./policies/decideSnapshotIngest.js"
@@ -1 +1,64 @@
export * from "../../../domain/models/ingestSnapshot/factories.js"
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 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)
export const makeVerifiedPreviousRunManifest = (
manifest: RunManifest,
): VerifiedPreviousRunManifest => ({ _tag: "VerifiedPreviousRunManifest", manifest })
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,
): Error => ({
_tag: "SnapshotIngestHardStopped",
payload: { SnapshotIdentity: snapshotIdentity, Reason: reason },
})
+156 -1
View File
@@ -1 +1,156 @@
export * from "../../../domain/models/ingestSnapshot/ops.js"
import { Either } from "effect"
import {
isNonEmptyString,
type RunIdentity,
type SegmentRecord,
type SelectedSnapshot,
type SnapshotIdentity,
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 type {
DerivedRunIdentity,
Error,
RequiredArtifact,
TaintedBundleInput,
} from "./types.js"
const parseBundleLocationText = (location: string): string | null => {
const trimmedLocation = location.trim()
return trimmedLocation.length === 0 || !trimmedLocation.includes("/")
? null
: trimmedLocation
}
const decideSegmentRecordFailure = (
selectedSnapshot: SelectedSnapshot,
bundleLocation: string,
): Error | null => {
if (bundleLocation.includes("too-large")) {
return foldFailure(selectedSnapshot.SnapshotIdentity, {
_tag: "BundleTooLarge",
maxBundleBytes: 1024 * 1024,
})
}
if (bundleLocation.includes("budget-exceeded")) {
return foldFailure(selectedSnapshot.SnapshotIdentity, {
_tag: "ParseBudgetExceeded",
parseBudget: 50_000,
})
}
return null
}
export const parseBundleLocation = (
snapshotIdentity: SnapshotIdentity,
input: TaintedBundleInput,
): Either.Either<ReturnType<typeof makeTrustedBundleLocation>, Error> => {
const location = parseBundleLocationText(input.location as string)
return location === null
? Either.left(foldFailure(snapshotIdentity, "BundleNotParseable"))
: Either.right(makeTrustedBundleLocation(location))
}
export const applyRunIdentityRules = (
selectedSnapshot: SelectedSnapshot,
): Either.Either<DerivedRunIdentity, Error> => {
const snapshotIdentity = selectedSnapshot.SnapshotIdentity as string
return isNonEmptyString(snapshotIdentity)
? Either.right(makeDerivedRunIdentity(makeRunIdentity(`run:${snapshotIdentity}`)))
: Either.left(
foldFailure(
selectedSnapshot.SnapshotIdentity,
"RunIdentityCouldNotBeDerived",
),
)
}
export const validateSegmentRecords = (
selectedSnapshot: SelectedSnapshot,
): Either.Either<ReadonlyArray<SegmentRecord>, Error> => {
const snapshotIdentity = selectedSnapshot.SnapshotIdentity as string
const bundleLocation = selectedSnapshot.BundleLocation as string
const failure = decideSegmentRecordFailure(selectedSnapshot, bundleLocation)
if (failure) {
return Either.left(failure)
}
return Either.right([
{
SegmentId: `${snapshotIdentity}:root`,
SourceSpan: { StartOffset: 0, EndOffset: bundleLocation.length },
AstNodeKind: makeAstNodeKind("Program"),
CanonicalSource: `// canonical projection for ${snapshotIdentity}`,
Hashes: {
RawHash: makeRawHash(`raw:${snapshotIdentity}`),
NormalizedHash: makeNormalizedHash(`normalized:${snapshotIdentity}`),
ShapeHash: makeShapeHash(`shape:${snapshotIdentity}`),
},
},
])
}
export const validateBoundaryProofs = (
snapshotIdentity: SnapshotIdentity,
segmentRecords: ReadonlyArray<SegmentRecord>,
): Either.Either<ReadonlyArray<string>, Error> => {
const firstSegment = segmentRecords[0]
return firstSegment
? Either.right([`boundary:${firstSegment.SegmentId}`])
: Either.left(foldFailure(snapshotIdentity, "NoDeterministicBoundaryProven"))
}
export const validateRequiredArtifacts = (
snapshotIdentity: SnapshotIdentity,
requiredArtifacts: ReadonlyArray<RequiredArtifact>,
segmentRecords: ReadonlyArray<SegmentRecord>,
): Either.Either<ReadonlyArray<RequiredArtifact>, Error> => {
const missingArtifact = segmentRecords[0] ? null : requiredArtifacts[0]
return missingArtifact === null
? Either.right(requiredArtifacts)
: Either.left(
foldFailure(snapshotIdentity, {
_tag: "RequiredArtifactMissing",
artifact: missingArtifact ?? "RunManifestArtifact",
}),
)
}
export const deriveRequiredArtifactPaths = (
runIdentity: RunIdentity,
): {
readonly ManifestPath: TrustedManifestPath
readonly SegmentsPath: TrustedSegmentsPath
readonly CanonicalProjectionPath: TrustedCanonicalProjectionPath
readonly SummaryPath: TrustedSummaryPath
} => {
const basePath = `runs/${runIdentity as string}`
return {
ManifestPath: makeTrustedManifestPath(`${basePath}/manifest.json`),
SegmentsPath: makeTrustedSegmentsPath(`${basePath}/segments.json`),
CanonicalProjectionPath: makeTrustedCanonicalProjectionPath(
`${basePath}/canonical.ts`,
),
SummaryPath: makeTrustedSummaryPath(`${basePath}/summary.json`),
}
}
+102 -1
View File
@@ -1 +1,102 @@
export * from "../../../domain/models/ingestSnapshot/shared.js"
import { Schema } from "@effect/schema"
const NonEmptyString = Schema.String.pipe(
Schema.filter((value) => value.trim().length > 0),
)
export const SnapshotIdentity = Schema.String.pipe(Schema.brand("SnapshotIdentity"))
export type SnapshotIdentity = Schema.Schema.Type<typeof SnapshotIdentity>
export const TaintedBundleLocation = Schema.String.pipe(
Schema.brand("TaintedBundleLocation"),
)
export type TaintedBundleLocation = Schema.Schema.Type<typeof TaintedBundleLocation>
export const TrustedBundleLocation = Schema.String.pipe(
Schema.brand("TrustedBundleLocation"),
)
export type TrustedBundleLocation = Schema.Schema.Type<typeof TrustedBundleLocation>
export const RunIdentity = Schema.String.pipe(Schema.brand("RunIdentity"))
export type RunIdentity = Schema.Schema.Type<typeof RunIdentity>
export const AstNodeKind = Schema.String.pipe(Schema.brand("AstNodeKind"))
export type AstNodeKind = Schema.Schema.Type<typeof AstNodeKind>
export const RawHash = Schema.String.pipe(Schema.brand("RawHash"))
export type RawHash = Schema.Schema.Type<typeof RawHash>
export const NormalizedHash = Schema.String.pipe(Schema.brand("NormalizedHash"))
export type NormalizedHash = Schema.Schema.Type<typeof NormalizedHash>
export const ShapeHash = Schema.String.pipe(Schema.brand("ShapeHash"))
export type ShapeHash = Schema.Schema.Type<typeof ShapeHash>
export const TrustedManifestPath = Schema.String.pipe(
Schema.brand("TrustedManifestPath"),
)
export type TrustedManifestPath = Schema.Schema.Type<typeof TrustedManifestPath>
export const TrustedSegmentsPath = Schema.String.pipe(
Schema.brand("TrustedSegmentsPath"),
)
export type TrustedSegmentsPath = Schema.Schema.Type<typeof TrustedSegmentsPath>
export const TrustedCanonicalProjectionPath = Schema.String.pipe(
Schema.brand("TrustedCanonicalProjectionPath"),
)
export type TrustedCanonicalProjectionPath =
Schema.Schema.Type<typeof TrustedCanonicalProjectionPath>
export const TrustedSummaryPath = Schema.String.pipe(
Schema.brand("TrustedSummaryPath"),
)
export type TrustedSummaryPath = Schema.Schema.Type<typeof TrustedSummaryPath>
export const SourceSpan = Schema.Struct({
StartOffset: Schema.Number,
EndOffset: Schema.Number,
})
export type SourceSpan = Schema.Schema.Type<typeof SourceSpan>
export const SnapshotMetadata = Schema.Struct({
ReleaseNotesSource: Schema.NullOr(Schema.String),
CollectedAt: Schema.NullOr(Schema.String),
})
export type SnapshotMetadata = Schema.Schema.Type<typeof SnapshotMetadata>
export const SelectedSnapshot = Schema.Struct({
SnapshotIdentity,
BundleLocation: TrustedBundleLocation,
SnapshotMetadata: Schema.NullOr(SnapshotMetadata),
})
export type SelectedSnapshot = Schema.Schema.Type<typeof SelectedSnapshot>
export const SegmentHashes = Schema.Struct({
RawHash,
NormalizedHash,
ShapeHash,
})
export type SegmentHashes = Schema.Schema.Type<typeof SegmentHashes>
export const SegmentRecord = Schema.Struct({
SegmentId: Schema.String,
SourceSpan,
AstNodeKind,
CanonicalSource: Schema.String,
Hashes: SegmentHashes,
})
export type SegmentRecord = Schema.Schema.Type<typeof SegmentRecord>
export const RunManifest = Schema.Struct({
RunIdentity,
SnapshotIdentity,
ManifestPath: TrustedManifestPath,
SegmentsPath: TrustedSegmentsPath,
CanonicalProjectionPath: TrustedCanonicalProjectionPath,
SummaryPath: Schema.NullOr(TrustedSummaryPath),
})
export type RunManifest = Schema.Schema.Type<typeof RunManifest>
export const isNonEmptyString = (value: string): boolean =>
Schema.is(NonEmptyString)(value)
+103 -1
View File
@@ -1 +1,103 @@
export * from "../../../domain/models/ingestSnapshot/types.js"
import type {
RunIdentity,
RunManifest,
SegmentRecord,
SelectedSnapshot,
SnapshotIdentity,
SnapshotMetadata,
TrustedCanonicalProjectionPath,
TrustedSummaryPath,
TaintedBundleLocation,
} from "./shared.js"
export type VerifiedPreviousRunManifest = {
readonly _tag: "VerifiedPreviousRunManifest"
readonly manifest: RunManifest
}
export type TaintedBundleInput = {
readonly _tag: "TaintedBundleInput"
readonly location: TaintedBundleLocation
}
export type DerivedRunIdentity = {
readonly _tag: "DerivedRunIdentity"
readonly value: RunIdentity
}
export type RequiredArtifact =
| "RunManifestArtifact"
| "SegmentRecordsArtifact"
| "CanonicalProjectionArtifact"
export type IngestFailureReason =
| "BundleNotParseable"
| "RunIdentityCouldNotBeDerived"
| "PreviousRunManifestNotVerified"
| { readonly _tag: "BundleTooLarge"; readonly maxBundleBytes: number }
| { readonly _tag: "ParseBudgetExceeded"; readonly parseBudget: number }
| "NoDeterministicBoundaryProven"
| { readonly _tag: "RequiredArtifactMissing"; readonly artifact: RequiredArtifact }
export type IngestUpstreamSnapshot = {
readonly SnapshotIdentity: SnapshotIdentity
readonly BundleInput: TaintedBundleInput
readonly SnapshotMetadata: SnapshotMetadata | null
readonly PreviousRunManifest: VerifiedPreviousRunManifest | null
}
export type UpstreamSnapshotIngested = {
readonly RunManifest: RunManifest
readonly SegmentRecords: ReadonlyArray<SegmentRecord>
readonly CanonicalProjectionPath: TrustedCanonicalProjectionPath
readonly SummaryPath: TrustedSummaryPath | null
}
export type SnapshotIngestHardStopped = {
readonly SnapshotIdentity: SnapshotIdentity
readonly Reason: IngestFailureReason
}
export type Event = {
readonly _tag: "UpstreamSnapshotIngested"
readonly payload: UpstreamSnapshotIngested
}
export type Error = {
readonly _tag: "SnapshotIngestHardStopped"
readonly payload: SnapshotIngestHardStopped
}
export type AwaitingSnapshotSelection = {
readonly _tag: "AwaitingSnapshotSelection"
readonly RunIdentityRulesDescription: string
readonly BoundaryRulesDescription: string
readonly RequiredArtifacts: ReadonlyArray<RequiredArtifact>
readonly MaxBundleBytes: number
readonly ParseBudget: number
}
export type SnapshotReady = {
readonly _tag: "SnapshotReady"
readonly SelectedSnapshot: SelectedSnapshot
readonly PreviousRunManifest: VerifiedPreviousRunManifest | null
readonly RequiredArtifacts: ReadonlyArray<RequiredArtifact>
readonly MaxBundleBytes: number
readonly ParseBudget: number
}
export type DeterministicSegmentsReady = {
readonly _tag: "DeterministicSegmentsReady"
readonly RunIdentity: RunIdentity
readonly SelectedSnapshot: SelectedSnapshot
readonly PreviousRunManifest: VerifiedPreviousRunManifest | null
readonly SegmentRecords: ReadonlyArray<SegmentRecord>
readonly BoundaryProofs: ReadonlyArray<string>
readonly RequiredArtifacts: ReadonlyArray<RequiredArtifact>
}
export type State =
| AwaitingSnapshotSelection
| SnapshotReady
| DeterministicSegmentsReady
| ({ readonly _tag: "SnapshotIngested" } & UpstreamSnapshotIngested)
@@ -9,14 +9,12 @@ import {
type State,
type UpstreamSnapshotIngested,
deriveRequiredArtifactPaths,
} from "../domain/models/IngestSnapshot.js"
import {
decideSegmentRecords,
} from "./ingestSnapshot/segments.js"
} from "../index.js"
import { decideSegmentRecords } from "./segments.js"
import {
validatePreviousRunManifest,
validateSnapshotSelection,
} from "./ingestSnapshot/selection.js"
} from "./selection.js"
const toEvent = (
deterministicSegmentsReady: DeterministicSegmentsReady,
@@ -1 +1,42 @@
export * from "../../../policies/ingestSnapshot/segments.js"
import { Either } from "effect"
import {
type DeterministicSegmentsReady,
type Error,
type SnapshotReady,
applyRunIdentityRules,
validateBoundaryProofs,
validateRequiredArtifacts,
validateSegmentRecords,
} from "../index.js"
export const decideSegmentRecords = (
snapshotReady: SnapshotReady,
): Either.Either<DeterministicSegmentsReady, Error> =>
Either.flatMap(applyRunIdentityRules(snapshotReady.SelectedSnapshot), (derivedRunIdentity) =>
Either.flatMap(validateSegmentRecords(snapshotReady.SelectedSnapshot), (segmentRecords) =>
Either.flatMap(
validateBoundaryProofs(
snapshotReady.SelectedSnapshot.SnapshotIdentity,
segmentRecords,
),
(boundaryProofs) =>
Either.map(
validateRequiredArtifacts(
snapshotReady.SelectedSnapshot.SnapshotIdentity,
snapshotReady.RequiredArtifacts,
segmentRecords,
),
() => ({
_tag: "DeterministicSegmentsReady" as const,
RunIdentity: derivedRunIdentity.value,
SelectedSnapshot: snapshotReady.SelectedSnapshot,
PreviousRunManifest: snapshotReady.PreviousRunManifest,
SegmentRecords: segmentRecords,
BoundaryProofs: boundaryProofs,
RequiredArtifacts: snapshotReady.RequiredArtifacts,
}),
),
),
),
)
@@ -1 +1,48 @@
export * from "../../../policies/ingestSnapshot/selection.js"
import { Either } from "effect"
import {
type Error,
type IngestUpstreamSnapshot,
type RunManifest,
type SnapshotReady,
type State,
foldFailure,
makeVerifiedPreviousRunManifest,
parseBundleLocation,
} from "../index.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 validateSnapshotSelection = (
state: State,
command: IngestUpstreamSnapshot,
): Either.Either<SnapshotReady, Error> => {
if (state._tag !== "AwaitingSnapshotSelection") {
return Either.left(
foldFailure(command.SnapshotIdentity, "RunIdentityCouldNotBeDerived"),
)
}
return Either.map(
parseBundleLocation(command.SnapshotIdentity, command.BundleInput),
(bundleLocation) => ({
_tag: "SnapshotReady" as const,
SelectedSnapshot: {
SnapshotIdentity: command.SnapshotIdentity,
BundleLocation: bundleLocation,
SnapshotMetadata: command.SnapshotMetadata,
},
PreviousRunManifest: command.PreviousRunManifest,
RequiredArtifacts: state.RequiredArtifacts,
MaxBundleBytes: state.MaxBundleBytes,
ParseBudget: state.ParseBudget,
}),
)
}
@@ -1 +1,22 @@
export * from "../../../workflows/ingestSnapshot.js"
import { Effect, Either } from "effect"
import {
type Error,
type Event,
type IngestUpstreamSnapshot,
type State,
decide,
makeAwaitingSnapshotSelection,
} from "../index.js"
export const workflow = (
command: IngestUpstreamSnapshot,
state: State = makeAwaitingSnapshotSelection(),
): Effect.Effect<Event, Error> =>
Effect.gen(function* () {
const decision = decide(state, command)
if (Either.isLeft(decision)) {
return yield* Effect.fail(decision.left)
}
return decision.right
})
-4
View File
@@ -1,4 +0,0 @@
export * from "./ingestSnapshot/shared.js"
export * from "./ingestSnapshot/types.js"
export * from "./ingestSnapshot/factories.js"
export * from "./ingestSnapshot/ops.js"
@@ -1,64 +0,0 @@
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 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)
export const makeVerifiedPreviousRunManifest = (
manifest: RunManifest,
): VerifiedPreviousRunManifest => ({ _tag: "VerifiedPreviousRunManifest", manifest })
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,
): Error => ({
_tag: "SnapshotIngestHardStopped",
payload: { SnapshotIdentity: snapshotIdentity, Reason: reason },
})
-156
View File
@@ -1,156 +0,0 @@
import { Either } from "effect"
import {
isNonEmptyString,
type RunIdentity,
type SegmentRecord,
type SelectedSnapshot,
type SnapshotIdentity,
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 type {
DerivedRunIdentity,
Error,
RequiredArtifact,
TaintedBundleInput,
} from "./types.js"
const parseBundleLocationText = (location: string): string | null => {
const trimmedLocation = location.trim()
return trimmedLocation.length === 0 || !trimmedLocation.includes("/")
? null
: trimmedLocation
}
const decideSegmentRecordFailure = (
selectedSnapshot: SelectedSnapshot,
bundleLocation: string,
): Error | null => {
if (bundleLocation.includes("too-large")) {
return foldFailure(selectedSnapshot.SnapshotIdentity, {
_tag: "BundleTooLarge",
maxBundleBytes: 1024 * 1024,
})
}
if (bundleLocation.includes("budget-exceeded")) {
return foldFailure(selectedSnapshot.SnapshotIdentity, {
_tag: "ParseBudgetExceeded",
parseBudget: 50_000,
})
}
return null
}
export const parseBundleLocation = (
snapshotIdentity: SnapshotIdentity,
input: TaintedBundleInput,
): Either.Either<ReturnType<typeof makeTrustedBundleLocation>, Error> => {
const location = parseBundleLocationText(input.location as string)
return location === null
? Either.left(foldFailure(snapshotIdentity, "BundleNotParseable"))
: Either.right(makeTrustedBundleLocation(location))
}
export const applyRunIdentityRules = (
selectedSnapshot: SelectedSnapshot,
): Either.Either<DerivedRunIdentity, Error> => {
const snapshotIdentity = selectedSnapshot.SnapshotIdentity as string
return isNonEmptyString(snapshotIdentity)
? Either.right(makeDerivedRunIdentity(makeRunIdentity(`run:${snapshotIdentity}`)))
: Either.left(
foldFailure(
selectedSnapshot.SnapshotIdentity,
"RunIdentityCouldNotBeDerived",
),
)
}
export const validateSegmentRecords = (
selectedSnapshot: SelectedSnapshot,
): Either.Either<ReadonlyArray<SegmentRecord>, Error> => {
const snapshotIdentity = selectedSnapshot.SnapshotIdentity as string
const bundleLocation = selectedSnapshot.BundleLocation as string
const failure = decideSegmentRecordFailure(selectedSnapshot, bundleLocation)
if (failure) {
return Either.left(failure)
}
return Either.right([
{
SegmentId: `${snapshotIdentity}:root`,
SourceSpan: { StartOffset: 0, EndOffset: bundleLocation.length },
AstNodeKind: makeAstNodeKind("Program"),
CanonicalSource: `// canonical projection for ${snapshotIdentity}`,
Hashes: {
RawHash: makeRawHash(`raw:${snapshotIdentity}`),
NormalizedHash: makeNormalizedHash(`normalized:${snapshotIdentity}`),
ShapeHash: makeShapeHash(`shape:${snapshotIdentity}`),
},
},
])
}
export const validateBoundaryProofs = (
snapshotIdentity: SnapshotIdentity,
segmentRecords: ReadonlyArray<SegmentRecord>,
): Either.Either<ReadonlyArray<string>, Error> => {
const firstSegment = segmentRecords[0]
return firstSegment
? Either.right([`boundary:${firstSegment.SegmentId}`])
: Either.left(foldFailure(snapshotIdentity, "NoDeterministicBoundaryProven"))
}
export const validateRequiredArtifacts = (
snapshotIdentity: SnapshotIdentity,
requiredArtifacts: ReadonlyArray<RequiredArtifact>,
segmentRecords: ReadonlyArray<SegmentRecord>,
): Either.Either<ReadonlyArray<RequiredArtifact>, Error> => {
const missingArtifact = segmentRecords[0] ? null : requiredArtifacts[0]
return missingArtifact === null
? Either.right(requiredArtifacts)
: Either.left(
foldFailure(snapshotIdentity, {
_tag: "RequiredArtifactMissing",
artifact: missingArtifact ?? "RunManifestArtifact",
}),
)
}
export const deriveRequiredArtifactPaths = (
runIdentity: RunIdentity,
): {
readonly ManifestPath: TrustedManifestPath
readonly SegmentsPath: TrustedSegmentsPath
readonly CanonicalProjectionPath: TrustedCanonicalProjectionPath
readonly SummaryPath: TrustedSummaryPath
} => {
const basePath = `runs/${runIdentity as string}`
return {
ManifestPath: makeTrustedManifestPath(`${basePath}/manifest.json`),
SegmentsPath: makeTrustedSegmentsPath(`${basePath}/segments.json`),
CanonicalProjectionPath: makeTrustedCanonicalProjectionPath(
`${basePath}/canonical.ts`,
),
SummaryPath: makeTrustedSummaryPath(`${basePath}/summary.json`),
}
}
-102
View File
@@ -1,102 +0,0 @@
import { Schema } from "@effect/schema"
const NonEmptyString = Schema.String.pipe(
Schema.filter((value) => value.trim().length > 0),
)
export const SnapshotIdentity = Schema.String.pipe(Schema.brand("SnapshotIdentity"))
export type SnapshotIdentity = Schema.Schema.Type<typeof SnapshotIdentity>
export const TaintedBundleLocation = Schema.String.pipe(
Schema.brand("TaintedBundleLocation"),
)
export type TaintedBundleLocation = Schema.Schema.Type<typeof TaintedBundleLocation>
export const TrustedBundleLocation = Schema.String.pipe(
Schema.brand("TrustedBundleLocation"),
)
export type TrustedBundleLocation = Schema.Schema.Type<typeof TrustedBundleLocation>
export const RunIdentity = Schema.String.pipe(Schema.brand("RunIdentity"))
export type RunIdentity = Schema.Schema.Type<typeof RunIdentity>
export const AstNodeKind = Schema.String.pipe(Schema.brand("AstNodeKind"))
export type AstNodeKind = Schema.Schema.Type<typeof AstNodeKind>
export const RawHash = Schema.String.pipe(Schema.brand("RawHash"))
export type RawHash = Schema.Schema.Type<typeof RawHash>
export const NormalizedHash = Schema.String.pipe(Schema.brand("NormalizedHash"))
export type NormalizedHash = Schema.Schema.Type<typeof NormalizedHash>
export const ShapeHash = Schema.String.pipe(Schema.brand("ShapeHash"))
export type ShapeHash = Schema.Schema.Type<typeof ShapeHash>
export const TrustedManifestPath = Schema.String.pipe(
Schema.brand("TrustedManifestPath"),
)
export type TrustedManifestPath = Schema.Schema.Type<typeof TrustedManifestPath>
export const TrustedSegmentsPath = Schema.String.pipe(
Schema.brand("TrustedSegmentsPath"),
)
export type TrustedSegmentsPath = Schema.Schema.Type<typeof TrustedSegmentsPath>
export const TrustedCanonicalProjectionPath = Schema.String.pipe(
Schema.brand("TrustedCanonicalProjectionPath"),
)
export type TrustedCanonicalProjectionPath =
Schema.Schema.Type<typeof TrustedCanonicalProjectionPath>
export const TrustedSummaryPath = Schema.String.pipe(
Schema.brand("TrustedSummaryPath"),
)
export type TrustedSummaryPath = Schema.Schema.Type<typeof TrustedSummaryPath>
export const SourceSpan = Schema.Struct({
StartOffset: Schema.Number,
EndOffset: Schema.Number,
})
export type SourceSpan = Schema.Schema.Type<typeof SourceSpan>
export const SnapshotMetadata = Schema.Struct({
ReleaseNotesSource: Schema.NullOr(Schema.String),
CollectedAt: Schema.NullOr(Schema.String),
})
export type SnapshotMetadata = Schema.Schema.Type<typeof SnapshotMetadata>
export const SelectedSnapshot = Schema.Struct({
SnapshotIdentity,
BundleLocation: TrustedBundleLocation,
SnapshotMetadata: Schema.NullOr(SnapshotMetadata),
})
export type SelectedSnapshot = Schema.Schema.Type<typeof SelectedSnapshot>
export const SegmentHashes = Schema.Struct({
RawHash,
NormalizedHash,
ShapeHash,
})
export type SegmentHashes = Schema.Schema.Type<typeof SegmentHashes>
export const SegmentRecord = Schema.Struct({
SegmentId: Schema.String,
SourceSpan,
AstNodeKind,
CanonicalSource: Schema.String,
Hashes: SegmentHashes,
})
export type SegmentRecord = Schema.Schema.Type<typeof SegmentRecord>
export const RunManifest = Schema.Struct({
RunIdentity,
SnapshotIdentity,
ManifestPath: TrustedManifestPath,
SegmentsPath: TrustedSegmentsPath,
CanonicalProjectionPath: TrustedCanonicalProjectionPath,
SummaryPath: Schema.NullOr(TrustedSummaryPath),
})
export type RunManifest = Schema.Schema.Type<typeof RunManifest>
export const isNonEmptyString = (value: string): boolean =>
Schema.is(NonEmptyString)(value)
-103
View File
@@ -1,103 +0,0 @@
import type {
RunIdentity,
RunManifest,
SegmentRecord,
SelectedSnapshot,
SnapshotIdentity,
SnapshotMetadata,
TrustedCanonicalProjectionPath,
TrustedSummaryPath,
TaintedBundleLocation,
} from "./shared.js"
export type VerifiedPreviousRunManifest = {
readonly _tag: "VerifiedPreviousRunManifest"
readonly manifest: RunManifest
}
export type TaintedBundleInput = {
readonly _tag: "TaintedBundleInput"
readonly location: TaintedBundleLocation
}
export type DerivedRunIdentity = {
readonly _tag: "DerivedRunIdentity"
readonly value: RunIdentity
}
export type RequiredArtifact =
| "RunManifestArtifact"
| "SegmentRecordsArtifact"
| "CanonicalProjectionArtifact"
export type IngestFailureReason =
| "BundleNotParseable"
| "RunIdentityCouldNotBeDerived"
| "PreviousRunManifestNotVerified"
| { readonly _tag: "BundleTooLarge"; readonly maxBundleBytes: number }
| { readonly _tag: "ParseBudgetExceeded"; readonly parseBudget: number }
| "NoDeterministicBoundaryProven"
| { readonly _tag: "RequiredArtifactMissing"; readonly artifact: RequiredArtifact }
export type IngestUpstreamSnapshot = {
readonly SnapshotIdentity: SnapshotIdentity
readonly BundleInput: TaintedBundleInput
readonly SnapshotMetadata: SnapshotMetadata | null
readonly PreviousRunManifest: VerifiedPreviousRunManifest | null
}
export type UpstreamSnapshotIngested = {
readonly RunManifest: RunManifest
readonly SegmentRecords: ReadonlyArray<SegmentRecord>
readonly CanonicalProjectionPath: TrustedCanonicalProjectionPath
readonly SummaryPath: TrustedSummaryPath | null
}
export type SnapshotIngestHardStopped = {
readonly SnapshotIdentity: SnapshotIdentity
readonly Reason: IngestFailureReason
}
export type Event = {
readonly _tag: "UpstreamSnapshotIngested"
readonly payload: UpstreamSnapshotIngested
}
export type Error = {
readonly _tag: "SnapshotIngestHardStopped"
readonly payload: SnapshotIngestHardStopped
}
export type AwaitingSnapshotSelection = {
readonly _tag: "AwaitingSnapshotSelection"
readonly RunIdentityRulesDescription: string
readonly BoundaryRulesDescription: string
readonly RequiredArtifacts: ReadonlyArray<RequiredArtifact>
readonly MaxBundleBytes: number
readonly ParseBudget: number
}
export type SnapshotReady = {
readonly _tag: "SnapshotReady"
readonly SelectedSnapshot: SelectedSnapshot
readonly PreviousRunManifest: VerifiedPreviousRunManifest | null
readonly RequiredArtifacts: ReadonlyArray<RequiredArtifact>
readonly MaxBundleBytes: number
readonly ParseBudget: number
}
export type DeterministicSegmentsReady = {
readonly _tag: "DeterministicSegmentsReady"
readonly RunIdentity: RunIdentity
readonly SelectedSnapshot: SelectedSnapshot
readonly PreviousRunManifest: VerifiedPreviousRunManifest | null
readonly SegmentRecords: ReadonlyArray<SegmentRecord>
readonly BoundaryProofs: ReadonlyArray<string>
readonly RequiredArtifacts: ReadonlyArray<RequiredArtifact>
}
export type State =
| AwaitingSnapshotSelection
| SnapshotReady
| DeterministicSegmentsReady
| ({ readonly _tag: "SnapshotIngested" } & UpstreamSnapshotIngested)
-42
View File
@@ -1,42 +0,0 @@
import { Either } from "effect"
import {
type DeterministicSegmentsReady,
type Error,
type SnapshotReady,
applyRunIdentityRules,
validateBoundaryProofs,
validateRequiredArtifacts,
validateSegmentRecords,
} from "../../domain/models/IngestSnapshot.js"
export const decideSegmentRecords = (
snapshotReady: SnapshotReady,
): Either.Either<DeterministicSegmentsReady, Error> =>
Either.flatMap(applyRunIdentityRules(snapshotReady.SelectedSnapshot), (derivedRunIdentity) =>
Either.flatMap(validateSegmentRecords(snapshotReady.SelectedSnapshot), (segmentRecords) =>
Either.flatMap(
validateBoundaryProofs(
snapshotReady.SelectedSnapshot.SnapshotIdentity,
segmentRecords,
),
(boundaryProofs) =>
Either.map(
validateRequiredArtifacts(
snapshotReady.SelectedSnapshot.SnapshotIdentity,
snapshotReady.RequiredArtifacts,
segmentRecords,
),
() => ({
_tag: "DeterministicSegmentsReady" as const,
RunIdentity: derivedRunIdentity.value,
SelectedSnapshot: snapshotReady.SelectedSnapshot,
PreviousRunManifest: snapshotReady.PreviousRunManifest,
SegmentRecords: segmentRecords,
BoundaryProofs: boundaryProofs,
RequiredArtifacts: snapshotReady.RequiredArtifacts,
}),
),
),
),
)
-48
View File
@@ -1,48 +0,0 @@
import { Either } from "effect"
import {
type Error,
type IngestUpstreamSnapshot,
type RunManifest,
type SnapshotReady,
type State,
foldFailure,
makeVerifiedPreviousRunManifest,
parseBundleLocation,
} from "../../domain/models/IngestSnapshot.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 validateSnapshotSelection = (
state: State,
command: IngestUpstreamSnapshot,
): Either.Either<SnapshotReady, Error> => {
if (state._tag !== "AwaitingSnapshotSelection") {
return Either.left(
foldFailure(command.SnapshotIdentity, "RunIdentityCouldNotBeDerived"),
)
}
return Either.map(
parseBundleLocation(command.SnapshotIdentity, command.BundleInput),
(bundleLocation) => ({
_tag: "SnapshotReady" as const,
SelectedSnapshot: {
SnapshotIdentity: command.SnapshotIdentity,
BundleLocation: bundleLocation,
SnapshotMetadata: command.SnapshotMetadata,
},
PreviousRunManifest: command.PreviousRunManifest,
RequiredArtifacts: state.RequiredArtifacts,
MaxBundleBytes: state.MaxBundleBytes,
ParseBudget: state.ParseBudget,
}),
)
}
-21
View File
@@ -1,21 +0,0 @@
import { Effect, Either } from "effect"
import {
type Error,
type Event,
type IngestUpstreamSnapshot,
type State,
} from "../domain/models/IngestSnapshot.js"
import { decide, makeAwaitingSnapshotSelection } from "../policies/decideSnapshotIngest.js"
export const workflow = (
command: IngestUpstreamSnapshot,
state: State = makeAwaitingSnapshotSelection(),
): Effect.Effect<Event, Error> =>
Effect.gen(function* () {
const decision = decide(state, command)
if (Either.isLeft(decision)) {
return yield* Effect.fail(decision.left)
}
return decision.right
})