Skip to content

hydra-gates v1.8.0 ships a contract without patchObject() — the fix is on main but unreleased #514

Description

@rubenvdlinde

Summary

conduction/hydra-gates v1.8.0 — the latest tag, and the version every app has in composer.lock — ships an ObjectServiceInterface that is missing patchObject() and documents updateObject() with the wording that previously caused silent data loss. The fix is already on main but has never been released.

patchObject "Apply a partial update to an existing object."
v1.8.0 (installed everywhere) ❌ absent ⚠️ present
main ✅ present ✅ gone

f8cad2f0 "fix(contracts): ship patchObject() so the published contract has one definition" (2026-08-17) landed after v1.8.0 was cut (9fc64ab9, 2026-08-15).

Why this is not cosmetic

hydra-gates/composer.json claims the app's own namespace at runtime:

"autoload": { "psr-4": { "OCA\\OpenRegister\\Contract\\": "hydra-gates/contracts/" } }

That prefix is longer than openregister's own OCA\OpenRegister\lib/, so PSR-4 longest-prefix-wins hands the class to the gate package — openregister's autoload_classmap.php points at it explicitly. Nine repos vendor it (decidesk, hermiq, larpingapp, nldesign, openconnector, openregister, portaliq, scholiq, softwarecatalog), so under OC_App::loadApps() the winner is whichever app registers first. Measured in a running instance:

WINNER: /var/www/html/custom_apps/softwarecatalog/vendor/conduction/hydra-gates/
        hydra-gates/contracts/ObjectServiceInterface.php
hasPatchObject: NO

softwarecatalog's vendor directory defined openregister's contract. Patching openregister's own vendored copy changed nothing — another app still won.

Consequence: patchObject() — the read-merge-write path — is unreachable through the interface consumers type-hint, and the summary line they read in an IDE tooltip still recommends the erasing path.

Evidence it is caught, and is a true positive

openregister/tests/Unit/Service/ObjectServiceUpdateVersusPatchTest fails 1 error + 2 failures against v1.8.0:

  • testThePublishedContractDeclaresBothWritePaths
  • testTheContractDoesNotDescribeUpdateObjectAsAPartialUpdate
  • testThePublishedPatchSignatureMirrorsTheImplementation

Full local run, inside a booted Nextcloud: 16 839 tests, 37 875 assertions — these 3 are the only real failures. Please do not "fix the tests".

Ask

Cut v1.8.1 from main so the released package matches the source of truth, then let the apps pick it up.

⚠️ Sizing this deliberately, because it is not a one-file release: 56 commits are unreleased on main since v1.8.0, including gate-behaviour changes (phpcs errors must fail the gate; warnings still pass #483, gate-8: judge how the CALLER consumes the null #506, coverage-guard: deletions are not coverage regressions #480). Those will reach all 18 apps at once. The gate scripts already run from .github@main, so their behaviour is live regardless; the tag mainly propagates contracts/ and quality-config/. Still worth a deliberate release rather than an unattended one — which is why this is an issue and not a PR.

Found while running the fleet's suites locally during a GitHub Actions outage.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions