open-standards/joule-ui/conformance/lang/v1/l2-ingest.json
Transaction Science 8a0f6073f7 joule-ui: the line language (SPEC §11), a streaming ingest into validated widget trees
joule-ui takes in OpenUI Lang 1.0 the way it takes in A2UI: a model writes a
surface as a program, one widget a line, and joule-ui-lang builds a widget tree
against the host's registry as the program streams. After every chunk a snapshot
holds the tree as far as it can be built, each widget checked by joule-ui's own
validate, and every error with its source line and reason code. State, queries,
operators, conditionals, built-in functions and sequences of actions are parsed
and refused not-declarative. A canonical writer turns a tree back into the
language; it parses back to the same tree.

- joule-ui-core: WidgetSchema::positional, the order a positional call passes
  props in (SPEC §3); absent from the wire form when undeclared.
- joule-ui-interaction: begin_interaction and Pending::finish, the lifecycle's
  three phases in two steps for a host whose handler is asynchronous (SPEC §6);
  run_interaction is built on them and seals what it sealed before.
- conformance/lang/v1: L1 statements, L2 ingest, L3 streaming, L4 the canonical
  form, L5 refusals, with an independent Python verifier written from §11.
- docs/create.md: the design of Create.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-27 04:46:19 -04:00

985 lines
23 KiB
JSON

