Block actions: hover controls, make-note (→), block reminders with quiet hours, phone capsule bar (DESIGN §42) #191
Closed
opened 2026-09-26 15:25:15 +00:00 by kayg
·
89 comments
No Branch/Tag specified
dev
wip/delete-1119
wip/collabrev-1197
wip/collabloss-1197
wip/cards2-1083
wip/cards-1083
wip/canvas-visual
wip/canvasvis2-976
wip/calhdr-1112
wip/calcards-1115
wip/browserfix
wip/blocks-1125
wip/allday-1107
wip/agenda-decks
wip/agenda-1086
wip/adv7c-1105
wip/txentry-1198
wip/trayicons2-1095
wip/trayicons-1095
wip/tagperf-1186
wip/sidebar3-1094
wip/rev2-webperf
wip/rev2-money-ident
job/adv-1202
wip/restyle-notes
wip/previewcard-1098
wip/palette2-1123
wip/palette-1093
wip/onboard2-1141
wip/onboard-1141.aborted-early
wip/onboard-1141
wip/nlpchip-1127
wip/morph-1104
wip/merge-round-7c5
wip/merge-round-7c4
job/notifloop-1194
wip/merge-round-7c3
wip/merge-round-7c2
wip/merge-round-7c
wip/mchrome-1084
wip/mailghost2-1094
wip/mailghost-1094
wip/kbpreview2-1118
wip/kbpreview-1118
wip/kanban-1092
wip/importhang-1121
wip/hiderev-1153
wip/hide4-1153
wip/hide3-1153
wip/hide2-1153
wip/hide-1153
wip/editreg-1132
job/collabloss-1197
wip/editorrail3-1113
wip/editorrail2-1113
wip/editorrail-1113
wip/e2e-b2-1071
wip/e2e-b-1071
wip/draw4-1101
wip/draw3-1101
wip/draw2-1101
wip/draw-1101
wip/directory-1199-r
wip/directory-1199
job/onboard-1141
job/hide-1153
job/perf-1124
job/perf2-1124
job/tocrail-1191
job/restyle-settings
wip/restyle-settings
job/segmented-1200
wip/notifloop-1194
job/tagperf-1186
wip/segmented-1200
job/restyle-files
job/tagdnd-1187
job/merge30
job/cards-1179
wip/cards2-1179
wip/cards-1179
wip/tocrail-1191
wip/tagdnd-1187
wip/restyle-files
wip/perf-1124
wip/merge30j
job/restyle-notes
job/wizchoices-1140
wip/wizchoices-1140
wip/restyle-1190
job/moneyfmt-1180
job/txentry-1198
wip/moneyfmt2-1180
wip/moneyfmt-1180-r
wip/moneyfmt-1180
job/pillglass-1189
job/flags-1181
wip/flags-1181
job/restyle-1190
job/restyle-mailmoney
job/restyle-search
job/settingsreg-1195
job/wizard-1140
site/website
wip/wizardrev2-1140
wip/wizardrev-1140
wip/wizard5-1140
wip/wizard4-1140
wip/wizard3-1140
wip/wizard2-1140
wip/wizard-1140
wip/pillglass-1189
wip/settingsreg-1195
job/merge29
job/fu-1171
wip/merge29j
wip/fu-1171
job/fu-1166
job/directory-1199
job/proflog-1204
job/txresearch-1188
wip/fu-1166
job/merge28
job/search-1066
wip/search-1066
wip/merge28j
job/gateslot-1182
job/bulkimport-1157
job/mailnet-1160
wip/mailnetrev-1160
wip/mailnet-1160
wip/bulkrev-1157
wip/bulkimport-1157
job/startup-1161
wip/startup-1161
job/merge27
job/linkcards-1151
wip/linkcards3-1151
wip/linkcards2-1151
wip/linkcards-1151
job/traydate-1144
wip/traydate3-1144
wip/traydate2-1144
wip/traydate-1144
job/draw-1101
wip/merge27j
job/blockpill-1152
wip/blockpill3-1152
wip/blockpill2-1152
wip/blockpill-1152
job/minihover-1149
wip/minihover2-1149
wip/minihover-1149
job/merge25
wip/merge25-r
wip/merge25b
wip/merge25
job/inspector-1129
job/tags-1110
wip/inspector3-1129
wip/inspector2-1129
wip/inspector-1129
wip/tagsrev-1110
wip/tags2-1110
wip/tags-1110
job/dates-1148
wip/datesrev-1148
wip/dates2-1148
wip/dates-1148
job/licence-1145
wip/licence2-1145
wip/licence-1145
job/selfhost-1156
job/merge23
wip/merge23
job/tagfilter-1109
wip/tagfilter2-1109
wip/tagfilter-1109
job/kbd-1134
wip/kbd2-1134
wip/kbd-1134
job/palfoot-1137
wip/selfhost-1156
wip/palfoot2-1137
wip/palfoot-1137
job/toggle-1158
wip/toggle-1158
job/kbpreview-1118
job/docratchet-1155
job/perflint-1133
job/devtests-1159
wip/docratchet-1155
wip/devtests-1159
job/segv-1136
wip/toast-1142
wip/segv-1136
job/toast-1142
job/blockreload-1147
wip/blockreload-1147
job/font-1150
wip/font-1150
job/importui-1120
job/minimonth-1149
wip/importui-1120
wip/minimonth-1149
job/depcheck-1146
wip/perflint-1133
wip/depcheck-1146
job/calcards-1115
job/blocks-1125
job/plus-1128
job/shift-1138
wip/plus2-1128
wip/plus-1128
wip/shift-1138
job/moneyfid-1130
job/editorrail-1113
wip/moneyrev-1130
wip/moneyfid-1130
job/noext-851
wip/noext-851
wip/noext3-851
wip/noext2-851
job/week-1135
wip/week-1135
job/editreg-1132
job/smoke-1122
wip/smoke-1122
job/docs-1143
job/palette2-1123
job/calhdr-1112
job/nlpchip-1127
job/mailghost-1094
job/reconnect-1131
wip/reconnect-1131
job/trayicons-1095
job/delete-1119
job/importhang-1121
job/cards-1083
job/palette-1093
job/mchrome-1084
job/e2e-a-1071
job/canvas-visual
job/previewcard-1098
job/allday-1107
wip/e2e-a2-1071
wip/e2e-a-1071
job/e2e-b-1071
job/adv7c-1105
job/kanban-1092
job/agenda-1086
job/merge-round-7c
job/morph-1104
wip/surfaces-p2
job/merge-round-9
wip/merge-round-9
job/7cfix-small
wip/7cfix-small
job/mailui-1078
job/merge-round-8
wip/merge-round-8
wip/mailui-1078
job/mailround-1038
job/applemail-accept
wip/settitle-1068
wip/mailround2-1038
wip/mailround-1038
wip/e2e-7b
job/crash-1069
wip/crash-1069
job/searchlost-1066
wip/searchlost-1066
job/7b-reconcile
job/flake-1065
wip/flake-1065
wip/merge-round-7b7
wip/merge-round-7b6
wip/merge-round-7b5
wip/merge-round-7b4
wip/7b-reconcile
job/appupdate-1059
job/nfd-1044
wip/appupdate-1059
job/e2e-7b
job/loop-1062
wip/loop-1062
job/pdfprev-1045
job/invtoggle-1053
wip/pdfprev-1045
wip/nfd-1044
wip/invtoggle-1053
job/7bfix-e2e
job/mailstress-b
wip/7bfix-e2e
wip/mailstress-b
job/7bfix-adv
wip/7bfix-adv
job/mailstress-a
job/stack-1054
wip/stack-1054
wip/mailstress-a
job/mailstress-1038
wip/mailstress-1038
job/upload500-1051
wip/upload500-1051
job/share-1034
wip/share-1034
job/syncerr-1037
job/7bfix-photos
wip/7bfix-photos
job/paste-1036
job/setside-1039
wip/setside-1039
wip/paste-1036
job/lease-1042
wip/syncerr-1037
wip/lease-1042
job/7bfix-data
job/passkeybind-1043
wip/apprevoke-1041
job/invite-1035
wip/invite-1035
job/merge-round-7b2
wip/merge-round-7b2
job/mailproxy-486
job/apprevoke-1041
job/rebuild-1033
job/pillborder-1029
wip/pillborder-1029
wip/mailproxy-486
wip/applemail-486
job/headless-998
wip/headless-998
job/groups-1028
wip/groups-1028
job/rebuildwarn-1016
wip/rebuildwarn-1016
job/startup-1011
wip/startup-1011
job/monthpill-1009
job/bgthumb-1025
job/sharetitle-1012
wip/monthpill-1009
wip/bgthumb-1025
wip/sharetitle-1012
job/canvas-cards-977
wip/canvas-cards-977
job/canvas-pencil-978
job/canvas-sketch-990
wip/canvas-sketch-990
wip/canvas-pencil-978
job/canvas-files-989
wip/canvas-files-989
job/canvas-collab-991
wip/canvas-collab-991
job/weekscroll-1018
wip/weekscroll-1018
wip/canvas-core-976
job/canvas-core-976
job/round-drag
wip/round-drag
job/round-settings
job/browserfix
wip/oapi-974
job/oapi-974
job/hist2-integrate
job/mailhtml-726
wip/mailhtml-726
wip/hist2-integrate
job/moneyfu-984
job/drag-1015
wip/drag-1015
job/rename-1017
wip/rename-1017
job/hist2-api
wip/hist2-api
job/oneacct-1014
wip/oneacct-1014
wip/moneyfu-984
job/hist2-bench
job/hist2-restore
wip/hist2-bench
job/hist2-write
job/hotfix-724
wip/hotfix-724
wip/hist2-write
wip/hist2-restore
job/hist2-store
job/hist2-ui
wip/hist2-ui
wip/hist2-store
job/searchstarve-965
job/shutdown-963
wip/shutdown-963
wip/pubedit-981
job/pubedit-981
job/analytics-973
wip/searchstarve-965
job/authflash-850
job/weeklane-969
job/pvtitle-1004
job/hist-975
wip/authflash-850
job/voicepill-617
wip/pvtitle-1004
job/headring-1003
wip/weeklane-969
wip/voicepill-617
wip/headring-1003
wip/analytics-973
job/agentscope-980
wip/thumbsandbox-988
job/thumbsandbox-988
wip/hist-975
job/links-856
wip/links-856
job/davetag-966
wip/davetag-966
job/filesstorm-1000
job/hoverpad-725
wip/filesstorm-1000
job/ffmpegblas-993
job/merge-round-7a
wip/hoverpad-725
wip/ffmpegblas-993
job/nowdot-1002
wip/verify-7a
job/noteid-857
wip/nowdot-1002
wip/noteid-857
wip/merge-round-7a
wip/agentscope-980
job/imapedge
job/a11yfix2
wip/imapedge-941
wip/imapedge
wip/a11yfix2
job/notetask-986
job/logheading
wip/logheading-998
job/textthumb-652
job/photolive-987
wip/photolive-987
job/davactive-983
job/savefix-985
job/tabicons-607
wip/davactive-983
wip/tabicons-607
wip/notetask-986
wip/savefix-985
job/dirid-627
job/buildspeed-1007
wip/dirid-627
job/agenda-decks
job/perfguards-impl
job/undo-a11y
wip/undo-a11y
job/mailperf
job/wal-824
wip/settings-50
job/settings-50
job/notesfilter-606
wip/notesfilter-606
job/surfaces-p2
wip/wal-824
job/maillayouts
wip/mailperf
wip/maillayouts
job/taskmeta-659
job/money-ident
wip/money-ident
wip/taskmeta-659
job/errstates
wip/perfguards-impl
job/headings-881
wip/headings-881
wip/errstates
job/voice-619
job/gaps-827
job/notesperf
wip/notesperf
wip/voice-619
job/hddsql-549
job/perf-stream-668
wip/perf-stream-668
wip/deeplinks-fix
job/deeplinks-fix
job/authfix
job/docsfix-rust
wip/docsfix-rust
job/webperf
job/docsfix-web
job/datafix2
job/webdav-lock-476
job/copyfix
wip/copyfix
wip/webperf
job/focus-658
wip/protofix
job/mediafix
job/protofix
wip/mediafix
job/agentfix
job/hhmm-724
wip/agentfix
job/undo-722
job/reuse
wip/webdav-lock-476
wip/reuse
job/scopefix
job/datafix
wip/hhmm-724
wip/undo-722
job/surfaces-p1
wip/hddsql-549
job/voicememos-618
wip/datafix2
wip/surfaces-p1
job/fix-940
wip/fix-940
job/blaze-surfaces
wip/datafix
wip/blaze-surfaces
job/taskday-655
job/linknav-639
wip/linknav-639
wip/gaps-827
job/isolation-707
job/audiophotos-720
wip/audiophotos-720
job/advfind-664
wip/voicememos-618
wip/taskday-655
wip/isolation-707
wip/advfind-664
wip/scopefix
wip/focus-658
job/testgaps
wip/testgaps
job/overscroll-718
wip/authfix
job/deps
wip/overscroll-718
job/rev2-agentfix
job/rev2-money-ident
job/rev2-mailperf
wip/deps
job/hardening-728
wip/hardening-728
job/searchgen-832
wip/searchgen-832
job/photopw-849
job/mailsql-825
wip/photopw-849
job/sharefix
wip/sharefix
job/rev2-mailhtml-726
job/rev2-perfguards
job/copyval-723
job/lightglass-r2
wip/lightglass-r2
wip/docsfix-web
job/copy-audit
job/macinterop-staging-r2
job/design-sync
job/rev2-taskmeta-659
job/rev2-webperf
job/docs-audit
job/rev2-advfind-664
job/rev2-mailproxy-486
job/states-audit
job/rev2-datafix
job/design-drift
job/test-gaps
job/rev2-voicememos-618
job/rev2-mediafix
job/rev2-deps
job/rev2-datafix2
job/licence-audit
job/issue-hygiene
job/rev2-protofix
job/rev2-voice-619
job/rev2-isolation-707
job/rev2-surfaces-p1
job/deeplink-audit2
job/rev2-audiophotos-720
wip/test-gaps
job/rev2-overscroll-718
job/rev2-undo-722
wip/states-audit
job/rev2-dropmd-719
job/rev2-linknav-639
job/merge-7b-plan
wip/merge-7b-plan
job/rev2-taskday-655
wip/mailsql-825
job/rev2-webdav-lock-476
job/rev2-browserfix
wip/design-drift
job/rev2-hddsql-549
wip/deeplink-audit2
job/rev2-scopefix
job/rev2-authfix
job/rev2-hardening-728
job/rev2-wal-824
job/rev2-sharefix
job/calsidebar-638
job/chrome-audit
job/ioperf
wip/ioperf
wip/chrome-audit
wip/calsidebar-638
job/dropmd-719
wip/dropmd-719
job/ocr-build
wip/ocr-build
job/blaze-settings
wip/copyval-723
job/toastring-721
wip/toastring-721
job/deployfix-732
wip/deployfix-732
wip/blaze-settings
job/money-import-recheck
job/rev-a11y
job/perf-arch-db
job/rev-7b-data
wip/textthumb-652
wip/perf-arch-db
job/sec-protocols
job/sidehdr-660
job/rev-7b-security
job/research-surfaces
job/rev-design-gaps
job/rev-mcp-api
wip/sidehdr-660
job/perf-arch-memory
wip/sec-protocols
job/perf-arch-bundle
job/snapedge-714
wip/rev-mcp-api
job/sec-supplychain
wip/research-surfaces
job/perf-arch-sync
job/rev-consistency
job/perf-arch-server
wip/perf-arch-server
wip/perf-arch-memory
job/perf-arch-io
job/perf-arch-client
job/sec-fs
job/sec-mcp-scopes
job/sec-sharing
job/perf-guards
job/sec-browser
job/sec-admin-deploy
job/sec-auth
wip/snapedge-714
job/bgpicker-717
wip/perf-arch-bundle
wip/money-import-recheck
job/advsetup-654
wip/bgpicker-717
wip/advsetup-654
job/burst-709
job/kbdcaps-710
job/app-pw-chooser
wip/burst-709
wip/app-pw-chooser
job/imaptest-625
wip/kbdcaps-710
job/fix-499
wip/fix-499
job/perf-mut-667
job/calimg-589
job/perf-snap-666
wip/calimg-589
wip/perf-snap-666
wip/perf-mut-667
job/perf-cache-665
wip/perf-cache-665
job/voicefiles-620
wip/voicefiles-620
job/admin-burst-705
wip/admin-burst-705
job/voicememos-review
wip/voicememos-review
wip/ryw-653
job/ryw-653
job/writeonopen-661
job/instant-663
wip/writeonopen-661
job/money-import-review
wip/money-import-review
wip/importjs-610
review/integrations-407-round6
wip/integrations-review
job/dragghost-612
wip/dragghost-612
job/integrations
wip/integrations
job/decider-656
job/merge-round-6
job/perf-rerun
wip/merge-round-6
job/integrations-review-round5
job/selalign-576
wip/selalign-576
job/mcp-events-491
job/files-631
job/cal-e2e-569
wip/cal-e2e-569
job/reload-423
wip/reload-423
wip/mcp-events-491
wip/files-631
job/notesbridge-644
wip/notesbridge-644
job/editor-series
job/calcard-series
wip/calcard-series
job/mcp-events-review-491
wip/mcp-events-review
wip/editor-series
job/quirks-546
job/integrations-recheck
job/tocrail-636
wip/tocrail-636
wip/quirks-546
wip/reminders-643
job/reminders-643
wip/davscale-573
job/davscale-573
job/integrations-review
wip/ocr-eval-584
job/ocr-eval-584
job/esc-537
wip/esc-537
job/toastname-586
wip/toastname-586
job/submenu-579
wip/submenu-579
job/tasks-mode
wip/tasks-mode
job/agentdocs-630
job/dupwrite-634
wip/agentdocs-630
wip/dupwrite-634
job/lightglass-588
wip/lightglass-588
job/tabswitch-549
job/ghosttask-623
wip/ghosttask-623
job/toaststack-616
job/weekstate-609
job/mailsync-613
wip/mailsync-613
wip/weekstate-609
job/maildup-626
wip/tabswitch-549
wip/maildup-626
wip/toaststack-616
job/motion-611
wip/motion-611
job/tlstest-601
wip/tlstest-601
job/perf-495
job/floating-sheet
wip/floating-sheet
job/remdup-585
wip/remdup-585
job/fix-502
wip/fix-502
job/attachplay-622
job/perf-batch
wip/perf-batch-563
wip/perf-495
hotfix/mail-sync-diag
job/mail-m3
wip/mail-m3
job/attach-poof-603
job/calhover-608
job/editorbar-604
job/mentions-605
job/merge-round-4
job/allday-514
wip/merge-round-4
wip/allday-514
job/merge-round-4a
wip/merge-round-4a
job/sharestack-580
job/fix-501
wip/sharestack-580
wip/fix-501
job/perf-batch-563
job/apw-cache-review
wip/apw-cache-review
job/probe-520
wip/probe-520
job/mac-393
wip/mac-393
job/header-571
job/flake-513
wip/flake-513
job/docs-thumb-547
wip/header-571
job/webcal-572
wip/webcal-572
wip/shortcuts-542
job/shortcuts-542
wip/docs-thumb-547
job/caldav-stress
wip/caldav-stress
wip/sweep-478
job/apw-cache-512
wip/apw-cache-512
job/money-empty-540
wip/restart-505
wip/money-empty-540
wip/fix-510
job/restart-505
job/fix-503
job/perf-496
wip/perf-496
job/fix-498
wip/fix-498
job/info-inspector-465
wip/info-inspector-465
job/fix-510
job/fix-507
wip/fix-507
wip/fix-503
job/fix-493
job/money-kinds
wip/money-kinds
job/hygiene-548
job/merge-round-3
wip/fix-493
job/drag-snap-536
wip/merge-round-3
wip/merge-round-0930
wip/drag-snap-536
job/align-538
wip/align-538
job/bg-flash
wip/bg-flash
job/money-import
job/search-count-544
wip/search-count-544
wip/money-import
job/settings-key-541
wip/settings-key-541
job/toast-539
job/preview-421
wip/preview-421
wip/toast-539
job/tasks-500-531
job/title-plain-526
wip/title-plain-526
wip/tasks-500-531
job/notes-bridge
wip/parity-484
job/parity-484
job/files-slow
job/crash-525
wip/notes-bridge
wip/files-slow
wip/crash-525
job/kbd-motion-527
wip/bg-422
job/analytics-504
wip/analytics-504
wip/kbd-motion-527
job/upload-pill-523
wip/upload-pill-523
wip/tray-order
job/tray-order
wip/overflow-mid
wip/merge-round-2
job/perf-494
wip/perf-494
wip/mcp-fast-492
wip/motion-477
wip/asr-ab-489
wip/theme-variants-506
wip/overflow-511
wip/week-header-508
wip/attach-427
job/dav-delete-471
job/iso-435
wip/iso-435
wip/files-sel-keys
wip/dav-delete-471
job/align-253
job/siwc-490
wip/siwc-490
job/money-kinds-review
wip/align-253
wip/money-kinds-review
job/small-bugs-3
wip/overlay-title-487
wip/multiget-500
wip/hidden-420
wip/webcal-ui
wip/webcal-431
job/perf-367
job/location
wip/small-bugs-3
wip/location
wip/perf-367
wip/admin-deny-483
job/tag-unicode-473
wip/tag-unicode-473
job/blur-436
wip/photos-470
wip/blur-436
wip/small-bugs-4
wip/hunt-20260930
wip/settings-hdr-482
wip/chips-416
job/dedup-375
wip/dedup-375
job/doc-stack
wip/doc-stack
job/tokens-literals
wip/tokens-literals
job/jobs-leftovers
wip/send-fast
wip/paste-467
wip/money-numbers
job/money-plugin
wip/money-plugin
job/break-dav
wip/merge-batch
wip/crossday-469
wip/mac-verify
wip/mail-m2
wip/break-dav
wip/money-review2
job/money-md
job/modes-424
wip/money-md
wip/jobs-leftovers
job/agenda-413
wip/agenda-413
wip/modes-424
job/recog-417
wip/recog-417
wip/bounce-425
wip/ab-384-luna
job/webdav-perf
wip/webdav-perf
job/toast-ring
wip/toast-ring
job/money-review
wip/money-review
wip/micro-motion
wip/settings-card
wip/minical
job/notes-imap-428
job/least-priv
wip/ui-small-2
wip/flaky-426
wip/drag-end-418
job/jank
wip/jank
wip/least-priv
wip/docs-site
job/agenda
job/sec-batch
wip/sec-batch
wip/per-user-index
job/area-calendars
wip/area-calendars
job/parity
wip/parity
job/documents-research
wip/documents-research
job/test-infra
job/reminders-sync
wip/small-bugs-2
wip/reminders-sync
wip/gestures
job/google-oauth
wip/tags-merge
wip/tags
job/e2e-theme
wip/e2e-theme
job/icon-align
wip/test-infra
wip/select-align
wip/editor-385
job/voice
wip/webdav
job/webdav
job/app-pw-ui
job/editor-integrity
wip/editor-integrity
wip/voice
wip/quota
wip/cal-followups
wip/icon-align
job/composer-scale
wip/composer-scale
job/jobs-page
wip/jobs-page
job/hig-type
wip/hig-type
wip/app-pw-ui
job/motion-spring
job/mcp
wip/motion-spring
wip/mcp
job/small-bugs
wip/push-hosts
job/profile-sign
wip/touch-369
wip/profile-sign
job/mobile-focus
wip/mobile-focus
wip/ui-polish-354
wip/small-bugs
wip/dup-task
job/toast-polish
job/app-pw-scopes
wip/toast-polish
wip/app-pw-scopes
wip/cli-agent
wip/selection-pills
job/preview-attach
wip/preview-attach
job/dav-proppatch
wip/dav-proppatch
wip/cal-switcher
job/atomic-race
wip/atomic-race
job/photos-shared
wip/photos-shared
wip/cal-grid
wip/note-rewrite
wip/search-rebuild
job/mail-m1
job/paperless-import
wip/paperless-import
wip/mail-m1
wip/hidden-activity
wip/search-d
wip/pricing-research
wip/cursors
wip/auto-scheme
job/single-pills
wip/single-pills
wip/xuser-matrix
wip/money-format
wip/app-pw-setup
wip/purge-dos
wip/vault-health
wip/caldav-apple
wip/xuser-audit
wip/e2e-green
wip/tabbar
wip/adv-harness
wip/maple-mono
job/search-fix
wip/search-fix
wip/search-perf-c
job/adv-harness
wip/sidebar-headers
job/glass
wip/temp-index
job/polish
wip/polish
wip/file-protocols
wip/money-research
wip/glass
wip/voice-models
wip/collab-redo
job/voice-research
wip/hunt-20260928
wip/notes-actions-research
wip/search-pad
wip/search-perf
wip/search-sticky
wip/editor-undo
wip/chrome-rules
wip/motion
wip/appearance-research
wip/appearance
wip/audit-bugs
wip/cal-glass
wip/block-actions
wip/authz-order
wip/event-stripes
wip/chrome-sidebar
wip/auth-flaky
wip/robust-2
wip/gate-fix
wip/menu-blur
wip/import-calternaljs
wip/tray-fix
job/import-calternaljs
wip/index-order
wip/audit-fixes
wip/search-chevrons
research/mail
wip/phone-chrome
wip/dedup-break
wip/csp
wip/ui-audit
wip/select-toast
wip/perf
wip/flat-layout
wip/fonts
wip/event-tint
wip/sync-converge
wip/data-split
wip/glass-audit
wip/robustness
wip/sync-chaos
wip/search-thumbs
wip/fuzz
wip/menu-icons
wip/search-pill
wip/sync-changing
wip/heading-links
wip/date-formats
wip/a11y
wip/break-editor
wip/e2e-fix
wip/settings-sections
wip/sync-root-guard
wip/search-palette
wip/share-edit
job/toasts
wip/toasts
wip/cont-analytics
wip/authz-review
wip/popovers
wip/overlay-glass
wip/change-feed
wip/editor-modes
wip/composer-align
wip/cont-agenda
wip/agenda-merge
job/agent-conventions
wip/agent-conventions
wip/backend-misc
job/route-audit
wip/route-audit
wip/ui-batch
wip/heif-hardening
wip/grid-resize
wip/ask-page
wip/webmcp
job/deeplink-audit
wip/deeplinks
wip/shortcuts
wip/cont-tz-days
main
No results found.
Labels
Clear labels
No items
No labels
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
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
kayg/calternal#191
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Implement docs/DESIGN.md §42 exactly (owner grill 2026-09-26; read it first). Depends on #182 (Craft block vs text modes): merge dev once it lands. Slices, one commit or more each:
Screenshots desktop hover/menus/picker/floating toolbar and phone text/block bars, light and dark, for Claude's review.
Starting #191 on branch
job/block-actions, based one976bff6c74b3131266b3baeb33ab318edccd46e(dev). I have read §42 and confirmed #182 has not landed ondevyet. I am beginning with slices 1 and 4 as instructed; I will mergedevbefore final gates and handle dependent slices if #182 lands during this job.Finding for slice 1:
packages/ui/src/components/PillGroup.sveltealready provides the shared glass capsule, horizontal scrolling, keyboard toolbar semantics, and body portal. The live app editor had formatting commands inpackages/editor, butNoteEditorSurface.sveltedid not mount a formatting bar. I am reusingPillGroupand mounting desktop selection and phone keyboard bars in the app.Slice 4 decision: I kept the existing
calternal-remindersrecord envelope incrates/calternal-notes-core/src/reminders.rs(schema,blockId,trigger,state,revision,updatedAt) and addedsetterplusaudienceas additive fields. This keeps the lossless frontmatter projection compatible with existing records while making the new audience explicit. Reminder create/list/delete use stable Note and block IDs, strict RFC 3339 times, ETag guarded writes, and a 128-record per-Note bound. A picker with generic presets and the existing composer parser is being added before #182 integration.Build finding: the Notifications test build hit an existing compile error from
70c847eaincrates/plugins/files/src/index.rs:620:Ok(())was returned from aResult<bool, Failure>function. The unchanged-row fast path means the index row is current, so it now returnsOk(true). Verification:cargo test -p calternal-plugin-files --libpassed (88 passed, 0 failed).Slice 4 backend is committed as
3ddd98e959975d5835910735fbe90f33efa3d6b5. It projects Note reminder history and pause/restore state, resolves Everyone from current internal Shares and stable Files item fingerprints, previews each recipient's local delivery time and quiet-hours hold, and persists per-User Done/Snooze actions. Quiet hours are stored in the existing top-levelnotificationsUser settings section and default to 23:00–06:00 in the User's configured zone (UTC when none is configured); the setter's explicit time is never held. Snooze defaults to ten minutes and accepts 1 minute to 7 days. Verification:cargo test -p calternal-plugin-notifications --libpassed (17 passed, 0 failed);cargo test -p calternal-plugin-notes block_reminder_projection --libpassed (2 passed, 0 failed). OpenAPI and web checks are still in progress.Finding: the Notes E2E bound its server to 127.0.0.1 but navigated to localhost. On this host, getent resolves localhost to ::1 first, and Playwright returned ERR_CONNECTION_REFUSED. I changed this test harness base URL to 127.0.0.1 to match the IPv4 bind. The full production-build E2E run is in progress.
Correction to the Notes E2E finding: setting its public URL to 127.0.0.1 caused WebAuthn to reject the RP ID (
rp_id is not an effective_domain of rp_origin). I restored the localhost origin and added a Chromium host resolver rule to connect localhost to the server's IPv4 listener. This keeps the origin valid for passkeys while fixing the connection refusal. I am rerunning the E2E flow.Further trace of the connection refusal: Auth bootstrap logs the setup URL during build_live_app, before main binds the TCP listener. The Notes E2E returned as soon as it saw that log line, so it could navigate before /readyz was available. I added a readiness poll before launching the browser, and kept the localhost origin plus the IPv4 Chromium resolver rule. Retrying now.
Resuming after the planned VM restart. Branch: job/block-actions; checkpoint HEAD:
0bf913aa4d; working tree is clean. I have read the prior report comments and confirmed #182 is still open and its selection-mode commit is on job/editor-modes, not dev. I am continuing independent work now and will merge dev before final gates once the dependency lands.Slice 1 verification: the shipped FormatButton uses 44×44 px targets with 20 px glyphs for coarse pointers and 28×28 px targets with 18 px glyphs for fine pointers. Apple HIG buttons guidance confirms the general 44×44 pt hit region; its accessibility sizing table lists 28×28 pt as the macOS default button size. I added both source links beside the §42 measurements in commit
6dd63aa9.Test-runner finding: a component test named
FormatButton.test.tsran in Vitest's unit project and resolved Svelte's server entry, somount()was unavailable. The app config assigns browser resolution only to*.svelte.test.ts; renaming the test to that form selected the component project. The new button tests now pass, andbun run checkreportssvelte-check found 0 errors and 0 warnings.The phone action row is now a reusable row over the existing PillGroup. It keeps Make a note, Remind and Copy link visible but disabled for multi-selection, and keeps Move, Duplicate and Delete available. Focused verification: 5 test files, 8 tests passed; bun run check reported svelte-check found 0 errors and 0 warnings. Parent surface wiring is pending the #182 selection-mode change.
Progress (HEAD
469bc5b4): added the fine-pointer block hover action capsule and its component tests. It reuses the sharedPillGroup,FormatButtonand block action descriptors; targets use the existing 28 px fine-pointer and 44 px coarse-pointer metrics. Test output:Test Files 1 passed (1)/Tests 2 passed (2). Check output:svelte-check found 0 errors and 0 warnings.The component test caught a Svelte
effect_update_depth_exceededloop when root registration measured the anchor. The root callback now runs underuntrack; both tests pass. The editor host wiring still depends on #182 landing indev.Finding (HEAD
69e60600): typed local reminder time2026-03-29 02:30inEurope/Berlinfalls inside the spring DST gap. JavaScript normalizes that wall time to a later clock time, which would schedule an instant the user did not enter. The picker now checks calendar and local clock components after conversion and asks the user to choose another time when the wall time is missing.TZ=Europe/Berlin bun run test -- src/lib/editor/format/reminderDateTime.test.ts:Test Files 1 passed (1),Tests 3 passed (3).bun run check:svelte-check found 0 errors and 0 warnings.Add to this job (Claude review of #182 screenshots): the block selection ring sits flush against the text (no inner space). Draw it outset from the text box (about 6px on each side, radius matching the block surface) so text never touches the ring, and keep the drag handle aligned with the first line.
Finding after merging #182: the production Notes E2E exposed two integration gaps. The merged editor still mounts neither the desktop block capsule nor the phone block-action row. The selection cue also computed
outlineOffset: 0px, matching the screenshot review note that the ring touches the text. I added production E2E assertions for both toolbars, a 6px ring gap, and disabled single-target actions for Shift-click multi-selection; wiring is in progress.Full workspace test after merging the latest
devinto #152 on 2026-09-26:cargo testfailed incalternal-plugin-notifications::reminders::tests::reminder_paths_and_block_ids_are_constrained:date_from_daily_note_path("Notes/Journal/20260924-dailynote.md")returnedNone, but the test expectedSome("2026-09-24").Notes/Journal/and validates the result withcalternal_notes_core::daily_note_path, which now returns the canonical flatNotes/YYYYMMDD-dailynote.mdpath per DESIGN §40.Notes/Journal/%-dailynote.mdand rejects paths outsideNotes/Journal/. A Log reminder stored in a flat Daily note therefore cannot be found or delivered.This crosses into notifications behavior. I am holding that change pending scope direction; #191 is the existing owner issue for block reminders.
Production Notes E2E evidence: after selection, menu, collaboration and screenshots passed, the final uncaught-error check found from the block menu's Escape path and repeated Svelte effect-depth errors when the floating text toolbar mounted. The toolbar root callback now updates outside the PillGroup effect, and the menu keeps its data object through close. I am rebuilding and rerunning the production E2E against these fixes.
Production Notes E2E evidence: after selection, menu, collaboration and screenshots passed, the final uncaught-error check found a null items read from the block menu Escape path and repeated Svelte effect-depth errors when the floating text toolbar mounted. The toolbar root callback now updates outside the PillGroup effect, and the menu keeps its data object through close. I am rebuilding and rerunning the production E2E against these fixes.
The production Notes E2E now passes: notes e2e: ok. It covers the desktop block toolbar, multi-select action disabling and menu cleanup, the 6 px selection ring, phone action and text bars in both themes, and the existing Notes collaboration flow. Targeted block menu tests also pass (3/3).
A real editor test found that Copy link could not resolve a list-item container position (ensureAnchorAt returned null). The anchor resolver now finds the item's first text block, and refuses to insert an anchor into a code block where it would become visible code. Both reminder/anchor tests pass.
Finding during the production Notes E2E: Back returned to
/notes/<source-id>with the source titleProject Atlasand browser history intact./n/<id>is the public stable alias and redirects with replaceState to/notes/<id>, so the new E2E helper's/nexpectation timed out despite the app route being correct. The helper now waits for/notes/<id>; the production flow is running again.Finding in the production Notes E2E: Make a note, Back, and opening the existing linked Note all passed after the route assertion matched
/notes/<id>. Returning from that linked Note remounted the source editor and cleared its prior selection anchor; the later Shift-click selected onlyGoals(one.cal-block-selectednode). I am updating the E2E to select its range start again after the Note navigation, then rerunning the full production flow.Production Notes E2E passed on the real local server after the route and range-start assertions were corrected. Exact output:
notes e2e: ok. It covers Make a note creation, Back to the source Note, opening the existing linked Note, reminder creation and chip rendering,Lstable block links, multi-select action states, keyboard selection, and Notes collaboration. I committed the E2E changes and this issue's desktop/phone screenshots ine24233b1(test(web): cover block actions and capture issue screenshots).Finding from the first local-server adversarial attempt:
attack.pystopped before the new Note reminder probes at its existing quiet-hours assertion, withTypeError: check() got an unexpected keyword argument 'expect'. Multipleexpect=call sites were already present, butcheck()did not accept expected statuses. I added the same expected-status handling used byattack2.py; the current run is finishing its remaining probes, then I will rerun with the corrected helper. The attempt also reported a Photos shared-timeline mismatch under concurrent host load; I will verify that separately before classifying it.The Photos timeline and Files 404 findings were cascading setup failures from the same probe exception:
attack.pycreatesPhotos/2024/2024-06-02/adversarial-photo.jpglater in its Photos section, but the TypeError at the earlier quiet-hours check stopped before that upload.attack2.pythen checked the missing fixture. I will rerun itsisolationandpluginssections after the helper fix, with the fixture present, to verify the cross-Plugin behavior.Merged the latest
devintojob/block-actionsas6cf75175before final verification. The OpenAPI schema conflict was additive: I kept this branch'sRecipientPreviewand reminder response field, retaineddev'sRangeMetrics/RangeReportand search 401/403 responses, then regeneratedpackages/api-client/src/generated.tsfrom the combined contract. The contract parses and has no unresolved merge values. The full adversarial runner is now building and will wait for another worktree's active Chromium process before browser probes begin.Finding after the
devmerge: theFloatingSurfaceexport moved belowMenuondev, while this branch still exported it at its old position. Git kept both lines; Vite 8.3.0 then failed the production build withDuplicated export 'FloatingSurface'inpackages/ui/src/index.ts:6and:21. I removed the old duplicate and kept the relocated export. Verification:bun run --cwd apps/web buildexited 0 and wrote the production site tobuild. Fix committed as5037ad32.Finding after the
devmerge:authz_matrix.pystopped before sending its authorization requests because the new/api/v1/analyticsoperation had no identity classification. The handler callsdata_scope_userand reads the authenticated User's data, so I added it to the matrix's data prefixes.python3 -m py_compile tests/adversarial/authz_matrix.pypassed, and a focused classification check returnedstandard and admin only. Fix committed as596f30ea. The in-flight run had already loaded the old mapping, so I will verify the matrix with a clean local server after its remaining probes finish.Resuming #191 after the VM restart. Branch
job/block-actionsis clean at596f30ea87bed6ca8abeab94cc8da1313ce725fe; currentdevisf6418fc72d750d941f23554ad16381f6dd400fd6and is merged in6cf75175. I read §42 and the prior report comments. The pending task is to finish the local-server adversarial verification, then run the final workspace gates, clean generated build output, and post the final report.Adversarial finding:
POST /api/v1/notes/{id}/reminderswithaudience: "public"returned 422 from Axum JSON deserialization, while the probe expected 400. The route documents 400 for semantic validation but does not document the extractor's invalid-enum 422. I will update the probe and OpenAPI response list to record the actual malformed-field response. The same run did not return the semantic-search fixture within its 120-second deadline; I am classifying that timeout as load/model latency and will confirm from the final runner output.Final Clippy finding in the touched Notes API file:
clippy::redundant_closureatcrates/plugins/notes/src/reminders_api.rs:243for.ok_or_else(|| ApiError::internal()). The lint gate is-D warnings; I will use the associated function directly and rerun Clippy.Resolved the Clippy finding in commit
98a8c008by passingApiError::internaldirectly took_or_else. Focused verification passed:cargo clippy -p calternal-plugin-notes --all-targets -- -D warningsfinished successfully.Finding after the latest
devmerge:bash packages/api-client/check-generated.shfound that the four Public Edit operations in the merged OpenAPI/client were missing their standard 429ErrorEnveloperesponses. The server's generated document includes these rate-limit responses, so I regenerated and am staging the contract and TypeScript client before rerunning the consistency check.Merge decision for the public-guest editor: preserve the incoming Home-relative link, note-card and attachment restrictions. Hide the #191 block-action controls and
Lshortcut in that editor because the public-guest session has no authenticated adapters for Make a note, Copy link or Remind. Text editing and formatting remain available. This keeps the public share boundary while retaining block actions for account-backed Note editors.Completed #191 on
job/block-actions.Built
Implemented shared formatting capsules and block actions for desktop and phone: hover controls, the block menu, Make a note, block-link copying, and block reminders. Added reminder persistence and APIs, fire-time recipient resolution, per-user Done/Snooze, quiet-hour delivery, settings, inbox handling, and OpenAPI/TypeScript client updates. Added the Apple HIG capsule metrics to
docs/DESIGN.md§42, adversarial probes, and 37 real-build screenshots inapps/web/artifacts/block-actions-191/.Files include
apps/web/src/lib/editor/format/*,apps/web/src/lib/notes/{NoteEditorSurface.svelte,NoteView.svelte,editorHost.ts,api.ts}, the editor and notification settings,crates/plugins/notes/{src/reminders_api.rs,src/store.rs,migrations/0012_block_reminders.sql},crates/plugins/notifications/{src/block_reminders.rs,src/routes.rs,src/store.rs,migrations/0003_block_reminders.sql},crates/calternal-notes-core/src/reminders.rs,contracts/openapi.json,packages/api-client/src/generated.ts,apps/web/e2e/notes.mjs, andtests/adversarial/attack.py.Head SHA:
5993a437d941be37c433f9198dfc5e684e4e77f1.Gates
cargo fmt --check: exit 0, no output.cargo clippy --all-targets -- -D warnings:Finisheddevprofile [unoptimized + debuginfo] target(s) in 21.40scargo test: exit 0. Aggregating its 69 suite summaries: 1,246 passed, 0 failed, 12 ignored. The Notes suite output wastest result: ok. 95 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 63.63s; Notifications wastest result: ok. 17 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.40s.bun run --cwd apps/web check:svelte-check found 0 errors and 0 warningsbun run --cwd apps/web test:Test Files 79 passed (79);Tests 564 passed (564).bash packages/api-client/check-generated.sh:🚀 ../../contracts/openapi.json → src/generated.ts [359.8ms]; no generated diff.Removed 7551 files, 9.2GiB total;apps/web/buildwas deleted.Adversarial findings and gaps
After merging
devthrough21ee397d, the live-server suite covered 237 OpenAPI operations across four identities (948 requests). The server stayed alive; hostile-byte checks had 0 findings; the restart probe had 0 findings. The runner exited 1 on two non-SLOWfindings, both recorded on existing issues: a Journal log-rewrite storm returned[-1, 200, 412](#205), and public thumbnail requests returned{256: 404, 1024: 404}after thumbnail generation had already timed out at 30 seconds (SLOW) (#213). The earlier bookmark-capture timeout finding is tracked on #210. RemainingSLOWtimings occurred on the shared host and are treated as load.The semantic recall timeout reported earlier on #208 returned the expected
Apartment huntingNote in both later full adversarial runs.Decisions where DESIGN.md was silent
text/plainschema-error response. OpenAPI and the TypeScript client now declare this response.Claude review (block-actions-191 screenshots). Not merged yet:
Re-take the phone and picker screenshots after the fixes.
Continuation start: branch
job/block-actions, HEAD5993a437d941be37c433f9198dfc5e684e4e77f1;devat21ee397d5c3d24f6355d90b17c2e36b2cf76615ais already merged in this branch. I am fixing the five points in Claude's latest review and will commit each fix separately, then re-take the phone and reminder-picker screenshots.Owner 2026-09-27: the reminder picker 'needs to look way better, it doesn't fit our app aesthetic'. Redesign it to this spec (references: Things 3 'When' popover, Todoist web date picker, Linear due-date popover):
Screenshots: popover near the right edge (proves no clipping), with typed input, with a quiet-hours recipient, existing reminder; light and dark; 1440 and 390.
Owner 2026-09-27 (screenshot of the phone block bar showing 'Make a note / Remind me / Copy li…' with text): the bottom capsule shows ICONS ONLY, no text. Labels on demand, implemented once in the shared tooltip/capsule so every icon capsule on touch behaves the same (tray, pills, block bar):
Also record the rule in DESIGN §34 (touch tooltips) in ASD-STE100.
Continuation on job/block-actions. Starting HEAD
5993a437d9; current dev iscf142cb41e. The worktree is clean. I am implementing the latest review items: anchor rendering/writing, phone tray replacement, presence de-duplication, localized time formatting, reminder picker redesign, and shared touch-and-hold tooltips; I will commit each fix separately and re-take the requested production screenshots.Diagnosis for the leaking ^iefhey (Claude): packages/editor/src/anchor.ts applyBlockAnchor with placement 'after' writes the id on its own line ('\n^id') after the block. For a paragraph that line is a soft break INSIDE the same paragraph; when the paragraph is later continued (here 'Scope confirmed with the leads.'), the id is no longer at the end, so the parser keeps it as text. Fix at the source: for paragraphs, list items and headings, write the id inline at the end of the block's last line (' ^id'); keep the own-line form only for blocks that need it (tables, code fences, quotes). The serializer must always move a block's anchor to its end on write, and the parser should also recover a mid-paragraph '^id' line followed by more text (repair on load, preserving bytes elsewhere). Tests: continue a paragraph after its id was assigned, from the editor and via collab; round-trip keeps exactly one trailing id.
Owner 2026-09-27 (screenshot of the desktop block controls):
Starting continuation of #191 on branch job/block-actions.
Base:
21ee397d5cCurrent head:
5993a437d9Finding:
packages/editor/src/anchor.ts::applyRawBlockAnchorTargethandles everyplacement: 'after'target by inserting\n^<id>after the block.packages/editor/src/markdown.tsonly recognizes a following anchor line when the full line contains anchor tokens, so adding text after that line makes^<id>ordinary paragraph text. This matches the leak in the reviewed screenshot. I am adding a regression for paragraph continuation and fixing the source writer/parser plus editor collaboration path.Finding: the focused Markdown and real editor anchor tests pass (198 editor tests; 3 Svelte anchor tests). The full editor suite then exposed that inline anchor ownership must stay in the shared Rust/TypeScript Markdown contract: six vector outputs still expect the old own-line spelling, and schema-equality cases see owner attrs on newly parsed headings and trailing ids. I am updating both readers/writers and the shared vectors together; the typecheck also found four
Editor.svelteattributes set toundefined, which I will fix as a separate small gate repair.The cross-language property round found that the Rust reader treated
^idtextas a stored block anchor while the editor kept it as text. Rust now requires a separator before continuation prose, matching the editor. I added the rule to the Markdown contract, refreshed both vector sets, and verifiedcargo test -p calternal-collab --test cross_languagepasses, including 5,000 generated cases per family.Note presence used each Yjs client id as a peer key, so the same person appeared more than once when they opened the note in multiple tabs. Presence now keys by immutable User ID, omits other tabs for the local User, and keeps client-id fallback only for older states without an ID.
collab.test.tscovers both cases; the focused suite passes (7 tests).The reminder chip used
Date.toLocaleString()in its accessible label, which exposed a machine-formatted timestamp, and the picker built a local ISO-like label by hand. Both now use shared@calternal/uiformatters. The chip uses the device IANA zone; recipient rows retain their server-computed local date and zone, with the clock localized by the shared formatter. Tests cover Europe/Berlin, America/Los_Angeles and localized wall clocks; the focused suite passes (11 tests).Finding: the presence de-duplication change made the account id required, but public-link guest identities do not have one.
bun run --cwd apps/web checkreported the missingidat the guest provider boundary. Made the account id optional and passed an empty local-id fallback into the de-duplicator; the web check then passed with 0 errors and 0 warnings. Committed as8dc73106.Progress: the phone toolbar now uses icon-only controls and replaces the bottom mode tray while a block is selected. Desktop action order is
→, clock,⋯; the menu stays 8 px from the selected block and flips to the left when the right side has no room. Block selection now uses a tinted fill without a border or outline, with the keyboard focus ring rule kept separate. Focused block action tests passed (3/3);bun run checkreported 0 errors and 0 warnings. Commit:a85ccc3c.Progress: the shared warm tooltip now supports a 450 ms touch hold. A held finger can slide across actions; release leaves a 900 ms peek and suppresses that gesture's click. A normal tap still runs the action. The shortcut label stays in
aria-label, and the icon buttons disable text selection/callout and use a reduced-motion-aware press scale. The focused touch gesture test passed (1/1);bun run checkreported 0 errors and 0 warnings. Commit:cce597fb.Finding: the reminder preview endpoint labels the setter as
You. The audience avatar stack used the first character of that short label, so it showed Y instead of the account's real initials. It now maps the setter id back to the current account display name; a focused test checks Kay and Grace Hopper, and the E2E flow asserts K/G are shown with no Y. Focused helper tests passed (4/4), andbun run checkreported 0 errors and 0 warnings. Commit:c4b209fd.Production-build local E2E evidence after merging dev: creating a block reminder added an active reminder with a generated blockId in the Note frontmatter, but GET /api/v1/notes/{id} did not show the matching raw
^block-idin the Markdown body within the 15 s save poll. This leaves the reminder target without its durable file anchor. I am tracing the editor transaction and source-aware save path before rerunning the screenshots.Correction to the previous finding: code inspection showed that the E2E poll used
note.body.split("\n\n")[0], which is the YAML frontmatter added by the reminder. It therefore never checked the Markdown body. The reported persistence gap is not confirmed. I am updating the probe to strip frontmatter before checking the raw^block-idand will rerun it.Clarification: the reminder anchor poll searched the full Note body and passed; the raw
^block-idwas present. The later collaboration save poll failed because it splitnote.bodyat the first blank line and inspected the YAML frontmatter instead of the Markdown body. My earlier persistence-gap report was incorrect. I am fixing that E2E predicate and will rerun the local production flow.Adversarial finding (real local server, production browser build): a fresh Note with one body paragraph accepts an HTML clipboard paste containing one paragraph and one image. Typing one short suffix and pressing Ctrl+Z then Ctrl+Shift+Z duplicates the pasted text/image in the live Note. One reproduction changed saved Markdown from one pasted paragraph/image to three pasted paragraphs/images, and duplicated the typed suffix. This also reproduces without the block-anchor repair actions, so it is independent of the #191 anchor fix. I am tracing the undo/update path before changing code.
Follow-up to the paste-history finding: I corrected the browser reproduction so it enters text mode with the documented block-to-text gesture before placing the caret and pasting. In a fresh Note, a single HTML clipboard paragraph containing one image, followed by one typed suffix and Ctrl+Z / Ctrl+Shift+Z, still reproduces persisted duplication: a paste that starts with one image is saved with three image embeds (the minimal run also showed duplicated pasted text/suffix). The text-only clipboard variant does not reproduce.
The behavior points to the collaboration room’s delete/conflict-shadow merge path in
crates/calternal-collab/src/session.rs(update_deletes_blockandmerge_conflict_shadow); source inspection and the persisted result are consistent with the undo deletion being shadowed, then the redo update being merged into the live room twice. This is a likely root path, not a proven line-level diagnosis. I did not change that crate because fixing it would alter another crate’s behavior beyond this web-editor job. The finding is filed for a collaboration-owner fix and should get a server-level regression case there.Adversarial finding (fresh Note on a real local server and production browser build): one HTML text paragraph pasted into a Note, followed by a short typed suffix, survives one Ctrl+Z / Ctrl+Shift+Z pair. With 500 undo keystrokes followed by 500 redo keystrokes, the live editor returns to the original paragraph. After a 2-second flush window, GET /api/v1/notes/{id} also returns only the original body (
# 186 isolated editor history/history start); the pasted paragraph and suffix are absent. The fixture contains no image and does not perform block-anchor actions, so this is separate from the image-paste duplication reported above. This is persisted Note data loss under a repeated collaboration-history storm.The behavior points to collaboration room update processing. I have not proven the exact server line. I am not changing
calternal-collabbecause that would change another crate's behavior beyond this web-editor job; this needs a collaboration-owner fix and a regression test there. I will keep the minimal reproduction available as an opt-in adversarial probe and keep the default browser pass focused on the normal one-pair history round trip.Post-merge production E2E found that a double-click on a linked heading could enter text mode, then Escape briefly restore the block selection before a late Chromium editor focus cleared it. The event trace showed
Goalsselected during the Escape handler, followed by focus returning to.cal-proseand removing the selection. I added a one-event focus guard for that exit path and changed the test to double-click.linked-heading-textbecause the full-width heading locator had been hitting its inline Copy link control.bun run --cwd apps/web checkpassed (svelte-check found 0 errors and 0 warnings), and the production E2E reached and passed “double click edits and Escape returns to selection”.The post-merge real-local-server adversarial run found one non-SLOW analytics consistency issue. The probe ran 90 analytics reads and 30 log writes in 32 threads; four reads timed out, then its two post-storm day-metrics reads disagreed (
analytics storm consistency: two reads after the storm disagree). The local server stayed alive. The same run had concurrent perf and build jobs on the shared host, and the server was using 50–66% of one core during this section, so load may contribute, but this is not classified as SLOW-only. It touches Analytics plugin behavior outside the block-actions UI work; I filed the evidence without changing that crate.The post-merge real-local-server adversarial run found a public collaboration protocol-rate-limit gap. The probe opened a valid public Edit WebSocket, sent 301 empty binary frames (the documented probe comment says malformed frames share the per-link/IP budget), and observed that the socket did not close within 10 seconds:
public collab frame rate limit: the 301st frame did not close the socket. This is a non-SLOW protocol-abuse result. It touches public collaboration behavior outside the block-actions UI work; I filed the evidence without changing that behavior.Continuation #191 on
job/block-actions. Starting HEAD:d9b6a1d9ac6d340e15be246723d6b77bbc407902. Currentdev:0558cc4ecaeb7f51af1e06acd31870b5f87b9f00; common base:57d1752c990e1509dfdb7faed55815158dbb2c57. I have read the repository contract, DESIGN §42, CONTEXT.md, and the issue history. I am mergingdevonce now, then will run the requested final verification and report any remaining work instead of extending scope.Finding during final production screenshot capture (head
72d03077):bun apps/web/e2e/notes.mjs --screenshots artifacts/block-actions-191-finalcaptured the desktop action menu, reminder picker (typed, quiet-hours, existing), hover tooltip, selection and formatting states in both themes. The run then exited 1 before fresh phone captures: the mobile context timed out after 10 seconds waiting for.cal-prosetextContinued from another tab.. Per the finish instruction, I did not tune or modify the E2E probe. I copied the existing production phone captures from the prior reviewed run into the ignored artifact directory for the issue attachment set.One time-boxed adversarial round after merge
72d03077(ADVERSARIAL_SKIP_WEB_BUILD=1 timeout -k 30s 15m tests/adversarial/run.sh) reached the 15 minute cap and exited 124.Completed sections: the authorization matrix passed all 237 OpenAPI operations across four identities (948 requests); the editor round passed its Markdown size, browser paste/history, collaboration, concurrent edit and restart cases; the search storm had 0 failures; semantic recall returned
Apartment huntingfor the transport-nearby housing query.The API round was still running at the cap. Every finding emitted before termination had the runner's
SLOWmarker: log write 5.1 s, Files Note rename 7.4 s, Task create 8.3 s, task tick 7.2 s, task attach 5.0 s, DAV Basic app password 9.6 s, and DAV discovery 10.5 s. I treated these as load per the owner rule. The later API sections and the final restart probes did not run; I did not restart the round.Final report — #191
Built
Implemented the #191 slices already committed on
job/block-actions: shared text/action capsules, desktop block controls and menu,Lblock links, Make a note, phone block mode, reminder picker/API/frontmatter, fire-time audience resolution, per-User Done/Snooze, quiet-hours handling, settings, and OpenAPI/client updates.Key files:
apps/web/src/lib/editor/format/*;apps/web/src/lib/notes/{NoteEditorSurface.svelte,NoteView.svelte,editorHost.ts,api.ts}; editor and Notifications settings;packages/editor/src/{anchor.ts,markdown.ts};crates/calternal-notes-core/src/reminders.rs;crates/plugins/notes/{src/reminders_api.rs,src/store.rs,migrations/0012_block_reminders.sql};crates/plugins/notifications/{src/block_reminders.rs,src/routes.rs,src/store.rs,migrations/0003_block_reminders.sql};crates/calternal-collab/src/markdown.rs;contracts/openapi.json;packages/api-client/src/generated.ts;docs/DESIGN.md;apps/web/e2e/notes.mjs;tests/adversarial/attack.py.Head and push
Head:
72d03077c7d37f2eb5c177a1bfe621d99daf5b6a(dev merge commit).git push origin job/block-actionsoutput:Everything up-to-date.Gates
cargo fmt --check— exit 0; no output.cargo clippy --all-targets -- -D warnings— exit 0. Verbatim final line:Finisheddevprofile [unoptimized + debuginfo] target(s) in 8m 45scargo test— stopped at the 60-minute cutoff while the Files suite was still running. Last observed test output:test tests::slow_upload_keeps_its_slot_while_bytes_arrive ... ok. No final exit status was produced.bun run --cwd apps/web check,bun run --cwd apps/web test, andbash packages/api-client/check-generated.shwere not reached.cargo cleanoutput:Removed 17085 files, 14.8GiB total. Removedapps/web/buildandapps/web/.svelte-kit/output.Adversarial round
One 15-minute run exited 124 at its timebox. It completed the 948-request authorization matrix, editor round, search storm (0 failures), and semantic recall. Every API finding emitted before the cap had the
SLOWmarker. The later API and restart sections did not run; I did not restart the round.Screenshots
Uploaded 28 PNG issue assets for desktop and phone states in Paper White and Tokyo Night. They cover hover actions, menus, formatting capsules, reminder typed/quiet-hours/existing states, and phone block/text bars. The fresh production E2E run captured the desktop set, then exited 1 before fresh phone capture: mobile timed out after 10 seconds waiting for
.cal-prosetextContinued from another tab.. The phone screenshots attached here are from the prior production capture after the reviewed UI fixes. No new PNGs were committed.Remaining work
Finish
cargo test, run the web check and test gates plus generated-client consistency, complete the remaining adversarial sections, and refresh the phone screenshots after fixing or diagnosing the E2E timeout.Decisions where DESIGN.md was silent
setterandaudienceto the existing lossless frontmatter envelope. Quiet-hour settings live in the existing top-levelnotificationsUser settings section; a missing zone defaults to UTC.Starting work on branch job/block-actions at
72d03077c7; base dev is21d985bf7a. I read CLAUDE.md, CONTEXT.md, docs/DESIGN.md §42 and the issue. I will fix selected text styling, reminder picker details, verify the missing-space report, then merge dev once and run the requested gates/screenshots.Finding: the screenshot's blue underline is the real internal link created by the earlier Make a note step in apps/web/e2e/notes.mjs. The selected-state CSS in NoteEditorSurface.svelte only sets the tint/background; it does not set text color or decoration. I will capture block selection on plain text and assert computed text styles are unchanged before/after selection, while keeping linked-block behavior covered separately.
Progress: the picker now resolves 18:00/20:00 defaults and shows each preset's resolved clock via the shared User time formatter. It reads up to two distinct, per-User times from the existing local reminder history. The input uses a filled surface with a focus ring and no border. E2E assertions now cover preset times, learned history, a viewport-edge flip, selected text style, and where the collaboration edit lands relative to the callout.
E2E finding: block selection resolves a list paragraph to its parent list item, so the first style assertion targeted a node that does not receive the selection decoration. I updated the test fixture with a plain top-level paragraph; the assertion and fresh selection captures now target the actual selected paragraph. The first run stopped at this test assertion before reaching the collaboration check.
Finding: the two-context production-build E2E edit did not reproduce the missing separator. “Update from the field team.” remained in the “Retire the legacy export tool” list item; the callout body retained “Decision” and did not contain the inserted text. The test also checked the saved Markdown after both edits. This points to the reported screenshot being a fixture/capture artifact rather than a block merge or collaboration defect. I am keeping the corrected placement assertions as a regression check.
Fresh screenshots from the production-build Notes E2E on this merged branch. These are issue attachments and are not committed.
Gate finding: the single full
cargo testpass reported one failure in the server'swire::tests::live_apps_run_in_separate_processeswrapper. Its childwire::tests::full_app_setup_session_config_and_backuptimed out waiting for/api/v1/admin/configto observe theinstance_name = "Updated"file change within the test's 5-second watcher window (crates/calternal-server/src/wire.rs:2904-2922). The child ran for 14.87 seconds and returnedElapsed(()); preceding Rust tests passed. This is outside the block-actions changes. I am not rerunning the full gate under the one-pass instruction.Final report
Head:
04506cb9a12faffe65d52ec0e322f42aea5a9eef(working tree clean). Commits:caccf225, merge6ed1a463,40a6725d,04506cb9.Built
devonce and kept the sharedMENU_ICONSmap. Regenerated the OpenAPI client. Fresh phone and desktop screenshots are attached in the preceding issue comment; none are committed.Issue-specific files:
apps/web/src/lib/editor/format/BlockReminderPicker.svelte,apps/web/src/lib/editor/format/reminderTimeHistory.ts, andapps/web/e2e/notes.mjs. The requesteddevmerge also carries the current contract/client changes.Gates
cargo fmt --check: passed, exit code 0, no stdout.cargo clippy --all-targets -- -D warnings: first attempt hit a missing shared sccache temp directory under another worktree. Retried withRUSTC_WRAPPER=and a worktree-localTMPDIR; passed:cargo test: failed only in the server’s nested live-app test. The child timed out waiting for the config watcher’s 5-second reload window atwire.rs:2904-2922:bun run check:bun run test:packages/api-client/check-generated.shpassed:Production-build Notes E2E:
notes e2e: ok.Known gaps and decisions
The one adversarial round reached its 45-minute cap (exit 124) with 335 reported entries, mostly SLOW latency markers. It also recorded non-SLOW timeouts: 16 of 24 concurrent Journal PATCHes got no response within 30 seconds; the other eight returned 412 after 25.7 seconds. Calendar and DAV requests also timed out, and a recurring-log check found the same Event identity for two occurrences after a timed-out write. Later, the feed proxy returned
502 local adversarial server is unavailable; the harness could not finish isolation/collaboration probes before the cap. These findings are filed for triage in #267. The single round was not repeated.The design does not define where reminder-use history lives. I kept the two learned times in localStorage scoped by User ID; the choices do not sync between devices. The new plain paragraph is test fixture data only and is placed after “Goals” so it does not change the original range-navigation checks.
Cleanup completed:
cargo cleanprintedRemoved 17895 files, 13.4GiB total;apps/web/build/was deleted. Screenshots remain attached to #191, not in Git.Starting final fixes on job/block-actions, based on dev merge-base
7b169436e5. Review head:04506cb9a1. I will fix reminder preset chronology, desktop action-pill placement, merge dev once, and rerun the isolated watcher test as requested.Finding: BlockReminderPicker.svelte resolved fixed preset times on open but kept the static label 'This evening' and static row order. At a 20:45 local clock, the 20:00 row resolves to tomorrow, while tomorrow morning sorts before it; near 23:30, the later-today fallback can move into the next day. I added a fixed-clock regression test for 08:00, 18:30, 20:45 and 23:30; the test failed on the missing resolver before implementation and now passes.
Finding: BlockHoverActions.svelte clamps against the viewport only (). When the block's right-side pill does not fit, the left-side fallback can start around x=188 and cross the sidebar boundary, matching the reported x≈200 placement. The toolbar is portalled to body, so its placement needs the content bounds explicitly.
Finding: BlockHoverActions.svelte clamps against the viewport only (minX = 8). When the block right-side pill does not fit, the left-side fallback can start around x=188 and cross the sidebar boundary, matching the reported x≈200 placement. The toolbar is portalled to body, so its placement needs the .editor-surface content bounds explicitly.
The ignored config-reload watcher test passed alone 3 times with its existing 5-second timeout: run 1 passed in 6.47 s, run 2 in 3.95 s, run 3 in 13.11 s (test-process elapsed values). No timeout occurred, so I left the deadline unchanged.
Finding: the production notes E2E measured the 850 px case with a full-width block at x=302.8–816 and its action pill at x=714–808, so the pill covered the block when neither horizontal side fit inside the editor column. The fallback now aligns the pill with the block right edge and moves it above or below; the focused component test passes 3/3.
The production notes E2E had two time-dependent assumptions that no longer hold after hiding past/duplicate presets: it required 4 rows and clicked Later today. At Sunday 23:17 local, only Tomorrow morning and Tomorrow evening are distinct future standard presets; Later today is past and Next week duplicates tomorrow morning. The E2E now accepts 2–4 unique rows and clicks the first available standard preset.
E2E finding: the collaboration probe's generic
dblclick()targeted the center of a full-width paragraph. For short list text, that point is whitespace; Chromium selected the paragraph break into the next block, andEndsometimes placed the caret in that next block. The probe now double-clicks actual text and asserts that the caret stays in the intended block before typing. A production notes E2E run completed successfully; the corrected gesture and layout assertions are being rerun before final gates.E2E finding: the second collaborative edit target was below the 900 px viewport (
y=974). Coordinate-based Playwright clicks do not scroll, so the interaction hit the page and left focus on the live-region status node. The E2E now scrolls each target into view before deriving pointer coordinates. This is a probe issue, not a production editing failure.Verification finding:
bun e2e/layout-sweep.mjs --only notechecked 28 screens. The new block-action bounds assertion passed for desktop with the sidebar open and collapsed. The existing note route still reports CLS 0.054 at 1440/open (limit 0.05), and the mobile sweep reports the Linked mentions label/icon vertical alignment at about 1.0 px on the 390 px note and menu-note screens. These are outside the block-action files. One later notes E2E also received a 200 reminder-preview response containing only the owner after sharing the quiet-hours recipient; a prior full notes E2E run passed that recipient flow. I am reporting both as verification gaps and leaving notification behavior outside this issue.#191 finished on
job/block-actions.Head SHA:
821bac40518ca92f43ae6e8a96d05290d380e497.devwas merged once before the final gates. Conflict resolution kept both sides inapps/web/src/routes/+layout.svelteandtests/adversarial/attack2.py.Built
Issue-specific source and test files:
apps/web/src/lib/editor/format/reminderDateTime.ts,BlockReminderPicker.svelte,reminderDateTime.test.ts,BlockHoverActions.svelte,BlockHoverActions.svelte.test.ts,apps/web/e2e/layout-sweep.mjs, andapps/web/e2e/notes.mjs. The dev merge also resolvedapps/web/src/routes/+layout.svelteandtests/adversarial/attack2.py.Final gates
cargo fmt --check— exit 0; output was empty.cargo clippy --all-targets -- -D warnings— exit 0:cargo test— exit 0. The following per-suite summary lines are verbatim from its output (72 suites, 1,318 passed, 0 failed, 12 ignored):bun run check— first attempt found the readonly-propertydeletetyping error in the new test cleanup. Replaced it withReflect.deleteProperty; the final rerun exited 0:bun run test— exit 0:bash packages/api-client/check-generated.sh— exit 0:Adversarial and visual checks
The one time-boxed broad round found one authz response-order mismatch (
PUT /api/v1/admin/configfor a standard user returned 422, expected 403), recorded on #268.Calendar Event from Logtimed out at 30 seconds while multiple jobs were loading the shared host; the server stayed alive and later Calendar/Journal calls completed, recorded on #250. The media probe did not see a thumbnail within its 10-second wait under the same load; that observation is on #264. These runs do not establish quiet-host failures. Most other broad-round reports were SLOW load markers; hostile-byte and restart probes reported zero findings.The broad runner used the prebuilt server override, so
target/debug/calternalwas absent when the CLI subsection started. I builtcalternal-cliand ran the missing CLI subsection against a real local server:The notes E2E completed successfully once. Later full reruns were unstable in recipient preview and editor focus setup. The note-only layout sweep checked 28 screens and passed the new block-action bounds assertion; it also flagged existing CLS 0.054 and about 1 px Linked mentions icon/label alignment at 390 px. These are not block-action placement failures.
Decisions
Later todayuses 18:00 if it is still ahead; after that, it uses the next whole hour if that remains the same local day, and is hidden if rounding crosses midnight.This eveninguses 20:00 today when future, otherwise it becomesTomorrow evening. All visible presets are future, chronological, and duplicate instants are collapsed.Screenshots:
Continuing the accepted #191 work on
job/block-actions. Starting branch HEAD:821bac40518ca92f43ae6e8a96d05290d380e497; localorigin/devbase at start:976b804f99188feb300e391c1942836599e2d429. I am fetching and integratingorigin/devonce, then will run the requested gates, push this branch, and report the exact results.Gate finding after integrating
origin/dev:bun run --cwd apps/web testreported 1 failed, 101 passed; the failed assertion expectedformatLocalClock('09:30', 'de-DE')to return9:30, while merged UI commit60de3ef7now intentionally pads system 24-hour labels and returns09:30. I kept the formatter behavior and aligned that stale expectation with the merged behavior. Focused verification passed:Test Files 1 passed (1)andTests 17 passed (17). I did not rerun the full web suite because this job requires one full gate run.#191 continuation complete
Branch:
job/block-actionsMerged
origin/devonce at976b804f99188feb300e391c1942836599e2d429. Final HEAD:16f5364f4da19be7b8cf505066dc6176cff70a5a. The branch was pushed; origin already had this exact HEAD.Integration
Resolved the Notes E2E, bottom chrome, and adversarial probe conflicts while preserving both sides: reminder and block-action checks remain; CSP checks and mode preloading remain; the phone block bar still suppresses the mode tray; direct adversarial probes reach the Rust server and keep the public Origin. Regenerated OpenAPI and the typed client with
packages/api-client/check-generated.shafter building the web SPA; the script exited 0.The full web test gate found the existing
de-DEclock expectation stale against merged upstream commit60de3ef7(system 24-hour clocks are now padded). I kept the formatter behavior and changed the expectation to09:30. The focused file passed:Test Files 1 passed (1)andTests 17 passed (17).Gates
cargo fmt --check: exit 0, no output.cargo clippy --all-targets -- -D warnings: exit 0. Final output:Finisheddevprofile [unoptimized + debuginfo] target(s) in 8m 30s.cargo test: exit 0; 72 suite summaries, 1,339 passed, 0 failed, 12 ignored. Final output excerpt:test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s.bun run --cwd apps/web check: exit 0.svelte-check found 0 errors and 0 warnings.bun run --cwd apps/web testgate output:Test Files 1 failed | 101 passed (102);Tests 1 failed | 667 passed (668). The one failure was the stale clock expectation above. The focusedtime.test.tsrun passed after the update; the full suite was not rerun because this job calls for one full gate run.Adversarial round
Ran the real-server probe with
ADVERSARIAL_ATTACK2_ONLY=1 ADVERSARIAL_SKIP_WEB_BUILD=1. The round-one reminder, auth, and hostile-input probes completed; the authorization matrix covered 244 OpenAPI operations across four identities.HOSTILE BYTES FINDINGS 0. Its only finding wasappearance concurrent PUT latency :: SLOW p95=0.810s exceeds the 0.500s target. Round two reached journal-race probes and was stopped after about 20 minutes because another adversarial suite was running on the shared host and the job has a ~60-minute limit. All findings observed before the stop wereSLOW; no non-SLOWfinding was observed. This adversarial round is incomplete.Decisions and gaps
de-DEassertion with it.TabBarwhile retaining the block-actions-bar visibility condition.cargo cleanreportedRemoved 18318 files, 14.7GiB total;apps/web/buildandapps/web/.svelte-kitwere removed. Worktree is clean.Merged in
bdcecc42: block actions (→ ⏰ ⋯ inside the note column), reminder picker with future-only resolved presets + learned times, quiet hours, icon-only phone capsule, inline ^id anchors (Obsidian style; fixes the raw ^id leak), tint selection. Orchestrator verified: web 670/670, editor 397/397, clippy clean, notes/notifications/server tests 177/177, generated client OK.