Log attachments: deleted file still shown, attachments not live, batch send not live, Log order, raw camera names #427
Open
opened 2026-09-29 11:06:03 +00:00 by kayg
·
238 comments
No Branch/Tag specified
dev
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
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
wip/delete-1119
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/segmented-1200
wip/rev2-webperf
wip/rev2-money-ident
wip/previewcard-1098
job/collabloss-1197
wip/palette2-1123
wip/palette-1093
wip/onboard2-1141
job/restyle-settings
wip/onboard-1141.aborted-early
wip/onboard-1141
wip/notifloop-1194
wip/nlpchip-1127
wip/morph-1104
wip/merge-round-7c5
wip/merge-round-7c4
wip/merge-round-7c3
wip/merge-round-7c2
wip/merge-round-7c
wip/mchrome-1084
job/restyle-files
job/tagdnd-1187
job/merge30
job/perf-1124
job/tocrail-1191
job/cards-1179
wip/cards2-1179
wip/cards-1179
job/segmented-1200
wip/tocrail-1191
job/hide-1153
wip/tagdnd-1187
wip/restyle-files
wip/perf-1124
wip/merge30j
job/onboard-1141
job/restyle-notes
wip/restyle-notes
job/wizchoices-1140
job/adv-1202
job/notifloop-1194
wip/wizchoices-1140
wip/restyle-1190
job/moneyfmt-1180
job/txentry-1198
wip/moneyfmt2-1180
wip/moneyfmt-1180-r
wip/moneyfmt-1180
job/tagperf-1186
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/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#427
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?
Owner report (2026-09-29, calternal.cloud, with a screenshot of the Calendar preview card for "Gym")
7F56BB27-910A-4F79-B160-17CCBEED73D1_1_102_o.jpeg. Server evidence: the daily noteNotes/20260929-dailynote.mdstill has the child line- [7F56BB27-…_1_102_o.jpeg](<Photos/2026/2026-09-29/2026-09-29 163314-3e69 7F56BB27-…_1_102_o.jpeg>)under the Gym entry, but the file no longer exists anywhere in the Home (it was deleted by the owner).Expected
calternal-id(DESIGN §33); a rename never breaks the link.Proof
Production-build e2e for each point (batch send live, ordering, live attachments, delete with undo and restore, outside delete shows Missing), plus screenshots of the card with a photo, a document and a Missing attachment at 390 and 1440 px, light and dark. The adversarial round: delete and restore races while the entry is being edited, and a thousand attachments on one entry. Gates per crate as in the preamble.
Starting attach-427 on branch job/attach-427, based at
191b179baa(dev). I have read CLAUDE.md, docs/DESIGN.md, and CONTEXT.md. I am tracing the log, attachment, delete/restore, and live-update paths before making atomic changes.Finding: the API create path calls append_log_entry for every composer and CalDAV create, and that helper always inserts after the last parsed line. The Calendar composerSaved handler also constructs each optimistic CalendarLog with attachments: [], so a newly sent entry is first rendered without its attachment data. I am fixing chronological insertion in calternal-notes-core while keeping existing line order unchanged, then I will address the live attachment projection.
Finding:
append_log_entryused to append every new Log row after the last row, even when the User had existing rows out of time order. It now inserts each new row before the first later start time and leaves existing rows in their original order. Regression cases cover a hand-reordered day, equal-time rows, CRLF, and the property writer's byte preservation. The Notes core suite passes after updating the old append-position assertions to identify the created row by block ID, which is the new insertion contract.The Log insertion rule and regression coverage are committed as
2b0d9f61(Insert new Log rows at their time position).cargo fmt --check,cargo test -p calternal-notes-core(501 unit tests plus integration suites), andcargo clippy -p calternal-notes-core --all-targets -- -D warningspass. The rule puts a new equal-time row after the last existing row with that time, and leaves every older row in place.#427 finding: Files move/rename changed the Index path, but Log children still pointed at the old Markdown target; Calendar resolves attachment identity by that path, so a rename could appear as Missing. I added a Notes rewrite under the shared writer lock, with Files move recovery replaying the idempotent old-to-new update. A Files route regression now checks the updated child target and preserved item ID. Rust gates are in progress; I will report their output with the final head SHA.
Finding: the Home watcher calls Files adoption without an old fingerprint. That path rebuilt the Index row on an existing file and could replace its stable item ID after an outside change. I changed the no-fingerprint path to preserve an existing ID while still adopting new paths and removing deleted paths. The Files regression test now replaces the file, adopts it without a fingerprint, and asserts that its item ID stays the same. The Root change bus still uses its prior fingerprint to distinguish server writes.
Related 5xx found while seeding fixtures: an attachment upload returned 500 after creating the files (new issue filed). attach-427 owns attachment behaviour, so fix it in this job if the root cause is in the attach path.
Implemented and committed the #427 attachment lifecycle and live Log work. HEAD:
09c05b884d. Merged dev once before final checks; resolved the Calendar e2e overlap by retaining both suites' coverage.Built:
Files: apps/web/e2e/calendar.mjs, apps/web/e2e/composer.mjs, apps/web/src/lib/calendar/{attachments.test.ts,data.ts,journal.ts}, apps/web/src/lib/composer/{commit.test.ts,commit.ts}, apps/web/src/lib/tooltip/tooltip.test.ts, apps/web/src/routes/calendar/[view]/[date]/+page.svelte; crates/calternal-server/src/wire.rs, crates/plugins/calendar/src/view.rs, crates/plugins/files/src/{agent_undo.rs,index.rs,lib.rs}, crates/plugins/files/migrations/0016_log_attachment_trash.sql; packages/ui/src/components/calendar/{AttachmentDeck.svelte,ItemPreview.svelte,attachments.ts,model.ts}, packages/ui/src/components/tooltip/{TooltipLayer.svelte,place.ts}; docs/DESIGN.md; tests/adversarial/attack2.py.
Gate output:
Known gaps:
cargo test -p calternal-plugin-fileswas stopped with exit 130 during dependency compilation, before tests ran. Calendar/server crate gates and workspace gates were not run.bun run checkidentified stale generated OpenAPI/API-client output for attachment fields and the Remove link route; code generation and a passing rerun remain. Production-build e2e, adversarial probes, and screenshots were not run, so no visual evidence is attached. No claim is made that those acceptance checks passed.Decisions where DESIGN was silent: order only newly created entries by time and keep existing handwritten row order; use 32 attachments per preview page; restore Trash links by stable block ID while preserving edits; cap batched attachment metadata queries at 500 IDs. These choices are documented in code/DESIGN where applicable.
Resuming round 2 on branch job/attach-427, based on
43c1377c8f. I am tracing the Log attachment upload and liveness paths, then will run the requested production-build proof and gates.Finding during #427 verification: the Trash restore flow re-adds the child link, but the serialized target is
[attached](<Attachments/attached.txt>).calternal-notes-coreuses and tests this canonical angle-bracket form. The existing Files integration assertion expects[attached](Attachments/attached.txt)and fails once the stack overflow is avoided. I left that assertion unchanged under the owner rule; the Files suite therefore has a known failure pending orchestrator review of the stale expectation.The first OpenAPI regeneration exposed a Calendar compile error in the attachment path: the call supplied the view timezone to load_log_details, but the function signature omitted it while photo labels used it. I added the missing parameter and documented the visibility/timezone invariant. I’m running the Calendar crate gate now.
Resuming round 2 on
job/attach-427at7e8e9af43. The prior integration commit is336f5e306; I will fetch and integrate currentorigin/devonce before final gates. I am continuing the interrupted Calendar timezone projection change, then finishing #460 atomic attach behavior, the e2e proof and required gates.Resuming round 2 on
job/attach-427at7e8e9af43. The branch includes theorigin/devintegration at336f5e306; the latest committed change adds a concurrent attachment probe. I am finishing the timezone-aware attachment labels, then handling #460 retry atomicity/concurrency, generated API client checks, production e2e evidence, and the requested gates.Focused evidence while resuming #427:
cargo test -p calternal-plugin-calendarcompiled and ran 50 tests; 48 passed and 2 failed. Both failures are Calendar range requests that now resolve Log attachments. SQLite returnedno such table: photos_media, and the route returned HTTP 500. Calendar must keep rendering when the optional Photos plugin has not created its Index table. I am checking plugin migration startup and will add a regression for the absent table.Calendar attachment lookup now passes against a test Index with the Photos migration installed, matching server startup (which applies the core plugin migration sets).
cargo fmt --checkpassed, andcargo test -p calternal-plugin-calendarpassed: 50 unit tests, 1 cache integration test, 3 protocol tests, 0 doc-test failures.Files gate evidence:
cargo test -p calternal-plugin-filesran 133 tests; 129 passed, 3 failed, 1 was ignored. Two restore tests failed their existing exact link checks.restore_event_attachmentemitted<...>destination wrappers for every link, including simple paths whose stored form was unwrapped ([attached](Attachments/attached.txt)). Trash metadata did not retain that Markdown style. I am preserving the wrapper bit in the saved link and restoring it; unsafe bare destinations still need wrappers. The third failure was the five-minute atomic-write/reconcile stress test timing out on this shared host; I classify it as SLOW-only.Starting resumed work on #427 and #460.
Branch: job/attach-427
Current HEAD:
7d856a5561Branch base at start of this round:
43c1377c8fI am reviewing the existing uncommitted Trash-link Markdown-style preservation change, then will finish atomic/idempotent attachment handling, generated API artifacts, adversarial coverage, and the requested production e2e evidence. I will merge origin/dev once before final gates as directed.
During conflict resolution with origin/dev, the first
cargo test -p calternal-notes-corerun found that the merged batch splice omitted the Daily note prefix before the Log section. Five tests failed with the output missing## Logor the day heading. The splice now copies the exact source prefix first; the full core crate passes 511 unit tests and all 37 integration tests.After regenerating the contract,
bun run checkreported that the existingremoveLogAttachmentpath was not anApiPath. The Notes handler was registered and had autoipa::pathannotation, butremove_journal_attachmentwas missing from the NotesOpenApipath list. I added the handler to that list; contract regeneration and the clean web check are pending.The first production Composer run passed the time-correction flow, then failed at the manual-order proof with
ReferenceError: shiftDate is not definedinapps/web/e2e/composer.mjs. I replaced the undefined helper call with date arithmetic from the script's existingtodayvalue. The browser flow is being rerun.The second production Composer run passed time correction and the previously failing date calculation, then stopped at the manual-order fixture with
ReferenceError: findFile is not defined.findFilealready exists in the shared e2e harness, so I imported it and removed the unused path variable. The Composer flow is being rerun.The third production Composer run passed the time-correction and manual-date steps, then the fixture failed with
EACCESwhen the test process tried to overwrite a server-owned Daily note underuserData. I changed the fixture to upload the complete hand-ordered Markdown through the real tus Files endpoint, then read it for the ordering assertion. This keeps the server as the only Home writer.The fourth Composer run passed the manual-order fixture, then failed in the held-send check because the journal response had no
entriesarray. I updated the existing wait to include the response status and error body while keeping the same success condition. The next run will show whether the held send or journal read is failing.The fifth Composer run passed the attachment preview and manual-order fixture, then the held-send probe found
GET /api/v1/notes/journal/<today>returning 404Note not foundafter the batch was released. I added a response capture for that held batch so the next run asserts its status and returned date before polling the journal; this will distinguish a rejected write from a date mismatch.The latest Composer run stopped at the existing chip geometry check:
Composer chips use the shared 28–32 px visual size and readable text role. Earlier runs passed it, so I kept the size threshold unchanged and added measured height/font size to the failure output for the next production run.The first production Calendar run stopped at the pre-existing commit-freeze probe:
assert.ok(sentBody, 'the send started')remained false after its 40 × 50 ms wait. No attachment flow ran. This is a 2-second UI/network timeout under the current shared-host load; I left the assertion unchanged and will retry the production run once.Follow-up to the Calendar run note: I traced the repeated 2-second timeout to the test code, not host load. The test closed its blank Composer and typed
Frozen snapshotwithout reopening it, so the intercepted send could not start. I added the missingawait openComposer()before typing; the send assertion remains unchanged.The Calendar commit-freeze test also intercepted the old
/api/v1/notes/journal/logendpoint and read a top-leveltextfield. Since #468, single sends use/api/v1/notes/journal/log/batchwithentries[0].text, so the probe could never observe the request. I updated the interceptor, response capture, unroute and snapshot assertion to the one-entry batch contract; the existing success assertions remain.Production e2e retry:
CALTERNAL_SERVER_BIN=/mnt/hdd/targets/jobs/attach-427/debug/calternal-server CALENDAR_E2E_SHOTS=... bun e2e/calendar.mjsstopped in the existing media sandbox preflight before starting the server. The harness reportedtoo many local threads for the bounded media sandbox test: 3629(limit 3584). I did not bypass the guard. Attachment-card screenshots and the production e2e proof remain outstanding due to this host-level limit.Focused real-server adversarial result: the attachment checks passed (8/8 concurrent tus uploads returned 201; the Log attach returned 201; a concurrent Daily note edit returned 200; the final read retained all eight links and the edit). Requests were slow on the shared build host (upload times 24.9–48.2 s), and I recorded the separate Log/Files scan-storm 503s and timeouts in #493 for controlled-load follow-up.
Production calendar e2e remains blocked before server startup by the media-sandbox thread guard (
too many local threads for the bounded media sandbox test: 3629; limit 3584). I did not bypass the guard, so requested attachment-card screenshots and visual proof remain outstanding.Production E2E evidence: the API-backed Daily note fixture returned 404 because it used
Notes/Journal/<date>-dailynote.md.calternal-notes-core::daily_note_pathuses the flatNotes/<date>-dailynote.mdpath. I corrected the Files API read fixture and am rerunning the production Calendar flow.Focused production Calendar proof created the real attachments and reached the Trash/restore race, then failed because
trashAndRestoredid not awaitpage.evaluate(). The assertion therefore readundefinedinstead of HTTP statuses. I added the missing await without changing expected statuses and am rerunning the proof.After the preview-refresh fix, the focused proof reached the Missing state successfully. It then failed its light-theme check because the E2E called
setThemewithout reloading the route, leaving the hydrated app in its prior system palette. I changed the fixture to navigate back to the stable Log deep link after setting each theme; theme expectations are unchanged.The focused proof captured the 390px light card correctly. Resizing the still-open selected preview to 820px left its previous anchor outside the viewport, so the chip tooltip hover could not run. The screenshot loop now reopens the preview by its stable Log block link after each viewport change; all responsive assertions remain enabled.
Finished: #427 and #460
Head:
0182ec91f7f81ab2cfc63a3eeb69d38fb035e0adDelivered
Photo · 16:33, keep full names in collision-aware tooltips, and show outside-deleted files as Missing with Remove link.contracts/openapi.jsonandpackages/api-client/src/generated.ts;bash packages/api-client/check-generated.shcompleted successfully.Production proof
calendar attachment e2e: lifecycle and responsive proof passed. It covers live attachments, Trash Undo, restore from Trash, edit/restore race, outside deletion to Missing, Remove link, photo/document labels and tooltip collision checks.Gates
Captured output:
Clippy passed for
calternal-plugin-files,calternal-plugin-calendar,calternal-server,calternal-plugin-notesandcalternal-notes-corewith-D warnings. The generated API check passed. The production build completed; it printed existing vendoruse clientdirective warnings.Known gaps and findings
entry not found); the same test passed alone. Notes-core had one performance-threshold failure at 8.252 ms against an 8 ms limit; it passed alone. Both occurred under shared-host load.Decisions
Files
CONTEXT.md;docs/DESIGN.md;contracts/openapi.json;packages/api-client/src/generated.ts;apps/web/e2e/{calendar.mjs,composer.mjs,harness.mjs};apps/web/src/lib/calendar/{attachments.test.ts,data.ts,journal.ts};apps/web/src/lib/composer/{commit.test.ts,commit.ts};apps/web/src/lib/files/{uploads.svelte.test.ts,uploads.svelte.ts};apps/web/src/lib/tooltip/tooltip.test.ts;apps/web/src/routes/calendar/[view]/[date]/+page.svelte;crates/calternal-notes-core/src/{dayfile.rs,lib.rs,links.rs};crates/calternal-notes-core/tests/log_rewrite.rs;crates/calternal-server/src/wire.rs;crates/plugins/calendar/src/view.rs;crates/plugins/files/migrations/0017_log_attachment_trash.sql;crates/plugins/files/src/{agent_undo.rs,index.rs,lib.rs,uploads.rs};crates/plugins/notes/src/{calendar_links.rs,lib.rs};packages/ui/src/components/calendar/{AttachmentDeck.svelte,ItemPreview.svelte,attachments.ts,model.ts};packages/ui/src/components/tooltip/{TooltipLayer.svelte,place.ts};tests/adversarial/attack2.py.Started merge-round-3 on branch
job/merge-round-3, from fetchedorigin/devat558457cf32e1d429da3834a05ff2720d11284302. The prior clean integration branch is preserved. I will merge the nine requested branches in order, resolve Files migration numbers, regenerate the contract and client, and run the requested per-crate and web gates. No push or deployment.All nine requested branches are merged in order on
job/merge-round-3. Files uses 0016 Share Search invalidations, 0017 Log attachment Trash, and 0018 Sidecar pairs. Conflicts retain DELETE child re-parenting, chronological insertion, Notes locking for Files mutations, attachment metadata in Trash, photo edit file movement and restore, and the existing Maintenance redirects. Settings now says “Photo edit files (.xmp, .aae)” and starts with what Files shows.The final
git fetch origin/git merge origin/devbrought document thumbnail and attachment request-struct changes. The resolution keeps those together with #427's friendly capture labels, Missing state and bounded deck pagination. Gate logs are inartifacts/merge-round-3/.A merge interaction removed Log metadata from the Index before the Markdown restore completed. I removed that early deletion; the existing explicit cleanup remains after successful restore. A new migration test upgrades a version-15 Index with a retained Share through 16–18, then applies the migrations again to prove repeat startup succeeds.
Web type check passed:
svelte-check found 0 errors and 0 warnings.The web suite reported one timeout with unchanged expectations:
Test Files 1 failed | 136 passed (137)Tests 1 failed | 907 passed (908)StatRow summary cards > toggles all four cards together and remembers the mode.The requested isolated rerun (
bun run test src/lib/components/analytics/widgets/StatRow.svelte.test.ts) passed:Test Files 1 passed (1)Tests 13 passed (13).I will retain and quote both complete gate logs in the final report. No assertion or timeout was changed.
The read-only source review found a concrete inherited paired-file recovery gap from
job/hidden-420: a crash after the photo edit file enters Trash and before its photo moves leaves the edit file in Trash while recovery returns the photo's Log links. A crash between the parent and edit-file restore moves has the symmetric split.The integration fix uses the existing stable parent ID and existing restore intents. Recovery returns already-trashed edit files before restoring aggregate Log links when the photo move did not commit. Recovery also finishes pending restore file moves before restoring Log links. Fingerprints must match before a returned edit file receives its indexed identity. A regression test replays both filesystem/Index boundaries. Rust validation is pending; no passing claim yet.
The live normal-pair lifecycle returned 500 during Trash. The Files crate regression run reproduced it:
The fixture used invalid XMP bytes. Tags correctly rejects this source as a conflict, but Files mapped the Tags error to a generic 500. Files now keeps a conflict response and cancels the untouched Trash reservation for invalid metadata. A new regression checks the conflict and absence of a pending intent. The normal paired-file test now uses valid XMP. No existing test expectation was changed.
A second source review identified two gaps in the recovery follow-up. Pair restore intents are now written in one transaction. Recovery checks destination occupancy for the full pair before moving any member, so an uncommitted refused restore can cancel its intents without poisoning startup. These follow-ups await the new Files gates.
The local DAV replay passed:
The attachment e2e first timed out waiting for the filename tooltip (
TimeoutError: textContent: Timeout 30000ms exceeded.). Its isolated rerun passed without changing the test:The production screenshots cover 390, 820 and 1440 px in Paper and Tokyo Night and are attached to this issue. They are for the orchestrator's visual review.
Composer's first run stopped before server startup because the shared-host media setup counted 4370 local threads, above its 4090-thread threshold. This is host-load evidence, not an application failure. A later bounded retry will be recorded with the first run.
The externally refreshed
origin/devref now points beyond the final fetched/merged cutoff8ac92b4008e489f22710878c69f481aabeabcb0a. All nine requested branch tips and that cutoff are ancestors of the integration branch. Per the one-fetch/merge rule, I am not chasing subsequent remote advances.Local performance run:
bun apps/web/e2e/send-fast-perf.mjs, 3 runs per batch size, debug server, production web build. The profile records one batch write per send plus visible/acknowledged p50/p95 and server mean/peak CPU and RSS. Revision:6a025baad12aafaec426cc9b13f7893c3ca3cbf0(before the pending Files recovery commit; the measured Composer hot path is unchanged by that commit).Load averages before:
[21.8, 23.81, 23.37]; after:[18.98, 22.64, 23]. CPU may exceed 100% because the server uses several cores. The first one-entry sample includes cold work.docs/perf/baseline.jsonrecords opening Composer (visible_msp50 548 / p95 1322 ms), with CPU throttle 4 and different viewports. It has no matching batch-send acknowledgement/resource baseline. These values are adjacent context, not a regression comparison. No threshold issue is warranted from unmatched debug/local metrics. The raw JSON is attached to #427. This was a local run; no perf VM measurement or lock was used.The full Composer e2e retry progressed through the mounted Calendar batch and second-browser checks, then failed an existing assertion:
The test had previously opened
/calendar/day/${yesterday}.ComposerController.show()usesoptions.date ?? this.contextDate?.(), andOpenComposerOptions.datedocuments “default: the context day, else today.” The Calendar installs that context day. The response therefore matches the documented controller behavior. I kept the existing expectation unchanged, as required. This mismatch needs the orchestrator's decision; I did not change the feature's date behavior or weaken the test. The separate required attachment lifecycle e2e passed on its isolated rerun.The first Composer attempt stopped before startup due to the shared-host media thread threshold; the retry's assertion failure is a different result and is retained separately.
The production browser denial pass failed an existing pending-Role title assertion:
The preceding assertions passed: no admin header link and no “Copy link to Users” action while Role was pending. The title did not expose an admin section. Both
job/admin-deny-483's merged tree and the fetched dev cutoff usedisplayedHeader.title; the shared overlay header retains the background Calendar title for a cold Settings link. This is a cosmetic expectation mismatch, not an authorization failure. I kept the expectation unchanged. The pending-title behavior needs the orchestrator's decision. The offline admin coverage guard passed with 39 reviewed operations, and the separate valid-body live authorization matrix is running.Search clippy passed. The full Search unit run hit the existing five-second publication wait deadline:
The required isolated rerun passed without changing the test or its deadline:
The test waits for a staged rebuild to reach the write lock while a reader holds the old generation. It did not reach that point within five seconds in the combined run on this shared host. Both logs are retained in the merge report. No expectation was changed.
The bounded valid-body authorization matrix completed all 1891 requests, with 59 failures. No unauthorized success or 5xx was listed. Most failures were a 403 body/code mismatch:
The existing
sample()choosesFalsefor booleans. Therefore the schema-validapp_surfaces_putandadmin_app_surfaces_putfixtures disable a surface. The authorized writes can switch off API access before later admin-denial cases.session_contextthen correctly returns the disabled-surface 403 text before the admin route guard, rather than the guard's JSONforbiddencode. The long run also leaves the Web sessions used at the final fresh-assertion revocation checks older than at fixture setup; this is a likely contributor to those two 403s and is not yet independently verified.I kept the existing fixtures and expectations unchanged under the owner rule. The existing focused
ADMIN_DENIAL_ONLYmode is being checked with fresh fixtures and valid bodies; it sends no authorized admin configuration writes. This keeps the whole-matrix failure distinct from a focused proof of fail-closed admin guards. The matrix's final text still says “valid/malformed” because that label is hard-coded, but this bounded run used valid bodies only. Malformed and exploit/DoS phases were not run.Decision needed from the orchestrator: repair the matrix fixture order/bodies and freshness setup before treating the full matrix as green. The integration branch cannot be reported as all gates green while this result remains.
Starting merge-round-3 in
job/merge-round-3, based onorigin/devatcd3cea757508d9f581d00fb7d5d7973fbc0a75fd. I preserved the prior localjob/merge-round-3ref asjob/merge-round-3-pre-rebuildand am assembling the requested branches in order. No push, deploy, or merge to dev is planned.Merge round 3 integration report
State: incomplete; do not fast-forward this snapshot to
devyet. The four-hour job limit ended while CLI Clippy was compiling. No completed final-tree gate failed. No source branch was dropped because the completed gates showed no failing branch.job/merge-round-33e5056d485e9021d2d1f708613e783b0b901b447job/multiget-500,job/dav-delete-471,job/iso-435,job/admin-deny-483,job/attach-427,job/hidden-420,job/files-sel-keys,job/small-bugs-3,job/sweep-478.92f5803f3,3ea69e317,26b986bc4,0948cffa1,99c088193,df6b07a5a,3e5056d48.Completed gate output (verbatim excerpts)
cargo fmt --checkexited 0 with no output.Finished \dev` profile [unoptimized + debuginfo] target(s) in 56.92s`test result: ok. 40 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.37stest result: ok. 36 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.09stest result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.31sFinished \dev` profile [unoptimized + debuginfo] target(s) in 14.97s`test result: ok. 512 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.21stest result: ok. 19 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 8.21stest result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.06stest result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.35stest result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01sFinished \dev` profile [unoptimized + debuginfo] target(s) in 2m 55s`test result: ok. 127 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 151.26sFinished \dev` profile [unoptimized + debuginfo] target(s) in 48.77s`test result: ok. 144 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 178.62sThe dev-version migration test passed:
test tests::dev_files_schema_upgrades_through_share_log_and_sidecar_migrations ... okFinished \dev` profile [unoptimized + debuginfo] target(s) in 1m 53s`test result: ok. 52 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 7.01stest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.12stest result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.22sFinished \dev` profile [unoptimized + debuginfo] target(s) in 1m 13s`test result: ok. 45 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 11.10sFinished \dev` profile [unoptimized + debuginfo] target(s) in 55.79s`test result: ok. 36 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 46.71stest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.38stest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.09stest result: ok. 21 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 10.44stest result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.05stest result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02stest result: ok. 1 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 5.66stest result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01sFinished \dev` profile [unoptimized + debuginfo] target(s) in 27.32s`test result: ok. 31 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 1.93sFinished \dev` profile [unoptimized + debuginfo] target(s) in 10.78s`test result: ok. 50 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 9.04stest result: ok. 42 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.56sFinished \dev` profile [unoptimized + debuginfo] target(s) in 1m 48s`test result: ok. 85 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 19.67sOther completed checks:
Parity matrix: 190 web API actions, 122 shortcuts, 2 static commands, 136 menu actions, 31 settings groups, 172 actions with adapter gapsCross-User classification gate: 311 operations classified; its test suite printedRan 5 tests in 0.246sandOK.Admin coverage: 39 reviewed operations; contract and Rust guards agree; its test suite printedRan 14 tests in 2.404sandOK.ai: 4 migrations, no duplicate numbers;analytics: 2 migrations, no duplicate numbers;calendar: 3 migrations, no duplicate numbers;files: 18 migrations, no duplicate numbers;mail: 8 migrations, no duplicate numbers;notes: 19 migrations, no duplicate numbers;notifications: 4 migrations, no duplicate numbers;photos: 6 migrations, no duplicate numbers;video: 1 migrations, no duplicate numbers.Remaining work
bun run check,bun run test, andbun run buildare pending.docs/perf/baseline.jsonare pending.cargo cleanis running but has not returned yet;apps/web/buildwas removed.Decisions
share_search_invalidations, 0017log_attachment_trash, 0018sidecar_pairs. The populated dev-schema upgrade test passed.The branch contains the merged code and commits, but the listed pending gates mean this is not a green merge candidate yet.
Merge round 3 report addendum
Branch
job/merge-round-3, HEAD3e5056d485e9021d2d1f708613e783b0b901b447.Removed 25367 files, 17.5GiB total.apps/web/buildremoval check:web build output removed: True.git diff --checkexited 0 with no output; the worktree has no modified or untracked files.The branch is still not a green merge candidate.
Resuming merge round 3 on
job/merge-round-3, HEAD/base3e5056d485e9021d2d1f708613e783b0b901b447. The fetchedorigin/devisf2d03f37af584f4259c0fc9119fd524b91332a50.git merge-tree --write-tree HEAD origin/devexited 0 with no conflicts. Per the resume instruction, no merge is required and gates stay on the exact requested tree. Per-crate gates use CARGO_BUILD_JOBS=6. Build/web/contract/classification gates and normal local functional lifecycle checks will run. Exploit, hostile-input and cross-User intrusion probes will remain incomplete. No push or deploy.Final-tree web check failure at
3e5056d485e9021d2d1f708613e783b0b901b447:AttachmentDeck.svelteretains an unusedthumbFailed()function that refers to the removedfailedstate (lines 497 and 499). Search finds no call to this function. Thumbnail rendering now usesFileThumb, which owns its fallback state. The obsolete helper is present in the requested HEAD. No expectation or source was changed: the resume prompt requires gate-only work on this exact tree. This is a compile/type-check failure, not a SLOW result. The merge candidate cannot be reported green.Web test run at the unchanged requested HEAD finished with a timeout:
One isolated rerun passed without changing source, fixtures, expectations or the 5000ms timeout:
The full run remains recorded as exit 1. The separate web check failure from the obsolete AttachmentDeck helper is a confirmed type error. The production build exited 0.
Resume checkpoint on unchanged HEAD
3e5056d485e9021d2d1f708613e783b0b901b447. CLI and Auth gates passed. Verbatim result lines:calternal-cliclippy:calternal-clitest:calternal-authclippy:calternal-authtest:Search onwards continues with CARGO_BUILD_JOBS=6. Web results were posted separately.
Search Clippy passed on the unchanged requested HEAD. Search unit tests passed (
36 passed; 0 failed; 1 ignored), as did ask evaluation and citation integration tests. The indexer integration binary failed while waiting for a newly indexed fixture:The helper polls 250 times with 20 ms sleeps. No source, fixtures or expectations were changed. The runner continues through the remaining crates. A single isolated rerun and the integration binaries skipped by Cargo will run after this sequence; the original full-gate exit 101 will remain in the report.
Search timeout follow-up on unchanged HEAD
3e5056d485e9021d2d1f708613e783b0b901b447. The single isolated failed case, the integration binaries skipped after Cargo stopped, and doc tests passed. No expectations or source changed. The original fullcargo test -p calternal-searchexit 101 remains recorded. Verbatim output excerpts:resume-search-isolated.log:resume-search-remaining.log:resume-search-doc.log:Generated contract gate failed at unchanged requested HEAD
3e5056d485e9021d2d1f708613e783b0b901b447.bash packages/api-client/check-generated.shbuilt a fresh server and generated the contract/client, thengit diff --exit-codereturned 1. Verbatim diff:The generated files were restored to HEAD after saving this evidence, as the resume prompt requires only gates on the exact tree. No source or expected output was changed. The worktree is clean. This is stale generated output, not a SLOW finding.
The focused production attachment e2e failed at the final desktop/dark tooltip capture. Verbatim error:
The preceding normal lifecycle assertions completed; five responsive screenshots were captured. The 1000-attachment pagination assertions were not reached. A single unchanged focused rerun is in progress; both results will be retained. No source, expectations, fixtures or timeout settings changed.
The one unchanged attachment rerun also failed on tooltip visibility, this time at the initial photo tooltip:
No more browser retries will run. Both focused e2e runs failed and are reported as failures, not assumed SLOW-only results. Five production screenshots from the first run exist (390/820/1440 Paper, 390/820 Tokyo Night); 1440 Tokyo Night and the final imported-list pagination assertions remain incomplete. The normal local DAV and Sidecar lifecycle checks both passed.
Merge round 3 resume report
State: not a green merge candidate. The requested gate runs are finished. Confirmed blockers remain in the unchanged snapshot.
job/merge-round-33e5056d485e9021d2d1f708613e783b0b901b447artifacts/merge-round-3/resume-*(ignored). Source files and checked-in generated files are unchanged.CARGO_PROFILE_DEV_DEBUG=line-tables-only,CARGO_INCREMENTAL=0,CARGO_BUILD_JOBS=6,TMPDIR=<worktree>/target/tmp. The presetCARGO_TARGET_DIRwas used. Each crate ran separately.Findings and known gaps
bun run checkfailed with two undeclaredfailedreferences inpackages/ui/src/components/calendar/AttachmentDeck.svelte:497and:499. The unusedthumbFailed()helper remains after thumbnail failure handling moved toFileThumb. This is a confirmed type error. Evidence was posted on #427.resume-generated.diff. Generated files were restored to HEAD to preserve the exact requested tree.rebuild_matches_incremental_resultswhile waiting for the new fixture to appear. One unchanged isolated rerun passed. The integration binaries skipped after Cargo stopped and the doc tests passed. The original gate remains exit 101.Rust gates: verbatim output excerpts
cargo fmt --checkexited 0 with no output.cargo clippy -p calternal-cli --all-targets -- -D warnings:cargo test -p calternal-cli:cargo clippy -p calternal-auth --all-targets -- -D warnings:cargo test -p calternal-auth:cargo clippy -p calternal-search --all-targets -- -D warnings:cargo test -p calternal-search:cargo clippy -p calternal-embed --all-targets -- -D warnings:cargo test -p calternal-embed:cargo clippy -p calternal-fs --all-targets -- -D warnings:cargo test -p calternal-fs:cargo clippy -p calternal-plugin-calendar --all-targets -- -D warnings:cargo test -p calternal-plugin-calendar:cargo clippy -p calternal-plugin-photos --all-targets -- -D warnings:cargo test -p calternal-plugin-photos:cargo clippy -p calternal-server --all-targets -- -D warnings:cargo test -p calternal-server:Search follow-up: verbatim result lines
resume-search-isolated.log:resume-search-remaining.log:resume-search-doc.log:Web, contract, parity and classification: verbatim output
bun run --cwd apps/web check(exit 1):bun run --cwd apps/web test(exit 1):Isolated ThemePicker rerun (exit 0):
bun run --cwd apps/web build(exit 0):bash packages/api-client/check-generated.sh(exit 1; diff posted in the finding comment):resume-parity.log(passed):resume-xuser-classification.log(passed):resume-admin-classification.log(passed):Local normal lifecycle checks: verbatim output
DAV and Sidecar run (exit 0):
Attachment
resume-attachment-e2e.log(exit 1):Attachment
resume-attachment-retry.log(exit 1):Production evidence
Five screenshots from the first attachment run were uploaded to #427. They show the same real local fixtures in the production app. They do not prove the unfinished checks.
Decisions
origin/devwasf2d03f37af584f4259c0fc9119fd524b91332a50.git merge-tree --write-tree HEAD origin/devexited 0 with no conflicts. Per the resume exception, no new merge was made and all gates stayed on the exact requested HEAD.Cleanup and final status
cargo cleanexited 0:apps/web/buildandapps/web/.svelte-kit/outputwere removed.git diff --checkexited 0 with no output.git status --porcelain=v1produced no output. HEAD remains3e5056d485e9021d2d1f708613e783b0b901b447. No tracked source or generated files changed.Do not fast-forward this snapshot to dev as an all-green candidate. The failures and incomplete live isolation coverage require follow-up.
Starting merge round 3 on
job/merge-round-3. HEAD:cb75820852a922f3d09cb596fd261b9cb0d0dd43; merge base targetorigin/dev:15e17aeafc8ea160c109e62fba57f6961c39d21f. I will mergeorigin/dev, resolve both sides' intent, then investigate the attachment tooltip and run the requested gates and matrices.Search e2e finding: the real server had a 60-query search round-trip p50 of 68.8 ms and p95 of 265.2 ms, then the palette assertion failed with the Notes section missing. The Search test already recognized the 200 ms provider fan-out deadline but retried only when Log entries were absent; it stopped early when another seeded section was missing. I changed the retry condition to wait for the same four expected sections before asserting them. The expected section set is unchanged.
Finding: Search's compact palette failed the centered-growth e2e after the resize observer measured 13 results. The rendered center was 447.17 px while the prior two-result palette center was 450.5 px (900 px viewport).
search-dialog.sveltepassed the measuredtopandheighttogether but still transitionedtop, contradicting its adjacent layout invariant and causing an observable drift during the transition. I removed thetoptransition and made the e2e wait for the measured growth before sampling settled bounds. The production Search e2e is being rerun after rebuilding the app.Finding: after the centered palette checks passed, Search e2e reported no section labels even though
.group-headrows were present. The merged Search markup adds.search-group-bluras the first child before each heading label, so the oldspan:first-childselector matched nothing. I changed the test selector tospan:first-of-type; the expected four result sections and their order remain unchanged. The e2e is being rerun.Finding: the Search e2e now locates the four result headings correctly and passes the responsive centered-growth checks. It next sampled the sticky blur at opacity
0.999997while the CSS transition was still active, then failed the existing exact1assertion. I changed the wait to require opacity1and no active transition before reading paint; the expected rendering assertion is unchanged.Finding: after waiting for the blur transition to finish, the Search e2e still failed its unchanged wash assertion because
getComputedStyle(...).backgroundImageserializes the CSStransparentstop asrgba(0, 0, 0, 0). I kept the existing/linear-gradient.*transparent/expectation and changed the probe to inspect the shared--glass-header-washtoken, whose declared gradient expresses the same contract. The Search e2e is being rerun.Finding: the sticky blur checks now reach paint validation, where Chromium serializes transparent mask stops as
rgba(0, 0, 0, 0), so the unchangedtransparentassertion failed on each computed mask. I kept the CSS contract and normalize that CSSOM spelling in the probe before checking each gradient. No UI expectation changed; Search is being rerun.Finding: the unchanged Search preview assertion waits for the highlighted text to fit inside its scroll pane. It failed with the mark 0.40625 px above the pane edge (
mark.top=178.59375,pane.top=179,scrollTop=72), afterSearchPreviewcalledscrollIntoView({ block: 'nearest' }). I added a 1 pxscroll-margin-blockon preview marks so native nearest scrolling leaves the highlight inside the pane and preserves the existing assertion.Finding: the Search e2e passed through keyboard preview, Search actions, facets, deep links, saved searches and Files scope, then the Calendar integration helper timed out looking for header view controls. With the desktop sidebar open, the merged Calendar UI correctly places sub-views there under DESIGN §34, so the header switcher is absent. I extended the helper to verify the selected Week link in Calendar navigation; the view assertion stays the same.
The live #483 authorization matrix completed 2,055 requests and found 84 failures. For denied admin routes, the bearer API/CLI surface gate returns plain text with HTTP 403 before the role guard runs, so the required
forbiddenerror code is absent. Two valid/auth/sessions/revoke-allWeb-cookie calls also returned 403 after the matrix's long sweep. I am preserving the matrix's exact status and error-code expectations; I will make surface-gate denials use the API error envelope and keep the revocation fixture's recent-assertion precondition fresh immediately before that request.The focused admin authorization rerun passed after the two fixes. It completed all 2,055 requests across 331 OpenAPI operations with exit code 0 and no failure rows. The bearer surface gate now returns the shared API
forbiddenenvelope, and the fixture restores its disposable Web session's five-minute assertion window immediately before the authorized revoke-all request. No matrix status or error-code expectation changed.cargo test -p calternal-serverexposed one fixture failure: the legacy Appearance migration test moved the file on disk but its temporary DB lacked the Notes migration tables required by the shared Files move hook (rewrite_log_attachment_targets_lockedchecks Note links for every moved item). The route logged and tolerated that migration error, leaving the fixture's Index assertion stale. The expectation is correct; I added the Notes migration to the Appearance test database setup and will rerun the server crate gate.#427 — merge round 3 final report
Merged
origin/devat15e17aeafc8ea160c109e62fba57f6961c39d21fintojob/merge-round-3; the merge isf1b067bde. No push, deployment, or merge intodevwas done.Head:
cc25c441b7a974185622a1dee853cf38686d2b67What changed
uploadBytesoptions as{ conflictPolicy, completeByPatch, photosUpload, patchChunkBytes }and updated its callers. Kept the cross-User route and case inventory from both branches.pointerover; it now reads the DOM without auto-wait and moves to a neutral point before hover. The product tooltip itself worked.auto_scheme.locationfield; its rejection case remains unchanged..calternal/backgrounds/path during the DESIGN §35 migration. Both legacy and visible background paths get the 20 MB cap and image decode check; rejected uploads leave no staged row.Finishing files:
apps/web/e2e/harness.mjs,apps/web/e2e/calendar.mjs,apps/web/e2e/search.mjs,apps/web/src/lib/components/search-dialog.svelte,apps/web/src/lib/search/SearchPreview.svelte,crates/calternal-server/src/wire.rs,crates/calternal-server/src/appearance.rs,crates/plugins/files/src/lib.rs,crates/plugins/files/src/uploads.rs,tests/adversarial/authz_matrix.py,tests/adversarial/xuser_matrix.py, andtests/adversarial/attack.py. The benchmark isbench/merge-round-3.mjs, wired throughbench/run.sh. The starting branch also includes the orchestrator changes tocontracts/openapi.json,packages/api-client/src/generated.ts, andpackages/ui/src/components/calendar/AttachmentDeck.svelte.Gates
bun run checkoutput:bun run testsummary:Attachment e2e:
Search e2e passed its functional assertions, then failed only its local performance assertions. Exact result:
Two-User isolation matrix output:
Admin authorization rerun (from the captured #427 result):
Rust gates used
CARGO_PROFILE_DEV_DEBUG=line-tables-only CARGO_INCREMENTAL=0 CARGO_BUILD_JOBS=4 CARGO_TARGET_DIR=/mnt/hdd/targets/merge-check TMPDIR=$PWD/target/tmp.cargo fmt --checkexited 0 with no output. For each package, these are the finalclippy -D warningsandtestsummary lines:The one API-only adversarial round ended with the server alive. Its output reported
==== FINDINGS 150(128SLOWrows and 22 other rows). The direct background-path failures came from the binary built before commit6c4f396e6; the Files integration gate passed after the fix. The valid Appearance concurrency fixture was corrected incc25c441bafter the run; I did not repeat the one-round campaign.Non-SLOW results were reported on existing issues: tag rename/reconcile/rebuild returned 409 and left the probe Tag page empty (#532); Calendar Event-from-Log, Journal and Reminders requests timed out and the completion readback did not show the updated VTODO (#250, #267). The server reported
server alive at end: True. The DAV Files credential setup also returned 403. A DAV PUT that updated an existing resource returned 204 while the probe expected 201; it then retained the old ETag and its follow-on move/delete got 412. I kept those existing DAV expectations unchanged for owner review.Local performance profile
bench/merge-round-3.mjsran once locally against 1,000 Log attachments and a 24-request burst. It recorded load average before23.69 / 24.80 / 26.29and after27.63 / 25.61 / 26.53. Results:docs/perf/baseline.jsonhas no 1,000-attachment profile, so there is no like-for-like baseline. The Search first-result p95 was 359.0 ms (50 ms target), with 19 main-thread tasks over 50 ms and max 724.0 ms; I added the local result to #434. These are shared-host diagnostics, not quiet-host regression measurements.Visual evidence
Attached 24 production-build screenshots to this issue. Calendar attachment cards cover 390, 820 and 1440 px in Paper and Tokyo Night. Search covers few, end and many results at those widths in Paper and Tokyo Night.
Calendar attachment proof:
Search palette proof:
Decisions and gaps
Removed 24175 files, 15.3GiB total;apps/web/buildandapps/web/.svelte-kitwere removed.Related findings were recorded on #551, #553, #532, #250, #267 and #434. No issues were closed.
Starting merge round 4 on
job/merge-round-4, based oncc25c441b7a974185622a1dee853cf38686d2b67(round 3 /origin/dev). I have readCLAUDE.md,CONTEXT.md, and the relevant navigation, chrome, search, deep-link, plugin, and settings decisions indocs/DESIGN.md. I am merging the approved branches in the requested order and will report conflict resolutions and gate output here.Finding during
tray-orderconflict resolution: this branch stores a five-item slice invisibleModes, while the round-3 tree keeps the complete enabled list and uses width limits only for the visible window. I kept the uncapped list and the 5-desktop/3-phone window. The branch's older Appearance schema also put Location insideauto_scheme; the current tree has a dedicated Location API. I preserved that API and added the branch's separate account-scoped mode-order endpoint and hostile-input probe.The
title-plain-526merge conflicted in the layout sweep, Search e2e and Photos view. I kept the round-3 Mail/Money fixture path and added the header-only Photos fixture path; Search now checks that Calendar Week content loads while the root title has no view menu; Photos uses the date as its ModeHeader title with breadcrumbs and retains the Backgrounds folder view.In
align-538, the Files alignment changes overlapped the #448 selection-column collapse and #527 reduced-motion handling. I kept the selection column dynamic (zero until selection marks are visible), used the shared icon-size token inside IconLabel, and retainedmotionDurationMsin both shared sidebar rows. The Files e2e keeps its selection-only and keyboard flows and now also runs the alignment matrix in the normal production run.In the Search count merge, I combined the #544 palette settle check with the existing #427 ResizeObserver-height wait. This preserves both the Show all animation check and the later measured-height check. I also retained the #483 stable destination annotation beside the new accessible group/count row naming, and kept both the Tab Bar and Search Index benchmark report checks.
The Toast benchmark conflicted with the shared report and runner. I retained the Tab Bar, Search Index, Calendar attachment and path-menu profiles, then added the Undo-ring average and burst profile. The generated local report had Markdown hard-wrap whitespace that failed
git diff --check; I removed only those trailing spaces before committing.In the Calendar preview merge, #421's append-attachment route overlapped #427's Missing-link removal route. I kept both routes, both Journal client calls, and both ItemPreview callbacks. The MCP allowlist now includes the existing Mail Reader tool plus the new duplicate and Journal-attachment tools. The API contract and generated client remain for the requested final regeneration after the ordered merges.
Analytics merge: kept the #504 chart hover/performance helpers and cursor-position tests alongside #381 responsive heatmap screenshots and #421 shared tooltip positioning tests. The merged harness exposes both --layout-screenshots-only and --perf-only paths. The resolved merge is committed as
9ba68beb3;git diff --checkpassed.Drag-snap merge: resolved Calendar overlaps by keeping the #421 Cmd+I anchored-preview helper beside #536 dragging settings helpers; preserved both provider-zone composer iCalendar updates and drag-only non-recurring move adapters; kept conditional DELETE and ETag-conditional PUT handlers in the CalDAV fixture. The bench help text covers both toast and snap profiles. Merge commit:
b06402852.git diff --checkpassed.Settings-shortcut merge: combined host-specific browser fallbacks, screen-reader descriptions, IconLabel rows and reduced-motion opening behavior. I retained Cmd+I for the inspector because DESIGN §34 assigns that binding; the conflicting branch value used Cmd+Shift+Period. I also kept #526 plain mode titles and sidebar sub-views, so no title menu was restored. Commit:
df47b06f4.git diff --cached --checkpassed.Background-flash/user-storage merge: kept the existing first-paint mode-order store while placing its browser persistence behind userStorage; joined synchronous session cleanup with mode-order invalidation; added dual-name support for the validated prebuilt media runtime. Removed one extra blank EOF line found by
git diff --cached --check. Commit:b650681c8.Tasks merge: retained Task anchor metrics and test output beside the Tab Bar, Search Index, toast, attachment, and Analytics reporting. Merged the Task profile into
bench/run.sh, preserved both measured baseline workloads via a no-conflict recursive merge of the two JSON sides, and kept the adversarial reconciliation uniqueness probe. Commit:d8e93b4bc.git diff --checkpassed.Notes bridge merge: combined CalDAV allowed-network configuration with the optional IMAP listener; kept the #391 Saved-place projection, #531 task indexing and #428 IMAP change notifications. The notes plugin migrations overlap: kept #391 as migration 20 and renumbered the three Notes IMAP migrations to 21–23 with matching filenames. Cargo.lock now contains both location/embed and IMAP dependency trees (861 packages; TOML parse passed). Commit:
f99a49124.Merged origin/job/parity-484 as
231012153. Conflict resolution keeps #428 duplicate/Journal attachment tools, #431 Calendar tools, #555 session hints, and #391 Location docs alongside generated WebMCP actions. The e2e registration count is 25 fixed tools plus generated registry names; the parity branch's baseline of 22 omitted three tools merged earlier in this round. I used the parity branch's current exception schema because its checker accepts route-specific presentation/onboarding exclusions, while the older file held retired generated pending lists. I will regenerate the matrix from the merged contract after the last branch.Merged origin/job/crash-525 as
70c6aa464. The parity dispatch task and #525 worker-stack headroom are complementary: the dispatch boundary cancels handler futures with the request and removes outer Tower frames; the 4 MiB worker stack covers the remaining synchronous filesystem/Tower frames. I kept both, with their cancellation test and cross-source rename storm/profile. Resolved docs/perf/baseline.json by combining its non-overlapping task/toast and Tag rename metrics; run.sh's conflict was only the profile-sampling comment.Build finding: cargo run -p calternal-server -- openapi stopped while compiling calternal-plugin: error[E0063] missing field default_user_enabled in initializer of PluginAccessState at crates/calternal-plugin/src/lib.rs:1362. I am checking the new field’s existing fixture values before applying the minimal fix.
Build finding: server contract generation then stopped in crates/plugins/notes/src/lib.rs because build_new_day_file is imported from calternal_notes_core and also defined locally at line 1299. I am comparing both implementations to keep the shared Notes Core invariant without changing Note behavior.
Follow-up build finding after the Notes helper fix: calternal-server has stale call sites after the PluginState API change. notes_imap.rs:235 calls is_enabled with two arguments, but the current method needs default_user_enabled and user_id. In mcp.rs, AppPasswordAccess::Read/Write call sites do not match call_api and the type is not imported for production code. I am tracing the access guard and plugin defaults so the fixes preserve current authorization.
Contract freshness finding: rebuilding calternal-server openapi from the merged sources added four operations missing from the previous generation: GET/PUT /api/v1/preferences/mode-order, POST /api/v1/calendar/items/duplicate, and POST /api/v1/notes/journal/entries/{block_id}/attachments. Regeneration now reports 333 registry operations, 315 generated tools, and 0 parity adapter gaps. I am rerunning the clean-generation check against the rebuilt server binary.
Web gate finding: the userStorage source guard found two direct localStorage calls for the saved Settings destination in apps/web/src/routes/+layout.svelte. Both now use the per-User userStorage facade, so Settings history stays isolated across Users. Verification: bun run --cwd apps/web check passed with 0 Svelte errors and 0 warnings; bun run --cwd apps/web test passed 148 files / 1011 tests.
Round 4 E2E progress: the merged Files suite exposed three harness issues before its device/theme matrix could complete.
files.mjsredeclared the sharedpdfFixture, so the duplicate was removed in favor of the existing harness helper.setThemeContext()relied on a userStorage test seam without installing it; the helper now installs the seam. The phone touch probe targeted a folder row overlapped by the floating header (tap coordinate 195,38); scrolling the row to the center before dispatching touch made the probe hit the intended target. The Files keyboard and rename flow now passes at phone, tablet, and desktop widths in both themes. Screenshot cropping also needed the host Nixlibstdc++.so.6directory inLD_LIBRARY_PATH;sharpthen loaded successfully. The full Files suite is continuing through selection, shared, Recent/Trash, and remaining checks.Further Files E2E evidence: the Recent/Trash phone flow asserted that a long-press showed
.marks-visible, then asserted it was hidden before invoking Done. I moved the existing Done action before the hidden-marks assertion, preserving thetrueandfalseexpectations and adding a short comment for the state transition. The phone row is centered before touch dispatch. The isolated Files selection matrix then passed at phone, tablet, and desktop in both themes, with zero CSP reports. A separate loaded full run timed out resolving the alpha row after a select-all toggle; the focused selection matrix reproduced the state at all six configurations and the row remained present witharia-selected=false, so this timeout did not reproduce under the focused run.Files E2E finding (performance-only): the full production-build run passed the phone/tablet/desktop selection, keyboard rename, Recent/Trash evidence, drag-to-pin, and breadcrumb drop flows with 0 CSP reports across 33 pages. It stopped at the existing request-coalescing assertion after the breadcrumb move/reload scenario:
GET /api/v1/files/entries?path=Inbox&limit=500&sort=nameoccurred twice. The list remained usable and the preceding move/stat checks passed. I kept the existing expected request count unchanged. This is a duplicate read only; it is not a crash, 5xx, data loss, authorization or security issue.Search E2E finding (merge contract mismatch): after switching its fixture User into Money and using the shared #555 auth/theme setup, the #545 indexing indicator checks passed at 390, 820 and 1440 px in both themes with no CSP reports. The suite then timed out waiting for Navigate count
7; its expected title list is Calendar, Files, Photos, Mail, Analytics, Money and Ask. The mergedPLUGIN_NAVIGATIONregistry also contains Notes, and Notes is a non-toggleable Core mode, so SearchAccess includes Notes for this User. With Money enabled, the Search provider can expose eight enabled mode rows. I did not change the existing assertion or hide Notes in runtime code because that would resolve a design conflict between #34 and #544 beyond this merge's authorized behavior. This is not a 5xx, crash, authorization or isolation finding; the full Search E2E remains blocked on whether Notes belongs in this Navigate group.Calendar E2E finding: the real event opens in the composer as
09:00 - 10:30 Morning review #area/work, while the existing expectation atapps/web/e2e/calendar.mjs:1231and its keyboard-reopen check expects09:00 - 10:30 Morning review #work. I left the expected text and the nested tag value unchanged. The run stopped at this assertion before the remaining Calendar flow.Finding (reload-safe boot #555 E2E): the setup navigated User A to
/moneyand waited for the real empty-budget state, but Money is a User opt-in and the new User started with it disabled. The initial run timed out at that wait. I added the same explicitPUT /api/v1/plugins/money/me {enabled:true}setup used by Search #544, preserving the empty-state and isolation assertions; I am rerunning the isolation E2E now.Finding (Analytics #504 E2E): the real seeded Analytics run reported one KPI value/delta-chip intersection at 390 px (
Total tracked,313h 40m). Its 1440 px and 1024 px checks passed. Chart-render profiling also observed CPU tasks over 50 ms during range changes (worst 117 ms); this is SLOW-only load evidence, not a merge blocker under the performance rule. The run then stopped during the screenshot material matrix because its fresh BrowserContext did not install the #555userStoragetest seam beforesetThemeread it. I will fix that fixture setup and rerun; I am preserving the layout assertion while investigating the 390 px intersection.Analytics follow-up: after adding 2 px of float clearance, a production-browser probe seeded 23 real 14-hour Log entries plus the indexed prior-year Daily Note and reran the same 390 px range-box calculation. It returned
[]for KPI/chip intersections.bun apps/web/e2e/analytics.mjs --screenshots ... --screenshots-only --material-matrixpassed and produced the Paper/Noir color/photo screenshot matrix at 390, 820 and 1440 px plus hover crops. The full interaction run later timed out waiting for a time-of-day heatmap mark at 30 s while the server logged 4–6.5 s SQLite pool waits; classify that run as SLOW host load. The trace also measured render CPU tasks up to 91 ms; logged as performance follow-up, not a merge gate.Finding (Tasks #531 screenshot E2E): it stopped before the first screenshot in
seedThemeInDocumentbecause each fresh screenshot BrowserContext lacked the #555window.__userStorageTestseam. I will install the shared seam before navigating to/readyz, then rerun the same six phone/tablet/desktop light/dark captures; Task contents and overflow assertions remain unchanged.Tasks #531 E2E follow-up: the #555 theme-seam setup works and the suite now reaches the phone sheet. At 390 px,
.sheet-titleisAll-day items for Thursday, 1 October; the body heading and unchanged expectation areAll-day items. The dialog's accessible label already retains the full date.PopoverSurfacehas an explicitsheetTitleprop, but this call site does not set it. I will pass the concise body heading assheetTitle, preserving the dated dialog label and all test expectations.Tasks #531 follow-up:
bun apps/web/e2e/calendar-task-overflow.mjs --screenshots artifacts/merge-r4/taskspassed after setting the explicit concise phone-sheet title. It saved all six real production captures: 390, 820 and 1440 px in light and dark. The suite verified each Task appears once and the date remains in the accessible dialog label. No test expectation changed.Finding (Toast #539 × keyboard motion #527): a focused toast remains mounted and live (
data-removed=false, 4000 ms ring duration), but after F6 its ring hasanimation-name:noneandanimation-play-state:running. The matched #527 rule frompackages/ui/src/tokens.cssappliesanimation:none !importantto every descendant whendata-input="keyboard"; it cancels the ring's timer visualization before the #539 focus pause can work. Reduced motion is false and the ring selector matches. I will exempt this timer indicator while retaining its focus/page-hidden pause rules; the E2E assertion remains unchanged.Toast follow-up: the keyboard-mode CSS override now makes the original
animation-play-state === 'paused'assertion pass. The focused smoke found a one-frame settling edge: the first offset was 6.2483, then the computed-paused animation advanced to 6.6650 (about 17 ms at a 4 s duration) before remaining paused. I will wait two animation frames before taking the unchanged 700 ms baseline; the<0.1stability assertion stays intact.Toast #539/#527 follow-up: the keyboard input-modality exemption preserves the live ring while focus and hidden-page states still pause it. The full
bun apps/web/e2e/toast-ring.mjs --screenshots ...run passed: geometry at 390/820/1440 in Paper and Tokyo Night, 0/25/75% drain frames, hover pause/resume, F6 pause, Escape dismissal, and the Undo toast's observed 8398 ms lifetime. The unchanged 700 ms offset check now starts after two animation frames.Settings shortcut #541 E2E follow-up: the seeded Note loads with its title and body, but this local server falls back to the documented Markdown editor (
Not live: changes save when you pause). That editor has the Note'srole="textbox"and accessible name, but no.cal-proseclass; the live editor uses.cal-prose. The timeout is therefore a selector mismatch, not a missing Note. I will target the shared accessible Note textbox and keep the comma-content and no-Settings assertions unchanged.Settings shortcut E2E: two test setup issues surfaced in the production build. On phone width, the open Navigation Dialog owns the first Escape and closes before Settings, so the helper now follows the actual overlay stack before continuing; the existing product assertions remain unchanged. The Note typing guard now locates the accessible Markdown fallback editor. Chromium 1.63's bundled browser blocked the real local collaboration WebSocket with
ERR_BLOCKED_BY_LOCAL_NETWORK_ACCESS_CHECKS; the E2E now grantslocal-network-accessonly to its throwaway localhost origin so it exercises the server-backed editor and can retain the console-error assertion. Both are test setup changes, not product behavior changes.Adversarial round update: the admin authorization matrix passed all 2,071 requests over the 335 OpenAPI operations, including all 39 admin operations. The two-User matrix stopped during fixture setup:
xuser_matrix.pycreates a Money budget for User A without enabling the optional Money plugin; #555 moved plugin availability to a per-User setting, so the fixture receives HTTP 404 before isolation assertions run. I will repair the fixture setup and run that focused matrix. Search chaos also reportsadmin_rebuild_search_indexas expected 200 / actual 202; the route already documented and returned 202 on thecc25c441bbase, so I left the old expectation unchanged. The runner's nested Calendar/Mail/Money browser scripts also could not find the custom-target release server becauseCALTERNAL_SERVER_BINwas not set; the separately requested Calendar and Money web E2Es already passed or have their own recorded outcome. The appearance 3 MiB proxy probe returned the proxy's synthetic 502; I am checking it against the direct-backend result and host load before classifying it.Adversarial isolation follow-up: I verified the Photos shared-timeline mismatch is a false positive in the probe, not cross-User leakage. Its unexpected item
875a63cb-6a35-4906-98f4-46f86f05aefais A's ownPhotos/2024/2024-06-02/share-probe.jpg, uploaded after the probe captured A's expected ID list; the database row hasowner_id=A, and B's row is the authorized shared view withviewer_id=B. The assertion compares against a stale pre-upload list. Separately, I committed9927a6ec2to enable the optional Money Plugin for both Users inxuser_matrix.py, so the required ownership matrix can reach its Money assertions instead of failing on fixture setup.The focused two-User matrix passed after the #555 fixture update. Verbatim summary:
Two-User OpenAPI matrix: 335 operations classified; 159 operations replayed; 733 A-ID vs missing-ID comparisons across B, C, D and anonymous; 22 identifier routes classified with no local fixture factory; median absolute timing delta 1.2 msandJob/Mail/quota ownership checks: 97 comparisons; 0 denial failures. The admin authorization matrix also passed 2,071 requests, including 39 admin operations.Merge round 4 report
Branch:
job/merge-round-4Base:
origin/devatcc25c441bHead:
a6fd7f7040972d476575c06a4c363e21070bb42dAll 16 approved branches were merged in this order:
tray-order→kbd-motion-527→title-plain-526→align-538→search-count-544→toast-539→preview-421→analytics-504→drag-snap-536→settings-key-541→bg-flash→tasks-500-531→perf-494→notes-bridge→parity-484→crash-525. No push, deploy, or merge todevwas made. The local merge oforigin/devwas already up to date before final gates.Built and changed
The round combines the Tab Bar ordering and width, keyboard motion, plain titles, IconLabel alignment, Search counts, Toast ring, Calendar preview, Analytics, Calendar drag snapping, Settings shortcut, user-scoped background storage, Tasks, performance profiles, Notes bridge, generated parity registry, and Tag rename stack fix. The contract and API client were regenerated;
packages/api-client/check-generated.shexited 0.Files: 326 tracked files changed (163 under
apps, 62 undercrates, 41 underpackages, 19 underbench, 18 underdocs, 12 undertests, plus contracts, scripts, lockfile, and CI/docs). Highlights:apps/web/src/lib/userStorage.ts,apps/web/src/lib/components/AppToaster.svelte,apps/web/src/routes/calendar/[view]/[date]/+page.svelte,packages/ui/src/components/calendar/TimeGrid.svelte,packages/api-client/src/generated.ts,contracts/openapi.json,contracts/actions.json, and the Notes IMAP/Tasks routes incrates/plugins/notesandcrates/calternal-server.Conflict decisions:
devremoval of the five-tab cap while sizing the Tab Bar tomin(enabled, 5)on desktop and three tabs on phones.Gates
cargo fmt --checkexited 0 with empty stdout. Per-crate Clippy commands exited 0. The terminal completion lines were:cargo build --release -p calternal-servercompleted with:cargo testpassed for every changed crate. Verbatim test result lines retained in the gate logs:calternal-apialso passed: 9 unit tests and 0 doc tests. Its direct gate output was not retained in the sidecar logs.bun run checkoutput:Final
bun run testoutput:E2E and security results
GET /api/v1/files/entries?path=Inbox&limit=500&sort=namecalls and expected none.09:00 - 10:30 Morning review #area/work, expected... #work. The drag snap interaction ran before that assertion.%2e%2esegments anda*bwere literal folder names; actual traversal and reserved-name cases were rejected.tests/adversarial/run.shinvocation was red, so the round is not green. Its Search chaos fixture expects the staged rebuild route to return 200; the route returns 202, which is also the behavior on basecc25c441b. The Money 404 in the first matrix attempt was fixture opt-in; after enabling Money for A and B and accepting 204, the focused matrix passed.run.sh's debug build. Nested Calendar/Mail/Money checks could not find the debug server, and the sync section lackedcalternald. A focusedROUND2_SECTIONS=cli,syncrun built the debug binaries: sync passed. The CLI probe remains red because API name validation rejects its control-character filenames before listing (only two safe names remain), and its retry assertion expectsagentwhile the fixture user isowner. Existing CLI unit tests cover escaping; I left the adversarial expectations unchanged.editor-proxy(local adversarial server is unavailable); the direct backend returned the required 413 and the health checks passed. This is a probe/proxy failure, not a product route 5xx.systemappearance default, DAV alarm 204 vs expected 201, DAV cross-date move/delete 412 vs expected 204, and Calendar burst expected 120 photos but found 0. These were not changed because the job forbids changing existing expectations and limits behavior changes to merge resolution. SLOW latency/timeouts under concurrent load are recorded in the adversarial log; they are load findings.Performance
The feature branches include hot-path profiles and recorded results. No new aggregate profile was run for the integrated snapshot; the local host was running concurrent builds and browser jobs. Stored numbers include:
These measurements are from the recorded feature runs, not a fresh round-4 integrated comparison. Performance is not a merge gate.
Decisions and remaining gaps
No new product behavior decision was needed outside the approved branches. Integration choices are listed above. Do not merge this round yet: resolve the Notes restart/data-integrity finding and review the other non-SLOW adversarial findings, then repair the stale/unprovisioned E2E fixtures without changing their existing assertions.
Screenshots are attached (Money captures were excluded): Files selection, Files Recent, feature E2Es, Calendar preview cards, Calendar week hover, User-storage appearance/login.
Cleanup:
cargo cleanreportedRemoved 33908 files, 19.8GiB total;apps/web/buildwas removed. Worktree is clean. No push or deploy was made.Start integrity triage on job/merge-round-4 at
a6fd7f7040. Comparecc25c441bproduction with this merged head. Focus on restart durability, room epochs, rebuild byte preservation, Reminder completion and Calendar photo readback, then the three E2E stops. No push or deploy.Started merge-round-4a on branch
job/merge-round-4a, based on origin/dev atcc25c441b7a974185622a1dee853cf38686d2b67. I’m checking the round-4 conflict resolutions, then I’ll merge the eight approved web branches in order and run the requested web gates and production e2e set. No Rust changes are intended.Started data-consistency follow-up for merge round 4. Branch:
job/merge-round-4. Initial head:a6fd7f7040972d476575c06a4c363e21070bb42d. Comparison base: productioncc25c441b. I will compare the six findings ten times at each revision, inspect the three E2E stops, and commit each confirmed fix with a deterministic regression test. No push or deploy.Source findings for #427:
6e0d42faeadds Notes toPLUGIN_NAVIGATION. The existing group unit test already requires all eight rows. The seven-row E2E assertion omits Notes. Update it to include Notes and retain an exact title/order assertion.#worktoarea/workin Log mode (CONTEXT, DESIGN §31). Both revisions use this mapping. The edit dialog returns the stored Tag. Update the two edit assertions to#area/work; do not change stored Tags.loadFilesVisibility().then(syncVisibility)callback reloads even when neither switch changed. The callback is byte-identical on productioncc25c441b. Keep the duplicate-request assertion and remove only that unnecessary reload after confirming the real-server behavior.ReminderResource::calendar_datapreservesdav_metadata.completed_at, andreminders.rsis unchanged between production and round 4. The probe writes 09:00 and expects 00:00. The focused readback will verify the supplied timestamp on both builds before updating the assertion.Integration check found that the merged layout kept an unused
selectSubviewfragment from #571 after #526 removed the title sub-view menu;ModeHeaderhad no matching callback. The firstbun run checkreportedMODE_SUBVIEWSmissing at+layout.svelte:397and an implicitany. I removed the stale fragment, updated the Top row comment to DESIGN §34, and reran the check:svelte-check found 0 errors and 0 warnings.The original Notes restart probe has a pre-existing fixed 4 s save assumption.
restart.mjs,calternal-collab, the Notes provider, and DAV Reminder persistence are byte-identical betweencc25c441banda6fd7f704. The old report first read the 44-byte original body, then read 63 bytes after reconnect: the 19-byte difference is exactly the pending edit and separators. This is consistent with one delayed save and replay, not duplicate content. A valid cached snapshot must retain its epoch while its file etag still matches. The subsequent stale-epoch and legacy-refusal expectations require the preceding edit to have reached disk.Written reason for the probe change: wait for the actual edit to appear exactly once on the REST read before the crash cut point. Keep the original stale-epoch, legacy-refusal and byte-equality expectations. If persistence times out, stop there and report that one failure, rather than infer three more integrity failures from an unestablished precondition. An in-process regression test will cover a crash before the write and idempotent pending-edit replay without a timing race. No product epoch behavior changes.
The requested toast-ring e2e passes ring geometry and hover pause checks, then fails its F6 keyboard-focus pause assertion: computed
animationPlayStateisrunningattoast-ring.mjs:502. A focused production-browser probe showed the cause: the #527 keyboard-mode selector inpackages/ui/src/tokens.csssetsanimation: none !importanton every descendant, which cancels the #539 timer-ring animation before AppToaster can pause it with Sonner. I’m making the timer stroke an explicit exception to that global motion reset, so its existing expanded-state pause remains authoritative.Comparison complete: production
cc25c441band mergeda6fd7f704each passed ten original Notes restart probes, ten Reminder completion write/read probes, and ten 120-photo bursts with eight workers. Every photo was accepted (POST 201, PATCH 204) and visible exactly once. The source diff for calternal-collab, the Notes provider, restart.mjs and DAV Reminder persistence is empty across those heads.Four Notes follow-ups are filed separately: #597 missing edit, #598 stale report, #599 44→63 bytes, #600 legacy sync. These reports remain unreproduced; the confirmed pre-existing probe defect is its 4 s persistence assumption. The exact 19-byte delta is one pending edit and separators. The new in-process test proves retained-epoch/idempotent replay at a pre-save crash cut point; the corrected real-server probe observes a persisted edit before requiring a new epoch.
Reminder: #558 has the 09:00 request / 00:00 expectation defect and twenty successful timestamp-preserving reads. Photo burst: #565 already records rejected uploads on production; the original round-4 0/120 witness is missing, so no accepted-write-loss claim can be established. No introduced integrity failure is reproduced, so there is no failing case to bisect across the 16 merges. This does not rule out an interaction present only in the old full-suite fixture.
Files duplicate Inbox GET was reproduced with the production binary and fixed by
ec000d777. Search's eighth row is the Notes Tab added by round 4; Calendar shows the canonical stored #area/work Tag. Written expectation reasons are above. Focused flows passed; full Calendar still stops at the pre-existing #569 composer snapshot. The additional Files hidden-files fixture uses the wrong Apple AAE filename; it remains unchanged, and a temporary correct-filename diagnostic passed (#420).Final bounded ordinary-write round:
consistency probe: 0 findings;restart probe: 0 findings. The full exploit/protocol-abuse campaign was not run in this session and remains a release-verification gap. Rust crate gates are running; web check and all 1011 tests passed. Files production screenshot evidence (390/820/1440, Light/Dark and additional widths) is attached: https://git.kayg.org/attachments/fd3cbd26-fb49-430d-a2f7-e1a5211a69f9 . Local benchmark numbers and the release/large-folder follow-up are on #563.Round 4 consistency follow-up — head
f91f5484992a39d6e23664d73f55a2d556ee3b88Built and committed the Files duplicate-listing fix, focused persistence comparison, corrected probe preconditions, and a deterministic in-process Notes crash regression. No push or deploy. The worktree is clean. Required
origin/devintegration ran once: documentation-only head4b849557fb584587e5a651eecc2a5dacf65781a5, merged in208383af7. The conflict kept the latest owner Toast timings and the round-4 feature decisions.Release status: no introduced data-integrity failure was reproduced. These comparisons give no evidence that round 4 makes production worse. This is not a full release clearance: the original four Notes incidents have no raw witness and remain unreproduced; the full exploit/protocol-abuse campaign was not run in this session. The final robustness check was a bounded ordinary-write/restart round, not the full suite.
Comparison and classification
The isolated production binary reported
cc25c441b7a974185622a1dee853cf38686d2b67; the merged binary reporteda6fd7f7040972d476575c06a4c363e21070bb42d. Each ran ten original restart probes and ten ordinary Reminder/120-photo checks. The focused API probes preserve the original completion PUT and photo upload flow but use an owner-only fixture, not the old full-suite accumulated state. The source diff is empty for calternal-collab, the Notes provider, restart.mjs and DAV Reminder persistence across these two heads.No introduced failing case exists to bisect across the 16 merge commits. This does not exclude an interaction confined to the old full-suite fixture. No product epoch or persistence contract was changed.
The new Rust test replaces volatile rooms in process before any save timer starts. It asserts the same cached epoch, unchanged disk body before replay, and the exact edited body after applying the same pending update twice. Existing post-write restart tests still require a new epoch. The real-server restart probe now observes the edit on disk before its crash, keeps the original stale/refusal/byte-equality assertions, and stops at a failed persistence precondition instead of reporting dependent noise.
E2E assertion triage
ec000d777skips a reload only when both visibility flags already match the loaded listing. The exact duplicate-request assertion was retained and passes.6e0d42faeadds Notes to PLUGIN_NAVIGATION. Its unit test already expects eight rows. The E2E now includes Notes and still asserts exact titles/order and keyboard reachability. Written reason was posted before changing it.nFrozen snapshot; that expectation is unchanged.hidden-proof.png.aae; contract is<stem>.aae). A temporary correct-filename diagnostic passed the full preference flow and was removed; #420 has the evidence. The committed fixture remains unchanged for owner review.Files changed since the incoming merged head
CONTEXT.md and docs/DESIGN.md changes come from the required origin/dev integration. All other changes are atomic job commits. No dependencies or migration numbers changed. Doc comments were re-read before this report.
Gates
cargo fmt --check: exit 0, empty output.cargo clippy -p calternal-collab --all-targets -- -D warningsandcargo test -p calternal-collab: exit 0 (73 tests plus doc tests). Rust environment: CARGO_PROFILE_DEV_DEBUG=line-tables-only, CARGO_INCREMENTAL=0, CARGO_BUILD_JOBS=4, worktree target/tmp; preset CARGO_TARGET_DIR retained. No Rust route/contract implementation changed, so calternal-server was not a touched-crate gate.Verbatim Rust gate summary:
bun run checkandbun run test: exit 0. Verbatim summary:DAV probe unit tests: 15 passed. Focused production-SPA E2E output:
Final bounded robustness output, verbatim (fresh owner-only fixture, one 120-photo burst and one two-restart run):
The full robustness suite has no new summary to quote. It was not rerun. Its other previous non-SLOW findings are outside this focused investigation.
Performance and visual evidence
New profile: bench/files-listing-427.py. Local debug run, shared-host load 21.77/22.01/20.38, 120 real uploaded photos: 50 serial reads p50 29.74 ms / p95 52.87 ms, CPU 1.0 s (59.38%), mean RSS 444593574 / peak 447209472 bytes. Burst 32 reads / eight workers: p50 71.46 ms / p95 111.63 ms, CPU 0.46 s (134.72%), mean RSS 447233536 / peak 447250432 bytes. Baseline files.entries: 1.8 / 3.1 ms on release perf-test at
369ab6a2f9. Environments are not comparable. #563 records the release/perf-lock and largest-folder follow-up; 120 entries do not fulfill the realistic 50k worst case.Files screenshot archive: production build, 390/820/1440 px, Light/Dark, plus additional widths/zoom. Row-box geometry assertions passed; cap-height visual signoff remains with Claude (#538). Claude remains the visual reviewer; no claim of visual approval is made. Comparison and full gate logs contain no private fixture credentials.
Known gaps: original four Notes witnesses and original photo upload-status witness unavailable; full robustness campaign unrun; full Calendar and unchanged Files hidden-files E2E stop as described; largest realistic release performance run pending.
Decisions: no new product behavior outside DESIGN. Test choices: use a read-confirmed persistence cut point, preserve completion instants, include every enabled Navigate Tab, keep canonical stored Tags, and keep upload rejection separate from accepted-write loss. Do not change a valid epoch or weaken photo-count assertions to suppress a finding.
Cleanup: temporary production worktree, web build, snapshot binaries and private runtime fixtures removed. Screenshot and redacted evidence artifacts retained.
cargo cleanexited 0 with this output:Starting merge round 6 on
job/merge-round-6, based onorigin/devat3f258302a0f2d6418ff60c9ce22cbb33e008ca99. I have readCLAUDE.md,CONTEXT.md, the relevant Calendar, Mail, Appearance, Chrome/motion and Notes sections ofdocs/DESIGN.md, and issue #427. I will merge the eight approved branches in the requested order, apply the two small UI fixes, then run the requested gates and one time-boxed robustness round.Merge findings and resolutions so far:
(folder_id, generation, message_id)to(folder_id, generation, uid). The oldON CONFLICT(folder_id, generation, message_id) DO NOTHINGinsert clause is removed because the new schema permits several UIDs to reference one message.Gate finding:
bun run --cwd apps/web testfailed 3 of 1,053 tests (150 files passed). Failures: the Calendar week short title now returnsSepwhile my added assertion expectedSep 2026; a warm Calendar snapshot remains stale after the unmounted-view Files notification instead of being removed; and the #549 preview-editor test cannot find itsEdit log entrycontrol. I am resolving the title assertion and reconciling cache/editor behavior with the current shared Composer and retained-snapshot design before rerunning the web gate.Gate finding:
cargo test -p calternal-plugin-notesfailed 1 of 167 tests.tests::daily_and_composer_preserve_unrelated_bytesreceives 404 fromGET /journal/2026-09-24after the Composer successfully appends to a Daily note whose legacy Log line needs a block ID. The new #549 snapshot reader does not repair or serve that committed source in this case. I am tracing the pending-ID/snapshot path; all other Notes tests passed (166 passed, 0 ignored).Finding update: the focused test passes when run alone. The full Notes suite uses one shared test User ID, and under parallel test load another Notes writer can hold the User mutex while the Journal snapshot fallback tries its nonblocking legacy-ID repair; that read then returns 404. I kept the #549 nonblocking snapshot contract and the byte-preserving Log write contract, because repairing the legacy line before the Log write returns changes bytes earlier than the existing test and design allow. I will run the Notes test gate serially and record this transient missing-snapshot race as a known gap for follow-up.
Finding during merge-round-6 e2e:
toaststack-616.mjscould not click Sync now because the shared Mail fixture had no successful-sync timestamp, so #613 correctly kept the button busy as a first sync. After representing the fixture accounts as previously synced and having the toast probe return a completed status after its gated queue request (there is no IMAP worker in this probe), the unchanged five-click dedupe assertions passed and 12 production screenshots were captured. Commit:83431474c992.Finding during merge-round-6 e2e: the Week Today check initially timed out at 17:32 local because its now line was 6.5 hours below the scroller top, beyond the test's existing 1–5 hour window. The app focused the correct date and kept the correct Week URL. Playwright 1.63 had reset the attempted fake clock after the full-page navigation. The e2e now pins its test clock to local noon and installs it on the loaded page before each Today action; the assertion is unchanged. Both Today actions passed, then the script saved all 12 Week/Day screenshots at 390, 820, and 1440 px in light and dark. Commit:
9cb68197460c.Finding and fix: the production glass audit reached the desktop context submenu at 1440 px and found that the expanded “View as” trigger lost its hover highlight when the pointer entered its child surface. The recursive Menu explicitly suppressed the active state for an open submenu trigger. I removed that suppression and documented the pointer-state invariant. The audit expectation remains unchanged; I am rebuilding and rerunning the full audit now.
Finding from the real production glass audit: the Settings inner-card assertion still calculated light alpha from the pre-#588 36% overlay. The page rendered 92%, which is the new 78% light overlay plus the unchanged 14-point inner-card step. I updated this expectation because #588 explicitly changes the light glass token. Dark alpha and the shared step are unchanged; rerunning the audit now.
Production Chromium evidence from
test:e2e:glass-audit: after opening/notes, the audit timed out waiting 30 s for the realNotes actionsbutton.NotesExploreris rendered only whenAppSidebarreceivesmode === 'calendar', butmodeForPath('/notes')now returnsnotesand the mode registry has a Notes mode. This leaves Notes mode without its Notes tree or actions. I changed the sidebar condition to match Notes mode, with DESIGN §§28 N1 and 34 and job #549 recorded by the module comment; the production audit will verify the fix.Production Chromium evidence from
test:e2e:glass-audit: the dark 390 px pass reached the Catppuccin row, which has a submenu, then timed out waiting for a separate flyout.Menu.svelteintentionally drills into a child list on narrow layouts; it does not open a flyout on hover. I updated the glass audit to tap submenu rows and return through the back row at 390 px, while retaining hover/flyout checks at desktop widths (issue #436, DESIGN §34).The follow-up production audit reached the Catppuccin submenu at 390 px after switching the test to the documented tap-to-drill interaction. The blur check then sampled its old location: the probe was at y=363 while the live menu had re-placed to y=629, so the measured variance ratio was 1.00 outside the glass surface. The audit now repositions its stripe from the live surface bounds before each pixel check (issue #436, DESIGN §34).
The focused 390 px dark audit opened and measured the real Catppuccin submenu, then failed while returning to the root menu.
Menu.sveltelabels its drill-back rowBack to <current submenu>; the audit had hard-codedBack to Theme. I changed it to use the active family label, so the sweep can continue through every narrow-layout submenu (issue #436, DESIGN §34).Production Chromium evidence: the dark 1440 px Theme variant menu opened and accepted its selection, but the audit timed out waiting for raw
localStorageto change. Appearance preferences use the per-User storage namespace, the same production store used by Photos. I am updating both the read and wait inselectThemeSubmenuByMouseto use the audit's__userStorageTestseam (issue #436, DESIGN §34).The focused dark 1440 px production audit passed Theme, Files, Photos, Notes and Editor menus, then failed while checking the Calendar preview Tooltip. The test moved the pointer to page coordinate (5,5) to dismiss the Tooltip; that also left the anchored preview and removed its trigger before the keyboard check. I will dismiss it over a non-action area inside the live preview so the Tooltip closes while the preview remains mounted (issue #436, DESIGN §34).
The targeted Tooltip rerun showed that hovering the preview eyebrow did not dismiss the visible Tooltip, even though the trigger stayed mounted. The shared layer dismisses on focusout and shows again on reader keyboard navigation. I am using Shift+Tab to dismiss the pointer Tooltip, then Tab to check the keyboard Tooltip, while keeping the pointer over the anchored preview (issue #436, DESIGN §34).
The focused 390 px surface audit passes with the fixture in its initial Files view. In the full run, the earlier desktop menu audit changed the saved Files view to Grid; the selection-tray audit then timed out on a
.fc-itemtext match. The existing context-menu audit documents that Files clips visible names but preserves the full filename in the option's accessible name. I am switching the selection-tray audit to that same role/name locator (issue #436, DESIGN §34).The full glass audit reached Chromium light / week background / 1440 px, then timed out opening the Calendar preview. Playwright reported the Event center was intercepted by an attachment thumbnail (
.pile-slot); the Calendar still contained the provider-backed Event. I am updating the audit to find a real unobscured point inside the Event before moving the mouse, so the preview check exercises the production hover behavior without an overlay intercepting the test coordinate.The Chromium visual and interaction matrix completed. WebKit then timed out waiting for the first Calendar route to hydrate its Light theme: the test context used the local HTTP origin, where WebKit does not expose the Secure
__Host-calternal_user_hintcookie needed by the per-User Theme store. I am moving WebKit screenshots to the existing same-origin HTTPS test front ine2e/harness.mjs, so the production app receives the real secure session and user hint.The HTTPS run authenticated correctly and its real Calendar range returned “Attack on Titan,” but the Event was absent from the WebKit grid. The first fixture context set the host timezone; the second browser context did not. This left WebKit's virtualized TimeGrid centered at 18:00 UTC while the Event was at 20:00 Europe/Berlin. I am giving both browser contexts the same timezone so the actual rendered Calendar view and fixture use the same local hour.
Finding: Linux WebKit's Calendar TimeGrid emitted an initial scroll event while its 2,001-day track still had zero scroll range. then replaced with 2024-01-02 and then 2021-04-07. After the fix, the route and visible columns remain on the requested 2026 week, and the real Attack on Titan Event renders. Fix: defer the initial scroll write until the next frame, ignore scroll/settle events until then, and keep the grid hidden until positioned. Added a deep-link assertion to the production glass audit. Commit:
597f208cc.Correction to the finding: Linux WebKit's Calendar TimeGrid emitted an initial scroll event while its 2,001-day track still had zero scroll range. The Calendar replaced the requested week of 2026-09-28 with 2024-01-02 and then 2021-04-07. After the fix, the route and visible columns remain on the requested 2026 week, and the real Attack on Titan Event renders. The fix defers the initial scroll write until the next frame, ignores scroll and settle events until then, and keeps the grid hidden until positioned. The production glass audit now asserts that the deep link remains unchanged. Commit:
597f208cc.Finding: the real HTTPS front used by the glass audit forwarded API streams but dropped Notes collaboration WebSocket upgrades. On the production Note route, the API created the Note but the editor remained at Connecting and its contenteditable surface did not mount. I added a streamed TCP tunnel for upgrade handshakes and frames. Evidence: the focused Chromium Notes and Editor menu audit now passes, including opening a real Note and applying Turn into and Move actions.
The redundant Playwright API route caused a late ECONNRESET during the first full WebKit glass run. The HTTPS fixture already sends the real Secure session cookie, so I removed that route and let same-origin requests go directly through the HTTPS front. Verification: full Chromium glass audit passed; full WebKit glass audit passed across all three widths, light/dark themes, theme/photo backgrounds, menu states, and interaction checks. Linux WebKit still reports its expected backdrop-pixel and Block action limitations; Chromium covers the rendered pixel and real Editor actions. Commit:
828df0a32.Merge round 6 final report
Merged approved branches in the requested order:
job/motion-611,job/weekstate-609,job/toaststack-616,job/mailsync-613,job/maildup-626,job/ghosttask-623,job/lightglass-588, andjob/tabswitch-549. Also merged the currentorigin/devonce before final gates. No push or deploy was made.Head:
3286cad7208562f3c357fb59204854b0dbab6f84.Built and integration fixes
202, progress, and connect-toast states. Mail migration0009supports duplicate UID memberships; removed the now-obsoleteON CONFLICT (..., message_id) DO NOTHINGhotfix clause. Deleted Tasks no longer project into Calendar. Light glass and contrast checks are integrated. Journal day snapshots and cached Calendar rendering are integrated with Notes migration0024.Intlmonthshortformatting (Sep). Removed the Appearance sentence “A 91% paper scrim keeps text readable on this picture.”route.fetchcookie workaround after it caused a lateECONNRESET; the HTTPS origin already supplies its Secure session cookie.origin/dev: Mail0009and Notes0024were free.Changed files
CLAUDE.mdapps/web/e2e/animation-trace.mjsapps/web/e2e/calendar.mjsapps/web/e2e/files-paste.mjsapps/web/e2e/glass-audit.mjsapps/web/e2e/harness.mjsapps/web/e2e/kbd-motion-527.mjsapps/web/e2e/mail-sync-613.mjsapps/web/e2e/settings-shortcut.mjsapps/web/e2e/task-trash-623.mjsapps/web/e2e/theme-variants-506.mjsapps/web/e2e/toaststack-616.mjsapps/web/e2e/weekstate-609.mjsapps/web/package.jsonapps/web/src/app.d.tsapps/web/src/lib/a11y/inputModality.tsapps/web/src/lib/actions/pillFeedback.test.tsapps/web/src/lib/actions/pillFeedback.tsapps/web/src/lib/calendar/ItemPreview.svelte.test.tsapps/web/src/lib/calendar/agenda.svelte.test.tsapps/web/src/lib/calendar/data.test.tsapps/web/src/lib/calendar/data.tsapps/web/src/lib/calendar/journal.test.tsapps/web/src/lib/calendar/journal.tsapps/web/src/lib/calendar/model.test.tsapps/web/src/lib/calendar/sidebarState.svelte.tsapps/web/src/lib/calendar/window.test.tsapps/web/src/lib/capsule-motion.test.tsapps/web/src/lib/components/AppToaster.svelteapps/web/src/lib/components/SidebarLinks.svelteapps/web/src/lib/components/ToastBody.svelteapps/web/src/lib/components/analytics/BklitTooltipMaterial.test.tsapps/web/src/lib/components/app-sidebar.svelteapps/web/src/lib/files/FilesSidebar.svelteapps/web/src/lib/mail/MailSidebar.svelteapps/web/src/lib/mail/MailSidebar.svelte.test.tsapps/web/src/lib/mail/syncStatus.test.tsapps/web/src/lib/mail/syncStatus.tsapps/web/src/lib/navigation/modePreload.tsapps/web/src/lib/notifications/InboxPanel.svelteapps/web/src/lib/stores/toasts.svelte.test.tsapps/web/src/lib/stores/toasts.svelte.tsapps/web/src/lib/themes.test.tsapps/web/src/lib/time.test.tsapps/web/src/lib/tray.svelte.test.tsapps/web/src/lib/ui/uiScale.svelte.test.tsapps/web/src/lib/ui/uiScale.svelte.tsapps/web/src/routes/+layout.svelteapps/web/src/routes/calendar/[view]/[date]/+page.svelteapps/web/src/routes/settings/[...path]/+page.svelteapps/web/src/routes/settings/appearance/BackgroundGroup.svelteapps/web/src/routes/settings/mail/MailSection.svelteapps/web/src/routes/settings/mail/MailSection.svelte.test.tsbench/calendar-weekstate-609.mjsbench/hdd-emu.shbench/kbd-motion-527.mjsbench/mail-sync.pybench/run.shbench/tab-switch-seed.pybench/tab-switch-trace.pybench/tab-switch.mjsbench/tab-switch.test.mjsbench/task-trash-623.pybench/toast-ring-539.mjscrates/calternal-plugin/src/lib.rscrates/calternal-plugin/src/timing.rscrates/calternal-server/Cargo.tomlcrates/plugins/calendar/src/lib.rscrates/plugins/calendar/src/view.rscrates/plugins/files/src/lib.rscrates/plugins/files/src/listing.rscrates/plugins/mail/Cargo.tomlcrates/plugins/mail/migrations/0009_duplicate_uid_memberships.sqlcrates/plugins/mail/src/cache.rscrates/plugins/mail/src/cache/store.rscrates/plugins/mail/src/imap.rscrates/plugins/mail/src/routes.rscrates/plugins/mail/src/sync.rscrates/plugins/notes/migrations/0024_journal_day_snapshots.sqlcrates/plugins/notes/src/lib.rscrates/plugins/notes/src/store.rscrates/plugins/notes/src/tasks_api.rscrates/plugins/notes/src/tasks_dav.rscrates/plugins/notes/src/tasks_store.rsdocs/DESIGN.mddocs/perf/2026-10-01-maildup-626.mddocs/perf/2026-10-01-tabswitch-549.mddocs/perf/baseline.jsondocs/perf/runs/tab-switch-2026-10-01-549-after-smoke.jsondocs/perf/runs/tab-switch-2026-10-01-549-partial.jsondocs/perf/runs/tab-switch-2026-10-01-549-round3-hdd.jsondocs/perf/runs/tab-switch-2026-10-01-549-round3-scale-warm.jsondocs/perf/runs/tab-switch-2026-10-01-549-round4-corrected-smoke.jsondocs/perf/runs/tab-switch-2026-10-01-549-round4-final-hdd.jsondocs/perf/task-trash-623.mdpackages/api-client/src/index.test.tspackages/api-client/src/index.tspackages/ui/src/components/OverlaySurface.sveltepackages/ui/src/components/SegmentedControl.sveltepackages/ui/src/components/TabBar.sveltepackages/ui/src/components/calendar/AgendaList.sveltepackages/ui/src/components/calendar/ItemPreview.sveltepackages/ui/src/components/calendar/MiniMonth.sveltepackages/ui/src/components/calendar/TimeGrid.sveltepackages/ui/src/components/calendar/model.tspackages/ui/src/components/calendar/window.tspackages/ui/src/components/menu/Menu.sveltepackages/ui/src/date.tspackages/ui/src/index.tspackages/ui/src/motion.tspackages/ui/src/time.tspackages/ui/src/tokens.csstests/adversarial/calendar_event_tags.mjstests/adversarial/mail-sync.mdtests/adversarial/mail_screenshot_fixture.pytests/adversarial/mail_sync_provider.pytests/adversarial/task-trash-623.mjsGates and evidence
Output excerpts below are verbatim.
cargo fmt --all -- --checkexited 0 with no output. All listed clippy commands exited 0:Per-crate Rust test outputs:
The server failure was
wire::tests::live_apps_run_in_separate_processes: nested testfull_app_setup_session_config_and_backuptimed out atcrates/calternal-server/src/wire.rs:7533withcalled Result::unwrap() on an Err value: Elapsed(())while waiting for the dedup scrub. No test expectation was changed.Web gates:
The production build completed (
✓ built in 39.88s). Toast, week-state, TLS Dovecot mail-sync, and task-trash e2e runs passed. Their logs report, respectively:PASS: five Sync now clicks queued once, one non-empty toast rendered, and 12 production screenshots saved;calendar Week state e2e: focus, URL, data, both Today actions, cross-month title, and screenshot matrix passed;PASS Mail screenshots captured at 390, 820, and 1440px in Light and DarkwithCSP REPORTS mail-sync-613: 0 across 1 pages; and all six task-trash combinations at 390/820/1440 px in Light and Dark passed.The glass audit produced 166 screenshots per engine, with Chromium and WebKit surface checks passing in segmented runs. The final combined audit rerun did not finish: it timed out in
setThemewhile switching theme. Linux WebKit cannot rasterize backdrop-filter pixels; Chromium covered those pixel checks and Notes Editor block actions.Calendar e2e is not green. The latest run ended with:
The two-User/admin matrices and the one robustness-suite run remain undone. The four-hour stop point was reached, so I stopped without rerunning gates.
Performance
The perf VM lock was occupied, so measurements were local. Profiles and results are in
docs/perf/andbench/. Week-state measurements: 2k updates p50 2.2 µs / p95 5.54 µs; 10k worst-case updates p50 0.93 µs / p95 1.76 µs. Toast dedupe at 390 px: p50 18.5 ms / p95 54.2 ms; 50-toast burst 65.3 ms p50/p95. Mail local sync averaged 2.92 s over 2k messages, with page p50 27.87 ms / p95 51.06 ms. Task-trash debug restore on 1k Task Notes exceeded 120 s and is marked SLOW; there is no valid p50/p95 result. There is no matching baseline for these paths to calculate a regression threshold.Decisions where DESIGN was silent
Intlshort month formatting for the week title.Screenshots (ignored worktree artifacts, not committed): Chromium glass matrix, WebKit glass matrix.
Cleanup:
cargo cleanreportedRemoved 21186 files, 12.9GiB total; removedapps/web/.svelte-kitandapps/web/build.Starting round 2 on
job/merge-round-6at3286cad7208562f3c357fb59204854b0dbab6f84. Branch base (merge-base with current origin/dev) is3f258302a0f2d6418ff60c9ce22cbb33e008ca99.I will reproduce the isolated server test and Calendar resize e2e, run the missing isolation/adversarial and glass audit gates, then merge
origin/devonce at the end only if its ref has moved.Server test comparison:
wire::tests::live_apps_run_in_separate_processespassed 5/5 on3286cad7208562f3c357fb59204854b0dbab6f84(test durations: 17.34s, 17.79s, 10.53s, 14.56s, 24.98s) and 1/1 onorigin/devat687ff703136e71e89f8dfba139e93cd0788b25c1(7.85s).crates/calternal-server/src/wire.rsis identical at both revisions. The scrub poll already checks forphase == "complete"every 50ms, but only allows 10 seconds; I will make that condition wait load-tolerant while keeping a finite deadline.Calendar e2e evidence: the bottom-edge resize passed in the full production run (the moving Journal block showed
09:00and11:00, and the saved end was11:00). The run then failed during inline edit: the PATCH response changed the title but moved the entry from2026-09-30to2026-10-01; the e2e queried the original day and did not find it. The Composer already documents that a bare time parse resolves to today, so I am tracing the editor's date resolution and will preserve the source day unless the text contains an explicit date token.Calendar date-edit fix: the production Calendar e2e now passes the bottom-edge resize checks and the edit of a Journal entry on
2026-09-30; the edit keeps that source date when the text has no date token. The previous run showed the parser's current-day value moving the entry to2026-10-01. The full e2e then advanced to the next check and timed out waiting for theOpen notelink after “Turn into note”; I am inspecting the rendered action and accessible name.Calendar E2E investigation finding: the Composer's “Open note” toast action renders as a button through the shared ToastBody component. The old test queried it as a link and timed out after the note was created. Updated the locator to assert the visible button label; no user-visible behavior changed. Commit:
7f91461b41.Calendar fixture finding: the Files replacement hit the server's atomic BLAKE3 precondition (412
upload destination changed). A temporary trace at the filesystem precondition confirmed that the bytes changed during finalization; the server correctly rejected the stale replacement. I changed this fixture setup to append through the Daily Note body API with its required If-Match ETag, retrying only on 412 and preserving the latest body. The repair-hint assertion remains unchanged. This keeps the test on the single-writer Notes path and removes an unrelated Files-versus-Journal race (#427, DESIGN §§2, 38).Calendar repair follow-up: the repair endpoint returned 200 and rewrote the Daily note to
- 19:00 dinner with Sam, while/api/v1/notes/journal/{date}kept the previous snapshot because the newly valid line has no stable block ID yet. This matches the existing #549 rule that Journal snapshots stay on the last complete revision until ID reconciliation. I added an explicit/notes/reconcilestep after repair in the E2E before asserting the committed Journal view; the repair response and resulting entry assertions remain in place.Calendar E2E follow-up: the midnight-range assertion later queried
.block.actualglobally. TimeGrid mounts both the source-day segment and its next-day continuation, so strict mode found two identical Journal titles after the resize checks had passed. Scoped the locator to the source date column, which is the segment owning the stable Log identity used by the move assertion.Calendar E2E copy finding: after the midnight selector fix, the suite reached the future Composer guard and timed out on the old phrase “A log entry is for now or earlier”. The production Composer uses the CONTEXT glossary term “Journal” in its validation message. Updated the test to match the rendered Journal copy.
Calendar E2E fixture finding: the Agenda deck test uploaded its Daily note under
Notes/Journal, but the canonical Daily note folder has moved toNotes(as documented bycalendar-perf.mjs). Calendar therefore did not show the fixture line. Updated the test upload to the canonical folder; its attachment and Agenda assertions are unchanged.Calendar E2E Agenda finding: after correcting the Daily note folder, the fixture was still absent because Agenda initially loads only two days while this fixture is four days back. The UI has a “Show earlier days” control. The test now activates that control before checking the older fixture row, so it exercises the real paging behavior.
Round-6 Calendar e2e findings: GridColumn still renders .drag-label-start/.drag-label-end. The bottom resize commits and its live labels pass after the test waits for the single settled source-day block; the top resize also passes with that state wait and source-day scope. The original label timeout was stale rendered geometry, not a removed selector. The Agenda test also expected Enter to expand the attachment deck, but AgendaList now routes Enter to its documented Journal edit action (
39c5b07); the test now follows that behavior and selects the line to expand the deck. The full run next exposed a stale column-geometry assertion after ArrowRight: the route changed while the visible header was still settling. I changed it to wait for the user-visible date header; the next full run will verify that and continue the suite.Additional Calendar e2e finding: the photo preview flow used click-to-open, but merged #589 changed desktop activity previews to open on hover. The full run reached the photo pile, focused it, and then timed out with no popover. The test now hovers the photo pile and asserts the visible preview, matching the current interaction. The preceding date-window check also confirmed the route/title date but the old virtual-column coordinate helper returned null, so reload checks now assert the visible Calendar title.
Correction to the photo finding: the clicked pile selects the Calendar activity; Cmd+I opens its anchored Inspector under DESIGN §34. A hover only showed its warm Tooltip, and no preview. The test now selects the pile and uses Cmd+I before asserting the saved photo. The previous comment that this flow should use hover was inaccurate; the hover-preview change affects other item types, while this pile uses the selection/Inspector action.
The photo Inspector opens after the selection + Cmd+I path. Its accessible UI has both a filename link and an “Open photo” link, so the old substring locator matched two visible actions and failed strict mode. The e2e now asserts the exact filename link.
The Journal attachment preview showed the recognized ticket.jpg as an accessible photo link (“Open photo ticket.jpg, 01:25”), not an “Open ticket.jpg” button. The old test selector was stale; it now asserts the photo link the User sees.
Correction for the attached JPG: the server range API intentionally presents linked images as “Photo · ” (with ticket.jpg in the card Tooltip). The prior test expectation “Open ticket.jpg” did not match this accessible display name. It now asserts the photo card label and its full-name Tooltip.
Calendar follow-up finding: the Agenda fixture is valid (both Notes Journal and Calendar range return the Sept 28 entry and its three attachments). The stress E2E then fails at Week/1440: the lane cap counts space used by the 34 px +N pill as a content lane, while GridColumn also reserves 34 px on every visible block. The existing 50-overlap stress assertion reports three block slivers. I’m changing the cap so an overflow cluster gives one lane to +N, and will rerun the full E2E.
Calendar E2E finding: the overflow-lane change now passes the 50-entry checks at Day/1440, Week/1440 and Week/390. The later resized-grid assertion is stale:
parseFloat()on the--guttercustom property yields NaN (bodyWidth: null), while TimeGrid.measure uses a 56 px fallback; the actual seven-column track is 686.98 px. I am aligning the test gutter fallback with the production sizing rule and rerunning the full flow.Calendar E2E finding: after using TimeGrid.measure’s 56 px gutter fallback, the resized-grid check passes. The Agenda next fails because both the selected inline deck and the desktop hover preview expose an
Open ticket.pdfbutton. The test already identifies the inline deck ascards; I am scoping the remaining visibility check to that list.Calendar E2E finding: the keyboard check reaches Control+i after Enter opens the Composer and Escape closes it, but that sequence leaves no selected item. The app shortcut correctly opens Day info when there is no selected item; DESIGN §39 says Control+i opens the preview for a selected item. I am adding the supported Space selection before that shortcut. The Agenda fixture is present in the API, but one run stayed at its initial two-day state after the pager action; I am refreshing the app after external fixture writes and explicitly revealing the older day.
Calendar E2E finding: the final phone long-press test targets 08:30 on yesterday, which the same E2E now fills with
Wrote the calendar test(08:30–10:15). The grid correctly starts no creation ghost over that Journal block. I am moving the touch proof to the empty 11:30 slot, before the 13:00 entry.Calendar E2E finding: the phone pointer now starts in the empty 11:30 slot, but the live label is
11:30 AM – 11:45 AMbecause this phone BrowserContext omitted a locale and uses Playwright’s en-US default. The other phone touch context pins en-GB. I am setting the same locale on the full-suite phone context so the existing 24-hour label expectation matches the test setup.Calendar E2E finding: after the app reload and one earlier-days page, the Sept 28 section appears, but its
Show Monday itemsbutton detaches during Playwright click because the Agenda IntersectionObserver hydrates that day as it enters the viewport. I am scrolling the section into view and waiting for its visible Journal row, matching the virtualization behavior.Calendar E2E finding: the deep link opens the correct attached Journal entry at
/d/<date>#^<id>, as shown in the production screenshot. The preview exposesaria-label="Journal"in ItemPreview.svelte, while runLogAttachmentProof still waits for a dialog namedLog entry. I am updating this stale accessible-name locator toJournal.Round 6 report — stopped after the owner’s ~4-hour limit.
Head:
c4a61e8cf0. I merged the one neworigin/devcommit (687ff7031, Mail sync) once; the merge was clean. No push or deploy.Built and committed:
origin/dev(7.85s on dev; branch runs: 17.34s, 17.79s, 10.53s, 14.56s, 24.98s).+Npill, avoiding unreadable sliver blocks.Files changed by this branch:
crates/calternal-server/src/wire.rs;apps/web/src/routes/calendar/[view]/[date]/+page.svelte;apps/web/e2e/calendar.mjs;packages/ui/src/components/calendar/GridColumn.svelte;packages/ui/src/components/calendar/TimeGrid.svelte. The merged origin commit also changescrates/plugins/mail/src/cache/store.rsandcrates/plugins/mail/src/sync.rs.Gate output captured before the stop:
cargo fmt --check(before the origin/dev merge): exit 0, no stdout.bun run check:bun run test:git diff --check: exit 0, no stdout.cargo clean:apps/web/buildwas removed.Known gaps: the full Calendar E2E did not reach
calendar e2e: all flows passed; it reached the Journal attachment preview flow and then exited. The exact failure text was not retained when the long-running tool output was compacted. The current capture isapps/web/artifacts/calendar-427/failure.pngand is not committed or attached. The final phone/tablet/desktop light/dark screenshot matrix is incomplete. The two-User plus admin isolation matrix, adversarial suite, combined glass audit, and post-merge Rustclippy/testgates were not run.cargo fmt --checkalso predates the origin/dev merge. I stopped further work at the owner’s ~4-hour limit as instructed.Decisions not covered by DESIGN: the
+Npill takes width from content lanes; when no lane meets the minimum readable width, the grid shows the pill without block slivers. The Agenda E2E reloads after external fixture writes and scrolls the target section into view so the app’s cache and virtualized list settle. The phone fixture usesen-GBand an empty 11:30 slot to avoid the existing 08:30–10:15 entry.Starting merge round 7a on
job/merge-round-7a, based atorigin/devSHAc4a61e8cf090170f35b1bed3350d9de20c83ecd5. I have read CLAUDE.md, docs/DESIGN.md and CONTEXT.md. I will merge the requested branches in order, run each group’s crate gates, and commit one checkpoint per group. No push, deploy or merge into dev.Group 1 finding and resolution: the Notes plugin branches both used migration 0024. I kept dev's
0024_journal_day_snapshots, renamed DAV resource projections to 0025, and renamed the authoritative Reminder wire epoch to 0026. The Notes Bridge Daily note identity migration adds only a missingcalternal-id:with_daily_note_identityverifies the parsed frontmatter mapping differs only by that key and returns an existing valid UUID unchanged. Itsdaily_identity_migration_is_lossless_and_idempotenttest uses a moved Daily note with CRLF, a YAML comment and custom Tag metadata; stripping the new ID restores the original bytes, and the second pass is identical.Group 1 gate finding:
cargo test -p calternal-plugin-notesreported the known #653 testtests::daily_and_composer_preserve_unrelated_bytesas 404 instead of 200. Per the job instructions, I reran it alone;cargo test -p calternal-plugin-notes tests::daily_and_composer_preserve_unrelated_bytes -- --exactpassed (1 passed; 0 failed). The other 181 Notes plugin tests passed in the full run. I kept its assertion unchanged.Group 1 checkpoint:
967ef3f89.Merged dupwrite-634, reminders-643, notesbridge-644, and davscale-573 in order. The Journal, DAV and reminder Notes migrations are 0024, 0025 and 0026. Notes Daily ID migration was checked: it adds only the missing ID frontmatter, leaves unrelated bytes intact, and is idempotent on a real-shaped Daily note. Added a migration regression for a fresh database and a copied version-24 database; both apply versions 25 and 26 and the DAV projection table is present.
The stale
path:Daily Note selector now returns 409 before UUID lookup so collab does not return 404 after UUID migration. Its regression test passed.Gates:
cargo fmt --check: exit 0, no output.cargo clippy -p calternal-collab --all-targets -- -D warnings:Finisheddevprofile [unoptimized + debuginfo] target(s) in 2m 11s.cargo test -p calternal-collab:test result: ok. 30 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out(all integration test binaries also passed).cargo clippy -p calternal-server --all-targets -- -D warnings:Finisheddevprofile [unoptimized + debuginfo] target(s) in 57.83s.cargo test -p calternal-server:test result: ok. 107 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 14.43s.cargo clippy -p calternal-dav --all-targets -- -D warnings: passed;cargo test -p calternal-dav: 46 unit and 37 replay tests passed.cargo clippy -p calternal-imap --all-targets -- -D warnings: passed; all IMAP tests passed (58 total).cargo clippy -p calternal-plugin-notes --all-targets -- -D warnings:Finisheddevprofile [unoptimized + debuginfo] target(s) in 1m 46s.cargo test -p calternal-plugin-notes:test result: FAILED. 182 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 116.88s; known #653 testdaily_and_composer_preserve_unrelated_bytesfailed with 404 vs 200. Per instruction, reran alone:test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.63s.cargo test -p calternal-plugin-notes notes_migrations_apply_fresh_and_from_a_dev_schema_copy:test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 182 filtered out; finished in 0.41s.No test expectation was changed. The #653 full-suite failure is load-sensitive and was reported here for follow-up.
Group 2 progress: merged
job/files-631,job/fix-493,job/fix-510, andjob/docs-thumb-547in order. Files migrations are now 0016–0020;0020_coalesce_folder_reconcile.sqlfollows the already-used 0019 migration. The upgrade test’s max-version expectation is now 20 because this job explicitly adds #493’s migration.The #547 merge exposed two cache-integrity issues during integration: the FS API argument order differed from #510’s call sites, and an existing empty legacy
.failedmarker prevented the new writer from creating a versioned marker. Unified cache reads/publishes on(hash, size, ThumbnailKind)and made stale marker upgrades atomic. Addedstale_unversioned_failure_marker_allows_decoder_retry;cargo test -p calternal-fspassed (54 unit tests, 42 storage tests, doc tests 0). Files clippy passed; the full Files suite had 152 pass, 1 ignored, and only the old expected migration value 19 failed; the targeted upgrade test passed after changing it to 20.Checkpoint SHA so far:
66399e3d4(docs-thumb merge; not the Group 2 checkpoint).Group 2 progress: merged
job/perf-496at46d67a770. The conflict resolution keeps both per-user Search isolation and the bounded SQLite reconciliation design. Bounded scan pages now skip paired Sidecars while preserving orphan behavior, and staging rebuilds use a separate manifest without updating private readers. Search validation passed:cargo clippy -p calternal-search --all-targets -- -D warningssucceeded;cargo test -p calternal-searchpassed 73 tests with 3 ignored. The only integration cleanup was removing unused no-budget constructors after SearchIndex writers became explicitly memory-bounded.Group 2 progress: merged
job/restart-505at0a3d5cc67. Search startup now keeps #496's configured writer budget while acquiring the #505 cross-process startup gate, retrying only TantivyLockBusy, and removing a stale lock only after the OS lock is free. Server shutdown drains queued changes and waits for the actor to drop the writer. The same-Home two-server regression passed. Search gates passed:cargo clippy -p calternal-search --all-targets -- -D warningssucceeded;cargo test -p calternal-searchpassed 75 tests with 3 ignored. The server test build also exposed a #547 Calendar MIME type mismatch inThumbnailKind::for_indexed_file; corrected the call to passSome(mime), and the restart test then passed (1 passed, 110 filtered out).Group 2 complete. Checkpoint:
ea09d8c8b(checkpoint: 7a group 2). The ordered merges include Files/Search/thumb work, bounded Search reconciliation, restart-safe writer ownership, the #513 reconcile barrier, and #520's chaos probe. Rust gates passed for all changed Group 2 crates:calternal-db(27 passed, 1 ignored),calternal-embed(36 passed, 4 ignored),calternal-fs(59 unit + 42 storage passed),calternal-plugin-files(155 passed, 1 ignored),calternal-plugin-calendar(87 passed),calternal-plugin-video(11 passed),calternal-search(75 passed, 3 ignored),calternal-server(108 passed, 3 ignored), andcalternal-tags(12 passed). Every listed crate's clippy gate also passed.cargo fmt --all -- --checkpassed. One compile defect found during integration in Calendar's thumbnail kind call was corrected and covered by the Calendar gates.Notes crate gate finding (known #653 load-sensitive test): full
cargo test -p calternal-plugin-noteshad 182 passed and one failure intests::daily_and_composer_preserve_unrelated_bytes(assertion observed 404, expected 200); 183 tests total. The required isolated rerun passed:1 passed; 0 failed; 0 ignored; 0 measured; 182 filtered out. The initial short filter selected zero tests, then I reran the fully qualified test name. No expectation was changed.Files e2e finding: the real production UI renders a filename fixture (
spaced out name .txt) with computedwhite-space: nowrapin its one-line FileName mode. The existing assertion inapps/web/e2e/files.mjsrequirespre, and the run failed at that assertion after the desktop keyboard, pin, and breadcrumb flows passed. This collapses visible repeated spaces. I am keeping the assertion and changing the one-line FileName rule to preserve whitespace.Second Files e2e finding: after a successful Ctrl+V copy into
Archive, the Files row is visible and/api/v1/files/stat?path=Archive%2Fcopy-action.txtreturns HTTP 200, but the active element is<body>. Pressing LinuxAlt+ArrowUpthen leaves the route at/files?path=Archive; the listbox owns that shortcut. In the isolated real-server reproduction, the listbox was focused immediately before Ctrl+V and focus was lost by the time paste completed. The earlierAlt+ArrowUpfrom Inbox to Home passed. I am fixing the paste refresh so it keeps the list mounted and keyboard focus usable.Finding from the production Files e2e rerun: the suite reaches
checkListingGetCoalescingand passes the keyboard transfer checks, then waits forgamma.mdin Recent after the main flow renamedInbox/gamma.mdtoInbox/delta.md.Evidence: real-server API reproduction returned
before=["Inbox/gamma.md"], rename status204, renamed stat status200, and thenafter=["Inbox/delta.md"]from/api/v1/files/recent?limit=200. I left the existing e2e assertion unchanged because it conflicts with the live indexed path. The broader run therefore stops before its Trash restore and tus upload checks; I am running those checks separately against the production build.#427 merge-round 7a report
Branch:
job/merge-round-7aHead:
8c42d902ce619780ccb23084b8167c8cfa1f4370Checkpoints: Group 1
967ef3f89; Group 2ea09d8c8b; Group 38c42d902c.Merged the authorized Groups 1–3 in the requested order, including the #634 duplicate-write and collab fixes; reminder, Notes bridge and DAV changes; Files/Search/thumbnails; WebDAV, WebCal, app-password cache review, integrations plus review fixtures, MCP events, agent docs, and Appearance migration. The deliberately excluded branches were not merged. Migration numbers were checked against
origin/devbefore final gates: DAV 0025, reminders 0026, Files 0019–0020, Search 0004, core integrations 0007–0012, Calendar 0005; Mail 0009 remains the version already on dev. The #407 review now compares its #626 SQL fixture to shipped Mail 0009 and applies the real migration set, avoiding a duplicate registration.Two follow-up fixes are included:
packages/ui/src/components/files/FileName.svelteuseswhite-space: prefor one-line filenames. The existing real filename fixture showed thatnowrapcollapsed repeated spaces.apps/web/src/lib/files/FilesBrowser.svelterefreshes clipboard writes without a loading-state remount and restores focus after an empty-folder paste mounts a new collection. A real-server reproduction confirmed that the nextAlt+ArrowUpthen navigates to the parent.Gate output / results
Per-crate
cargo clippy -p <crate> --all-targets -- -D warningsandcargo test -p <crate>passed for every changed Rust crate:calternal-server,calternal-api,calternal-auth,calternal-collab,calternal-dav,calternal-db,calternal-embed,calternal-fs,calternal-imap,calternal-plugin,calternal-plugin-calendar,calternal-plugin-files,calternal-plugin-mail,calternal-plugin-money,calternal-plugin-notes,calternal-plugin-notifications,calternal-plugin-video,calternal-search, andcalternal-tags. The Notes full run had the known load-sensitivedaily_and_composer_preserve_unrelated_bytesfailure (404 expected 200); the requested isolated rerun passed:1 passed; 0 failed; 0 ignored; 0 measured; 182 filtered out. No test expectation was changed.Additional production evidence:
Files screenshots are in the ignored local directory
artifacts/files-round7(208 images covering Files, Shared, Recent and Trash at phone, tablet and desktop widths in light and dark). Thefj issue commentinterface has no attachment option, so they are not attached to this issue.Known gaps at the 5-hour limit: Connected Accounts, Mail, and MCP Events end-to-end probes remain unrun. I did not run the two-User/admin matrix, the one robustness suite, or the merged bench profiles. The full
apps/web/e2e/files.mjsrun passed keyboard transfer and the coalescing check, then stopped at its Recent assertion: it renamedInbox/gamma.mdtoInbox/delta.mdearlier but later still waits forgamma.md. A real-server API check returnedbefore=["Inbox/gamma.md"], rename204, stat200, andafter=["Inbox/delta.md"]. I kept that existing assertion unchanged. The isolated production restore and 5 MiB tus checks passed. I also did not separately apply the migration set to a copied dev-schema database; the per-crate migration tests passed.Decisions not settled by DESIGN: preserve all spaces in one-line filenames to match the full stored/displayed name; restore keyboard focus to the mounted Files collection after paste into an empty folder; use the already-shipped Mail 0009 migration in review tests rather than registering another version. No further product behavior or test expectation was changed.
Round 2 starting on job/merge-round-7a at
8c42d902ce; branch base is origin/devc4a61e8cf0. I am running the requested upgrade, adversarial and e2e checks, then will fix the stale Files Recent assertion and report gate output. No push, deploy or merge.Finding: the Files flow renames gamma.md to delta.md, then opens Recent where only delta.md is the live renamed item. The old assertion typed 'g' and expected gamma.md to receive focus; it could not match the row the User sees after the rename. I changed this check to type 'd' and assert focus on delta.md. This keeps the existing interaction check and corrects its fixture expectation.
Resuming round 2 after the build-host resize. Branch:
job/merge-round-7a; base/production head:origin/devc4a61e8cf090170f35b1bed3350d9de20c83ecd5; current head:8c42d902ce619780ccb23084b8167c8cfa1f4370. The existing uncommitted change updates the Files Recent e2e to followdelta.mdafter rename. I am reviewing the saved gate notes and continuing the required upgrade, matrix, robustness and e2e checks without merging new branches.Finding from the Files e2e after the stale Recent name was corrected: the production Recent view contains
delta.md, but typing onlyddoes not focus it. Recent applies type-to-select from the first matching name, and the fixture also contains otherd…files. The assertion therefore did not identify the renamed row. I will type the unique prefixdeltaand keep the keyboard-focus assertion on the row the User sees.Round 2 finding, 2026-10-02:
apps/web/e2e/files.mjsreached the keyboard paste flow. The copy API returned 200 forArchive/copy-action.txtand the row became visible. The followingAlt+ArrowUpdid not restore the Inbox row within 30 seconds. The same step passed in the earlier run, so I am doing one focused reproduction to distinguish a repeatable focus/navigation issue from load sensitivity. The corrected Recent assertion also passed before this later failure.Round 2 build finding: the origin/dev and head binaries use the job's configured Cargo target. After saving the
c4a61e8cfbinary, the first head--features mail-test-providerbuild reused the oldcalternal-imapartifact and failed incrates/plugins/notes/src/imap.rswithcannot find function apple_markdown in module calternal_imap::projection(the head API). I preserved the baseline binary, rancargo cleanon this job target, and started a clean head rebuild. This is a cross-revision build artifact issue; I made no Rust source change.Round 2 real-data finding: the Dovecot fixture has 2,000 provider UIDs, including two UIDs with one RFC Message-ID. The old server stores 1,999
mail_messagesrows and 2,000mail_membershipsrows; both duplicate UIDs are memberships of the same cached message, matching the #626 per-UID model. I corrected the one-off probe to expect 1,999 content rows and 2,000 UID memberships, and it will compare both counts/checksums across the upgrade.Started rev-mcp-api review.
job/rev-mcp-apic4a61e8cf090170f35b1bed3350d9de20c83ecd5(origin/dev)job/agentdocs-630.review-findings.md. Each confirmed new finding gets a separate issue after a duplicate search.Independent data-integrity review started for round 7b.
Branch:
job/rev-7b-dataBase SHA:
c4a61e8cf090170f35b1bed3350d9de20c83ecd5I will review the 25 named branch heads, with priority on Undo receipts, live-room write ordering, read-your-writes, Calendar mutations, voice memo files and Tasks. I will record evidence in
review-findings.mdand check for duplicate issues before I file each confirmed finding. This job makes no product changes.Decisions: use local job branch heads where present and record the full SHA for each; use origin heads only when a local branch is absent.
Starting the rev-consistency static review on
job/rev-consistency. Base:c4a61e8cf090170f35b1bed3350d9de20c83ecd5(origin/dev). I read CLAUDE.md, CONTEXT.md and DESIGN.md. Scope follows the job prompt: shared primitives/helpers, token overrides, glass/focus styles and plain-language UI copy. Findings will be recorded inreview-findings.mdand grouped into deduplicated issues. No product edits or full builds. The existing body of #427 describes attachment bugs; this job uses #427 as its explicitly assigned review tracker.rev-a11y accessibility audit started.
Branch:
job/rev-a11y. Base:c4a61e8cf090170f35b1bed3350d9de20c83ecd5(origin/dev).Scope: whole web app source audit against WCAG 2.2 AA and DESIGN §§34, 35, 57. No product edits, build, push or deployment. The job assigns #427, although that issue currently describes Log attachment behavior; this audit follows the job prompt and reports here. Findings will go in review-findings.md and separate component-family issues after duplicate searches.
Started the source-only design-gap review requested by the rev-design-gaps job.
job/rev-design-gapsorigin/devatc4a61e8cf090170f35b1bed3350d9de20c83ecd5review-findings.md. Search for duplicates before each new issue. No product edits, full builds, pushes or deployments.Started the round 7b defensive security review on
job/rev-7b-security. Base SHA:c4a61e8cf090170f35b1bed3350d9de20c83ecd5. The review covers the 25 queued branches in the job brief. I will commitreview-findings.md, search for duplicate issues before filing each finding, and leave product files unchanged. The current date is 2026-10-02.Confirmed P1 privacy leak in
job/maillayouts: sender image permission is revoked on the server, but only the selected message cache entry is invalidated. A second warmed message retains permission and can load sender images. Merge blocker filed as #736. The local inert check used the actual branch cache and confirmed stale permission; no network request was sent. Evidence and regression test idea are in that issue andreview-findings.md.Review checkpoint at
eea364d9b(basec4a61e8cf). Product code is unchanged.Confirmed source findings:
wire.rs:2375, but the missing-Note branch writes Home content incrates/plugins/notes/src/lib.rs:3871. The agent-doc read example reaches that route.composer_api.rs:219,tasks_api.rs:91), butscripts/action_registry.py:146andwire.rs:2375require mutation access. Generated CLI/WebMCP ask for change confirmation.mail/src/routes.rs:45).Duplicate checks found existing owners: #667 for missing client-operation idempotency receipts; #688 for unbounded Money transaction lists. These will be recorded without new duplicate issues.
The checked-in TypeScript client matches an offline regeneration with the pinned
openapi-typescript 7.13.0. No claim of source-to-OpenAPI regeneration: the server was not built.Checks so far:
Round 7b review findings:
task_views.rs:180,194,202atf620390c724ee08540d38b0ba69c3d12225fc1e4. The route replaces a complete client view with no client revision. The file CAS checks the server's current read. Static proof.+page.svelte:851,journal.ts:30,58,67,edits.ts:353at5f7fdb96706aca0c457a6b7851f548f7f618ac85. The old inverse uses an ETag refreshed by a later read. This is inherited in the reviewed head.The two Calendar checks import the reviewed adapter and stub only transport. They do not use a live server or change User files. Full output is in
review-findings.md.No product changes. Review continues with Note caches, voice memo projections, editor decorations and migration interactions.
Confirmed static findings at review base
c4a61e8cf090170f35b1bed3350d9de20c83ecd5, branchjob/rev-consistency:MailView.svelte:148,650,files/model.ts:329-342,AdminSection.svelte:61-70.DraftStack.svelte:60-62,AttachmentDeck.svelte:107,303-304,flip.ts:374-380. Node probe returns[]for the literalflyhelper; the CSS control is detected.files/transfer.ts:199-218owning the action.Duplicate evidence was added to #658 (focus token contracts/local rings), #73 (menu copy feedback) and #308 (local hidden-label recipes). Further material/token/copy findings will go to their existing owners. Product source is unchanged. The first findings are committed in
b18d62f24; the remaining notes are being recorded now.The real-data upgrade probe exposed a local verification limit: on the old binary, uploads of the repository's valid 2×2 PNG and a Markdown file both produced
.failedthumbnail markers containingdecoder-failed-v1; theirfiles.thumbnailjobs completed withoutlast_error, and the Files API reportedhas_thumbnail: false. The staged media runtime haslocal-nproc-limit=3486, while the shared account had over 4,800 threads during the run. I am recording the Files identities and continuing the migration/data-integrity checks; thumbnail rendering remains unverified under this host load. No product behavior change is inferred from this evidence.Accessibility source audit progress on branch
job/rev-a11y; first report commit4d9126541123987e5d0fc40a2a2ac3dc0885a2b3, initial basec4a61e8cf090170f35b1bed3350d9de20c83ecd5.New component-family issues after duplicate searches:
A small browser probe bundles the actual
focusTrap.tsaction, with no product build or product change. It reproduces both #740 failures: hidden explicit initial focus leaves focus outside, and a hidden final candidate lets Tab escape. This is behavior evidence, not visual review. Full production screenshots and assistive-technology runs are not part of this read-mostly job.The existing #658 owns focus-ring styling. The report will add duplicate evidence there instead of filing another ring-style issue. Review continues through Composer, Photos and the remaining route families.
Confirmed a second static merge blocker: #816, new media parser in
job/voicefiles-620has no nesting bound.iso_box_tracksrecurses atcrates/calternal-media/src/lib.rs:367; Files and Search call it during indexing of User-controlled files. Input byte and per-call loop limits do not bound stack use. No crash payload was executed. The issue records repair and regression coverage. Review continues with the remaining cross-plugin changes.Finished the rev-consistency static review.
job/rev-consistency.origin/dev:c4a61e8cf090170f35b1bed3350d9de20c83ecd5.a5252c5c63e5824709a75c90e3b553ed7f5ae59c.review-findings.md, with 11 grouped findings, source evidence, shared owners, expected results and test ideas. This is a review artifact; no product code changed.review-findings.mdonly, 337 lines. Four atomic documentation commits. No push, deploy or new merge commit.Final verification
git fetch origin && git merge origin/devcompleted once before final checks.The fetched revision is still
c4a61e8cf090170f35b1bed3350d9de20c83ecd5.Merge output, verbatim:
git diff --checkandgit diff --check origin/dev...HEADexited 0 with nooutput. The branch changes only this report. No product source, dependency,
test expectation, migration or build artifact was committed.
node apps/web/scripts/check-type-tokens.mjsexited 0. Output, verbatim:node apps/web/scripts/check-motion-tokens.mjsexited 0. Output, verbatim:The helper-call probe in F2 shows a coverage gap despite this passing guard.
node apps/web/scripts/check-user-storage.mjsexited 1 before scanning source.This worktree does not have its TypeScript dependency installed. Output,
verbatim:
The job asks for a read-mostly review without full builds. No Rust crate or web
product file changed, so Cargo format/clippy/test and web check/test were not
run. No route or background job changed, so no performance profile or live
adversarial run was required. No dependency version was selected or changed.
Known gaps
behaviour or performance. Each issue gives a test idea for its fix.
linked implementation issues.
UX gaps closed
None. This job records and routes evidence; it does not change the UI.
UX gaps left
The reported focus, material, scaling, copy-feedback and plain-language gaps
remain. Runtime checks for keyboard, touch, screen readers, Undo and live
updates belong to the implementation jobs. Their screenshot sets must cover
390, 820 and 1440 px, light/dark, with macOS emulation.
Cleanup
Ran
cargo cleanwithCARGO_PROFILE_DEV_DEBUG=line-tables-only,CARGO_INCREMENTAL=0,CARGO_BUILD_JOBS=4and worktreeTMPDIR. Kept the preset job target directory. Output, verbatim:Decisions
Followed the job prompt's review scope despite #427's attachment-report body. Used static checks, as this job explicitly avoids full builds. Added overlapping evidence to existing issues. Filed the script guard gap as a follow-up to closed #477. Applied the newer 2026-10-02 silent-privacy instruction to the opt-in conflict in #726. No product design decision or implementation was made.
The worktree is clean. This review does not close #427 or any finding issue.
Source review findings for #427, base
c4a61e8cf090170f35b1bed3350d9de20c83ecd5. No product changes.Each new issue has its DESIGN reference, file:line evidence, observed and expected behavior, duplicate check and test idea. The committed
review-findings.mdalso maps 18 observations to existing tickets. Place-reminder UI work remains under #393; Task IDs and saved-search rename/pin are already implemented.Round 7b review update. Two local fixture checks confirmed stale cache faults, both non-blocking because no server write loss was shown:
Evidence and exact test output are in review-findings.md at commit
68f834ba8plus the next atomic review commit. No product files changed. The fixture tests run reviewed store/function code with mocked collaborators; they do not claim a live-server reproduction.Finished rev-mcp-api review.
Branch:
job/rev-mcp-apiBase:
c4a61e8cf090170f35b1bed3350d9de20c83ecd5(origin/dev)Head:
4a82c6414156f4362e0571afea542a8d0971b786Changed file:
review-findings.mdonly. Four atomic review commits. Worktree clean.Review delivered: 333 API operation bindings, shared adapter metadata and behavior review, and the separate agent-doc branch review. Eight new issues: #752, #754, #760, #814, #815, #817, #818 and #821. Existing owners retained for two findings: #667 and #688.
High-priority findings: the missing Daily note read branch writes content under read classification (#752); the CLI can replay a non-idempotent create after an ambiguous gateway response (#814). These are source findings, not claims of live reproduction.
Final gate output and decisions follow verbatim in the committed report. No Rust or web product code changed. Clippy, Rust tests, full web checks and full builds were excluded by this read-mostly job. One fetch and merge attempt before final checks returned Already up to date. cargo clean completed; web build output was absent. No push, deployment or integration merge.
MCP, API, CLI and WebMCP review
Issue: #427. Review scope: #484 and DESIGN §§14, 18, 33, 34, 41 and 48.
Review base:
c4a61e8cf090170f35b1bed3350d9de20c83ecd5(origin/dev).Branch:
job/rev-mcp-api.Agent docs source:
origin/job/agentdocs-630at183ac356359f1f84afad30932f02e07323ddb7ed.Review result: eight new issues and two confirmed findings assigned to existing
issues. High-priority findings concern read-only content writes (#752) and
unsafe CLI replay (#814). The other issues concern parser access (#754), large
downloads (#760), required headers (#815), legacy contracts (#817), input
errors (#818) and help (#821). No product code changed.
This is a source review. It changes no product code. It does not prove live
transport or authorization behavior. Findings below separate source evidence
from results observed on a running server.
Initial checks
The registry has 333 HTTP operations across 270 paths. It has 315 generated
tools. The route scope counts are 250 data, 44 account and 39 admin.
The parity inventory has no missing generated adapter. This result does not
prove that the adapters can complete each operation.
Commands and output:
Confirmed source findings
The review covers route and schema parity, tool names and input groups,
pagination, response bounds, retry safety, actionable errors and agent docs.
Each confirmed finding includes file and line evidence, the expected
behavior, a regression test idea and its issue or existing duplicate.
Decisions
the job prompt assigns it. Follow the explicit API review scope.
read-mostly review, as required by the job brief.
F01 — Daily note reads must preserve read-only App Password access
Priority: High. Issue: #752.
crates/calternal-server/src/wire.rs:2320derives App Password access fromis_read_request;:2375treats GET as read.crates/plugins/notes/src/lib.rs:3867enters the missing Daily note branch and:3871writes a new Note, indexes it and updates adjacent Daily note navigation.scripts/action_registry.py:146marks the GET action read-only.crates/calternal-server/src/mcp.rs:797describescalternal_todayas a read.origin/job/agentdocs-630at183ac356359f1f84afad30932f02e07323ddb7ed,crates/calternal-server/src/agent_docs/skill_intro.md:29recommends a read-only MCP App Password and:59usescalternal_todayas the first read.Source review shows that a route classified as a read contains a content-creation branch. Its authorization and its tool hints do not describe that branch. No live authorization test was run.
Expected: Keep read-only requests free of content writes. Missing Daily notes need a read result or an explicit write action that checks write access on the server. Preserve the ordinary Daily note flow for a User who can write. Update the tool hints and agent examples from the same action intent.
Test idea: Add a route-level regression for a missing Daily note under a read-only principal. Assert unchanged Home content and adjacent Daily notes. Check the API, MCP and generated adapters against the same contract. Keep existing status expectations.
Duplicate check: Searched all issue states for
daily,read-only, andMCP; read #661. #661 concerns a viewing-triggered rewrite of an existing Note in the editor, not the missing-Daily-note creation branch.F02 — Pure Composer and Task parser tools incorrectly require write access
Priority: Medium. Issue: #754.
crates/plugins/notes/src/composer_api.rs:1documents a pure preview function with no reads or writes;:219returnsproject(...).crates/plugins/notes/src/tasks_api.rs:91parses Task text and returns a preview without a content write.scripts/action_registry.py:146classifies every POST except ZIP download as a mutation. Bothnotes_composer_parseandparsehaveread_only: falseanddestructive: trueincontracts/actions.json.crates/calternal-server/src/wire.rs:2375has only the ZIP read exception.crates/calternal-cli/src/remote_commands.rs:294requires--confirm;apps/web/src/lib/webmcp/generated.ts:88confirms every action not marked read-only.A read-only API or MCP App Password cannot use the parsers. CLI and WebMCP request change confirmation for pure previews. The inventory gate still passes.
Expected: Declare read intent for the pure parser actions once and use it in route access and adapter hints. Keep authentication, body validation and CPU bounds. CLI and WebMCP must allow the preview without change confirmation.
Test idea: Add metadata assertions and read-only route tests for both parser actions. Add adapter tests that the pure previews do not ask for confirmation and do not write Home content.
Duplicate check: Searched all issue states for
notes_composer_parse,parser,read-onlyandparity. No specific parser-access issue found.F03 — Generated download tools cannot read valid attachments, Versions or ZIPs above 1 MiB
Priority: Medium. Issue: #760.
crates/calternal-server/src/mcp.rs:311,crates/calternal-cli/src/remote_commands.rs:343andpackages/api-client/src/index.ts:456stop generated responses above 1 MiB.contracts/actions.jsondeclares no Range or continuation input formail_download_attachment,download_versionordownload_zip;scripts/action_registry.py:49supplies Range only to other download actions.crates/plugins/mail/src/routes.rs:45permits attachments up to 25 MiB;:1439reads a whole attachment and accepts no Range header.crates/plugins/files/src/lib.rs:3620streams a complete Version without a Range input.crates/plugins/files/src/archive.rs:1streams a complete ZIP.These HTTP operations and the UI accept valid results larger than the adapter cap. The generated CLI, MCP and WebMCP tools fail on those results. The error recommends a smaller page or range that these operations do not accept. CLI Mail export is a separate path; it does not make the MCP or WebMCP tools complete.
Expected: Keep bounded tool outputs and provide a declared continuation or range path for these downloads, or an explicit supported transfer result. Map it to the existing server operation. Do not raise the cap without a memory bound.
Test idea: Use a synthetic 2 MiB attachment, saved Version and ZIP. Verify complete transfer with bounded chunks through each generated adapter. Assert that small transfers still retain their current output shape.
Duplicate check: Searched all issue states for
mail_download_attachment,attachment,pagination, and1 MiB. #484 and #472 mention the operation inventory; no specific large-download parity issue found.F04 — CLI retries non-idempotent writes after ambiguous gateway responses
Priority: High. Issue: #814.
crates/calternal-sync/src/remote.rs:39checks safe methods only for transport errors;:45retries 429, 502, 503 and 504 for every clonable request.crates/calternal-cli/src/remote_commands.rs:311uses that policy for every generated action;:390also applies it to ergonomic commands.crates/calternal-cli/src/main.rs:47defaults to three retries.crates/plugins/notes/src/lib.rs:3410creates a fresh Note identity on each request;:4349allocates fresh Log block IDs for each batch. The contracts for these actions have no request-operation identity.A gateway response can arrive after an upstream write committed. The CLI can then replay the same create and create a second item. Source evidence confirms the unconditional replay path; no live duplicate was produced in this review.
Expected: Do not automatically replay non-idempotent writes after an ambiguous result. Use a server-recognized operation identity and receipt when #667 supplies them. Until then, retain bounded retries for safe reads and provide an actionable unknown-write-result error for ambiguous writes.
Test idea: Use a test-only fault proxy that forwards one ordinary create, records its successful response, and returns a transient gateway status to the CLI. Assert one created item. Keep safe-read retry coverage and existing status expectations.
Duplicate check: Searched all issue states for
send_with_retry,retryandidempotency; read closed #350 and #460, and open #667. #667 owns the server receipt contract. This issue owns the concrete current CLI replay policy and depends on #667 for receipt-based retries.F05 — OpenAPI omits required revision and upload headers that generated tools require
Priority: Medium. Issue: #815.
crates/plugins/notes/src/reminders_api.rs:165and:251declare only path inputs, but:185and:267callmatch_etagwith the request headers.crates/plugins/files/src/public.rs:1446omits the If-Match parameter from the public-edit contract, while:1467requires it.scripts/action_registry.py:41adds required If-Match for these three operations. Its tus supplements at:29also add required upload protocol headers that OpenAPI omits.contracts/openapi.jsonlacks those header parameters.packages/api-client/src/generated.tsis byte-identical to a regeneration, so it faithfully repeats the omissions.contracts/actions.jsondeclares the extra required headers.An HTTP client or agent using the published OpenAPI schema can send a schema-valid request that the server rejects for a missing required header. The CLI, MCP and WebMCP schemas have a different required-input contract. Fresh generated files do not prevent this semantic drift.
Expected: Declare existing required protocol and revision headers in the owning route annotations. Generate OpenAPI, actions and the client from that declaration. Remove each corresponding supplement once the primary contract contains it. Preserve revision conflict checks.
Test idea: Assert that these operations expose required If-Match in both OpenAPI and the action schema. Check each tus operation for its required headers. Send requests formed from the documented schemas to the same route and keep stale-revision tests.
Duplicate check: Searched all issue states for
notes_create_block_reminderandaction-overrides; read #484. Its general registry scope and documented supplements do not provide a specific issue for these missing primary-contract requirements.F06 — Legacy MCP and WebMCP tools have incompatible contracts and lose pagination
Priority: Medium. Issue: #817.
crates/calternal-server/src/mcp.rs:363acceptsqforcalternal_search;apps/web/src/lib/webmcp/tools.ts:151acceptsqueryfor the same name.crates/calternal-server/src/mcp.rs:428accepts a Noteidforcalternal_open;apps/web/src/lib/webmcp/tools.ts:156instead acceptshrefand navigates the page.crates/calternal-server/src/mcp.rs:436accepts Homepathand visibility flags forcalternal_list_files;apps/web/src/lib/webmcp/tools.ts:166acceptsfolderId.apps/web/src/lib/webmcp/tools.ts:412returns only the first 100 File rows and drops next_cursor, total and raw item IDs. The legacy MCP Files input has no cursor or limit. Mail reader inputs atmcp.rs:404also omit the page cursor supported by the API.mcp.rs:797reads the Daily note forcalternal_today;tools.ts:402returns Journal, Events and Tasks from several routes. Generated registry tools already have common contracts but the legacy names remain registered.An agent cannot reuse a legacy call across surfaces. Legacy file and Mail list tools cannot reach later pages. The WebMCP File result also prevents an agent from obtaining the folderId needed by its own list tool without parsing a link or changing tools.
Expected: Keep compatibility through explicit wrappers, but choose one documented shared contract for each common data tool. Give page tools cursor and limit inputs and preserve stable IDs and continuation output. Give browser navigation a distinct name from reading content. Direct legacy descriptions to the common generated action when a compatibility shape must stay.
Test idea: Compare schemas and results for tools sharing a name. Use a folder and Mail thread with more than one page. Traverse every page once, preserve IDs, and verify the documented compatibility path.
Duplicate check: Searched all issue states for
calternal_list_files,parity,paginationandMCP; no specific legacy-contract drift issue found.F07 — Generated tool input errors do not identify the field to fix
Priority: Low. Issue: #818.
crates/calternal-api/src/actions.rs:234reports only Unexpected tool input field;:243reports only Missing required tool input field;:267reports only Invalid tool parameter type.apps/web/src/lib/webmcp/generated.ts:20and:21return the same unnamed-field errors;:39omits the field and expected type.An agent must guess which value to repair or reread the whole schema after a normal argument error. All generated adapters repeat this limitation.
Expected: Report the action ID, field path and expected shape, such as headers.If-Match is required. Report unknown field names without echoing supplied values. Keep credential and Home content values out of error text.
Test idea: Check missing nested headers, unknown fields and wrong primitive types through Rust and browser validators. Assert precise field paths and expected types. Include a sensitive test value and assert that the value is absent from the error.
Duplicate check: Searched all issue states for the quoted exact phrase
Missing required tool input field; no issue found.F08 — Generated tool names and help omit the object and outcome for basic actions
Priority: Low. Issue: #821.
scripts/action_registry.py:153builds names from raw operation IDs, and:154falls back to an operation ID with spaces when there is no summary.contracts/actions.jsonhas 23 eligible actions with one-word help. Examples: calternal_api_update for public-link settings, calternal_api_properties for Task edits, and calternal_api_head and calternal_api_terminate for tus uploads.crates/calternal-server/src/mcp.rs:338builds discovery from those fields.apps/web/src/lib/webmcp/generated.ts:82uses the same help for title and description.contracts/action-overrides.json:5already shows the reuse path: create is named calternal_api_create_note with Create a Note help. The other ambiguous entries have no corresponding override.Discovery gives an agent no object type or outcome for basic operations. Generic fields such as id or path cannot supply all of the missing context. The tools also mix bare verbs and plugin-qualified names.
Expected: Use the existing name/help override mechanism or route summaries to state an object and outcome. Prefer consistent plugin-qualified names for new tools; keep documented compatibility aliases for existing names. Include required revision, continuation and important result identities in useful help.
Test idea: Add a metadata review check for the identified ambiguous operations. Assert that help states the object and action and that a name change preserves compatibility. Keep descriptions concise.
Duplicate check: Searched all issue states for
action-overrides,calternal_list_filesandparity; no specific generated-help issue found.Existing issues, kept without duplicates
D01 — Writes have no common idempotency identity or receipt
Existing owner: #667.
The registry has no declared idempotency header. Note create accepts a title,
body, folder and tags, then allocates a new identity
(
crates/plugins/notes/src/lib.rs:3410). The Log batch accepts entries andallocates fresh block IDs (
:4349). There is no common receipt lookup in the333-operation contract. Some operations are already idempotent by their own
identity, such as Calendar “Log this”; this does not establish a common write
contract. #667 explicitly owns client-operation identities, repeated-ID results
and durable receipts. #814 separately records unsafe CLI replay before those
receipts exist.
Test idea: send the same ordinary create intent twice, including concurrent
calls and a lost acknowledgement. It must have one result. A changed payload
under that identity must fail. Use the same route on all adapters.
D02 — Collection results lack page and byte bounds
Existing confirmed owner: #688.
crates/plugins/money/src/routes.rs:897accepts only account and monthfilters.
:916returns every matching transaction. The action schema has nocursor or limit and the response has no continuation. All generated tools
stop at 1 MiB, so a large matching set has no complete adapter result.
#688 has this exact route and the expected bounded-page contract.
The route census also found collection responses without page inputs in
Calendar, Files, Photos, Mail, Notes, Search, Settings and Admin. The existing
list-bound campaigns are #678, #680, #682, #685, #703, #694, #691 and #697.
A collection schema alone does not prove an unbounded implementation: some
arrays have fixed domain limits. Do not file each schema array as a new bug.
Test idea: use a large matching set with variable row sizes. Traverse bounded
pages with stable identities and verify no missing or repeated unchanged row.
Compare the HTTP and generated tool contracts.
Agent docs review
Read
agent_docs.rs,agent_docs/groups.rs,agent_docs/skill_intro.md, theserver build script and DESIGN §58 on the separate agent-doc branch. Its
public routes are
/llms.txt,/skills/calternal/SKILL.md,/.well-known/agent-skills/index.json,/.well-known/mcp-server-cardand/api/openapi.json.and
document.modelContextentry point match the reviewed source.correctly says that live
tools/listis authoritative.MCP_PROTOCOLS. Its Instanceswitch defaults match the Instance policy defaults.
query Instance flags and do not query User flags. Cache headers use
public, max-age=60, must-revalidate; the security middleware preserves anexplicitly set cache header.
is the concrete mismatch between the guide's read intent and route behavior.
the reviewed
origin/devbase. Public-link resolution and cache behaviorwere inspected in source; no public endpoint was called.
Coverage and limits
The census checks all 333 method/path bindings and each action's scopes,
input groups, transfer encoding, help and successful-response media types.
The registry and parity tests check generated freshness and dispatch hooks.
The TypeScript client matches an offline regeneration with the pinned
openapi-typescript 7.13.0. This proves contract-to-client freshness. It doesnot prove that the server emits the same OpenAPI bytes: no server build ran.
Deep source reads cover the common Rust/browser mapping, CLI retry policy,
MCP discovery and dispatch, legacy tools, Note and Log writes, parser previews,
revision guards, tus inputs, binary downloads and Money lists. UI data calls
were compared with the registry inventory. Dynamic menus, editor WebSockets
and provider-backed behavior still need live semantic coverage. Existing
docs/action-registry.mdalso reports incomplete full-smoke coverage.No feature or hot path changed. No performance profile or benchmark run is
required for this review. No UI changed, so screenshots and UX interaction
checks do not apply. No live adversarial or authorization claim is made.
Final verification
Ran
git fetch origin && git merge origin/devonce before final checks.The fetched
origin/devremained atc4a61e8cf090170f35b1bed3350d9de20c83ecd5. Output:git diff --checkandcargo fmt --checkboth exited 0 with no output.Every Cargo command used
CARGO_PROFILE_DEV_DEBUG=line-tables-only,CARGO_INCREMENTAL=0,CARGO_BUILD_JOBS=4and the worktree'starget/tmp.The preset target directory was not changed. No Rust crate or web product
file changed, so clippy, Rust tests, full web check and full web tests were
not run. The review brief excludes full builds.
cmp packages/api-client/src/generated.ts artifacts/rev-mcp-api/generated.tsexited 0. The generator used its existing pinned package without installing
a dependency. Check output:
PYTHONDONTWRITEBYTECODE=1 python3 scripts/action_registry.py --checkexited 0. Output, verbatim:PYTHONDONTWRITEBYTECODE=1 python3 scripts/parity_matrix.py --checkexited 0. Output, verbatim:PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s scripts -p 'test_action_registry.py'exited 0. Output, verbatim:PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s scripts -p 'test_parity_matrix.py'exited 0. Output, verbatim:bun test packages/api-client/src/index.test.tsexited 0. Output, verbatim:Known gaps
product behavior.
round or provider-backed test ran. Source evidence is identified above.
origin/job/agentdocs-630, noton a merged
devbuild.needs the merge-time server build.
coverage. The parity inventory's zero-gap result does not close that work.
no User financial data was read or recorded.
UX gaps closed: none; no UI changed. UX gaps left: the adapter usability
findings are assigned to #754, #760, #817, #818 and #821.
No design choice changed. The decisions above concern the review method and
issue destination only. No push, deployment or integration merge was done;
only the explicitly requested merge of
origin/devwas attempted.Cleanup
cargo cleanexited 0. Output, verbatim:Removed the Python bytecode created by the initial checks. There was no web
build output. Review evidence remains in the ignored
artifacts/rev-mcp-api/directory; it is not committed.Finished the source-only design-gap review on
job/rev-design-gaps.Head:
80083063d21f78a62b73d7fd410b31ce1437d86c. Reviewedorigin/devatc4a61e8cf090170f35b1bed3350d9de20c83ecd5.Built: a committed source audit in
review-findings.md. It records ten new issues and eighteen source observations mapped to fifteen existing tickets. Each new issue includes a DESIGN reference, file:line evidence, observed and expected behavior, a duplicate check and a test idea. No product implementation changed. Three atomic documentation commits preserve progress.New issues:
Files:
review-findings.mdonly. Review scripts, issue bodies and receipts remain in ignoredartifacts/design-review/.Final fetch/merge output (verbatim):
Review check output (verbatim):
git diff --check: exit 0, no output. The final working tree is clean.Cargo and web product gates: not run. This documentation-only brief requests no full builds and minimal Cargo use. No dependency changed, so no version lookup was needed. No benchmark, production screenshot, native-client check or live API probe ran. No web build output was created.
Cleanup output (verbatim):
UX gaps closed: none; this is a review job. UX gaps left: the filed and existing tickets in the report. Rendering, cap-height alignment, accessibility, touch, motion and offline behavior still need production evidence at 390/820/1440 px in both schemes with macOS platform emulation. Source findings do not assert those checks passed.
Decisions: follow the explicit wider review brief despite #427's attachment-bug body; use the latest owner decisions; exclude OPEN and later-only features; map specific duplicates to existing issues and file narrow surface defects beyond shared architecture umbrellas. No new product design was chosen. Stable Task IDs, saved-search rename/pin, Files pins and shared Location consent were traced and excluded as false leads. Place-reminder authoring remains under #393.
No product edits, push or deploy. This review does not fix the Log attachment bug in #427.
BLOCKER #844: retrying a linked Note body failure can duplicate already acknowledged Logs. In the reviewed tasks-mode head, commitLogBatch acknowledges the Log rows before body writes; Send all marks drafts committed only after all those writes complete, so a rejected body call leaves the same drafts available. A retry allocates new Log IDs. This code is inherited and remains in the reviewed heads.
A local test of the actual batch function with mocked prepare and transport observes log-1 acknowledged, the body call rejected, then log-2 written from the same snapshot. No live-server reproduction claimed. File:line evidence, the regression test idea and exact test output are in the issue and review-findings.md. No product files changed.
Round 7b independent defensive review finished.
Branch:
job/rev-7b-securityHead:
e98c0119d3f5e8b3825d7feba9a454cd66721b44Built: a pinned review report with coverage for all 25 queued branches, two duplicate-checked repair issues, and inert local cache checks.
Committed file:
review-findings.mdonly. Five atomic report commits. No product edits, pushes or deploys. The requested origin/dev merge was already up to date.Merge blockers:
The report below contains source locations, impact, repair and regression ideas, per-branch boundary checks, exact validation output, decisions and known gaps. No issue was closed.
Round 7b defensive security review
Tracking issue: #427. Review branch:
job/rev-7b-security.Base:
c4a61e8cf090170f35b1bed3350d9de20c83ecd5(origin/dev, 2026-10-02).This report records a static review. Product files stay unchanged. Branch heads
are pinned below. A finding needs a source location, impact, and a regression
test idea. Authorization holes and data leaks block merge.
Branch coverage
job/agentdocs-630183ac356359f1f84afad30932f02e07323ddb7edjob/submenu-579142c063a87206721042ae52d24140490a80627d3job/tasks-modef620390c724ee08540d38b0ba69c3d12225fc1e4job/toastname-586093db3ec12a26d1d9ed303853ee733fbc5e79ccdjob/tocrail-636144f0316a7ed6eb9f1ed495d21918e3e78656365job/quirks-54650a006765ab635665cc0fc53ccaef10d6210fdf0job/calcard-series5f7fdb96706aca0c457a6b7851f548f7f618ac85job/editor-seriesa087d0aba9f39bbfb5447c2ce22db0de25fd37a0job/reload-4232399db841cf16ade3fbf47fcfab50578a3abe364job/cal-e2e-56996908cbef8bbf078ce73bbc1a51f432ba8c416c8job/selalign-576174b554e1a66f53b0c9d92ede41b47eac145f419job/maillayoutsf9f360e68f4e9ca106ddd7fea24d1f4363881a2bjob/dragghost-612bc08062b167e59ca7ac39426a96481b2664b2e75job/writeonopen-66104c4a651be5a0da6c1311af9ad2d39bd289b8a09job/ryw-6534723c5f3b1ebfaa90905376e4a3d14e2ee60ae63job/perf-cache-665b88bc6ac888fd18e7e8a256f0b5b65ecaeed92c2job/perf-snap-666253c2a00cade24a7f845a5e67f309093641b8850job/perf-mut-66752d2b17f805072cd0304d7a05fe0534523cc7bc3job/fix-499242022301673dc6746d89985ee36078743723591job/calimg-589421dd63735d116cba4961a0a3ca4c985baa83480job/voicefiles-620b7ef7a2ab57f45b5d46cd19b4560215acae918e3job/imaptest-625f811d7aa4bf922ceb3948ddb5b6241944fb5cbd3job/burst-709c421756ac9af5a9b653b7c9f53c41b3aca24de89job/admin-burst-70523a6fe0e0e326f789c886f366880f5b86683b287job/instant-663e62249dedcc2c7d108e4432596d40aee6f5a4bc8Findings
P1 — BLOCKER: revoked sender image permission remains in the reader cache
Issue: #736.
Branch:
job/maillayouts.The server stores image permission per User and sender.
MailView.svelte:917changes that permission but deletes only the selected message cache key at
line 926. Another cached message from the same sender keeps
remote_content_allowed = true. Selection uses that cached detail at lines548–553 without checking permission again.
MailReaderContent.svelte:56andframe.ts:131then permit HTTPS images. The sender can receive the User's IPaddress and message-open time after permission was removed. This data leak
blocks merge.
The inert local check uses the branch's actual
BoundedReaderCache. It storestwo permitted message details, applies the current delete-and-replace operation
to one, and confirms that the other still has permission. It sends no request.
The check proves stale cache state; it does not measure browser network traffic.
Fix: update a live sender permission model, or invalidate all details and pending
loads for the sender. A regression test must cover a second warmed message and
a prefetch that finishes after permission changes.
P1 — BLOCKER: media header parser has no nesting bound
Issue: #816.
Branch:
job/voicefiles-620.crates/calternal-media/src/lib.rs:358definesiso_box_tracks. Lines 366–367recurse on User-controlled container headers without a depth limit or a shared
work budget. The 16 MiB input cap and per-call loop cap do not bound stack use.
Files indexing calls it at
crates/plugins/files/src/index.rs:1105; Searchindexing calls it at
crates/calternal-search/src/indexer.rs:2628. Stackexhaustion can terminate the server. This crash risk blocks merge.
This is a static finding. No crash payload or threshold was tested. Fix the
shared parser with a finite container grammar or an iterative traversal with
depth and work limits. Test those limits and normal audio/video headers after
the repair. The related older #519 and DAV XML #785 do not track this parser.
Security boundary checks
job/agentdocs-630job/submenu-579job/tasks-modejob/toastname-586job/tocrail-636job/quirks-546job/calcard-seriesjob/editor-seriesjob/reload-423job/cal-e2e-569job/selalign-576job/maillayoutsjob/dragghost-612job/writeonopen-661job/ryw-653job/perf-cache-665job/perf-snap-666job/perf-mut-667job/fix-499job/calimg-589job/voicefiles-620job/imaptest-625job/burst-709job/admin-burst-705job/instant-663All new private routes inherit session authority from the server. Cookie writes
require the configured Origin. Read-only credentials reject writes and protocol
upgrades. Plugin handlers then require the data scope and bind queries or Home
access to that principal. No new outbound server fetch was found. Shared browser
caches were checked against session cleanup and late response publication.
The Tasks singleton and Mail reader cache do not each implement a session reset.
The reviewed shell unmounts private views synchronously at session end and reloads
before it mounts another User. That normal flow prevents the suspected User-switch
leak. It does not fix sender permission changes within the same Mail session.
These results cover the pinned source heads, not a combined application build.
Decisions
remote heads are compared before review.
change product code.
separate, and distinguish static evidence from runtime observations.
Validation
Local cache check (exit 0):
Inert shared-cache checks (exit 0):
Final fetch and
git merge origin/devwere run once. Integration output(exit 0):
The integration base remains
c4a61e8cf090170f35b1bed3350d9de20c83ecd5. All 25 remote heads still matchthe reviewed heads.
Report and source-integrity checks (exit 0):
git diff --checkreturned no output and exit 0. The inert checks above werererun after the final fetch and merge.
No Rust or web source was authored.
cargo fmt --check, crate clippy/test,bun run checkandbun run testwere not run. This report makes no claimthat the queued branches build or pass their gates. The review-specific job
requires minimal cargo use. No live adversarial round was run: there was no
API merge. The findings include regression test ideas for the repair jobs.
Cleanup:
cargo clean(with the required cargo environment) returned exit 0:Web build and
.svelte-kitoutput were absent. Review artifacts stayin the ignored
artifacts/security-review/directory.Known gaps
was run. No queued branch was merged by this review.
expressly limits builds. No crate or package source was edited.
reviewed head contains the primitive only.
the reviewed branch sets AGPL-3.0-only and has no external dependency.
The real-data probe reached the head server and found one Files identity difference after migration: the
Notesdirectory row's item ID changed, while the child Note, Daily note, Task and renamed File rows kept their IDs, paths, sizes and hashes. In the latest run the old Files listing had Notes IDde446454-547c-457e-a9d8-1394ff05f4d5, the head listing returnedebce9041-8695-46bf-858a-05eaa42fa93e, and the settled SQLite row after server shutdown hada5e2298c-4d33-4a36-9d2f-48383de548f7. The head Index comment for #627 says legacy directory rows without saved parent fingerprints receive a new ID when the target fingerprint changes; the Notes files do change during the calternal-id migration. I am recording this separately and will compare file IDs and data checksums while allowing the documented legacy-directory refresh. This may invalidate an old folder deep link, so please confirm whether #627's migration behavior is acceptable.Non-blocking #847: the maillayouts warm list refresh retains every cached row absent from the fresh page, even when the page is complete and empty (next=null). It saves the deleted row again and can reopen its retained body. The exact merge expression was checked in a local fixture; no provider or browser reproduction is claimed.
All 25 pinned branch diffs have now been screened. The report lists coverage and evidence limits. Fetched origin/dev once and merged it once; dev remains
c4a61e8cf0and the merge reported Already up to date. No reviewed branch was merged. Final documentation checks and cleanup follow.Finished the independent round 7b data-integrity review of 25 pinned heads.
Review branch: job/rev-7b-data.
Head:
19b18f6160.Built: committed review-findings.md plus ignored local evidence fixtures. No product edits, push, deploy, or reviewed-branch merge.
Filed seven separate findings after duplicate searches:
Final documentation gate: git diff --check
c4a61e8cf0HEAD returned exit 0 with no output. git status --short also returned no output. Six local fixture checks passed by reproducing faults; full verbatim output follows in the report. No Rust/web build gates or live-server round were run, as required by this read-mostly brief. Findings remain open; they were not fixed in this review job.Decisions: freeze reviewed heads; distinguish inherited defects; use local collaborator fixtures instead of full builds; classify stale displays without accepted write loss as non-blocking. No product design choice was made. UX gaps closed: none. UX gaps left: #790, #826, #829, #847.
The fetched origin/dev stayed at
c4a61e8cf0. The one requested merge reported Already up to date. Cargo cleanup completed; web build output was absent.Round 7b data-integrity review
Issue: #427. Review branch:
job/rev-7b-data.Base:
c4a61e8cf090170f35b1bed3350d9de20c83ecd5.Scope
Review writes to User files and the Index. Check Undo, live rooms, API,
MCP and DAV writes, Calendar edits, Tasks, retries and deleted-data caches.
Product code is outside this job. Branch diffs are stored in the ignored
artifacts/rev-7b/directory.Branch heads at review start
job/agentdocs-630183ac356359f1f84afad30932f02e07323ddb7ed3f258302a0f2d6418ff60c9ce22cbb33e008ca99job/submenu-579142c063a87206721042ae52d24140490a80627d33f258302a0f2d6418ff60c9ce22cbb33e008ca99job/tasks-modef620390c724ee08540d38b0ba69c3d12225fc1e43f258302a0f2d6418ff60c9ce22cbb33e008ca99job/toastname-586093db3ec12a26d1d9ed303853ee733fbc5e79ccd3f258302a0f2d6418ff60c9ce22cbb33e008ca99job/tocrail-636144f0316a7ed6eb9f1ed495d21918e3e78656365687ff703136e71e89f8dfba139e93cd0788b25c1job/quirks-54650a006765ab635665cc0fc53ccaef10d6210fdf0687ff703136e71e89f8dfba139e93cd0788b25c1job/calcard-series5f7fdb96706aca0c457a6b7851f548f7f618ac85687ff703136e71e89f8dfba139e93cd0788b25c1job/editor-seriesa087d0aba9f39bbfb5447c2ce22db0de25fd37a0687ff703136e71e89f8dfba139e93cd0788b25c1job/reload-4232399db841cf16ade3fbf47fcfab50578a3abe364687ff703136e71e89f8dfba139e93cd0788b25c1job/cal-e2e-56996908cbef8bbf078ce73bbc1a51f432ba8c416c8687ff703136e71e89f8dfba139e93cd0788b25c1job/selalign-576174b554e1a66f53b0c9d92ede41b47eac145f419687ff703136e71e89f8dfba139e93cd0788b25c1job/maillayoutsf9f360e68f4e9ca106ddd7fea24d1f4363881a2b687ff703136e71e89f8dfba139e93cd0788b25c1job/dragghost-612bc08062b167e59ca7ac39426a96481b2664b2e75687ff703136e71e89f8dfba139e93cd0788b25c1job/writeonopen-66104c4a651be5a0da6c1311af9ad2d39bd289b8a09c4a61e8cf090170f35b1bed3350d9de20c83ecd5job/ryw-6534723c5f3b1ebfaa90905376e4a3d14e2ee60ae63c4a61e8cf090170f35b1bed3350d9de20c83ecd5job/perf-cache-665b88bc6ac888fd18e7e8a256f0b5b65ecaeed92c2c4a61e8cf090170f35b1bed3350d9de20c83ecd5job/perf-snap-666253c2a00cade24a7f845a5e67f309093641b8850c4a61e8cf090170f35b1bed3350d9de20c83ecd5job/perf-mut-66752d2b17f805072cd0304d7a05fe0534523cc7bc3c4a61e8cf090170f35b1bed3350d9de20c83ecd5job/fix-499242022301673dc6746d89985ee36078743723591c4a61e8cf090170f35b1bed3350d9de20c83ecd5job/calimg-589421dd63735d116cba4961a0a3ca4c985baa83480c4a61e8cf090170f35b1bed3350d9de20c83ecd5job/voicefiles-620b7ef7a2ab57f45b5d46cd19b4560215acae918e3c4a61e8cf090170f35b1bed3350d9de20c83ecd5job/imaptest-625f811d7aa4bf922ceb3948ddb5b6241944fb5cbd3c4a61e8cf090170f35b1bed3350d9de20c83ecd5job/burst-709c421756ac9af5a9b653b7c9f53c41b3aca24de89c4a61e8cf090170f35b1bed3350d9de20c83ecd5job/admin-burst-70523a6fe0e0e326f789c886f366880f5b86683b287c4a61e8cf090170f35b1bed3350d9de20c83ecd5job/instant-663e62249dedcc2c7d108e4432596d40aee6f5a4bc8c4a61e8cf090170f35b1bed3350d9de20c83ecd5Findings
F1 — BLOCKER: saved Task views lose acknowledged edits
Branch:
job/tasks-modeatf620390c724ee08540d38b0ba69c3d12225fc1e4.Evidence:
crates/plugins/notes/src/task_views.rs:39,180,194,202andapps/web/src/lib/tasks/api.ts:84. The route accepts a complete view withoutthe revision the client read. It replaces that view in the current file, then
checks the current file hash. Two clients can read filter A. The first saves
filter B. The second changes the layout from its old copy and restores filter A
with a successful 200. The User lock does not prevent this lost update.
Expected: require the client revision and return 412 on a stale replacement.
Test idea: read twice, save a filter, then submit the other retained copy with a
layout change; preserve the first filter and every other view.
Proof: static control-flow review. No live-server reproduction.
Duplicate check: all issue titles, saved-view and stale-write searches; no
separate issue found. Filed: #731.
F2 — BLOCKER: Calendar Undo overwrites a later edit
Branch:
job/calcard-seriesat5f7fdb96706aca0c457a6b7851f548f7f618ac85.Evidence: Calendar route
+page.svelte:851, Journal adapterjournal.ts:30,58,67,and
edits.ts:353. Undo captures the old fields without the revision returnedby its forward write. A later
readDaycan replace the module ETag with therevision of another committed edit. Undo then submits the old fields with that
new revision. The server accepts the inverse and removes the later edit.
Proof: the local test imports the reviewed Journal adapter and stubs transport.
It commits B at R2, installs C at R3, reads the day, then submits the same patch
used by the Undo closure. The adapter sends R3 and final title A replaces C.
The Svelte closure is checked statically. No live-server test was run.
Expected: bind the inverse to the forward result revision or durable receipt.
This Undo design is inherited, and remains present in the reviewed head.
Filed: #777.
F3 — Calendar retries retain the rejected ETag
Branch:
job/calcard-seriesat the F2 head.journal.ts:58returns the cachedETag. PATCH and DELETE do not discard it on 412.
forgetDays:54clears onlyday promises. A Calendar range refresh contains no ETags. After another
Installation changes the entry, normal edit retries keep using the rejected
ETag until a fresh Journal read or document reload.
Proof: two calls to the reviewed
patchEntry, withforgetDaysbetween them,both send R0 after a fixture change to R1. Both return 412. Non-blocking: the
server keeps the newer data. Expected: discard a rejected revision and refresh
the write precondition before a deliberate retry.
Filed: #790.
F4 — a late read replaces an acknowledged month snapshot
Branch:
job/reload-423at its recorded head. Evidence:money/store.svelte.ts:125,146,245and the month route+page.svelte:81,121.A pending read captures only the session generation. Mutation invalidation
removes stored reports but does not fence that read. After the save stores the
new report, the old response replaces memory, browser storage and the view.
Proof: local test runs the branch store with transport and storage fixtures.
It observes the older marker after write invalidation and
rememberMonth.Svelte state runes use identity stubs. No live server or rendering check.
Non-blocking: no lost server write. Fence reads issued before a mutation.
Filed: #826.
F5 — an online warm Note open retains a deleted body after refusal
Branch:
job/perf-cache-665at its recorded head. Evidence:notes/NoteView.svelte:150,182,319andnotes/collab.ts:213.A warm open skips
getNote. A refused room then enables fallback editingwithout reading the Note again or clearing its cached body. If a deletion event
was missed while disconnected, the online view still presents the deleted Note.
Proof: local test runs the exact
loadandconnectfunction bodies withfixtures for the editor and provider. After refusal, the view stays ready,
retains the body, enables fallback and has made zero authoritative reads.
The renderer and live transport are outside this check. Non-blocking: no
accepted write to the deleted Note. Revalidate refusal and render missing on 404.
Filed: #829.
F6 — BLOCKER: retry after a linked body failure duplicates Logs
Branches: inherited Composer code in the recorded
job/tasks-modehead;Log batch server reviewed at the recorded
job/ryw-653head.Evidence:
composer/commit.ts:326,343,349,composer/Composer.svelte:1279,1294,1297,1300, and Noteslib.rs:4355.commitLogBatchacknowledges durable Logs before linked Note body writes.If a body write fails, Send all keeps the original drafts.
markCommittedis after the rejected await. Sending those drafts again allocates new Log IDs.
Proof: local test runs the exact batch function body with prepare and transport
fixtures. The first call acknowledges
log-1before its body call rejects.Retry of the same snapshot creates
log-2. The draft retention path is checkedstatically. No live server or rendered Composer test was run.
Expected: retry the retained body against the acknowledged stable Log ID.
This flaw is inherited, not claimed as a new change in either branch.
Filed: #844.
F7 — a complete Mail page retains deleted cached rows
Branch:
job/maillayoutsat its recorded head. Evidence:mail/MailView.svelte:623,630,463,547andmail/readerCache.ts:67.The warm-page refresh appends every old row absent from the fresh page.
Even an empty complete page with
next = nullretains all deleted rows andstores them again. A retained row can open its cached body without a new read.
Proof: local test executes the branch's exact list merge expression. A cached
removed row survives an authoritative empty complete page. The provider and
rendered route are outside this check. Non-blocking: no accepted deleted write.
Expected: reconcile the complete window and invalidate removed bodies.
Filed: #847.
Review observations
#667 puts the preference write, inverse and receipt in one writer transaction.
Replay compares the canonical input. Legacy writes increase the revision.
Undo rejects a newer revision and rolls back the Undo mark on rejection.
#653 publishes Note, Journal, Calendar and DAV projections before batch 201.
The durable queued job remains for repair. File updates still use checked
replacement and the same User lock.
#661 disables the editor's automatic trailing paragraph. The change removes
a document edit triggered by mount and decoration transactions.
The #634 live-room path retains its flush lock, source ETag check and external
block merge. Daily notes do not join live rooms. This is a static check, not
evidence from a concurrent server run.
#620 changes voice memo MIME and backlink reads. It adds no audio file write.
The Index rechecks the source fingerprint after its bounded MIME probe.
#666 adds a bounded snapshot primitive. It does not wire every Tab to it;
adapter adoption stays in follow-up work.
#667 adds core migration 7 and Mail migration 10. The fetched
origin/devhas core migrations through 6 and Mail through 9. No number collision was
found. The SQL adds a table and a defaulted column; downgrade compatibility
was read, not tested with an older binary.
Coverage
Every recorded branch diff was screened. Large branches received focused
write-path reads; UI-only changes received a check for storage callbacks.
This is not a full correctness audit of every line.
agentdocs-630submenu-579tasks-modetoastname-586tocrail-636quirks-546calcard-serieseditor-seriesreload-423cal-e2e-569selalign-576maillayoutsdragghost-612writeonopen-661ryw-653perf-cache-665perf-snap-666perf-mut-667fix-499calimg-589voicefiles-620imaptest-625burst-709admin-burst-705instant-663Limits and known gaps
belong to this review job. They remain open for their implementers.
live API/DAV/MCP concurrency run, crash recovery test or browser run was done.
later branch commits need a delta review.
Each finding issue gives a regression test idea for its implementer.
Final base update
Ran
git fetch originonce, thengit merge origin/devonce. Fetched dev:c4a61e8cf090170f35b1bed3350d9de20c83ecd5. Merge output:Validation
No product files changed. No Rust or web build run. Final fixture checks ran
five files in separate Bun processes: six checks reproduced the reported faults.
These tests pass when the defects occur; they do not prove the product is fixed.
Documentation gate:
git diff --checkandgit diff --check c4a61e8cf090170f35b1bed3350d9de20c83ecd5 HEAD.Both returned exit 0 with no output. Rust and full web gates were not run:
this read-mostly job changed only this report and the brief excludes full builds.
Cleanup:
cargo cleanused the preset job target and required environment.Verbatim output:
apps/web/buildandapps/web/.svelte-kitwere absent.Local check:
bun test artifacts/rev-7b/calendar-write-review.test.ts.The tests assert that the faults occur. They are evidence, not product gates.
Local check:
bun test artifacts/rev-7b/money-snapshot-review.test.ts.Local check:
bun test artifacts/rev-7b/note-cache-refusal-review.test.ts.Local check:
bun test artifacts/rev-7b/composer-partial-retry-review.test.ts.Local check:
bun test artifacts/rev-7b/mail-stale-page-review.test.ts.Decisions
Use the local job branch heads when available. Record their full SHA so
the review has a fixed scope. Use remote heads only when no local branch exists.
Separate inherited flaws from newly added behavior. File data corruption and
lost acknowledged edits as blockers. File stale displays as non-blocking when
no accepted server mutation is shown. Use small collaborator fixtures to check
client control flow without a full build on the shared host. These are review
method choices; no product design decision was made.
rev-a11y accessibility source audit complete.
Branch:
job/rev-a11y. Head:25eb9623626d597ef16357ada4aa0bc030953c7d. Auditedorigin/dev:c4a61e8cf090170f35b1bed3350d9de20c83ecd5.Built and committed
review-findings.mdin five atomic documentation commits. Twelve new component-family issues are linked below; #658 received duplicate evidence. Each new issue contains context, source anchors, expected behavior, a fix and a test idea. Follow-up comments correct several initial line references. The final diff changes only the report. No product edits, push or deployment.The requested one-time origin/dev sync was already up to date. Final checks and their output, cleanup, UX gaps and decisions follow. Full app gates and production visual/assistive-technology checks were not run, as specified for this read-mostly job.
Web accessibility review — rev-a11y
This report records the source audit requested by the rev-a11y job. It does
not certify WCAG conformance. No product files change in this job.
Scope and evidence
job/rev-a11y.origin/dev:c4a61e8cf090170f35b1bed3350d9de20c83ecd5.CLAUDE.md,CONTEXT.md, DESIGN §§28, 34, 35, 38 and 57; the currentkeyboard-motion rule (#611) replaces #527.
The project also requires 44 px touch targets and reduced motion. WCAG
2.5.8 AA uses 24 px with exceptions; 44 px is the stricter project rule.
packages/uiandapps/web, duplicatesearches in Forgejo, and small checks where needed. Production builds,
screenshots and full Rust gates are outside this read-mostly job.
The start comment records the mismatch. The audit follows the job prompt.
Findings
A1 — Shared focus containment accepts hidden controls
Priority: P1. Family: focus traps and Settings surfaces.
Tracking: #740.
Criteria: 2.4.3 Focus Order, 2.1.1 Keyboard.
Evidence:
apps/web/src/lib/a11y/focusTrap.ts:87:tabbables()checks the control'sown
hiddenflag and an inert ancestor. It does not check a hiddenancestor, CSS visibility, or hidden input types.
apps/web/src/lib/a11y/focusTrap.ts:142:moveFocusIn()accepts anexplicit target without a visibility check. A failed focus has no fallback.
apps/web/src/routes/settings/[...path]/+page.svelte:294: initial focuscan select
.settings-shell .shell-back.apps/web/src/routes/settings/[...path]/+page.svelte:523: the phonelayout hides the content's
.settings-detail-nav, which contains thatBack button. The visible Back button is in the shared sheet chrome,
outside
.settings-shell.Effect: a phone Settings detail link can request focus on a hidden Back
button. Hidden candidates can also prevent Tab wrapping at the visible end
of a surface.
Fix: use one visibility-aware focus candidate predicate. Apply it to
initial focus and containment. Check hidden/inert ancestors and hidden
input types. Resolve CSS visibility only during focus operations, with no
per-frame observers. If the requested target cannot take focus, use the
first visible control or the surface. Select the visible sheet Back button
for phone Settings.
Test: open a Settings detail link with a keyboard at 390 px. Check that
focus is inside the visible dialog. Add hidden first/last candidates to the
focus-trap tests. Check Tab and Shift+Tab wrapping and Escape restoration.
A2 — PDF previews expose page numbers without document text
Priority: P1. Family: shared PDF viewer.
Tracking: #741.
Criteria: 1.1.1 Non-text Content, 1.3.1 Info and Relationships.
Evidence:
packages/ui/src/components/viewer/PdfView.svelte:6: the module statesthat there is no text layer.
packages/ui/src/components/viewer/PdfView.svelte:74: pdf.js draws eachpage on a canvas.
packages/ui/src/components/viewer/PdfView.svelte:111: each canvas hasonly a page-number label and no content alternative.
packages/ui/src/components/viewer/QuickLook.svelte:235: Quick Look usesthis viewer for PDF files.
Effect: a screen reader can find the PDF name and page number, but cannot
read its text in the preview. This applies to Files, Photos and public-link
previews that use Quick Look.
Fix: add a lazy pdf.js text layer and the available document structure.
Keep canvas paint decorative when an equivalent text layer exists. Keep
page loading bounded. For image-only pages, show a real text-unavailable
state and retain Download. Do not invent OCR output.
Test: open a small text PDF in Quick Look. Check that body text and reading
order reach the accessibility tree, that links work with the keyboard, and
that unloaded pages do not allocate all text layers at once.
A3 — Search scope and subfolder controls have no keyboard route
Priority: P1. Family: search filter chips.
Tracking: #742.
Criterion: 2.1.1 Keyboard.
Evidence:
apps/web/src/lib/search/SearchField.svelte:276: the Ask context removalbutton has
tabindex="-1".apps/web/src/lib/search/SearchField.svelte:282: the Calendar scoperemoval button has
tabindex="-1".apps/web/src/lib/search/SearchField.svelte:295: Include subfolders hastabindex="-1". Its click handler is the only UI call tosetSubfolders().apps/web/src/lib/search/SearchField.svelte:182: the chip key handlercan select, remove or edit ordinary pills. It cannot focus or activate
these nested controls or clear the separate Calendar/Ask scope chips.
Effect: a keyboard User cannot use the visible Include subfolders action
or remove those scope chips through their controls.
Fix: give the controls real Tab stops, or extend the shared chip keyboard
model to reach and activate every action. Preserve the typed query. Give
the active control visible focus and announce changes once.
Test: open scoped search with a keyboard. Toggle Include subfolders with
Space, clear Calendar scope, and clear Ask context. Check the result scope
and query without pointer input.
A4 — Warm tooltips cannot stay open under the pointer
Priority: P2. Family: shared warm tooltips.
Tracking: #744.
Criterion: 1.4.13 Content on Hover or Focus.
Evidence:
packages/ui/src/components/tooltip/TooltipLayer.svelte:208: pointerexit hides the bubble unless the pointer stays inside the trigger.
packages/ui/src/components/tooltip/TooltipLayer.svelte:391: the bubblehas
pointer-events: none.Effect: moving from a small toolbar control onto its tooltip closes the
text. A User who magnifies the interface cannot keep the text visible while
moving to read it. Escape dismissal already exists.
Fix: retain the tooltip while either the trigger or bubble is hovered.
Allow pointer entry to the bubble. Use a bounded grace period across the
gap. Preserve Escape dismissal, keyboard behavior and touch peek behavior.
Test: hover a toolbar action, move through the gap into the tooltip, and
check that it stays visible. Escape must close it without moving focus.
Leaving both regions must close it.
A5 — Interactive TagPill targets stay compact on touch
Priority: P2. Family: shared TagPill.
Tracking: #745.
Rule: DESIGN §35, 44 px touch targets. Also inspect 2.5.8 with spacing.
Evidence:
packages/ui/src/components/TagPill.svelte:43: the interactive buttondoes not use
touch-hitor a minimum target token.packages/ui/src/components/TagPill.svelte:68: the small form uses textsize and 3 px vertical padding. The medium form has a 40 px height fallback.
apps/web/src/lib/components/TagEditor.svelte:143: matching suggestionsrender interactive TagPills without a larger control wrapper.
packages/ui/src/components/calendar/ItemPreview.svelte:220: Tags inthe Calendar preview use the same compact interactive form.
Effect: the touch User must hit a compact chip. Shared sizing tokens do not
increase this button to the project minimum.
Fix: keep the compact paint. Add a shared 44 px coarse-pointer target and
enough spacing that adjacent targets do not overlap. Reuse
touch-hitifits expanded area fits the layout; otherwise grow the button's layout box.
Test: inspect the effective targets in Tag editor suggestions and Calendar
preview Tags at 390 and 820 px with touch emulation. Check short Tags and
adjacent remove actions. Each action must have a separate 44 px target.
A6 — Focus style divergence is already tracked by #658
Tracking: #658. No duplicate
issue is needed.
Evidence:
apps/web/src/calternal-app.css:252adds two box-shadow bands tothe global focus outline;
packages/ui/src/tokens.css:1487also defines aglobal outline. Local variants include
Checkbox.svelte:181,Select.svelte:107,TimelineScrubber.svelte:213andactions/resizableEdge.ts:94. The native Checkbox input is transparent andpaints its focus on the sibling indicator. The guard must check this
indirect focus paint as well as the active input.
Fix and acceptance remain in #658. Keep keyboard focus visible when styles
are consolidated. Do not remove motion for keyboard input.
A7 — Composer has invisible actionable Tab stops
Priority: P2. Family: Composer.
Tracking: #819.
Criterion: 2.4.7 Focus Visible.
Evidence:
apps/web/src/lib/composer/Composer.svelte:1849and:1850render Stack draft and Discard draft as native
.sr-onlybuttons. Theyremain Tab stops.
apps/web/src/calternal-app.css:260clips that class to a1 px box, with no focus reveal in the app or component.
Effect: a keyboard User reaches an invisible action and cannot see its
name or focus. The screen-reader alternative must remain available.
Fix: reuse a shared focus-reveal utility or the visible Composer action
surface. Show the label and full ring while the action has keyboard focus.
Keep draft guards and recovery. Keep shared keyboard motion.
Test: Tab to both actions with a real draft. Check visible names and focus,
Enter/Space activation, and discard recovery at each required width/theme.
A8 — Photos scrubber has a 28 px touch target
Priority: P2. Family: Photos timeline scrubber.
Tracking: #820.
Rule: DESIGN §35, 44 px touch targets.
Evidence:
apps/web/src/lib/photos/TimelineScrubber.svelte:274makes thetouch track ignore pointers. Its touch thumb is 28 × 48 px at
:291andaccepts pointers only while active or dragging at
:313. The outer 44 pxstrip does not increase the effective target.
Fix: keep the narrow painted grip. Expand its effective target to 44 × 48 px
inside the strip. Keep normal scrolling outside the target and pointer
capture on the hit target. Use CSS.
Test: scroll a multi-month timeline until the handle appears. Start a touch
drag beside the painted grip within the expanded target. Check capture,
jump, adjacent item menus, and scrolling outside the target. Check existing
keyboard slider actions. This is a project-rule finding, not a claim that
the basic 24 px WCAG 2.5.8 AA size fails.
A9 — Zoomed image previews cannot pan with the keyboard
Priority: P1. Family: shared image viewer.
Tracking: #830.
Criteria: 2.1.1 Keyboard, 2.5.7 Dragging Movements.
Evidence:
packages/ui/src/components/viewer/ImageView.svelte:97changesthe image offset only in the pointer-drag path. The exported API at
:114supplies zoom only.
viewer/QuickLook.svelte:155maps navigation keys toitem changes and at
:165maps zoom keys tozoomBy(). The stage clipsenlarged edges at
ImageView.svelte:161.Effect: a keyboard User can enlarge an image but cannot inspect its edges
at that zoom. Custom panning also lacks a single-click or tap alternative.
Fix: add a bounded shared pan command. Expose keyboard actions and named
pan controls that work by one click or tap. Keep item navigation distinct.
Use the shared shortcut registry, tooltip and 44 px target primitives.
Test: inspect every image edge at enlarged zoom with keyboard actions, then
with individual clicks/taps without dragging. Check Reset, item navigation,
focus, names, target size and reduced motion at all required widths/themes.
A10 — Category labels break persistent error descriptions
Priority: P2. Family: inline category fields.
Tracking: #831.
Criterion: 1.3.1 Info and Relationships.
Evidence:
apps/web/src/lib/components/money/AssignedCell.svelte:92and:102build the error reference and ID from the category label. The callerat
apps/web/src/routes/money/[budget]/[month]/+page.svelte:268passescategory.name. A space in a label splitsaria-describedbyinto separateID references. Repeated labels can also collide.
Effect: the initial alert can speak, but the invalid field has no valid
persistent error description for these labels.
Fix: use
$props.id()or a supplied stable item ID and a fixed suffix. Keepthe visible category label as the field name. Do not sanitize labels into IDs.
Test: use a label with spaces and repeated labels across groups. Each
invalid field must reference one existing, unique error element. Check the
accessible description when focus returns. Use no real financial data.
A11 — Analytics heatmap readouts lack full-size touch access
Priority: P2. Family: Analytics marks.
Tracking: #845.
Rule: DESIGN §35, 44 px touch targets.
Evidence:
apps/web/src/lib/components/analytics/BklitAnalyticsHeatmapMarks.tsx:49and
:55use the painted bin dimensions minus the gap. These dimensionsreach the buttons at
BklitKeyboardMarks.tsx:120. The shared heatmap columntokens at
packages/ui/src/tokens.css:20range from 13 to 18 px at thedefault 16 px root.
BklitAnalytics.tsx:995caps Calendar heatmap width withthe maximum token and supplies a 2 px gap. Its mark CSS at
:335adds nolarger touch target. No full-size readout alternative exists in the wrapper.
Fix: preserve exact-cell fine-pointer hover and keyboard access. Provide a
real-data readout list or day/hour selector with separate 44 px targets for
touch. Reuse the same readout values. Do not overlap enlarged cell targets.
Test: reach each value in a long Calendar range and the Time of day chart
through full-size touch actions. Check parity with hover and keyboard
readouts. Measure target size and spacing for WCAG 2.5.8. The date-navigation
exemption does not supply an equivalent Analytics readout.
A12 — Live Photo playback has a 28 px touch target
Priority: P2. Family: Live Photo playback.
Tracking: #846.
Rule: DESIGN §35, 44 px touch targets.
Evidence:
packages/ui/src/components/viewer/LiveMotion.svelte:74rendersa named native toggle, but the target is 28 px high at
:109. It has noexpanded hit area or coarse-pointer size rule.
QuickLook.svelte:233placesit outside the header action group that has larger control targets.
Fix: preserve the compact paint and expand the coarse-pointer target with
the shared target primitive, or grow its control box. Keep adjacent actions
separate and preserve pressed state and explicit reduced-motion playback.
Test: tap the expanded area, check playback/state, and verify 44 px effective
targets. Check Space/Enter and reduced motion at all required widths/themes.
A13 — Modal backgrounds stay live despite the inert contract
Priority: P1. Family: modal shell.
Tracking: #848.
Rule: shared modal contract and the ARIA modal-dialog pattern.
Evidence:
apps/web/src/lib/overlay/state.svelte.ts:3says the layout makesthe feed inert.
open()at:50changes a count and dismisses transient UI.apps/web/src/routes/+layout.svelte:796and:819do not bind inert to theapp frame or route content. Only the bottom Tab Bar and Primary Pill consume
overlay state to remove interaction. The desktop sidebar at
apps/web/src/lib/components/app-sidebar.svelte:451is inert only whencollapsed.
packages/ui/src/actions/portal.ts:24moves a branch withoutisolating siblings.
focusTrap.ts:229listens only for local keydown, withno document focus-entry guard.
Effect: background controls can still receive programmatic focus and then
keyboard input. A scrim and local Tab loop do not make a background inert.
This confirms the source contract gap. Reader-specific exposure despite
aria-modalrequires a production assistive-technology check.Fix: give modal background state one shared owner. Keep background app
content and lower dialogs inert while the top dialog is open, including its
exit. Preserve nested menus and the supported toast action path. Restore
prior state and focus on close. Update the stale comments with the fix.
Test: open Search over focusable route content and an expanded sidebar.
Attempt a delayed background focus. Open a confirmation over Settings;
check upper-dialog focus, then restoration to Settings and the app opener.
Check Escape, nested menus, toast actions and screen-reader exploration.
Behavior evidence
A small browser harness bundles the actual
focusTrap.tsand its localdependencies. It uses one Chromium browser at 390 px with macOS platform
emulation. The fixture is behavior evidence, not a UI visual review.
node artifacts/rev-a11y/focus-probe.mjsexits 0 and prints:The first case requests a button under
display:noneand leaves focus onthe outside opener. In the second case, a hidden last candidate prevents
wrapping and native Tab reaches an outside button. The full phone Settings
route remains an acceptance test for the fix.
The added #848 case tests the shared action with visible controls. It does
not render OverlaySurface; source inspection establishes the missing inert
binding in the app. The #831 fixture tests the browser's ID-reference parsing
with a neutral label. It does not render the full category editor.
Source-lint coverage
A sequential scan uses the installed Svelte compiler. It removes only
accessibility-suppression comments in memory, while preserving positions.
It writes no product output. First scan output:
Warnings alone are not findings. Several wrappers delegate keyboard actions
to their child controls; programmatic deep-link targets and initial focus
also require context. The report records only defects with source evidence.
Coverage and limits
The source scan covers 243 Svelte files in
packages/ui/srcandapps/web/src, excluding the test-fixture directory. Manual review followsthe shared controls and their route consumers. It includes the React chart
interaction adapters that Svelte mounts.
The 19 compiler warnings were read in context. Most are programmatic focus
targets, wrapper listeners with child keyboard controls, or delegated input
handlers. VideoView has no caption track and suppresses that warning; media
caption/transcript requirements need a content and playback review. No blanket
media conformance claim is made.
Source checks cannot certify screen-reader reading order, actual focus-ring
paint, reflow at zoom, touch spacing or contrast over User backgrounds.
The fix jobs need real production builds at 390, 820 and 1440 px, light and
dark, with macOS rendering. No screenshots were taken in this read-mostly
job. VoiceOver, another screen reader, native media controls and real touch
devices were not tested.
Verification
The required one-time
git fetch origin && git merge origin/devran beforethe final checks. Output, exit 0:
origin/devremainsc4a61e8cf090170f35b1bed3350d9de20c83ecd5; no reviewedproduct source changed. The final diff contains only this report.
The focused existing test uses Vitest 5.0.1 with one worker and an audit-only
config. It imports the real shared theme module directly through the app's
theme facade. This avoids the UI barrel and a full app build. Output, exit 0:
The theme checks include AA text roles across curated materials and control
contrast. They do not replace rendered checks. Two initial harness setup
attempts stopped before tests: missing generated SvelteKit configuration,
then the unresolved UI package. The isolated config resolved both; no test
expectation or product file changed.
The final browser probe output is quoted above; exit 0. The source-lint
summary is quoted above; exit 0.
git diff --checkhas no output and exits 0.Full
bun run check,bun run test, Rust format/clippy/test and a serveradversarial run were not executed. The job asks for a read-mostly review,
minimal crate use and no full builds. No Rust, API, route or product source
changes. No feature benchmark is required for this report-only change.
Cleanup uses the preset
/mnt/hdd/targets/jobs/rev-a11ytarget, withCARGO_PROFILE_DEV_DEBUG=line-tables-only,CARGO_INCREMENTAL=0,CARGO_BUILD_JOBS=4and worktreetarget/tmp.cargo cleanexits 0:Web-output cleanup exits 0:
UX gaps closed
No product gap is fixed in this review. Twelve component-family issues now
have source evidence, an exact fix and an acceptance test. Focus entry and
escape defects have a browser reproduction. Existing #658 has additional
evidence instead of a duplicate issue.
UX gaps left
A1–A13 remain implementation work. The existing Calendar Task completion
gap is #657; no duplicate was
filed. Production visual and assistive-technology acceptance checks remain
for the fix jobs. The open shared sr-only reuse issue
#308 is separate from A7's
clipped focusable controls.
Decisions
attachment title. Record all audit links on the assigned issue.
theme test. Do not make product edits or build standalone review pages.
sub-44 px target an AA failure or treat Focus Appearance as AA.
only because a compiler warning exists or a rendered check has not run.
No product design decision or dependency change was made.
One real-data probe returned HTTP 503 for a valid Reminders VTODO
PUTto the local DAV endpoint withIf-None-Match: *, after Mail had cached 1,999 messages and 2,000 UID memberships. During that run, SQLite showedmail.syncandfiles.thumbnailjobs still leased; the shared account thread count reached 5,996. An earlier run completed the same DAV PUT and GET successfully. The first 503 response body was not retained, so I cannot classify it beyond a load-sensitive 503. I moved the DAV seed before the Mail backfill and added bounded response text to the next failure diagnostic; no assertion is being weakened.The Cross-User classification gate found the new Connected Accounts operations missing explicit policy and path-ID semantics. I added owner-scoped classifications for list/create/update/delete and legacy migration status under DESIGN §49 / #407, plus
integration_account_idfor the update/delete{id}paths.XUSER_CLASSIFY_ONLY=1 python3 tests/adversarial/xuser_matrix.pynow reportsCross-User classification gate: 342 operations classifiedandGenerated entry point classification: 960 tools classified. The full matrix has not reached server setup yet; the media-runtime host thread guard is the next gate.The requested Cross-User/Admin runner now passes both classification inventories and the Admin coverage check, but the real server matrix does not start:
prepare-media-runtime.shexits withtoo many local threads for the bounded media sandbox test: 6759. The full robustness run stopped at the same guard after classification and Admin coverage, this time reporting 6,370 threads. Both exits happen before browser setup or API attacks. I did not bypass the sandbox's explicit 4,090-thread safety threshold or retry the suite; no Two-User isolation or robustness result is claimed.Mail TLS Dovecot e2e update (commit
efe8323fe): the old flow opened/settings/mail/connectand waited for anOtherradio. That route now directs Users to Connected Accounts, so the fixture could not reach its form. The e2e now seeds the controlled localhost TLS account through the authenticated Mail API, then exercises the real Mail UI.The first run stopped at the removed radio. The updated run passed account creation and live sidebar progress, but 2,000-message backfill exceeded its 180-second completion budget. The server logged SQLite pool waits up to 19.5 seconds and a Mail row insert taking 3.8 seconds while other worktrees were building/checking. This run did not establish a Mail product failure; the completion gate remains unverified under this host load.
#427 merge-round 7a — Round 2 final report
Branch:
job/merge-round-7aHead:
0a16bf704284f5d3b9a27a9046512155d64c2935Base check: fetched and merged
origin/devonce before final gates; it was up to date. No push, deploy, or branch merge was performed.Built and files
The committed round-2 gate fixes are:
apps/web/e2e/files.mjs: Recent now followsgamma.mdafter it is renamed todelta.md; type-to-select sends the filename prefix key.apps/web/e2e/harness.mjs,apps/web/e2e/integrations-review.mjs,apps/web/e2e/mail-sync-613.mjs: emulate macOS platform metadata for screenshot review.apps/web/e2e/mail-sync-613.mjs: seed the TLS Dovecot account through the current authenticated Mail API, then exercise the real Mail UI.tests/adversarial/authz_matrix.py,tests/adversarial/xuser_matrix.py: classify Connected Accounts operations and their{id}parameter for the User/Admin matrices.The full branch contains 259 changed files across the previously reported merge groups. Earlier group details and per-crate gates are in the earlier #427 comments. Rust source did not change after those Rust gates.
Upgrade proof
Built
origin/devatc4a61e8cf090170f35b1bed3350d9de20c83ecd5and this head. The old binary seeded real-shaped data through its API; the new binary migrated the same data directory; then the old binary was started again.All requested migrations applied: core 0007–0012, Calendar 0005, Notes 0025/0026, Files 0016–0019, Search 0004. The 1,999 Mail message rows, 2,000 memberships (including two duplicate RFC Message-ID memberships), and message checksum were unchanged; known Mail UIDs were not refetched. Notes/Daily content remained stable apart from documented IDs/version metadata. Reminders over DAV remained present. The old binary started and served health, Notes and Mail successfully after migration.
Gate output
Per-crate
cargo clippy -p <crate> --all-targets -- -D warningsandcargo test -p <crate>passed for the 19 changed Rust crates listed in the earlier #427 final report. The Notes suite had one load-sensitive failure (daily_and_composer_preserve_unrelated_bytes, 404 where its existing assertion expects 200); its isolated rerun was1 passed; 0 failed; 0 ignored; 0 measured; 182 filtered out. No test expectation changed.The requested robustness suite reached the same classification output, then stopped before attack setup at:
Mail TLS Dovecot e2e connected through the real API and showed live folder/message progress, but its 2,000-message backfill did not finish in 180 seconds:
The Files e2e stopped before rename/Recent at fixture upload because the local media/server environment returned 503:
Known gaps and UX review
UX gaps closed: corrected the stale Files Recent expectation after rename; extended User/Admin classification to Connected Accounts; changed Mail e2e setup to the current account API; generated the Connected Accounts review screenshots with macOS platform emulation at 390/820/1440 px in light and dark themes.
UX gaps left: the corrected Files typeahead/Recent flow was not verified end-to-end after the fixture upload returned 503. Mail account creation and live progress passed, but full backfill completion remains unverified within the e2e budget. The web unit suite has 29 timeout failures and one worker-start error across unrelated tests; no expectations were changed and no retry was run. XUser and robustness attack phases did not start because the bounded media runtime rejected the host thread count. Thumbnail readiness stayed false (
decoder-failed-v1) under the media runtime guard.Upgrade finding for owner review: the
Notesdirectory identity changed fromace3ae33-0db4-41a3-9f6e-89bfd9d6908bto7304b637-0602-4b6f-a062-7f4d6b39c0e9. The existing #627 behavior creates a new ID when the parent fingerprint is unavailable; confirm whether this is acceptable for stable folder links.The Connected Accounts screenshot set has 66 images and is saved at
artifacts/connected-accounts/; the archive isartifacts/connected-accounts-review.zip. The installedscripts/fjCLI has no issue attachment/upload command, so I could not attach it to this comment. The macOS VM is offline; screenshots used Playwright macOS platform emulation and no real-Mac run was attempted.Decisions not settled by DESIGN
/settings/mail/connecte2e flow no longer exposes itsOthersetup form; continue the actual sync check in the Mail UI.No pushes, deploys, or merges were performed.
Starting merge-round-7a from branch job/merge-round-7a at
0a16bf7042. I am merging origin/dev first, then I will check host load and continue the requested deploy-readiness probes.Round 3 report — merge-round-7a
Deploy readiness: No. It is not demonstrated by this round. At 21:45:29 the host load average was 30.94/27.23/27.94 on 12 cores, so the quiet-host condition was false. The verification policy in this job also reserves the full web suite and XUser/robustness matrices for the merge round; I did not run them here.
Changes
No product source changed. I fetched and merged
origin/dev(c4faf184d) once. The resulting head is01d28acb9f5d1226a431dca82db154770c144698; it contains media guard fix440e19dce(verified as an ancestor). The merge changeddeploy/media-sandbox,docs/DESIGN.md, andtests/adversarial/prepare-media-runtime.sh. No push or deploy was performed.Gate output
cargo fmt --checkexited 0; stdout and stderr were empty. No crate clippy/tests or web checks ran: this round authored no Rust or web source.cargo cleancompleted withRemoved 1 file, 356B total.apps/web/buildand/mnt/hdd/targets/shared-server/CURRENTwere absent.Findings and remaining gaps
The preceding issue report records: Files fixture upload returned
503 !== 201; Mail account setup and live progress passed, but the 2,000-message backfill exceeded 180 seconds; XUser and robustness stopped before attack setup at the old media thread guard (6,759 and 6,370); thumbnail readiness wasdecoder-failed-v1. The previousbun run testreported 22 failed files, 131 passed, 29 failed tests, 1,041 passed and one worker error over 1,175.81 seconds. There is no same-conditionorigin/devcomparison in the evidence.The old Files run's server log line was not retained in the issue history or this worktree, so I cannot classify its 503 as load or a server refusal. The current Files e2e assertion prints the status but not the captured
startServer()diagnostics. Re-run it with diagnostics preserved; if the response is a real refusal, fix it with a regression test. No new backfill rate was measured, and thumbnail readiness was not rechecked after the guard fix.UX gaps closed: none in this verification-only round.
UX gaps left: Files upload/Recent flow, Mail backfill completion, and thumbnail readiness remain unverified. The previous web unit failures also need the merge-round run.
Decisions not covered by DESIGN: none; no product behavior was changed.
For the merge round
Run the web unit suite once with
cd apps/web && bun run test --maxWorkers=2. Runtests/adversarial/run.shonce on the quiet host; this is the full adversarial round for XUser, robustness and media/thumbnail checks. For Files and Mail e2e, build the production SPA and server first because both shared build paths were absent here:On a Files upload 503, preserve and inspect the server diagnostics before the harness closes it. The Files e2e exercises its real thumbnail pipeline; the adversarial run also exercises the media input and thumbnail checks. Do not change the known pre-existing Notes directory ID behavior from #627.
Round 4 verification started on job/merge-round-7a, base
01d28acb9. This job is the merge round. I will build the production SPA and server, run the full adversarial runner, full web unit suite with two workers, Files upload/rename/Recent, Mail 2,000-message backfill, and thumbnail readiness. No push or deploy. Logs stay in artifacts/round4; final readiness will cite actual completed output.Round 4 finding: the full web unit run reported a failure in OverlaySurface.svelte.test.ts (Inspector phone sheet header). The run is still active; I will rerun each failed file alone after it exits. No expectation has changed. Production SPA build and cargo fmt --check passed. bun run check output:
svelte-check found 0 errors and 0 warnings.The Files e2e now prints redacted server diagnostics on failure. The Mail e2e now measures the 2,000-message budget from account creation and prints seconds and messages/s, including progress on timeout. Node syntax checks passed for both scripts. Browser runs wait for the server build and run one at a time.
Round 4 full web unit suite completed. Verbatim summary:
The only failure was
OverlaySurface.svelte.test.ts > moves an Inspector title and close action into the phone sheet header:Error: Test timed out in 5000ms.As instructed, I reran that file alone with
bunx vitest run src/lib/components/OverlaySurface.svelte.test.ts --maxWorkers=2. Verbatim summary:This is load under the job's classification rule. No expectation or timeout changed. Other gates completed: production SPA build,
cargo fmt --check(exit 0, no output), andbun run check(svelte-check found 0 errors and 0 warnings). The server build is active. Adversarial and browser runs are queued; no readiness claim yet.Round 4 server build hit an infrastructure failure in the shared compiler cache, not a Rust diagnostic. Evidence:
The compiler wrapper exited with status 254. Another concurrent compiler reported:
This job exports its own TMPDIR. The shared sccache process used a temporary path from another job. I will resume the same build with
RUSTC_WRAPPER=only for this job, retaining the assigned CARGO_TARGET_DIR, four build jobs, line-tables-only and no incremental compilation. I will not restart or alter the shared cache service. Production SPA and web checks are already complete; no gate is waived.Round 4 telemetry review found a measurement edge case: Mail runs sidebar, first-page and navigation checks before its completion helper. Those waits can consume the 180-second budget. A loop that checks its deadline before its first status read would then report zero messages without measuring progress. The helper now reads real status at least once before reporting a timeout. The 180-second completion budget stays in place; no status-code assertion or fixture changed. Node syntax and diff checks passed. The real Mail run is still queued behind the server build and adversarial round.
The server has reached linking. The linker is active and waiting on disk I/O. No build diagnostic has appeared in the direct-compiler retry. No readiness claim yet.
Round 4 server build completed after bypassing the shared sccache temporary-directory failure. Verbatim final build output:
The build contains the production SPA and the explicit Mail test-provider feature, plus the CLI and sync binaries needed by the adversarial runner. The full
tests/adversarial/run.shis now active. Its opening static gates reported:These are classification gates only; the live matrices are still to run. Current head:
ba5134fa2. Files and Mail browser flows remain queued after this one full adversarial round. No push or deploy.Round 4 update: production SPA and server builds are complete. Full Vitest ran: 153 files passed; one OverlaySurface test timed out and its unchanged file passed alone (11/11), so that failure meets the requested load classification.
Adversarial runner exited 1. Search reported missing committed hits, watcher overflow recovery failure, repair HTTP 503 and unfinished startup repair (#956). XUser and authz aborted during fixture Upload/App Password setup (#957). Editor reported
editor findings=10 seed=25608414 historySeeds=25608414; restart barrier timeout aborted remaining robustness phases and cleanup hung until the job's server was terminated (#959). No complete authorization or robustness pass can be claimed.Fixed and regression-tested a separate startup cause: nested probes inherited parent Notes listener settings without that parent's TLS files. Fresh e2e servers now remove inherited Notes listener settings; explicit data-directory fixtures keep them. Focused real-server regression:
# tests 1,# pass 1,# fail 0. Commit331231cb1c. Existing standalone theme mocks also fail withwindow is not defined; expectations and fixtures were left unchanged and #958 records that gap.Files and Mail checks are now running sequentially. Current deploy readiness is no.
Mail e2e passed on the production SPA and real server with the isolated TLS Dovecot provider:
Exit 0. The budget begins before account creation, not after UI navigation. macOS emulation was installed before registration. All 12 Settings/Mail screenshots are attached: Mail macOS evidence. This is test-only provider data, not shipped UI data.
Files upload returned 503 before rename/Recent or worker thumbnail readiness. The redacted server log shows database checkout waits up to 16.20410488 seconds but no upload failure line. A focused rerun now retains the response error envelope through the existing byte uploader, with the unchanged 201 assertion and identical fixture bytes. Commit
1a0539880.Deploy readiness: no. No push or deploy was performed.
Built the production SPA plus calternal-server, calternal-cli and calternal-sync. The server includes mail-test-provider for the isolated local TLS fixture. Fetched and merged origin/dev once before final verification: Already up to date. The first server build failed because the shared sccache process used a deleted worktree's temporary directory. The same assigned target built successfully with RUSTC_WRAPPER empty for this job; no shared process was reset.
Built/fixed: fresh e2e servers no longer inherit a parent Notes listener configuration without its private TLS files. The real-server regression failed before the fix and passed afterward. Files failure reports retain redacted server diagnostics and use the existing byte uploader to preserve failure envelopes. Mail measures the full 180-second budget from account creation and reports actual progress if UI checks consume the budget. Thumbnail evidence reports successful renderer-specific WebP responses. A focused upload/rename/Recent mode shares the full probe's rename action; it does not bypass any full-flow assertion or claim the full suite passed.
Files: apps/web/e2e/harness.mjs, harness.test.mjs, files.mjs and mail-sync-613.mjs. No production Rust or UI source changed. Existing test expectations and fixture bytes were preserved. Seven atomic commits made in this round. Head:
da5c2890108494294e3e25ce22a62bdb09419bfconjob/merge-round-7a.Gate output, verbatim:
The full Vitest suite exited 1 for one OverlaySurface 5-second timeout. That unchanged file passed alone, so it meets the requested load classification. cargo fmt --check exited 0 with no output. node --check and git diff --check passed. No crate changed, so per-changed-crate clippy/test gates do not apply.
Adversarial command tests/adversarial/run.sh exited 1. Verbatim summaries:
Search recovery failures and repair 503 are #956. Live XUser/authz matrices aborted before coverage (#957). Seven existing standalone theme mock tests fail with window undefined (#958); their fixtures/expectations were not changed. Editor restart barrier timeout aborted remaining robustness probes, then cleanup waited indefinitely; this job's stuck server was killed (#959). The full matrices and remaining robustness phases did not complete and cannot be called passing. The original ordinary Files upload returned 503, with captured database checkout waits up to 16.20410488 seconds but no upload failure line (#960). Its precise cause remains unresolved; a successful repeat is not a root-cause fix.
Mail, verbatim:
Mail exited 0. All 12 macOS-rendered Settings/Mail screenshots are attached for the orchestrator's visual review. No screenshot is committed. No Mail rate issue is required because the measured backfill meets the budget.
Thumbnail readiness in the focused repeat, verbatim:
Files focused command
bun apps/web/e2e/files.mjs --rename-recent-onlyexited 0, verbatim:It uses macOS emulation, uploads through the real file input, asserts rename HTTP 204 and stable item ID, then checks the committed name in Recent. The complete repeat did not pass: #961 records the slow-click wait failure. Its shell session ended with 143 after logging the failure, rather than producing the wrapper's exit marker. No positive full-suite result is inferred.
Decisions: no new UI design. Fresh default data-directory fixtures remove all inherited Notes listener fields, since any nested field enables that optional configuration; explicit data-directory restart fixtures retain their settings. Measure Mail from the start of account creation, including preceding UI checks, rather than restarting the timer at completion polling. Preserve response diagnostics using the existing uploader, without retrying or weakening a failing assertion.
UX gaps closed/verified: real Mail connection, live progress, 2,000-message listing and completion; Files worker thumbnails and upload -> committed rename -> Recent with stable item identity. UX gaps left: the complete Files repeat stopped at slow second click rename (
TimeoutError: waitFor: Timeout 30000ms exceeded., #961). No complete Files e2e pass is claimed. Authorization and robustness gaps are listed above. No staging checks ran because this job explicitly forbids deploying. Performance measurements did not run because this issue is verification, not performance.Remaining verification: after fixing #956/#957/#959/#960, run
tests/adversarial/run.shthrough live XUser/authz and all robustness/restart phases. After resolving #961, runCALTERNAL_SERVER_BIN=<rebuilt-server> bun apps/web/e2e/files.mjsthrough the full Files UI flow. This job did not repeat the full adversarial round or weaken an assertion.Cleanup completed:
cargo cleanreportedRemoved 7538 files, 5.1GiB total; production web build output and private retained adversarial fixtures were removed. Logs and screenshot evidence remain in artifacts/round4. The working tree is clean.Staging smoke: merge round 7a on dev.calternal.com
Image:
staging-a0f94231bfrom 06:02Z to 06:30Z. At 06:30:19Z another job redeployed staging withstaging-imap-0e8fde491, which is 7a plus #941 (Notes IMAP edge) and has no new migrations. Calendar and Notes ran on the 7a image. Tasks, Files, Photos, Search, Settings and Mail ran on the imap image. Accounts:interop-admin(Owner) andmacinterop(User), both with saved browser states. Screenshots at 1440 px, light theme, are in the privatestaging/smoke-7a/folder.Flows
/auth/mereturns 200.POST log/batch201,PATCH200 (edit),PATCH200 (move to 07:00),DELETE204, Undo,DELETE204.[[Smoke7a task]]becomes a Markdown link. Ctrl+click opens the target and Linked mentions shows 1. Copy link gives/n/<id>and that link opens the note.done. Ctrl+Z with the cursor in the text sets it back totodo.DELETE204.Server log (06:02Z to 06:52Z)
ERRORand no 5xx produced by the server.WARN Skipped a Task projection with an empty title (#623), mostly as bursts at startup.WARN Notes change feed publication failed error=invalid relative path, only on the imap image, during outside WebDAV writes.Upgrade
git log c4a61e8cf..a0f94231b -- '**/migrations/**'adds 13 migrations: db 0007–0012, auth 0012, Calendar 0005, Files 0019/0020, Notes 0025/0026, Search 0004. No migration changed after the tested head0a16bf704.c4a61e8cfdata to 7a at 05:52:55Z._migrationslists all 13 entries,integration_migration_statusislegacy_accounts_v1 = completeandintegration_migration_failureshas no rows.missing: [],upgrade_checks: pass), and Mail counts and checksums did not change. That report lists "Files 0016–0019", but 0016–0018 are already in production and 7a's new Files migrations are 0019/0020. Group 2 set the expected maximum to 20, and staging applied 0020.Notesfolder ID changes on upgrade (#627), so old folder links to Notes break.Bugs found (not 7a regressions: the same code is in
c4a61e8cf)liveParse, which can still be null (Composer.svelte:1069).- [x]but leavesstatus: todo. The Task stays open in the API, Calendar and Reminders, because the sync only goes from frontmatter to checkbox.refreshBuckets()returns early when the buckets are less than 30 s old (BUCKETS_STALE_MS), so an upload made soon after the page loads stays hidden until a reload. The SSE events arrive.bwrap: Creating new namespace failed: Resource temporarily unavailable(the outer NPROC limit is 64). Every thumbnail getsdecoder-failed-v1and nothing is logged (54 failure markers, the first from 2026-10-02 19:24 onc4a61e8cf). Check that production thumbnails work.79effe5cf, which is aftera0f94231b.The macOS Calendar and Reminders check was skipped because the staging-imap job held the Mac lock. CalDAV PUT and GET for a Log VEVENT and a VTODO work with the Mac App Password.
Ready for production: yes. This smoke found no 7a regression and the upgrade is proven. The round's own adversarial run on
a0f94231bexited 1; its Search size finding is the leak fixed in79effe5cf.Started merge-round 7a verification on job/merge-round-7a at
61222f456d; origin/dev was4a871b3838at start. I am mapping the requested probes and will run them against one release server.Full adversarial run found a Files TUS concurrency regression in the Journal race probe: 2 of 10 conditional upload PATCH requests returned HTTP 500 (
upload state failed) afterindex_and_change_feedcompleted; the failure was atcrates/plugins/files/src/uploads.rs:1683. The destination had a competing committed revision. I changed the finalize check to classify a changed destination as HTTP 412 while keeping HTTP 500 and the retained install intent when live bytes match but the Index row is corrupt. Added a focused regression test; crate gates are pending after the single adversarial run finishes.Verification finding: the Files crate suite timed out in the existing write/reconcile storm test. Exact output:
The host load average at the end was 40.96, 37.81, 36.66. The new focused TUS regression test passed separately (1 passed). I did not change the existing test or its expectations. This storm timeout is outside the TUS code changed for #427 and remains for triage.
verify-7a final report
Branch:
job/merge-round-7aMerged
origin/devonce at516faaa698570bdb468626cf6cd75d9c81b33ac2.Head:
c82b9aca1c5719205fc33260ce050e77737e1427.Built
Fixed the Files TUS completion race. A destination changed by a competing committed upload now returns the existing 412 precondition response so the client can retry. If live bytes still match but the Index row is damaged, completion still returns 500 and retains the install intent for repair. Added a focused regression test. Files changed:
crates/plugins/files/src/index.rs,crates/plugins/files/src/uploads.rs,crates/plugins/files/src/lib.rs.Commit:
c82b9aca1 fix(files): classify concurrent TUS destination changes.Verification
Built the release server, CLI, and sync crates once. Output:
The full
tests/adversarial/run.shprobe reached its final authz matrix. The shell wrapper then failed to retain the runner status because zsh treatsstatusas read-only; exact wrapper output:zsh:1: read-only variable: status. Findings and matrix output were retained in the run log. Static gates reported:#957 XUser and #959 editor matrix output:
Search count leak commit
79effe5cfis an ancestor of this head (git merge-base --is-ancestor 79effe5cf HEADexited 0); the XUser Search isolation probe passed. The final #957 authz matrix completed all 2,216 requests but had six no-response timeouts and no reported authorization mismatch:#964 production Files E2E passed, including type-to-select in Recent:
Rust gate output:
The Files crate suite had one timeout in the existing write/reconcile storm test; the focused TUS regression passed separately:
cargo clippy -p calternal-server --all-targets -- -D warningswas started but stopped at the four-hour job cutoff before it reachedcalternal-server;cargo test -p calternal-serverwas not run. The merge round must run both server gates.cargo cleancompleted with:The web build output was removed.
Known gaps and findings
The adversarial rounds found unresolved content scrub/GC problems: scrub stayed in
phase=scanningat 90 and 180 seconds without repairing damaged CAS content; after restart, 32 orphan blobs and marker garbage remained. This is a data-integrity blocker (#972). The 50K-file deletion/purge probe did not complete within its bound (#78, #174). The authz matrix had the six timeouts above; the Notes IMAP valid APPEND timed out after continuation. Search upload/rename storm requests also timed out under load; the matrix reported no Search isolation or committed-hit failure. Server SIGTERM exceeded 60 seconds and the harness used SIGKILL (#963). These findings were recorded on the existing issues, including #956, #269, #190, #960, #454, #972, #78, #174, #963 and #965. Staging smoke was already reported as passed.The Files storm test failed at its five-minute deadline under host load (load average 40.96, 37.81, 36.66); its assertion was not changed. The full adversarial wrapper status was not captured due the zsh variable collision described above.
Decision
DESIGN.md does not set the response for a TUS destination replaced by a newer concurrent upload. I used 412 Precondition Failed because the upload is stale and the sync client can retry against the current revision. A verified Index mismatch still uses the prior 500 recovery path.
7a READY FOR PRODUCTION: no
UX gaps closed: no UI code changed in this verification job. The #964 keyboard type-to-select behavior in Files Recent passed in the production E2E.
UX gaps left: none found in the #964 flow exercised by that E2E.