Skip to content

Phase 5 Rulings — ADR-084…088, plus directives D-5.1 and D-5.2

Phase 5 Rulings — ADR-084…088, plus directives D-5.1 and D-5.2

Date: 2026-08-01 · Disposes of: R5-F-01R5-F-07 from Phase5_Authorised_Adversary_Review.md Applied directly to the whitepaper. No W document, for the reason R3 gave.

How the product questions were handled, because that is the whole difficulty of this round

Phase 5 was flagged at review time as roughly half not rulable from the architecture: what a GM is entitled to, whether a high-volume GM is a supported customer, and what membership means are product decisions, and this corpus refuses invented rationale more strongly than it refuses gaps.

The disposition therefore separates two things that were tangled in the findings:

  • The architectural half is ruled now, and in each case it is the half that decides what the mechanism must be able to express and which way it fails when nobody has decided. That is a genuine architectural question with a defensible answer, and answering it does not pre-empt the product.
  • The product half is recorded as an open decision with a named consequence, not resolved. Where a value cannot be chosen without it, the ruling is that the value stays pending — because a number chosen blind silently encodes a compromise, which is worse than a blank that is visibly empty.

Two findings needed no ADR at all. Applying ADR-045’s criterion rather than defaulting to an ADR is now the third time this session.


ADR-084 — Declassify Cannot Widen Disclosure of Another Participant’s Content

Status: Accepted · Date: 2026-08-01 · Amends: 022 · interacts with 073

✅ Confirmed — product owner, 2026-08-06. Not an amendment; nothing below changes.

This record ends by leaving a door open: “A product may later decide a GM can obtain another participant’s content, but that is a consent-bearing feature with its own record, not a flag.”

That decision has now been taken, and it is: no. Descent Studio’s Cinematic Replay Editor proposed exactly the mechanism this ADR anticipated — a GM-issued “Unrestricted Replay Token” granting a player the full raw event stream, with the GM assuming responsibility. The product owner ruled Player-Channel access out of scope:

“If they didn’t have permission initially, they don’t have permission.”

Why this is written here rather than as a new ADR. The workflow rules require an ADR when a decision contradicts or narrows an existing one, or rejects an alternative a future reader would plausibly re-propose. This contradicts nothing — it affirms. And the rejection and its reasoning already live in this record; a second ADR would restate a decision this one owns, which is the corpus’s most-recorded defect. What is genuinely new is the provenance — the door was tested and the product closed it — so it belongs on the record a reader of ADR-084 actually opens.

Deliberately a confirmation and not an Amends. The four link types differ by the obligation they create; an Amends would assert a narrowing that did not happen and would require a reverse link in §11 for a change to nothing.

The owner’s formulation is the more general statement of the rule. This ADR reasons from disclosure-set mechanics — no mechanism may widen a viewer’s disclosure set. “If they didn’t have permission initially, they don’t have permission” says the same thing from the participant’s side and holds for any future export, share or replay surface without being re-derived per feature. See docs/studio/Cinematic_Replay_Engine_Proposal.md §6.

Context

R5-F-01, the round’s only 🔴. ADR-022 makes an export per-viewer filtered and “scoped to one requesting identity”, then adds “an optional GM declassify toggle per channel”. §8.2 defines four Visibility Channels, one of which is the Player Channel, “visible to specific player”. Whether declassify reaches that channel was never stated, and one reading exports content the channel model exists to keep private — through a supported feature, working exactly as configured, violating no stated control.

Decision

1. Declassify is scoped to concealment the GM themselves authored — the GM Channel and the Secret Channel. Applied to those, it does exactly what it was written for: handing players the monster stats and the secret rolls after a campaign ends.

2. Declassify may never widen the disclosure of content authored by another participant, which the Player Channel carries by definition. This is the same principle ADR-073 established for the degradation ladder — no rung may widen any viewer’s disclosure set — applied to a different mechanism. The two are stated separately because they constrain different machinery, and neither implies the other.

