Split out of #10757 (direction 4) by PM ruling on PR #10824.
resolveUserAuthzGrants (packages/core/src/security/resolve-authz-context.ts ~330–560) issues 8 sequential round trips — legs 6–13 of an authenticated data request:
6. sys_member {user_id}
7. sys_user_position
8. sys_member {organization_id} (fellow-org, limit 1000)
9. sys_user_permission_set
10. sys_position {name $in}
11. sys_position_permission_set
12. sys_permission_set {id $in}
13. sys_user {id} (ai_seat)
They could be 2–3. No caching, no invalidation contract, no staleness — every read stays live, so this is independent of #10757's tranche 2 (caching) and cannot drift from whatever invalidation design that lands.
Why this is likely the highest-leverage no-risk work left
cloud#1539 measured, causally by latency injection (R² = 0.9994), that an authenticated request is 23.4 sequential legs and that:
L, not N, is the multiplier. Batching is worth exactly as much as deleting.
So collapsing 8 legs into 2–3 removes ~5–6 of 23.4 — roughly a quarter of the whole request — without touching a single authorization semantic.
Against the measured prod model server_ms ≈ 33 + L × 36.6:
| legs | prod server time |
|---|
| today | 23.4 | ~890 ms |
| after this card | ~18 | ~690 ms |
Not sufficient alone (cloud#1521's gate is ≤200 ms, and placement is the lever that clears it — cloud#1546 is testing that now), but it is the largest block available that carries no staleness risk whatsoever.
Why batching beats caching here, stated plainly
A batched read returns the same rows or fails loudly. A cache returns stale grants silently — a permission revoked at T still honoured until a TTL expires. On the authorization path that difference is the whole ballgame, which is why this is separable from tranche 2 and worth doing whether or not tranche 2 ever ships.
Constraints
Measuring the result
X-OS-Debug-Timing: json on an admin principal returns Server-Timing: db;dur=…;desc="N queries". That gives the query count directly, but the number that matters here is legs, not queries — report both, and say how you established the leg count (a batch that runs 3 queries in parallel is 1 leg; 3 sequential is 3).
Split out of #10757 (direction 4) by PM ruling on PR #10824.
resolveUserAuthzGrants(packages/core/src/security/resolve-authz-context.ts~330–560) issues 8 sequential round trips — legs 6–13 of an authenticated data request:They could be 2–3. No caching, no invalidation contract, no staleness — every read stays live, so this is independent of #10757's tranche 2 (caching) and cannot drift from whatever invalidation design that lands.
Why this is likely the highest-leverage no-risk work left
cloud#1539 measured, causally by latency injection (R² = 0.9994), that an authenticated request is 23.4 sequential legs and that:
So collapsing 8 legs into 2–3 removes ~5–6 of 23.4 — roughly a quarter of the whole request — without touching a single authorization semantic.
Against the measured prod model
server_ms ≈ 33 + L × 36.6:Not sufficient alone (cloud#1521's gate is ≤200 ms, and placement is the lever that clears it — cloud#1546 is testing that now), but it is the largest block available that carries no staleness risk whatsoever.
Why batching beats caching here, stated plainly
A batched read returns the same rows or fails loudly. A cache returns stale grants silently — a permission revoked at T still honoured until a TTL expires. On the authorization path that difference is the whole ballgame, which is why this is separable from tranche 2 and worth doing whether or not tranche 2 ever ships.
Constraints
packages/specis off limits — stop and report if a batch needs a contract change.Measuring the result
X-OS-Debug-Timing: jsonon an admin principal returnsServer-Timing: db;dur=…;desc="N queries". That gives the query count directly, but the number that matters here is legs, not queries — report both, and say how you established the leg count (a batch that runs 3 queries in parallel is 1 leg; 3 sequential is 3).