From 5cc77602b77e0af3594b1038079e479760e3eed5 Mon Sep 17 00:00:00 2001 From: Conduction Release Bot Date: Tue, 11 Aug 2026 14:28:53 +0200 Subject: [PATCH] fix(gate-24): the JS probe knew one of two registration APIs, so it cleared repos that have leaves MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gate-24 (integration-parity) decides applicability from its own subject matter: does this repo register integration leaves at all? The PHP half looks for `new LeafDescriptor(` in lib/. The JS half looked only for `registerIntegration(` in src/. There are TWO canonical JS registration forms, and the gate knew one. `registerIntegration(descriptor)` is the convenience wrapper exported from @conduction/nextcloud-vue; the registry object it wraps is called directly as `OCA.OpenRegister.integrations.register(descriptor)`, which is equally canonical — it is how nextcloud-vue registers its OWN built-in leaves (src/integrations/builtin/files.js). So an app using the direct form was told, verbatim, "this repo registers no integration leaves at all". That sentence is not cosmetic: it routes the gate to `na`, which does NOT count against coverage, instead of `structural`, which does. The one gate that exists to correlate the server and JS halves of a leaf therefore switched itself off precisely in repos that have halves to correlate, and did so while printing a confident absence claim. MEASURED, `--full`, on ConductionNL/decidesk at e03f5932: [gate-24] integration-parity: NOT APPLICABLE — ... this repo registers no integration leaves at all — no `new LeafDescriptor(` in lib/ and no `registerIntegration(` in src/. decidesk registers exactly one leaf, `decidesk-decisions`, at src/integrations/registerDecisionsLeaf.js:175 via `target.OCA.OpenRegister.integrations.register(decisionsLeafDescriptor)` — and that id was present in the LIVE JS registry in the same repo's Playwright run, read out of `window.OCA.OpenRegister.integrations.list()`. The gate said the set was empty while the runtime enumerated a member of it. POSITIVE CONTROL, old probe vs new, over the fleet checkout: decidesk old=0 new=1 <- false negative, fixed openregister old=0 new=1 <- false negative, fixed openconnector old=1 new=1 <- no regression procest old=1 new=1 <- no regression hermiq old=1 new=1 <- no regression nldesign old=0 new=0 <- correctly negative docudesk old=0 new=0 <- correctly negative and on decidesk the verdict moves from a false `na` to `SKIPPED (structural)`, which moves the coverage line from "58 of 58 applicable gates ran" to "58 of 59" — the gap becomes visible instead of being absorbed. `integrations\.register` cannot collide with `unregister(`, because the qualifier is part of the match, nor with `registerIntegrationIcons(`, because `\(` anchors the end. Why this matters beyond the count: the drift gate-24 exists to catch is live right now. openregister advertises `kvk` and `opencorporates` over OCS capabilities while @conduction/nextcloud-vue never registered either in JS (ConductionNL/nextcloud-vue#630), and it went unnoticed until an app's e2e test compared the two lists by hand. A parity gate that cannot tell it has leaves is a parity gate that cannot find that. NOT FOR IMMEDIATE MERGE. This turns a silent `na` into a counted `structural` gap in at least two repos, so it can redden a `--require-full-coverage` run mid-wave — the same reason #347 is being held. Land it once the wave settles. --- hydra-gates/scripts/run-hydra-gates.sh | 33 +++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/hydra-gates/scripts/run-hydra-gates.sh b/hydra-gates/scripts/run-hydra-gates.sh index 7f2c6867..f5293d25 100755 --- a/hydra-gates/scripts/run-hydra-gates.sh +++ b/hydra-gates/scripts/run-hydra-gates.sh @@ -3840,12 +3840,39 @@ _parity_has_js=0 if [ -d lib ] && grep -rqE 'new[[:space:]]+LeafDescriptor[[:space:]]*\(' lib/ --include='*.php' 2>/dev/null; then _parity_has_php=1 fi -if [ -d src ] && grep -rqE '\bregisterIntegration[[:space:]]*\(' src/ 2>/dev/null; then +# THE JS PROBE MUST MATCH BOTH SUPPORTED REGISTRATION APIs, NOT ONE. +# +# `registerIntegration(descriptor)` is the convenience wrapper exported from +# @conduction/nextcloud-vue (src/integrations/registry.js). The registry object +# it wraps is equally canonical and is called directly as +# `OCA.OpenRegister.integrations.register(descriptor)` — including by +# nextcloud-vue's OWN built-in leaves (src/integrations/builtin/files.js). +# +# Probing for only the wrapper made this gate produce a FALSE ABSENCE CLAIM, and +# the claim was load-bearing: an app registering leaves via the direct form was +# told "this repo registers no integration leaves at all", which routes it to +# `na` (not counted as a gap) instead of `structural` (counted). So the one gate +# that exists to correlate the server and JS halves of a leaf switched itself +# off, silently, in exactly the repos that have leaves to correlate. +# +# MEASURED across the fleet checkout, both forms are live: +# registerIntegration( -> hermiq/src/integration-leaf.js, +# openconnector/src/integration.js, +# procest/src/main.js +# integrations.register( -> decidesk/src/integrations/registerDecisionsLeaf.js, +# openregister/src/main.js +# decidesk registers `decidesk-decisions` through the second form and was +# reported by this gate as having no leaves at all, on a --full run, while that +# very id was present in the live JS registry. +# +# `integrations\.register` cannot collide with `unregister(` (the qualifier is +# part of the match) nor with `registerIntegrationIcons(` (the `\(` anchors it). +if [ -d src ] && grep -rqE '\b(registerIntegration|integrations\.register)[[:space:]]*\(' src/ 2>/dev/null; then _parity_has_js=1 fi if [ ! -f scripts/check-integration-parity.sh ]; then if [ "${_parity_has_php}" = "0" ] && [ "${_parity_has_js}" = "0" ]; then - _skip 24 "integration-parity" na "no scripts/check-integration-parity.sh, and this repo registers no integration leaves at all — no \`new LeafDescriptor(\` in lib/ and no \`registerIntegration(\` in src/. There is no server↔JS pair for parity to correlate." + _skip 24 "integration-parity" na "no scripts/check-integration-parity.sh, and this repo registers no integration leaves at all — no \`new LeafDescriptor(\` in lib/ and neither \`registerIntegration(\` nor \`integrations.register(\` in src/. There is no server↔JS pair for parity to correlate." else _skip 24 "integration-parity" structural "no scripts/check-integration-parity.sh, but this repo DOES register integration leaves (lib/ LeafDescriptor: ${_parity_has_php}, src/ registerIntegration: ${_parity_has_js}). server↔JS leaf parity (ADR-066 Decisions 4/7: phantom render surfaces, orphan JS registrations, renderMode mismatch) is UNVERIFIED — a leaf whose other half never registered is invisible to this run." fi @@ -3874,7 +3901,7 @@ if [ -f scripts/check-integration-parity.sh ]; then if grep -qiE 'skipping|not found locally|could not be located' "${_parity_log}" 2>/dev/null \ && ! grep -qE '^(✓|✗)' "${_parity_log}" 2>/dev/null; then if [ "${_parity_has_php}" = "0" ] && [ "${_parity_has_js}" = "0" ]; then - _skip 24 "integration-parity" na "scripts/check-integration-parity.sh ran but SKIPPED (it could not locate the canonical JS check), and this repo registers no integration leaves at all — no \`new LeafDescriptor(\` in lib/ and no \`registerIntegration(\` in src/. There is no server↔JS pair for parity to correlate. See ${_parity_log}." + _skip 24 "integration-parity" na "scripts/check-integration-parity.sh ran but SKIPPED (it could not locate the canonical JS check), and this repo registers no integration leaves at all — no \`new LeafDescriptor(\` in lib/ and neither \`registerIntegration(\` nor \`integrations.register(\` in src/. There is no server↔JS pair for parity to correlate. See ${_parity_log}." else _skip 24 "integration-parity" structural "scripts/check-integration-parity.sh ran but SKIPPED — it could not locate the canonical JS check, so NOTHING was correlated — while this repo DOES register integration leaves (lib/ LeafDescriptor: ${_parity_has_php}, src/ registerIntegration: ${_parity_has_js}). server↔JS leaf parity (ADR-066 Decisions 4/7: phantom render surfaces, orphan JS registrations, renderMode mismatch) is UNVERIFIED by this run — this is NOT a pass. See ${_parity_log}." fi