From b4e3e4880abac0b0144a28ef27370ba69cdd670e Mon Sep 17 00:00:00 2001 From: Conduction Release Bot Date: Mon, 3 Aug 2026 23:50:18 +0200 Subject: [PATCH] =?UTF-8?q?fix(gate-55):=20port=20the=20OBJECT=20route=20f?= =?UTF-8?q?orm=20fix=20=E2=80=94=20the=20package=20was=20behind=20hydra?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Second casualty of the same drift that cost gates 62/63. hydra's `development` carries `a48e65e2 fix(gate-55): catch the OBJECT route form, not just string route values`, and the package's copy of `check_detail_page_discipline.py` predates it by 25 lines. The fix catches `"route": {"name": "", "query": {...}}` — the object form stats-block entries use to deep-link a KPI. The renderer calls `router.resolve({name, query})` inside a computed and reads `.href` off the result, so an unresolvable name throws and the page emits console errors. A gate that only inspected string route values never saw it. Found while resolving hydra#512's merge: the file is deleted in the delegation branch and modified on development, so taking either side silently loses something. That is now twice in one merge — the exact drift the delegation exists to end, appearing while the delegation is still in flight. ⚠️ Worth stating plainly: my first attempt at this port wrote an EMPTY file, because I ran `git show origin/development:…` inside the .github clone, where that ref does not exist — it is hydra's. `git show` on a missing ref produced nothing, the redirect truncated the file, and the diff read "453 deletions". An absence manufactured by a wrong lookup, caught only because 453 deletions is an implausible shape for a one-commit port. The diff is now +25/-0, which is what a port of a 25-line fix should look like. py_compile clean. --- .../lib/check_detail_page_discipline.py | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/hydra-gates/scripts/lib/check_detail_page_discipline.py b/hydra-gates/scripts/lib/check_detail_page_discipline.py index 32eb956..468d74b 100644 --- a/hydra-gates/scripts/lib/check_detail_page_discipline.py +++ b/hydra-gates/scripts/lib/check_detail_page_discipline.py @@ -412,6 +412,31 @@ def check_page(path, page, page_ids, findings): f"existing page id in the merged manifest" ) + # (f2) The OBJECT route form: `"route": {"name": "", "query": {...}}`, + # used by stats-block entries[] to deep-link a KPI. The renderer calls + # `router.resolve({name, query})` inside a COMPUTED and reads `.href` off the + # result, so an unresolvable name throws and the page emits console errors on + # every mount — it does not degrade to a dead link. + # + # This form is invisible to (f), which only inspects string values. Observed + # 2026-08-03 on openconnector: deleting the EventDeliveries page during the + # ADR-080 dead-letter merge left two ConsumerDetail stats entries pointing at + # it. A string-only scan reported "no unresolvable route refs" while the E2E + # suite failed on ConsumerDetail — the check and the symptom disagreed, and + # the check was wrong. + objroutes = [] + _collect(cfg, "route", objroutes) + for r in objroutes: + if isinstance(r, dict): + name = r.get("name") + if isinstance(name, str) and name and name not in page_ids: + findings.append( + f"{path}: page '{pid}' — route object {{name: '{name}'}} does not " + f"resolve to an existing page id in the merged manifest " + f"(router.resolve() throws inside a computed, so the page emits " + f"console errors on mount)" + ) + def check_file(path, page_ids, findings, base_ref): try: