# 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 `