oficina / home Public

Re-review: two of my own fixes were false, including a reversal

The §14 step-up fix was wrong and is reversed. I claimed the roster
write's step-up was a different mechanism from §14's row — different
caller, different check. It is that row. The directory origin holds no
credential: §4 says it obtains its session by exchanging an assertion,
the same mechanism instances use, so its AuthTime comes from that
exchange and the only way a failed sessions.Fresh passes is a NEW
exchange in which the credential origin re-verifies rather than minting
from its standing session — a max_age-style parameter, which is exactly
what §14 describes. The doctrine says so outright ("home §14 names it;
this is its trigger") and A.1 asked to move the row. §5.2's
show-codes-once page really does sit behind a plain sessions.Fresh, but
that page is on the credential origin where the session was minted by
real authentication, and it does not transfer. The row moves to
built-when.

The §2 fix introduced two false clauses of its own. It widened
"directory" to "home", which is the exact conflation the doctrine's
ruling 13 exists to prevent and is false for the credential origin,
which can sign in as anyone and so reads individually granted items
too. And "until an owner notices" asserted a bound §13a denies four
screens later — a directory row and a notification are what honest code
leaves behind, and the owner's remedy runs back through the compromised
origin. The honest bound is the length of the compromise.

Ruling 15's ground moves off §2.2 entirely, having now failed twice.
Grounding it on the floor being "the instance's decision on its own
request path" was also false: authentication is the home's under ruling
1, the team is the home's under 17 and 23, and the home knows aud->team
through team_instances — so a per-team floor would be enforced at
assertion minting, on a resource the home owns, which the new line
permits. What actually blocks it is mechanical: passkey.Gate keys on
Enrolled(sess.Subject), per account with no team in scope, so a floor
needs a per-team policy record and per-team enrolment state slice one
does not have. §5.2 and §14's trigger are corrected to match, and §14's
"a sixth call" has been stale since call 6 existed.

§5.5 promoted from non-blocking and fixed: it still said an instance
decides capability entirely from its own grants, which is the status
quo ruling 23's own Rejected column names as overturned — and it is the
section Docs and Sheets build from. Per-item capability still comes
from the instance's grants; team standing now comes from its call-8
roster copy, so a member with no per-item grant reaches team-rung items.

§7's closing paragraph was still pre-23 in two places, asserting that a
person-to-resource entitlement is what §2.2 forbids and that the home
never forms an opinion about whether a person is entitled to anything.
Both now carry the qualifier the narrowing requires.

AGENTS.md: the falsifiable form gains "and which of them own it", the
boundary test gains roster_epoch's narrow exception (a builder
following it as written would reject a claim §5.3 puts on every
assertion), and the restore sentence gains the roster, which does not
rebuild either.

Also: the epoch exception scoped to the call-8 path per the doctrine's
revision 5, §10's recovery naming the operator verb that breaks its
circularity, and §1's blank line before the rule restored.

Reviewed by Fable 5.1; two passes, both CHANGES NEEDED.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PsPrUY5B4wtAZHGZJ3PJyS
Paul Campbell pushed by paul@keymail.dev 3de8f0b4eb9f210a5a041df4c4087ffd4038c41b parent b7249ba
2 files changed, +79 −31
  • AGENTS.md +17 −4
  • docs/superpowers/specs/2026-08-30-home-design.md +62 −27

CI passed — run details

Intent

Human

