Skip to content

fix(gate-66): an availability-guarded lookup is correct, not a violation - #458

Merged
rubenvdlinde merged 1 commit into
mainfrom
feat/gate-66-availability-guarded-lookups
Aug 14, 2026
Merged

fix(gate-66): an availability-guarded lookup is correct, not a violation#458
rubenvdlinde merged 1 commit into
mainfrom
feat/gate-66-availability-guarded-lookups

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

This is what stopped a fleet-wide script from running over 1,263 call sites — and it would have been a regression in every one of the 106 it touched.

Measured on portaliq:

if ($this->isOpenRegisterAvailable() === false) {   // isInstalled('openregister')
    return ['success' => false, 'message' => 'OpenRegister is not installed or enabled.'];
}
try { $cfg = $this->container->get('OCA\OpenRegister\Service\ConfigurationService'); }

Injecting that dependency makes the service unconstructable on an instance without OpenRegister and turns the clean message into a 500 — the exact failure ADR-083 rule 3 exists to prevent. The app was already right; the gate was wrong to report it.

The rule, refined

Rule 1 governs unconditional dependencies. Where a class reaches for OpenRegister only after establishing it is there, deferring construction is the point and the lookup stays. The finding text now offers both remedies instead of only injection.

File-scoped deliberately: per-method scoping would flag the helper that does the reaching while clearing the caller that does the checking.

Measured effect

Fleet split: 106 guarded, 1,000 unguarded.

before after
portaliq / scholiq / doriath / hermiq 1 each 0
pipelinq 192 192
decidesk 120 120
opencatalogi 57 57

Tests

16, both directions pinned: the guarded shape passes, and the same shape with the availability check removed still fails, so the clause cannot go quiet.

clean/ gains OptionalCapabilityService.php, carrying the exact construct planted/ is reported for — if the availability clause is ever lost, that arm goes red. Acceptance matrix: 146 passed, 0 failed.

This is what stopped a fleet-wide script from running over 1,263 call
sites, and it would have been a regression in every one of the 106 it
touched.

Measured on portaliq:

    if ($this->isOpenRegisterAvailable() === false) {
        return ['success' => false,
                'message' => 'OpenRegister is not installed or enabled.'];
    }
    try { $cfg = $this->container->get('OCA\OpenRegister\Service\ConfigurationService'); }

Injecting that dependency makes the whole service unconstructable on an
instance without OpenRegister and turns the clean message into a 500 —
the exact failure ADR-083 rule 3 exists to prevent. The app was already
right; the gate was wrong to report it.

So rule 1 governs UNCONDITIONAL dependencies. Where a class reaches for
OpenRegister only after establishing it is there, deferring construction
IS the point and the lookup stays. The finding text now says so, and
offers both remedies rather than only injection.

File-scoped on purpose: per-method scoping would flag the helper that does
the reaching while clearing the caller that does the checking.

Fleet split, measured: 106 guarded, 1000 unguarded. Effect —

  portaliq/scholiq/doriath/hermiq  lookup findings -> 0
  pipelinq 192, decidesk 120, opencatalogi 57  unchanged

16 tests. Both directions pinned: the guarded shape passes, and the SAME
shape with the availability check removed still fails, so the clause
cannot go quiet. clean/ gains OptionalCapabilityService.php, which carries
the exact construct planted/ is reported for — if the availability clause
is ever lost, that arm goes red.
@rubenvdlinde
rubenvdlinde merged commit d308ef7 into main Aug 14, 2026
35 checks passed
@rubenvdlinde
rubenvdlinde deleted the feat/gate-66-availability-guarded-lookups branch August 14, 2026 17:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant