Skip to content

M6-07 Permission hints and expiry overview

No Date Ruling Reason
D-M6-07-1 2026-10-22 One H1 function: domain.ReadHorizonGaps(agent, H(A) paths, T(A), snapshots) returns one hint per person of T(A) and channel of H(A) the person cannot read. M1-49 computed the gaps inline in app/explain.go; the explainer now calls the domain function, and the list "Permission hints" calls the same explainer method (readHorizon), so "who has access" (via_agent) and the list never disagree. H(A) and T(A) stay domain.Horizon and domain.Triggerers of M1-49 (T(A) without the people SR2 blocks). Brief Design note 1; 07 section 6.
D-M6-07-2 2026-10-22 The other three kinds. grant_to_disabled: a grant in effect whose subject person, agent or app has status disabled or deleted; a pending person's grants take effect (07 SR7) and do not count, a group never (deleting a group revokes its grants). trigger_blocked: a grant in effect with level trigger to an active person or a group that reaches at least one channel with an effective operator (archived channels left out, no one triggers there), where on every such channel SR2 (operator of effective tool class host) or SR3 (project binding) blocks the subject exactly as the guard of agent.invoke does: no owner and no ready own dev environment (for a group: no member in effect with one); the hint names the blocking rules (sr2, sr3). A disabled subject is reported as grant_to_disabled only. A trigger grant that reaches no operated channel gives no hint, because SR2 and SR3 are not the reason. agent_personal: every active agent in mode personal with its credential holder and its trigger set of SR1 (domain.TriggerSet, the set I1 checks). Brief Design note 1; 07 sections 9.5, SR2, SR3.
D-M6-07-3 2026-10-22 Scope and paging. The instance needs the owner role; a space needs owner or manage there (authorize(access.hints.read) on instance or space; no read 404, read without manage 403; a space that does not exist is 404 for owners too). For a space, H1 covers the channels of the space for every agent, not only the agents that operate a channel of the space: an agent of another space that reads a channel of this space can leak it to its own triggering people, and that is exactly what the manager of this space must see. The grant kinds cover grants on the space and its channels; agent_personal the personal agents that serve a target in the space. Every agent comes from the new source port authz.AgentDirectory (agents module), because an agent can serve a channel only through the threads it operates. The list is ordered by kind (h1_read_horizon, grant_to_disabled, trigger_blocked, agent_personal) and within a kind by agent, person and channel, by grant ID or by agent ID; the cursor carries the kind and the key, and a page is computed lazily (H1 agent by agent), so every hint appears on exactly one page. Measured with 50 agents and 500 people: the whole H1 list in one request about 1.7 s on a developer machine, a first page of three about 0.3 s, both within http.request_timeout. Brief Design note 2; 07 section 2.6.
D-M6-07-4 2026-10-22 "Expiring soon": grants not revoked and memberships not removed (of live groups) with expires_at in (now, now + authz.expiry_reminder_lead], whether reminded or not (the reminder marker belongs to the job of M1-30, the list shows the state); tokens of agents and apps not revoked in the same window from the new source port authz.TokenExpirySource (identity, ids and expiry only), only on the instance and so only for owners (R-AZ-34); never personal tokens. Ordered by expiry, then grant, membership, token, then ID, paged by that position. For a space: grants on the space and its channels and the memberships of groups that hold a grant in effect on such a target. A page carries the names of its principals, groups, spaces and channels (AccessLabels, also on the hints), so the client builds its sentences without further reads and no name beyond the administration lists appears. Brief Design note 3; 07 section 9.4.
D-M6-07-5 2026-10-22 "Extend" creates the new grant (subject, target, level and capabilities of the old one, a new reason, a new expiry) and then revokes the old one, both through the step-up interceptor, so one step-up within auth.step_up_max_age covers both and the access never lapses in between; a failed creation revokes nothing. A token is renewed by creating a new one (secret shown once) and revoking the old one in the token screen of the agent. Brief Design note 4; 07 sections 2.5 and 9.4.
D-M6-07-6 2026-10-22 Names of the merged code instead of the brief (D-W-100): the port identity.TokenExpiry of the brief is the source port authz.TokenExpirySource declared by authz (02 section 4.1 rule 4) and implemented by identity/app.TokenExpiry; chat.Operators needs no new port, the effective operator per channel comes from StructureSource.Channels as in M1-49; the cursor codec of M1-18 is app.Cursors. The hint field of the blocking rule is the list rules, because SR2 and SR3 can block the same grant on different channels. Merged names win (D-W-100).