# traversal-log-v21-2026-10-05.jsonl.gz — schema

Keyboard traversal of U.S. municipal government sites, **version 2.1 of the dataset**.
Published 5 October 2026 by Maksim Galatin & AIfa. Licence: CC BY-NC 4.0.

| | |
|---|---|
| file | `traversal-log-v21-2026-10-05.jsonl.gz` |
| lines | 95,216 — one per pair *domain + page type* (the same pairs as version 2) |
| domains | 11,902 × 8 page types |
| measured | base traversal 1–2 October 2026, re-measurements 3–4 October 2026 (UTC) |
| engines | v5.3.1 — 54,170 lines, v5.4 — 25,849, v5.4.2-en — 8,113, v5.4.1-en — 6,788, v5.4.3-en — 296 |

Versions 1 and 2 stay published unchanged. Every line that changed category since version 2 keeps its
version 2 category in `категория_А_v2` and lists the rules that changed it in `поправки_v21`.

## The headline figure and how to recompute it

    barrier share = lines with category A == "БАРЬЕР"
                    / lines with category A in ("ДОСТУПНО", "БАРЬЕР")
                  = 5,966 / 24,236 = 24.62 %

    option B (an almost invisible focus ring counts as a barrier):
                  = 6,086 / 24,236 = 25.11 %   (120 pages differ)

    version 2, from the same file (field категория_А_v2):
                  = 8,448 / 25,252 = 33.45 %

Python:

    import gzip, json, collections
    c = collections.Counter(json.loads(l)["категория_А"].split(":")[0]
                            for l in gzip.open("traversal-log-v21-2026-10-05.jsonl.gz", "rt", encoding="utf-8"))
    print(c["БАРЬЕР"] / (c["БАРЬЕР"] + c["ДОСТУПНО"]))

The unit is a **page** (domain + page type), not a site.

## Categories (fields `категория_А`, `категория_Б`, `категория_В`)

| category | meaning | lines (A) |
|---|---|---:|
| `ДОСТУПНО` | a keyboard user reaches the goal and the focus is visible | 18,270 |
| `БАРЬЕР` | the goal is not reached, or reached with invisible / hidden / off-screen focus, fields without labels, focus trap | 5,966 |
| `НЕТ_ФУНКЦИИ_ИЛИ_ЦЕЛИ` | the function or goal is not on the site (incl. 5,973 pages handing off to a third-party provider and 684 with the goal in a collapsed menu) | 34,247 |
| `НЕИЗМЕРИМО` | cannot be measured: access denied to the crawler (12,428), server silent, server error, timeout, closed, broken TLS, unstable frame, a failed re-measurement | 18,786 |
| `ВНЕ:<reason>` | outside the denominator — see below | 17,947 |

Outside the denominator (`ВНЕ:`): no website address in the CISA registry 8,936 · parked domain 3,208 ·
not in the CISA registry on 31 August 2026 1,944 · broken DNS 1,248 · the same page already counted for another
alias domain 1,088 · a different organisation's domain 576 · home page unavailable 433 · somebody else's site 304 ·
domain does not exist 138 · address leads nowhere 56 · frame to another site 16.

Option A counts an almost invisible focus ring as visible; option B counts it as a barrier; option C equals A.

## Why a line's category can differ from its `вердикт`

The category follows the latest measurement of that page and the corrections listed in `поправки_v21`,
not only the original traversal verdict. Examples in this file: 180 lines with verdict
`ДОШЁЛ_ФОКУС_ВИДЕН` are barriers because the focus re-measurement of 1 October found the ring hidden or
off-screen (field `фокус_перемер_v54`, the same mechanism as in version 2); 530 lines with verdict `ДОМЕНА_НЕТ`
are "not measurable" because all three DNS resolvers return an address but the connection was refused or reset
(rule П4).

## Corrections of version 2.1 (field `поправки_v21`: list of `{правило, основание}`)

| rule | lines | what it does |
|---|---:|---|
| П1 | 1,944 | domain not in the CISA .gov registry on 31 August 2026 → outside the denominator |
| П2 | 584 | manual decisions by domain: somebody else's site, parked page, login or error instead of the home page |
| П3 | 7,192 | pages of 899 domains measured while the browser leaked a Russian interface language are replaced by an English re-measurement (engine v5.4.1-en); a failed re-measurement makes the page not measurable |
| П4 | 11,616 | domains excluded by version 2 as "no domain", "parked" or "home unavailable" re-classified after a triple DNS and HTTP check |
| П5 | 480 | the final page is Chrome's own error page → not measurable |
| П6 | 1,088 | one page measured under several alias domains is counted once |
| П7 | 712 | Wix sites: the engine could not see Wix's focus ring; the category follows the pixel focus re-measurement of the same page |
| П8 | 12 | decisions on single lines from before/after screenshots |
| П9 | 55 | empty frame: the engine compared two empty crops → not measurable |
| П10 | 28 | a Cloudflare challenge page was measured instead of the site → not measurable |
| П11 | 60 | the goal is an e-mail, phone or file link, not a page → "no function or goal" instead of "server silent" |
| П12 | 272 | re-measurements of 3 October: Wix (84), English re-runs of failed pages, 17 domains with Google DNS addresses, 20 empty frames |
| П13 | 8,166 | all 8,292 pages outside Wix where the first pass saw no focus ring, re-measured on 3–4 October with engine v5.4.2, which applies the label rule itself; 1,891 of them re-measured again on 4 October after an instrument fix (the paired mode had not opened them) |
| П14 | 54 | the engine's rule "focus visible but fewer than 70 % of form fields labelled → barrier", applied where only the older focus layer is available |

| П15 | 306 | CivicPlus banner: our honest user agent made CivicPlus sites lay a "This site has been optimized for modern browsers" banner over the header, which ordinary browsers never see; 306 pages where it could have caused the barrier re-measured on 4 October with engine v5.4.3, which dismisses the banner with its own button before the first Tab |
| П16 | 2,605 | label rule recomputed over fields a person and a screen reader can reach (`checkVisibility()`, no `aria-hidden` / `inert` ancestor); hidden helper fields of the Google Translate widget and hidden spam-trap fields no longer count |

A line can carry several rules; the counts are rule entries, not lines.

## New fields in version 2.1

| field | meaning |
|---|---|
| `категория_А_v2` | the line's category A in version 2 |
| `вердикт_v21` | the verdict set by a version 2.1 rule when it changes the verdict (e.g. П16: `ДОШЁЛ_ФОКУС_ВИДЕН`, `ПЕРЕМЕР_НЕ_ВОСПРОИЗВЕДЁН`); the original traversal verdict stays in `вердикт` — 3,773 lines |
| `поправки_v21` | corrections applied to the line, in order (rule and reason) |
| `рамка_до`, `рамка_после`, `язык_браузера`, `document_hasFocus` | written by engine v5.4.2: focus ring boxes before/after, browser language, whether the window had focus |
| `wix`, `wix_класс_контейнера` | Wix detection by engine v5.4.2 |
| `браузер` | browser version used by engine v5.4.2; the local path of the browser is masked as `[local path]` |
| `плашка_civicplus` | engine v5.4.3 (296 lines): `{была, закрыта}` — whether the CivicPlus banner was present and dismissed before the first Tab |
| `метки_доля_все_поля`, `полей_всего`, `полей_видимых` | engine v5.4.3 (296 lines re-measured for the CivicPlus banner; for the 3,300 pages of rule П16 the same counts are in its reason text): label share over all fields (the old way), number of fields, number of fields a person and a screen reader can reach; `метки_доля` is now computed over the latter |

All other fields are described in `traversal-log-v5-SCHEMA.md` and keep their meaning.

## What was changed before publication

* E-mail addresses (3,321) and phone numbers (5,389) in text fields are replaced with `[e-mail]` and `[phone]`.
* Local file paths of our measuring computer (8,422, mostly in `браузер`) are replaced with `[local path]`.
* Paths to screenshots are reduced to file names.
* Nothing else was altered. The categories recomputed from this public file equal the figures above.
