From 44d9d2065c7c9c2262d1fb8a52ca08a27acde14d Mon Sep 17 00:00:00 2001 From: Elizabeth W Date: Mon, 25 May 2026 01:19:10 -0600 Subject: [PATCH] ingest blueprint phase --- design/feature/recovery-pipeline/status.md | 14 +-- .../04-blueprint.fs | 90 +++++++++++++++++++ .../workflows/ingest-snapshot/shared-model.fs | 60 +++++++++++++ 3 files changed, 157 insertions(+), 7 deletions(-) create mode 100644 design/workflows/ingest-snapshot/deterministic-bundle-ingest/04-blueprint.fs create mode 100644 design/workflows/ingest-snapshot/shared-model.fs diff --git a/design/feature/recovery-pipeline/status.md b/design/feature/recovery-pipeline/status.md index c49b4c7..03b8aae 100644 --- a/design/feature/recovery-pipeline/status.md +++ b/design/feature/recovery-pipeline/status.md @@ -40,7 +40,7 @@ | Bounded Context | Workflow Slice | Slice Discovery | Core Sketch | Blueprint | Design Security | Assembly | Impl Security | Refactor | Notes | | :-------------- | :------------- | :-------------- | :---------- | :-------- | :-------------- | :------- | :------------ | :------- | :---- | -| `ingest-snapshot` | `deterministic-bundle-ingest` | `Complete` | `Complete` | `Ready` | `Not Started` | `Not Started` | `Not Started` | `Not Started` | `Foundational source-of-truth slice.` | +| `ingest-snapshot` | `deterministic-bundle-ingest` | `Complete` | `Complete` | `Complete` | `Ready` | `Not Started` | `Not Started` | `Not Started` | `Foundational source-of-truth slice.` | | `dependency-recovery` | `identify-vendored-packages` | `Not Started` | `Not Started` | `Not Started` | `Not Started` | `Not Started` | `Not Started` | `Not Started` | `Shrinks app-authored surface before later phases.` | | `dependency-recovery` | `externalize-accepted-dependencies` | `Not Started` | `Not Started` | `Not Started` | `Not Started` | `Not Started` | `Not Started` | `Not Started` | `Depends on package identification decisions.` | | `static-context-evidence` | `extract-segment-context` | `Not Started` | `Not Started` | `Not Started` | `Not Started` | `Not Started` | `Not Started` | `Not Started` | `Produces deterministic evidence for downstream consumers.` | @@ -75,12 +75,12 @@ ### Blueprint Gate -- [ ] domain types make illegal states harder to express -- [ ] shared concepts reused appropriately -- [ ] policy is pure -- [ ] reducer/apply shape is explicit -- [ ] workflow contract is explicit -- [ ] approved for design security review or assembly +- [x] domain types make illegal states harder to express +- [x] shared concepts reused appropriately +- [x] policy is pure +- [x] reducer/apply shape is explicit +- [x] workflow contract is explicit +- [x] approved for design security review or assembly ### Design Security Gate diff --git a/design/workflows/ingest-snapshot/deterministic-bundle-ingest/04-blueprint.fs b/design/workflows/ingest-snapshot/deterministic-bundle-ingest/04-blueprint.fs new file mode 100644 index 0000000..1189fee --- /dev/null +++ b/design/workflows/ingest-snapshot/deterministic-bundle-ingest/04-blueprint.fs @@ -0,0 +1,90 @@ +module IngestSnapshot.DeterministicBundleIngest + +open IngestSnapshot.SharedModel + +// 1. Primitives + +type TaintedBundleInput = TaintedBundleInput of BundleSource + +type DerivedRunIdentity = DerivedRunIdentity of RunIdentity + +type BoundaryProof = BoundaryProof of string + +type RequiredArtifact = + | RunManifestArtifact + | SegmentRecordsArtifact + | CanonicalProjectionArtifact + +type IngestFailureReason = + | BundleNotParseable + | RunIdentityCouldNotBeDerived + | NoDeterministicBoundaryProven + | RequiredArtifactMissing of RequiredArtifact + +// 2. Commands (Inputs) + +type IngestUpstreamSnapshot = + { SnapshotIdentity: SnapshotIdentity + BundleInput: TaintedBundleInput + SnapshotMetadata: SnapshotMetadata option + PreviousRunManifest: RunManifest option } + +// 3. Events (Facts) + +type UpstreamSnapshotIngested = + { RunManifest: RunManifest + SegmentRecords: SegmentRecord list + CanonicalProjectionPath: CanonicalProjectionPath + SummaryPath: SummaryPath option } + +type SnapshotIngestHardStopped = + { SnapshotIdentity: SnapshotIdentity + Reason: IngestFailureReason } + +type Event = + | UpstreamSnapshotIngested of UpstreamSnapshotIngested + +// 4. Errors + +type Error = + | SnapshotIngestHardStopped of SnapshotIngestHardStopped + +// 5. State (Aggregates) + +type AwaitingSnapshotSelection = + { RunIdentityRulesDescription: string + BoundaryRulesDescription: string + RequiredArtifacts: RequiredArtifact list } + +type SnapshotReady = + { SelectedSnapshot: SelectedSnapshot + PreviousRunManifest: RunManifest option + RequiredArtifacts: RequiredArtifact list } + +type DeterministicSegmentsReady = + { RunIdentity: RunIdentity + SelectedSnapshot: SelectedSnapshot + PreviousRunManifest: RunManifest option + SegmentRecords: SegmentRecord list + BoundaryProofs: BoundaryProof list + RequiredArtifacts: RequiredArtifact list } + +type State = + | AwaitingSnapshotSelection of AwaitingSnapshotSelection + | SnapshotReady of SnapshotReady + | DeterministicSegmentsReady of DeterministicSegmentsReady + | SnapshotIngested of UpstreamSnapshotIngested + +// 6. Contract Signatures + +val deriveRunIdentity : SelectedSnapshot -> Result + +val validateSnapshotSelection : State -> IngestUpstreamSnapshot -> Result + +val decideSegmentRecords : SnapshotReady -> Result + +val decide : State -> IngestUpstreamSnapshot -> Result + +val apply : State -> Event -> State + +val workflow : IngestUpstreamSnapshot -> Effect.Effect> diff --git a/design/workflows/ingest-snapshot/shared-model.fs b/design/workflows/ingest-snapshot/shared-model.fs new file mode 100644 index 0000000..c395176 --- /dev/null +++ b/design/workflows/ingest-snapshot/shared-model.fs @@ -0,0 +1,60 @@ +module IngestSnapshot.SharedModel + +// 1. Shared primitives + +type SnapshotIdentity = SnapshotIdentity of string + +type BundleSource = BundleSource of string + +type RunIdentity = RunIdentity of string + +type SourceSpan = + { StartOffset: int + EndOffset: int } + +type AstNodeKind = AstNodeKind of string + +type RawHash = RawHash of string + +type NormalizedHash = NormalizedHash of string + +type ShapeHash = ShapeHash of string + +type ManifestPath = ManifestPath of string + +type SegmentsPath = SegmentsPath of string + +type CanonicalProjectionPath = CanonicalProjectionPath of string + +type SummaryPath = SummaryPath of string + +// 2. Shared compounds + +type SnapshotMetadata = + { ReleaseNotesSource: string option + CollectedAt: string option } + +type SelectedSnapshot = + { SnapshotIdentity: SnapshotIdentity + BundleSource: BundleSource + SnapshotMetadata: SnapshotMetadata option } + +type SegmentHashes = + { RawHash: RawHash + NormalizedHash: NormalizedHash + ShapeHash: ShapeHash } + +type SegmentRecord = + { SegmentId: string + SourceSpan: SourceSpan + AstNodeKind: AstNodeKind + CanonicalSource: string + Hashes: SegmentHashes } + +type RunManifest = + { RunIdentity: RunIdentity + SnapshotIdentity: SnapshotIdentity + ManifestPath: ManifestPath + SegmentsPath: SegmentsPath + CanonicalProjectionPath: CanonicalProjectionPath + SummaryPath: SummaryPath option }