fix(gates 12-22): four gates could not detect the defect they exist for, and gate-20 had never fired at all - #277
Merged
Conversation
…or, and gate-20 had never fired at all Every gate in the 12-22 band was given one textbook true positive in a real fleet repo and asked to catch it. Measured against package sha cdfbd7a, and re-measured on top of fef032b (#272), across openregister (207 .vue, 794 spec scenarios), pipelinq (202 .vue, type:"dashboard" pages) and shillinq (an ADR-040 AppHost adopter that keeps its own SettingsController). Seven fired, named the plant, and returned to their exact prior verdict when it was removed: 12, 13, 14 (both invariants), 15, 16, 18, 19, 21, 22. Four did not. 1. GATE-20 HAD NEVER FIRED. NOT RARELY - NEVER. Its search was `grep -nE "->${_pat//(/\\(}" "${_file}"`, and the expanded pattern `->findObjects\(` begins with `-`, so grep parses it as OPTIONS: `grep: invalid option -- '>'`, exit 2, no output. `2>/dev/null || true` discarded the message and the status, every file came back with zero hits, and the gate printed PASS. Planting `$this->objectService->findObjects(...)` in openregister's ActionsController: PASS. Repairing the grep ALONE is not the fix. The receiver test was "the FILE mentions ObjectService somewhere", and with the grep working that yields 14 findings on openregister and 5 on shillinq, ALL FALSE - `createFromArray()` is a real method on OpenRegister's *Mappers*. The receiver is now part of the pattern. Fleet measurement across the three repos afterwards: ONE finding, and it is real - shillinq's BookingNotificationController resolves OCA\OpenRegister\Service\ObjectService from the container inside its non-admin authorisation guard and calls findObject(), which does not exist on it (real surface: find/findAll/saveObject/createObject/updateObject/ deleteObject). That is a BadMethodCallException in an auth guard, shipped. 2. GATE-17 WAS WRONG ABOUT THE SAME API, IN THE OTHER DIRECTION. Four of the six names in OBJECT_SERVICE_CRUD - findObjects, createFromArray, updateFromArray, deleteFromId - do not exist on ObjectService; they are precisely what gate-20 flags as fabricated. findAll/createObject/ updateObject/deleteObject were absent. And `^\s*return\s+new\s+JSONResponse` sits in WRAPPER_NOISE_PATTERNS, which was tested BEFORE the ObjectService check - so the commonest pass-through spelling of all, `return new JSONResponse($this->objectService->findAll([]));`, was discarded as "response wrapping" with the call still inside it. It did not merely miss the shape: RESCUE_PATTERNS' `\$this->\w+Service->\w+\(` then matched it and returned False. The gate rescued its own subject. Blast radius of both changes across openregister/pipelinq/shillinq: 0 new findings. The CRUD-name filter and the `@spec exclude` escape hatch are untouched. 3. GATE-14 NEVER JUDGED THE TEN ROUTES AppHost SUPPLIES (#265, closed). #223 taught invariant 1 about `Routes::standard()`. Invariant 2 asks the opposite question and still read route names as literals out of the leaf's own appinfo/routes.php, where those ten names never appear. Deleting `SettingsController::update()` from shillinq - which keeps its own controller, as aliasControllerUnlessLeafDefinesIt explicitly allows - leaves PUT /api/settings resolving to nothing. That is not a 404: the router matches, ControllerMethodReflector reflects, the request dies 500. shillinq's own docblock on update() spells the hazard out. Gate-14's findings log came back EMPTY and the gate said PASS. 4. THREE GATES REPORTED PASS OVER A CRASHED CHECKER. With python3 replaced by a stub that always exits 1 - so not one file was inspected by any python-backed gate: gate-12 SKIPPED (wiring) gate-15 PASS gate-17 SKIPPED (wiring) gate-16 PASS gate-18 PASS gate-19 FAIL - "an unreported number of scenario(s)" 15/16/18 wrote `2>/dev/null || true` and counted lines in an empty log. 19 read exit 1 as EXIT_FAIL from a helper that never printed its own summary, producing a blocking verdict with a count nobody measured. The three helpers now print a terminal `# count=` marker and the runner requires it; gate-18's helper contract is "always exit 0", so any non-zero exit is a wiring skip; gate-19 treats "EXIT_FAIL with no FAIL - N summary line" as wiring. check_spec_coverage.py and check_dashboard_antipattern.py also stop returning their finding COUNT as an exit status (#209). 5. GATES 12 AND 13 PASSED OVER A src/ WITH ZERO .vue (#274). `[ -d src ]` is not `src/ contains a Vue component`. nldesign's src/ holds one manifest.json, and at fef032b both gates print PASS there - the shape that let twelve gates certify nldesign in #225, still current, not one `rm` away. Now `na`, with the judgement #274 asked for stated in the reason: NcSelect / NcModal / NcDialog are Vue SFC components, a PHP template cannot instantiate one, so these two stay .vue-only and gate-40 keeps the language-agnostic input-label rule for templates/. 6. GATE-22's VERDICT DEPENDED ON WHERE THE GATES WERE CHECKED OUT. `require('ajv/dist/2020')` resolves relative to check_manifest.js, never to the repo under test. Run from openregister's own root with node_modules/ajv PRESENT in that root, the validator printed "Ajv is not resolvable from this process (no node_modules, no NODE_PATH)" - false - and gate-22 went FAIL; exporting NODE_PATH to that same directory flipped it to PASS. Same tree, same package, two verdicts. Resolution is now anchored on the manifest's own repo root, then cwd, then this package, and the degradation names every directory it searched. 7. GATE-15's SLOT MATCHER HAD AN ATTRIBUTE-ORDER BLIND SPOT. `<template #widget-x class="wide">` and `<template #widget-x='{i}'>` did not match - the pattern assumed the slot binding was the last thing before `>`. Same class as gate-44's first-attribute stop in #272. TESTS test_gate_or_objectservice_surface.sh NEW - gate-20 and gate-17, each with the silent sibling that must stay silent (a mapper's real createFromArray; a domain-named method with an identical body), plus a direct assertion that a grep pattern starting with `-` is parsed as options test_gate_crashed_checker_is_not_a_finding.sh all six python-backed gates under a broken interpreter, generically, so a future gate inherits the assertion test_gate_empty_scope_never_passes.sh gates 12/13 on an nldesign-shaped repo, with the one-.vue control test_gate_route_registration.sh new fixture routes-standard-missing- update/, differing from its sibling by exactly the deleted method test_check_manifest.sh ajv resolved from the subject's node_modules with cwd and NODE_PATH pointing elsewhere test_check_dashboard_antipattern.py four slot-tag spellings that were silent misses Every one mutation-checked against the pre-fix tree: the crashed-checker arm is 7 failures red at cdfbd7a, the 12/13 arm 3 failures red at fef032b, the slot-tag arm 4 subtests red, and the ajv anchor red - all green after. 50 helper suites pass, 59 bin-level assertions pass.
…13 ran test-hydra-gates-bin.sh looped 12 and 13 into 'with src/ present, every src-guarded gate really runs'. That fixture's src/ holds one .js file and no .vue, so the assertion encoded the belief this PR removes: that `[ -d src ]` is the same as 'the gate has a subject'. Both gates printed PASS there — an empty glob under an existing src/, nldesign's exact shape. They are now asserted separately and more strictly: not 'did not say na', but 'said na and NAMED the empty .vue glob'. PASS is called out by name as the regression it would be. 61 bin assertions pass, 50 helper suites pass.
…or, and gate-20 had never fired at all Every gate in the 12-22 band was given one textbook true positive in a real fleet repo and asked to catch it. Measured against package sha cdfbd7a, and re-measured on top of fef032b (#272), across openregister (207 .vue, 794 spec scenarios), pipelinq (202 .vue, type:"dashboard" pages) and shillinq (an ADR-040 AppHost adopter that keeps its own SettingsController). Seven fired, named the plant, and returned to their exact prior verdict when it was removed: 12, 13, 14 (both invariants), 15, 16, 18, 19, 21, 22. Four did not. 1. GATE-20 HAD NEVER FIRED. NOT RARELY - NEVER. Its search was `grep -nE "->${_pat//(/\\(}" "${_file}"`, and the expanded pattern `->findObjects\(` begins with `-`, so grep parses it as OPTIONS: `grep: invalid option -- '>'`, exit 2, no output. `2>/dev/null || true` discarded the message and the status, every file came back with zero hits, and the gate printed PASS. Planting `$this->objectService->findObjects(...)` in openregister's ActionsController: PASS. Repairing the grep ALONE is not the fix. The receiver test was "the FILE mentions ObjectService somewhere", and with the grep working that yields 14 findings on openregister and 5 on shillinq, ALL FALSE - `createFromArray()` is a real method on OpenRegister's *Mappers*. The receiver is now part of the pattern. Fleet measurement across the three repos afterwards: ONE finding, and it is real - shillinq's BookingNotificationController resolves OCA\OpenRegister\Service\ObjectService from the container inside its non-admin authorisation guard and calls findObject(), which does not exist on it (real surface: find/findAll/saveObject/createObject/updateObject/ deleteObject). That is a BadMethodCallException in an auth guard, shipped. 2. GATE-17 WAS WRONG ABOUT THE SAME API, IN THE OTHER DIRECTION. Four of the six names in OBJECT_SERVICE_CRUD - findObjects, createFromArray, updateFromArray, deleteFromId - do not exist on ObjectService; they are precisely what gate-20 flags as fabricated. findAll/createObject/ updateObject/deleteObject were absent. And `^\s*return\s+new\s+JSONResponse` sits in WRAPPER_NOISE_PATTERNS, which was tested BEFORE the ObjectService check - so the commonest pass-through spelling of all, `return new JSONResponse($this->objectService->findAll([]));`, was discarded as "response wrapping" with the call still inside it. It did not merely miss the shape: RESCUE_PATTERNS' `\$this->\w+Service->\w+\(` then matched it and returned False. The gate rescued its own subject. Blast radius of both changes across openregister/pipelinq/shillinq: 0 new findings. The CRUD-name filter and the `@spec exclude` escape hatch are untouched. 3. GATE-14 NEVER JUDGED THE TEN ROUTES AppHost SUPPLIES (#265, closed). #223 taught invariant 1 about `Routes::standard()`. Invariant 2 asks the opposite question and still read route names as literals out of the leaf's own appinfo/routes.php, where those ten names never appear. Deleting `SettingsController::update()` from shillinq - which keeps its own controller, as aliasControllerUnlessLeafDefinesIt explicitly allows - leaves PUT /api/settings resolving to nothing. That is not a 404: the router matches, ControllerMethodReflector reflects, the request dies 500. shillinq's own docblock on update() spells the hazard out. Gate-14's findings log came back EMPTY and the gate said PASS. 4. THREE GATES REPORTED PASS OVER A CRASHED CHECKER. With python3 replaced by a stub that always exits 1 - so not one file was inspected by any python-backed gate: gate-12 SKIPPED (wiring) gate-15 PASS gate-17 SKIPPED (wiring) gate-16 PASS gate-18 PASS gate-19 FAIL - "an unreported number of scenario(s)" 15/16/18 wrote `2>/dev/null || true` and counted lines in an empty log. 19 read exit 1 as EXIT_FAIL from a helper that never printed its own summary, producing a blocking verdict with a count nobody measured. The three helpers now print a terminal `# count=` marker and the runner requires it; gate-18's helper contract is "always exit 0", so any non-zero exit is a wiring skip; gate-19 treats "EXIT_FAIL with no FAIL - N summary line" as wiring. check_spec_coverage.py and check_dashboard_antipattern.py also stop returning their finding COUNT as an exit status (#209). 5. GATES 12 AND 13 PASSED OVER A src/ WITH ZERO .vue (#274). `[ -d src ]` is not `src/ contains a Vue component`. nldesign's src/ holds one manifest.json, and at fef032b both gates print PASS there - the shape that let twelve gates certify nldesign in #225, still current, not one `rm` away. Now `na`, with the judgement #274 asked for stated in the reason: NcSelect / NcModal / NcDialog are Vue SFC components, a PHP template cannot instantiate one, so these two stay .vue-only and gate-40 keeps the language-agnostic input-label rule for templates/. 6. GATE-22's VERDICT DEPENDED ON WHERE THE GATES WERE CHECKED OUT. `require('ajv/dist/2020')` resolves relative to check_manifest.js, never to the repo under test. Run from openregister's own root with node_modules/ajv PRESENT in that root, the validator printed "Ajv is not resolvable from this process (no node_modules, no NODE_PATH)" - false - and gate-22 went FAIL; exporting NODE_PATH to that same directory flipped it to PASS. Same tree, same package, two verdicts. Resolution is now anchored on the manifest's own repo root, then cwd, then this package, and the degradation names every directory it searched. 7. GATE-15's SLOT MATCHER HAD AN ATTRIBUTE-ORDER BLIND SPOT. `<template #widget-x class="wide">` and `<template #widget-x='{i}'>` did not match - the pattern assumed the slot binding was the last thing before `>`. Same class as gate-44's first-attribute stop in #272. TESTS test_gate_or_objectservice_surface.sh NEW - gate-20 and gate-17, each with the silent sibling that must stay silent (a mapper's real createFromArray; a domain-named method with an identical body), plus a direct assertion that a grep pattern starting with `-` is parsed as options test_gate_crashed_checker_is_not_a_finding.sh all six python-backed gates under a broken interpreter, generically, so a future gate inherits the assertion test_gate_empty_scope_never_passes.sh gates 12/13 on an nldesign-shaped repo, with the one-.vue control test_gate_route_registration.sh new fixture routes-standard-missing- update/, differing from its sibling by exactly the deleted method test_check_manifest.sh ajv resolved from the subject's node_modules with cwd and NODE_PATH pointing elsewhere test_check_dashboard_antipattern.py four slot-tag spellings that were silent misses Every one mutation-checked against the pre-fix tree: the crashed-checker arm is 7 failures red at cdfbd7a, the 12/13 arm 3 failures red at fef032b, the slot-tag arm 4 subtests red, and the ajv anchor red - all green after. 50 helper suites pass, 59 bin-level assertions pass.
…13 ran test-hydra-gates-bin.sh looped 12 and 13 into 'with src/ present, every src-guarded gate really runs'. That fixture's src/ holds one .js file and no .vue, so the assertion encoded the belief this PR removes: that `[ -d src ]` is the same as 'the gate has a subject'. Both gates printed PASS there — an empty glob under an existing src/, nldesign's exact shape. They are now asserted separately and more strictly: not 'did not say na', but 'said na and NAMED the empty .vue glob'. PASS is called out by name as the regression it would be. 61 bin assertions pass, 50 helper suites pass.
…o lib/Controller/
NC's RouteParser::buildControllerName() does not prefix the app namespace when
the route name already contains a backslash, so
`AppHost\Controller\GenericHealth#index` is looked up as the bare class
`AppHost\Controller\GenericHealthController`. PSR-4 maps `OCA\<App>\` onto
`lib/`, so that class lives at lib/AppHost/Controller/ — not under
lib/Controller/, which is the only place the resolver looked.
Reproduced against this package's own gates-23-33/planted fixture:
lib/Controller/AppHost/Controller/GenericHealthController.php
route='AppHost\Controller\GenericHealth#index'
rule=controller-class-not-found
a path that cannot exist, reported as a missing class, INSIDE the repository
that ships the file. Same shape as the gate-30 finding in #276: the path the
gate derives is not the path the app uses.
The false FAIL was only half of it. Where a DI binding rescued the absence the
loop `continue`d, so the method-existence check never ran — measured on two new
fixtures differing by exactly one renamed method: at origin/main BOTH report
PASS, including the one whose route resolves to nothing. That is #265's defect
at a different address.
Both candidate paths are probed and the one that EXISTS wins; when neither does
the lib/Controller/ spelling is reported exactly as before, so a genuinely
missing controller reads the same as it always has.
Also: test_gate_route_registration.sh hardcoded its runner, so pointing
HYDRA_GATES_RUNNER_UNDER_TEST at a pre-fix tree silently kept running the FIXED
one and reported all-green. A mutation check that cannot fail is the same defect
as a gate that cannot fail. With the override honoured, the suite is 5 failures
red against origin/main and green after.
And test-hydra-gates-bin.sh's 'with src/ present, every src-guarded gate really
runs' loop had a stale premise: #276 gave that fixture two real .vue files
(because gates 26/31/32 now distinguish 'src/ exists' from 'src/ contains what I
read'), so gates 12 and 13 correctly run and PASS there. They go back in the
loop, and the loop now asserts its own premise first. The zero-.vue case is
asserted where its premise actually holds — the nldesign-shaped fixture in
test_gate_empty_scope_never_passes.sh.
52 helper suites pass, 60 bin assertions pass.
The branch was rebased from fef032b onto 34370f6 (#276) after main moved, which rewrote its commits. `git cherry HEAD origin/<branch>` reports NO commit on the remote that is missing from this history — the remote tip's two commits are the pre-rebase spelling of the first two here — so this merge records the reconciliation and keeps the rebased tree, which is a strict superset.
…ot see `_overlaps` walks FORWARD from the declaration line through the method body. The docblock sits ABOVE the declaration, and the docblock is the only place `@spec` can live — so the scope window never contained the tag. Measured on a two-method fixture: delete the `@spec openspec/...` line, leave the body byte-identical, and the helper prints `# count=0` and exits 0. Every @SPEC tag in a repository can be stripped and gate-16 stays green. `run_gate` also skipped any file whose `added` set was empty, and a pure deletion produces exactly that, so the file was never even opened. Same family as filter_preexisting_methods.py filing an auth-attribute removal as pre-existing: a body-shaped scope cannot see a change that is not in the body. Gate-16 does NOT route through that helper — its four call sites are gates 6, 7, 8 and 30, and check_spec_coverage.py references it zero times — it arrives at the same blind spot by its own path. The fix keys on 'a tag was TAKEN AWAY', not on 'a docblock was touched'. A file that lost a tag is evaluated twice — as it is, and as it was at the base, with the same walkers and therefore the same exemptions — and only the DIFFERENCE is reported. So: delete a tag -> the method that lost it, and only it typo-fix a legacy untagged docblock -> clean (no inherited debt surfaced) add a new untagged method -> still caught, unchanged All three asserted, the second being the anti-widening control.
…ed-defect-audit # Conflicts: # hydra-gates/scripts/run-hydra-gates.sh # hydra-gates/tests/test-hydra-gates-bin.sh
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What was measured
Every gate in the 12–22 band was given one textbook true positive of exactly what it exists to catch, in a real fleet repo whose shape suits it; then the plant was removed and the gate had to return to its exact prior verdict, and a clean repo had to stay clean. Three further arms were added after the earlier bands showed a plant cannot see them: break the interpreter, run against a repo whose subject the gate cannot see, and read the exit byte on a many-finding run.
Final measurement at
[hydra-gates] gate package: ff8869d17ed38fbc52b746f99c6ca89abaf841d0(this branch, merged with48c88ba). Earlier arms measured atcdfbd7a,fef032band34370f6; each defect below is quoted with the sha it was measured at.Repo shapes — two per gate where behaviour can differ by shape:
appinfo/routes.php, 207.vue, 794 spec scenarios, register JSONsRoutes::standard(), keeps its ownSettingsControllertype:"dashboard"pagessrc/holding onemanifest.json.vueAppHost\Controller\GenericHealth<NcSelect :reduce="(o) => o.value" />, noinput-labelnanot PASS on zero-.vuesrc/<NcModal>insrc/views/settings#updatedeleted from an AppHost adopter (d) DI-boundAppHost\Controller\GenericHealth<CnDashboardPage>in a#widget-<id>slot@spec; deleting an existing@specfetchAll() { return new JSONResponse($this->objectService->findAll([])); }#### Scenario:with no@e2e$this->objectService->findObjects(...)lib/*.php.mddocumenting themtype+ additional propertySeven defects
1. gate-20 had never fired. Not rarely — never. Its pattern expands to
->findObjects\(, which begins with-, so grep parses it as options (grep: invalid option -- '>', exit 2).2>/dev/null || truediscarded the message and the status, so every file returned zero hits and the gate printed PASS fleet-wide.Repairing the grep alone is not the fix: the receiver test was "the file mentions ObjectService somewhere", which with a working grep yields 14 false findings on openregister and 5 on shillinq —
createFromArray()is a real method on OpenRegister's Mappers. The receiver is now part of the pattern. Measurement across all three repos afterwards: one finding, and it is real — shillinq'sBookingNotificationControllerresolvesOCA\OpenRegister\Service\ObjectServicefrom the container inside its non-admin authorisation guard and callsfindObject(), which does not exist on it. ABadMethodCallExceptionin an auth guard, shipped.2. gate-17 was wrong about the same API, in the other direction. Four of six names in
OBJECT_SERVICE_CRUDdo not exist on ObjectService — they are what gate-20 flags as fabricated — andfindAll/createObject/updateObject/deleteObjectwere absent. Separately,^\s*return\s+new\s+JSONResponsesits inWRAPPER_NOISE_PATTERNSand was tested before the ObjectService check, so the commonest pass-through spelling was discarded as "response wrapping" with the call still inside it — then matched byRESCUE_PATTERNSand returnedFalse. The gate rescued its own subject. Blast radius of both fixes across the three repos: 0 new findings.3. gate-14 never judged the ten routes AppHost supplies (#265). #223 taught invariant 1 about
Routes::standard(); invariant 2 asks the opposite question and still read route names as literals out of the leaf's ownroutes.php, where those ten never appear. DeletingSettingsController::update()from shillinq leavesPUT /api/settingsresolving to nothing — not a 404: the router matches,ControllerMethodReflectorreflects, the request dies 500. shillinq's own docblock spells the hazard out. Gate-14's findings log came back empty.4. gate-14 derived a path the app does not use.
AppHost\Controller\GenericHealth#indexresolved tolib/Controller/AppHost/Controller/…while PSR-4 puts it atlib/AppHost/Controller/…, so the gate reportedcontroller-class-not-foundinside the repository that ships the file. And where a DI binding rescued the absence the loopcontinued — so the method-existence check never ran: two fixtures differing by one renamed method both reported PASS. #275 found the same root independently from gate-5's side and landed the two-root probe; this branch's resolver is now byte-identical tomain's, and adds the gate-14 invariant-2 fixtures that assert it from the other direction.5. Three gates reported PASS over a crashed checker. With
python3exiting 1 — nothing inspected by any python-backed gate:15/16/18 wrote
2>/dev/null || trueand counted lines in an empty log; 19 read exit 1 asEXIT_FAILfrom a helper that never printed its summary — a blocking verdict carrying a count nobody measured.6. gates 12 and 13 passed over a
src/with zero.vue(#274).[ -d src ]is not "src/contains a Vue component". Atfef032bboth printed PASS on the nldesign shape. Nowna, with the judgement #274 asked for written down:NcSelect/NcModal/NcDialogare Vue SFC components, a PHP template cannot instantiate one, so these two stay.vue-only and gate-40 keeps the language-agnostic rule fortemplates/. (#280 closed the gate-45 half; this is the gate-12 half.)7. gate-16 could not see the deletion of its own tag.
_overlapswalks forward from the declaration; the docblock is above it, and the docblock is the only place@speclives. Delete the tag, leave the body byte-identical →# count=0, exit 0. Every@spectag in a repository could be stripped and gate-16 stayed green.run_gatealso skipped any file with an emptyaddedset, which a pure deletion produces, so the file was never opened. Same family asfilter_preexisting_methods.pyfiling an auth-attribute removal as pre-existing — gate-16 does not route through that helper (its four call sites are gates 6/7/8/30, andcheck_spec_coverage.pyreferences it zero times); it reached the same blind spot by its own path.Plus gate-22's verdict depended on where the gates were checked out (
ajvresolved relative tocheck_manifest.js, never to the repo under test — run from openregister's root withnode_modules/ajvpresent there it printed "not resolvable … no node_modules", which was false), and gate-15's slot matcher had gate-44's attribute-order blind spot (<template #widget-x class="wide">did not match).Exit is a status, count on stdout — swept, empirically
check_e2e_coverage.py1check_spec_coverage.py1detect-redundant-controllers.py# count=marker1check_dashboard_antipattern.py0check_manifest.jsfailedalready clamped to 0/10/1/2/3check_spec_coverage.pyandcheck_dashboard_antipattern.pyused to return the count; both are now a status plus a terminal# count=marker, which is also what lets the runner tell "clean" from "did not execute".Anti-widening
createFromArray()in a file mentioning ObjectService → not flagged.ping#indexsibling is unaffected;routes-standard/still yields exactly one finding..vuecarrying the defect and both go straight back to FAIL.python3on the same fixture still FAILs the planted dialect..mddocumenting conflict markers is not flagged.Tests — all mutation-checked against the pre-fix tree
test_gate_or_objectservice_surface.sh(new)--leading grep pattern is parsed as optionstest_gate_crashed_checker_is_not_a_finding.shtest_gate_empty_scope_never_passes.sh.vuecontroltest_gate_route_registration.shroutes-standard-missing-update/(#265) andpsr4-namespaced-controller{,-missing-method}/.HYDRA_GATES_RUNNER_UNDER_TESTsilently kept running the fixed one and reported all-green — a mutation check that could not fail. Fixed here too.test_check_spec_coverage.pytest_check_manifest.shtest_check_dashboard_antipattern.py59helper suites pass (2 quarantined, unchanged),61bin-level assertions pass.Verdicts will move
gate-20 and gate-17 can now produce findings in repos that were green — starting with the shillinq auth-guard call above. Gates 12/13/15/16/18/19 can now report
SKIPPED (wiring)orNOT APPLICABLE; neither is a pass.Closes #265. Closes the gate-12 half of #274.