Skip to content

ADR-0092 D1's tier table still records Tier 1 as {name, image} — the 2026-09-03 ruling made the shipped set {name, image, locale} #14951

Description

@os-sales

Found while implementing #14787. Filed rather than fixed in that PR, because docs/adr/** is a governed surface (Prime Directive #14): including the amendment there would fork an ordinary contract-review PR into governance territory, and the prescribed handling for a mixed diff is to split the governed files into their own PR.

The drift

Maintainer ruling 2026-09-03 on #14787 (option B, adopted 「同意」) widened the ADR-0092 D2 self-service whitelist:

The identity table's user-writable set grows from two fields to three […] SYS_USER_PROFILE_EDIT_FIELDS becomes {name, image, locale}

The code now says exactly that. ADR-0092 does not. Three places in docs/adr/0092-sys-user-profile-field-delegation.md still state the two-field set as the decision:

  • the TL;DR bullet for D1 — "only name and image are profile-editable through the generic path";
  • the D1 tier table itself — "Tier 1: profile-editable" lists name and image and nothing else;
  • the D2 bullet and its Behaviour section — "sys_user → {name, image} is its first entry" / "First and only entry shipped by this ADR".

docs/adr/0105-group-tenancy-posture-and-first-class-org-scope.md repeats the two-field spelling in passing as well.

Why this is not just a stale sentence

Prime Directive #13: an accepted ADR binds until a superseding ADR says otherwise, and reversing a recorded decision is itself a decision that needs a new ADR or an amended status line — not a changeset that quietly does the opposite. A reader who reaches ADR-0092 first will read the two-field set as the governing decision and the third field as drift to be corrected, which is backwards. The ruling is the newer decision; the ADR is the older one and has to say so.

There is one wrinkle worth deciding rather than assuming. ADR-0092's own scope note says:

the decision about which fields open up is sys_user-specific (D1); the mechanism (D2) is family-wide by construction. A future "org admins may edit sys_organization.name" is a one-line whitelist registration citing this ADR, not a new ADR.

That anticipates new object registrations as ordinary work. It does not obviously cover changing D1's own tier table for sys_user, which is the decision text rather than an example. So the amendment route is a judgement call for the maintainer: an amended status line plus a D1 revision, or a small superseding ADR.

What the amendment should record

  • Tier 1 becomes {name, image, locale}, dated, citing the ruling.
  • locale has no auth semantics — it is not a login key, not authorization state, and better-auth is oblivious to it — which is the same reasoning that put name and image in Tier 1.
  • The D6 session-snapshot mirror deliberately did not widen with it: better-auth carries no locale on its user model, so there is no cached copy to keep coherent and mirroring one would manufacture an incoherence. That is now a separate named constant in identity-write-guard.ts, and the ADR's D6 text should say the two sets are no longer the same set.
  • D5 is unchanged and is worth restating, because it is where readers of this ADR will look next: the whitelist decides which columns, permission sets decide who, and member_default still denies allowEdit on sys_user. Whether an ordinary member gets a self-service route to their own locale is a further decision that [Decision] May a user set their own sys_user.locale? — the ADR-0092 D2 self-service whitelist stays {name, image} after #13881 (column lands readonly, system-context writes only) #14787's ruling did not take.

Not urgent, but not cosmetic

Nothing is broken at runtime; the enforcement and the pins are correct and shipped. The cost is that the governing document disagrees with the governed code, which is the condition under which a later PR "restores" the old behaviour in good faith.

Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions