Overlays: close acts at once; the outro never delays navigation or input #1391

Closed
opened 2026-10-07 18:18:33 +00:00 by kayg · 15 comments
Owner

Finding (interaction audit #1369, perf VM)

Closing an overlay waits for its outro animation before the app acts. packages/ui/src/components/OverlaySurface.svelte requestClose() sets present = false, then setTimeout(onclose, outMs): the route navigation, focus restore and the content underneath change only after the animation. This breaks the owner rule (CLAUDE.md "Motion and loading", #611): never await an animation before showing content or accepting input.

Measured close → underlying view usable, p50 / p95:

Required

  • onclose (navigation, state change, focus restore) runs in the same frame as Escape / scrim / swipe / close button. The outro still plays, as a visual only, on a detached or retained layer with pointer-events: none and inert, so the page underneath accepts input at once. Route-driven overlays must not lose their outro: keep the surface mounted for the outro after navigation (portal or retained layer), not delay the navigation.
  • One fix in the shared OverlaySurface (and FloatingSurface if it has the same pattern). Callers do not change unless they await the close.
  • Reduced motion: no outro, same immediate close.
  • Find out why Composer close takes 400–900 ms when the outro is 120 ms / the sheet morph: list the other work on that path (route load, effects, focus restore) and fix it.
  • Regression test: after Escape, the underlying route and focus are set within one frame; a click on the page during the outro lands. Re-measure the six rows above with the audit harness (bench/interaction-audit-1369.mjs on branch job/instaudit-1369) on the perf VM.
## Finding (interaction audit #1369, perf VM) Closing an overlay waits for its outro animation before the app acts. `packages/ui/src/components/OverlaySurface.svelte` `requestClose()` sets `present = false`, then `setTimeout(onclose, outMs)`: the route navigation, focus restore and the content underneath change only after the animation. This breaks the owner rule (CLAUDE.md "Motion and loading", #611): never await an animation before showing content or accepting input. Measured close → underlying view usable, p50 / p95: - Settings / close Composer: 414 / 910 ms - Tasks / close Composer: 861 / 892 ms - Calendar / close Composer: 433 / 514 ms - Settings / close Search: 438 / 504 ms - Notifications / close inbox: 389 / 439 ms - Search / close Composer from Search: 43 / 476 ms Budget: 150 ms. Full audit: https://git.kayg.org/kayg/calternal/src/branch/job/instaudit-1369/docs/perf/2026-10-07-1369-interaction-audit.md ## Required - `onclose` (navigation, state change, focus restore) runs in the same frame as Escape / scrim / swipe / close button. The outro still plays, as a visual only, on a detached or retained layer with `pointer-events: none` and `inert`, so the page underneath accepts input at once. Route-driven overlays must not lose their outro: keep the surface mounted for the outro after navigation (portal or retained layer), not delay the navigation. - One fix in the shared OverlaySurface (and FloatingSurface if it has the same pattern). Callers do not change unless they await the close. - Reduced motion: no outro, same immediate close. - Find out why Composer close takes 400–900 ms when the outro is 120 ms / the sheet morph: list the other work on that path (route load, effects, focus restore) and fix it. - Regression test: after Escape, the underlying route and focus are set within one frame; a click on the page during the outro lands. Re-measure the six rows above with the audit harness (`bench/interaction-audit-1369.mjs` on branch job/instaudit-1369) on the perf VM.
Author
Owner

Starting #1391 on job/outro-1391 at base 0419170fe456b58614befcb12d9c9d255118f1c0. I have read the issue, CLAUDE.md, CONTEXT.md, DESIGN §§34 and 59, and am checking the #1369 audit branch and current OverlaySurface implementation before changing it.

Starting #1391 on `job/outro-1391` at base `0419170fe456b58614befcb12d9c9d255118f1c0`. I have read the issue, CLAUDE.md, CONTEXT.md, DESIGN §§34 and 59, and am checking the #1369 audit branch and current OverlaySurface implementation before changing it.
Author
Owner

Finding from the #1369 source audit: OverlaySurface.requestClose() awaits the shared outro timeout before onclose(). Composer and Notifications close by changing local state, but Settings starts goto(launch); route completion is asynchronous. The route stays inert until OverlaySurface's open effect cleans up. Its focus trap restores on destroy, then retries focus each animation frame while the target is inert. FloatingSurface has transitions but calls onclose() directly. I will measure when the underlay and focus are usable, release the shared shell on close, and keep the outgoing surface inert and pointer-transparent for its existing outro.

Finding from the #1369 source audit: `OverlaySurface.requestClose()` awaits the shared outro timeout before `onclose()`. Composer and Notifications close by changing local state, but Settings starts `goto(launch)`; route completion is asynchronous. The route stays inert until OverlaySurface's `open` effect cleans up. Its focus trap restores on destroy, then retries focus each animation frame while the target is inert. `FloatingSurface` has transitions but calls `onclose()` directly. I will measure when the underlay and focus are usable, release the shared shell on close, and keep the outgoing surface inert and pointer-transparent for its existing outro.
Author
Owner

Perf setup finding: the first locked baseline launch exited before serving because the copied calternal-server-release could not find libsherpa-onnx-c-api.so. On the build host, ldd resolves Sherpa and ONNX Runtime from /mnt/hdd/targets/shared-server/target/sherpa-onnx-prebuilt/...; the perf VM has ONNX Runtime system libraries but no Sherpa library. I am copying the matching prebuilt runtime libraries and will retry. No interaction samples were recorded in that attempt.

Perf setup finding: the first locked baseline launch exited before serving because the copied `calternal-server-release` could not find `libsherpa-onnx-c-api.so`. On the build host, `ldd` resolves Sherpa and ONNX Runtime from `/mnt/hdd/targets/shared-server/target/sherpa-onnx-prebuilt/...`; the perf VM has ONNX Runtime system libraries but no Sherpa library. I am copying the matching prebuilt runtime libraries and will retry. No interaction samples were recorded in that attempt.
Author
Owner

Evidence update for #1391: the first bun run check found the exact layout.observer-purpose pin for packages/ui/src/components/OverlaySurface.svelte stale after the lifecycle edit (<module>:fa2e0bcd714dddd0). I refreshed only that ledger hash to af64020a35b1e9621d3b94202e59ada4604b5d383d58ce276378f6b6af396971; the rule and ratchet counts are unchanged. The focused OverlaySurface and focusTrap tests passed (36/36). I will rerun the web check after the pin refresh.

Evidence update for #1391: the first `bun run check` found the exact `layout.observer-purpose` pin for `packages/ui/src/components/OverlaySurface.svelte` stale after the lifecycle edit (`<module>:fa2e0bcd714dddd0`). I refreshed only that ledger hash to `af64020a35b1e9621d3b94202e59ada4604b5d383d58ce276378f6b6af396971`; the rule and ratchet counts are unchanged. The focused OverlaySurface and focusTrap tests passed (36/36). I will rerun the web check after the pin refresh.
Author
Owner

Evidence update: the next bun run check confirmed the same exact site is also recorded in the #1058 adoption checkpoint. I updated the matching hash in contracts/perf/exceptions.json and contracts/perf/adoption-1058.json to af64020a35b1e9621d3b94202e59ada4604b5d383d58ce276378f6b6af396971. The live observer site is unchanged; no performance rule or ratchet count changed. I will rerun the check against both synchronized records.

Evidence update: the next `bun run check` confirmed the same exact site is also recorded in the #1058 adoption checkpoint. I updated the matching hash in `contracts/perf/exceptions.json` and `contracts/perf/adoption-1058.json` to `af64020a35b1e9621d3b94202e59ada4604b5d383d58ce276378f6b6af396971`. The live observer site is unchanged; no performance rule or ratchet count changed. I will rerun the check against both synchronized records.
Author
Owner

Baseline profile finding: the overlay-only run indexed 1,000 Notes, 1,000 Tasks, 84 Journal logs, 84 Calendar events/tasks, and 12 notifications, then Playwright crashed while navigating the unrelated Calendar route. It produced 0 interaction samples; subsequent routes reported Target crashed. The filtered harness still navigated every Tab before applying its interaction filter. I am changing it to visit only the selected close path's Tab, then I will rerun the matched row on both builds.

Baseline profile finding: the overlay-only run indexed 1,000 Notes, 1,000 Tasks, 84 Journal logs, 84 Calendar events/tasks, and 12 notifications, then Playwright crashed while navigating the unrelated Calendar route. It produced 0 interaction samples; subsequent routes reported `Target crashed`. The filtered harness still navigated every Tab before applying its interaction filter. I am changing it to visit only the selected close path's Tab, then I will rerun the matched row on both builds.
Author
Owner

Performance profile finding: the overlay-only setup indexed its Notes (1,000), Tasks (1,000), Journal Logs (84), Calendar Events/Tasks (84 each), and Notifications (12) fixtures, then Playwright reported Target crashed while waiting for the Settings main view. A second filtered attempt reproduced the Settings renderer crash. The perf VM has no matching recent kernel OOM-kill entry; the host load was 1.17 / 1.82 / 1.89 before and 2.69 / 2.28 / 2.05 after the failed run. No interaction samples were produced. I am narrowing this profile to the selected overlay open/close path and its required fixture (12 notifications for the inbox row), then I will retain the data-scope limitation in the report.

Performance profile finding: the overlay-only setup indexed its Notes (1,000), Tasks (1,000), Journal Logs (84), Calendar Events/Tasks (84 each), and Notifications (12) fixtures, then Playwright reported `Target crashed` while waiting for the Settings main view. A second filtered attempt reproduced the Settings renderer crash. The perf VM has no matching recent kernel OOM-kill entry; the host load was 1.17 / 1.82 / 1.89 before and 2.69 / 2.28 / 2.05 after the failed run. No interaction samples were produced. I am narrowing this profile to the selected overlay open/close path and its required fixture (12 notifications for the inbox row), then I will retain the data-scope limitation in the report.
Author
Owner

The scoped close-path profile reproduced the same Settings renderer failure with all optional Notes, Tasks, Journal Logs, Calendar, Search and Notifications fixture setup skipped: Target crashed while assertTabContent waited for main, 0 samples. Load was 2.78 / 2.06 / 1.94 before and 2.50 / 2.02 / 1.93 after; the run indexed no data and the perf VM still has no matching OOM-kill record. This rules out the large fixture and unrelated interaction sweep as the cause. I am checking the production-build route setup and will use only rows that collect five accepted samples; I will report any route-specific gap explicitly.

The scoped close-path profile reproduced the same Settings renderer failure with all optional Notes, Tasks, Journal Logs, Calendar, Search and Notifications fixture setup skipped: `Target crashed` while `assertTabContent` waited for `main`, 0 samples. Load was 2.78 / 2.06 / 1.94 before and 2.50 / 2.02 / 1.93 after; the run indexed no data and the perf VM still has no matching OOM-kill record. This rules out the large fixture and unrelated interaction sweep as the cause. I am checking the production-build route setup and will use only rows that collect five accepted samples; I will report any route-specific gap explicitly.
Author
Owner

A second route failed under the same minimal profile: Tasks also reports Target crashed while waiting for the production main view, with 0 samples and no fixture data indexed. The Settings and Tasks failures occur before opening an overlay. This points to the audit browser/build route setup rather than overlay close behavior; I am gathering renderer diagnostics before I continue the paired measurements.

A second route failed under the same minimal profile: `Tasks` also reports `Target crashed` while waiting for the production `main` view, with 0 samples and no fixture data indexed. The Settings and Tasks failures occur before opening an overlay. This points to the audit browser/build route setup rather than overlay close behavior; I am gathering renderer diagnostics before I continue the paired measurements.
Author
Owner

Perf VM diagnosis: the Settings, Tasks and Search audit pages all ended with Playwright Target crashed; page diagnostics record page-crash. journalctl -k records repeated Compositor trap int3 entries in chrome-headless-shell at the failed runs. The runs indexed no fixture data. --disable-gpu and --disable-features=VizDisplayCompositor did not prevent the crash. No matching OOM kill appears in the kernel log. I am keeping this as an environment limitation and moving paired before/after samples to the local host, recording its load for every run.

Perf VM diagnosis: the Settings, Tasks and Search audit pages all ended with Playwright `Target crashed`; page diagnostics record `page-crash`. `journalctl -k` records repeated `Compositor` `trap int3` entries in `chrome-headless-shell` at the failed runs. The runs indexed no fixture data. `--disable-gpu` and `--disable-features=VizDisplayCompositor` did not prevent the crash. No matching OOM kill appears in the kernel log. I am keeping this as an environment limitation and moving paired before/after samples to the local host, recording its load for every run.
Author
Owner

The local close-path snapshot shows the Settings route is already an active aria-modal OverlaySurface (role=dialog, label Settings). The Composer shortcut deliberately refuses to stack a second modal while one is active, so the audit's old Settings/close Composer and Settings/close Search palette rows are not valid paths in the current app. I have changed the profile to measure the Settings OverlaySurface closing itself, and moved Search palette close to the non-modal Calendar route. The visual matrix now opens Composer over Tasks.

The local close-path snapshot shows the Settings route is already an active `aria-modal` OverlaySurface (`role=dialog`, label `Settings`). The Composer shortcut deliberately refuses to stack a second modal while one is active, so the audit's old `Settings/close Composer` and `Settings/close Search palette` rows are not valid paths in the current app. I have changed the profile to measure the Settings OverlaySurface closing itself, and moved Search palette close to the non-modal Calendar route. The visual matrix now opens Composer over Tasks.
Author
Owner

Finding: the production screenshot at phone width shows a visible ring on the Composer field immediately after Meta+N opens it. focusQuietly passed focusVisible: undefined whenever data-input="keyboard", so programmatic initial focus could match :focus-visible (apps/web/src/lib/a11y/inputModality.ts). This conflicts with the current no-ring rule for code-moved focus. I will make programmatic focus quiet in every input mode; native Tab and arrow navigation keep their ring behavior.

Finding: the production screenshot at phone width shows a visible ring on the Composer field immediately after Meta+N opens it. `focusQuietly` passed `focusVisible: undefined` whenever `data-input="keyboard"`, so programmatic initial focus could match `:focus-visible` (apps/web/src/lib/a11y/inputModality.ts). This conflicts with the current no-ring rule for code-moved focus. I will make programmatic focus quiet in every input mode; native Tab and arrow navigation keep their ring behavior.
Author
Owner

Finding: the isolated Search/Composer profile recorded zero samples. Its diagnostic state had path=/calendar/week/2026-10-05 and composerSurfaceCount=0; close-only setup skipped the real Search palette and result flow, then sent Meta+N from Calendar. I am rerunning this row through the audit's real Search flow with its API-created Note fixture. This is a benchmark setup correction; it did not indicate a product failure.

Finding: the isolated Search/Composer profile recorded zero samples. Its diagnostic state had `path=/calendar/week/2026-10-05` and `composerSurfaceCount=0`; close-only setup skipped the real Search palette and result flow, then sent Meta+N from Calendar. I am rerunning this row through the audit's real Search flow with its API-created Note fixture. This is a benchmark setup correction; it did not indicate a product failure.
Author
Owner

#1391 implementation and verification complete.

Head SHA: 9a2b071cae8986487729a715fc93433d1af9a1b0
Branch: job/outro-1391. origin/dev (d395b6e25) is merged. No push, deploy, or issue close was done.

Change

OverlaySurface now stages its shared outro and commits leaving state with Svelte tick(). The outgoing surface becomes inert, hidden from assistive technology, and non-interactive; then onclose and the idempotent shell release run without waiting for the spring outro. Svelte retains the visual layer until its transition finishes. Focus restoration runs once when the trap deactivates, and code-moved focus suppresses the ring while native Tab and arrow navigation keep it.

The Search benchmark opens Composer through the real > new task palette command. Its underlay is Calendar because this app resolves /today to Calendar. The benchmark also records process-tree CPU/RSS and the real underlay-ready point. The perf profile is in docs/perf/baseline.json.

Before / after performance

Six paths, five samples per path, one warm-up close, alternating before/after by path. Latency is input-to-underlay-ready p50/p95. CPU and RSS are process-tree p50 values.

Close path Before latency ms After latency ms CPU % p50 before → after RSS peak MB p50 before → after
Settings panel 1195 / 1424.6 277.2 / 316.1 137.6 → 175.3 1009.7 → 941.9
Composer from Tasks 447.7 / 509.6 177.3 / 222.6 106.9 → 130.8 891.5 → 882.8
Composer from Calendar 389.1 / 444.9 283.3 / 309.1 122.4 → 128.2 940.7 → 937.5
Search palette from Calendar 519.8 / 598.0 439.2 / 731.9 127.7 → 100.4 948.0 → 947.0
Notifications inbox 562.1 / 752.9 249.9 / 523.0 130.5 → 149.7 955.2 → 952.9
Composer from Search 300.0 / 354.4 340.5 / 497.0 126.1 → 113.0 995.7 → 980.0

The perf VM Chromium compositor trapped with SIGTRAP on route loads, so the paired runs used the local 12-CPU host and the shared prebuilt Release server. Exact build/server hashes and per-run load averages are recorded in the profile. Search Composer p50/p95 and Calendar Search p95 were higher after; these rows are load-sensitive and remain visible in the baseline for review.

UX gaps closed

  • The page underneath is ready while the spring outro remains visible.
  • Escape and scrim close use the same shared motion path.
  • The outgoing surface does not accept pointer, keyboard, or screen-reader interaction.
  • Focus returns once, without a programmatic focus ring.
  • Production captures cover macOS-emulated phone (390), tablet (820), and desktop (1440) widths in light and dark. They include post-click and post-shortcut frames.

The final phone light frame sequence is Escape, +1 frame, and +3 frames. The Tasks underlay is visible at +1 while Composer continues its outro.

Width Light: click / shortcut Dark: click / shortcut
390 click / shortcut click / shortcut
820 click / shortcut click / shortcut
1440 click / shortcut click / shortcut

UX gaps left: none known. Performance gap: the inbox profile has 12 real notifications and other selected routes show their real empty states; there is no separate large-list or repeated-close burst profile.

Gates

bun run build exited 0:

✓ built in 1m 32s

bun run check exited 0:

perf-lint: PASS; 0 violations; 22544 scoped exceptions
svelte-check found 0 errors and 4 warnings in 2 files

Focused Vitest exited 0:

 Test Files  3 passed (3)
      Tests  40 passed (40)
   Start at  04:34:23
   Duration  22.34s (transform 63%, environment 18%, tests 12%, import 5%, setup 2%)

No Rust files are in the issue delta, so Rust format, clippy, and test gates were not run. cargo clean output:

     Removed 0 files

Decisions not specified in DESIGN

  • Use tick() as the boundary: it commits inert/accessibility state before calling onclose, without waiting for a transition promise. The shared spring outro remains visual only.
  • Use Search's actual > new task action and a Calendar underlay for the Search close profile; that is the real accessible app flow.
  • Use local paired measurements after the perf VM compositor failed; the baseline records the limitation and exact web/server hashes.
#1391 implementation and verification complete. Head SHA: `9a2b071cae8986487729a715fc93433d1af9a1b0` Branch: `job/outro-1391`. `origin/dev` (`d395b6e25`) is merged. No push, deploy, or issue close was done. ## Change `OverlaySurface` now stages its shared outro and commits `leaving` state with Svelte `tick()`. The outgoing surface becomes inert, hidden from assistive technology, and non-interactive; then `onclose` and the idempotent shell release run without waiting for the spring outro. Svelte retains the visual layer until its transition finishes. Focus restoration runs once when the trap deactivates, and code-moved focus suppresses the ring while native Tab and arrow navigation keep it. The Search benchmark opens Composer through the real `> new task` palette command. Its underlay is Calendar because this app resolves `/today` to Calendar. The benchmark also records process-tree CPU/RSS and the real underlay-ready point. The perf profile is in `docs/perf/baseline.json`. ## Before / after performance Six paths, five samples per path, one warm-up close, alternating before/after by path. Latency is input-to-underlay-ready p50/p95. CPU and RSS are process-tree p50 values. | Close path | Before latency ms | After latency ms | CPU % p50 before → after | RSS peak MB p50 before → after | |---|---:|---:|---:|---:| | Settings panel | 1195 / 1424.6 | 277.2 / 316.1 | 137.6 → 175.3 | 1009.7 → 941.9 | | Composer from Tasks | 447.7 / 509.6 | 177.3 / 222.6 | 106.9 → 130.8 | 891.5 → 882.8 | | Composer from Calendar | 389.1 / 444.9 | 283.3 / 309.1 | 122.4 → 128.2 | 940.7 → 937.5 | | Search palette from Calendar | 519.8 / 598.0 | 439.2 / 731.9 | 127.7 → 100.4 | 948.0 → 947.0 | | Notifications inbox | 562.1 / 752.9 | 249.9 / 523.0 | 130.5 → 149.7 | 955.2 → 952.9 | | Composer from Search | 300.0 / 354.4 | 340.5 / 497.0 | 126.1 → 113.0 | 995.7 → 980.0 | The perf VM Chromium compositor trapped with `SIGTRAP` on route loads, so the paired runs used the local 12-CPU host and the shared prebuilt Release server. Exact build/server hashes and per-run load averages are recorded in the profile. Search Composer p50/p95 and Calendar Search p95 were higher after; these rows are load-sensitive and remain visible in the baseline for review. ## UX gaps closed - The page underneath is ready while the spring outro remains visible. - Escape and scrim close use the same shared motion path. - The outgoing surface does not accept pointer, keyboard, or screen-reader interaction. - Focus returns once, without a programmatic focus ring. - Production captures cover macOS-emulated phone (390), tablet (820), and desktop (1440) widths in light and dark. They include post-click and post-shortcut frames. The final phone light frame sequence is [Escape](https://git.kayg.org/attachments/918687f6-f234-4c1f-b0a5-e9cfe4327b2e), [+1 frame](https://git.kayg.org/attachments/e4e711b9-03a7-4ab6-821f-1754c7c1069d), and [+3 frames](https://git.kayg.org/attachments/b11eeceb-04df-400b-ad89-60471ab08d53). The Tasks underlay is visible at +1 while Composer continues its outro. | Width | Light: click / shortcut | Dark: click / shortcut | |---|---|---| | 390 | [click](https://git.kayg.org/attachments/4ee2346b-c8ba-4982-bccc-78357265a69e) / [shortcut](https://git.kayg.org/attachments/0fd610ba-9a18-49e5-b2fc-c9a39d6ce785) | [click](https://git.kayg.org/attachments/0462059a-a3c0-4786-8509-74747aa4f32a) / [shortcut](https://git.kayg.org/attachments/d2049fec-b69b-4f08-9b8d-03d457e1b614) | | 820 | [click](https://git.kayg.org/attachments/3f93e4df-d132-4602-8dc3-7b6f23e0276b) / [shortcut](https://git.kayg.org/attachments/6f7cb038-6487-4a15-8108-344cd85981ed) | [click](https://git.kayg.org/attachments/6e9a6d28-b70f-4c20-a3cc-66ecdad0a086) / [shortcut](https://git.kayg.org/attachments/dc6e4ca4-40af-417d-b985-c3ae391d3bc3) | | 1440 | [click](https://git.kayg.org/attachments/58a11da4-15de-48c5-b819-efdcf221030c) / [shortcut](https://git.kayg.org/attachments/05b9d03e-109b-44b2-962d-f943b2164843) | [click](https://git.kayg.org/attachments/feade57b-6c1f-4105-9c93-bba9edc267c6) / [shortcut](https://git.kayg.org/attachments/e9d828b2-a63c-4f01-a348-9a24fbb1c8c2) | UX gaps left: none known. Performance gap: the inbox profile has 12 real notifications and other selected routes show their real empty states; there is no separate large-list or repeated-close burst profile. ## Gates `bun run build` exited 0: ```text ✓ built in 1m 32s ``` `bun run check` exited 0: ```text perf-lint: PASS; 0 violations; 22544 scoped exceptions svelte-check found 0 errors and 4 warnings in 2 files ``` Focused Vitest exited 0: ```text Test Files 3 passed (3) Tests 40 passed (40) Start at 04:34:23 Duration 22.34s (transform 63%, environment 18%, tests 12%, import 5%, setup 2%) ``` No Rust files are in the issue delta, so Rust format, clippy, and test gates were not run. `cargo clean` output: ```text Removed 0 files ``` ## Decisions not specified in DESIGN - Use `tick()` as the boundary: it commits inert/accessibility state before calling `onclose`, without waiting for a transition promise. The shared spring outro remains visual only. - Use Search's actual `> new task` action and a Calendar underlay for the Search close profile; that is the real accessible app flow. - Use local paired measurements after the perf VM compositor failed; the baseline records the limitation and exact web/server hashes.
kayg referenced this issue from a commit 2026-10-08 10:41:40 +00:00
Author
Owner

Deployed to calternal.cloud in merge round 35a (build cc1af3c12, live 2026-10-09 00:12 IST). Closing.

Deployed to calternal.cloud in merge round 35a (build cc1af3c12, live 2026-10-09 00:12 IST). Closing.
kayg closed this issue 2026-10-08 18:41:43 +00:00
Commenting is not possible because the repository is archived.
No labels
No milestone
No project
No assignees
1 participant
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
kayg/calternal-v0#1391
No description provided.