# Research: BaselineSnapshot Artifact Truth & Downstream Consumption Guards ## Decision 1: Model BaselineSnapshot with a single persisted lifecycle enum and derived historical truth in V1 - Decision: Add a first-class BaselineSnapshot lifecycle state with `building`, `complete`, and `incomplete`, and derive historical `superseded` truth in presentation/resolution instead of persisting it as a lifecycle mutation. - Rationale: The spec is intentionally narrow to BaselineSnapshot, but the constitution requires snapshots to remain immutable. A persisted three-state lifecycle is enough to separate artifact truth from run truth, while derived historical status lets the UI communicate that a snapshot is no longer current without mutating immutable artifacts. - Alternatives considered: - Separate lifecycle and historical-status enums. Rejected for V1 because it adds more schema and UI complexity than the spec requires. - Persisted `superseded` lifecycle mutation. Rejected because it conflicts with the constitution rule that snapshots and backups remain immutable. - Generic polymorphic artifact-state framework. Rejected because the spec explicitly limits scope to BaselineSnapshot. ## Decision 2: Keep staged item persistence and add explicit finalization instead of rewriting capture into one large transaction - Decision: Preserve the existing deduplicated, chunked item-persistence strategy in `CaptureBaselineSnapshotJob`, but make snapshot creation begin in `building` and add an explicit finalization checkpoint before the snapshot can become `complete`. - Rationale: The current job already deduplicates item payloads and inserts items in chunks. Replacing that with one large transaction would be a broader persistence rewrite with higher regression risk. The core integrity defect is not the existence of staged persistence; it is the lack of explicit artifact finalization and unusable-state marking when staged persistence fails. - Alternatives considered: - Wrap snapshot row plus all item writes in one transaction. Rejected because it is a larger behavioral change, can increase lock duration, and is not necessary to satisfy the artifact-truth invariant. - Delete snapshot rows on failure. Rejected because the spec allows retaining incomplete artifacts for diagnostics and auditability. ## Decision 3: Treat `active_snapshot_id` as a cached pointer to the latest complete snapshot only - Decision: Keep `baseline_profiles.active_snapshot_id`, but tighten its semantics so it may point only to a complete snapshot. Effective baseline truth resolves from complete snapshots, not from the latest attempt. - Rationale: Existing services, stats objects, and Filament resources already use `active_snapshot_id` heavily. Replacing it wholesale would create unnecessary churn. Tightening its meaning and adding a shared effective-snapshot resolver keeps compatibility while enforcing the new truth rule. - Alternatives considered: - Remove `active_snapshot_id` and resolve current truth only by querying snapshots. Rejected because it would require broader UI/service refactoring and lose a useful current-pointer optimization. - Leave `active_snapshot_id` semantics unchanged and only add compare-time checks. Rejected because profile truth and UI would still silently advance to incomplete snapshots. ## Decision 4: Use a centralized consumability/effective-truth service or helper for capture, compare, and UI - Decision: Introduce one authoritative domain path for determining whether a snapshot is consumable and which snapshot is the effective current baseline for a profile. - Rationale: The current code assumes snapshot validity in multiple places: capture promotion, compare start, compare execution, stats, and UI. Duplicated state checks would drift. A central resolver keeps the rule enforceable and testable. - Alternatives considered: - Inline `status === complete` checks in each service/page. Rejected because that duplicates rules and invites inconsistent handling of superseded or legacy snapshots. - Put all logic only on the Eloquent model. Rejected because effective-truth resolution involves profile-level fallback rules, legacy handling, and operator-safe reason codes that fit better in a domain service/helper. ## Decision 5: Backfill legacy snapshots conservatively using proof, not assumption - Decision: Backfill historical snapshots as `complete` only when completion can be proven from persisted item counts, `summary_jsonb`, and producing-run context where available. Mark ambiguous rows `incomplete`. - Rationale: The defect being fixed is silent trust in partial artifacts. Blindly backfilling historical rows as complete would reintroduce the same governance-integrity problem under a new label. Conservative backfill is aligned with the spec and with the platform’s fail-safe posture. - Alternatives considered: - Mark every legacy snapshot `complete`. Rejected because it makes historical ambiguity look trustworthy. - Mark every legacy snapshot `incomplete`. Rejected because it would unnecessarily invalidate proven-good history and create avoidable recapture churn. ## Decision 6: Completion proof must allow valid empty captures only when emptiness is explicitly proven - Decision: Allow a snapshot to become `complete` with zero items only when the capture completed cleanly and the scope/result proves there were zero subjects to capture. Otherwise, zero items are not enough to infer completeness. - Rationale: Existing tests allow empty captures for zero-subject scopes, and a zero-subject baseline can still be a valid outcome. The important distinction is between intentionally empty and ambiguously incomplete. - Alternatives considered: - Require at least one item for every complete snapshot. Rejected because it would make legitimate empty captures impossible. - Treat any zero-item snapshot as complete. Rejected because it would misclassify failures that occurred before meaningful assembly. ## Decision 7: Reuse the existing artifact-truth and badge infrastructure for presentation - Decision: Extend the existing `ArtifactTruthPresenter` and badge registration patterns for BaselineSnapshot lifecycle and usability rather than creating a new snapshot-specific presentation system. - Rationale: The repo already centralizes artifact truth across EvidenceSnapshot, TenantReview, ReviewPack, and OperationRun. Reusing that system keeps state labels, colors, and operator explanations consistent and satisfies BADGE-001. - Alternatives considered: - Add ad-hoc state rendering in each Filament resource/page. Rejected because it would violate badge centralization and drift across surfaces. - Introduce a separate baseline-only presenter. Rejected because the existing artifact-truth envelope already models the required dimensions.