{
"cases": [
{
"expected": {
"errors": [],
"incomplete": false,
"nodes": [
{
"key": "root",
"line": 1,
"statement": "root"
},
{
"key": "card",
"line": 2,
"statement": "card"
},
{
"key": "t1",
"line": 3,
"statement": "t1"
},
{
"key": "t2",
"line": 4,
"statement": "t2"
}
],
"orphans": [],
"tree": {
"children": [
{
"children": [
{
"name": "Text",
"props": {
"text": {
"type": "text",
"value": "one"
}
}
},
{
"name": "Text",
"props": {
"size": {
"type": "number",
"value": 14.0
},
"text": {
"type": "text",
"value": "two"
}
}
}
],
"name": "Card",
"props": {
"subtitle": {
"type": "text",
"value": "sub"
},
"title": {
"type": "text",
"value": "Hello"
}
}
}
],
"name": "Page",
"props": {
"title": {
"type": "text",
"value": "Home"
}
}
},
"unresolved": []
},
"input": "root = Page([card], \"Home\")\ncard = Card(\"Hello\", [t1, t2], \"sub\")\nt1 = Text(\"one\")\nt2 = Text(\"two\", 14)\n",
"name": "hoisting"
},
{
"expected": {
"errors": [],
"incomplete": false,
"nodes": [
{
"key": "root",
"line": 1,
"statement": "root"
},
{
"key": "a",
"line": 2,
"statement": "a"
},
{
"key": "b",
"line": 3,
"statement": "b"
}
],
"orphans": [],
"tree": {
"children": [
{
"name": "Text",
"props": {
"text": {
"type": "text",
"value": "a"
}
}
},
{
"name": "Text",
"props": {
"text": {
"type": "text",
"value": "b"
}
}
}
],
"name": "Page",
"props": {}
},
"unresolved": [
"missing"
]
},
"input": "root = Page([a, missing, b])\na = Text(\"a\")\nb = Text(\"b\")\n",
"name": "unresolved-left-out"
},
{
"expected": {
"errors": [],
"incomplete": false,
"nodes": [
{
"key": "root",
"line": 1,
"statement": "root"
},
{
"key": "a",
"line": 2,
"statement": "a"
}
],
"orphans": [
"old"
],
"tree": {
"children": [
{
"name": "Text",
"props": {
"text": {
"type": "text",
"value": "a"
}
}
}
],
"name": "Page",
"props": {}
},
"unresolved": []
},
"input": "root = Page([a])\na = Text(\"a\")\nold = Text(\"old\")\n",
"name": "orphans"
},
{
"expected": {
"errors": [],
"incomplete": false,
"nodes": [
{
"key": "root",
"line": 1,
"statement": "root"
},
{
"key": "root/0",
"line": 1,
"statement": "root"
},
{
"key": "root/0/0",
"line": 1,
"statement": "root"
},
{
"key": "root/0/1",
"line": 1,
"statement": "root"
},
{
"key": "root/1",
"line": 1,
"statement": "root"
}
],
"orphans": [],
"tree": {
"children": [
{
"children": [
{
"name": "Text",
"props": {
"text": {
"type": "text",
"value": "x"
}
}
},
{
"name": "Text",
"props": {
"text": {
"type": "text",
"value": "y"
}
}
}
],
"name": "Card",
"props": {
"title": {
"type": "text",
"value": "c"
}
}
},
{
"name": "Text",
"props": {
"text": {
"type": "text",
"value": "z"
}
}
}
],
"name": "Page",
"props": {}
},
"unresolved": []
},
"input": "root = Page([Card(\"c\", [Text(\"x\"), Text(\"y\")]), Text(\"z\")])\n",
"name": "inline-calls-and-keys"
},
{
"expected": {
"errors": [],
"incomplete": false,
"nodes": [
{
"key": "root",
"line": 1,
"statement": "root"
},
{
"key": "t",
"line": 2,
"statement": "t"
},
{
"key": "t#2",
"line": 2,
"statement": "t"
}
],
"orphans": [],
"tree": {
"children": [
{
"name": "Text",
"props": {
"text": {
"type": "text",
"value": "again"
}
}
},
{
"name": "Text",
"props": {
"text": {
"type": "text",
"value": "again"
}
}
}
],
"name": "Page",
"props": {}
},
"unresolved": []
},
"input": "root = Page([t, t])\nt = Text(\"again\")\n",
"name": "used-twice"
},
{
"expected": {
"errors": [],
"incomplete": false,
"nodes": [
{
"key": "root",
"line": 1,
"statement": "root"
},
{
"key": "c",
"line": 2,
"statement": "c"
}
],
"orphans": [],
"tree": {
"children": [
{
"name": "Card",
"props": {
"subtitle": {
"type": "text",
"value": "sub"
},
"title": {
"type": "text",
"value": "t"
}
}
}
],
"name": "Page",
"props": {}
},
"unresolved": []
},
"input": "root = Page([c])\nc = Card(\"t\", null, \"sub\")\n",
"name": "null-skips-an-optional"
},
{
"expected": {
"errors": [],
"incomplete": false,
"nodes": [
{
"key": "root",
"line": 1,
"statement": "root"
},
{
"key": "ch",
"line": 2,
"statement": "ch"
}
],
"orphans": [],
"tree": {
"children": [
{
"name": "Chart",
"props": {
"labels": {
"type": "list",
"value": [
{
"type": "text",
"value": "a"
},
{
"type": "text",
"value": "b"
}
]
},
"options": {
"type": "object",
"value": {
"colours": {
"type": "list",
"value": [
{
"type": "text",
"value": "red"
},
{
"type": "text",
"value": "blue"
}
]
},
"max value": {
"type": "null"
},
"stacked": {
"type": "bool",
"value": true
}
}
},
"values": {
"type": "list",
"value": [
{
"type": "number",
"value": 1.0
},
{
"type": "number",
"value": -2.5
},
{
"type": "number",
"value": 300.0
}
]
}
}
}
],
"name": "Page",
"props": {}
},
"unresolved": []
},
"input": "root = Page([ch])\nch = Chart([\"a\", \"b\"], [1, -2.5, 3e2], {stacked: true, \"max value\": null, colours: ['red', \"blue\"]})\n",
"name": "data-props"
},
{
"expected": {
"errors": [],
"incomplete": false,
"nodes": [
{
"key": "root",
"line": 1,
"statement": "root"
},
{
"key": "b1",
"line": 2,
"statement": "b1"
},
{
"key": "b2",
"line": 3,
"statement": "b2"
},
{
"key": "b3",
"line": 4,
"statement": "b3"
},
{
"key": "b4",
"line": 5,
"statement": "b4"
},
{
"key": "b5",
"line": 6,
"statement": "b5"
},
{
"key": "b6",
"line": 7,
"statement": "b6"
}
],
"orphans": [],
"tree": {
"children": [
{
"name": "Button",
"props": {
"action": {
"type": "action",
"value": {
"id": "Go",
"payload": null
}
},
"label": {
"type": "text",
"value": "none"
}
}
},
{
"name": "Button",
"props": {
"action": {
"type": "action",
"value": {
"id": "Open",
"payload": {
"type": "text",
"value": "x"
}
}
},
"label": {
"type": "text",
"value": "one"
}
}
},
{
"name": "Button",
"props": {
"action": {
"type": "action",
"value": {
"id": "Send",
"payload": {
"type": "list",
"value": [
{
"type": "text",
"value": "a"
},
{
"type": "number",
"value": 2.0
}
]
}
}
},
"label": {
"type": "text",
"value": "two"
}
}
},
{
"name": "Button",
"props": {
"action": {
"type": "action",
"value": {
"id": "Pick",
"payload": {
"type": "list",
"value": [
{
"type": "number",
"value": 1.0
},
{
"type": "number",
"value": 2.0
}
]
}
}
},
"label": {
"type": "text",
"value": "list"
}
}
},
{
"name": "Button",
"props": {
"action": {
"type": "action",
"value": {
"id": "Go",
"payload": null
}
},
"label": {
"type": "text",
"value": "wrapped"
}
}
},
{
"name": "Button",
"props": {
"action": {
"type": "action",
"value": {
"id": "ToAssistant",
"payload": {
"type": "list",
"value": [
{
"type": "text",
"value": "hi"
},
{
"type": "object",
"value": {
"id": {
"type": "number",
"value": 1.0
}
}
}
]
}
}
},
"label": {
"type": "text",
"value": "by name"
}
}
}
],
"name": "Page",
"props": {}
},
"unresolved": []
},
"input": "root = Page([b1, b2, b3, b4, b5, b6])\nb1 = Button(\"none\", @Go())\nb2 = Button(\"one\", @Open(\"x\"))\nb3 = Button(\"two\", @Send(\"a\", 2))\nb4 = Button(\"list\", @Pick([1, 2]))\nb5 = Button(\"wrapped\", Action([@Go()]))\nb6 = Button(\"by name\", go)\ngo = @ToAssistant(\"hi\", {id: 1})\n",
"name": "actions"
},
{
"expected": {
"errors": [],
"incomplete": false,
"nodes": [
{
"key": "root",
"line": 1,
"statement": "root"
},
{
"key": "tabs",
"line": 2,
"statement": "tabs"
},
{
"key": "t1",
"line": 3,
"statement": "t1"
},
{
"key": "t1/0",
"line": 3,
"statement": "t1"
},
{
"key": "t2",
"line": 4,
"statement": "t2"
}
],
"orphans": [],
"tree": {
"children": [
{
"children": [
{
"children": [
{
"name": "Text",
"props": {
"text": {
"type": "text",
"value": "1"
}
}
}
],
"name": "Tab",
"props": {
"title": {
"type": "text",
"value": "One"
}
}
},
{
"name": "Tab",
"props": {
"title": {
"type": "text",
"value": "Two"
}
}
}
],
"name": "Tabs",
"props": {}
}
],
"name": "Page",
"props": {}
},
"unresolved": []
},
"input": "root = Page([tabs])\ntabs = Tabs([t1, t2])\nt1 = Tab(\"One\", [Text(\"1\")])\nt2 = Tab(\"Two\")\n",
"name": "only-of-children"
},
{
"expected": {
"errors": [],
"incomplete": false,
"nodes": [
{
"key": "root",
"line": 1,
"statement": "root"
},
{
"key": "n",
"line": 2,
"statement": "n"
},
{
"key": "n/0",
"line": 2,
"statement": "n"
}
],
"orphans": [],
"tree": {
"children": [
{
"children": [
{
"name": "Text",
"props": {
"text": {
"type": "text",
"value": "inside"
}
}
}
],
"name": "Note",
"props": {
"author": {
"type": "text",
"value": "by"
},
"body": {
"type": "text",
"value": "the body"
}
}
}
],
"name": "Page",
"props": {}
},
"unresolved": []
},
"input": "root = Page([n])\nn = Note(\"by\", \"the body\", [Text(\"inside\")])\n",
"name": "derived-order"
},
{
"expected": {
"errors": [],
"incomplete": false,
"nodes": [
{
"key": "root",
"line": 1,
"statement": "root"
},
{
"key": "a",
"line": 3,
"statement": "a"
}
],
"orphans": [],
"tree": {
"children": [
{
"name": "Text",
"props": {
"text": {
"type": "text",
"value": "second"
}
}
}
],
"name": "Page",
"props": {}
},
"unresolved": []
},
"input": "root = Page([a])\na = Text(\"first\")\na = Text(\"second\")\n",
"name": "duplicate-later-wins"
},
{
"expected": {
"errors": [],
"incomplete": false,
"nodes": [
{
"key": "root",
"line": 1,
"statement": "root"
},
{
"key": "a",
"line": 2,
"statement": "a"
},
{
"key": "b",
"line": 3,
"statement": "b"
}
],
"orphans": [],
"tree": {
"children": [
{
"children": [
{
"name": "Card",
"props": {
"title": {
"type": "text",
"value": "b"
}
}
}
],
"name": "Card",
"props": {
"title": {
"type": "text",
"value": "a"
}
}
}
],
"name": "Page",
"props": {}
},
"unresolved": [
"a"
]
},
"input": "root = Page([a])\na = Card(\"a\", [b])\nb = Card(\"b\", [a])\n",
"name": "cycle"
},
{
"expected": {
"errors": [
{
"code": "no-root",
"line": 2,
"statement": "page",
"warning": true
}
],
"incomplete": false,
"nodes": [
{
"key": "page",
"line": 2,
"statement": "page"
},
{
"key": "t",
"line": 1,
"statement": "t"
}
],
"orphans": [],
"tree": {
"children": [
{
"name": "Text",
"props": {
"text": {
"type": "text",
"value": "x"
}
}
}
],
"name": "Page",
"props": {}
},
"unresolved": []
},
"input": "t = Text(\"x\")\npage = Page([t])\n",
"name": "fallback-entry"
},
{
"expected": {
"errors": [],
"incomplete": false,
"nodes": [
{
"key": "root",
"line": 1,
"statement": "root"
},
{
"key": "a",
"line": 2,
"statement": "a"
},
{
"key": "b",
"line": 3,
"statement": "b"
},
{
"key": "c",
"line": 4,
"statement": "c"
}
],
"orphans": [],
"tree": {
"children": [
{
"name": "Text",
"props": {
"text": {
"type": "text",
"value": "tab\there é"
}
}
},
{
"name": "Text",
"props": {
"text": {
"type": "text",
"value": "it's"
}
}
},
{
"name": "Text",
"props": {
"text": {
"type": "text",
"value": "bad \\q escape"
}
}
}
],
"name": "Page",
"props": {}
},
"unresolved": []
},
"input": "root = Page([a, b, c])\na = Text(\"tab\\there \\u00e9\")\nb = Text('it\\'s')\nc = Text(\"bad \\q escape\")\n",
"name": "escapes"
},
{
"expected": {
"errors": [
{
"code": "no-root",
"line": 0,
"statement": ""
}
],
"incomplete": false,
"nodes": [],
"orphans": [],
"tree": null,
"unresolved": []
},
"input": "",
"name": "empty"
}
],
"class": "L2"
}