Fork-network mining results, capability gap inventory, and a conformance harness - #1
Merged
Merged
Conversation
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Research output for the
chore/fork-fix-miningbrief, 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-identicalmainbut 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:RangeSliderthumbs swap identity on collisionsarendipitee@42b56dd3slider.rsuse_animated_openunmount racejcgruenhage@6f0a69f0lib.rssarendipitee@f63ee07elib.rs,popover.rsVirtualListholds a borrow across the call that reads itsarendipitee@799a4ff3virtual_list.rsTwo forks fix
use_animated_openin 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:
RadioGroupandSelectdeclarename/required, document them as being for form submission, and never reference them in their render bodies.Checkboxdoes it correctly.data-side.DropdownMenu,ContextMenu,MenubarorSelectnever returns focus to the trigger.Finding 3 is confirmed by execution, not by reading: four failing conformance tests against a passing
Dialogcontrol. It also corrected the static analysis — focus falls to<body>only inContextMenu;DropdownMenuandMenubarkeep focus on the closed menu's item, which is worse and needs a different fix.Contents
docs/README.mddocs/adopt-fork-fixes-results.mddocs/capability-gaps.mddocs/lifting-from-forks.mddocs/conformance-harness.mdplaywright/oracle-focus-restore.spec.tsDeviations from the brief, stated plainly
commit · fork · category · what it fixes · take? · batch). Not yet produced — the report is prose with per-candidate detail.docs/adopt-fork-fixes.md, which is the brief itself onchore/fork-fix-mining. Restored; the report now uses the output name the brief specifies.Verification
fix/preview-a11y-uxis not merged intomain— its three CSS fixes remain pending there.Generated by Claude Code