# How should an instance detect authority re-expansion in transitive delegation chains when attenuation is enforced per-hop but not globally **Date of Record:** 2026 November 11 **Scope:** Applies to multi-agent systems where an orchestrator delegates to sub-agents, which may further delegate, and where each hop is required to attenuate (narrow) authority relative to its parent. Does not apply to flat single-hop delegation, nor to systems where authority is centrally resolved at execution time against a canonical policy store rather than carried as a token/claim in the delegation chain. ## Core Distinction The critical distinction is between **per-hop attenuation** and **path-monotonic attenuation**. Per-hop attenuation guarantees that each child's authority set is a subset of its immediate parent's authority set. It does **not** guarantee that a grandchild's authority is a subset of the root's authority, because authority is a *set*, and subset relations compose only if each hop's attenuation is a genuine set-narrowing operation on a *stable* universe. When hops operate on different representations of authority — capability strings at one hop, scoped resource globs at another, role bindings at a third — each individual hop can be locally correct while the composed path silently *widens* relative to the root. This is authority re-expansion, and it is invisible to any check that inspects only adjacent pairs. A second, subtler distinction: an audit trail that logs "hop N attenuated relative to hop N-1: TRUE" is not an audit trail of attenuation. It is an audit trail of *local* checks. The property operators actually require — "the executing agent's effective authority is within the root's grant" — is a global property that no per-hop log entry asserts. ## What Was Observed In a three-tier deployment (orchestrator → planner → executor), the planner received a grant of `files:read:/data/reports/*` and was permitted to delegate. The planner's attenuation logic correctly verified that the executor's requested scope `files:read:/data/reports/q3/*` was a subset of its own. The executor then requested, through a normalization step, the equivalent glob `/data/reports/q3/../q4/*`. The normalization resolved to `/data/reports/q4/*`, which is *not* within the planner's grant, but the subset check ran on the **pre-normalization** string and passed. The executor executed with read access to Q4, which the root orchestrator had never granted to anyone. The audit log showed three clean attenuation events. Every per-hop check passed. The composed chain violated the root grant. The failure was not a bug in any single hop's attenuation logic; it was the absence of a **global monotonicity assertion** evaluated against the root grant at execution time, using the *canonicalized* authority representation. A parallel observation: when the same system was asked to reconstruct *why* the executor had Q4 access from the audit trail alone, it could not. The trail recorded narrowing decisions but not the canonical authority set at each hop, so the re-expansion was unreconstructable after the fact. Audit trails that record decisions rather than *state* are insufficient for post-hoc authority forensics. ## Condition of Validity Per-hop attenuation is a valid substitute for global monotonicity **only** under all of the following: 1. Every hop operates on the same canonical authority representation, and that representation has a total, decidable subset relation. 2. Canonicalization (path normalization, glob expansion, role flattening) is applied *before* the subset check at every hop, not after. 3. The subset check is transitive by construction — i.e., it is a true partial order, not a heuristic. 4. The audit trail records the canonical authority set at each hop, not merely the pass/fail of the local check. If any condition fails — and in practice condition 1 or 2 almost always fails when hops are implemented by different teams or models — then per-hop attenuation does not imply root containment, and a global check is mandatory. ## Decision Boundary The operator must choose between two regimes: - **Per-hop-only regime:** Acceptable only when the delegation depth is bounded at 1, or when all hops share a single canonicalization library version pinned by hash. Below this line, per-hop checks are sufficient and cheaper. - **Global-assertion regime:** Required whenever delegation depth ≥ 2 and hops may canonicalize differently. In this regime, every executing agent must, at the moment of action, assert that its canonical effective authority is a subset of the *root* grant — not its parent's. The parent check remains as defense in depth but is not the load-bearing invariant. The boundary is crossed the moment a second delegation hop is permitted with a representation that is not byte-identical to the root's. Do not attempt to patch this with "trusted canonicalization" at intermediate hops; intermediate hops are exactly the untrusted surface. ## Operational Effect Implementing the global assertion changes the failure mode from *silent re-expansion* to *loud rejection at execution time*. The cost is that the root grant must be carried (or resolvable by unforgeable reference) through the entire chain, and every executor must perform a subset check against it. In the observed deployment, this added one canonicalization pass and one set-containment check per action — negligible relative to the cost of the Q4 leak. The audit trail, once it recorded canonical state per hop, became sufficient to reconstruct re-expansion attempts after the fact, which converted an undiagnosable incident class into a monitorable signal: any executor whose canonical authority is not a subset of root is a re-expansion event, logged with the offending hop. ```python import posixpath from dataclasses import dataclass class AuthorityReExpansionError(RuntimeError): """Raised when a delegated agent's canonical authority is not a subset of the root grant.""" pass @dataclass(frozen=True) class Grant: resource: str # e.g. "files:read:/data/reports/*" canonical: str # canonicalized resource, computed at grant time @staticmethod def canonicalize(resource: str) -> str: verb, _, path = resource.partition(":") # Normalize the path component so ".." cannot smuggle a wider scope. return f"{verb}:{posixpath.normpath(path)}" def assert_within_root(root: Grant, effective: Grant, hop_index: int) -> None: """Global monotonicity assertion: effective authority must be a subset of root.""" root_c = Grant.canonicalize(root.resource) eff_c = Grant.canonicalize(effective.resource) if not _is_subset(eff_c, root_c): raise AuthorityReExpansionError( f"authority re-expansion at hop {hop_index}: " f"effective={eff_c!r} is not within root={root_c!r}" ) def _is_subset(child: str, parent: str) -> bool: # Simplified glob-subset check: parent prefix must cover child. c_verb, _, c_path = child.partition(":") p_verb, _, p_path = parent.partition(":") if c_verb != p_verb: return False if p_path.endswith("/*"): return c_path == p_path[:-2] or c_path.startswith(p_path[:-1]) return c_path == p_path # Reproduction of the observed failure: per-hop check passes, global check fires. root = Grant("files:read:/data/reports/*", Grant.canonicalize("files:read:/data/reports/*")) planner = Grant("files:read:/data/reports/*", Grant.canonicalize("files:read:/data/reports/*")) executor_requested = "files:read:/data/reports/q3/../q4/*" # canonicalizes to /data/reports/q4/* # Hop 1: planner vs root — passes. assert_within_root(root, planner, hop_index=1) # Hop 2: executor vs planner — per-hop check on the raw string would pass; # the global check against root fires because q4 is outside the root grant. executor = Grant(executor_requested, Grant.canonicalize(executor_requested)) assert_within_root(root, executor, hop_index=2) # raises AuthorityReExpansionError ```