Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 22 additions & 20 deletions docs/STATUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,16 @@ questions they had been sitting behind. When an ADR contains both, split it.

### Correct by reasoning, unconfirmed by eye — the thing to watch

**Four claims are now believed on argument and a passing test, and nobody has
looked at any of them.** Individually each is defensible; as a set it is the
**Four claims are believed on argument and a passing test. One is now half
confirmed** — the owner checked reduced motion in Firefox on 2026-09-28 and the
headline shows, which settles the hydration half and leaves the scroll-triggered
sections open. Individually each is defensible; as a set it is the
largest risk this workstream carries, because the test count going up reads as
reassurance while this list quietly grows.

| Claim | Why no agent can close it |
|---|---|
| The landing page is not blank for a reduced-motion visitor | The agent's browser reports `document.hidden` even when fronted, so `requestAnimationFrame` is frozen and the pane cannot tell a working page from a broken one. **Outstanding since 2026-09-25** |
| The landing page is not blank for a reduced-motion visitor | **Hero confirmed by the owner in Firefox, 2026-09-28** — which proves the hydration fix. The sections below it use `whileInView` and an `IntersectionObserver`, a different mechanism, and are still unobserved. The agent's browser freezes `requestAnimationFrame`, so it can close neither half |
| `color-scheme` fixed dark-mode scrollbars and autofill | A scrollbar's colours are not exposed to `getComputedStyle`, and autofill needs a real interaction |
| Logical properties flip under `dir="rtl"` | That browser does not re-resolve logical properties on a direction change — proven with an isolated inline-styled element, which also fails to flip |
| A learner hitting an error boundary gets a usable page | Inducing a real render error means changing code to break it |
Expand Down Expand Up @@ -113,10 +115,11 @@ problem-type branching, three-state auth pattern and static boundary are all
implemented and guarded. The package therefore records what exists and names four
narrow defects instead of proposing to rebuild working foundations.

**The first action is not a documentation task.** `docs/specs/frontend-roadmap.md`
§A1: open `/` with reduced motion enabled and confirm the headline appears. Ten
minutes, outstanding since 2026-09-25, and it is the only unverified claim left
from four stages of redesign.
**The first action was not a documentation task, and it is now half done.**
`docs/specs/frontend-roadmap.md` §A1: the owner opened `/` with reduced motion on in
Firefox on 2026-09-28 and the headline shows — settling the hydration half, which is
the half that had been outstanding since 2026-09-25. **Scrolling down closes the
rest**, because the sections below the hero use a different mechanism.

| File | What it is |
|---|---|
Expand All @@ -126,7 +129,7 @@ from four stages of redesign.
| `docs/adr/033-interface-and-learning-languages.md` | Names the four language axes, defers localisation, and records that `<track>` lacks `srclang`/`label` — which the API cannot yet supply |
| `docs/design-system.md` | Reference for tokens, the three component tiers, variants and states. Carries the two open design questions rather than settling them |
| `docs/specs/frontend-state-and-api.md` | State boundaries, problem-type handling, retry safety, and a **measured** bundle baseline |
| `docs/runbooks/accessibility-verification.md` | Automated versus human checks. **Written, never walked** |
| `docs/runbooks/accessibility-verification.md` | Automated versus human checks. **§3.1 partly walked 2026-09-28; nothing else** |
| `docs/frontend-principles.md` | Fourteen rules, each linked to its authority |
| `docs/design/figma-handoff.md` | A written structure. **No Figma file was created or modified** |
| `docs/specs/frontend-roadmap.md` | The remaining gaps in dependency order, **conditional on which ADRs are accepted**. Nothing in it jumps ahead of M14 |
Expand All @@ -147,10 +150,9 @@ from four stages of redesign.
**Documenting is not implementing, and all four ADRs being accepted has not
changed that.** The documents describe decisions and procedures; two of the
defects they identified were then fixed in code with provoked tests, and the rest
is still unbuilt. `runbooks/accessibility-verification.md` says of itself that it
has never been walked, and section A of the roadmap — five verification items,
including the reduced-motion check outstanding since 2026-09-25 — needs a person
with a browser rather than an agent.
is still unbuilt. `runbooks/accessibility-verification.md` has one row in its
verification log — §3.1's hero half, 2026-09-28 — and section A of the roadmap still
needs a person with a browser rather than an agent for the rest.

---

Expand Down Expand Up @@ -195,14 +197,14 @@ something got through every check that already existed:

**Two things are explicitly not verified, and neither should be read as done:**