3. The reason this is architectural and not a product preference: §8.2’s channels are relied on by the live replication path, by ADR-022’s archive builder, and by §14.7’s generated disclosure tests. A toggle that can lift a channel’s meaning makes that meaning unstable for every consumer, so the channel model would no longer be something any of them could depend on. A product could later decide that a GM may obtain another participant’s content — but that is a consent-bearing feature with its own record, not a flag on an export.

4. Where the toggle applies, the export records which channels were declassified, so an archive is self-describing rather than indistinguishable from a filtered one.

Alternatives Considered and Why Rejected

  • Let declassify cover all four channels. The permissive reading. It makes §8.2’s Player Channel unenforceable at the one moment it matters most, and does so silently, since the export is a legitimate operation with no signal to the affected participants.
  • Leave it unstated and decide per deployment. The status quo, and the finding. An ambiguity in a disclosure control resolves, under delivery pressure, toward whatever is easiest to implement.
  • Require per-player consent inline in the toggle. A reasonable product design and not an architectural ruling; recorded as the direction a future feature would take rather than mandated here.

Consequences (including the negative ones)

  • A GM cannot produce a single complete archive of a campaign, and some will consider that a missing feature. It is the intended outcome: the archive of a shared campaign is per-identity by design (ADR-022), and this ADR only stops a toggle from quietly reversing that.
  • “Content authored by another participant” needs a precise boundary at implementation time. A GM’s own note about a player is the GM’s content; a player’s note is not. The rule is clear at the edges and will need a decision in the middle, and pretending otherwise would be the kind of false precision this document avoids.

Enforcement

  • CI: §14.7’s generated disclosure tests include a declassified export, asserting that no Player-Channel item authored by another participant appears in it.
  • Release checklist: any new channel added to §8.2 declares whether declassify may reach it.

§11 Index Line

ADR-084: The ADR-022 declassify toggle is scoped to concealment the GM authored — GM and Secret channels — and may never widen disclosure of content another participant authored, which is what §8.2's Player Channel carries. A toggle able to lift a channel's meaning would make that meaning unstable for the live path, the archive builder and §14.7 alike; a declassified export records which channels it lifted.


ADR-085 — Departure Is Not Erasure, and Membership Needs Exactly One Revocation Point

Status: Accepted · Date: 2026-08-01 · Amends: 026 · Depends-on: 080

Context

R5-F-02: the specification has no room membership model. invite, eject, ban and revoke do not appear; all nine membership hits are Orleans clustering. What happens when a person leaves a table is undefined, and the only removal mechanism the architecture has — subject erasure (ADR-078, ADR-080) — is the wrong instrument, because a departing player usually wants to stop participating rather than to destroy a year of a shared notebook.

Most of this finding is product design and is not ruled here. Who may remove whom, whether removal is reversible, and what a removed player retains are decisions about how tables work.

Decision

1. Departure is not erasure, and the two must never be implemented as one operation. Erasure is a subject’s own request against their identity linkage and authored items. Departure is a change in who participates. Conflating them means either that leaving a group destroys a player’s contributions to a shared campaign, or that removing a disruptive participant is unavailable because it would look like deleting their data. Both failure modes come from having one verb, so the ruling is that there are two.

2. A departed participant’s authored content remains unless they separately request erasure. §7.3’s Yjs permanence and ADR-080’s item-granular erasure already produce this; it is stated so that a future membership feature does not reach for a bulk delete.

3. Whatever membership turns out to mean, revocation has exactly one architectural requirement, and it is stated now because it is the part that outlives a session: revoking participation must reach (a) ADR-026’s document-write capability token, which is scoped to RoomId + a DocId set with an expiry and is otherwise valid until it expires, and (b) export entitlement, since ADR-022 scopes an archive to a requesting identity and nothing currently re-checks that the identity still participates. These two are named because they are the paths where a stale authorisation is not obvious — everything else in the design re-derives authority per request from the RoomGrain.

4. Open, and owned by product rather than by this ADR: who may remove whom; whether removal is reversible; whether a removed participant retains read access to sessions they played. This ADR is deliberately silent, and the silence is recorded rather than left to be mistaken for coverage.

Alternatives Considered and Why Rejected

  • Define the whole membership model here. It would be invented. The corpus’s rule against fabricated rationale applies with more force to a policy than to a technical alternative, because a policy nobody chose reads as one somebody did.
  • Treat removal as erasure of the participant from that room. The conflation clause 1 exists to prevent. It destroys other participants’ co-authored context and gives a GM a data-destruction button.
  • Defer everything, including the revocation requirement. The requirement is cheap now and expensive later: a capability token with no revocation path is a design that must be rebuilt rather than extended.

Consequences (including the negative ones)

  • This ADR does not make membership implementable. It constrains it. A reader looking for the membership design will not find one, and that is accurate rather than an oversight.
  • ADR-026’s token gains a revocation check it did not have, which is a real cost on a hot path the ADR deliberately made cheap (“authorize once, relay many”). The mitigation is that revocation is rare and can invalidate by generation rather than by lookup — but the cost is real and is not waved away.

Enforcement

  • ArchitectureTests: no code path performs erasure as part of a membership change.
  • CI: a revoked participant’s outstanding ADR-026 capability token is rejected by the relay, and an export request from a revoked identity is refused.
  • Release checklist: the membership model, when it exists, is checked against clauses 1–3.

§11 Index Line

ADR-085: Departure and erasure are two verbs and must never be one operation — a departed participant's authored content remains unless they separately request erasure. Whatever membership comes to mean, revocation must reach ADR-026's document-write capability token and export entitlement, the two authorisations that outlive a session. Who may remove whom is an open product decision this ADR deliberately does not make.


ADR-086 — A Plugin’s Interest Set Is Bounded by the Admitting Principal’s Own Disclosure Set

Status: Accepted · Date: 2026-08-01 · Amends: 010, 040

Context

R5-F-03: §6.4’s trust tier table declares its axes — what executes (P0–P3) and what enters (P4) — and neither is authority. The GM appears in the table once, as a source of URLs. The practical consequence is that a plugin is admitted by one principal and observes data belonging to several, and nothing in the tier model addresses that, because the tiers ask what code can reach and never on whose behalf it was admitted.

Decision

1. A plugin’s interest set may never exceed the disclosure set of the principal who admitted it. A GM-installed plugin observes what the GM is entitled to observe — which is a great deal — and never more. The bound is the admitting principal’s §8.2 channel entitlement, evaluated per viewer, not a separate plugin permission model.

2. This bounds the gap without adding an axis to §6.4. The table continues to classify extensions; the authority question is answered where authority is actually modelled, which is §8.2’s channels. §6.4 states that it classifies extensions and not principals, so a reader stops expecting an answer it does not contain.

3. Q-027 (PLUGIN_INTEREST_SET_MAX) remains pending and is now a resource bound rather than a disclosure bound. Its absence no longer leaves a confidentiality hole — clause 1 covers that — and it still bounds cost. Separating the two is the point: they were one pending value doing two jobs, and only one of them was urgent.

Alternatives Considered and Why Rejected

  • Add a principal axis to §6.4. Proportionate-looking and larger than it appears: it would require classifying every human role in the system, and the finding is bounded by clause 1 without it. Recorded as available if a second authority finding appears.
  • Give plugins their own permission model. A second entitlement system alongside §8.2’s channels, which would then have to be kept consistent with it. The corpus’s recorded failure mode of two mechanisms owning one property.
  • Rely on the sandbox. The sandbox constrains what a plugin can do, and this finding is about what it can see. Different properties, and §6.4’s own P1/P2 note already records the cost of conflating access control with resource control.

Consequences (including the negative ones)

  • A plugin cannot offer a feature that requires seeing more than its installer. Some legitimate designs are foreclosed — a plugin computing table-wide statistics over content the GM cannot see is not implementable. That is the intended trade.
  • Evaluating the bound per viewer has a cost on the interest-set path, which is inside the frame budget §9.5 protects. It is the same evaluation the snapshot filter already performs, so it should reuse it rather than duplicate it.

Enforcement

  • ArchitectureTests / registration-time: a plugin manifest declaring interest outside the admitting principal’s channel entitlement is refused at registration, the same shape as ADR-068’s refusal of a descriptor with no viable C-Companion rendering.
  • CI: §14.7’s disclosure tests include a plugin whose declared interest exceeds its installer’s entitlement.

§11 Index Line

ADR-086: A plugin's interest set may never exceed the disclosure set of the principal who admitted it, evaluated against §8.2's channels rather than through a second permission model. This bounds §6.4's missing authority axis without adding one; §6.4 states that it classifies extensions and not principals. Q-027 accordingly becomes a resource bound rather than a disclosure bound.


ADR-087 — A Quota That Cannot Distinguish Legitimate Volume From Abuse Must Not Be Given a Number Yet

Status: Accepted · Date: 2026-08-01 · Amends: 015, 047, 059

Context

R5-F-04: §10.3’s cost defences are per-account quotas, and the GM is the account with the most legitimate reason to approach every one. A convention organiser, a play-by-post organiser with fifty rooms, and an account systematically scraping campaigns produce the same telemetry. Q-034 (export concurrency and daily caps) and Q-049 (checkout concurrency across rooms) are both pending.

§10.3 face 6 already names the abusive shape — “one account scripting tree-scrubbing across fifty rooms” — and treats it as a cost problem, which for anonymous and player-level abuse it is.

Decision

1. Q-034 and Q-049 stay pending, and their blocker is now named: the product’s entitlement-tier model. They are not blocked on measurement. Setting them today means choosing a point between a supported customer and an abuser that the system cannot tell apart, and encoding that compromise in a constant nobody will later recognise as a compromise.

2. A quota that bounds a legitimate high-volume use and an abusive one with the same number requires a dimension other than volume. Entitlement is the obvious one. This is the architectural claim and it holds regardless of which tiers the product invents.

3. Cost containment does not wait for it. The existing per-account bounds continue to protect the platform’s bill, which is what they were designed for and where they work. What is deferred is treating them as an abuse control, which they were never able to be.

4. Where a bound must exist before the tier model does, it is set to protect cost and is labelled as such in Quantity_Registry.md — not as an abuse threshold. A bound doing one job must not be documented as doing two.

Alternatives Considered and Why Rejected

  • Pick a number now and tune it later. The default path, and the one this ADR exists to reject. The registry’s own rule says a permanently pending bound is operationally identical to no bound — but a wrong bound is worse than both, because it looks decided.
  • Rate-limit by behavioural signal instead of entitlement. Attractive and unfalsifiable at this stage: no traffic exists, so any signal would be invented. Available once there is data.
  • Treat all high-volume GMs as abusers. Breaks the customer the platform most wants.

Consequences (including the negative ones)

  • Two protections stay unimplemented for longer, and this ADR makes that a decision rather than an oversight. If the product model is slow, the exposure is real and is on this record.
  • It creates a dependency from an infrastructure quantity to a commercial decision, which is unusual and correct: the number genuinely cannot be derived from the architecture.

Enforcement

  • Quantity_Registry.md: Q-034 and Q-049 carry the blocker explicitly, so neither is set by someone who reads only the registry.
  • Release checklist: any quota presented as an abuse control names the dimension by which it separates abuse from use.

§11 Index Line

ADR-087: Q-034 and Q-049 stay pending and their blocker is the product's entitlement-tier model, not measurement — a quota bounding legitimate high volume and abuse with one number encodes a compromise in a constant nobody will later recognise as one. Existing per-account bounds continue to contain cost, which is what they were designed for; where a bound must exist first it is labelled a cost bound and not an abuse threshold.


ADR-088 — Privileged Actions Are Recorded; Authentication Design Is Out of Scope and Says So

Status: Accepted · Date: 2026-08-01 · Amends: 031

Context

