fix(calendar): the polish round — review fixes and the revised handoff #268

Merged
nalum merged 25 commits from feat/calendar-polish into main 2026-08-26 18:38:28 +00:00
Owner

Stacked on #265 (feat/calendar-toolbar) — merge that first. The morning review's fixes plus the handoff's post-1.8.1 revisions, both surfaces:

Review fixes

  • A job on the calendar opens the shared JobSheet (§2.3: "the job card, unmodified — a placement, not a variant"); the web was opening a bespoke read-only summary. Compose already opened the real sheet.
  • The toolbar's today control returns to the calendar icon — the drawn date-box rendered badly at icon size.
  • + (U+FF0B) is drawn into Eagrai Symbols: DejaVu's own plus contours scaled 1.25× on a full-em advance (same face, public-domain geometry, no second licence), and the add affordances say + again. Verified rendering at the full-em advance in the pinned browser.

Handoff revisions (§2.1/§2.4/§2.5)

  • View planes: week and agenda stand on their own opaque --surface panel with a --line edge — the page's dot matrix never shows through; the selected column, untimed band and today's rail stay --card.
  • One day surface: the week's bottom strip retires; tapping anywhere on a day opens the §2.7 day sheet, a block outranks the column, the axis runs the whole day and opens at 08:00 (or the now line). The column tint means now, never the-one-you-tapped.
  • Named blocks: a week block carries mark + name where its column can hold it (container-sized, never a breakpoint), inked with the new on-mark token — cmd/tokengen computes the pick (on-accent vs ink, pole fallback under AA) per theme × mode × mark, custom themes re-make it at apply time, conformance/on-mark.json pins web and Android to the same choices.
  • Centred agenda at ~46rem — wide windows add margin, not row width.
  • The row's shrink order: meta leaves first (absent, never clipped), a narrow late row drops its clock and keeps late (now its own span — fixture updated), the title never falls below ~6em, the pill never leaves, the row clips its own content.

Issues #266 (Android confirm counts) and #267 (golden coverage for the new sheets) track the remaining calendar follow-ups.

