- Ya
- 15 Agosti 2026, 06:07 UTC
- Mwandishi
- kamo
- Ahadi ya
- ec62628
26 unenforced becomes 20, and none of it is new enforcement. The six sales-agent rights have been gated the whole time: AiSalesAgentController checks them across thirteen endpoints, with a purpose-built helper whose fallback keeps every existing MANAGE_AI_SETTINGS holder working so the split needed no migration. It is among the best-implemented authorization in the platform and the audit called all six dead. The argument pattern used [^()], which cannot span a nested call. Against can(c.memberId(), **************** it matched c.memberId() and forbidden() and never saw can(...) at all. Every gate whose arguments contain a nested call was invisible. Fixed by allowing one level of nesting, and all six are ground truth now so a regression fails the run. §10 replaced hard-coded helper names with a structural rule because guessing the vocabulary of enforcement had failed four times. That was right and insufficient: this pass guessed the shape of the arguments instead. Four failures from guessing names, the fifth from guessing syntax. The ground-truth guard missed it because none of its thirteen rights used a nested argument — a guard only covers the shapes it was given. What caught it was reading AiSalesAgentController while triaging the cluster. So the rule gains a clause: when the analyzer reports a whole cluster as dead, read the controller first, because a systematic blind spot looks exactly like a systematically unenforced module. Two parity guards needed correcting as fallout. VIEW_SALES_AGENTS was pinned as "gates nothing" on the strength of the wrong output, and the non-trivial-subset lower bound was 20 — which the shrinking list reached exactly. A bound that tracks the current count breaks on every success, so it now only catches the collapse it was written for.