diff --git a/README.md b/README.md
index badf8a6..a8b3915 100644
--- a/README.md
+++ b/README.md
@@ -49,15 +49,15 @@ WPT corpus is SHA-pinned by [`scripts/fetch_references.sh`](scripts/fetch_refere
to commit [`dd54691`](https://github.com/web-platform-tests/wpt/commit/dd54691426c23a08c6f4a0972b2c40965307e5ce)
(2026-05-11) so the pass count is reproducible at any future date.
-| Suite | Source | Cases | Status |
-|---|---|---:|:---:|
-| `urlpattern.any.js` | WPT · `urlpatterntestdata.json` | 366 | ✓ 366 / 366 |
-| `urlpattern-constructor.any.js` | WPT *(inline)* | 4 | ✓ 4 / 4 |
-| `urlpattern-hasregexpgroups.any.js` | WPT · `urlpattern-hasregexpgroups-tests.js` | 55 | ✓ 55 / 55 |
-| `urlpattern-compare.tentative.any.js` | WPT · `urlpattern-compare-test-data.json` | 25 | ✓ 25 / 25 |
-| `urlpattern-generate.tentative.any.js` | WPT · `urlpattern-generate-test-data.json` | 19 | ✓ 19 / 19 |
-| yarlpattern unit tests | this repo · tokenizer / parser / parts / regex / engine / pattern | 130 | ✓ 130 / 130 |
-| **Total** | | **599** | ✓ **599 / 599** |
+| Suite | Source | Status |
+|---|---|:---|
+| `urlpattern.any.js` | WPT · `urlpatterntestdata.json` | ✅ 366 / 366 |
+| `urlpattern-constructor.any.js` | WPT *(inline)* | ✅ 4 / 4 |
+| `urlpattern-hasregexpgroups.any.js` | WPT · `urlpattern-hasregexpgroups-tests.js` | ✅ 55 / 55 |
+| `urlpattern-compare.tentative.any.js` | WPT · `urlpattern-compare-test-data.json` | ✅ 25 / 25 |
+| `urlpattern-generate.tentative.any.js` | WPT · `urlpattern-generate-test-data.json` | ✅ 19 / 19 |
+| yarlpattern unit tests | this repo · tokenizer / parser / parts / regex / engine / pattern | ✅ 130 / 130 |
+| **Total** | | ✅ **599 / 599** |
→ [**Full per-case conformance report**](docs/wpt-compliance.md) (regenerate via `just compliance-report`)
· [**Documented deviations and stricter-than-yarl rules**](SPEC_DEVIATIONS.md)
diff --git a/docs/wpt-compliance.md b/docs/wpt-compliance.md
index 4eb1965..fd99a5b 100644
--- a/docs/wpt-compliance.md
+++ b/docs/wpt-compliance.md
@@ -1,15 +1,9 @@
# WHATWG URLPattern Conformance Report
-Generated by `scripts/generate_compliance_report.py` on **2026-05-13 03:13:47 UTC**, running against [`web-platform-tests/wpt/urlpattern/`](https://github.com/web-platform-tests/wpt/tree/dd54691426c23a08c6f4a0972b2c40965307e5ce/urlpattern) pinned at [`dd54691`](https://github.com/web-platform-tests/wpt/commit/dd54691426c23a08c6f4a0972b2c40965307e5ce) with regex engine **`regex`** (set-operation support: yes). Suite names match the upstream WPT runner basenames.
+Generated by `scripts/generate_compliance_report.py` on **2026-05-13 04:06:52 UTC**, running against [`web-platform-tests/wpt/urlpattern/`](https://github.com/web-platform-tests/wpt/tree/dd54691426c23a08c6f4a0972b2c40965307e5ce/urlpattern) pinned at [`dd54691`](https://github.com/web-platform-tests/wpt/commit/dd54691426c23a08c6f4a0972b2c40965307e5ce) with regex engine **`regex`** (set-operation support: yes). Suite names match the upstream WPT runner basenames.
> **Legend.** ✓ pass · ✗ fail · ◐ xfail (known engine gap) · ◑ skip · ⚠ error.
-
-
-
-
-
-
## Summary
| Suite | Total | Pass | XFail | Skip | Fail | Error |
diff --git a/scripts/generate_compliance_report.py b/scripts/generate_compliance_report.py
index 477626b..bb7cc2c 100755
--- a/scripts/generate_compliance_report.py
+++ b/scripts/generate_compliance_report.py
@@ -4,7 +4,7 @@
Standalone script (not packaged in the wheel). Runs every WHATWG
``web-platform-tests/wpt/urlpattern/`` case against :class:`URLPattern`,
captures the outcome of each, and emits a structured Markdown report
-with shields.io badges + accessible Unicode-symbol status indicators.
+with accessible Unicode-symbol status indicators.
The script reproduces the harness logic from ``tests/test_wpt.py`` and
the auxiliary test files inline — running it does not require pytest.
@@ -12,11 +12,9 @@
The output is meant for human reading on GitHub: collapsible
```` blocks per suite, summary table at the top, per-case
-rows with pattern previews and pass/fail symbols. Colors come from
-shields.io (high-contrast green/red/blue/grey palette that's
-distinguishable for the common color-vision-deficiency types) and
-never carry meaning alone — every status is paired with a symbol and
-a word.
+rows with pattern previews and pass/fail symbols. Status is conveyed
+by a Unicode glyph paired with a status word — color never carries
+meaning alone.
"""
from __future__ import annotations
@@ -63,12 +61,10 @@ def _wpt_ref() -> str:
return "main" # best-effort fallback for a non-git corpus
-# -------------------------- symbols + shields.io palette ---------------------
+# -------------------------- per-case status symbols --------------------------
#
# Accessibility rule (matches the README): the symbol carries the meaning;
-# color is decorative. Every cell pairs a Unicode glyph with a status word
-# and (in summary tables) a shields.io badge whose alt text restates the
-# result.
+# every cell pairs a Unicode glyph with a status word.
SYM_PASS = "✓"
SYM_FAIL = "✗"
@@ -76,13 +72,6 @@ def _wpt_ref() -> str:
SYM_SKIP = "◑"
SYM_ERROR = "⚠"
-# Wong-style colorblind-safe palette (paired with shape + text)
-COLOR_PASS = "2ea043" # GitHub success-green
-COLOR_FAIL = "cf222e" # GitHub danger-red
-COLOR_XFAIL = "1f6feb" # informational blue
-COLOR_SKIP = "6e7681" # muted grey
-COLOR_ERROR = "bf8700" # attention yellow
-
# -------------------------- result data classes -----------------------------
@@ -436,13 +425,6 @@ def add(name: str, pattern: dict[str, str], *, expected: bool) -> None:
# -------------------------- rendering ---------------------------------------
-def _badge(label: str, value: str, color: str) -> str:
- """One shields.io badge anchored at the suite's section."""
- safe_label = label.replace(" ", "%20").replace("/", "%2F")
- safe_value = value.replace(" ", "%20").replace("/", "%2F")
- return f""
-
-
def _status_cell(status: str) -> str:
"""One Unicode-symbol-and-word cell for a single case result."""
return {
@@ -454,17 +436,6 @@ def _status_cell(status: str) -> str:
}[status]
-def _suite_badge(suite: SuiteResult) -> str:
- """Header badge for one suite — picks color from the result mix."""
- if suite.is_clean and suite.passing == suite.total:
- return _badge(suite.title, f"{suite.passing}/{suite.total}", COLOR_PASS)
- if suite.is_clean and suite.skipping == suite.total:
- return _badge(suite.title, "skipped (tentative)", COLOR_SKIP)
- if suite.is_clean:
- return _badge(suite.title, f"{suite.passing}/{suite.total}", COLOR_PASS)
- return _badge(suite.title, f"{suite.failing + suite.erroring} failing", COLOR_FAIL)
-
-
def _render(suites: list[SuiteResult]) -> str:
out: list[str] = []
engine = get_default_engine()
@@ -496,10 +467,6 @@ def _render(suites: list[SuiteResult]) -> str:
)
out.append("")
- # ---- top-of-page badges
- out.extend(_suite_badge(suite) for suite in suites)
- out.append("")
-
# ---- summary table
out.append("## Summary")
out.append("")