Summary
gate-48's frontend-CSRF-signal scan uses the git pathspecs src/**/*.vue, src/**/*.js, src/**/*.ts. In a plain (non-:(glob)) git pathspec, * matches /, so src/**/… requires at least one directory below src/. Every file sitting directly at src/foo.js is invisible to that scan.
Found while building a control for #425's gate-48 arm; the fixture only separated once the file was moved into a subdirectory. It is pre-existing — both fa555a2 and a316aa5 behave identically — so it is not a regression from the 2026-08-13 comment-class fixes.
Reproduced
One repo, one commit dropping #[NoCSRFRequired], one JS file, nothing else varying but its path.
$ git diff --name-only HEAD~1...HEAD
lib/Controller/ThingController.php
src/thing.js
$ git diff -U0 HEAD~1...HEAD -- 'src/**/*.vue' 'src/**/*.js' 'src/**/*.ts'
<- empty
$ git diff --name-only HEAD~1...HEAD -- 'src/**/*.js' 'src/*.js'
src/thing.js
Both call sites are affected:
run-hydra-gates.sh, the _csrf_fe_signals python heredoc — git diff -U0 f'{base}...HEAD' -- 'src/**/*.vue' 'src/**/*.js' 'src/**/*.ts'
- the same pathspec list wherever else gate-48 enumerates the frontend diff
Severity: low, and the direction is fail-CLOSED
A missed signal makes _csrf_fe_signals zero, which routes to the caller-state check (check_csrf_callers.py) — the conservative branch. In my fixture the gate still FAILed, for the right reason, via that fallback. So this does not currently let a CSRF removal through; it makes the signal count a floor rather than a count, and it means the NOTE gate-48 prints about the frontend diff can be wrong about what it read.
Suggested fix
Add the top-level spelling alongside the recursive one — 'src/*.vue' 'src/**/*.vue' etc. — or switch to :(glob)src/**/*.js, where ** means "zero or more directories" and * does not cross /.
Acceptance
The fixture above, with src/thing.js left where it is: the signal scan must see the file. Keep the subdirectory arm as the control so a fix that only handles the top level is visible too.
Measured 2026-08-13 while re-measuring gates 7/25/48/49/50 across the eighteen core apps.
Summary
gate-48's frontend-CSRF-signal scan uses the git pathspecs
src/**/*.vue,src/**/*.js,src/**/*.ts. In a plain (non-:(glob)) git pathspec,*matches/, sosrc/**/…requires at least one directory belowsrc/. Every file sitting directly atsrc/foo.jsis invisible to that scan.Found while building a control for #425's gate-48 arm; the fixture only separated once the file was moved into a subdirectory. It is pre-existing — both
fa555a2anda316aa5behave identically — so it is not a regression from the 2026-08-13 comment-class fixes.Reproduced
One repo, one commit dropping
#[NoCSRFRequired], one JS file, nothing else varying but its path.Both call sites are affected:
run-hydra-gates.sh, the_csrf_fe_signalspython heredoc —git diff -U0 f'{base}...HEAD' -- 'src/**/*.vue' 'src/**/*.js' 'src/**/*.ts'Severity: low, and the direction is fail-CLOSED
A missed signal makes
_csrf_fe_signalszero, which routes to the caller-state check (check_csrf_callers.py) — the conservative branch. In my fixture the gate still FAILed, for the right reason, via that fallback. So this does not currently let a CSRF removal through; it makes the signal count a floor rather than a count, and it means the NOTE gate-48 prints about the frontend diff can be wrong about what it read.Suggested fix
Add the top-level spelling alongside the recursive one —
'src/*.vue' 'src/**/*.vue'etc. — or switch to:(glob)src/**/*.js, where**means "zero or more directories" and*does not cross/.Acceptance
The fixture above, with
src/thing.jsleft where it is: the signal scan must see the file. Keep the subdirectory arm as the control so a fix that only handles the top level is visible too.Measured 2026-08-13 while re-measuring gates 7/25/48/49/50 across the eighteen core apps.