<task-notification> <task-id>a4d29f9ead14e710e</task-id> <tool-use-id>toolu_011Jfky4sZuhK5o7EG5672F9</tool-use-id> <output-file>/home/paulca/.cache/tmp/claude-1001/-home-paulca-amadan-net-oficina-home/d63f5ac7-6b42-48c5-a13d-34e6faf8e44c/tasks/a4d29f9ead14e710e.output</output-file> <status>completed</status> <summary>Agent "Fable re-review: suite-amendment" finished</summary> <note>A task-notification fires each time this agent stops with no live background children of its own. The user can send it another message and resume it, so the same task-id may notify more than once.</note> <result>**VERDICT: CHANGES NEEDED** All seven blocking fixes landed as described, and the non-blocking ones too (seed verb, per-team epoch + 404, gate 10, Rejected column, AGENTS.md rules 2 and 3, §6's directions — call 7 home→instance, call 8 instance→home, now correct). Verified at `/home/paulca/amadan.net/oficina/home/.claude/worktrees/suite-amendment/docs/superpowers/specs/2026-08-30-home-design.md` against `2b68301` and the doctrine. But two of the fixes introduced new false claims, and ruling 23 falsifies more sentences than either commit reached. ## Blocking **1. The roster step-up is not a "different mechanism" from §14's row — it is that row.** (§10 line 996, §14 line 1383.) The directory origin holds no credential; §4 says it "obtains its session by exchanging an assertion, the same mechanism instances use". So its session's `AuthTime` is set by the exchange, and when `sessions.Fresh` fails the only way to make it pass is a new exchange in which the credential origin *forces re-verification* rather than minting from its standing session. rastrillo v0.22.0 says exactly this in `RequireFresh`'s doc (`/home/paulca/go/pkg/mod/github.com/carlosframework/rastrillo@v0.22.0/sessions/sessions.go:334-345`): a stale session "redirects to SigninPath with return_to plus reauth=1 … re-verifying calls SignIn, which rotates the session with a fresh AuthTime". At the directory origin, SigninPath is the assertion exchange and `reauth=1` is the `max_age`-style parameter. Same mechanism, different caller. The doctrine says so in §5.4 ("home §14 names it; this is its trigger") and A.1 ("In §14 move *step-up for instances* to built-when: *roster writes*"), in both rev 4 and rev 5. The branch does the opposite and records no divergence — under doctrine §10 that is a bug in the app spec. Fix: take A.1 as written, sequence the round trip with the roster, name the credential origin's reauth parameter, and delete "different caller, different mechanism" in §10 and §14. (§3.2's `sessions.Fresh` citation is correct for the show-codes-once page — that page is at the credential origin, where the session was minted by real authentication. It does not transfer.) **2. The §2 blast-radius sentence (lines 167-176) has two false clauses.** (a) "a compromised **home** costs … It still costs no *per-item* grant" — widening *directory* to *home* is the precise error the doctrine's ruling 13 Rejected column names, and it is false for the credential-origin tier, which §13a says "can sign in as anyone" and therefore reads every individually granted item as that person. The clause must say *directory origin*. (b) "until an owner notices" asserts a bound §13a itself denies four screens later ("neither does a directory row or a notification: those are what honest code leaves behind"). The owner's only remedy runs through the compromised origin. The honest bound is the duration of the compromise. **3. §5.5 — promote from non-blocking.** "decides capability **entirely from its own grants** … a person with no grant … gets nothing" (lines 601-604). Ruling 23's own Rejected column names "§5.5 … as they stood" as the overturned status quo, and §5.5 stands untouched. It is the instance-side section Docs and Sheets build from; as written a suite instance ignores call 8. Two sentences: team standing from the call-8 copy (suite ruling 5, §5.3), per-item from its own grants; a member with no grant reaches team-rung items. **4. §7's closing paragraph is still pre-23.** Line 754: "the home holding a person↔resource entitlement **is** what §2.2 forbids" (present tense — the roster is one). Lines 810-812: "It never forms an opinion about whether a person is entitled to anything" — contradicts the paragraph twelve lines above it ("Ruling 23 forms one deliberately … holds and enforces"). **5. AGENTS.md disagrees with the spec at the headline, and its own rule is "fix it in the same commit".** `/home/paulca/amadan.net/oficina/home/.claude/worktrees/suite-amendment/AGENTS.md`: the falsifiable form (lines 31-34) still reads "that some person belongs to a particular set of them" — spec §0 now says "which people belong to which team, and which of them own it", and the owner class is the whole cost of ruling 23. The boundary test (lines 129-136) states (a) closed-set with no `roster_epoch` exception — a builder following it rejects a claim §5.3 puts on every assertion. Line 316 "loses credentials, which do not rebuild" omits the roster (§10). Rules 2 and 3 are fine. **6. Ruling 15's restated ground does not hold — this is where the resources-we-own / instance's-items line leaks.** §2.2 lines 243-246: "a policy the home would have to enforce **on an instance's behalf** … which is the instance's decision on its own request path." Authentication is the home's (ruling 1: one RP), the team is the home's (17, 23), and the home knows `aud`→team via `team_instances`, so a per-team 2FA floor is enforced at assertion minting — a policy on a *resource the home owns*, which the new line permits. An instance demands nothing at authentication; it exchanges an assertion. Consequently §5.2's "a home-side policy contradicts §2.2" and §14's "argued past §2.2" are now false. Ruling 15's *outcome* stands on mechanics — `Gate` is `Enrolled(sess.Subject)`, per-account, and slice scope — so re-ground it there rather than on §2.2. (§14's "a sixth call" has been stale since call 6 existed.) The line holds everywhere else I pressed it: the §2.2 roster bullet, both §7 paths, ruling 19's narrowing, §6. ## Non-blocking — status confirmed, with sharpening - **§10 recovery circularity stays non-blocking**, but say the mechanism: no call carries an instance's roster copy *to* the home (8 is a pull), so "the instances' own copies" means an operator reads them out and re-seeds via §10's operator verb; after a total loss the "owner's confirmation" presupposes an owner the home no longer knows, and the seed verb is the break. Same wording is in doctrine §5.3 — file it there too. - **§13 sequencing stays non-blocking.** The roster (table, seed verb, owner write + step-up, call 8) has no step; doctrine §12 step 4 puts it on top of home step 4. "Step 4 must land before either ships" gains a second reason in suite shape (ruling 5); lone shape is unaffected (suite §12). - **Doctrine is now revision 5** (`d55fa15`, on `origin/main` after `210312f`). Citing rev 4 is explicitly allowed by gate 9's one-revision grace and the rev-5 status says the home's citation "is correct as it stands". One rev-5 change touches the home: §5.3 scopes the epoch exception to the call-8 path and says a call-7-answering instance must not act on the claim. §5.4 should carry that scope when next touched. - **Roster add writes directory rows** (doctrine §5.4: "announces them to every `team_instances` row's directory entry"). Home §6/§9/§10 have call 2 as the only directory writer. Unstated for the home builder; removal's effect on those rows is unstated in both documents. - Editorial: ruling 23's Rejected column repeats "which the doctrine's own first revision proposed"; §1's blank line before `---` was removed (restore it — main had it); §10's memberships paragraph splits "by a team owner … or seeded by the drain" across a five-line parenthetical (reflow with fix 1); §2 line 157 "the federation story §3 refuses" — §3 refuses nothing and "federation" is retired vocabulary (pre-existing on main). Fixes 2, 3, 4 and 5 are a few sentences each. Fix 1 is a ruling-consistent reversal of last round's change and should be recorded as such. Fix 6 changes a ground, not an outcome.</result> <usage><subagent_tokens>156065</subagent_tokens><tool_uses>18</tool_uses><duration_ms>373830</duration_ms></usage> </task-notification>

Attributed to this commit: 79.2 g CO₂e (10286404 tokens). This is an attribution, not a measurement — usage counted from this commit's own marker forward to the next one on suite-amendment, never backward from it. A turn that produced more than one commit books all of its tokens to the last one, and a concurrent session on this branch can add to the same figure. Some of it was priced using the shared default rate, because no model-specific factor row exists yet for at least one model involved. The Carbon view has the repo total, which is never derived from this attribution.

diff --git a/AGENTS.md b/AGENTS.md
index 6c6e2e2..fb1ca99 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -29,9 +29,14 @@ XI's category label, not a claim it never sees one. Spec §0 carries the full
gloss.
The falsifiable form: **publish this database in full and the worst anyone
-learns is how many people exist, what their teams are called, and that some
-person belongs to a particular set of them.** No document. No cell. No
-readable address.
+learns is how many people exist, what their teams are called, which person
+refs belong to which team, and which of them own it.** No document. No cell.
+No readable address.
+
+**"And which of them own it" arrived with ruling 23** and is the whole cost
+of the membership roster: an owner row names a person ref from one team plus
+a fact that is usually public, where the old wording needed several teams
+and an outside fact. Spec §0 and §3.3 carry the full reasoning.
*Two absolutes were argued and lost, and stay lost:* **"never stores your
address"** — a magic link's address is at rest between send and click,
@@ -194,6 +199,14 @@ quietly ignored).
be cosmetically failable.** The subject flagrantly fails (a) — a hostile
subject is account takeover — so the test must exempt identity by
construction or it proves too much and gets argued around.
+
+ **One narrow exception, added 2026-09-05 with ruling 23: `roster_epoch`.**
+ It is not a closed enumerated set and does not fail cosmetically, so it
+ would fail test (a) as written. What admits it is that **the instance
+ decides nothing from it** — an unparseable value is ignored, a differing
+ value buys exactly one call-8 refetch, and call 8's answer is what is
+ enforced. A builder following the test without this exception rejects a
+ claim §5.3 now puts on every assertion. Spec §5.4 carries the reasoning.
- **Any "prune when all consumers have caught up" is unbounded in a
hibernating fleet.** A dormant instance runs no timers to advance its
cursor. Retention is a fixed horizon or a per-consumer TTL, never a
@@ -313,7 +326,7 @@ quietly ignored).
cold-wake latency is a suite-wide outage. Stated because hibernation is
the platform default and would otherwise apply silently.
- **A backup you have never restored is a hope, not a backup.** Losing this
- database loses credentials, which do not rebuild. The restore drill runs
+ database loses credentials **and the roster**, neither of which rebuilds — call 2 cannot write membership and no channel carries an instance's copy back, so roster recovery is an operator reading instances out and re-seeding (spec §10). The restore drill runs
before launch.
---
diff --git a/docs/superpowers/specs/2026-08-30-home-design.md b/docs/superpowers/specs/2026-08-30-home-design.md
index a0fa582..8fb9cc6 100644
--- a/docs/superpowers/specs/2026-08-30-home-design.md
+++ b/docs/superpowers/specs/2026-08-30-home-design.md
@@ -130,6 +130,7 @@ blind, replaceable*.
| 21 | **§11's zero-JS rule gains one named carve-out: passkey enrolment and ceremony screens may load script. Everything else stays scriptless** — §11 | Passkeys leaving slice one; a blanket exemption; a progressive-enhancement version, since the ceremony itself cannot happen without script either way | Paul, 2026-09-05 |
| 22 | **The team selection is navigation state, not session state: `?team=<sqid>` on every team view, with `/` a generic entry that picks a team and `302`s to the explicit URL** — §11 | A session cookie (history does not restore one, so Back has no correct behaviour; and a shared cookie couples every same-origin team-dependent request across tabs, not just New); a URL fragment read by CSS `:target` (the server never learns the team, so nothing server-rendered can be team-scoped — not the grid, not the switcher's `aria-current`, not gate 4's 404); a `prefs` row (§14) | Paul, 2026-09-05, after a second opinion from **GPT-6 Astra via Codex** (its default; `gpt-5.3-codex` and `gpt-5.3-sol` were both refused by the account, so the model is named from Codex's own rollout record rather than from what was asked for) |
| 23 | **The suite sharing doctrine (`oficina/suite`) binds this spec, and membership becomes a record of the home's own.** The team is the boundary; the home owns identity, the team and the membership roster; it never owns a per-item grant. `(team, person, role)` is written only at the directory origin by an owner behind step-up, or seeded by the drain with the team's first owner. A directory row never grants team standing. Call 8, roster pull, is added to §9. | **The status quo this overturns: team standing living only in each instance's grants, with the home holding no roster at all** (§5.5, §7 as they stood). And the doctrine's own first revision, which derived the roster from call-2 directory rows, which the doctrine's own first revision proposed: the row has no owner role (§6 — `kind` is member or guest), §7 says the home never learns who an owner is, the row is scoped per (team, app) where the roster is per team, and any instance can write one under its consumer token — so deriving from it routes around the step-up entirely | Paul, 2026-09-05 (suite ruling 12). Numbered 23 because the doctrine's appendix said "add ruling 22" and 22 was already taken; a review of the doctrine caught the collision |
+
---
## 2. What the home is
@@ -168,12 +169,17 @@ aspirational:
and **every instance re-checks authorization on every request** (§6), so a
compromised directory grants nothing **of an instance's own**. **Ruling 23
changed the rest of this sentence and it is amended rather than
- annotated.** A compromised directory origin can now write the roster, and a
- member reads everything team-visible in every instance of that team — so a
- compromised home costs the graph, a convenience outage, **and, until an
- owner notices, team-visible content across a team's apps.** It still costs
- no *per-item* grant, which is the thing the home does not hold. §13a sets
- out the full radius; this bullet no longer contradicts it.
+ annotated.** A compromised **directory origin** can write the roster, and a
+ member reads everything team-visible in every instance of that team — so it
+ costs the graph, a convenience outage, **and team-visible content across a
+ team's apps for as long as the compromise lasts.** Not "until an owner
+ notices": §13a is explicit that a directory row and a notification are
+ "what honest code leaves behind", and the owner's only remedy runs back
+ through the compromised origin. It still costs no *per-item* grant, which
+ is the thing the home does not hold. **The credential origin is a
+ different and worse tier** — §13a: it "can sign in as anyone", and so reads
+ individually granted items too — and this bullet is about the directory,
+ which is the distinction the doctrine's ruling 13 exists to keep.
- **It holds no content *at rest*.** The worst case in a published database
is §3's leak list, never anyone's work. **Since the 2026-09-05 amendment a
live compromise is larger**: the activity cache holds recent titles in RAM
@@ -235,16 +241,26 @@ Each is something somebody will propose in good faith.
document a guest may comment on: all instance-side, decided there on every
request (§5.5).
- **Ruling 15's ground has to be restated, not carried over.** It read
- "ruling 15 exists because the per-team 2FA floor would have breached
- this", against the old clause *never holds an authorization model*. A
- per-team 2FA floor is not a per-item grant, so under the new clause that
- sentence is simply false. The objection that survives is narrower and
- still holds: **a 2FA floor is a policy the home would have to enforce on
- an instance's behalf, at sign-in, for a team.** The roster says who is on
- a team; a floor says what an instance must demand of them, which is the
- instance's decision on its own request path. §5.2 and §14's trigger say
- "argued past §2.2" and mean this bullet, not the deleted one.
+ **Ruling 15's ground has to move off §2.2 entirely, and two drafts of
+ this paragraph failed to.** It first read "ruling 15 exists because the
+ per-team 2FA floor would have breached this", against the old clause
+ *never holds an authorization model* — false under the new one, since a
+ 2FA floor is not a per-item grant. It was then re-grounded on the floor
+ being "the instance's decision on its own request path", which is also
+ false: authentication is the home's (ruling 1, one RP), the team is the
+ home's (rulings 17 and 23), and the home knows `aud` → team through
+ `team_instances` — so a per-team floor would be enforced at assertion
+ minting, on a resource the home owns, which this bullet's own line
+ *permits*. An instance demands nothing at authentication; it exchanges an
+ assertion.
+
+ **So ruling 15 stands on mechanics, not on §2.2.** `passkey.Gate` keys on
+ `Enrolled(sess.Subject)` — per account, with no team in scope — and
+ building a per-team floor means a per-team policy record and a per-team
+ enrolment state that slice one does not have. That is the objection, and
+ it is the one §14's row should carry. **§5.2's "a home-side policy
+ contradicts §2.2" and §14's "argued past §2.2" are now false and are
+ corrected there.**
**It does hold the membership roster** (suite ruling 4, ruling 23). "Is
this person on this team" is a fact about the home's own records. "May
@@ -492,7 +508,7 @@ Passkey via `passkey.Handlers.Gate`, **optional per person**.
**Per-team enforcement is not in slice one** (ruling 15). The first draft
promised it and neither spec could build it: no call carried a team's
policy, `Gate` is strictly per-account (`Enrolled(sess.Subject)`), and every
-workaround breached something — a home-side policy contradicts §2.2, and an
+workaround breached something — a home-side per-team policy needs a per-team policy record and per-team enrolment state slice one does not have (ruling 15, re-grounded 2026-09-05 — it was §2.2 until ruling 23 rewrote that clause), and an
`amr` claim on the assertion fails §5.4's boundary test. It moves to §14
with a trigger, rather than being discovered by the first paying team that
flips the switch.
@@ -566,7 +582,7 @@ Two-sided, and the first draft wrote only the half it needed for theme
> (b)** the home already holds it for its own purposes, so carrying it adds
> nothing to what the home knows.
-**One narrow exception, added 2026-09-05: an invalidation hint.** The roster
+**One narrow exception, added 2026-09-05: an invalidation hint.** (Scoped, per the doctrine's revision 5, to the **call-8 path only** — an instance answering call 7 must not act on the claim at all.) The roster
epoch (suite §5.3) rides the assertion and fails (a) as written — a
monotonically rising integer is not a closed enumerated set and does not
fail cosmetically. It is admissible on a different argument, and the
@@ -599,9 +615,16 @@ theme interpolated into CSS is an injection, not an ugly page.
### 5.5 What the instance does with it
Verifies the signature by `kid`, checks `aud` is itself, consumes the `jti`
-locally, mints a session — and then **decides capability entirely from its
-own grants**. An assertion for a person with no grant is a valid assertion
-that gets nothing.
+locally, mints a session — and then **decides capability from two sources,
+since ruling 23**. **Per-item** capability comes entirely from its own
+grants, exactly as before: an assertion for a person with no grant is a
+valid assertion that gets nothing individually granted. **Team standing**
+comes from its copy of the roster (call 8, suite ruling 5), not from a
+grant — so a member with no per-item grant still reaches everything at the
+team rung, which is the point of a team. An earlier version of this
+paragraph said capability came *entirely* from the instance's own grants;
+that is the status quo ruling 23's Rejected column names as overturned, and
+Docs and Sheets build from this section.
**The link-share ordering problem** (docs-e6, 2026-08-30). A link-share
visitor who wants to comment signs in — and under the attribution rule,
@@ -751,7 +774,7 @@ the model calls it.
answers it.** The first claim of a free label is a decision about a resource
alone: is this label taken? The *second* instance is the hard one, because
"only Acme may create `acme.sheets`" needs a principal, and the home holding
-a person↔resource entitlement is what §2.2 forbids and ruling 9 refuses
+a person↔resource entitlement **over an instance's items** is what §2.2 forbids and ruling 9 refuses (ruling 23 has the home hold exactly such an entitlement over a resource of its own, the roster — that is the narrowing, and it is why this sentence now carries the qualifier)
("*where might I have things*, never *may I have this*"). An earlier draft
argued this away as "a name, not a document". **That argument is wrong and
is recorded here so it is not made again:** §2.2 says *never holds an
@@ -809,7 +832,7 @@ discovered; §2's blast-radius argument survives it.
So the home's whole vocabulary here is two facts: *is this label free*, and
*is this calling origin already an instance of this team*. It never forms an
-opinion about whether a person is entitled to anything. That is the
+opinion about whether a person is entitled to anything **in an instance**. Since ruling 23 it does form one about team standing, which is its own record; the paths here form none of either. That is the
distinction ruling 19 rests on, and it is a narrower one than "names versus
documents".
@@ -993,7 +1016,19 @@ Migrations additive-only.
**`memberships`** — `(team, person_ref, role)`, role being `owner` or
`member`, added by ruling 23. Written **only** at the directory origin, by a
-team owner, behind a fresh-assertion step-up at the directory origin — `sessions.Fresh` (§3.2), the same freshness check §5.2's show-codes-once page sits behind, over the assertion exchange of §4. **Not §14's "step-up for instances" row**, which is a different mechanism for a different caller and is still listed there as not built, or seeded by the drain
+team owner, behind a **fresh-assertion step-up — which is §14's row, now triggered**.
+An earlier pass of this branch claimed it was a different mechanism for a
+different caller; that was wrong and is reversed here. The directory origin
+holds no credential (§4: it "obtains its session by exchanging an assertion,
+the same mechanism instances use"), so its session's `AuthTime` comes from
+that exchange, and the only way to make a failed `sessions.Fresh` pass is a
+**new exchange in which the credential origin re-verifies** rather than
+minting from its standing session — a `max_age`-style parameter on the
+exchange, which is exactly what §14 describes. (§5.2's show-codes-once page
+does sit behind a plain `sessions.Fresh`, but that page is on the credential
+origin, where the session was minted by real authentication. It does not
+transfer.) The doctrine agrees: §5.4 says "home §14 names it; this is its
+trigger", or seeded by the drain
with the team's first owner from the sealed queue payload §7 already
carries. That bootstrap exists because gating a membership write on an owner
needs an owner to exist first, and the circularity has to break outside the
@@ -1014,7 +1049,7 @@ about guests changes.
The directory rebuilds as instances re-upsert; passkeys do not. **The
membership record does not rebuild either**, and that is new with ruling 23:
call 2 cannot write it, and no channel reaches a hibernating instance to ask
-for it. Recovery is the instances' own copies plus an owner's confirmation
+for it. Recovery is the instances' own copies plus an owner's confirmation — and the mechanism is worth naming, because "the instances' copies" is not a channel: no call carries a roster *to* the home (call 8 is a pull), so it means **an operator reading an instance's copy out by hand and re-seeding through §7's operator verb**. After a total loss the confirming owner cannot be one the home knows, so the seed verb is what breaks that circularity too
at the directory origin, or it is re-entry by hand.
**A restore mints a new roster generation.** Refusing an epoch lower than
@@ -1374,13 +1409,13 @@ identity authority. That filing belongs at `carlos/pegamento`.
| Thing | Trigger |
|---|---|
-| **Owner-enforceable per-team 2FA** (ruling 15) | A team asks, *and* either a sixth call carrying team policy is argued past §2.2 or rastrillo grows a per-team notion |
+| **Owner-enforceable per-team 2FA** (ruling 15) | A team asks, *and* either a call carrying team policy is built — `passkey.Gate` keys on `Enrolled(sess.Subject)`, per account, so this needs a per-team policy record and per-team enrolment state — or rastrillo grows a per-team notion. **Not "argued past §2.2"**: ruling 23 rewrote that clause, and the objection is mechanical rather than doctrinal |
| Pegamento's vault facet — team names the home cannot read | The vault ships with a recovery story |
| Operator reset for a fully locked-out person | The first person loses passkey and codes together |
| Auto-drain of the queue | The platform ships a machine credential, **and** we choose to give up the abuse gate, **and** ruling 19's fallback adjudication is automated — three decisions. A machine credential supplies no judgement about who may take a reserved name (§7) |
| **Suite-wide sign-out / session revocation** | Named as an exposure now: a stolen laptop's instance sessions live to their TTL with no revocation channel. Trigger: the first report, or before any team holds regulated data |
| **Account deletion / erasure** | Before a person asks, which under most regimes is not optional for long |
-| **Step-up for instances** (`RequireFresh`-grade) | An instance flow needs it; requires a fresh-assertion round trip with a `max_age`-style parameter. **Not the roster write's step-up** (ruling 23), which is the *directory origin's own* `sessions.Fresh` check and is built with the roster — different caller, different mechanism |
+| ~~**Step-up for instances**~~ (`RequireFresh`-grade) | **Triggered 2026-09-05 by ruling 23: roster writes need it** (doctrine §5.4, A.1). It is built with the roster — a fresh-assertion round trip with a `max_age`-style parameter, requested by the directory origin and honoured by the credential origin. The caller differs from the instance flow this row first imagined; the mechanism does not |
| Any preference beyond theme | It passes §5.4 |
| Billing, plans, quotas | Somebody has to pay |
| **Mail and Files behind suite SSO** | Keymail or Slopbox verifies assertions per §5.3 in its own repository. Until then they are `integrated: false` registry entries rendered as outbound links (§11, ruling 17) |