Target project: permissions — handoff note

Current authoritative settings (after Updates 1-5; later updates supersede earlier values for the same keys):
{
  "deny_wins": false,
  "expiry_inclusive": false,
  "inherit_roles": false,
  "owner_bypass": false,
  "action_casefold": false,
  "group_union": false,
  "resource_scope": "prefix",
  "suspended_denies": false,
  "token_ttl": 200,
  "wildcard_action": false,
  "audit_denials": true,
  "default_allow": true
}

Fixed interface and algorithm contract to preserve:
- Implement evaluate(payload) -> {allowed:boolean, reason:string, matched:[grant_index], audit:[reason]}. Do not mutate inputs. Inputs are ordinary ASCII.
- Subject has tenant, roles[], groups[], owner, suspended; resource has tenant, id; payload has now, issued_at, action, grants, role_parents.
- Evaluation order, early returns with matched=[]:
  1. Deny different tenant, reason "tenant".
  2. Deny if now - issued_at > token_ttl, reason "token".
  3. If suspended_denies and subject suspended, deny, reason "suspended". Currently suspended_denies=false, so this does not trigger.
  4. If owner_bypass and subject owner, allow, reason "owner". Currently owner_bypass=false, so this does not trigger.
- Roles: start with subject.roles, plus subject.groups only if group_union. Currently group_union=false, so groups are excluded. If inherit_roles, follow role_parents transitively and tolerate cycles. Currently inherit_roles=false, so no inheritance.
- Grant matches if: grant role is in effective roles; grant action equals requested action (ASCII case-insensitive only if action_casefold; currently false, so case-sensitive) or grant action is "*" only if wildcard_action (currently false); scope matches resource.id by equality for resource_scope="exact" or by prefix for "prefix" (currently "prefix", so prefix match); and grant expires is null or now <= expires if expiry_inclusive (currently false, so require now < expires).
- Gather original indexes of every matching grant in matched.
- If no matches: allowed = default_allow (currently true), reason "default".
- If matches: reason "grants"; if deny_wins, allow only if any allow and no deny (currently deny_wins=false, so any allow suffices).
- Audit: audit is [reason] only on denied results when audit_denials is true (currently true); otherwise [].

Exceptions and unresolved items:
- None recorded for the target project. All 12 settings above are currently resolved.
- Archived records for other projects are unrelated, were discarded, and must not be applied to permissions.