- **The reduced-motion fix has never been seen working in a browser.** React's
hydration error is gone — that is verified — but "the content becomes visible"
is not the same claim. The only browser available to the agent reports
`document.hidden` even when fronted, so `requestAnimationFrame` is frozen at
zero frames per second and Motion cannot animate in it at all. **Someone needs
to open `/` with reduce-motion enabled and confirm the headline appears.** This
is the only item outstanding from four stages of work, and it is a thirty-second
check.
- **The reduced-motion fix was unobserved when this was written; the hero half was
confirmed on 2026-09-28.** React's hydration error being gone was always verified;
"the content becomes visible" is a different claim, and the owner has now seen the
headline in Firefox with reduced motion on. What is still unobserved is everything
below the hero, which animates through `whileInView` rather than on mount. The
agent's browser reports `document.hidden` even when fronted, so
`requestAnimationFrame` is frozen at zero frames per second and Motion cannot
animate in it at all. The remaining half is a scroll away.
- **The backend suite has not been run since M14 T6.** Nothing under `backend/`
has changed across these four stages, which is inference, not a run. The 1532
figure below is inherited.
Expand Down
46 changes: 30 additions & 16 deletions docs/adr/030-accessibility-wcag-22-aa.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,15 +109,22 @@ caption is *correct*.
| `Field.test.tsx` | 1.3.1, 3.3.1, 4.1.3 — label association, `aria-invalid`, `role="alert"` |
| `PageTitle.test.tsx` | one heading treatment, no hand-written `<h1>` |

**Proposed additions, all without a dependency:**
**Added 2026-09-27, no dependency:**

1. **3.3.8** — assert every auth field sets `autoComplete`. A future "security
hardening" that strips it would break password managers, which is the failure
this criterion exists for, and nothing would notice today.
2. **2.5.8** — assert the `sm` and `md` button sizes keep a minimum height at or
above 24px. A unit assertion on the variant strings, not a rendered
measurement, so it is cheap and stable.
3. **2.4.11** — once reproduced, a test for whichever remedy is chosen.
1. **3.3.8** — `(auth)/accessible-authentication.test.tsx`. Asserts every auth field
sets `autoComplete`, and the *values*: a manager offers a saved password for
`current-password` and a generated one for `new-password`, and swapping those is
the failure that looks like it works. Also asserts no CAPTCHA. The regression it
guards is a plausible one — stripping `autocomplete` from a login form looks like
hardening and breaks exactly what this criterion relies on.
2. **2.5.8** — `ui/Button.test.tsx`. Asserts each size keeps a minimum height at or
above 24px, against the variant strings rather than a rendered box, because jsdom
computes no layout.

**Still outstanding:**

3. **2.4.11** — once reproduced. There is no remedy to test until somebody has seen
the fault, and ADR-006 forbids fixing what has not been seen.

**Requires a person, and cannot be delegated to a scan:**

Expand All @@ -126,7 +133,8 @@ caption is *correct*.
changes announced without flooding.
- 200% zoom and 320 CSS px reflow (1.4.10), at which the lesson layout's two
columns must collapse.
- `prefers-reduced-motion` in a real browser — **still outstanding**, see §6.
- `prefers-reduced-motion` in a real browser — **hero confirmed 2026-09-28**; the
scroll-triggered sections below it are still unobserved. See §6.
- `forced-colors: active`, which ADR-029's palette cannot be reasoned about.
- Caption accuracy, which is a human review step in the transcript workflow
(ADR-014, ADR-015) and not a frontend concern.
Expand Down Expand Up @@ -164,13 +172,19 @@ installed.

## 6. One thing this ADR does not let us claim

**No conformance claim is made, and one item is outstanding.** The
reduced-motion fix shipped in PR #71 has never been observed working in a
browser: the only browser available to the agent reports `document.hidden` even
when fronted, so `requestAnimationFrame` is frozen at zero frames per second and
Motion cannot animate in it. React's hydration error is gone — that is verified —
but "the content becomes visible for a reduced-motion visitor" is a different
claim and remains unverified.
**No conformance claim is made.** The reduced-motion fix shipped in PR #71 is now
**half confirmed**: the owner saw the headline in Firefox with reduced motion on,
2026-09-28, which establishes the hydration fix — the mismatch is what left
`opacity: 0` stuck inline. The sections below the hero use a different mechanism
(`whileInView` and an `IntersectionObserver`) and are still unobserved.

The agent cannot close the rest: its browser reports `document.hidden` even when
fronted, so `requestAnimationFrame` is frozen at zero frames per second and Motion
cannot animate in it at all.

Adopting 2.2 AA is a commitment to a target and a verification procedure. It is
still not a statement that the product conforms, and this file must not be cited as
one.

Adopting 2.2 AA is a commitment to a target and a verification procedure. It is
not a statement that the product currently conforms, and this file must not be
Expand Down
42 changes: 31 additions & 11 deletions docs/runbooks/accessibility-verification.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Runbook — verifying accessibility

**Status: written, never walked.** Written 2026-09-27 alongside ADR-030. No pass
described below has been performed end to end, and one step (§3.1) is known to be
**impossible** in the agent's browser and has been outstanding since 2026-09-25.
**Status: written; §3.1 partly walked 2026-09-28.** Written 2026-09-27 alongside
ADR-030. The owner confirmed the hero half of §3.1 in Firefox; **the below-the-fold
half is still open**, and no other pass below has been performed. See §6.

