Skip to content

Fork-network mining results, capability gap inventory, and a conformance harness - #1

Merged
MentalGear merged 10 commits into
mainfrom
claude/fork-fix-mining-ajwum2
Aug 29, 2026
Merged

MentalGear merged 10 commits into
mainfrom
claude/fork-fix-mining-ajwum2

Conversation

@MentalGear

Copy link
Copy Markdown
Owner

Research output for the chore/fork-fix-mining brief, plus two things the brief did not ask for but the evidence forced: an inventory of missing capabilities, and an executable oracle that turned one of them from a claim into a measured result.

No component code is changed. Everything here is documentation and tests.

What was mined

The brief scopes to two forks. This covers all 81 in the network — 111 refs carrying commits absent from upstream's 637-commit history, filtered by patch-id and then verified against the current source. The wider scope was not free, but one of the four adoptable fixes comes from jcgruenhage, outside the brief's two forks.

Only 18 of those 111 refs are a fork's main; 31 forks have an upstream-identical main but unique work on a topic branch. A main-only sweep would have missed every adoptable fix.

Findings

Four bug fixes, never submitted upstream, still live on main — all cherry-pick tested end to end from a clean checkout:

Fix Source Files
RangeSlider thumbs swap identity on collision sarendipitee@42b56dd3 slider.rs
use_animated_open unmount race jcgruenhage@6f0a69f0 lib.rs
Popover self-dismisses on internal click sarendipitee@f63ee07e lib.rs, popover.rs
VirtualList holds a borrow across the call that reads it sarendipitee@799a4ff3 virtual_list.rs