Stacked on #265 (`feat/calendar-toolbar`) — merge that first. The morning review's fixes plus the handoff's post-1.8.1 revisions, both surfaces: **Review fixes** - A job on the calendar opens the shared **JobSheet** (§2.3: "the job card, unmodified — a placement, not a variant"); the web was opening a bespoke read-only summary. Compose already opened the real sheet. - The toolbar's **today control returns to the calendar icon** — the drawn date-box rendered badly at icon size. - **+ (U+FF0B) is drawn into Eagrai Symbols**: DejaVu's own plus contours scaled 1.25× on a full-em advance (same face, public-domain geometry, no second licence), and the add affordances say + again. Verified rendering at the full-em advance in the pinned browser. **Handoff revisions (§2.1/§2.4/§2.5)** - **View planes**: week and agenda stand on their own opaque `--surface` panel with a `--line` edge — the page's dot matrix never shows through; the selected column, untimed band and today's rail stay `--card`. - **One day surface**: the week's bottom strip retires; tapping anywhere on a day opens the §2.7 day sheet, a block outranks the column, the axis runs the whole day and opens at 08:00 (or the now line). The column tint means *now*, never the-one-you-tapped. - **Named blocks**: a week block carries mark + name where its column can hold it (container-sized, never a breakpoint), inked with the new **`on-mark` token** — `cmd/tokengen` computes the pick (on-accent vs ink, pole fallback under AA) per theme × mode × mark, custom themes re-make it at apply time, `conformance/on-mark.json` pins web and Android to the same choices. - **Centred agenda** at ~46rem — wide windows add margin, not row width. - **The row's shrink order**: meta leaves first (absent, never clipped), a narrow late row drops its clock and keeps `late` (now its own span — fixture updated), the title never falls below ~6em, the pill never leaves, the row clips its own content. Issues #266 (Android confirm counts) and #267 (golden coverage for the new sheets) track the remaining calendar follow-ups.
§2.3's contract is one sentence: tapping a job opens the job card from
the jobs handoff, unmodified — a placement, not a variant. The web
calendar was opening a bespoke read-only summary sheet instead, a
second copy of the job rendering with none of the sheet's editing,
menu or reward affordances. It now opens the shared JobSheet exactly
as Today and the jobs board do, with the same local patch state so
edits land without a board refetch. Compose already opened the real
JobSheet — no Android change.
The toolbar's drawn today-box — a bordered rectangle with the date
inside — renders badly at icon size: the numeral collides with the
border and the header bar reads as smudge, worse in dark modes. The
previous control was already right: the calendar-today icon both
surfaces have carried since the first nav row. The date-in-a-box idea
goes; the icon returns, same aria-label, same position between the
arrows.
The calendar's add affordances write the demo's + (U+FF0B), and no
bundled face covers it — DejaVu 2.37 has no fullwidth forms, which is
how the glyph fell through to host fonts and diverged the page goldens
between machines. The subset now carries a real U+FF0B: DejaVu's own
plus contours, scaled a quarter up and centred on a full-em advance —
public-domain geometry from the same face, no second font licence.
The three calendar strings return to the demo's +, and the README's
generation script draws the glyph the same way.
The week view's blocks stand on the member's mark colour, and
--on-accent is only guaranteed against --accent — measured against the
member marks it fails on the dark ones. The handoff's one token
request: an on-mark pairing per mark, computed as whichever of
on-accent / ink reads better on that mark, carried by the generator so
no client re-derives it. Where neither theme ink clears AA 4.5 on a
mark (hearth dark's red tops out at 4.44), the better of black and
white steps in — the marks are mid-tone, so a pole always clears, and
a readable label outranks a theme-harmonised one; the generator
hard-fails only if even the poles cannot read.

cmd/tokengen emits --on-mark-<id> in every theme variant's CSS block
and an onMark map on each Android AppTokens. Custom themes make the
same pick at apply time from their resolved on-accent and ink — web in
theme.tsx (marks-colors.gen.ts now carries each mark's hex as data),
Android in applyCustomTokens — and conformance/on-mark.json holds the
two implementations to the generator's choices.
The §2.4 view-plane rule, added after the 1.8.1 build review: the page
ground is a dot matrix, and a view without its own opaque plane lets
the dots show through the hour axis and the agenda rails — the grid
reads as a texture and the view has no edge. Month already had its
plane (the hairline card grid); week and agenda now take a --surface
panel with a --line edge and the panel corner. Inside the plane the
selected column, the untimed band and today's rail stay --card, so
they still read as raised.

With the plane comes §2.5's other review fix: the agenda is a reading
column, centred in the window at ~46rem — at 2560px a left-aligned
column leaves two thirds of the page empty to its right and reads as a
rendering fault. Widening is not the answer; the extra width belongs
in the margins. Both surfaces.
The §2.4 revision after the 1.8.1 build review, both surfaces:

The bottom day strip goes. It was a second day surface with an 'Open
the day ›' link into the first one — two answers to one tap. Tapping
anywhere on a day (header, untimed band, empty hours) opens the §2.7
day sheet, the same sheet the month opens, so there is one day surface
in the product; a block outranks the column and opens its record. The
height the strip took goes back to the hour axis, which now runs the
full day and opens scrolled to 08:00 — or to the current-time line
when today is on show.

The column tint means NOW, not the-one-you-tapped: only today keeps
its card tint; the week cursor is state for the arrows, never a
highlight, so nothing on screen claims a selection the view no longer
has.

'No titles in the grid' is superseded: a block carries mark + name
whenever its column can hold it — the block is its own size container
(a container query on the web, BoxWithConstraints in Compose), so the
rule is the column's width, never a breakpoint. The label ink is the
new --on-mark pairing, never --on-accent, which fails on the dark
marks.
§2.1's addition after the 1.8.1 build review: when a row runs out of
width the meta gives way first, then the clock, and the title never
falls below ~6em — a job row that keeps 'Every Monday' and loses its
name inverts the promise the grammar makes. The meta is absent or
legible, never clipped: the row is its own size container, and below
~21em the meta leaves entirely (flex-shrink can only approach zero,
and a 4px box paints a letter fragment). The points pill is the one
meta that never leaves. 'late' is its own un-shrinkable span beside
the clock, so a narrow row never trades the state for the time: below
~21em a late row drops the clock — the middot belongs to the clock and
leaves with it — and keeps 'late'; the exact due time is one tap away
in the record. The row clips its own content, so no child paints
outside its ground at any width. Both surfaces.
test(ui): re-record the calendar goldens for the polish round
Some checks failed
android / build (pull_request) Has been cancelled
android / report (pull_request) Has been cancelled
check / commits (pull_request) Has been cancelled
check / go (pull_request) Has been cancelled
check / report (pull_request) Has been cancelled
check / web (pull_request) Has been cancelled
b4e885fd8b
The re-records the five commits below force together: the toolbar's
today icon, the drawn + back in every add affordance, the week and
agenda planes, the centred agenda, the week's named blocks and the
row's split late label. Component goldens re-record where the row
grammar moved; the live pages re-record across the calendar routes.
The week's opens-at-08:00 scroll and the agenda's opens-at-today scroll
both ran in Calendar's own effect — which fires BEFORE the ThemeProvider
parent effect that stamps data-cal-view on <html>. The target view was
still display:none at that moment, so scrollTo and scrollIntoView were
no-ops and the week opened on six empty midnight hours while the agenda
opened on the 1st. Anchoring moves to the next animation frame, after
the attribute lands and the view is actually on show.

Two container fixes ride along because the anchors are meaningless
without them: the agenda plane scrolls internally (max-height 40rem,
per the demo) so today anchors inside the panel and the toolbar stays
put, and the week axis viewport drops to 26rem — at 38rem only 132px
of the 24-hour axis could scroll, so 08:00 (272px) was unreachable.
Android already anchors correctly (initial scroll state / LaunchedEffect
on a visible list) and keeps its internal panels; no change there.
The locked demo stacks the week the other way round: the no-time band
first, then the weekday heads, then the hour axis — the heads sit
against the hours they caption instead of floating two rows above
them. Both surfaces had the heads on top; both flip to the demo's
order.
At 390px the toolbar wrapped into five rows and ate ~330px before a
date appeared — the exact 380px failure §6 was written against. The
demo's phone frame settles it in three: the period label rides inline
with the when group, the two segmented controls share a row, and the
create collapses to a 44px + icon button (its name staying as the
accessible label). Desktop keeps the single row and the worded button.

Android's toolbar already stacks in the demo's grammar; no change.
Rule 2.7 of the calendar handoff: day-step buttons are icons with the
date in the tooltip, and nothing truncates. The sheet's steps were text
chips carrying the neighbouring date, which clipped to an ellipsis at
sheet width — the one truncation the rule names. The chips drop the
visible words; the date stays in the tooltip (title) and the
accessible label.
Screen one of create asked five questions where rule 4 lists four: a
standalone Last day row sat beside When — half of the four-box form
(What day / Last day / Starts / Ends) the handoff tore down. The When
picker gains a Last day leg instead: a picker-row under All day that
flips the same month grid to picking the span's end, the readback
naming the whole span. The Runs row keeps its multi-day gate and now
appears the moment When makes a span. Same fold on Android's create
sheet.
The empty-day + add opened the create sheet seeded to today, so
adding to the gap between the 20th and the 22nd meant re-picking the
date the link already named. The link now carries its day into the
sheet, the same seed the day sheet's primary passes. Same on Android.
The create sheet auto-focuses its title, and the field's Escape
handler swallowed the key even when nothing had been typed — so the
sheet law (the topmost surface answers Escape) needed two presses.
Escape still reverts an edit in progress; with nothing to revert it
passes through and the sheet closes. Android's back gesture already
behaves this way.
test(ui): re-record the calendar page goldens for the review fixes
Some checks failed
android / build (pull_request) Has been cancelled
android / report (pull_request) Has been cancelled
check / commits (pull_request) Has been cancelled
check / go (pull_request) Has been cancelled
check / report (pull_request) Has been cancelled
check / web (pull_request) Has been cancelled
3e597648af
The anchors, the band order, the agenda plane and the phone toolbar
all move pixels on the calendar pages; the goldens follow in their own
commit so the fixes diff readably.
Author
Owner

Review round against the updated handoff (after a live make deploy audit): seven more commits.

  • The open anchors actually fire — the week/agenda scroll effect ran before data-cal-view landed, so it scrolled a display:none view. Week now opens at 08:00/now-line, agenda opens on today inside its own scrolling plane (demo's 40rem cap); the week axis viewport drops to 26rem so the anchor is reachable.
  • Untimed band above the day heads (the demo's order), both surfaces.
  • Phone toolbar compacts to the demo's three rows (~150px): segs share a row, create collapses to a 44px +; both surfaces.
  • Day-sheet steps are icons with the date in the tooltip — nothing truncates (§2.7); both surfaces.
  • Last day folds into the When picker — screen one back to rule 4's four questions; Runs keeps its multi-day gate; both surfaces.
  • Agenda's empty-day + add seeds its own day; both surfaces.
  • An untouched field lets Escape close the sheet (the create title ate the first press).

make check, gallery 53/53, live pages 66/66, Android tests + Roborazzi all green; page goldens re-recorded in their own commit.

Review round against the updated handoff (after a live `make deploy` audit): seven more commits. - **The open anchors actually fire** — the week/agenda scroll effect ran before `data-cal-view` landed, so it scrolled a `display:none` view. Week now opens at 08:00/now-line, agenda opens on today inside its own scrolling plane (demo's 40rem cap); the week axis viewport drops to 26rem so the anchor is reachable. - **Untimed band above the day heads** (the demo's order), both surfaces. - **Phone toolbar compacts to the demo's three rows** (~150px): segs share a row, create collapses to a 44px +; both surfaces. - **Day-sheet steps are icons with the date in the tooltip** — nothing truncates (§2.7); both surfaces. - **Last day folds into the When picker** — screen one back to rule 4's four questions; Runs keeps its multi-day gate; both surfaces. - **Agenda's empty-day + add seeds its own day**; both surfaces. - **An untouched field lets Escape close the sheet** (the create title ate the first press). `make check`, gallery 53/53, live pages 66/66, Android tests + Roborazzi all green; page goldens re-recorded in their own commit.
Author
Owner

Week-view follow-ups from the deployed check, four more commits:

  • The axis rules the whole day — the label/rule loops still ran the old 8-mark count (00:00–14:00), so the evening floated unruled. Twelve marks now; Android already had twelve.
  • Hour labels centre on their rules — top-aligned text made every line read as the hour above it (the reported misalignment). Both surfaces.
  • The open-anchor had a second leg: on a fresh page load the effect fired while the board was still the LoadingBoard — no axis in the DOM — and never re-fired. board.loading is now a dep, so reload-into-week/agenda anchors too (folded into the anchors commit).
  • The clock gives way after the meta (§2.1) — the anchored phone agenda exposed ordinary timed rows clipping their span mid-glyph at ~13.7em; below the threshold the whole clock now leaves on both surfaces (late rows still keep the word).

Page goldens re-recorded; make check, pages 66/66, Android tests + Roborazzi green.

Week-view follow-ups from the deployed check, four more commits: - **The axis rules the whole day** — the label/rule loops still ran the old 8-mark count (00:00–14:00), so the evening floated unruled. Twelve marks now; Android already had twelve. - **Hour labels centre on their rules** — top-aligned text made every line read as the hour above it (the reported misalignment). Both surfaces. - **The open-anchor had a second leg**: on a fresh page load the effect fired while the board was still the LoadingBoard — no axis in the DOM — and never re-fired. `board.loading` is now a dep, so reload-into-week/agenda anchors too (folded into the anchors commit). - **The clock gives way after the meta** (§2.1) — the anchored phone agenda exposed ordinary timed rows clipping their span mid-glyph at ~13.7em; below the threshold the whole clock now leaves on both surfaces (late rows still keep the word). Page goldens re-recorded; `make check`, pages 66/66, Android tests + Roborazzi green.
nalum force-pushed feat/calendar-polish from 3e597648af
Some checks failed
android / build (pull_request) Has been cancelled
android / report (pull_request) Has been cancelled
check / commits (pull_request) Has been cancelled
check / go (pull_request) Has been cancelled
check / report (pull_request) Has been cancelled
check / web (pull_request) Has been cancelled
to ff62a68eb6
Some checks failed
android / build (pull_request) Has been cancelled
android / report (pull_request) Has been cancelled
check / commits (pull_request) Has been cancelled
check / go (pull_request) Has been cancelled
check / report (pull_request) Has been cancelled
check / web (pull_request) Has been cancelled
2026-08-26 10:50:38 +00:00
Compare
Author
Owner

Two more from the live check:

  • The week cursor follows the month cursor (one commit, both surfaces): paging months in the month or agenda view moved only the fetch window — weekSel stayed behind, so opening the week view landed on a week outside the loaded range and drew empty until a week step forced the window over. Stepping the month now carries the week cursor: today's week when the month holds today, else the month's first week. Verified live: month → next month → Week opens on the new month's first week with its data.

  • The Month→Week default flip was not a code bug — it was me. My verification scripts clicked the Week/Agenda toggles while signed in as the real account, and calendar_view syncs through UserSettings (ADR-0029), so they overwrote the stored pref. I've restored it to auto (Month on desktop) with a masked settings write; the rest of the settings record (mark, theme, text scale, card tilt) was untouched. Apologies for the confusion that caused.

make check, pages 66/66, Android tests + Roborazzi green.

Two more from the live check: - **The week cursor follows the month cursor** (one commit, both surfaces): paging months in the month or agenda view moved only the fetch window — `weekSel` stayed behind, so opening the week view landed on a week outside the loaded range and drew empty until a week step forced the window over. Stepping the month now carries the week cursor: today's week when the month holds today, else the month's first week. Verified live: month → next month → Week opens on the new month's first week with its data. - **The Month→Week default flip was not a code bug — it was me.** My verification scripts clicked the Week/Agenda toggles while signed in as the real account, and `calendar_view` syncs through UserSettings (ADR-0029), so they overwrote the stored pref. I've restored it to auto (Month on desktop) with a masked `settings` write; the rest of the settings record (mark, theme, text scale, card tilt) was untouched. Apologies for the confusion that caused. `make check`, pages 66/66, Android tests + Roborazzi green.
fix(calendar): the week cursor follows the month cursor
All checks were successful
check / commits (pull_request) Successful in 15s
check / go (pull_request) Successful in 2m44s
check / report (pull_request) Successful in 4s
check / web (pull_request) Successful in 4m28s
android / build (pull_request) Successful in 6m37s
android / report (pull_request) Successful in 4s
3354ebd699
Paging months in the month or agenda view moved only the fetch
window; weekSel stayed behind, so opening the week view showed a week
outside the loaded range — rows empty until a week step forced the
window over. Stepping the month now carries the week cursor with it:
today's week when the month holds today, else the month's first week.
Same on Android.

Test report

Suite Tests Result Skipped
Unit 1440 ✅ pass 1
Integration 133 ✅ pass —

Coverage: 27.0%

Updated by the check workflow · commit 68f5b3c14e

<!-- ci-test-report --> ## Test report | Suite | Tests | Result | Skipped | | --- | --: | --- | --: | | Unit | 1440 | ✅ pass | 1 | | Integration | 133 | ✅ pass | — | **Coverage:** 27.0% <sub>Updated by the check workflow · commit 68f5b3c14e71060f687accdf7ad355e5eed88bc2</sub>

Android test report

Suite Tests Result Skipped
Unit (debug) 194 ✅ pass 0

Coverage: 10.5% of lines

Updated by the android workflow · commit 68f5b3c14e

<!-- android-test-report --> ## Android test report | Suite | Tests | Result | Skipped | | --- | --: | --- | --: | | Unit (debug) | 194 | ✅ pass | 0 | **Coverage:** 10.5% of lines <sub>Updated by the android workflow · commit 68f5b3c14e71060f687accdf7ad355e5eed88bc2</sub>
Author
Owner

The repeat-editor formatting report, two commits:

  • The interval field wears the sheet's ink. The underline treatment was scoped to the jobs repeat sheet's wrapper on the old reasoning that the event form was a form — that form died in #264, so the event repeat sheet and the new-job sheet rendered a bare <input> that color-scheme: dark paints as the browser's own near-black box. The underline is now the editor field's own dress; the jobs wrapper keeps only its width override. (Android's Material field already follows the theme.)

  • Your job screenshot also caught a real leak: it shows a Yearly chip, which the job repeat SHEET filters out — meaning it was the NEW-JOB sheet, which called the shared editor unfiltered on both surfaces. Creating a job could offer EVERY_N_YEARS, which domain.ValidateRepeat rejects on an item at save. Both create flows now pass the same JOB_KINDS filter the repeat sheet documents.

Verified live in dark mode: event editor keeps five shapes with a themed underlined field; the new-job editor offers four. Gallery 53/53, make check, Android tests + Roborazzi green.

The repeat-editor formatting report, two commits: - **The interval field wears the sheet's ink.** The underline treatment was scoped to the jobs repeat sheet's wrapper on the old reasoning that the event form was a form — that form died in #264, so the event repeat sheet and the new-job sheet rendered a bare `<input>` that `color-scheme: dark` paints as the browser's own near-black box. The underline is now the editor field's own dress; the jobs wrapper keeps only its width override. (Android's Material field already follows the theme.) - **Your job screenshot also caught a real leak**: it shows a Yearly chip, which the job repeat SHEET filters out — meaning it was the NEW-JOB sheet, which called the shared editor unfiltered on both surfaces. Creating a job could offer `EVERY_N_YEARS`, which `domain.ValidateRepeat` rejects on an item at save. Both create flows now pass the same `JOB_KINDS` filter the repeat sheet documents. Verified live in dark mode: event editor keeps five shapes with a themed underlined field; the new-job editor offers four. Gallery 53/53, `make check`, Android tests + Roborazzi green.
The underline treatment on the editor's interval field was scoped to
the jobs repeat sheet's wrapper, on the old reasoning that the event
form was a form and its boxed field belonged. That form is gone —
every host of the shared editor is now a sheet of chips and rows — so
the event repeat sheet and the new-job sheet rendered a bare input,
which color-scheme: dark paints as the browser's own near-black box.
The underline is now the editor field's own dress; the jobs wrapper
keeps only its size overrides. Android's Material field already
follows the theme.
fix(jobs): creating a job offers only a job's four repeat shapes
All checks were successful
check / commits (pull_request) Successful in 22s
check / go (pull_request) Successful in 2m58s
check / report (pull_request) Successful in 6s
check / web (pull_request) Successful in 4m20s
android / build (pull_request) Successful in 6m42s
android / report (pull_request) Successful in 3s
115c5457c8
The job repeat sheet filters the shared editor to the four kinds a
job rule may hold, but the new-job sheet called the editor unfiltered
— so creating a job offered Yearly, which domain.ValidateRepeat
rejects on an item, and the save would come back InvalidArgument.
Both surfaces now pass the same job-kind filter the repeat sheet
documents (yearly is events-only; the ban is the caller's filter,
never a capability removed from the shared editor).
Author
Owner

Ruling applied — the new job's Repeats is now a row that opens the sheet, both surfaces (one commit):

  • Screen two's No/Yes toggle and the inline rule editor are gone; a Repeats · No › picker row opens the same JobRepeatSheet the job sheet already uses, and the row's value reads the rule's own words (jobRepeatLabel) once one is picked.
  • This also stops the question being asked twice — the sheet leads with its own No chip (the same critique §4.1 makes of the event form's old Repeats? No | Yes).
  • The previous commit's JOB_KINDS export moves back inside the sheet on both surfaces — with the inline call site gone, the sheet is the only job path into the shared editor again.
  • The Yes msgid fell out of the catalogs with the toggle (extract --clean + android-i18n ride the commit).

Verified live: screen two is rows (Repeats · No › / Worth · Nothing yet ›), the row opens the full sheet (phrased chips, builder, readback), a chip pick commits and lands back on the row. make check, Android tests + Roborazzi green; no goldens pose the new-job screens (#267's gap again).

Ruling applied — **the new job's Repeats is now a row that opens the sheet**, both surfaces (one commit): - Screen two's No/Yes toggle and the inline rule editor are gone; a `Repeats · No ›` picker row opens the same `JobRepeatSheet` the job sheet already uses, and the row's value reads the rule's own words (`jobRepeatLabel`) once one is picked. - This also stops the question being asked twice — the sheet leads with its own No chip (the same critique §4.1 makes of the event form's old `Repeats? No | Yes`). - The previous commit's `JOB_KINDS` export moves back inside the sheet on both surfaces — with the inline call site gone, the sheet is the only job path into the shared editor again. - The `Yes` msgid fell out of the catalogs with the toggle (extract --clean + android-i18n ride the commit). Verified live: screen two is rows (`Repeats · No ›` / `Worth · Nothing yet ›`), the row opens the full sheet (phrased chips, builder, readback), a chip pick commits and lands back on the row. `make check`, Android tests + Roborazzi green; no goldens pose the new-job screens (#267's gap again).
fix(jobs): the new job's Repeats is a row that opens the sheet
All checks were successful
check / commits (pull_request) Successful in 21s
check / go (pull_request) Successful in 2m56s
check / report (pull_request) Successful in 3s
android / build (pull_request) Successful in 6m51s
android / report (pull_request) Successful in 3s
check / web (pull_request) Successful in 7m18s
6243488578
Screen two asked Repeats as a No/Yes toggle that unfolded the rule
editor inline — a form growing inside a sheet of rows, and a second
grammar beside the event create's Repeats row. It also asked the
repeat question twice: the sheet it now opens leads with its own No
chip. The toggle and the inline editor go; a Repeats picker row opens
the same JobRepeatSheet the job sheet already uses, valued with the
rule's own words. Same on Android. The job-kind filter export from
the last change moves back inside the sheet — its only caller again.
Author
Owner

On-device check found a launch crash on the phone (API 31): NoSuchFieldError: ListFormatter$Type.UNITS in waitingNames — the Type/Width overload and Type.UNITS itself only exist from API 33 (minSdk is 26), and Robolectric's pinned sdk 35 meant no suite could see it. Below 33 the names now fall back to a comma join (byte-identical to conformance/render-job.json's English pick, Ali, Sam); 33+ keeps ICU's per-locale list styling. Swept the rest of the android.icu usage — MessageFormat, DateFormat skeletons and the plain ListFormatter.getInstance(locale) are all API 24–26 — and a lint pass shows zero remaining NewApi hits. Verified on the device: reinstall, launch, boards render, no crash.

On-device check found a launch crash on the phone (API 31): `NoSuchFieldError: ListFormatter$Type.UNITS` in `waitingNames` — the Type/Width overload and `Type.UNITS` itself only exist from **API 33** (minSdk is 26), and Robolectric's pinned sdk 35 meant no suite could see it. Below 33 the names now fall back to a comma join (byte-identical to `conformance/render-job.json`'s English pick, `Ali, Sam`); 33+ keeps ICU's per-locale list styling. Swept the rest of the `android.icu` usage — MessageFormat, DateFormat skeletons and the plain `ListFormatter.getInstance(locale)` are all API 24–26 — and a lint pass shows zero remaining NewApi hits. Verified on the device: reinstall, launch, boards render, no crash.
fix(android): waiting names survive devices below API 33
Some checks failed
check / commits (pull_request) Successful in 20s
check / go (pull_request) Successful in 2m46s
check / report (pull_request) Successful in 4s
check / web (pull_request) Successful in 5m38s
android / build (pull_request) Successful in 7m25s
android / report (pull_request) Successful in 4s
check / commits (push) Has been cancelled
check / go (push) Has been cancelled
check / report (push) Has been cancelled
check / web (push) Has been cancelled
tag / tag (push) Has been cancelled
android / report (push) Has been cancelled
android / build (push) Has been cancelled
68f5b3c14e
The ListFormatter overload taking Type and Width — and Type.UNITS
itself — only exist from API 33, so opening any board with a waiting
panel threw NoSuchFieldError on older phones (minSdk is 26; the crash
device runs 31). Robolectric pins sdk 35, which is why no suite saw
it. Below 33 the names fall back to a comma join — byte-identical to
the fixture's English pick — and ICU's per-locale list styling keeps
the newer devices.
nalum changed target branch from feat/calendar-toolbar to main 2026-08-26 18:38:24 +00:00
nalum merged commit 68f5b3c14e into main 2026-08-26 18:38:28 +00:00
nalum deleted branch feat/calendar-polish 2026-08-26 18:38:28 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
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!268
No description provided.