Treat every step in §3 as a plan rather than a tested procedure. `rollback.md`
found its own §3 wrong the first time it was walked; assume this one has the same
Expand Down Expand Up @@ -60,7 +60,7 @@ differs more between versions than between pages.
Each is a separate sitting. Do not try to do all five at once — they use different
attention and the mistakes cross over.

### 3.1 Reduced motion — **outstanding, and the oldest item here**
### 3.1 Reduced motion — **hero confirmed 2026-09-28; below the fold still open**

Turn on the OS setting (Windows: Settings → Accessibility → Visual effects →
Animation effects off; macOS: Accessibility → Display → Reduce motion), then open
Expand All @@ -75,11 +75,21 @@ blank** for reduced-motion visitors: ten components branched on
`opacity: 0` inline, and React declined to patch the mismatch. A unit test
asserted the branch and passed the whole time because it mocked the hook.

The fix is believed correct and **has never been observed working.** The agent's
browser reports `document.hidden` even when fronted, so `requestAnimationFrame`
is frozen at zero frames per second and Motion cannot animate in it at all —
which also means that pane cannot distinguish a working page from a broken one.
React's hydration error is gone; that is verified. This is the other half.
**Confirmed for the hero on 2026-09-28** — the owner saw the headline in Firefox
with reduced motion on. That is the half that proves the hydration fix: the
mismatch is what left `opacity: 0` stuck inline, so a visible headline means server
and client now agree.

**The half below the hero is still open, and it is a different mechanism.** The
headline, subtitle and calls to action come from `Hero`, which animates on mount.
The featured course cards and the four "what you get" panels use `Reveal` and
`StaggerList`, driven by `whileInView` and an `IntersectionObserver` — and they were
also among the nine blanked elements. Scroll down with the setting still on.

The agent cannot close either half: its browser reports `document.hidden` even when
fronted, so `requestAnimationFrame` is frozen at zero frames per second and Motion
cannot animate in it at all — which also means that pane cannot distinguish a
working page from a broken one.

Also check `prefers-reduced-motion` on `/courses/[slug]` (the `Reveal` sections)
and the enrolment list (`StaggerList`).
Expand Down Expand Up @@ -185,6 +195,16 @@ it has entries, nothing in this file may be cited as evidence of conformance.

| Date | Section | By | Result |
|---|---|---|---|
| — | — | — | — |
| 2026-09-28 | §3.1, hero only | Owner, Firefox | **Headline shows with reduced motion on.** This is the half that proves the hydration fix: the mismatch is what left `opacity: 0` stuck inline, so a visible headline means the server and client now agree. Version not recorded |

**Still outstanding in §3.1: everything below the hero.** The headline, subtitle and
both calls to action come from `Hero`, which animates *on mount*. The sections
underneath use a different mechanism — `Reveal` and `StaggerList`, driven by
`whileInView` and an `IntersectionObserver` — and were also among the nine blanked
elements. Confirming the hero does not confirm those.

**Twenty seconds closes it:** with reduced motion still on, scroll down `/` and check
that the **featured course cards** and the **four "what you get" panels** appear.
Also worth a glance at a course page, which uses `Reveal` for its sections.

Known outstanding: **§3.1**, since 2026-09-25.
Nothing else in §3 has been walked.
15 changes: 10 additions & 5 deletions docs/specs/frontend-roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,20 @@ it**, so doing A last would be the expensive order.
**No code changes. Nothing here needs an ADR approved.** Each item converts a
believed claim into a known one, and two of them gate later work.

### A1 · Reduced motion in a real browser — **do this first**
### A1 · Reduced motion in a real browser — **half done 2026-09-28**

- **Benefit:** confirms the landing page is not blank for visitors who asked for
less motion. Until stage 2 it was — entirely, for exactly those people.
- **Scope:** ten minutes. `docs/runbooks/accessibility-verification.md` §3.1.
- **Dependencies:** none. **Outstanding since 2026-09-25.**
- **Acceptance:** headline, subtitle, both calls to action, course cards and all
four feature panels visible with the OS reduced-motion setting on; runbook §6
gains its first row.
- **Done 2026-09-28:** the owner confirmed the **headline** shows in Firefox with
reduced motion on. That is the half that proves the hydration fix — the mismatch
is what left `opacity: 0` stuck inline, so a visible headline means server and
client agree. Runbook §6 has its first row.
- **Still open, and a different mechanism:** everything below the hero. The headline,
subtitle and calls to action animate *on mount*; the featured course cards and the
four "what you get" panels use `Reveal`/`StaggerList`, driven by `whileInView` and
an `IntersectionObserver`, and were also among the nine blanked elements.
**Scrolling down with the setting still on closes it — twenty seconds.**
- **Why it cannot be automated here:** the agent's browser reports
`document.hidden` even when fronted, so `requestAnimationFrame` is frozen and
that pane cannot tell a working page from a broken one.
Expand Down
Loading