Two forks fix use_animated_open in incompatible directions, and the one with an open upstream PR (DioxusLabs#291) is the weaker: its per-animation .catch() lets a stale close task overwrite state after a reopen, trading a stuck-open element for one that disappears while open.

Three capability gaps outrank all four fixes:

  1. RadioGroup and Select declare name/required, document them as being for form submission, and never reference them in their render bodies. Checkbox does it correctly.
  2. No overlay does collision detection — placement is static CSS keyed off data-side.
  3. Closing a DropdownMenu, ContextMenu, Menubar or Select never returns focus to the trigger.

Finding 3 is confirmed by execution, not by reading: four failing conformance tests against a passing Dialog control. It also corrected the static analysis — focus falls to <body> only in ContextMenu; DropdownMenu and Menubar keep focus on the closed menu's item, which is worse and needs a different fix.

Contents

Path What
docs/README.md Index and per-claim confidence
docs/adopt-fork-fixes-results.md The mining report (3 adversarial review rounds)
docs/capability-gaps.md Missing capabilities and which fork closed each
docs/lifting-from-forks.md Porting playbook: licensing, three lift shapes, name mapping, traps
docs/conformance-harness.md Harness design: APG / HTML / Radix-opinion tiers and their sources
playwright/oracle-focus-restore.spec.ts Five APG conformance tests — 4 red, 1 control green

Deviations from the brief, stated plainly

  • Scope: 81 forks rather than the two named.
  • Format: the brief asks for a categorized, batched table (commit · fork · category · what it fixes · take? · batch). Not yet produced — the report is prose with per-candidate detail.
  • File: this branch had overwritten docs/adopt-fork-fixes.md, which is the brief itself on chore/fork-fix-mining. Restored; the report now uses the output name the brief specifies.

Verification

  • Executed: focus restore (4 fail / 1 control pass), and every cherry-pick in the adoption sequence.
  • Static: everything else. No component code was compiled as part of these claims.
  • Point-in-time: PR states and fork contents read on 2026-08-29.
  • Branch fix/preview-a11y-ux is not merged into main — its three CSS fixes remain pending there.

Generated by Claude Code

claude added 10 commits August 29, 2026 13:02
Surveys all 81 forks of DioxusLabs/dioxus-components for work that never
made it upstream, and records what is worth adopting into this fork.

Method: enumerate every fork ref, discard SHAs already present in
upstream's history, filter by patch-id, then verify each remaining
candidate against the current code on main and test cherry-pick
applicability. Topic branches are included deliberately -- 31 forks have
an upstream-identical main but carry unique work on a branch.

Findings: four unmerged correctness fixes that are still live on main
(RangeSlider thumb identity, use_animated_open unmount race, popover
outside-dismiss false positive, VirtualList borrow held across a call),
11 conditional candidates, and ~45 rejected with reasons.

Also documents a conflict between two competing fixes to
use_animated_open, where the version with an open upstream PR trades a
stuck-open element for one that disappears while open.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K3xAwYCh5jJupi9U4CG5C7
Adversarial review of the fork-fix report found four factual errors:

- Tumypmyp/main was listed as having a tree byte-identical to main. It
  does not: the fork is 51 commits behind and 2 ahead. It still yields
  nothing (diff against its merge-base is empty, since its sheet-example
  fix landed upstream independently), but the reason is staleness, not
  identity.
- The patch-identical count was 10; recomputing with git cherry over all
  111 mined refs gives 21 refs across 17 distinct branch tips.
- "58 forks with a novel ref" counted 9 forks whose only novelty is a
  gh-pages build branch, which the report excludes elsewhere. 49 have
  real work.
- hovinen's branch was described as adding only a test module. It also
  moves the workspace to dioxus 0.8.0-alpha.0 with a [patch.crates-io]
  block of git dependencies and a personal dioxus-test fork.

Also tightens two line citations (use_animated_open runs to 280, the
virtual_list borrow is at 203-205), clarifies that the WhaleFromMars
line numbers refer to main, records how PR states were checked, and
marks the section 5 race analysis as reasoned from source rather than
reproduced.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K3xAwYCh5jJupi9U4CG5C7
Second review pass found the one copy-pasteable section was broken:

- It named DioxusLabs/dioxus-components as the object source, but none of
  the four commits exist upstream -- they live only in the sarendipitee
  and jcgruenhage forks. Added the two remotes and the branches that
  carry the commits.
- `git cherry-pick <sha> -- <path>` is not valid git; it fails with "bad
  revision". Replaced with `git show <sha> -- <path> | git apply --index`
  plus `git commit -C <sha>`, which takes only the primitives hunk and
  preserves authorship.
- Spelled out the conflict resolution for the popover commit, whose only
  conflict is the fork's own playwright spec.

The whole sequence has now been executed against a clean checkout of
bf007c1 and produces four commits with original authorship intact.

Also notes that PR DioxusLabs#254 is a draft, and that the section 7 count is the
balance of the analysed candidates rather than an independent figure.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K3xAwYCh5jJupi9U4CG5C7
Companion to adopt-fork-fixes.md. That report covered bug fixes; this
covers behaviour a headless component library is expected to have, that
upstream does not implement, and that at least one fork does.

Three findings outrank everything in the fix report:

- RadioGroup and Select declare name/required props, document them as
  being for form submission, and never reference them in their render
  bodies. A developer following the documented API ships a form that
  silently omits the field. Checkbox does this correctly and is the
  reference implementation; Switch is half-wired.
- No overlay does collision detection. Placement is static CSS keyed off
  data-side, so any popover, select, tooltip or dropdown near a viewport
  edge renders off-screen, and ContextMenu opens at raw click
  coordinates with no clamping.
- Closing a DropdownMenu, ContextMenu, Menubar or Select drops focus to
  body. Dialog and Popover restore focus correctly via the vendored
  focus trap; the menu family never got it.

Also records the layer map: primitives IS this repo (there is no
separate primitives repository), and the framework offers no body/scroll
or portal API, so document::eval is the only mechanism available for
scroll lock and aria-hidden work.

Verification is static -- nothing was compiled or run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K3xAwYCh5jJupi9U4CG5C7
A specification oracle rather than a regression test: each assertion
encodes a rule from the WAI-ARIA Authoring Practices Guide, the standard
this library's README commits to, so a failure is a conformance gap
rather than a preference.

Covers the rule that Escape closes the overlay and returns focus to the
trigger, for DropdownMenu, Select, Menubar and ContextMenu -- the four
components that move real DOM focus onto their items via roving tabindex
and, per static analysis, never hand it back.

Includes a control case: Dialog implements focus restore via the
vendored focus trap and must pass. If the control fails alongside the
others, the harness is at fault rather than the components. Failures
print where focus actually landed so the output diagnoses rather than
just reports.

The existing suite already presses Escape and asserts data-state closed
on these components but never asserts where focus went, which is how 122
tests coexist with this gap.

Not yet executed -- the preview app is still building.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K3xAwYCh5jJupi9U4CG5C7
The oracle was executed against the preview app built from this commit.
Four of the five tests fail and the control passes:

  DropdownMenu  focus stays on <div role="option"> "Edit"      FAIL
  Menubar       focus stays on <div role="menuitem"> "New"     FAIL
  ContextMenu   focus falls to <body>                          FAIL
  Select        trigger reported inactive                      FAIL
  Dialog        focus returns to its trigger                   PASS (control)

The passing control is what makes the failures meaningful: same
harness, same page, same keypress, and Dialog behaves correctly.

It also corrects the static analysis. I predicted focus falls to <body>
in all four cases; that holds only for ContextMenu. In DropdownMenu and
Menubar focus remains on the menu item of the menu that just closed,
which is worse than <body> -- the next Tab continues from inside
dismissed content that is no longer on screen. These therefore are not
one bug with one shared fix.

Adds a local-only playwright config because this image ships Chromium
1194 while the pinned Playwright wants 1223; it also reuses an
already-running dx server instead of starting its own.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K3xAwYCh5jJupi9U4CG5C7
lifting-from-forks.md is the missing "how": the licence position
(upstream and all three source forks are MIT OR Apache-2.0, so lifting
is permitted and attribution is the requirement), how to fetch fork
branches into a private ref namespace, and three lift shapes --
cherry-pick a commit, lift a module, port a concept -- with the rule
for choosing between them.

It records the traps found the hard way: never take dependency edits,
check whether a file is generated before patching it (focus-trap.js is
rebuilt from .ts and silently discards edits), git cherry is a filter
rather than a verdict, and verify the bug still exists before porting
its fix.

It also carries a name-mapping table verified against main --
use_effect_cleanup and dioxus_sdk_time::sleep are already present under
the same names, ReadOnlySignal has been renamed to ReadSignal,
use_previous does not exist, focus.rs was deleted in favour of
selectable/selection/listbox/collection -- plus the environment setup
needed to run the oracle, where the dx version must match the lockfile
rather than Cargo.toml and dx cannot fetch its own dependencies unless
NO_PROXY is narrowed.

The queue lists ten items with the oracle to write for each, flagging
the three that need demo fixtures that do not exist yet.

docs/README.md indexes the four artifacts and states confidence
per claim: focus restore is executed, everything else is static.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K3xAwYCh5jJupi9U4CG5C7
Branch chore/fork-fix-mining carries docs/adopt-fork-fixes.md as a task
brief, and this branch had overwritten that path with the mining report.
The brief is restored, and the report moves to the filename the brief
actually asks for as its output: docs/adopt-fork-fixes-results.md.
Cross-links updated.

Two differences between the brief and what was produced are worth
stating rather than hiding:

- Scope. The brief names two forks (dignifiedquire, sarendipitee); the
  survey covered all 81 in the network. That was not free -- but one of
  the four adoptable fixes comes from jcgruenhage, outside the brief's
  scope, and would have been missed.
- Format. The brief asks for a categorized, batched table with columns
  commit/fork/category/what it fixes/take?/batch. The report is prose
  with per-candidate detail and does not yet present that table.

Also records that branch fix/preview-a11y-ux is NOT folded into main:
its three CSS fixes (iOS focus auto-zoom floor, accordion grid-rows
animation, dropdown/select viewport clamp) are absent from main and
still pending on that branch. Its dropdown clamp comment independently
corroborates the collision-detection gap, calling collision-aware
flip/shift positioning an upstream concern.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K3xAwYCh5jJupi9U4CG5C7
…ance

Correction: an earlier draft credited upstream's move away from native
<dialog> to commit dd87bf0 "Rewrite Dialog and AlertDialog primitives
to match Radix". That commit is not in upstream main -- merge-base
--is-ancestor fails, it exists only in dignifiedquire's fork, and that
author has zero commits in upstream main. Upstream did once use
showModal and now renders div role="dialog"; the Radix-parity rewrite
is the fork's direction, not upstream's.

Adds a section on what the project is reaching for, since it decides
which harness rules are binding. The README requires new primitives to
adhere to the WAI-ARIA Authoring Practices and describes the styled
layer as shadcn style; Radix is not mentioned there at all. But
primitives/src contains zero links to w3.org or the Authoring
Practices, zero commits reference wai-aria or APG, and the four Radix
mentions are peer-precedent asides rather than specification.

The standard is therefore the stated contract and Radix the informal
touchstone, with neither systematically checked -- which is how a
focus-restore gap survives 122 Playwright tests. For the harness: hold
the library to APG because it is its own commitment, keep Radix-parity
rules in a separately labelled tier, and treat form submission as a
third source that is plain HTML semantics.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K3xAwYCh5jJupi9U4CG5C7
Adds docs/conformance-harness.md, which settles where each rule in the
harness comes from and how the harness proves itself before judging a
component.

Three tiers, kept separate on purpose: APG (the project's own stated
contract), HTML (form submission and constraint validation), and
Radix-parity (explicitly opinion, since upstream never committed to
Radix and could fairly reject a suite that conflates the two).

Researched the HTML tier, which is where the most severe defect sits.
The normative text is the WHATWG spec's form-control-infrastructure,
forms, and form-elements sections, all verified reachable. The decisive
concept is "submittable element": only button, input, select and
textarea can contribute to a form's entry list, so a div role="radio"
cannot participate however much ARIA it carries. Dioxus renders plain
DOM rather than custom elements, so ElementInternals.setFormValue is
unavailable and the hidden-native-input pattern is the only conforming
approach, not a hack.

For executable reference, web-platform-tests sparse-clones to 32MB for
html/semantics/forms: form-submission-0 (33 tests, including
constructing-form-data-set), constraints (44), resetting-a-form,
the-label-element. These cannot be pointed at our components -- they
assert on native elements -- so they serve as a rule inventory and a
proven technique rather than as our suite. The eight rules they yield
are listed; the first four would have caught the RadioGroup and Select
defects.

Records the calibration design: every rule runs against the component
and a known-correct reference. For the HTML tier that reference is the
browser itself -- a native input in the same fixture -- which needs no
vendoring and cannot drift, making it stronger than the current
internal Dialog control.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K3xAwYCh5jJupi9U4CG5C7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants