Re-derive the audit structurally — 57 decorative

Fixkamo-internal
Shipped
August 14, 2026 at 10:34 PM UTC
Author
kamo
Commit
6d4a0d0

The count moved 58 -> 52 -> 47 -> 57 because every version hard-coded a list of gate-helper names and the codebase has more than anyone can recall. Six were missed across three passes — denyUnless, hasAnyRight, sessionHasRight, forbidden, findByMemberAndRight, checkRole — and each miss reported a working permission as dead. audit_v3.py names none of them. It uses the structural difference between code that USES a right and prose that DISCUSSES one: argument position (hasRight(request, RoleRightType.X), List.of(RoleRightType.X)) or receiver position (RoleRightType.X.name(), which is how OrganizationController gates branding). A javadoc paragraph mentioning {@code MANAGE_TIMECARDS} no longer reads as a check — that was the source of most phantom 'enforced' results. It validates against 13 rights confirmed by reading the code and exits non-zero rather than emit a list it disagrees with. The guard caught two defects while the analyzer was being written, and disproved one of my own earlier corrections: VIEW_DASHBOARD is decorative. The file-level pass had rescued it wrongly. Net vs the shipped list: +13 (six sales-agent rights, four marketing VIEW_*, VIEW_DASHBOARD, VIEW_TIME_OFF, VIEW_VOICEMAIL — all rescued by file-level matching but never passed to anything), -2 (VIEW_PAYROLL, MANAGE_PAYROLL, which genuinely are enforced). Analyzer and its output are committed so the number is reproducible instead of asserted, and the file says not to hand-edit — editing one entry by eye is how it drifted before.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing