# A2UI v0.8 — Implementation Grading This grades two implementations against the v0.8 spec (): - **Lit reference** at `C:\Users\andersonch\Code\openclaw\vendor\a2ui\renderers\lit\src\0.8` - **Native WinUI** in this repo at `src/OpenClaw.Tray.WinUI/A2UI/` The Lit code looks like the canonical browser renderer the OpenClaw canvas host ships; the WinUI code is this repo's branch `feat/a2ui-native-winui`. Citations use repo-local paths. Lit paths are anchored at the OpenClaw checkout: `openclaw\vendor\a2ui\renderers\lit\src\0.8\`. WinUI paths are anchored at `src/OpenClaw.Tray.WinUI/A2UI/`. ## Method For each spec area, deductions land in two buckets: - **Gap** — implementation is missing or wrong vs. spec. Letter grade penalty. - **Good deviation** — implementation does something the spec _doesn't say to do_, but it's the correct call. Listed but doesn't penalize. Grades are A–F, separately for Lit and WinUI. There is no curving — "A" means it would pass a strict spec audit and a strict security audit; "B" means it works for normal traffic but fails under a hostile agent; etc. --- ## Scorecard | Area | Lit | WinUI | Notes | | --- | --- | --- | --- | | Component coverage (catalog completeness) | A | A | both 18/18 | | Component property completeness | B | A− | Lit has 4 documented TODOs; WinUI has minor distribution mappings | | Streaming / JSONL parsing | B | A | Lit: lenient; WinUI: lenient + size caps | | Data binding / `A2UIValue` | B+ | A | Lit auto-parses JSON strings (surprising); WinUI strict RFC 6901 | | Action transport | B | A | Lit: DOM event passthrough; WinUI: debounced + single-flight + fallback queue + gateway tag protocol | | Action context security | D | A | Lit punts to host; WinUI scopes to declared `dataBinding` and redacts secrets | | Theming | A− | A− | Equivalent power; different idioms | | URL safety / SSRF | F | A− | Lit unrestricted; WinUI HTTPS+allowlist for `Image`/`Video`/`AudioPlayer`, plus DNS-rebinding pin on `Image` fetches only | | Modal lifecycle | A− | A | Both work; WinUI uses native `ContentDialog` | | List virtualization | C | A | Lit builds all items; WinUI uses `ItemsRepeater` w/ recycling | | Bi-directional binding (write-back) | A | A | Both implement; spec is silent (good deviation) | | Markdown in `Text` | B+ | n/a | Lit's enhancement is real but increases attack surface | | Test coverage | D | A− | Lit: 1 model test, no per-component; WinUI: render matrix + scale + integration | | Spec deviations called out (good ones) | B | A | Lit's improvements partially offset its gaps | | **Overall** | **B−** | **A−** | | The two "A" grades have very different shapes: - **Lit** is a smaller codebase that gets the happy path right, with two notable **good** deviations (Markdown rendering, bi-directional binding) but several papercut **gaps** and a **non-trivial security delta** inherited from a "the host will sanitize" posture. - **WinUI** is significantly more code, fills almost every gap, and adds defenses the spec doesn't ask for. Its remaining minus comes from the things it _doesn't_ do yet (List `template` mode, Row wrap, `MultipleChoice.variant`). --- ## Lit implementation — detailed deductions ### Documented `TODO` gaps Verbatim TODOs in `vendor/a2ui/.../ui/root.ts` and component files: | Property | File:Line | Status | | --- | --- | --- | | `Divider.thickness` / `axis` / `color` | `ui/root.ts:317` | type declared, value not applied to `
` | | `MultipleChoice.maxAllowedSelections` | `ui/root.ts:334` | accepted but not enforced | | `TextField.validationRegexp` | `ui/root.ts:367` | not applied to `` | | `DateTimeInput.outputFormat` | `ui/datetime-input.ts:159` | placeholder; always uses browser format | | `MultipleChoice.selections` resolution | `ui/multiple-choice.ts:87–103` | logic incomplete when `selections` is path-bound | | `AudioPlayer.description` | `ui/audio.ts` | spec'd property silently dropped | Letter penalty: **−1 step on Component Property Completeness** (A → B). ### `A2UIValue.path` resolver auto-parses JSON-shaped strings `data/model-processor.ts:198–225` detects `valueString` payloads that look like `{...}` or `[...]` and **silently parses them as JSON**. The intent is "developer convenience"; the consequence is that a string literal containing a `[` or `{` becomes a structured value. This is a **gap** because the spec distinguishes `valueString` from `valueArray`/`valueMap` precisely so the agent can be unambiguous. Letter penalty: **−1 step on data binding**. ### URLs are passed through to the DOM `ui/image.ts:67–74` binds `` directly. There is no allowlist for `data:` / `javascript:` / `file:` / private-IP hosts, no SSRF protection, no DNS rebinding defense. The WinUI impl has all of these. The host **may** sanitize before forwarding URLs, but the renderer offers no defense in depth. Letter penalty: **−2 steps on URL safety** (this is the F). ### Component registry allows arbitrary custom elements `vendor/a2ui/.../ui/root.ts:118–140, 441–471` lets the embedding app set `enableCustomElements = true` and then renders any `` whose tag is registered in `componentRegistry`. This is **beyond spec** — useful for extensibility, dangerous for catalog-strict mode. **Not graded as a gap** since it's behind a flag, but it's worth flagging at the host level. ### One unit test covers everything `vendor/a2ui/.../model.test.ts` exercises `A2uiMessageProcessor` for `beginRendering` and `surfaceUpdate`. There are **no per-component render tests, no event-dispatch tests, no markdown sanitizer tests, no data-binding edge-case tests**. Letter penalty: **−2 steps on test coverage** (D). ### Good deviations - **Markdown rendering** in `Text` (`ui/text.ts`, `ui/directives/markdown.ts`). HTML blocks wrapped in `