The compiled value-domain validation form: replaces the interpretive
BastDoc walk in validate_bytes with a compile-once-walk-many
constraint tree built at engine-compile time. This was the design
session + implementation ADR-012 §3 delegated; the shape decisions
are recorded in new ADR-012 §3a.
- New src/validation_plan.rs: ValidationPlan + ValidNode/ValidField/
ValidVariant (Debug+Clone+PartialEq+Eq+Hash+Send+Sync),
compile(&BastDoc) with eager $ref resolution, and a per-buffer walk
with deferred error-path rendering (zero happy-path allocation,
byte-identical error messages vs the 0.2.0 walker).
fingerprint() via DefaultHasher, same as the phase-6 pattern.
- Compile-time graph safety: definition-level cycle set + depth cap
(128) reject cyclic $ref graphs with AlkTypeError::Schema. The
interpretive walker resolved refs lazily with no guard (stack-
overflow hazard); diamond (shared) refs still compile.
- bast_validation.rs: interpretive walker retired (deleted);
validate_value survives as a one-shot wrapper (compile + validate)
for callers holding a doc without an engine.
- engine: Arc<ValidationPlan> built at compile in BOTH modes; the
plan compile runs before the layout build and doubles as the
engine's cyclic-ref gate (LayoutBuilder/OffsetMap struct recursion
has no cycle guard; a cyclic doc previously overflowed there).
validate_bytes walks the plan; new accessor validation_plan().
validate_bytes signature unchanged.
- lib.rs: pub mod validation_plan + re-exports (ValidationPlan,
ValidNode, ValidField, ValidVariant).
Verification: cargo test --release (355 pass, incl. parity suite,
fingerprint contract, cycle/depth rejection, Send+Sync + thread-share
assertions); clippy --all-targets -D warnings clean; cargo doc
zero warnings; wasm32-unknown-unknown release build green.
Co-authored-by: opencode <noreply@alk.dev>