From 30b01c1696b72bafeb583e6fa643eeb192c3fc82 Mon Sep 17 00:00:00 2001 From: "glm-5.2" Date: Sat, 15 Aug 2026 10:29:27 +0000 Subject: [PATCH] Sync BAST pivot doc with main (semver/ADR impact mapping) Brings the 'Semver and ADR Impact' section from main onto this branch so the two doc copies don't drift. No code change. --- docs/research/bast-pivot.md | 94 +++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/docs/research/bast-pivot.md b/docs/research/bast-pivot.md index aeb44ba..a8ac0e0 100644 --- a/docs/research/bast-pivot.md +++ b/docs/research/bast-pivot.md @@ -613,6 +613,100 @@ over unchanged. - BAST-native validator — a recursive walker over the BAST type tree that checks value-domain constraints on a materialized `Value`. Replaces the 19 custom keyword validators for the `validate_bytes` path. Enforces: integer ranges, float finiteness, string/bytes `maxLength`, RFC 3339 timestamp shape, enum index bounds, union variant dispatch (recursing into variants). See [The Validator Split](#the-validator-split). - BAST meta-schema validation at compile time (optional but recommended — the engine can skip it and trust the caller, or validate as a guard) +## Semver and ADR Impact + +This section is the scope-creep guardrail for the public API during +implementation. The crate is on crates.io at 0.1.0 with zero real +consumers, so a breaking bump is free — but the contract still needs to +be explicit so the implementation doesn't drift. Per AGENTS.md, the +0.1.0 public surface is the items re-exported from `src/lib.rs`. + +### Public API delta + +| Public item (from `lib.rs` re-exports) | Class | Change | +|---|---|---| +| `AlkTypeKind` (enum + variants + methods) | **Additive** | Unchanged. 19 variants, same methods. New `from_str()`/`to_str()` mapping for lowercase BAST kind strings (`"uint32"` ↔ `AlkTypeKind::Uint32`) — additive methods. | +| `Endian`, `VariableEncoding`, `DiscriminatorKind` | **Unchanged** | — | +| `AlkTypeEngine::compile` | **Breaking** | Signature: `compile(schema: &mut Value, mode)` → `compile(bast_doc: &Value, root_name: &str, mode)`. Adds required `root_name` param (D-BAST-001); drops `&mut` (BAST needs no in-place `normalize_refs`); input is a BAST document, not a custom-keyword JSON Schema. | +| `AlkTypeEngine::validate_json` | **Breaking (behavioral)** | Signature unchanged `(instance: &Value) -> Result<...>`, but the validator it runs is now a standard `jsonschema::Validator` from a consumer-provided JSON Schema supplied at `compile`, not a custom-keyword validator built from the alktype schema. The compiled engine must carry a separate JSON-Schema validator (or `validate_json` takes the JSON Schema at call time — to be decided in step 6). Either way the *contract* of what schema validates the instance changes. | +| `AlkTypeEngine::validate_bytes` | **Unchanged (contract)** | Same signature. Internally the validation step switches from `jsonschema::Validator` to the BAST-native validator. Error type unchanged (D-BAST-009). | +| `AlkTypeEngine::is_valid_json` | **Breaking (behavioral)** | Same caveat as `validate_json` — validates against the consumer JSON Schema, not the alktype schema. | +| `AlkTypeEngine` accessors (`endian`, `mode`, `offset_map`, `layout_builder`, `sequential_reader`, `read_field`, `write_field`, etc.) | **Unchanged** | Layout-layer accessors are format-agnostic. | +| `LayoutMode`, `OffsetMap`, `ByteRange` | **Unchanged** | — | +| `LayoutBuilder`, `PackedLayout`, `FieldPosition` | **Unchanged** | — | +| `SequentialReader`, `FieldValue` | **Unchanged** | — | +| `UnionDispatch` | **Unchanged** | — | +| `data_access::*` functions | **Unchanged** | — | +| `AlkTypeError` (all 4 variants) | **Unchanged** | D-BAST-009 keeps `Validation(jsonschema::ValidationError<'static>)`. | +| `Schema` builder (`struct_`, `object`, `field`, `build`, all setters) | **Breaking (output format)** | Public method signatures unchanged. `build()` output changes from custom-keyword JSON to BAST JSON (for `struct_`) / standard JSON Schema (for `object`). Callers that introspect the built `Value` break; callers that pass it straight to `compile` are source-compatible once `compile` takes BAST. | +| `Definitions` builder (`new`, `define`, `define_value`, `build`, `merge_into`) | **Breaking (output format)** | Same as `Schema` — signatures unchanged, `build()`/`merge_into()` output shape changes to BAST `$defs`. | +| `Discriminator` builder enum | **Unchanged** | — | +| `build_validator` (from `validation`) | **Breaking (signature or removal)** | Currently `build_validator(schema: &Value) -> Result` builds a custom-keyword validator. Under the pivot it either (a) is removed (consumers call `jsonschema` directly for standard JSON Schema) or (b) is repurposed to build a standard `jsonschema::Validator` from a consumer-provided standard JSON Schema (no custom keywords). Decision belongs to step 6. Either way the current signature's contract breaks. | +| `get_alktype_kind`, `get_alktype_kind_enum`, `get_alktype_kind_loose`, `get_alktype_kind_loose_enum`, `normalize_refs`, `inline_union_variant_refs`, `resolve_ref`, `resolve_ref_or_inline`, `parse_align`, `parse_discriminator`, `parse_encoding`, `parse_endian`, `parse_max_length` | **Breaking (removal or rework)** | All currently re-exported from `lib.rs`. `normalize_refs` and `inline_union_variant_refs` are removed (BAST needs neither). The `get_alktype_kind*` family is removed (replaced by direct `kind` parsing). The `parse_*` and `resolve_*` functions are reworked to read BAST properties instead of keyword-value objects, or removed if subsumed by the BAST parser. **Open: which of these stay public vs become internal.** Current leaning — drop all from `lib.rs` re-exports (they're engine-internal accessors, not consumer API); the BAST parser exposes a new typed surface instead. | + +**Net breaking surface:** `compile`, `validate_json`/`is_valid_json` +(contract), `Schema::build`/`Definitions::build` (output format), +`build_validator` (signature/removal), and the ~13 `schema::*` helper +re-exports. **Net additive:** BAST parser, BAST-native validator, +`AlkTypeKind::from_str`/`to_str`. **Net unchanged:** the entire layout ++ data-access + materialize + tunion layer, `AlkTypeError`, the +`Discriminator` builder, `AlkTypeKind` variants. + +### ADR impact + +| ADR | Action | Reason | +|---|---|---| +| [ADR-001](../architecture/decisions/001-alktype-purpose-scope-jsonschema-engine.md) (purpose, scope, "schema is the format") | **Supersede** | The "schema is the format" principle is retained and strengthened (BAST *is* the format), but the concrete format changes from custom-keyword JSON Schema to BAST. A new ADR (ADR-BAST or renumbered) records the BAST format as the realization of the principle. ADR-001's Status → Superseded by ADR-BAST. | +| [ADR-002](../architecture/decisions/002-two-layout-modes-packed-vs-aligned.md) (two layout modes) | **Unchanged** | Layout modes are format-agnostic. No content change; maybe a one-line note that the input format changed but the modes didn't. | +| [ADR-003](../architecture/decisions/003-schema-annotations.md) (endianness, alignment, encoding, discriminators) | **Amend** | Annotation *semantics* carry forward unchanged; annotation *location* moves from custom-keyword objects to BAST type-level properties. Amend the "where annotations live" sections, keep the semantics. | +| [ADR-004](../architecture/decisions/004-error-handling-validation-strategy.md) (`AlkTypeError`, load-time build, access-time check) | **Amend** | Error enum shape unchanged (D-BAST-009). The "validation strategy" section updates: bytes path uses BAST-native validator, JSON path uses standard `jsonschema`. The load-time/access-time split is retained. | +| [ADR-005](../architecture/decisions/005-int64-uint64-first-class-kinds.md) (Int64/Uint64, JSON precision caveat) | **Unchanged** | Kinds carry forward; JSON precision caveat is unchanged. | +| [ADR-006](../architecture/decisions/006-reject-non-final-inline-length-prefixed-in-aligned-mode.md) (reject non-final inline length-prefixed in aligned mode) | **Unchanged** | Layout rule, format-agnostic. | +| [ADR-007](../architecture/decisions/007-packed-mode-read-factory.md) (packed-mode read factory, `sequential_reader()` returns owned reader) | **Unchanged** | Reader factory semantics are format-agnostic. | +| [ADR-008](../architecture/decisions/008-reject-tunion-in-aligned-mode.md) (reject TUnion in aligned mode for v1) | **Unchanged** | Layout rule, format-agnostic. | +| [ADR-009](../architecture/decisions/009-builder-api.md) (builder API) | **Amend** | Public method surface unchanged; `build()` output format changes (BAST for `struct_`, standard JSON Schema for `object`). Amend the "output format" section; keep the method catalog. | +| [ADR-010](../architecture/decisions/010-generalized-validation-validate-bytes.md) (`validate_bytes` — materialize then validate) | **Amend** | The two-step concept (materialize → validate) is retained. The validation step's *implementation* changes from `jsonschema` custom keywords to the BAST-native validator. Amend the "validation step" section; add a pointer to D-BAST-006/D-BAST-009 and the Validator Split section. | + +**New ADRs to write (post-implementation, grounded in shipped code):** +- **ADR-BAST** — the BAST format, meta-schema, and `$defs`/`$ref`/ + `kind` vocabulary. Supersedes ADR-001's format-specific content. +- **ADR-VAL-SPLIT** (or fold into ADR-004's amend) — the two-validator + model: BAST-native for `validate_bytes`, standard `jsonschema` for + `validate_json`. Records D-BAST-006, D-BAST-007, D-BAST-009. + +**Descriptive docs to sync (post-implementation):** +- `docs/architecture/schema-layer.md` — rewrite for the BAST parser + (replaces the custom-keyword accessor walk-through). +- `docs/architecture/validation.md` — rewrite for the validator split. +- `docs/architecture/builder.md` — update the `build()` output examples + to BAST JSON. +- `src/lib.rs` module doc comment — update the "Takes a JSON Schema + with `AlkType:*` custom keywords" preamble to BAST. + +**Stale TODOs to remove:** any TODO referencing custom-keyword +normalization, `inline_union_variant_refs`, or the rejected +bare-name-ref design — align with the ADRs as AGENTS.md §"Architecture +Context" requires. + +### Open decisions deferred to implementation steps + +These are small enough to decide when the step is reached, but are +flagged here so they don't become drive-by semver changes: + +1. **`validate_json` JSON Schema source** (step 6): does the consumer + pass the JSON Schema to `compile` (engine carries a second + validator) or to `validate_json` at call time? The former preserves + the current single-call ergonomics; the latter is more flexible. Not + semver-relevant either way if `validate_json`'s signature can absorb + a new param or stay as-is — needs the call-site analysis. +2. **`build_validator` fate** (step 6): removed vs repurposed. If + repurposed, its signature stays but its contract (no custom + keywords) changes — a behavioral break, not a type break. +3. **`schema::*` helper re-exports** (step 3): drop from `lib.rs` + (engine-internal) vs keep public for consumers that walk schemas. + Leaning: drop — they're accessors for the old format, and the BAST + parser exposes a cleaner typed surface. Confirmed during step 3. + ## The Validator Split A key architectural clarification: BAST separates two concerns that the