--- status: draft last_updated: 2026-08-11 --- # Open Questions Each open question lives in its own file under [`questions/`](questions/), named `NNN-slug.md` (mirroring the ADR convention). This file is the index: theme-grouped tables for scannability, plus a cross-theme [Open](#open) section (active investigation targets) and a [Deferred / Blocked](#deferred--blocked) section that surfaces the safe-exit deferrals with their blocking conditions inline — so "what's currently on the architect's desk" and "what's currently parked and why" are each answerable at a glance. **Status values**: - `open` — Needs to be resolved now. Has a clear path to resolution. - `resolved` — Decided. The resolution is stated cleanly, without caveats about how it could be changed later. - `deferred(scope)` — Cannot be resolved yet. The information is genuinely missing — a crate spec, POC result, or use case that doesn't exist yet. Has a concrete blocking condition. Not a failure — scope management. - `deferred(unclear)` — Cannot be resolved yet. The pieces exist (decided in other ADRs, existing types, existing patterns) but the composition — how they fit together — isn't clear yet. Resolution requires investigation (work through examples, maybe POC), not waiting. Has a concrete investigation target and an impacts field. Not a failure — honest uncertainty in a poorly-defined problem space. - `partially resolved` — Some aspects decided, others deferred or open. - `dissolved` — The question was reframed out of existence (e.g., superseded by an ADR that retires the premise). Kept for reference. **Impacts field**: Every unresolved OQ (`open`, `deferred(scope)`, `deferred(unclear)`, `partially resolved`) should have an `Impacts` field stating what it blocks downstream. Be specific: "blocks the first hub deployment because the hub dials workers" not "blocks the hub crate." This is the triage signal that makes the deferral's urgency visible. Door type classifications describe **reversal cost** (how expensive it is to undo), not urgency: - **One-way door**: Reversal requires rewriting significant code or permanently closes a capability. Getting it wrong is expensive — requires ADR before implementation. - **Two-way door**: Reversal is cheap or additive. Getting it wrong is recoverable — decide, implement, revert if needed. Door type is separate from whether a decision is made. A two-way door is a decision you make now and can revert later, not a decision to defer. ## By Theme ### Layout Engine | OQ | Title | Status | Door | Pri | |----|-------|--------|------|-----| | [OQ-001](questions/001-arrays-of-variable-length-element-structs.md) | Arrays of Variable-Length-Element Structs | deferred(scope) | two | low | ### Platform Support | OQ | Title | Status | Door | Pri | |----|-------|--------|------|-----| | [OQ-002](questions/002-no-std-alloc-support.md) | `no_std` + `alloc` Support | deferred(scope) | two | low | ### Schema Construction | OQ | Title | Status | Door | Pri | |----|-------|--------|------|-----| | [OQ-003](questions/003-builder-api-for-schema-construction.md) | Builder API for Schema Construction | resolved (ADR-009) | two | med | | [OQ-004](questions/004-discriminator-field-name-type.md) | `Discriminator::Field` name — `&str` or `String` | resolved | two | low | | [OQ-006](questions/006-builder-spec-example-3-wrap-union.md) | Builder spec Example 3 — wrap `Union` in a `Struct` | resolved | two | low | ### Validation | OQ | Title | Status | Door | Pri | |----|-------|--------|------|-----| | [OQ-005](questions/005-union-materialization-shape.md) | `Union` materialization shape — byte-offset vs field-name consistency | resolved | two | med | | [OQ-007](questions/007-bytes-materialization-lossy-utf8.md) | `Bytes` materialization — lossy UTF-8 conversion | resolved | one | med | | [OQ-008](questions/008-unionvalidator-variant-dispatch.md) | `UnionValidator` variant dispatch | resolved | one | med | ## Open Active investigation targets — questions with a clear path to resolution that need to be worked through, not waited on. Each has a concrete investigation target. This section exists so "what's currently on the architect's desk" is answerable at a glance. > **Note**: All v0.1.0 open questions (OQ-004, OQ-005, OQ-006, OQ-007, > OQ-008) were resolved during the v0.1.0 POC round 2 (SFTP Packet > `validate_bytes` POC). The resolutions are summarized below for > traceability; see each OQ's full file for the decision rationale. > The currently-parked OQs are OQ-001 and OQ-002 (see Deferred / Blocked > below). ### OQ-004: `Discriminator::Field` name — `&str` or `String` — RESOLVED - **Status**: resolved. `String`, for ownership simplicity (the builder consumes `Self` on setters; `&str` would require a lifetime parameter on `Discriminator` and transitively on `Schema::union_`). Implemented in `src/builder.rs` since the initial v0.1.0 builder implementation. - **Full file**: [OQ-004](questions/004-discriminator-field-name-type.md) ### OQ-005: `Union` materialization shape — RESOLVED - **Status**: resolved. Both discriminator kinds return `{ "__discriminator": , ...variant-fields }`. The field-name path also had a real offset bug (returned start offset, not end) — fixed. Implemented in `src/materialize.rs`. - **Full file**: [OQ-005](questions/005-union-materialization-shape.md) ### OQ-006: Builder spec Example 3 — wrap `Union` in a `Struct` — RESOLVED - **Status**: resolved. [builder.md](builder.md) Example 3 now wraps the `Union` in a `Schema::struct_().field("payload", ...)` and merges `$defs` via `Definitions::merge_into`. Matches the realistic SFTP wire shape and the engine's `AlkType:Struct`-at-root constraint. - **Full file**: [OQ-006](questions/006-builder-spec-example-3-wrap-union.md) ### OQ-007: `Bytes` materialization — lossy UTF-8 conversion — RESOLVED - **Status**: resolved. Array of u8: the materializer produces `Value::Array` of `Value::Number` (one entry per byte, 0..=255) for `AlkType:Bytes` fields. The `BytesValidator` accepts both `Value::String` (for `validate_json`) and `Value::Array` (for `validate_bytes`). `maxLength` = max byte count. Implemented in `src/materialize.rs` and `src/validation.rs`. - **Full file**: [OQ-007](questions/007-bytes-materialization-lossy-utf8.md) ### OQ-008: `UnionValidator` variant dispatch — RESOLVED - **Status**: resolved. `UnionValidator` now builds a sub-validator for each variant at factory time and dispatches on `__discriminator` at validation time. `AlkTypeEngine::compile` calls `schema::inline_union_variant_refs` before `build_validator` to inline `$ref`s in union `mapping` entries (necessary because the `union_factory` receives the union node, but `$defs` live at the schema root). Implemented in `src/validation.rs`, `src/schema.rs`, and `src/engine.rs`. - **Full file**: [OQ-008](questions/008-unionvalidator-variant-dispatch.md) ## Deferred / Blocked The safe-exit visibility surface. These questions are parked because the information needed to resolve them does not exist yet — each has a concrete blocking condition. They are not failures; they are scope management. This section exists so "what's currently blocking the architect" is answerable at a glance, not by filtering the tables above. > **Note**: OQ-003 (Builder API) was resolved by > [ADR-009](decisions/009-builder-api.md) in v0.1.0 and is retained > below for traceability — it's marked **RESOLVED**, not deferred. > The currently-parked OQs are OQ-001 and OQ-002. ### OQ-001: Arrays of Variable-Length-Element Structs - **Blocked on**: A concrete consumer that needs arrays of structs with variable-length fields, where the elements are interleaved (`[fixed_0][str_0][fixed_1][str_1]...`) and the engine must walk sequentially rather than use a fixed stride. The SFTP `Name` packet has `Vec` where `File` contains strings, but SFTP serializes this as a sequence of length-prefixed strings (the serde `SeqAccess` pattern), not as an array of fixed-stride structs. Arrays of fixed-size structs are fully supported. - **Priority**: low - **Full file**: [OQ-001](questions/001-arrays-of-variable-length-element-structs.md) ### OQ-002: `no_std` + `alloc` Support - **Blocked on**: An embedded use case that requires `no_std` + `alloc` (e.g., a microcontroller running Rust without `std`). The WASM target has `std` available via `wasm-bindgen`. The engine's core (offset computation, read/write) is already allocation-free; the `jsonschema` dependency is the only `alloc` consumer. - **Priority**: low - **Full file**: [OQ-002](questions/002-no-std-alloc-support.md) ### OQ-003: Builder API for Schema Construction — RESOLVED - **Status**: resolved by [ADR-009](decisions/009-builder-api.md) in v0.1.0. - **Unblocking condition**: alkcall — the merged `alknet-call` + `alknet-channels` extraction from `@alkdev/alknet` — is the concrete consumer that needs programmatic schema construction in Rust. It builds both binary-layout schemas (channels' 8-byte chunk header) and JSON payload schemas (`OperationSpec` input/output/error schemas) at runtime. - **Resolution**: A fluent Rust builder producing `serde_json::Value`, covering AlkType kinds and standard JSON Schema. Implemented in `src/builder.rs`; spec in [builder.md](builder.md). See ADR-009. - **Full file**: [OQ-003](questions/003-builder-api-for-schema-construction.md)