elicit_ui
Formally verified UI construction with compile-time WCAG 2.2 compliance guarantees, built on AccessKit as a universal intermediate representation.
Overview
elicit_ui models UI construction as a proof-carrying pipeline. Every
interactive element is built through a factory trait that performs a WCAG
runtime check and, on success, returns both the constructed element and a
typed proof token — an Established<P> — that records what was verified.
Proof tokens compose upward through section aggregates into a final
Established<WcagLevelAAValid>, which is the only legal way to assert that a
surface is WCAG 2.2 Level AA compliant.
The compiler enforces this chain. There is no way to produce
Established<WcagLevelAAValid> without assembling all the leaf proofs from
which it is derived.
Architecture
┌─────────────────────────────────────────────────────────────────┐
│ WCAG Factory Traits │
│ WcagContrastFactory · WcagLabelFactory · WcagFocusFactory │
│ WcagKeyboardFactory · WcagTimingFactory · WcagTargetFactory │
│ WcagStructureFactory · WcagMediaFactory · WcagLanguageFactory │
│ WcagErrorFactory │
└────────────────────────────┬────────────────────────────────────┘
│ each method returns (Element, Established<Leaf>)
▼
┌─────────────────────────────────────────────────────────────────┐
│ Section Aggregate Factories │
│ WcagPerceivedFactory → Established<WcagPerceivedValid> │
│ WcagOperableFactory → Established<WcagOperableValid> │
│ WcagUnderstandableFactory → Established<WcagUnderstandableValid>│
│ WcagRobustFactory → Established<WcagRobustValid> │
└────────────────────────────┬────────────────────────────────────┘
│ assemble LevelAaEvidence
▼
┌─────────────────────────────────────────────────────────────────┐
│ WcagBackend supertrait │
│ build_level_aa(evidence) → Established<WcagLevelAAValid> │
└────────────────────────────┬────────────────────────────────────┘
│
┌───────────────┼───────────────┐
▼ ▼ ▼
elicit_egui elicit_ratatui elicit_leptos
(AccessKit IR) (Ratatui cells) (Leptos SSR/WASM)
The reference implementation of all factory traits is AccessKitUiBackend,
which builds AccessKit Node trees and issues proof tokens. Renderer crates
receive proof tokens through the IR but cannot forge them.
Proof Architecture
Proposition types
Every verifiable WCAG invariant has a corresponding Rust type — a
proposition — that implements elicitation::contracts::Prop. These types
are zero-cost phantoms that exist only at the type level.
; // SC 1.4.3, normal text ≥ 4.5:1
; // SC 2.4.7
; // the full Level AA composite
Proof tokens
Established<P> is the proof that proposition P holds. It is a zero-sized
type that carries no runtime data — only type-level evidence.
The ProvableFrom<C> trait
The credential-gated minting path is Established::prove:
ProvableFrom<C> declares "credential C proves proposition P". The
46 impls live in elicit_ui::contracts::wcag_proofs:
// … 44 more
Credential types
Each credential is a pub(crate) ZST in proof_credentials. External code
cannot construct one:
// pub(crate) — only factory methods inside elicit_ui can build this
pub ;
The factory method constructs the credential after performing the runtime
check, then passes it to prove:
Why this is a compile-time guarantee
NormalTextContrastVerifiedispub(crate)— external crates cannot writeEstablished::prove(&NormalTextContrastVerified).ProvableFrom<NormalTextContrastVerified>is only implemented forWcagContrastMinimumNormalText— no other proposition can be proved with that credential.Established::assert()remainspubas a general escape hatch, but any call toassert()on a WCAG proposition is immediately visible in code review and audit tooling as an explicit bypass.
WCAG 2.2 Contract Parity
Leaf propositions (41)
| Factory trait | Factory method | Proposition | WCAG SC | Level |
|---|---|---|---|---|
WcagContrastFactory |
build_contrast_minimum |
WcagContrastMinimumNormalText |
1.4.3 | AA |
build_contrast_minimum_large |
WcagContrastMinimumLargeText |
1.4.3 | AA | |
build_contrast_enhanced |
WcagContrastEnhancedNormalText |
1.4.6 | AAA | |
build_contrast_enhanced_large |
WcagContrastEnhancedLargeText |
1.4.6 | AAA | |
build_non_text_contrast |
WcagNonTextContrastMinimum |
1.4.11 | AA | |
WcagLabelFactory |
build_labeled_element |
WcagNamePresent |
4.1.2 | A |
build_labeled_form_field |
WcagFormLabelsProgrammatic |
1.3.1 / 3.3.2 | A | |
build_label_in_name |
WcagLabelInNameMatch |
2.5.3 | A | |
WcagFocusFactory |
build_focus_visible |
WcagFocusVisibleKeyboard |
2.4.7 | AA |
build_focus_appearance_minimum |
WcagFocusAppearanceMinimumArea |
2.4.11 | AA | |
build_focus_appearance_enhanced |
WcagFocusAppearanceEnhancedArea |
2.4.12 | AAA | |
WcagKeyboardFactory |
build_keyboard_accessible |
WcagKeyboardOperable |
2.1.1 | A |
build_keyboard_escape |
WcagKeyboardNotTrapped |
2.1.2 | A | |
build_remappable_shortcut |
WcagCharacterShortcutsRemappable |
2.1.4 | A | |
WcagTimingFactory |
build_timed_element |
WcagTimingAdjustable |
2.2.1 | A |
WcagTargetFactory |
build_target_minimum |
WcagTargetSizeMinimum |
2.5.8 | AA |
build_target_enhanced |
WcagTargetSizeEnhanced |
2.5.5 | AAA | |
build_pointer_gesture_alternative |
WcagPointerGesturesSimpleAlternative |
2.5.1 | A | |
build_pointer_cancellation |
WcagPointerCancellationUpEvent |
2.5.2 | A | |
WcagStructureFactory |
build_heading |
WcagHeadingStructureProgrammatic |
1.3.1 | A |
build_list |
WcagListStructureProgrammatic |
1.3.1 | A | |
build_table |
WcagTableHeadersProgrammatic |
1.3.1 | A | |
build_resizable_text |
WcagTextResizable |
1.4.4 | AA | |
WcagMediaFactory |
build_captioned_media |
WcagCaptionsSynchronized |
1.2.2 | A |
build_audio_described_media |
WcagAudioDescriptionPrerecorded |
1.2.5 | AA | |
WcagLanguageFactory |
build_language_page |
WcagPageLanguageIdentified |
3.1.1 | A |
build_language_element |
WcagPartLanguageIdentified |
3.1.2 | AA | |
WcagErrorFactory |
build_identified_error |
WcagErrorIdentificationDescriptive |
3.3.1 | A |
build_labeled_field |
WcagLabelsOrInstructionsPresent |
3.3.2 | A | |
build_error_suggestion |
WcagErrorSuggestionProvided |
3.3.3 | AA | |
build_error_prevention |
WcagErrorPreventionLegal |
3.3.4 | AA |
Section propositions (5)
Section factories accept evidence bundles — structs whose fields are
Established<LeafProposition> tokens. They compose leaf proofs into a
section-level proof and pass it upward.
| Factory | Evidence bundle | Section proposition |
|---|---|---|
WcagPerceivedFactory |
PerceivedEvidence |
WcagPerceivedValid |
WcagOperableFactory |
OperableEvidence |
WcagOperableValid |
WcagUnderstandableFactory |
UnderstandableEvidence |
WcagUnderstandableValid |
WcagRobustFactory |
RobustEvidence |
WcagRobustValid |
WcagBackend |
LevelAaEvidence |
WcagLevelAAValid |
Proof Composition
Proofs compose bottom-up. The compiler rejects any gap in the chain.
// 1. Leaf proofs — each factory method returns (Element, Established<LeafProp>)
let = backend
.build_contrast_minimum?;
let = backend
.build_focus_visible?;
// 2. Assemble a section evidence bundle — all fields are required proof tokens
let perceived_evidence = PerceivedEvidence ;
// 3. Section factory consumes the bundle, produces a section proof
let = backend.build_perceivable;
// 4. Repeat for all four WCAG principles, then assemble the top-level bundle
let level_aa_evidence = LevelAaEvidence ;
// 5. Mint the composite Level AA proof
let level_aa_proof: =
backend.build_level_aa;
If any leaf is missing the evidence bundle struct literal will not compile — there is no API to skip a field.
Trait Interface
Factory traits (leaf level)
// … WcagLabelFactory, WcagFocusFactory, WcagKeyboardFactory,
// WcagTimingFactory, WcagTargetFactory, WcagStructureFactory,
// WcagMediaFactory, WcagLanguageFactory, WcagErrorFactory
Section aggregate traits
Top-level supertrait
AccessKitUiBackend implements WcagBackend and is the reference backend
shipped with this crate. Other implementations must satisfy the same trait
bounds — the factory signatures are the contract.
Compile-Time Guarantee Summary
| What is guaranteed | Mechanism |
|---|---|
| Contrast ratio was checked before proof minted | NormalTextContrastVerified is pub(crate) — only the factory body can construct it |
| All WCAG SCs are covered before Level AA | LevelAaEvidence fields are Established<…> tokens — all must be present at the struct literal |
| No renderer can skip the factory | Renderer crates receive proof tokens via the AccessKit IR; they cannot call prove() on WCAG types because they cannot construct any WCAG credential |
| Section composition is total | Evidence bundle structs have no optional fields; every field is an Established<…> |
assert() bypasses are audit-visible |
assert() is pub but stands out immediately in code review; prove() + credential is the type-safe path |
Evidence Bundles
Evidence bundles are the bridges between proof layers. Each field must be filled with a token minted by the corresponding factory method.
Implementing a Custom Backend
To implement WcagBackend for a new rendering target:
-
Implement all ten leaf factory traits (
WcagContrastFactorythroughWcagErrorFactory). Each method must perform its runtime check, then callEstablished::prove(&Credential)only after the check passes. -
Implement the four section factories. These accept evidence bundles and call
provewith the evidence value as the credential. -
Implement
WcagBackend. Thebuild_level_aadefault impl composes the four section proofs intoEstablished<WcagLevelAAValid>— override only if the backend needs additional logic.
Note for external backends: Credentials are
pub(crate)insideelicit_ui. Implementations that live outside this crate can useEstablished::assert()at the leaf level — which is an explicit, auditable choice — or add their credential types andProvableFromimpls insideelicit_uias a new backend module.
Formal Verification
The proof architecture is designed for downstream formal verification.
Each proposition type implements elicitation::contracts::Prop, which
exposes a kani_proof() method for generating verification harnesses.
- Kani — bounded model checking on credential construction paths
- Creusot — deductive verification that factory bodies satisfy their WCAG
postconditions before calling
prove - Verus — SMT-based proofs of composition totality
Crate Layout
src/
├── lib.rs pub use surface
├── accesskit_backend.rs AccessKitUiBackend — reference WcagBackend impl
├── proof_credentials.rs 41 pub(crate) ZST credential types
├── contracts/
│ ├── mod.rs
│ ├── wcag_proofs.rs 46 ProvableFrom<C> for P impls
│ ├── node_roles.rs AccessKit role proofs
│ └── ui.rs layout / navigation proofs
├── traits/
│ ├── wcag.rs 14 factory traits + WcagBackend supertrait
│ └── renderer.rs UiNodeBridge, UiLayoutManager, UiNavigationManager
├── wcag_types.rs descriptor, element, evidence, section types
├── typestate.rs Layout<Pending>, Layout<Verified>
├── constraints/ runtime WCAG constraint checking
├── color_contrast.rs WCAG contrast ratio arithmetic
└── css_units.rs CssLength, zoom invariance
License
Licensed under Apache-2.0 OR MIT.