# Dump format The contract between the oracle service, the comparator, and eventually the engine under test. Frozen: changing it requires changing every consumer at once. ## Oracle protocol The oracle is a long-lived process speaking newline-delimited JSON on stdio. One JSON object per line in each direction, no pretty-printing, no interleaved text on stdout. Diagnostics go to stderr. Browsers stay open for the process lifetime. Nothing spawns a browser per case. ### Request ```json {"id": "case-0001", "html": "...", "engines": ["chromium", "firefox", "webkit"]} ``` `engines` is optional; omitted means every engine the service launched. ### Response ```json {"id": "case-0001", "dumps": {"chromium": {...}, "firefox": {...}}, "errors": {"webkit": "message"}} ``` `dumps` holds one dump per engine that succeeded. `errors` holds a message per engine that failed, and is omitted when empty. A response always carries the `id` it answers. ### Control `{"id": "...", "op": "ping"}` responds `{"id": "...", "ok": true, "engines": [...]}`. `{"id": "...", "op": "shutdown"}` closes browsers and exits. ## Dump ```json { "engine": "chromium", "viewport": {"width": 800, "height": 600}, "overflowed": false, "nodes": [ { "index": 0, "parent": -1, "tag": "HTML", "depth": 0, "bounding": {"x": 0.0, "y": 0.0, "w": 800.0, "h": 100.0}, "rects": [{"x": 0.0, "y": 0.0, "w": 800.0, "h": 100.0}], "style": {"display": "block", "...": "..."} } ] } ``` - `nodes` is every element in document order, starting at `` at index 0. Document order means `index` increases monotonically and a parent always precedes its children. - `parent` is an index into `nodes`, or `-1` for the root. - `tag` is the uppercase tag name as the DOM reports it. - `rects` is `getClientRects()`, one entry per box fragment, in content order. An empty array means the element generates no box — that is the signal, not a null `bounding`. - `bounding` is `getBoundingClientRect()`, always present, zeroed when `rects` is empty. - Coordinates are viewport-relative CSS pixels as doubles, serialized at full precision. - `overflowed` is true when the document scrolls in either axis. Overflow means a scrollbar may have stolen viewport width by a platform-dependent amount, so comparisons on an overflowed case are not trustworthy and the case is discarded. ## Style subset A fixed, ordered list. Present on every node, values exactly as `getComputedStyle` returns them. ``` display position box-sizing direction writing-mode float clear width height min-width max-width min-height max-height margin-top margin-right margin-bottom margin-left padding-top padding-right padding-bottom padding-left border-top-width border-right-width border-bottom-width border-left-width overflow-x overflow-y ``` A mismatch here indicts the style pipeline rather than layout, which is the second attribution axis. ## Comparison Comparison never uses absolute coordinates. 1. **Shape.** The sequence of `(tag, depth, parent)` must match. A mismatch is a parse divergence and the case reports that and stops — no geometry is compared. 2. **Size.** Each node's `bounding` width and height, and each fragment's width and height pairwise. 3. **Relative offset.** Each node's `bounding` origin minus its parent's `bounding` origin. The root compares against the viewport origin. A single wrong offset then appears once rather than corrupting every descendant. Tolerance is 1/60 px (0.01667), the coarsest engine quantization — Gecko app units. Blink and WebKit quantize at 1/64. Differences below tolerance are quantization noise. Both an exact verdict (within tolerance or not) and the raw signed delta are reported. The verdict gates pass/fail; the delta is the dense reward signal and needs no threshold.