diff --git a/.jules/palette.md b/.jules/palette.md index 74cddb7ad..41aa65b7f 100644 --- a/.jules/palette.md +++ b/.jules/palette.md @@ -19,3 +19,7 @@ ## 2024-07-13 - CLI Debugging Stack Traces **Learning:** Adding a `FAST_MLSIRM_DEBUG` bypass to user-friendly `try/except` blocks is crucial for DX. Otherwise, unexpected runtime errors during development will be swallowed into generic stderr messages, hiding the stack trace needed to actually fix the bug. **Action:** When adding `try-except` blocks to Python CLI subcommands to improve Developer Experience (DX) by preventing raw tracebacks for users, include a debug bypass (e.g., `if os.environ.get("FAST_MLSIRM_DEBUG"): raise`) in *all* catch blocks (including `RuntimeError` and `Exception`) to ensure tracebacks aren't swallowed during local development and debugging. + +## 2024-07-14 - Skip-to-Content Link Target Focus Outline +**Learning:** While `outline: none;` on the target `
` element prevents an unsightly visual artifact when a mouse user clicks inside it, it completely breaks keyboard accessibility by removing the focus indicator when a screen reader or keyboard user tabs into it via the skip-link. +**Action:** When implementing a programmatically focusable container (like a skip-link target), ensure `outline: none;` (or `:focus { outline: none; }`) is always paired with a visible outline using the `:focus-visible` pseudo-class so that keyboard navigation remains accessible without compromising mouse interaction. diff --git a/CHANGELOG.md b/CHANGELOG.md index a9a94ed43..82cd06d23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ ### Changed +- Added a keyboard-visible focus outline (`main:focus-visible`) to the - Rust EAP scoring now defaults to GPU-preferred `auto` execution in the core, PyO3 binding, and serving API. The f64 CPU reduction remains available via `device="cpu"`; an explicit unavailable `device="gpu"` request now warns diff --git a/python/fast_mlsirm/report.py b/python/fast_mlsirm/report.py index 30ee4276b..6f41764e3 100644 --- a/python/fast_mlsirm/report.py +++ b/python/fast_mlsirm/report.py @@ -498,6 +498,11 @@ def _css() -> str: outline: none; } +main:focus-visible { + outline: 3px solid #0f766e; + outline-offset: 3px; +} + .hero { min-height: 172px; display: flex; diff --git a/tests/test_report.py b/tests/test_report.py index 52d1d9091..5f6f65e6f 100644 --- a/tests/test_report.py +++ b/tests/test_report.py @@ -233,6 +233,29 @@ def test_render_report_requires_html_output(tmp_path): render_diagnostics_report(source, out) +def test_render_main_region_has_keyboard_focus_style(tmp_path): + source = tmp_path / "dimension_diagnostics.json" + out = tmp_path / "dimensions.html" + source.write_text( + json.dumps( + { + "candidates": [{"latent_dim": 2.0, "heldout_loglik": -8.0}], + "best": {"latent_dim": 2.0}, + } + ), + encoding="utf-8", + ) + + render_diagnostics_report(source, out) + + html = out.read_text(encoding="utf-8") + assert 'id="main-content"' in html + assert 'tabindex="-1"' in html + assert "main:focus-visible {" in html + assert "main:focus {" in html + assert "outline: 3px solid #0f766e;" in html + + def test_render_table_region_has_keyboard_focus_style(tmp_path): source = tmp_path / "dimension_diagnostics.json" out = tmp_path / "dimensions.html"