Skip to content

fix(hydra-gates): gate 3 resolves stubbed external contracts and tab bodies, gates 22 and 53 vendor schema 2.42.0 - #815

Merged
rubenvdlinde merged 4 commits into
mainfrom
fix/gates-3-22-53-false-positives
Oct 4, 2026
Merged

rubenvdlinde merged 4 commits into
mainfrom
fix/gates-3-22-53-false-positives

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

Three false positives found on learniq (development @ 9b70119) while clearing its gate debt, plus the gate-53 crash under a "type": "module" parent.

gate-3 stub-scan

learniq's six lifecycle guards implement OpenRegister's LifecycleGuardInterface::check(array $object, string $action, string $userId) and mark $userId unused on the @param line. The exemption (#339) wants the supertype resolvable in the repo, and it only looked under lib/. The interface belongs to another app, so the condition could never hold, even though learniq mirrors it as a stub in tests/Stubs/Lifecycle/.

  • check_caller_identity_exempt.py now also indexes stubs/ and any tests/**/[Ss]tubs directory (learniq, launchpad and pipelinq use tests/Stubs, thematiq uses stubs/). The stub still has to declare the same method with the same parameter, the marker is still required, and a supertype found nowhere still reports.
  • The caller-identity body ended at ^ \}, which a tab-indented file never contains, so the body ran to EOF. A later method's $userId then hid a real stub, and the short-method skip could never fire. The body now ends at the brace that matches the signature's own indent.

learniq: before FAIL, 6 finding(s) (all method=check rule=caller-identity-ignored param=$userId) → after PASS.

New suite test_gate_3_external_contract_and_tabs.sh: 3 of 7 arms fail on main, all 7 pass with the fix. The controls cover: no stub means it still reports; no unused marker means it still reports; a stub without the parameter means it still reports; a tab-indented class that implements nothing, with the marker, still reports. The existing gate-3 suites (contract_param 5/5, bodiless_declaration 4/4, 3_14_comment_evidence, check_stub_run_body) still pass.

gate-22 manifest-validation and gate-53 effective-manifest-crossref

The vendored schema was 2.37.0. onDemand on a run-action setup step is published in schema 2.42.0 (@conduction/nextcloud-vue 2.59.0, latest; also in 2.56.0-beta.6). The vendored file is now byte-identical to that package's src/schemas/app-manifest-v2.schema.json, which is the file hydra-gates-schema-sync.yml would copy. This supersedes #794: it vendors 2.41.0, which has no onDemand, so it would not fix learniq.

learniq: gate-22 before FAIL, at /setup/steps/4: must NOT have additional properties → after PASS. gate-53 before FAIL, 1 structural violation → after PASS (29 WARNs that were already there, not blocking).

diff_schema_strictness.js 2.37.0 → 2.42.0 finds the same 11 tightenings #794 lists, including the removal of savedViewPlaces. 2.41.0 → 2.42.0 reports none. So I checked the fleet against both schemas. For every core app that ships src/manifest.json (19; versioniq has none; zaakafhandelapp is out of scope), I validated the base manifest and the assembled effective manifest, each against 2.37.0 and 2.42.0:

  • None of them turns red.
  • dossiq and learniq go from red to green.
  • The other 17 pass on both schemas (Ajv path confirmed: Ajv validation against merged canonical schema: PASS).
  • No fleet manifest uses savedViewPlaces any more.

Full-runner gate-22/53 on thematiq, launchpad and pipelinq: PASS/PASS on both the old and the new schema.

Tests:

  • test_check_manifest.sh gains two fixtures. setup-ondemand fails on main and passes with the fix. setup-unknown-step-key is the same step with a misspelt key; it still FAILs and names /setup/steps/1.
  • The real-pair arm of test_diff_schema_strictness.js stripped savedViewPlaces, which the library has since removed. It now strips onDemand, the key this bump added.

gate-53 crash under a "type": "module" parent

Node takes a .js file's module type from the nearest package.json, and the package shipped none. A checkout under the Nextcloud server tree therefore failed with require is not defined in ES module scope. Fixed with scripts/lib/package.json set to {"type": "commonjs"}. New suite test_lib_commonjs_scope.sh copies the package under a "type": "module" parent: 4 failures without the file, 4 passes with it.

Package tests

run-helper-suites.sh discovers 127 suites. The local run reached the 50-minute timeout I had set, so I ran the 29 suites it had not reached yet one by one, with the same command and cwd.

  • Every suite passes (exit 0), except the one that is quarantined on main (orphaned_capability).
  • The only red in that run was test_diff_schema_strictness.js, which the schema bump broke. It is fixed in 92ae722 and passes again (exit 0).
  • tests/test-hydra-gates-bin.sh passes (exit 0).

Ajv was resolved through NODE_PATH, as CI installs it.

Not done: a supertype outside the repo with no stub still reports (fail-closed, as #339 designed). Any constraint a later library bump tightens remains the sync PR reviewer's call.

🤖 Generated with Claude Code

…ented body at its own brace

learniq's six lifecycle guards implement OpenRegister's
LifecycleGuardInterface::check(..., string $userId) and mark $userId unused,
but the exemption only looked for the supertype under lib/, so they were
reported with no closing action. The helper now also reads stubs/ and any
tests/**/[Ss]tubs directory; the stub must still declare the same method with
the same parameter, and an unresolvable supertype still reports.

The caller-identity body stopped at a four-space closing brace, so in a
tab-indented file it ran to EOF and a later method's $userId hid a stub. The
body now ends at the brace matching the signature's own indent.
…cloud-vue 2.59.0

The vendored copy was 2.37.0, so gates 22 and 53 rejected learniq's
run-action setup step with `onDemand`, a key the library publishes since
schema 2.42.0. The file is byte-identical to the one the package ships, which
is what hydra-gates-schema-sync.yml would vendor; it supersedes the 2.41.0 bump
in #794, which still lacks onDemand.

diff_schema_strictness.js names 11 tightened constraints between 2.37.0 and
2.42.0 (the same list as #794; 2.41.0 to 2.42.0 is additive). Validated the
base and effective manifests of all 19 fleet apps that ship one against both
schemas: no app turns red, dossiq and learniq turn green.
Node takes a .js file's module type from the nearest package.json above it.
The package shipped none, so a checkout under a "type": "module" tree (the
Nextcloud server checkout) loaded every helper as an ES module and gate-53
died with "require is not defined in ES module scope".
…atest bump added

The arm stripped savedViewPlaces from the vendored schema, a key the library
removed after 2.37.0, so it failed on the 2.42.0 copy. It now strips onDemand,
the 2.42.0 addition, and asserts the key and the closed step are still there so
a later bump says what to re-point instead of failing obscurely.
@rubenvdlinde
rubenvdlinde merged commit 7dd77e4 into main Oct 4, 2026
46 of 47 checks passed
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