diff --git a/hydra-gates/scripts/lib/test_gates_23_33_never_green_over_nothing.sh b/hydra-gates/scripts/lib/test_gates_23_33_never_green_over_nothing.sh index 45223c56..5800432f 100644 --- a/hydra-gates/scripts/lib/test_gates_23_33_never_green_over_nothing.sh +++ b/hydra-gates/scripts/lib/test_gates_23_33_never_green_over_nothing.sh @@ -217,6 +217,49 @@ if _run "${FIXTURES}/clean"; then _expect 24 "NOT APPLICABLE" "gate-24 with no wrapper and no leaves is na, not PASS" fi +# =========================================================================== +echo +echo "== gate-24: BOTH registration APIs count as having leaves (.github#349) ==" +# =========================================================================== +# `clean/` has no parity wrapper AND no leaf, so its NOT APPLICABLE above is +# correct. Drop ONE file on top of it — a leaf registered through +# `OCA.OpenRegister.integrations.register(...)`, the direct form — and the +# verdict must become SKIPPED (structural): the repo now has a server↔JS pair +# to correlate and nothing correlated it. +# +# The distinction is not cosmetic. `na` does NOT count against coverage; +# `structural` does. A gate that misreads its own subject matter as absent +# switches itself off silently, and prints a confident absence claim while +# doing it — measured on decidesk, whose registered leaf id was enumerable from +# the live JS registry in the same repo's Playwright run. +# +# THE PAIRED ARM MATTERS: `clean/` untouched must STAY `na`. A fix that made +# gate-24 structural everywhere would pass a one-armed version of this test and +# would be a false gap in every repo in the fleet. +_DIRECT="$(mktemp -d "${TMPDIR:-/tmp}/hydra-gate-24-direct.XXXXXXXX")" +cp -r "${FIXTURES}/clean/." "${_DIRECT}/" +cp "${FIXTURES}/direct-registry-overlay/src/integration-leaf-direct.js" "${_DIRECT}/src/" +if [ ! -f "${_DIRECT}/src/integration-leaf-direct.js" ]; then + _bad "the direct-registry overlay did not land — every assertion in this arm would be vacuous" +elif grep -rq 'scripts/check-integration-parity.sh' "${_DIRECT}" 2>/dev/null \ + || [ -f "${_DIRECT}/scripts/check-integration-parity.sh" ]; then + _bad "the direct-registry arm inherited a parity wrapper from clean/, so it exercises the wrapper path and not the leaf-detection path this arm is about" +elif _run "${_DIRECT}"; then + _expect 24 "SKIPPED (structural)" \ + "gate-24 recognises a leaf registered via integrations.register( — structural, not na" + _expect 24 "DOES register integration leaves" \ + "gate-24 says WHY it is structural" + # And the reason must not still claim the repo has no leaves. + _l24="$(_verdict 24)" + case "${_l24}" in + *"registers no integration leaves at all"*) + _bad "gate-24 still asserts 'registers no integration leaves at all' over a tree that registers one — .github#349 is live: ${_l24:0:160}" + ;; + *) _ok "gate-24 no longer claims the leaf set is empty" ;; + esac +fi +rm -rf "${_DIRECT}" + # =========================================================================== echo echo "== gate-23 in WARN mode: a finding must still be VISIBLE ==" diff --git a/hydra-gates/scripts/run-hydra-gates.sh b/hydra-gates/scripts/run-hydra-gates.sh index 5d315bdd..02fb9dec 100755 --- a/hydra-gates/scripts/run-hydra-gates.sh +++ b/hydra-gates/scripts/run-hydra-gates.sh @@ -3877,12 +3877,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 @@ -3911,7 +3938,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 diff --git a/hydra-gates/scripts/test-fixtures/gates-23-33/direct-registry-overlay/src/integration-leaf-direct.js b/hydra-gates/scripts/test-fixtures/gates-23-33/direct-registry-overlay/src/integration-leaf-direct.js new file mode 100644 index 00000000..b1845fed --- /dev/null +++ b/hydra-gates/scripts/test-fixtures/gates-23-33/direct-registry-overlay/src/integration-leaf-direct.js @@ -0,0 +1,35 @@ +/** + * THE SECOND CANONICAL REGISTRATION FORM — `.github#349`. + * + * The convenience wrapper exported from @conduction/nextcloud-vue is the form + * gate-24 already knew. The registry object it wraps is equally canonical and + * is called directly, as below — including by nextcloud-vue's OWN built-in + * leaves (src/integrations/builtin/files.js). + * + * gate-24's JS probe knew only the wrapper. An app registering this way was + * told, verbatim, "this repo registers no integration leaves at all", which + * routes the gate to `na` — NOT counted against coverage — instead of + * `structural`, which is. So the one gate that exists to correlate the server + * and JS halves of a leaf switched itself off in exactly the repos that have + * halves to correlate. Measured live on decidesk, whose `decidesk-decisions` + * id was in `window.OCA.OpenRegister.integrations.list()` in the same repo's + * Playwright run while gate-24 reported the set empty. + * + * ⚠️ THIS COMMENT MUST NOT NAME THE WRAPPER FUNCTION FOLLOWED BY AN OPEN + * PAREN. gate-24's probes are plain greps over file TEXT, comments included, + * so an explanatory sentence spelling the wrapper call out is indistinguishable + * from a registration. The first draft of this file did exactly that, and the + * arm below went GREEN against the PRE-#349 runner — a dead test that looked + * like coverage. Same family as `.github#358` (gates 19 and 26 parse prose), + * encountered while writing the fixture for a different gate. + * + * This file is an OVERLAY dropped on top of `clean/`, which has neither a + * parity wrapper nor any leaf. `clean/` alone is legitimately NOT APPLICABLE; + * `clean/` + this file must be SKIPPED (structural). + */ +;(function (target) { + target.OCA.OpenRegister.integrations.register({ + id: 'gateplant-direct-agent', + renderMode: 'mount', + }) +})(window)