From 91e3687cbdc97b6e7fc19a594476e57d085c9879 Mon Sep 17 00:00:00 2001 From: propcgamer20-png Date: Fri, 14 Aug 2026 18:35:09 +0530 Subject: [PATCH 1/2] Enhance HTML table structure and styling in report.py --- faircode/report.py | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/faircode/report.py b/faircode/report.py index 5dae654..0001326 100644 --- a/faircode/report.py +++ b/faircode/report.py @@ -191,8 +191,9 @@ def esc(s) -> str: reference_html = ( f'

Reference ' f'deviation {ref["deviation"] * 100:.1f}%

' - f'' - f'' + f'
ExpectedActualDelta
' + f'' + f'' f'{ref_rows}
Expected vs. actual share - {esc(d["name"])}
ExpectedActualDelta
' ) @@ -200,7 +201,11 @@ def esc(s) -> str: f'

{esc(d["name"])} ' f'{esc(d["kind"])} ' f'{d["dimension_score"]}/100

' - f'{"".join(rows)}
{reference_html}
' + f'' + f'' + f'' + f'' + f'{"".join(rows)}
Group breakdown - {esc(d["name"])}
GroupShare95% CICount
{reference_html}' ) flag_html = "" @@ -236,6 +241,11 @@ def esc(s) -> str: .dim {{ background:var(--surface); border:1px solid var(--border); border-radius:8px; padding:16px 20px; margin:16px 0; }} table {{ width:100%; border-collapse:collapse; }} + caption {{ text-align:left; font-size:11px; color:var(--muted); text-transform:uppercase; + letter-spacing:.04em; margin-bottom:4px; }} + th {{ padding:4px 8px; font-size:14px; font-weight:600; text-align:left; + border-bottom:2px solid var(--border); }} + th.num {{ text-align:right; }} td {{ padding:4px 8px; font-size:14px; border-bottom:1px solid var(--border); }} td.num {{ text-align:right; font-variant-numeric:tabular-nums; white-space:nowrap; }} td.ci {{ color:var(--muted); font-size:12px; }} @@ -348,7 +358,10 @@ def signed(val: float | int, dp: int = 1) -> str: f'{esc(cd["drift_level"])} drift' f'
PSI {cd["psi"]:.3f} · TVD {cd["tvd"]:.3f} · score {cd["dimension_score_a"]}→{cd["dimension_score_b"]} ({signed(cd["dimension_score_delta"], 0)})
' '' - f'{"".join(rows)}
' + f'' + f'' + f'' + f'{"".join(rows)}
Group-level share drift - {esc(cd["name"])}
GroupShare A → BΔ
' f'{more_html}' '' ) @@ -390,6 +403,11 @@ def signed(val: float | int, dp: int = 1) -> str: ".drift-card-head h2 { margin:0; font-size:18px; } " ".drift-metrics { font-size:12px; color:var(--muted); } " "table { width:100%; border-collapse:collapse; } " + "caption { text-align:left; font-size:11px; color:var(--muted); text-transform:uppercase; " + "letter-spacing:.04em; margin-bottom:4px; } " + "th { padding:6px 8px; font-size:14px; font-weight:600; text-align:left; " + "border-bottom:2px solid var(--border); } " + "th.num { text-align:right; } " "td { padding:6px 8px; font-size:14px; border-bottom:1px solid var(--border); } " "td.num { text-align:right; font-variant-numeric:tabular-nums; white-space:nowrap; font-size:13px; } " "td.label { width:25%; } " From 11e671c8faaa6f5a48c517566e77f6278294eddc Mon Sep 17 00:00:00 2001 From: propcgamer20-png Date: Fri, 14 Aug 2026 18:35:31 +0530 Subject: [PATCH 2/2] Update CHANGELOG for recent feature additions and fixes Updated CHANGELOG with recent changes including improvements to pre-push tests, CI workflows, accessibility features, and bug fixes. Added details on new scripts for checking broken links and enhancing HTML report tables. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f76549a..59e9f96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ All notable changes to Fair Code are documented here, newest first. - **Change-aware CI: `profiler`/`benchmark-harness` skip on docs-only changes** - extends the same idea to `.github/workflows/audits.yml`. A new `changes` job diffs the push/PR against its base commit and gates `profiler` (the full pytest suite) and `benchmark-harness` (the fairlearn end-to-end smoke test) behind whether anything test-relevant changed - same path set as the pre-push hook above, kept in sync deliberately. `run-audits` is left untouched and always runs: it's the one job in this workflow that's a required status check (#160), and a job skipped via `if:` can leave a required check permanently "waiting to be reported" instead of green, which would block merging every docs-only PR. `profiler`/`benchmark-harness` aren't required checks, so skipping them is risk-free. - **Theme-toggle button now exposes its state to assistive tech** (closes #250) - `#themeToggle`/`#explainerThemeToggle` had a dynamic `aria-label` ("Switch to light/dark mode") but nothing a screen reader announces as state, unlike the visible ☀/☾ glyph swap. Added `aria-pressed="true"/"false"` (`true` = dark mode active), kept in sync everywhere the label/glyph already update - initial load and on click - across `index.html`, `profiler.html`, and the explainer-page template in `scripts/build_explainers.py` (`make build-explainers` re-run to regenerate all 39 explainer pages). - **`scripts/check_broken_links.py`** (closes #253) - checks every tracked `.md` file for a `[text](#anchor)` that doesn't match any heading on that page, or a relative link/anchor to another file that doesn't exist. Wired into `make lint`/`lint.yml` alongside the em-dash check (that job is renamed `lint` accordingly). The anchor slugifier was reverse-engineered against all 71 real anchor links already in the repo (70 matched cleanly; the one holdout is a `#link-to-section` placeholder inside a CONTRIBUTING.md code-fence example, correctly ignored) rather than assumed, since GitHub's exact algorithm isn't public. Running it against the current tree found five real, previously-unnoticed broken links in the raw markdown - three explainers linked a misspelled/nonexistent `Ai Fair Recrutment Dataset` folder instead of `AI Fair Recruitment`, and `proxy-entanglement.md` linked a notebook path missing its `../` prefix - fixed in `explainers/neural-networks.md`, `proxy-variables.md`, `shap-values.md`, and `proxy-entanglement.md`. +- **`faircode/report.py`'s HTML report tables get proper headers** (closes #254) - the per-column breakdown table and the drift-comparison table had no `` header row at all (only the smaller reference-deviation table did, and even that had no `scope`); a screen reader had nothing to announce when reading a data cell. Added a ``/`` row plus a `` to all three tables (in both `to_html` and `compare_to_html`), with matching `th`/`caption` CSS in each report's embedded stylesheet - the caption text stands on its own since the report is often shared outside the page it was generated on (CI output, email, a PR comment). ### Fixed - **`scripts/build_explainers.py`'s `resolve_link_target()` silently broke every generic cross-repo-root link in an explainer** - found while fixing #253 above: rebuilding after the notebook-link fix showed the generated `.html` still pointing at the old broken path. Its fallback branch stripped a leading `../` from any relative link that wasn't a known explainer `.md` or a recognized project folder, even though `explainers/*.md` and the `.html` generated from it live in the same directory, so a plain relative link needs no rewriting at all. This wasn't just the notebook link - `disparate-impact.md`'s links to `unfair.py`/`fair.py` in `AI Fair Recruitment/` had the exact same bug, already live on the deployed site. Also removed a `PROJECT_ANCHORS` entry that hardcoded the misspelled `"Ai Fair Recrutment Dataset"` folder name as a redirect target - a band-aid for the exact typo fixed at the source above, now dead code.