The import command's pre-replay validation pass runs at Level 2: it confirms each NDJSON record has a known EventType and a payload that parses as a JSON object. This catches file-corruption failure modes (truncation, encoding errors, hand-edits that broke JSON) but does not catch version-skew failures — e.g. an export from an older wherehouse missing a payload field that a newer event handler requires.
Level 3 would unmarshal each payload into its event-type-specific struct (the same struct the handler in internal/eventbus uses), surfacing schema mismatches before ClearAllData runs.
Why this is deferred (Level 2 chosen)
- Level 3 requires the app layer to reach into per-event-type payload schemas currently owned by
internal/eventbus, which is a layering decision that deserves its own ADR.
- Level 2 already covers the failure modes seen in practice (corrupted backup files, truncated streams, garbage masquerading as NDJSON).
- Version-skew is a real but rarer scenario; today there are no version-skewed exports in the wild to validate against.
When to revisit
- After the first reported "import --replace cleared my DB then failed mid-replay because of a missing payload field" incident.
- Before any breaking change to a payload schema (would need this validation to protect users importing pre-change backups).
- If/when a payload-schema registry is introduced for other reasons.
References
- Level 2 validation introduced in commit
4d3208adec240b89d38cbb34dbd4d4e0a9676445
- ADR 0004 (import uses ReplayEvent)
- ADR 0005 (path-changed validation pattern)
- CLAUDE.md "No silent repair" invariant
The import command's pre-replay validation pass runs at Level 2: it confirms each NDJSON record has a known EventType and a payload that parses as a JSON object. This catches file-corruption failure modes (truncation, encoding errors, hand-edits that broke JSON) but does not catch version-skew failures — e.g. an export from an older wherehouse missing a payload field that a newer event handler requires.
Level 3 would unmarshal each payload into its event-type-specific struct (the same struct the handler in
internal/eventbususes), surfacing schema mismatches beforeClearAllDataruns.Why this is deferred (Level 2 chosen)
internal/eventbus, which is a layering decision that deserves its own ADR.When to revisit
References
4d3208adec240b89d38cbb34dbd4d4e0a9676445