R5-F-07: a GM account holds every secret of every campaign it runs, and the specification has no authentication section. FIDO2 appears exactly twice — once in §3’s tree as a library, once in §13’s roadmap as a thing to implement. MFA, account takeover, session hijack, impersonation and audit log are all zero. FIDO2 is a strong choice and is why the finding is 🔵 rather than 🟠, but recovery flows are where phishing-resistant systems are usually broken, and none is specified.

Decision

1. Authentication mechanism design is out of scope for this document, and the boundary is stated rather than left as an absence. A reader currently cannot tell whether authentication was considered and placed elsewhere or simply never addressed, and those are very different states. §13 owns delivery; the design belongs in a security specification this document names and does not contain.

2. Privileged account actions are recorded as domain events: export (including which channels were declassified, per ADR-084), erasure requests, membership changes when ADR-085’s model exists, and cartridge admission. This is in scope, is cheap, and reuses the event store the architecture already has.

3. The record is an audit trail, not a detection system, and the distinction is the one this corpus keeps having to restate: it makes a compromise investigable after the fact and stops nothing at the time. Claiming otherwise would repeat the “detection is not protection” error already recorded three times in this document’s history.

4. ADR-069’s semantics apply unchanged — these events record what happened with their inputs as evidence, and are never re-adjudicated.

Alternatives Considered and Why Rejected

  • Specify authentication here. Out of the document’s competence and scope; a half-specified auth design is worse than a named boundary, because it looks like a decision.
  • Log privileged actions to the diagnostic envelope (§10.4) instead. That envelope is sampled, capped and TTL’d by design (ADR-031), which is right for diagnostics and wrong for an audit trail — the retention properties are the opposite of what is needed.
  • Omit the audit trail until an incident demands it. An audit trail added after an incident cannot cover the incident.

Consequences (including the negative ones)

  • The audit trail is itself personal data about the acting principal, and is subject to ADR-078: it records an opaque SubjectId, never a name. It is also a retained class of data, so ADR-079’s rights-holder question applies to it — and the answer is that the acting principal can claim on it, which conflicts with an audit trail’s purpose. That tension is real and is not resolved here; it is named so that the retention decision is made deliberately.
  • Naming a document that does not exist creates a reference that will dangle until someone writes it. Recorded as preferable to an unexplained silence.

Enforcement

  • ArchitectureTests: the privileged-action event types exist and carry SubjectId rather than any personal attribute (ADR-078).
  • CI: an export, an erasure request and a cartridge admission each produce their audit event.
  • Release checklist: a new privileged action added to the product is added to the recorded set.

§11 Index Line

ADR-088: Authentication mechanism design is out of scope for this document and the boundary is stated rather than left as an absence. Privileged account actions — export with its declassified channels, erasure requests, membership changes, cartridge admission — are recorded as domain events carrying only a SubjectId. It is an audit trail, not a detection system, and the audit trail is itself retained data to which ADR-079's rights-holder question applies with an unresolved tension.


Section-level directive D-5.1 — Export accumulation is routine, not exceptional (R5-F-05)

Not an ADR. No architectural change is available, and the review said so: this is the limit every data-export feature has. What the finding adds over R4-F-06 is that the limit is routine rather than incidental — a GM exporting weekly holds a rolling copy, so every erasure is defeated by ordinary prudent behaviour rather than by an unlucky old file.

§7.6 already states the limit. It now also states that the accumulation is expected, so a player is told “your GM has a copy” rather than discovering it. ADR-084’s clause 4 turns out to help here: an export that records which channels it declassified makes the archive self-describing, which is the closest thing to visibility available.

Section-level directive D-5.2 — ADR-081’s guarantee is about the platform, not the participants (R5-F-06)

Not an ADR. ADR-081 is correct and narrow; the risk is that a narrow guarantee reads as a broad one — the same failure mode as R5-F-01, and as §7.3’s permanence claims before the axis was named. §9.4 now states the boundary where the guarantee is stated: the platform does not record, a participant running local capture is outside that guarantee, and the platform cannot detect it.