Calendar: the repeat sheet — the shared editor with the event-only additions #195

Closed
opened 2026-08-23 22:54:06 +00:00 by nalum · 2 comments
Owner

Part of the calendar redesign. The design handoff (design_handoff_calendar, held outside the repo) is the source; the facts it depends on are repeated here so this issue stands alone.

The jobs repeat sheet, reused: chips phrased from the event's own date, a sentence builder under or set it up that the chips fill in, a readback at the bottom, and a commit button that states the rule rather than saying Done.

Three additions, all of them the shared editor gating by record type rather than a second editor:

  • A multi-select weekday strip. EventRepeat.weekdays is a set, so Monday, Wednesday and Friday swimming is one event. The jobs handoff bans the strip because ItemRepeat.weekday is a single int — that is a job-rule ban, not a deletion from the editor.
  • One trap: MONTHLY_ON_NTH_WEEKDAY reads only the first entry (internal/domain/event.go:198) and validation accepts extras without complaint (:114 requires at least one, not exactly one). The strip must collapse to single-select the moment that kind is chosen, or the app silently drops days the reader picked.
  • An Until row, reading Keeps going when unset. A job's rule has no end date; an event's does, and it is inclusive — an occurrence on the until day still happens. It cuts occurrence starts only, so a span that begins before it still runs past it.
  • A yearly chip (Every 25 August), which is also what Birthday seeds.

The readback names two dates for a multi-day rule: "Tuesdays and Thursdays" cannot be checked against one.

Repeats? No | Yes in front of a chip row that already contains No is one decision asked twice; it goes.

EventRepeat carries no time_zone of its own, unlike ItemRepeat — the shared editor must not assume the field exists on the rule it is editing.


Two requirements added after #213 shipped

The job sheet went out to the family's cluster three times before it was right.
Seven visual defects, none caught by a suite: pickers that unfolded forms
instead of opening, three Save buttons on a commit-on-blur screen, (optional)
labels, a reward's name used as a field label, an unstyled add row, checkboxes
with a ghosted tick, and a create form with a browser spinner. Every one had to
be found by a person looking at a screen.

1. Screenshot goldens are part of this ticket

Record gallery (Playwright) and Roborazzi cases for every surface this ticket
builds or visibly changes, and treat them as a deliverable rather than a
follow-up. Three of #213's defects — the unstyled add row, the ghosted
checkboxes, the spinner in the create form — were pixel faults that a golden
would have caught before a deploy did.

#172 deferred its goldens on the reasoning that later tickets would re-record
them. That reasoning was sound then and is not now: the row grammar and the
pickers are settled, so an image recorded here stays valid.

Mechanics, from AGENTS.md: a new case rides in the same commit as the code
that adds it — a commit that adds a gallery or Roborazzi case without its image
is red on its own, because check / web runs npm run test:screens and
android / build runs verifyRoborazziDebug. A re-recorded existing case
goes in its own commit, so the reviewable diff stays code.

2. Check for leaked form styling before you finish

Every visual defect on #213 came from one place: the shipped app's form
fragments reused inside the new row grammar. They pass every test, because the
tests assert the pieces exist rather than that the screen reads right.

Before you call this done, grep the surfaces you touched and report what you
found and what you did about each:

  • a raw <input> / OutlinedTextField / BasicTextField outside the row and
    picker components — a form field dropped into a list of rows
  • type="number", which renders browser spinner arrows
  • btn, link-btn, btn-quiet or TextButton where a row or a quiet row
    verb belongs — underlined links reading as broken text
  • (optional) in any label — §8 names that pattern as the form admitting it
    should not have asked
  • any Save button on a surface that commits on blur, including Save changes and Save the points
  • a disabled-and-grey control where law 5 wants it absent
  • a record's title used as a field row's label — that column is for a
    field's name (Who, When, Worth), and a long title wraps in it

If your ticket is the first to land after this was written, add the check to
AGENTS.md beside the goldens rule, so it stops being a thing I remember to say.


Update — the demo wires the editor end to end (2026-08-25)

calendar-demo.dc.html carries all five EventRepeat shapes through the shared sheet; its copy is locked. The chips include the fortnight and the yearly (Every 25 August); the strip labels are Which days · a set, so Mondays and Wednesdays is one event and, on the nth-weekday kind, Which day · one only — the server accepts extras here and ignores them silently (the strip collapses to single-select exactly as described above); the Then readback names the next two dates for a multi-day rule, carries the re-derive warning (Changing the rule replaces it for the whole series — the series re-derives, and occurrences whose slot no longer lands are deleted.) and, on monthly-by-date, the clamp note (The 31st lands on the 30th, or the 28th, in months that are short.); Until offers presets plus Keeps going; the commit button states the rule (Run it every Tuesday).

Part of the calendar redesign. The design handoff (`design_handoff_calendar`, held outside the repo) is the source; the facts it depends on are repeated here so this issue stands alone. The jobs repeat sheet, reused: chips phrased from the event's own date, a sentence builder under `or set it up` that the chips fill in, a readback at the bottom, and a commit button that states the rule rather than saying Done. Three additions, all of them the shared editor gating by record type rather than a second editor: - **A multi-select weekday strip.** `EventRepeat.weekdays` is a set, so Monday, Wednesday and Friday swimming is *one* event. The jobs handoff bans the strip because `ItemRepeat.weekday` is a single int — that is a job-rule ban, not a deletion from the editor. - **One trap:** `MONTHLY_ON_NTH_WEEKDAY` reads only the **first** entry (`internal/domain/event.go:198`) and validation accepts extras without complaint (`:114` requires at least one, not exactly one). The strip must collapse to single-select the moment that kind is chosen, or the app silently drops days the reader picked. - **An `Until` row**, reading *Keeps going* when unset. A job's rule has no end date; an event's does, and it is inclusive — an occurrence on the until day still happens. It cuts occurrence *starts* only, so a span that begins before it still runs past it. - **A yearly chip** (`Every 25 August`), which is also what Birthday seeds. The readback names **two** dates for a multi-day rule: "Tuesdays and Thursdays" cannot be checked against one. `Repeats? No | Yes` in front of a chip row that already contains `No` is one decision asked twice; it goes. `EventRepeat` carries no `time_zone` of its own, unlike `ItemRepeat` — the shared editor must not assume the field exists on the rule it is editing. --- ## Two requirements added after #213 shipped The job sheet went out to the family's cluster three times before it was right. Seven visual defects, none caught by a suite: pickers that unfolded forms instead of opening, three Save buttons on a commit-on-blur screen, `(optional)` labels, a reward's name used as a field label, an unstyled add row, checkboxes with a ghosted tick, and a create form with a browser spinner. Every one had to be found by a person looking at a screen. ### 1. Screenshot goldens are part of this ticket Record gallery (Playwright) and Roborazzi cases for every surface this ticket builds or visibly changes, and treat them as a deliverable rather than a follow-up. Three of #213's defects — the unstyled add row, the ghosted checkboxes, the spinner in the create form — were pixel faults that a golden would have caught before a deploy did. `#172` deferred its goldens on the reasoning that later tickets would re-record them. That reasoning was sound then and is not now: the row grammar and the pickers are settled, so an image recorded here stays valid. Mechanics, from AGENTS.md: a **new** case rides in the same commit as the code that adds it — a commit that adds a gallery or Roborazzi case without its image is red on its own, because `check / web` runs `npm run test:screens` and `android / build` runs `verifyRoborazziDebug`. A **re-recorded existing** case goes in its own commit, so the reviewable diff stays code. ### 2. Check for leaked form styling before you finish Every visual defect on #213 came from one place: the shipped app's form fragments reused inside the new row grammar. They pass every test, because the tests assert the pieces exist rather than that the screen reads right. Before you call this done, grep the surfaces you touched and report what you found and what you did about each: - a raw `<input>` / `OutlinedTextField` / `BasicTextField` outside the row and picker components — a form field dropped into a list of rows - `type="number"`, which renders browser spinner arrows - `btn`, `link-btn`, `btn-quiet` or `TextButton` where a row or a quiet row verb belongs — underlined links reading as broken text - `(optional)` in any label — §8 names that pattern as the form admitting it should not have asked - **any Save button on a surface that commits on blur**, including `Save changes` and `Save the points` - a disabled-and-grey control where law 5 wants it absent - a record's title used as a field row's `label` — that column is for a field's name (`Who`, `When`, `Worth`), and a long title wraps in it If your ticket is the first to land after this was written, add the check to AGENTS.md beside the goldens rule, so it stops being a thing I remember to say. --- ## Update — the demo wires the editor end to end (2026-08-25) `calendar-demo.dc.html` carries all five `EventRepeat` shapes through the shared sheet; its copy is locked. The chips include the fortnight and the yearly (`Every 25 August`); the strip labels are `Which days · a set, so Mondays and Wednesdays is one event` and, on the nth-weekday kind, `Which day · one only — the server accepts extras here and ignores them silently` (the strip collapses to single-select exactly as described above); the `Then` readback names the **next two** dates for a multi-day rule, carries the re-derive warning (`Changing the rule replaces it for the whole series — the series re-derives, and occurrences whose slot no longer lands are deleted.`) and, on monthly-by-date, the clamp note (`The 31st lands on the 30th, or the 28th, in months that are short.`); `Until` offers presets plus `Keeps going`; the commit button states the rule (`Run it every Tuesday`).
Author
Owner

Delivered inside PRs #263/#264: EventRepeatSheet.tsx / EventRepeatContent — the shared repeat editor in event mode with the event-only additions (yearly chip, Until presets, next-two-dates readback, the create's No chip). One deliberate deferral: the demo's re-worded eventRepeatLabel strings ("Tuesdays and Thursdays") stay on the conformance-pinned wording — changing them ripples repeat.json and both surfaces' fixtures, so that rides with the #256-style wording sweep.

Delivered inside PRs #263/#264: EventRepeatSheet.tsx / EventRepeatContent — the shared repeat editor in event mode with the event-only additions (yearly chip, Until presets, next-two-dates readback, the create's No chip). One deliberate deferral: the demo's re-worded eventRepeatLabel strings ("Tuesdays and Thursdays") stay on the conformance-pinned wording — changing them ripples repeat.json and both surfaces' fixtures, so that rides with the #256-style wording sweep.
Author
Owner

Delivered inside PRs #263/#264 (shared repeat editor in event mode: weekday multi-select, Until presets, next-two-dates readback), merged to main 2026-08-26. The one deferral — the demo's re-worded eventRepeatLabel strings — is now tracked in its own issue.

Delivered inside PRs #263/#264 (shared repeat editor in event mode: weekday multi-select, Until presets, next-two-dates readback), merged to main 2026-08-26. The one deferral — the demo's re-worded eventRepeatLabel strings — is now tracked in its own issue.
nalum closed this issue 2026-08-26 18:48:02 +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#195
No description provided.