Decide: the event sheet's editability vs ADR-0036's authority split #257

Closed
opened 2026-08-25 22:19:12 +00:00 by nalum · 2 comments
Owner

The updated calendar handoff (design_handoff_calendar, now carrying the locked calendar-demo.dc.html) and the server model delivered in PRs #205 and #209 (ADR-0036) disagree about who may edit an event. Two gaps, one decided and one needing a ruling. Blocks #193 and touches #196.

1. An event with no attendees — decided by the design, server change needed

The handoff is explicit, twice (§7's note and two acceptance-checklist items):

An event with no attendees is household-owned: any member may edit and delete it. Attendance is not a permission — a Birthday and a Holiday have no attendees by definition and must never become uneditable, and Save nobody going must never lock an event.

The demo implements it: editable = ownerless || member.

The server does the opposite. RequireEventOwner denies any non-admin on an event with no refs — pinned by the empty member list denies non-admin case in internal/services/svc/authz_test.go — and ADR-0036 records the ownerless materialised child row as "editable only by an admin", as an accepted trade-off. Under the locked design that trade-off is no longer accepted.

Change: admit any household member (not Guest) when the event carries no OWNER ref; amend ADR-0036; integration coverage for the two checklist cases (a member edits a Birthday; Save nobody going followed by another member's edit).

2. Does joining make you an editor? — needs a ruling

§0.1 still says "after joining, the sheet becomes §5.1's editor with no reload and no second tap", and the demo gates editability on presence (member). But PR #205/#209 deliberately split attendance from authority: a self-add writes an ATTENDEE ref, and Update, Delete and the occurrence verbs require an OWNER ref — precisely so that joining somebody's appointment does not hand out the power to move or cancel it (the escalation #201 named and closed).

Both cannot ship. Either:

  • A. The handoff wins — joining grants editing. The ATTENDEE relation loses its point and #201's escalation reopens: any household member is one I'm going away from being able to move or delete any event.
  • B. The split wins, and §0.1's sentence is amended — after joining, the sheet keeps its no-chevron shape with the primary now Leave this one (asking scope on a repeating event); only OWNER refs get the editor. Clients gate on the relation type they hold, not on presence.

Recommendation: B. The escalation argument is the reason the relation exists, and it is the same shape as the jobs bundle's law 5 — fewer permissions mean fewer rows.

Whichever way it goes, it amends ADR-0036, and either the handoff/demo or the guard moves in the same change.


Ruled (2026-08-25)

  1. Ownerless events stay admin-only editable. The handoff's household-owned rule is not taken. Instead the state is prevented from arising: the last attendee may not leave an event — leaving it means deleting it. RemoveUser and LeaveOccurrence refuse a removal that would leave the member list empty (FailedPrecondition, naming the way out: delete it instead), and any other path that can empty the list gets the same guard — including Update if it can rewrite users, and the Who picker's Save nobody going commit, which under this ruling must either keep the last person or disappear. Events created with no attendees (a Birthday, a Holiday) remain admin-only editable, as today.
  2. Joining does not grant edit rights. The ADR-0036 attendance/authority split stands as PRs #205/#209 built it: a self-add writes an ATTENDEE ref, editing needs an OWNER ref. §0.1's "the sheet becomes the editor" sentence is the part of the handoff that moves.

The design project updates the handoff and the demo to match (the checklist's "an event with no attendees is household-owned" and "Save nobody going must never lock an event" items both flip; the demo's editable = ownerless || member gate becomes an owner-ref check and the last-attendee leave refusal appears). The bundle gets revalidated against this issue before the client work (#193/#196) starts.

Remaining server work here: the last-attendee guard on RemoveUser/LeaveOccurrence (and any users-emptying path), the ADR-0036 amendment recording both rulings, and integration coverage — the last owner refused, the refusal wording, and delete still open to them.

The updated calendar handoff (`design_handoff_calendar`, now carrying the locked `calendar-demo.dc.html`) and the server model delivered in PRs #205 and #209 (ADR-0036) disagree about who may edit an event. Two gaps, one decided and one needing a ruling. Blocks #193 and touches #196. ## 1. An event with no attendees — decided by the design, server change needed The handoff is explicit, twice (§7's note and two acceptance-checklist items): > An event with no attendees is household-owned: any member may edit and delete it. Attendance is not a permission — a Birthday and a Holiday have no attendees by definition and must never become uneditable, and *Save nobody going* must never lock an event. The demo implements it: `editable = ownerless || member`. The server does the opposite. `RequireEventOwner` denies any non-admin on an event with no refs — pinned by the `empty member list denies non-admin` case in `internal/services/svc/authz_test.go` — and ADR-0036 records the ownerless materialised child row as "editable only by an admin", as an accepted trade-off. Under the locked design that trade-off is no longer accepted. Change: admit any household member (not Guest) when the event carries no OWNER ref; amend ADR-0036; integration coverage for the two checklist cases (a member edits a Birthday; *Save nobody going* followed by another member's edit). ## 2. Does joining make you an editor? — needs a ruling §0.1 still says "after joining, the sheet becomes §5.1's editor with no reload and no second tap", and the demo gates editability on presence (`member`). But PR #205/#209 deliberately split attendance from authority: a self-add writes an ATTENDEE ref, and `Update`, `Delete` and the occurrence verbs require an OWNER ref — precisely so that joining somebody's appointment does not hand out the power to move or cancel it (the escalation #201 named and closed). Both cannot ship. Either: - **A. The handoff wins** — joining grants editing. The ATTENDEE relation loses its point and #201's escalation reopens: any household member is one `I'm going` away from being able to move or delete any event. - **B. The split wins, and §0.1's sentence is amended** — after joining, the sheet keeps its no-chevron shape with the primary now `Leave this one` (asking scope on a repeating event); only OWNER refs get the editor. Clients gate on the relation type they hold, not on presence. Recommendation: **B**. The escalation argument is the reason the relation exists, and it is the same shape as the jobs bundle's law 5 — fewer permissions mean fewer rows. Whichever way it goes, it amends ADR-0036, and either the handoff/demo or the guard moves in the same change. --- ## Ruled (2026-08-25) 1. **Ownerless events stay admin-only editable.** The handoff's household-owned rule is not taken. Instead the state is prevented from arising: **the last attendee may not leave an event — leaving it means deleting it.** `RemoveUser` and `LeaveOccurrence` refuse a removal that would leave the member list empty (`FailedPrecondition`, naming the way out: delete it instead), and any other path that can empty the list gets the same guard — including `Update` if it can rewrite `users`, and the Who picker's *Save nobody going* commit, which under this ruling must either keep the last person or disappear. Events created with no attendees (a Birthday, a Holiday) remain admin-only editable, as today. 2. **Joining does not grant edit rights.** The ADR-0036 attendance/authority split stands as PRs #205/#209 built it: a self-add writes an ATTENDEE ref, editing needs an OWNER ref. §0.1's "the sheet becomes the editor" sentence is the part of the handoff that moves. The design project updates the handoff and the demo to match (the checklist's "an event with no attendees is household-owned" and "*Save nobody going* must never lock an event" items both flip; the demo's `editable = ownerless || member` gate becomes an owner-ref check and the last-attendee leave refusal appears). The bundle gets revalidated against this issue before the client work (#193/#196) starts. Remaining server work here: the last-attendee guard on `RemoveUser`/`LeaveOccurrence` (and any users-emptying path), the ADR-0036 amendment recording both rulings, and integration coverage — the last owner refused, the refusal wording, and delete still open to them.
Author
Owner

Delivered in PR #258 per the two rulings: an event keeps at least one person (RemoveUser, LeaveOccurrence and Update's guest-list rewrite all refuse to take the last one off — code LAST_MEMBER, "to take the last one off, delete the event"), ownerless events stay admin-only editable, and joining still grants no edit rights. ADR-0036 carries the amendment. The clients gate the affordance at the control in PR #263 (the sheet's sole-person footnote replaces the Leave row).

Delivered in PR #258 per the two rulings: an event keeps at least one person (RemoveUser, LeaveOccurrence and Update's guest-list rewrite all refuse to take the last one off — code LAST_MEMBER, "to take the last one off, delete the event"), ownerless events stay admin-only editable, and joining still grants no edit rights. ADR-0036 carries the amendment. The clients gate the affordance at the control in PR #263 (the sheet's sole-person footnote replaces the Leave row).
Author
Owner

Ruled and implemented in merged PR #258: an event keeps at least one person (LAST_MEMBER refusal on RemoveUser/LeaveOccurrence/Update rewrite), ownerless events stay admin-only, joining grants no edit rights. ADR-0036 carries the amendment.

Ruled and implemented in merged PR #258: an event keeps at least one person (LAST_MEMBER refusal on RemoveUser/LeaveOccurrence/Update rewrite), ownerless events stay admin-only, joining grants no edit rights. ADR-0036 carries the amendment.
nalum closed this issue 2026-08-26 18:48:04 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
eagraiclainne/app#257
No description provided.