backend/) serving the API and the NeIOStaff dashboard,
and a Rust/Tauri desktop agent (agent/src-tauri/) that runs on employee machines and reports in.
The backend's app/Service/ directory is the real center of gravity — 28 sub-areas, far larger than any other module.
| Method | Path | Controller | Input | Output |
|---|
vendor/bin/phpunit, one shared Postgres database), the suite leaks fixture rows
(users, organizations) across test boundaries once at least one earlier test commits real data. Every one of
the 12 affected test classes was re-run in isolation — 307/307 passed clean — proving the tests
themselves are correct and the failures are environmental. See Risk #1.
| Count | Symptom | Representative classes | Cause |
|---|---|---|---|
| 123 errors | UniqueConstraintViolationException on users_email_unique |
AlertDetectionTest, AntiGamingRulesTest, EmployeeGroupSyncTest, MeetingLoadCalculatorTest, Graph pollers | A stray users row from an earlier test collides with a fixture's hardcoded email |
| 18 failures | Row-count assertions off by exactly the leaked rows (e.g. "expected 1 organization, found 2") | MemberEndpointTest, OrganizationEndpointTest, UserModelTest, DeletionServiceTest | Same leaked-row root cause, surfacing as a count mismatch instead of a key collision |
| 6 failures | assertCount(2, User::all()) found 996 instead |
Toggl/Clockify/Harvest/Generic/Solidtime importer tests | Same root cause — these assert a global table count, so leakage compounds visibly across the whole run |
| 1 risky, 1 skipped | Test/tested code left an error handler registered; one explicit markTestSkipped |
AlertStreamTest; RowLevelSecurityTest | Unrelated to the above — minor, not a regression signal |
php CLI memory_limit (128M) is too low for this
suite — a bare vendor/bin/phpunit run crashes with a fatal OOM error around test 100 unless you pass
-d memory_limit=1G, and the repo's docker-compose Postgres/Redis services were not running,
so the suite failed with connection-refused errors until started by hand.
CI runs php artisan test --parallel, which gives every worker its own database — no cross-test
leakage is possible. But composer.json's own test script — the command a developer
would naturally reach for as composer test — runs php artisan test --stop-on-failure
with no --parallel. That runs the whole suite against one shared database, and with
--stop-on-failure set, it stops at the first of the ~150 spurious failures — which, as shown in
the Test Summary tab, can be an entirely unrelated test near the start of the alphabetical run order.
vendor/bin/phpunit (no --parallel) →
123 errors, 24 failures. The exact same 12 test classes, re-run together in isolation → 307/307 pass.
A developer running the documented composer test command has no way to tell their own change
from this noise, and --stop-on-failure means they may never even see their own test run.
Proposed fix — match the local script to what CI already knows is safe:
--- a/composer.json +++ b/composer.json @@ "scripts" "test": [ - "@php artisan test --stop-on-failure" + "@php artisan test --parallel --stop-on-failure" ], "test:coverage": [ - "@php artisan test --coverage --stop-on-failure" + "@php artisan test --parallel --coverage --stop-on-failure" ],
These two jobs (and the three artisan commands that dispatch them — neiostaff:sync-calendar,
neiostaff:sync-shift-hours, neiostaff:sync-employees) have no test file anywhere in
the 2031-test suite that invokes them, unlike every sibling poller (CalendarPoller,
PresencePoller, MessageActivityPoller, ShiftHoursPoller — all
independently unit-tested under tests/Unit/Service/Graph/).
EmployeeGroupSyncTest.php's docblock, which cites two prior incidents of this same shape).
It would surface only as quietly wrong attendance numbers on the dashboard, not as a red test.
Proposed fix: add Unit/Jobs/SyncEmployeeCalendarTest.php and
SyncEmployeeShiftHoursTest.php following the existing Unit/Service/Graph/CalendarPollerTest.php
pattern — fake the Graph HTTP client, assert the job writes what the poller already proves it can parse.
Every /neiostaff/* dashboard route (timeline, attendance, screenshots, presence, fleet, team,
timesheet — 18 routes) gets Row-Level Security enforcement from one Route::middleware('db-user-context')
wrapper at the top of the group. That's correct today. But the sibling /agent/* route group has
AgentEndpointTest structurally asserting the middleware is present on every route in it — the
/neiostaff group has no equivalent test.
Unit/Security/RowLevelSecurityTest.php, which
tests the RLS policies thoroughly but doesn't structurally guard the route wiring itself.
A future refactor that moves one route out of the group (a common, easy-to-miss change) would silently drop
RLS enforcement for that route with nothing failing red.
Proposed fix: add a structural test mirroring AgentEndpointTest's pattern —
iterate every registered route under the neiostaff. name prefix and assert db-user-context
is in its middleware stack.
<script>, quotes, backslashes): PASS, treated as plain text since filtering uses .includes() on already-escaped table text, not innerHTML injection.php -d memory_limit=1G vendor/bin/phpunit yourself and confirm the final line still reads "Tests: 2031, ... Errors: 123, Failures: 24, Skipped: 1."