- C1: packed validate_bytes now exercised over all eleven primitive
kinds (LE battery + BE subset + corrupted-bool rejection) — the plan
materializer's i16..bool arms had zero public-path executions.
- C2: aligned validate_bytes over the default inline length-prefixed
encoding (string + bytes; ADR-006 last-position rule honored).
- C3: ReadPlan::compile cycle rejection through a union mapping entry
(compile_variant's own cycle arm — field-level cycles were already
covered; this shape reaches the variant path). Arm confirmed
executed in the post-fix coverage run.
- L1: builder.rs standard JSON-Schema conveniences locked with exact-
JSON table tests, plus an end-to-end build_validator compile test.
- L2: tunion::read_field_discriminator's enum arm (both endians) —
the last untested arm of the documented kind set (N1 parity).
docs/reviews/007-coverage-audit.md updated with per-finding
resolution blocks.
Verification: 488 lib + 78 integration tests green, clippy -D
warnings clean, wasm32-unknown-unknown build green.
- F1: materialize_plan_array (validate_bytes' packed path) now carries
the zero-progress array guard the reader and legacy walker already
had; validate_bytes no longer accepts an empty buffer against a
stride-0 empty-struct-element array that SequentialReader rejects.
Cross-consumer agreement test added (review #007 probe transcript).
- F2: MAX_LENGTH = 2^26 cap on the maxLength annotation — the N2
dual-layer pattern (clean Schema parse error naming value+maximum,
meta-schema "maximum": 67108864 so the published contract matches).
Also closes the silent usize-overflow drop in parse_max_length.
- docs/reviews/007-coverage-audit.md records the full audit: per-file
numbers, all classifications, and the N3a dead-surface list deferred
to the pre-release review.
Verification: 477 lib + 78 integration tests green, clippy -D warnings
clean, wasm32-unknown-unknown build green.
- Parse gate in BastField::parse: maxLength on any kind other than
string/bytes is a clean Schema error (records, arrays, inline
structs, refs, union shared fields all covered; the choke point
needs no ref-following since $defs entries are struct/union/enum)
- Meta-schema FieldDef: if kind in {string, bytes} else maxLength
forbidden — the published alk.dev/bast/v1 contract matches the
parser (N2 dual-layer pattern)
- M5's compute-side record maxLength arm became unreachable and was
deleted (offset-indirect arm stays); the two superseded M5
maxLength tests rewritten as the n3_* parse-rejection family
- ADR-006 remedy message tailored per kind: for records both
annotated remedies are dead ends, so the error text points at the
last-position fix only
- Docs aligned: bast-format.md (FieldDef meta-schema + FieldDef/
Variable-Length Encoding prose), layout-engine.md (Strategy 2 +
ADR-006 paragraph), schema-layer.md, ADR-003 §2/§3a amended,
builder .max_length() doc
- Review #006: N3 resolved (all findings now closed), M5 update
note, test-count bookkeeping note (in-session probes vs static
counts), status lines flipped to fully resolved
Verified: 547 tests green + 2 ignored doctests in BOTH release and
default profiles (a stale debug artifact from an earlier session
masked one H3 roundtrip test in debug; clean rebuild passes both),
clippy -D warnings clean, cargo doc --no-deps zero warnings, wasm
build green.
align: 2^62 compiled and reported total_size = 2^63 — meaningless
layout output the consumer may act on, and the reachable path to the
MAX_ARRAY_BYTES cap used exactly this knob.
- MAX_ALIGN = 4096 (page granularity) in schema.rs, documented with the
probe arithmetic
- parse_align returns Result and rejects over-cap values with a clean
Schema error naming path/value/maximum — a silent clamp was rejected
(it would change layout semantics without telling the consumer);
both call sites thread the path, so standalone BastDoc::new (which
never runs the meta-schema) is covered
- Meta-schema: "maximum": 4096 on StructDef.align and FieldDef.align —
the published alk.dev/bast/v1/schema contract now matches the parser
- H1's byte-cap test retuned to align 4096 x count 2^16 = 2^28 > 2^26
(the byte cap stays reachable under the new align cap)
Tests: 3 new (struct align above cap, field align above cap, align at
cap accepted). 511 tests green, clippy -D warnings clean, wasm32 build
green, cargo doc zero warnings.
L2: compile() builds Arc<Value> once and threads &Arc<Value> down the
compile walk; every real ReadPlan carries the document at construction
— the Value::Null-placeholder-then-map-overwrite dance is gone. The one
remaining Null in wrap_leaf is documented as correct-by-construction
(anonymous synthetic wrapper, never escapes).
L3: materialize_plan_field drops its plan parameter (taken solely to
discard) and the field-disc union arm's disc_field/let _ pair is
deleted — the order-walk + by-name capture is the materializer's
correct design, as the finding's parity note described.
508 tests green, clippy -D warnings clean, wasm32 build green,
cargo doc zero warnings.
M1: field_variable_kind (offset_map) now matches Record — a non-final
inline length-prefixed record field in aligned mode hits the ADR-006
rejection instead of computing silently corrupt offsets (probe-verified
clobber in the review: counts prefix at 0, id at 4).
M2: aligned record path locked with public-path tests —
materialize_aligned roundtrip (record<uint16>, wire arithmetic
asserted) and engine validate_bytes roundtrip + corrupted-buffer
rejection (record<uint32>). Record-as-last-field is the only safe
inline position post-M1.
M3: read_field's unreachable Struct arm (no struct-path entry ever
exists in an OffsetMap) replaced with a documented defensive Offset
error; doc comment states struct paths have no entry and the Offset
miss is the reachable composite failure. FieldValue::Struct (public
API, constructed by the packed reader) untouched.
Tests: 7 new (2 offset_map, 2 materialize, 1 engine M3 lock, plus the
roundtrip pair). 508 tests green, clippy -D warnings clean, wasm32
build green, cargo doc zero warnings.
Cyclic or over-deep $ref graphs stack-overflowed the three standalone
schema walkers (OffsetMap::compute, LayoutBuilder::new,
materialize_aligned) — SIGABRT on probe, parity-preserved from 0.2.0.
- New src/walk_guard.rs: check_ref_graph() — one bounded walk over the
reachable reference graph (depth cap 128 matching the plan compilers,
path-scoped cycle set; diamonds allowed, cycles and 201-def chains
rejected with the plan compilers' error wording)
- All three walkers run the guard at entry, before any recursion;
materialize_aligned's is defense-in-depth (a cyclic doc can no longer
produce an OffsetMap, but mismatched doc/map inputs must still fail
cleanly)
- Behavioral side effect, net-positive: the guard eagerly parses every
reachable def, so an invalid non-root def now surfaces at
LayoutBuilder::new instead of build() — four H3 tests updated to
expect the same Schema error earlier
- Test family: 12 new tests (walk_guard, offset_map, layout_builder,
materialize) covering self/two-def/composite-carrier cycles, deep
chains, and diamond non-rejection; no stack-overflow reproducers
in-tree per the review's Methodology warning
- Stale "walkers have no cycle guard" statements updated in
validation.md, 030 plan, ADR-012, and the engine gate comment
Verified: 501 tests green (423 + 17 + 34 + 15 + 12 + 2 ignored),
clippy -D warnings clean, wasm32 build green, cargo doc zero warnings.
Decision (recorded as an ADR-011 addendum): the packed-mode wire layout
for a field-name-discriminator TUnion is shared-then-variant — the
union's declared `fields` (disc + shared fields) first, then the
variant's own fields. Reader and materializer already implemented this;
LayoutBuilder was corrected from variant-only layout.
Enforcement in BastUnion::parse (the choke point every consumer
inherits — union roots at BastDoc::new, referenced unions at
resolve_ref):
- discriminator field must be declared in `fields`
- `fields` must not contain duplicate names
- variants must not re-declare shared fields (checked inline and
through $ref resolution — parse chain now threads the doc root)
- the discriminator field must be the FIRST entry in `fields` (the
reader reads the disc at the union start; a later position made it
dispatch on the wrong bytes — H3 item 2, probe-verified)
Schemas relying on the old variant-only builder convention (variants
re-declaring shared fields) are rejected with a clean Schema error
naming the convention. Breaking for 0.2.0-era re-declaring schemas;
announced with 0.3.x.
- L5: FieldValue::Union::variant_start doc now states per-kind
semantics (byte-disc: union_start + disc.offset + disc.size;
field-disc: after the shared walk).
- L6: roundtrip test added (poc_roundtrip.rs) — LayoutBuilder write →
SequentialReader read → materialize_packed → validate_bytes over a
field-disc union with a second shared field and non-redeclaring
variant; pins event.type@0/seq@1/handle@5, total 10.
- ADR-011: Status-block addendum recording the convention decision,
the no-re-declare rule, and the breaking-constraint note.
- Review #006 updated: H3/L5/L6 resolution blocks, resolution log,
recommended order.
Verified: 488 tests green (410+17+34+15+12, 2 pre-existing ignored),
clippy -D warnings clean, wasm32 build green, cargo doc zero warnings.
- Replace the three Vec::with_capacity(count) sites in materialize.rs
with Vec::new() — validate_bytes on an adversarial count no longer
OOM-aborts the process (AGENTS.md §3).
- New compile-time caps in schema.rs: MAX_ARRAY_ELEMENTS (2^16,
enforced at BastArray::parse — the choke point every consumer
inherits, bounds the walkers' per-element entry loops) and
MAX_ARRAY_BYTES (2^26, enforced per walker against the mode-specific
stride: compile_array, walk_array, compute_array_field).
- L1: fixed_composite_size/fixed_plan_size now return
Result<Option<usize>>; unwrap_or_default() gone, overflow is a clean
Schema error instead of silent stride-0.
- Zero-progress guard: stride-0 arrays whose elements consume 0 bytes
(legal empty-struct elements) now error in plan_walk_variable_array_
size and materialize_array_packed instead of looping count times.
- Tests: 8 new (parse/build/compile rejections, cap boundary,
short-buffer clean error) + array_count_large_u64_parses_on_64bit
rewritten to assert the new cap rejection. In-tree tests assert only
the safe (compile-time) half per review #006's Methodology warning.
- Review #006 updated: H1/L1 resolution blocks, new finding N2
(unbounded align annotations, found while re-deriving the cap
arithmetic), resolution log, recommended order.
Verified: 482 tests green (405+17+34+14+12, 2 pre-existing ignored),
clippy -D warnings clean, wasm32-unknown-unknown build green.
Public API bump 0.2.0 -> 0.3.0 (the 030-compiled-forms plan is now
fully implemented; all eight phases landed).
- Cargo.toml: version 0.3.0. lib.rs re-exports complete (ReadPlan +
sub-types, LeafMeta, OffsetEntry, ValidationPlan + sub-types).
- ADR-007 "Cost" rewritten to the Arc<ReadPlan> cost (15.7 ns) with
the 0.2.0 "re-parse on demand" framing as a historical note
(review #004 L2, the last loose end from that review).
- ADR-011/012 status blocks flipped to implemented; architecture
README ADR table rows updated; layout-engine.md rewritten for the
0.3.0 surface (engine-factory reader construction, OffsetMap
OffsetEntry/LeafMeta/fingerprint section, owned BastDoc compute
signature); SequentialReader module doc points at the engine
factory. Reviews #004 and #005 flipped to closed.
- Bench re-run (alktty wire_vs_bast, 0.3.0 tree): read p64 98
ns/chunk (parity with phase 2; hand-rolled 5.7 us/stream),
layout_build 180 ns (was ~1.2 us — the phase-4 owned-doc cache
removed the per-build re-parse, ~7x), sequential_reader_new 15.7
ns, write p64 -3%, engine_compile unchanged (meta-schema
validation dominates). No dedicated validate_bytes-stream bench:
the phase-7 spot check (~0.2 us plan-validate vs ~0.6 us
compile-per-call) stands; a dedicated bench is a follow-up if
alkcall profiling motivates it.
- Downstream: alktty compiles against the path dep unchanged; alkcall
has no dependency yet.
Verification (full block, all green): 474 tests; clippy -D warnings
clean; cargo doc zero warnings; wasm32 release build green; cargo
publish --dry-run clean at 0.3.0.
Resolve all 11 findings from the 0.3.0 plan review (#005) in one
docs-only pass. No source changes; the crate still builds/tests at
v0.2.0. The one substantive decision change is M3 (per user
direction: ship ValidationPlan in 0.3.0, no more hedging); the rest
are spec corrections or pre-implementation refinements to types that
do not yet exist on main.
- H1: refine ADR-011 CompositePlan::Union to carry
shared: Option<Box<ReadPlan>> (field-disc shared fields) and
variants: Vec<(String, CompositePlan)> (drop VariantPlan/
VariantKind). Plan phase 1 implements the refined shape.
- H2: plan phase 2 specifies ReadPlan stores schema: Arc<Value>
(not &Value), avoiding the self-referential struct ADR-011
rejects. Verified serde_json::Value: Hash + Eq holds with
preserve_order, so phase 6 derives are not blocked.
- M1: nested-union support falls out of the H1 shape refinement
(a variant can be CompositePlan::Union) — option (a) from the
review, no behavioral drop vs 0.2.0, no Semver regression row.
- M2: plan phase 5 adds an explicit first sub-step to derive Hash
on Endian and VariableEncoding in src/schema.rs (additive,
semver-safe prerequisite the original plan omitted).
- M3: reverse the ValidationPlan deferral. ADR-012's "Deferring
ValidationPlan" becomes "ValidationPlan — in scope for 0.3.0";
new ADR-012 §3 commits the decision (compiled form, no per-buffer
BastDoc walk, Hash + Eq + fingerprint()) and defers only the
concrete shape to a follow-on design session + the plan's new
phase 7. Plan gains phase 7 (ValidationPlan); old phase 7 (bump)
renumbered to phase 8. ADR-011's Out-of-scope and Scope
Boundaries bullets updated to point at ADR-012 §3. The deferral
black hole this review's methodology flagged is closed: the work
is committed with a concrete reactivation trigger, not hedged
into an unplanned future.
- L1: plan phase 2 corrects the dummy_field_for/ty_source removal
claim — only packed-side call sites go away; the helpers stay
for the aligned materialize_leaf_at path.
- L2: plan phase 2 states the packed-vs-aligned
materialize_typeref_packed split (packed gets a new plan-walking
function; the existing function stays for aligned).
- L3: plan phase 5 adds a Scope Boundary note — aligned
materialize's BastDoc structure walk is the permanent 0.3.0
design; an AlignedPlan is out of scope, tracked as an OQ.
- N1: fix "back-comat" -> "back-compat" typo.
- N2: plan phase 1 verification adds the read_plan_is_send_sync
static-bound assertion test ADR-011 requires.
- N3: Semver Contract table notes the Result drop on
SequentialReader::new (Result<Self, AlkTypeError> -> Self)
alongside the argument-type change.
Also: ADR-012 title -> "Plan Fingerprinting, ValidationPlan, and
Closing the Deferred M1 Sites in 0.3.0"; §3 (Fingerprinting
OffsetMap) renumbered to §4; README ADR table updated; review #005
gets a Resolution section recording how each finding was closed.
Verification (docs-only change, v0.2.0 unchanged):
cargo test --release ok (310 crate + 86 integration + 2 doctests)
cargo clippy --all-targets -- -D warnings ok
cargo doc --no-deps ok
Cross-checks docs/plans/030-compiled-forms.md against the codebase,
ADRs 011/012, the POC on readplan-poc, and review #004.
Findings:
- H1: field-disc union shape is in neither ADR-011 nor the POC
- H2: schema() &Value on Arc<ReadPlan> is the self-referential
pattern ADR-011 rejects
- M1: nested-union silent behavioral drop (POC rejects what 0.2.0
accepts); deferral-black-hole pattern
- M2: Endian/VariableEncoding missing Hash derive (phases 5/6 break)
- M3: ValidationPlan deferral flagged for re-evaluation — the
read+validate-on-untrusted-input case may be hotter than
ADR-012's 'not a hot loop' dismissal accounts for
- L1/L2/L3: dummy_field_for wording, materialize_packed split,
materialize_aligned BastDoc walk silence
- N1/N2/N3: typo, Send+Sync assertion test, Result drop on new
Includes a deferral-pattern scan methodology section surfacing
M1/L3/H2 as black-hole instances and confirming the plan's four
explicit deferred decisions are the healthy pattern.
Verification: file-only change, no code touched.
Traces the ~400x read-path gap (alktty wire_vs_bast bench) to
SequentialReader::read_field_at re-parsing BastDoc::new on every field
read, with the self-referential lifetime constraint as the root cause.
Findings:
- H1: per-field BastDoc::new re-parse in sequential_reader.rs:262
- M1: same re-parse in four one-shot paths (LayoutBuilder::build,
validate_bytes, engine read_field/write_field)
- L1: dead _field_schema param + Value clones in SequentialReader
- L2: ADR-007 Cost section + engine doc comment understate the re-parse
- N1: carry-forward of review #003 N2 (no new action)
Lays out fix options: Option A (owned typed tree, recommended, closes
H1+M1, breaking), Option B (read-plan precompute, fallback, H1 only,
non-breaking), Option C (borrow-from-engine, rejected, contradicts
ADR-007).
Verification: docs-only review; alktype source unchanged.
cab4932
- Add README.md reflecting the v0.1.0 state: 19 AlkType kinds, two
layout modes, builder + AlkTypeEngine usage example (verified to
compile and run), validation entry points, crate independence,
untrusted-schemas guarantee, docs pointers. Mirrors the alkvault
README structure.
- Add AGENTS.md with alktype-specific git workflow, project
conventions (no comments, AlkTypeError, untrusted schemas, overflow
safety, no async, no feature flags, wasm-clean, preserve_order
load-bearing, no unsafe), verification commands, and ADR/OQ index.
Blocks auto-commit on semver-relevant public API changes per the
crates.io 0.1.0 contract.
- Add LICENSE-MIT and LICENSE-APACHE (dual MIT/Apache-2.0, matching
alkvault and the Cargo.toml license field).
- Cargo.toml: add readme, keywords, categories, rust-version = "1.85".
- Fix broken intra-doc link in builder.rs: DiscriminatorKind ->
crate::schema::DiscriminatorKind (cargo doc now warning-free).
- N1 (review #002): document is_rfc3339_timestamp as non-strict in the
function doc comment. Lists the specific gaps (day-of-month per
month, seconds range, leap seconds) and points consumers needing
strict validation to chrono/time.
- N2 (review #002): document the FieldValue::Bytes-for-Record API
asymmetry in the FieldValue enum doc and on read_record_value.
- .opencode/agents/implementation-specialist.md: point to AGENTS.md
for full convention details (matches the alkvault pattern).
- review #002: mark N1/N2 resolved; all 7 findings now closed.
Verification:
- cargo test --release: 396 tests pass (310 crate + 86 integration)
- cargo clippy --all-targets -- -D warnings: clean
- cargo doc --no-deps: clean (no broken intra-doc link warnings)
- cargo build --target wasm32-unknown-unknown --release: clean
- cargo publish --dry-run --allow-dirty: clean
The immediate downstream consumer (alkcall) accepts schemas from
arbitrary internet peers in its hub/spoke topology. A panic is the
wrong failure mode for a malicious or unsupported schema - an Err
the caller can handle is correct.
Three sites converted:
- offset_map.rs: _ => Err(Offset { unsupported AlkType kind for
aligned offset computation })
- layout_builder.rs: _ => Err(Offset { unsupported AlkType kind
for packed layout computation })
- materialize.rs: _ => Err(Schema { internal: union discriminator
type N is not a supported byte discriminator })
The materialize.rs site uses Schema (not Access) because a wrong
disc_type is a schema-authoring bug (parse_discriminator should have
caught it), not a buffer-access error. The sibling sites in
sequential_reader.rs and tunion.rs already returned Err(Schema) -
only materialize.rs was the holdout.
Note: the k if k.is_fixed_size() guard in offset_map and
layout_builder means the compiler cannot enforce exhaustiveness at
compile time. Converting _ from unreachable! to Err is the runtime
mitigation. A future refactor could list all fixed-size kinds
explicitly to restore compile-time checking. Deferred to a separate
cleanup pass.
Verified: no unreachable! remains in production code (the one
remaining hit at offset_map.rs:688 is inside a #[test] fn).
cargo test --release: 396 tests pass, 0 failures
cargo clippy --all-targets -- -D warnings: clean
cargo build --target wasm32-unknown-unknown --release: clean (prior)
Four of seven review findings resolved. 5 new tests (391 -> 396 crate
tests; 438 -> 443 total). cargo test, clippy, wasm32 all green.
M2 (data_access.rs): write_bytes now validates data_len fits in u32
before the length-prefix cast. A >4GiB blob returns Access error
instead of silently writing a truncated length prefix (silent data
corruption on read-back).
M1 (builder.rs): Definitions::merge_into rewritten to access self.defs
directly instead of round-tripping through self.build() with a double-
cloned/unwrap_or_default chain that could silently drop definitions
on a shape mismatch. 4 new tests: insert-when-absent, merge-into-
existing, overwrite-duplicate-keys, no-op-on-non-object-top.
L1 (materialize.rs): byte-offset discriminator arm of
materialize_union_packed now uses checked_add for offset+disc_offset
and disc_abs_offset+disc_size, returning Access error on overflow.
Mirrors the existing sequential_reader.rs::read_union_value pattern.
L3 (error.rs): AlkTypeError::source() now returns Some(inner) for the
Validation variant (jsonschema::ValidationError implements
std::error::Error). Existing source_returns_none_for_all_variants
test split into source_returns_none_for_schema_offset_access and
source_returns_some_for_validation_variant.
Deferred: L2 (unreachable! -> Err, defense-in-depth), N1 (non-strict
RFC 3339 validator, docs-only), N2 (FieldValue::Bytes for Record,
API asymmetry). Review doc updated with resolution section.
Full source read of all 13 src/*.rs files for correctness, panic
safety, and API ergonomics ahead of v0.1.0 crates.io publish.
Findings:
- M1: Definitions::merge_into silently drops data via double-
unwrap_or_default chain; untested public API
- M2: write_bytes truncates u32 length prefix on >4GiB data
(data_len as u32 without bounds check)
- L1: materialize.rs union path uses unchecked offset arithmetic
(sequential_reader.rs sibling uses checked_add)
- L2: three unreachable!() in production code (offset_map, layout_
builder, materialize)
- L3: AlkTypeError::source() returns None for Validation variant
(ValidationError implements std::error::Error)
- N1: is_rfc3339_timestamp is non-strict (Feb 31 passes, seconds
unchecked)
- N2: SequentialReader returns FieldValue::Bytes for Record (API
asymmetry vs other composites)
Verification baseline (commit c0217d9):
- cargo test --release: 438 tests pass (391 crate + 47 integration)
- cargo clippy --all-targets -- -D warnings: clean
- cargo build --target wasm32-unknown-unknown --release: clean
- no unsafe, no TODO/FIXME, all unwrap/expect/panic in test modules