Reduce client work during Calendar Tab activation #1557
Open
opened 2026-10-10 19:54:33 +00:00 by kayg
·
129 comments
No Branch/Tag specified
dev
wip/cards2-1083
wip/cards-1083
wip/canvas-visual
wip/canvasvis2-976
wip/calhdr-1112
wip/blocks-1125
wip/allday-1107
wip/agenda-1086
wip/trayicons2-1095
wip/trayicons-1095
wip/sidebar3-1094
wip/previewcard-1098
wip/palette2-1123
wip/palette-1093
wip/nlpchip-1127
wip/mchrome-1084
wip/mailghost2-1094
wip/mailghost-1094
wip/kbpreview2-1118
wip/kbpreview-1118
wip/kanban-1092
wip/editreg-1132
wip/editorrail3-1113
wip/editorrail2-1113
wip/editorrail-1113
wip/draw4-1101
wip/draw3-1101
wip/draw2-1101
wip/draw-1101
wip/delete-1119
job/txentry-1198
job/rev1586
job/rev2-money-ident
job/rev2-webperf
job/morph-1104
job/previewcard-1098
job/importhang-1121
job/kanban-1092
job/merge-round-7b
job/merge-round-7c
job/calcards-1115
job/collabrev3-1197
job/e2e-b-1071
job/agenda-1086
job/agenda-decks
job/allday-1107
job/browserfix
job/calact9
job/adv7c-1105
wip/collabrev3-1197
wip/calcards-1115
wip/calact9
wip/calact10
wip/browserfix
wip/agenda-decks
wip/adv7c-1105
wip/txentry-1198
wip/rev2-webperf
wip/rev2-money-ident
wip/rev1586
wip/morph-1104
wip/merge-round-7c5
wip/merge-round-7c4
wip/merge-round-7c3
wip/merge-round-7c2
wip/merge-round-7c
wip/importhang-1121
wip/fix1586
wip/e2e-b2-1071
wip/e2e-b-1071
job/noncanon-1618
wip/noncanon-1618
job/edrevert-1616
job/partial-1605
wip/partial-1605
job/calact6
job/cold-1586
job/perfvm-1587
wip/cold-1586
job/cal404-1581
wip/calact6
wip/cal404-1581
job/dname-1584
wip/dname-1584
job/merge41
wip/merge41b
wip/merge41
job/rev1573c
job/hscroll-1579
wip/rev1573c
job/rev1573b
job/rev1573
wip/fix1573
wip/hscroll2
wip/hscroll-1579
job/rev1574
wip/fix1574
wip/rev1574
job/startup-1573c
job/merge40
wip/startup-1573d
wip/startup-1573c
job/calact5
wip/remtext2
wip/merge40c
wip/merge40b
wip/merge40
job/calact4
job/startup-1573
job/calprof
wip/calprof
wip/startup-1573
job/fs1575
job/fix1570
job/calact3
job/rec1540c
wip/fix1570
job/rev1570-review
wip/calact3
job/calact2
wip/calact2
job/calcold-1560
wip/calcold-1560
wip/rec1540c
job/fix1569
wip/fix1569
job/calact-1557
wip/calact-1557
job/remtext-1568
wip/remtext-1568
job/fix1566
wip/fix1566
job/rec1540b
job/reconcile-1540
job/money2rev
wip/money2rev
job/merge39
wip/merge39
wip/reconcile-1540
job/tabswitch2
job/merge38
wip/merge38
job/autherr-1553
wip/autherr-1553
job/money-688
wip/money688rev3
wip/money688rev2
wip/money688rev
wip/money688l
wip/money688k
wip/money688j
wip/money688i
wip/money688h
wip/money688g
wip/money688f
wip/money688e
wip/money688d
wip/money688c
wip/money688b
wip/money-688
wip/tabswitch2
wip/merge37
job/merge37
job/jobnames-1538
wip/jobnames-1538
job/tabcomp-perf
job/calscript-1492
wip/tabcomp-perf
wip/calscript-1492
job/mailbody-1533
wip/mailbody-1533
job/intlfmt-1461
job/merge36
wip/intlfmt2
wip/intlfmt-1461
wip/merge36
job/merge35c
job/tagperf-1186
wip/tagrev2
wip/tagrev
wip/tagperf4
wip/tagperf2-1186
wip/tagperf-1186
wip/tagfix5
wip/tagfix3
wip/tagfast2
wip/tagfast
wip/merge35c
job/notesel-1493
wip/notesel2
wip/notesel-1493
job/merge35b
wip/merge35b
wip/m35btriage
wip/m35bratchet
wip/calsel-1491
job/calsel-1491
job/notifread-1387
job/bulkwrite-1393
wip/notifread2
wip/notifread-1387
job/slowsel-1392
wip/bulkwrite-1393
wip/bulkrev4
wip/bulkrev3
wip/bulkrev2
wip/bulkrev
wip/bulkfix4
wip/bulkfix3
wip/bulkfix2
wip/bulkfix
job/mail7-1340
job/bigscroll-1481
job/searchperf-1425
wip/mailrev4
wip/mailrev3
wip/mailrev2
wip/mailrev
wip/mail7f
wip/mail7e
wip/mail7d
wip/searchperf2
wip/searchperf-1425
wip/mail7c
wip/mail7b
wip/mail7-1340
job/photoopen-1367
job/mailsel-1449
wip/bigscroll-1481
wip/slowsel3
wip/slowsel2
wip/slowsel-1392
wip/selroot
job/journaldup
wip/journaldup8
wip/journaldup7
wip/journaldup6
wip/journaldup5
wip/journaldup4
wip/journaldup3
wip/journaldup2
wip/journaldup
wip/jdrev5
wip/jdrev4
wip/jdrev3
wip/jdrev2
wip/jdrev
wip/jdfix9
job/bignote-1349
wip/mailsel-1449
wip/bignote3
wip/bignote2
wip/bignote-1349
job/statusmark-1457
wip/statusmark-1457
wip/photoopen4
wip/photoopen3
wip/photoopen2
wip/photoopen-1367
job/authflash-1473
job/merge35
wip/authflash-1473
job/phototags-1370
wip/phototags-1370
wip/merge35
wip/m35triage
job/tick-1446
wip/tick-1446
job/restartidx-1450
job/exmove-1333
job/coldnote-1451
wip/restartidx-1450
wip/exmove-1333
wip/coldnote-1451
job/undo412-1430
wip/undo412-1430
job/calwrite-1441
job/xcancel-1443
job/calscroll-1362
wip/xcancel-1443
wip/calwrite-1441
job/xsub-1445
wip/calscroll3
wip/calscroll2
wip/calscroll-1362
wip/xsub-1445
job/linkdup-1440
wip/linkdup2
wip/linkdup-1440
wip/tabswitch4
wip/tabswitch3
wip/tabswitch-1233
wip/navrev
job/tabswitch-1233
job/mdpaste-1431
job/taskundo-1433
job/directory-1199
wip/taskundo-1433
job/remind-1432
job/nfd-1411
wip/remind-1432
wip/dirfix4
wip/dirfix3
wip/dirfix2
wip/dirfix-1199
wip/directory-1199-r
wip/directory-1199
job/readerx-1427
wip/readerx-1427
job/scrollfade-1416
job/tipphone-1439
wip/nfd-1411
job/purge-1420
job/notifrow-1414
wip/purge-1420
wip/notifrow-1414
job/slop-1385
wip/slop2
wip/slop-1385
job/tbover-1409
job/qltitle-1408
job/grantlive-1405
job/taskclick-1434
wip/tbover-1409
wip/taskclick-1434
wip/qltitle-1408
job/scrub-1422
job/hotfix35
job/ticks-1361
wip/scrub-1422
job/taskprev-1401
wip/grantlive-1405
job/ghost-1323
wip/ticks3
wip/ticks2
wip/ticks-1361
wip/taskprev-1401
job/bash3-settings
wip/ghost-1323
job/mailmorph-1368
wip/bash3-settings
job/apiaudit-1374
wip/bash3-filesphotos
job/bash3-filesphotos
job/xuser39-1402
job/bash3-money
job/mailhtml-1372
wip/mailhtml2
wip/mailhtml-1372
job/bash3-interop
job/bash3-calendar
wip/bash3-money
wip/bash3-interop
wip/bash3-calendar
wip/mailmorph2
wip/mailmorph-1368
wip/bash3-tasks
job/outro-1391
job/linkpick-1379
job/linkdel-1384
wip/linkpick2
wip/linkpick-1379
wip/linkdel3
wip/linkdel2
wip/linkdel-1384
job/mailrows-1390
wip/mailrows-1390
wip/apiaudit2
wip/apiaudit-1374
job/bash-core
wip/outro-1391
wip/bash-core2
wip/bash-core
job/bash3-notes
job/bash3-tasks
job/merge34
job/notifdel-1363
wip/merge34
wip/notifdel2
wip/notifdel-1363
job/wklink-1371
wip/wklink-1371
job/searchbar-1360
wip/searchbar2
wip/searchbar-1360
job/merge33-1122
wip/merge33c
wip/merge33b
wip/merge33-1122
job/bash-security
job/mailglass-1373
wip/bash-security2
wip/bash-security
wip/mailglass-1373
job/instaudit-1369
wip/instaudit-1369
job/tabstorm-1338
wip/tabstorm2
wip/tabstorm-1338
wip/bash-files2
wip/bash-files
job/bash-files
job/bash-money
job/editfuzz-1335
wip/bash-money
wip/moneyrev
job/tasksperf-1286
wip/tasksperf3
wip/tasksperf2
wip/tasksperf-1286
wip/editfuzz2
wip/editfuzz-1335
review/dirrev-1199
job/merge32
wip/merge32b
wip/merge32
job/bash-chrome
job/tagdnd-1187
job/bash-notes
wip/bash-notes2
wip/bash-notes
wip/bash-chrome
wip/reconcile-c1
wip/adv-c1
wip/tagdnd2-1187
wip/tagdnd-1187
job/bash-calendar
job/deploy-c1
job/editbreak-1334
job/bash-perf
wip/bash-calendar2
wip/bash-calendar
wip/bash-perf
job/hunt-20261006
job/bash-interop
job/collabloss-1197
wip/collabrev-1197
wip/collabloss5-1197
wip/collabloss4-1197
wip/collabloss3-1197
wip/collabloss2-1197
wip/collabloss-1197
wip/bash-interop
job/bash-mail
wip/bash-mail
job/vis-1293
wip/vis-1293
wip/restyle-search-r
wip/restyle-search-fix2
wip/restyle-search-fix
wip/restyle-search
job/restyle-settings
job/restyle-search
wip/restyle-settings-fix
wip/restyle-settings
job/adv31
wip/advfix-a
wip/adv31
job/bash-tasks
wip/bash-tasks
job/restyle-files
wip/restyle-files-fix
wip/restyle-files
job/fmtbar-1210
wip/fmtbar2-1210
wip/fmtbar-1210
job/perf2-1124
wip/perf2-1124
job/proflog-1204
job/merge31
wip/restyle-notes
wip/merge31
wip/proflog-1204
job/restyle-notes
job/fix-1213
wip/fix-1213
job/hide-1153
job/restyle-mailmoney
job/notestatus-1209
wip/hide-1153
wip/hiderev2-1153
wip/hiderev-1153
wip/hide5-1153
wip/hide4-1153
wip/hide3-1153
wip/hide2-1153
job/sidebarblur-1208
wip/notestatus-1209
wip/sidebarblur-1208
wip/restyle-mailmoney
job/onboard-1141
wip/onboard2-1141
wip/onboard-1141.aborted-early
wip/onboard-1141
job/adv-1202
job/segmented-1200
wip/segmented-1200
job/merge30
job/notifloop-1194
job/toastmorph-1201
wip/notifloop-1194
job/perf-1124
job/tocrail-1191
job/cards-1179
wip/cards2-1179
wip/cards-1179
wip/tocrail-1191
wip/perf-1124
wip/merge30j
job/wizchoices-1140
wip/wizchoices-1140
wip/restyle-1190
job/moneyfmt-1180
wip/moneyfmt2-1180
wip/moneyfmt-1180-r
wip/moneyfmt-1180
job/pillglass-1189
job/flags-1181
wip/flags-1181
job/restyle-1190
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/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
fixbatch-25
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
fixbatch-23
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/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
hotfix-sidebar2
job/cards-1083
job/palette-1093
job/mchrome-1084
job/e2e-a-1071
job/canvas-visual
wip/e2e-a2-1071
wip/e2e-a-1071
backup/canvas-visual-before-reconcile
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
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/staging-imap
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-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/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/theme-detail
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
job/merge-round-3-pre-rebuild
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
backup/doc-stack-r3-reset-source
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
job/dedup-375-clean
job/dedup-375-before-rebase
wip/modes-424
job/recog-417
wip/recog-417
wip/bounce-425
wip/ab-384-luna
backup/doc-stack-round3-before-rebuild
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
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set
Reference
kayg/calternal-v0#1557
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?
Evidence
The #1233 profile measured the origin/dev release server (
dbd621434d0a1133f16230cca5c6a83af0d8aed3) with trusted CDP input, Chromium, macOS platform emulation, 1440 px and light theme. Seven warm Mail→Calendar switches took 1,464.9 ms p50 and 1,813.5 ms p95 from trusted input through full paint. DESIGN §59 budgets 100 ms for a warm Tab switch.A separate marked warm trace on the 10,000-file diagnostic fixture reached full paint in about 1.75 s. The browser trace shows a 644.377 ms
FunctionCallin the Svelte runtime bundle (BIPLcumV.js) and five long tasks, max 669 ms. The measured server timing was about 0.098 ms for the observed request, so server work did not explain that warm sample. Trace:artifacts/tab-switch-1233-mail-calendar/mail-calendar-warm-trace.json; request waterfall:artifacts/tab-switch-1233-mail-calendar/mail-calendar-warm-network.jsonin the #1233 worktree.A one-sample cold trace on the reduced 100-file fixture took 2,408.8 ms input-to-full-paint. It included Svelte runtime work of 592.642 ms and main-thread tasks of 926.447 ms and 816.967 ms. Calendar API timing also showed DB-backed reads around 0.19–0.30 s. This confirms the client activation cost is a warm-path bottleneck; cold Calendar fetch cost is additional and needs a separate measured change.
Trace:
artifacts/tab-switch-1233-cold100-recheck/mail-calendar-cold-trace.json; request waterfall:artifacts/tab-switch-1233-cold100-recheck/mail-calendar-cold-network.jsonin the #1233 worktree. These are diagnostic single traces, not a candidate A/B comparison.Request
Profile Calendar Tab activation and reduce the main-thread Svelte work after a warm switch. Keep server fetch work separate so each change has a clear measured effect. Add a regression profile for Mail→Calendar and compare five interleaved A/B pairs; require p50 and p95 to improve by at least 10% without another cell's p95 regressing by more than 10%.
Starting #1557 on
job/calact-1557. The worktree is clean at0c712b98c164b6734d54f63485012bd1a11005b4, a direct child of the requested4ebeba0b8e13b06223bc2b24ee7a398a0933bda0; the newer commit only adds the weekly benchmark run artifacts. I am bringing in the #1233 profiling harness before profiling Calendar activation.The source-mapped profile setup exceeded the harness default startup limit: after 25 minutes,
/healthzstill reportedmigrating / notes-upgrade-backfills. The runner stopped cleanly before a switch was measured or a fixture snapshot was saved. I am retrying with the harness-supported 60-minute readiness limit so the 10k-file Home can settle before profiling.Baseline visual evidence is captured in the worktree at
artifacts/calact-1557/before/: 12 production screenshots covering Calendar Week and Month at 390, 820, and 1440 px in light and dark, with Chromium macOS emulation. The screenshot script verifies a real CalDAV Event is returned by the Calendar API, waits for it in each view, and confirms the update notice is absent. The script is committed ascfad824f.The 10k-file full fixture did not reach server readiness:
/healthzremainedmigrating / notes-upgrade-backfillsafter 50 minutes of seeded-server time (52 minutes in theperf-runcall). No Calendar sample was measured. I am stopping this attempt and will keep the 10k Files scale while using the harness smoke seed for unrelated Notes, Tasks, and Money data, identically for source profiling and both sides of the A/B comparison.The smoke-level startup attempt did not reach Calendar profiling.
/healthzstayed atmigrating / prepare-data-directory; after the harness's 5-minuteTAB_SWITCH_START_TIMEOUT_MS,startRemoteServerfailed with:native media command failed; check runtime and service limits for launcher failures cause=Launch. I stopped the runner and server and verified the perf lock is free. I am checking the server startup constraint and will retry with a longer start timeout.Operational note: a read-only disk diagnostic (
duplus file count) ran outsideperf-runand overlapped the lock held by jobrec1540b-a1. It scanned 486 files (26 MB under the benchmarkdatadirectory) and took about 11 seconds. It may have added light I/O to that run. I stopped further perf-VM checks and will hold the lock for all next diagnostics and benchmarks.Finding for #1557: the imported Tab-switch harness uses /mnt/hdd/targets/jobs/tabswitch2/fixture-snapshot for perf-VM snapshots. Creating this issue's 10,000-File fixture there could replace another job's saved Home. I added TAB_SWITCH_FIXTURE_SNAPSHOT_DIR so this job can use /mnt/hdd/targets/jobs/calact-1557/fixture-snapshot while preserving existing defaults. Focused check: bun test bench/tab-switch.test.mjs — 24 pass, 0 fail.
Source-map profile finding (local fallback while the perf VM was held):
GridColumn.svelte; measured self frames includeTimeGrid.sveltemeasure (about 101 ms in nativescrollToand 62 ms inclientWidth),ModeHeader.sveltemeasure/offset (about 99 ms), then smallerGridColumn.svelteattachment andcalendar/layout.tsitem-slot work.Fix finding: the first
TimeGrid.measure()set--colwand calledscrollTo, then its immediately scheduled initialization frame set the same anchor again withscrollLeft. The first scroll write forced layout inside the activation flush. I now skip that write until the grid is initialized; resize and later navigation paths still use the existing scroll behavior. The focused component test checks that the grid reachesreadywith its measured track and no initialscrollTocall.bunx vitest run src/lib/calendar/TimeGrid.svelte.test.ts --maxWorkers=2passed (20 tests). The pinned production build completed successfully. The perf VM became busy again before the paired run; I am staging its candidate and fixture locally and will resume measurements whenperf-run statusis free.The web check found stale exact TimeGrid pins after the measured change. I compared the 38 live TimeGrid findings with both perf ledgers; all 38 symbols still exist. I refreshed only their changed syntax hashes in
contracts/perf/exceptions.jsonandcontracts/perf/adoption-1058.json. Exception counts, limits andcontracts/perf/ratchet.jsonare unchanged.bun run checkthen passed, and the full requested web test command passed: 318 files and 2,317 tests.#1557 performance run finding: the first perf VM attempt passed both HDD qualification probes, restored the settled fixture, and reached
/healthzstateokin 42.6 s. Chromium then returnedTarget crashedfrom CDP whilewaitForPhotoIndexchecked fixture readiness, before the timing loop started. This attempt produced no switch samples and is not counted. The server and browser processes were cleaned up. The VM has since been reserved by anotherrec1540b-b2-repeatrun; I will retry whenperf-run statusreports it free. Head:1c6b0148478b5547f89b6bc5b60c1532ee89dfb5.#1557 performance run finding: the single retry reproduced the same Chromium CDP
Target crashedduringwaitForPhotoIndexat the Photos readinesspage.evaluate, after the snapshot reached/healthzstateokand both HDD qualification probes passed. It failed before the timing loop, so both attempts have zero switch samples and no A/B result. I will not retry the A/B loop again. A minimal Chromiumdata:page probe is queued behind the current VM reservation throughperf-runto distinguish browser instability from the fixture readiness path. Head:1c6b0148478b5547f89b6bc5b60c1532ee89dfb5.#1557 diagnostic: Chromium
153.0.8010.12launched successfully underperf-run; adata:text/html,okpage completed a CDPRuntime.evaluateand returnedok. This rules out a general browser-launch/CDP failure. The reproducible crash is limited to the benchmark’s authenticated readiness page/API path atwaitForPhotoIndex; its exact cause remains unknown. No A/B retry was made, so the relative latency acceptance rule remains unmeasured. Head:1c6b0148478b5547f89b6bc5b60c1532ee89dfb5.calact-1557 report
Built
The Calendar
TimeGrid.measure()initial sizing path no longer writes a duplicate instantscrollTo. Its already scheduled initialization frame sets the same final horizontal anchor. Later resize and navigation measurements keep their existing scroll behavior. This removes one DOM scroll write per initial Week/Day grid mount, an O(1) change. The UI and Calendar view are unchanged.A source-mapped production trace showed a 596.8 ms Svelte
FunctionCallin thedom/task.js→batch.flush→ keyed each update path. The largest application/native self-time frames wereTimeGrid.measure()→ nativescrollTo(100.9 ms),ModeHeader.offset()fromModeHeader.measure()(99.1 ms), andTimeGrid.measure()’sclientWidthread (61.6 ms). Smaller work included CalendarGridColumnattachment,calendar/attachments.ts, andcalendar/layout.ts.The reported issue baseline was 1,465/1,814 ms p50/p95. The required perf-VM A/B did not reach its sample loop. Both attempts restored the settled fixture, reached
/healthzstateok(42.6 s and 43.6 s), and passed the two HDD qualification probes. Chromium then returned CDPTarget crashedfromwaitForPhotoIndexat the Photos readinesspage.evaluate. Neither attempt recorded a switch sample. A separate locked probe passed on Chromium 153.0.8010.12 with adata:page and CDP evaluation, so the exact failure is limited to the authenticated readiness page/API path; its cause is unknown. No more A/B retries were run.A/B acceptance: unmeasured. The required 5 interleaved baseline/candidate samples for each of Mail→Calendar, Files→Calendar, Calendar→Files and Notes→Tasks are not available. This report does not claim the ≥10% Mail→Calendar p50/p95 improvement or the ≤10% other-cell p95 regression rule passed. The §59 100 ms Warm Tab switch budget also remains unverified. Fixture plan: 10,000 Files, 366 Daily Notes, 10,980 Log entries, 30 recurring Events, 20 Notes and 20 Tasks; 1440 px, light, warm, Chromium. VM load was recorded inside
perf-run; the two failed attempts started at load averages 2.66/2.52/2.41 and 3.08/2.68/2.59.The before/after production screenshots below use a real CalDAV-backed Event, Chromium with macOS platform emulation, matching web/server build IDs, both themes and all required widths. Week and Month each have phone, tablet and desktop captures. The reviewer should judge the visuals.
Files and commits
packages/ui/src/components/calendar/TimeGrid.svelte— initial scroll-write optimization and invariant comment.apps/web/src/lib/calendar/TimeGrid.svelte.test.ts— regression test for the initial measurement frame.bench/tab-switch.mjs,bench/tab-switch.test.mjs,bench/cdp-input.mjs,bench/cdp-input.test.mjs— focused #1233 comparison and trusted-input harness.apps/web/e2e/harness.mjs,apps/web/e2e/harness.test.mjs,apps/web/e2e/calendar-tab-switch-1557.mjs— fixture isolation, platform emulation regression and screenshot capture.contracts/perf/exceptions.json,contracts/perf/adoption-1058.json— refreshed exact TimeGrid source pins; exception counts and limits are unchanged;contracts/perf/ratchet.jsondid not change.Commits:
3e45f6f89,cfad824f6,b4d56f816,ab1193f1f,1c6b01484. Head:1c6b0148478b5547f89b6bc5b60c1532ee89dfb5.Gates (verbatim)
cd apps/web && bun run check:cd apps/web && bun run test -- --maxWorkers=2:Rust gates were not run because no Rust crate changed.
cargo cleancompleted andapps/web/buildplusapps/web/.svelte-kitwere removed.Gaps and decisions
waitForPhotoIndexreadiness path, then run the prescribed perf-VM A/B matrix. Its result must establish the fixed acceptance rule.scrollTobecause the next initialization frame already writes the equivalent anchor; retain later resize/navigation writes. No visual design choice outside DESIGN §59 was needed.origin/dev0c712b98c164b6734d54f63485012bd1a11005b4, while the job prompt named4ebeba0b8. This was disclosed at job start; the A/B comparison build and prebuilt API server were pinned to4ebeba0b8e13b06223bc2b24ee7a398a0933bda0. The required one-time merge oforigin/devwas already up to date.Starting #1557 on branch
job/calact2at base1c6b0148478b5547f89b6bc5b60c1532ee89dfb5. I will first reproduce the perf VM renderer crash with a one-pair smoke, then reduce Calendar activation layout work and rerun the requested trace, A/B profile, screenshots, and web gates.Finding for #1557:
waitForPhotoIndexfetches/api/v1/photos/timeline/bucketsinside the Chromium renderer and callsresponse.json()on the full day-bucket list, then keeps onlytotal. The API returns adaysrow for every captured day (for 100k Photos, the route comment says this can be a few thousand rows). This makes renderer-side response parsing a concrete crash candidate, but does not prove it caused the perf VM crash. I am moving the readiness poll to authenticatedBrowserContext.requestand will verify with a one-pair smoke.Screenshot finding: the baseline set completed with 18 captures, but the candidate set stopped at its first view because the candidate production build ID differs from the pinned
4ebeba0b8server. The app showed “Update available”, and the capture assertion failed. I am updating the screenshot context to report the selected asset build ID from/api/v1/version, matching the existing paired-benchmark behavior; this only affects the review harness.The post-merge
bun run checkfound a stale exact performance exception after the ModeHeader ResizeObserver scope changed:layout.observer-purposeinpackages/ui/src/components/ModeHeader.sveltereported the prior symbol<module>:45618a0c0c0ddf2fas unused or changed. I am refreshing the exact live entry and will not increase the committed ratchet.The corrected
bun run checkfound the paired adoption checkpoint also retained the old identities:contracts/perf/adoption-1058.jsonreported “adoption checkpoint differs from its exact live ledger entry” for the same four ModeHeader observers. I am refreshing those four checkpoint identities to the live entries; counts and the ratchet remain unchanged.The perf-lint check then found another stale exact pin in the same edited module:
render.boundforpackages/ui/src/components/ModeHeader.svelte#each(old scope473edc9628bc3230). I am checking all live exceptions in both changed UI modules at once and will refresh only identities that still have matching live findings.Progress: the fixed one-pair smoke has not reached
waitForPhotoIndexyet. At 2026-10-11 03:56 UTC, the perf VM's public/healthzstill reportedstate=migrating, phasenotes-upgrade-backfills, after the seeded server had been up for about 9 minutes. Chromium remained alive at ~100 MB RSS with no renderer crash. I am letting startup continue within the requested 45-minute perf-VM troubleshooting window; if it does not advance, I will use the local HDD profile and label those measurements.Finding: the perf-VM smoke exited before
waitForPhotoIndexafterwaitForStartupFilesReadytimed out at 1,500,000 ms./healthzstayed atmigrating / notes-upgrade-backfills; Chromium stayed alive near 100 MB RSS, so this attempt did not reproduce the renderer crash. The smoke seed was larger than needed for a one-pair readiness check: one year of daily Notes with 30 log entries per day (924 files total in the test Home). I am reducing only the smoke fixture to one day and a few entries, then I will use the local fallback if the perf VM remains unavailable at the 45-minute limit. Full A/B fixture settings stay unchanged.Follow-up:
e602bf5d4now keeps only the--smokefixture to one Journal day, two Log entries, five Notes and two Tasks; the full A/B fixture is unchanged. The seed generator completed for the reduced data.bun test bench/tab-switch.test.mjspassed 30 tests andnode --checkplusgit diff --checkpassed. The perf-VM lock is held by another job through its declared slot, which ends after this run's 45-minute troubleshooting window, so I will use the local profile at the cutoff.One-pair smoke passed on the local profile after the perf-VM window elapsed. With the reduced one-day fixture, startup reached
/healthzstateok, the request-context Photos wait saw all 100 seeded Photos, and one warm Photos→Calendar switch completed without a Chromium crash (741.6 ms input-to-full-paint; smoke-only, not an A/B cell). The local profile has no HDD emulation; the upcoming comparison will be labeled local and include its host load.Local A/B matrix completed: 5 interleaved samples per requested cell, Chromium, 1440 px, light, warm, 10,000 Files. The one-day smoke fixture supplied 1 Journal, 2 Log entries, 5 Notes and 2 Tasks. This ran locally without HDD emulation; load average before setup was 17.83/22.60/20.76 (1/5/15 minutes).
Input-to-full-paint p50/p95 ms, baseline → candidate:
The required Mail→Calendar improvement and no-regression thresholds did not pass in this local run. I am collecting the requested source-mapped candidate trace next; the high host load limits these comparison numbers.
Trace attempt did not capture a trace:
--trace-onlyused the normal Chromium+WebKit engine list and failed when the profiler requested a CDP session from WebKit (CDP session is only available in Chromium). I am retrying the trace with Chromium explicitly selected, 1440 px/light only, and the--tracecapture flag.Trace finding (#1557): after the TimeGrid and ModeHeader changes, the Calendar route still synchronously calls
getBoundingClientRect()twice and readsroute-content.clientHeightfrom its activation$effect(apps/web/src/routes/calendar/[view]/[date]/+page.svelte:2112-2123). The source-mapped candidate trace attributes about 20.55 ms of sampled self time to thegetBoundingClientRectpath. I am moving this measurement to ResizeObserver delivery so geometry reads happen after layout and the height comes from the observer entry.Implementation update: the route geometry reads are coalesced into one requestAnimationFrame after Tab activation, then all reads happen together before the unchanged height write. I kept the existing TimeGrid ResizeObserver entry as the source of its width and avoided adding another route observer. The original trace finding remains the reason for the change; the final source no longer reads this geometry from the activation effect.
The final A/B invocation exited before sampling: I pointed
--comparison-buildinside the runner's local profile, and fixture reset removed that directory before the build copy. No matrix samples were recorded. I am rebuilding the4ebeba0b8baseline outside the profile and will rerun the matrix.The final source-mapped trace removed the Calendar route's synchronous geometry path; the prior
TimeGrid.clientWidthand largeModeHeaderread are also absent. It still sampled 35.57 ms inget offsetLeft, called fromapps/web/src/lib/actions/measuredCapsule.svelte.ts:58duringSegmentedControlselection. This helper runs on Tab activation, so I am moving its reads to the existing ResizeObserver delivery and adding a regression test.Source-mapped trace follow-up: after the earlier Calendar and shared-header changes,
TimeGrid.measure()still spent 9.81 ms in a resizescrollToimmediately after writing--colw. I deferred that anchor correction to the next animation frame and cancel it when a newer scroll arrives. Added a regression test; the focused TimeGrid file passed (21 tests),bun run checkpassed with 0 Svelte errors/warnings andperf-lint: PASS; 0 violations; 22128 scoped exceptions, and the full web suite passed (318 files, 2320 tests). Only exact hashes on existing TimeGrid perf entries changed; ratchet counts did not change.Final source-mapped trace after
cb8f01195shows the resizeTimeGrid.measure()scroll correction is no longer a costly activation frame (the remaining sampledscrollTois 0.16 ms from date navigation). The trace still attributes 25.57 ms ofgetBoundingClientRectself time toapps/web/src/routes/+layout.svelte:612, where the bottom chrome's ResizeObserver and MutationObserver callbacks read the tray and write--tray-shiftsynchronously. I am coalescing that measurement into the next animation frame, then I will retrace once and report any remaining layout work.Final local evidence on
919f4b5a3:/healthzstateok; the renderer stayed alive. This host had load average 26.84 before the smoke, so its single latency sample is harness evidence only.TimeGrid.measure()resizeclientWidth/scrollToframe or the heavyModeHeader.offset()frame.scrollTonow maps to ordinaryscrollToDate(11.28 ms). The bottom chromegetBoundingClientRectsample fell from 25.57 ms to 0.16 ms after it moved to a coalesced animation frame. The largest Svelteeach.jsFunctionCall was 179 ms; the trace still shows 79.08 ms in TabBar's existing capsulereadSizepath under this host load.[17.41, 22.58, 21.26]; there was no HDD emulation. Mail→CalendarInput→2 frameswas baseline 545.8/599.3 ms p50/p95 and candidate 1259.7/2291.6 ms, so the requested improvement failed. Files→Calendar p95 also regressed 36.5%; Notes→Tasks improved and Calendar→Files improved onInput→2 frames. I am reporting the measured miss; I did not raise the perf ratchet.Final report — #1557
Branch:
job/calact2Final head:
98677b92e851ae8761fc97b4dbb5563013f41443Base:
1c6b01484;origin/devwas fetched and merged once and was already up to date. The final commit only cleans the app-shell module comment; the measured implementation head was919f4b5a32ba306972554f3363b917fcede3b733.Built
Hot-path work is bounded: one coalesced measurement per affected component/frame, with no per-row observers or repeated activation reads. No visible controls or styles were added.
Files
apps/web/e2e/calendar-tab-switch-1557.mjs,apps/web/e2e/harness.mjs,apps/web/src/lib/actions/measuredCapsule.svelte.ts,apps/web/src/lib/calendar/TimeGrid.svelte.test.ts,apps/web/src/lib/components/SegmentedControl.svelte.test.ts,apps/web/src/lib/modeHeader.svelte.test.ts,apps/web/src/routes/+layout.svelte,apps/web/src/routes/calendar/[view]/[date]/+page.svelte,bench/tab-switch-seed.py,bench/tab-switch.mjs,bench/tab-switch.test.mjs,contracts/perf/adoption-1058.json,contracts/perf/exceptions.json,packages/ui/src/components/ModeHeader.svelte,packages/ui/src/components/calendar/TimeGrid.svelte.Trace
TimeGrid.measure()clientWidth/scroll correction andModeHeader.offset()activation paths no longer appear as heavy frames. CalendarscrollToDateis 11.28 ms in the final trace.getBoundingClientRectfell from 25.57 ms in the earlier capture to 0.16 ms after deferral.TabBar.svelte:184getBoundingClientRectat 79.08 ms and the measured capsuleoffsetLeftat 9.49 ms. The TabBar sample is a remaining layout frame for follow-up; this report does not claim that all layout work is gone.each.jsFunctionCall: 179.01 ms. The earlier 597 ms Svelte-flush figure is a different trace aggregation, so this run does not support an apples-to-apples flush reduction percentage.A/B performance
Five interleaved samples per direction at 1440 px, light theme, warm switch; base
4ebeba0b8e13b06223bc2b24ee7a398a0933bda0, candidate919f4b5a32ba306972554f3363b917fcede3b733. The perf VM remained inmigrating/notes-upgrade-backfillsfor 25 minutes, so the run used the local build host without HDD emulation. Load average before setup was17.41, 22.58, 21.26. Fixture: 10,000 Files, 5 Notes, 2 Tasks, 30 recurring Events, no Photos.Input-to-two-frames p50/p95 in milliseconds (base → candidate):
Full-paint p50/p95 in milliseconds (base → candidate):
Acceptance missed. Mail → Calendar did not improve; Files → Calendar p95 regressed 36.5%. Candidate Mail runs also had more requests than baseline in some samples, including an 18-request, 4.7 MB outlier. The high host load and request differences limit attribution; the numbers are reported without adjustment.
Gates
Web gates ran on the implementation head above. The final head adds only the module-comment cleanup described above.
cd apps/web && bun run check:cd apps/web && bun run test -- --maxWorkers=2:cargo fmt,cargo clippy, andcargo testwere not run because this job changed no Rust crates or server routes/contracts.git diff --checkpassed.scripts/perf-lint --checkreportedperf-lint: PASS; 0 violations; 22128 scoped exceptions.UX gaps closed / left
:focus-visible=falsefor the focused controls.Decisions
The design specifies the instant-interaction goal but not this measurement schedule. The implementation uses ResizeObserver entries for settled geometry and one coalesced animation frame for writes that depend on route or capsule changes. It preserves the existing visual and interaction contract. The local A/B fallback followed the issue instruction after the perf VM did not become usable within the time box.
Screenshots
All screenshots use macOS platform emulation in Chromium. Links point to the original full-resolution PNG attachments.
Baseline
Final
Interaction captures (1440 px)
Starting round 3 on
job/calact3at98677b92e851ae8761fc97b4dbb5563013f41443, continuingjob/calact2. The measurement baseline is4ebeba0b8e13b06223bc2b24ee7a398a0933bda0. Round 2's A/B ran on the loaded build host (load about 20), so I will not use those measurements as evidence.Before measurement, the acceptance rule is: accept only if Mail→Calendar warm input-to-full-paint p50 improves by at least 10% against the baseline, and no p95 for any measured cell at either timing boundary (input-to-two-frames or full paint) regresses by more than 10%. I will capture five interleaved pairs at 1440 px in light theme, with warm Mail→Calendar, Files→Calendar and Calendar→Files switches, plus one Mail→Calendar Chrome trace per side. I interpret the p50 criterion against full paint because it measures when the switched view is visibly complete; input-to-two-frames remains a diagnostic boundary.
The initial focused Vitest command could not load
apps/web/vite.config.ts: this worktree had nonode_modules, sovitest/configand@sveltejs/kit/vitewere unresolved.bun --versionis 1.4.2; I am installing dependencies from the committed lockfile with frozen resolution before retrying. No source or lockfile was changed by the failed start.The focused test now passes:
bunx vitest run src/lib/tray.svelte.test.ts --maxWorkers=2→ 1 file and 28 tests passed.bun run check; echo exit=$?found one stale exact perf-lint pin after the TabBar edit:perf-lint: INVALID: ('layout.observer-purpose', 'packages/ui/src/components/TabBar.svelte', '<module>:dd9d7691a28135ce'): unused or changed exception. The Svelte check completed with 0 errors and 0 warnings. I am usingscripts/perf-lint --adopt-7cto refresh the exact identity;contracts/perf/ratchet.jsonwill not change.scripts/perf-lint --adopt-7crefreshed the changed TabBar identities, but it also proposed unrelated Money debt rows and swapped unrelated ModeHeader entries. I restored those unrelated ledger changes and kept only the five TabBar hash updates in each perf ledger.contracts/perf/ratchet.jsonis unchanged.scripts/perf-lint --checknow exits 0.Implementation slice committed:
5230953fc(perf(ui): defer Tab Bar sizing to ResizeObserver). TabBar now applies pane dimensions from ResizeObserver entries in one coalesced frame and keeps the last painted stage size for a reversed morph; it has nogetBoundingClientRect,offsetWidthoroffsetHeightreads. The focused regression test passed:bunx vitest run src/lib/tray.svelte.test.ts --maxWorkers=2→ 1 file, 28 tests passed.bun run check; echo exit=$?completed withsvelte-check found 0 errors and 0 warningsandexit=0. Only the exact TabBar hashes changed in the perf ledgers;contracts/perf/ratchet.jsonis unchanged. I am checking the perf-VM queue before staging the A/B run.Visual evidence: the production screenshot harness passed and saved 18 macOS-emulated screenshots under
artifacts/calact3/after/. They cover Calendar Week, Calendar Month and Files at 390, 820 and 1440 px in light and dark. The harness waited for a real CalDAV Event in Calendar, checked the Files API/empty state, and confirmed there was no update notice. These are captures for review; I made no visual-quality claim.Finding for #1557: the stage observer initially used
contentRect, but the shortcut stage gets the shared 1 px glass border. That value is 2 px smaller than the oldgetBoundingClientRect()result used to preserve the in-flight outer size, so reversing a shortcut morph could start slightly undersized. I am updating the observer to preferborderBoxSizeand keepcontentRectas the fallback.Resolved the border-box sizing finding for #1557 in
5eece8170. The observer now prefersborderBoxSizefor the pane and stage, withcontentRectfallback. I extended the focused test to inject a 100×40 outer stage box with a 98×38 content box, then verify activation preserves100px × 40pxwithout callinggetBoundingClientRect().bunx vitest run src/lib/tray.svelte.test.ts --maxWorkers=2passed: 1 file, 28 tests.Visual evidence attached: 18 macOS-emulated Chromium captures at phone (390 px), tablet (820 px), and desktop (1440 px), in light and dark.
Calendar Week
Calendar Month
Files
Finding for #1557: the first full
bun run checkfound one TypeScript error in the synthetic ResizeObserverEntry cast atapps/web/src/lib/tray.svelte.test.ts:503;svelte-checkreported missingcontentBoxSizeanddevicePixelContentBoxSize. Fixed the test fixture with an explicitunknownbridge inbd45ee005. The focused test passes (28 tests); the full check is running again.Perf VM wait update for #1557:
perf-run statusat 09:40 CEST still reportscalternal startup1573-baseline-repro-coldholding the lock since 09:22 CEST (expected 45 minutes). The smoke-profile bundle is prepared. I am waiting for the lock and will not take timing measurements on the build host.Finding for #1557: the macOS-emulated post-shortcut pointer-close capture reported one
:focus-visibletarget after the shortcut card returned to the Calendar Tab. Evidence: the temporary action capture failed its explicit:focus-visiblecount assertion after clicking.shortcut-card-close.TabBar.svelterestores the saved shortcut trigger with direct.focus()in theshortcut-returnpath. I am replacing that code-driven restore with the existingfocusQuietlyhelper and adding a focused regression test.Resolved the pointer-close focus-ring finding in
5193a67a3. Shortcut return now uses the sharedfocusQuietlyhelper for both the saved trigger and the active Tab fallback. Added a tray regression test that checks the focus call carriesfocusVisible: false.bunx vitest run src/lib/tray.svelte.test.ts --maxWorkers=2passed: 1 file, 29 tests. I will recapture the post-close screenshots after rebuilding the production assets.Updated action captures use the production build at
5193a67a36eb3ea9138f2c2126346017ad9fd414with macOS platform emulation in Chromium. The runner asserts no:focus-visiblering after pointer tab activation, the?shortcut opens, and pointer close returns focus. All six 390/820/1440 px light/dark captures passed and include the loaded real Calendar Event.Perf VM setup finding (10:39 CEST):
perf-run calternal calact3-ab 30acquired the lock at 10:20:26 with under-lock load average1.51 2.94 3.32. HDD qualification passed at both tested depths,/healthzreturns HTTP 200, and the--smokeseed wrote its 100-file Home. The runner has remained atGenerating and indexing seeded Homefor 19 minutes and has emitted no measured switch samples yet. The single bounded A/B session is still running; no acceptance decision is available.Perf setup diagnosis: the Tab-switch script selected its October 1 fallback server at
/mnt/hdd/targets/release-shared/release/calternal-server(SHA-2562f3567d91c34839851247bc0acbc25a56aaacd14dca269b8f0342ddf83447ed9). The shared server selected by/mnt/hdd/targets/shared-server/CURRENTis the 4eb build at/mnt/hdd/targets/shared-server/4ebeba0b8/calternal-server-release(SHA-25658ca0cefe0ffe215a31f0ec2844a4c2979806fd2cc4574925959c61be0d84e99). The running fallback responds to/healthzastext/plainokand returns 404 for/api/v1/version; the benchmark's startup probe expects the JSON phase API. No switch cell ran. I will stop this setup attempt and restart the same 5-pair profile using the prebuilt 4eb shared server, without compiling on the perf VM.Final report
Head:
226b40228d982449292b0957b13e1d2c921c825aChange
Removed the Tab Bar activation-time geometry read. The existing
ResizeObservernow watches the pane and animated stage, preserves the observed border-box size, and coalesces updates into one animation frame. Restoring focus after closing the shortcut card uses the shared quiet-focus helper.Files changed:
packages/ui/src/components/TabBar.svelteapps/web/src/lib/tray.svelte.test.tscontracts/perf/adoption-1058.jsoncontracts/perf/exceptions.jsonThe performance pins were refreshed only for the changed Tab Bar code. No ratchet threshold changed.
Perf VM A/B
The decision rule posted before the run was: accept only if warm Mail→Calendar input-to-fully-painted p50 improves by at least 10%, and no cell’s p95 regresses by more than 10%.
Run: perf VM through
perf-run, five interleaved pairs, Chromium, macOS platform emulation, 1440 px, light, warm,--smokeHome seed with the Calendar fixture retained. Baseline was4ebeba0b8e13b06223bc2b24ee7a398a0933bda0; candidate was this head. Under-lock starting load average was0.35 0.12 0.80. Both used the shared prebuilt server from 4eb (58ca0cefe0ffe215a31f0ec2844a4c2979806fd2cc4574925959c61be0d84e99).All values are milliseconds; each pair is p50/p95.
Decision: fail; no further tuning, as instructed. Mail→Calendar fully-painted p50 regressed 20.3%; its fully-painted p95 regressed 125.3%, and its two-frame p95 regressed 182.6%. Files→Calendar also regressed in p50 and p95. Calendar→Files fully-painted p95 regressed 2.1%.
Raw traces:
Trace summary, sampled self time: baseline top entries were
Pe(49.40 ms),scrollTo(44.00 ms), and an anonymous frame (10.56 ms); candidate top entries weremt(98.90 ms), garbage collection (38.16 ms), andw(22.58 ms). Longest sampled RunTask values were 138.86 ms baseline and 163.75 ms candidate. The top JavaScript frames are minified; these samples do not establish cause.Gates
bun run check; echo exit=$?bun run test -- --maxWorkers=2Focused Tab Bar tests: 29 passed.
scripts/perf-lint --adopt-7cpassed with 0 violations.UX gaps and decisions
Closed: activation no longer performs synchronous geometry reads; observed sizing retains the border box; shortcut-card close restores focus without showing a ring. Regression tests cover these behaviors. Screenshot evidence attached earlier in this issue covers real Calendar and Files data at phone (390 px), tablet (820 px), and desktop (1440 px), in light and dark, with macOS platform emulation. It includes mouse, shortcut-open, and close-click states.
Left: the requested performance acceptance failed. I made no tuning changes after the run. No other UX gap remains known from this change.
DESIGN did not specify Tab Bar measurement details. I reused the existing observer and frame scheduling, used
borderBoxSizewith the existing content-rectangle fallback, and kept the chosen focus behavior in the sharedfocusQuietlyhelper.No Rust crates changed. No push, merge, or deploy was performed.
Per the shared performance rule, I filed the measured warm-switch regression as follow-up #1576 with the per-cell values and raw trace links. No tuning was done after the failed acceptance result.
Starting investigation in worktree
job/calprof, based onorigin/devat0c712b98c164b6734d54f63485012bd1a11005b4. I am reading the #549 Tab-switch profile and trace support to capture the requested three warm Mail→Calendar samples with source locations. I will make no product changes; any profiling-only helper will stay isolated and be removed or committed only if useful for repeatable investigation.Finding:
bench/tab-switch.mjsalready records CDP JavaScript sampling, but its trace-only filter and trace start predicate hard-code Photos→Calendar, and it writes one fixed trace filename. That makes the requested three warm Mail→Calendar traces impossible without a small benchmark-only extension. The profiling build is generated with CLI-only--sourcemap --minify=false; it does not change Vite or production build configuration.Run finding (2026-10-11): the smoke Home indexed all 100 Photos and the CalDAV fixture exposed 30 daily recurring Events across 366 days. The server read probe passed. The first browser profile attempt then timed out after 30 seconds on the fixture-only PUT /api/v1/appearance, before any Tab-switch sample or trace was captured. The profile context performs that theme setup outside the perf-run lock; I am serializing this setup write under the lock and will retry. This timeout is setup evidence, not activation timing.
#1557 — Calendar activation attribution
Work and method
This was an investigation only. I added an opt-in trace-only profiling path to
bench/tab-switch.mjs, captured three Chrome CPU-sampling traces, and removed two invalid route-identity fields after finding they pointed at the always-present pull-status pill. No product code changed.The web build used source maps and disabled minification only for this run:
The app and server sources were the 4eb baseline. Each trace is a warm Mail→Calendar switch at 1440 px, light theme, smoke seed, with the Calendar fixture retained. The trace window starts at the trusted pointer event and ends after the benchmark’s fully-painted condition. Chrome’s CPU sampler was enabled.
The server VM load while locked was 3.04–3.28. The browser ran on the build host, whose one-minute load was 12.04–14.32. The unminified build, active sampler, and loaded browser host make these source-attribution timings unsuitable as a replacement for the production baseline.
A first attempt timed out on the fixture-only appearance write before a Tab sample. I moved that setup write under the VM lock and reran successfully. The timeout was setup-only.
Activation timings
The reported 4eb production baseline remains 546.1 / 563.7 ms input→two frames and 842.5 / 862.6 ms input→fully painted. Do not compare those values directly with this profiling build.
Source attribution
The CPU profile maps sampled JS to the nearest Svelte source frame. Svelte does not emit separate mount/effect duration events here, so the lifecycle column uses the sampled function and its source call sites. The costs below are sampled self time; they are not additive with browser layout events.
packages/ui/src/components/ModeHeader.svelte:269 offsetpage/titlechanges run the ModeHeader effect (:357–364); route mutations also schedule title measurement fromonMount(:332–341). The path reads the active scroller offset. This was the most repeatable Svelte JS cost.packages/ui/src/components/calendar/TimeGrid.svelte:543 centreYsetZoomcallscentreY(:581–585) when thehourHeighteffect sees a changed saved preference (:591–596). The high cost occurred in one trace only.packages/ui/src/components/calendar/GridColumn.sveltepackages/ui/src/routes/calendar/[view]/[date]/+page.svelteOther sampled native self time included
scrollTo(252–332 ms),getBoundingClientRect(207–608 ms), andclientWidth(40–68 ms). Native leaf samples do not preserve a single app call site, and these values overlap style/layout work; do not add them to component costs.Style, layout, forced reflow, GC and network
UpdateLayoutTreeTabBar.svelte:220(deferred capsule measure),TimeGrid.svelte:892(gridResizeObservermeasure),AppToaster.svelte:142(toast dock update), and Sveltedom/task.js:28(runtime flush).LayoutTimeGrid.svelte:892(34.6–72.5 ms per event). Runtime flushes also initiated layout events.TabBarstyle workUpdateLayoutTree: 102.5, 195.5, 106.7 msTabBar.svelte:220callsmeasure()andreadSize()(:184–186) after Tab state changes.TimeGridstyle/layout workUpdateLayoutTree: 68.6–147.6 ms;Layout: 34.6–72.5 msTimeGrid.svelte:892runsmeasure(), which reads the scrollport width and computed styles, then may write--colwand scroll position.AppToasterstyle workUpdateLayoutTree: 67.6–91.6 msAppToaster.svelte:142measures visible toast boxes at:150and:154.The trace has no distinct forced-reflow event with a direct source stack. It does show style/layout events inside mapped
TabBar,TimeGridand toaster callbacks. Treat these as layout work with those initiators, not as proof that every event was a synchronous forced reflow. The analyzer mapped 35–39 of 69–74 style/layout events to an enclosingFunctionCall; the remaining events did not retain a useful caller stack. Event durations can overlap and must not be summed with CPU samples.The traces contain 23–27
DrawFrameevents before the fully-painted marker. Median frame intervals were 89.8–92.7 ms, with p95 intervals of 144.4–309.7 ms. The first two compositor frames arrived at 54/138 ms, 172/274 ms, and 71/164 ms. Those frames do not mean Calendar content was ready: the target-ready marker took 1452–1749 ms in this loaded profiling run.Two API requests were reported per run, 908 transferred bytes in the benchmark report, and zero server read bytes. Calendar preference response-header wait was 38.6–50.1 ms; its
Server-Timing: totalwas 0.111–0.131 ms. This does not show a server-side activation bottleneck. Response events can appear later on the main-thread trace than the network timing’sreceiveHeadersEnd, so I used the network timing field for header wait.Route lifecycle and DESIGN §59
Calendar unmounts on a Tab switch and gets a new route instance when opened again.
apps/web/src/routes/+layout.svelte:1431–1471renders one active route child through{@render children()}; the Calendar route is not held beside Mail. The memory profile after GC measured 4,033 route descendants on Calendar and 18 on Mail. Calendar→Mail also reduced total DOM nodes by 14,983 and listeners by 1,446. Shared JS chunks and application data caches may remain loaded; this is the route DOM/component instance being removed.DESIGN §59 allows a bounded LRU view snapshot, not a hidden mounted Calendar route:
After GC, the smoke Calendar state used 23,687,704 bytes of JS heap, 17,305 DOM nodes, 1,934 listeners and 4,033 route descendants. Mail used 12,289,880 bytes, 2,322 DOM nodes, 488 listeners and 18 route descendants. The full mounted Calendar delta was 11,397,824 heap bytes, 14,983 DOM nodes, 1,446 listeners and 4,015 route descendants. This is a measured full-view retention cost, not the size of a row/cursor/selection/scroll snapshot. DESIGN §59 does not set a numeric snapshot byte limit; measure the snapshot before choosing one.
Why rounds 2–3 regressed
The old round-3 trace pair is attached to #1576 and remains minified. In the 2.5-second window after pointerdown, its candidate had 63
RequestAnimationFrameevents and 60FireAnimationFrameevents versus 35 and 35 for baseline; it had 19 versus 15 compositorDrawFrameevents. The candidate’s first two compositor frames were not later (56/136 ms versus 72/150 ms). The candidate trace had four longRunTaskevents with a maximum of 148.1 ms versus three with a maximum of 114.1 ms. These traces show more post-input frame work, but they do not contain a Calendar-ready/settled marker and cannot prove that a specific frame caused the p95 regression.The source diff at candidate
226b402gives the strongest explanation for the median regression.TimeGridstopped measuring the initial width immediately inonMount; it waits forResizeObserver(TimeGrid.svelte:930–934), then schedulesscheduleInitialPosition()for another animation frame (:811–828) before settinginitialized/.tg.ready. The benchmark’s fully-painted condition waits for.tg.ready. This inserts a frame gate on the measured Calendar-ready path. It is consistent with the +43.4 ms two-frame p50 and +170.9 ms fully-painted p50, but it cannot explain the +1,081 ms fully-painted p95 increase by itself. The minified traces do not establish the tail cause.Ranked fix plan
ResizeObserverwidth for sizing and publish the initial anchor/readiness before the next paint when the observer supplies the valid width. Expected saving: one frame (about 16.7 ms at 60 Hz; the profiled host showed much longer and noisy frame intervals). Risk: initial scroll anchoring or width may be wrong. Prove it with target-ready input→paint p50/p95, the current no-minify trace path, and checks that the correct day/columns appear without a ResizeObserver loop.requestAnimationFrameevents in this 2.5-second window. CandidateTabBarhas separate transition and observed-size callbacks. Expected saving: up to one later frame if the callbacks serialize; no defensible millisecond estimate yet. Risk: capsule morph timing and final size. Prove it by recording callback/frame counts alongside the same interleaved Mail→Calendar and Calendar→Files cells.userStorageand clear it at session end.Files, gates and gaps
Files changed:
bench/tab-switch.mjs,bench/tab-switch.test.mjs. No Rust or product files changed. Three source-mapped traces are attached: trace 1, trace 2, trace 3.Known gaps: the old candidate traces do not map to source and have no settled marker; this cannot attribute the long p95 tail. The current profiling timings are not production-comparable because the browser host was loaded and minification was disabled. The byte size of a §59 view snapshot remains unmeasured.
Decisions not covered by DESIGN: none required. I used a profile-only Vite command without changing production build settings and treated source-mapped timings as diagnostic, not as a new baseline.
Head:
2b6a1791eee6213e4c05e4049c61baa1877b7305. No push, merge or deploy was performed.cargo cleanoutput:Removed 0 files.apps/web/build,apps/web/.svelte-kitandtarget/tmpwere removed after profiling.Starting #1557 in
job/calact4, based on2b6a1791eee6213e4c05e4049c61baa1877b7305(job/calprof, profiling bench path present).I will implement A (Calendar Week DOM budget) and B (ModeHeader offset) as separate commits, each measured against its immediate parent. C (the §59 User-scoped view snapshot) is conditional on A and B both being accepted and time remaining. I will not use the rejected TimeGrid ResizeObserver-plus-extra-frame readiness pattern.
Decision rule before measurement: run five interleaved baseline/candidate pairs on the perf VM, with server and Chromium browser on that VM, smoke Calendar fixture, 1440 px light warm, and cells Mail→Calendar, Files→Calendar, Calendar→Files. Record input→two frames and input→fully painted p50/p95 for each cell. Keep a change only if Mail→Calendar fully-painted p50 improves by at least 10% and no cell's p95 regresses by more than 10%; otherwise revert that change. Record the load average while holding the
perf-runlock.Finding:
bench/tab-switch.mjslaunched Chromium inprepareFixture, the auth phase and the profile loop on the build host, so its measurements did not satisfy #1557's server-and-browser-on-perf-VM requirement. Commitbe11c15b634d3f1846cdf748c6146e8853a5651cadds opt-in--vm-browser: it launches the perf VM's cached Chromium, forwards CDP and the HTTPS front over the existing SSH session, records the VM load for browser samples, and stops/removes the browser profile during locked cleanup.Evidence:
Finding and measurement setup: commit
5c88e8616fe3844c3ece4900fee61aa84e5d0306adds a five-pair interleaved build comparison tobench/tab-switch.mjs. Each cell alternates parent/candidate order. Samples use trusted CDP pointer input and report input→two frames and input→fully painted p50/p95. The report computes the already-posted gate for Mail→Calendar and every cell's p95. It also captures Calendar Week from both builds at 1440/820/390 in light/dark, with macOS platform emulation and a visible real Event check.Evidence:
The perf VM's cached Chromium binary is present. Its first locked CDP startup probe did not open port 9227; I am checking the binary startup before running the full profile. No A/B sample has been taken yet.
Remote browser startup probe succeeded under
perf-runon perf VM 10.69.69.63. Cached headless Chrome for Testing 153.0.8010.12 launched and renderedabout:blank; load average inside the lock was 6.44, 4.92, 3.98. This confirms the VM has a usable browser binary; the Calendar A/B startup and fixture still need verification.Remote browser smoke exposed a concrete harness error before any browser sample:
remote()returns{ code, stdout, stderr }, butstartVmChromium()called.trim()on that object. The run ended withTypeError: (await remote(...)).trim is not a functionatbench/tab-switch.mjs:367; server setup and HDD qualification succeeded, but no browser profile or switch timing was collected. I am correcting the caller to readstdoutand will rerun the smoke under the perf lock.Preliminary DOM finding: I read the live perf-VM Week route through CDP while the fixture/profile run was in setup.
.tghas 3,327 element descendants before counting text or comment nodes, and no Event cards are present in that capture. The empty Week grid alone is over the 3,000-node target. The required component breakdown and fixture-backed count are still pending. Existing CSS grid lines and visible-window rendering remain unchanged; I will use the real A/B screenshot run to identify which components account for the excess.Correction to the preliminary count: the live embedded build did contain 240 Calendar Event cards; my initial
.event-blockselector did not match its production markup. It rendered 21 date columns from 2026-10-04 through 2026-10-24 while the root declared--visible-days: 7, and.tghad 3,327 element descendants. This run uses the server's embedded production assets, so it is a diagnostic, not the issue's paired-build DOM result. The A/B run will serve the frozen parent and candidate worktree builds and report their exact counts and per-component breakdowns.Profile setup finding: my first trace invocation omitted
--smoke, so it used the full three-year fixture. The isolated data/home directories reached 936 MB, and the release server was still indexing; no timing sample was collected. I stopped that run and closed its Chrome profile. During teardown, the stopped server returned HTTP 502, butwaitForPhotoIndextreated every non-200 response as “still indexing” and could poll for its one-hour deadline. I added a fail-fast status check and a bench regression test (bun test bench/tab-switch.test.mjs: 13 pass, 0 fail, 50 expect() calls). I will rerun with--smoke; the aborted run is not part of the A/B results.Perf-pin finding: the first
bun run checkafter the GridColumn edits failed because therender.boundfingerprint forGridColumn.svelte#each:011c4146f38bb440:1changed. I refreshed the exact pins with../../scripts/perf-lint --adopt-7c: “Adopted 9746 exact #1058 sites; ordinary future ratchet remains active” and “perf-lint: PASS; 0 violations; 22128 scoped exceptions”.contracts/perf/ratchet.jsonis unchanged. The web check is running again.A/B harness finding: the fixture and smoke seed completed on the perf VM (100 Photos indexed, 30 recurring Calendar Events; server read probes returned HTTP 200), but the run stopped before sampling.
profileAbContextcalledavailableTabs()on a newly createdabout:blankpage, so the parent bundle exposed 0 Tabs and the assertion failed (0 !== 3). The perf lock was released and the remote browser/server were cleaned up. I am moving the assertion after the initial Mail route load, retaining that load as the A/B warm-up, and will rerun the same profile.A/B harness finding: all 30 timing samples completed (five interleaved pairs for each of Mail→Calendar, Files→Calendar and Calendar→Files). Screenshot setup then timed out at
#route-content .tg .block.plan.event-blockafter the 1440 light/dark captures. This shows the required 820 px Week view does not expose that exact visible TimeGrid selector. The run saved no acceptance result; the VM lock was released and cleanup completed. I am checking the existing responsive Calendar view and will update the screenshot readiness/DOM accounting to use its real Week content at 820/390, then rerun.Candidate A timing result (five interleaved warm pairs per cell; server and Chromium on the locked perf VM; 1440 px light): Mail→Calendar fully-painted p50 changed 3051.4 ms → 2774.4 ms (9.08% improvement; required ≥10%). Files→Calendar changed 2638.1 ms → 2388.0 ms (9.48%). Calendar→Files changed 1323.8 ms → 1334.1 ms (-0.78%). The largest p95 cell change is Calendar→Files, -11.98% (improved); no cell regressed >10%. The timing acceptance rule therefore rejects A because the Mail→Calendar p50 threshold is missed. I am completing the required responsive screenshots and DOM/listener evidence before reverting the A product commit.
The scroll-to-Event retry narrowed the 820 px case: the Week grid reached
.tg.ready, but the Event selector had no attached nodes within 30 seconds. The smoke fixture also contains real Journal Logs, Tasks and other Calendar items. I am changing screenshot readiness to bring the first attached real Week item into view (preferring Events when present) and recording item counts, so the capture proves visible loaded Calendar data at every width without assuming the responsive grid renders an Event at its leading column.Candidate A completed a second five-pair timing set, but still failed the acceptance rule: Mail→Calendar fully-painted p50 was 3162.8 ms → 3024.0 ms (4.39%); Files→Calendar was 2521.0 ms → 2227.4 ms (11.65%); Calendar→Files was 1210.0 ms → 1243.8 ms (-2.79%). Every p95 improved (changes -13.41%, -12.64%, and -12.22% respectively), but Mail→Calendar remained below the required 10% p50 improvement. I am reverting A. Screenshot capture also failed at 820 px: after waiting for
.tg.ready, the Week grid had no attached Event, Log, Task or Activity item, so the all-width comparison is still incomplete. I will record grid loading state in the capture diagnostic and keep this as a known screenshot/DOM verification gap if the real Week view remains empty at that viewport.A is rejected and reverted in commit
a273f76dd: the Mail→Calendar p50 improvement remained below 10%, despite p95 improvements in every cell. Its GridColumn listener/tag optimization is not in the working tree. I am moving on to the independent ModeHeader offset change from the pre-A parent. The 820 px screenshot/item gap remains under investigation in the bench capture path.B implementation is committed as
51c31486e. ModeHeader now caches the active scroll offset from scroll events and route/title effects read that cache; the focused test asserts a route update does not read the inner scroller'sscrollTop, while horizontal scroll still uses the fast path. Focused Vitest result:Test Files 1 passed (1);Tests 21 passed (21). The required five-pair perf VM profile is queued behindstartup1573-default-p1-baseand will compare the frozen pre-B build with B.Perf-run setup finding (#1557): the smoke fixture was ready (seed 549, 10,980 log entries, 366 daily notes), but the bench server phase/read probe timed out after 30,003.8 ms on
GET /api/v1/notes/journal/2026-10-11. It reported 4,180 CPU ms and 527,630,336 RSS bytes; the same probe returned 200 for Calendar range (126.6 ms), Notes tasks/day (77.6 ms), and Files entries (1,319.2 ms). The A/B browser timing phase is continuing. This is outside the ModeHeader change and needs separate triage if it reproduces.Candidate B result (#1557): five interleaved warm pairs on the perf VM, Chromium with macOS platform emulation, 1440 px/light. Mail→Calendar full-paint p50 improved 4.68% (3,063.3 → 2,919.8 ms), below the required 10%. Files→Calendar p50 changed by -3.17%; Calendar→Files improved 16.05%. No cell's full-paint p95 regressed: changes were -2.94%, -0.47%, and -23.25%. The rule therefore rejects B; I am reverting it.
The timing report completed, but the screenshot pass did not: after the candidate build was selected, Week reached
.tg.readywith 505 nodes and 11 columns but had zero Events, Logs, Tasks, or Activities for 30 seconds. I did not treat the empty capture as visual evidence. The run's smoke fixture had 10,980 log entries and 30 recurring Events; the before build rendered 105 Event cards in its 1440 px screenshots. Report:artifacts/tab-switch-1557/B-ab.jsonin the calact4 worktree.Visual evidence setup finding (#1557): the A/B harness rejected the required 820 px and 390 px light/dark screenshot matrix because its timing-only 1440 px/light validation also ran in
--ab-visual-onlymode. I split the timing and screenshot matrix checks and added a focused test.bun test bench/tab-switch.test.mjs: 15 pass, 0 fail, 58 expect() calls. The production capture has not rerun yet.Candidate A screenshot result (#1557): the real perf-VM fixture was ready (seed 549, 10,980 logs, 30 recurring Events). The parent production build rendered 105 Event cards at 1440 px in both light and dark. The candidate then reached
.tg.readywith 505 TimeGrid nodes and 11 columns, but zero Events, Logs, Tasks, or Activities for 30 seconds; the harness stopped rather than saving an empty capture.artifacts/tab-switch-1557/A-visual.jsonrecords the snapshot. Candidate B had the same empty-grid symptom. The A and B timing candidates remain rejected/reverted; their timings are not treated as acceptable evidence while the candidate screenshots show different data states.Baseline responsive capture finding (#1557): with the same parent production build on both sides and the smoke fixture ready, the Calendar Week rendered 105 Event cards at 1440 px light/dark. At 820 px, the route reached
.tg.readywith 505 nodes, 11 columns, andvisible_days=7, but no Events, Logs, Tasks, or Activities appeared within 30 seconds. The capture stopped before 390 px; I did not save or attach an empty image. The/api/v1/calendar/rangeand daily read probes all returned 200 in this run. Valid parent screenshots are available for 1440 px only. This prevents a complete responsive review set and is a baseline Calendar data/rendering issue, not a candidate result.Follow-up to the earlier journal probe:
/api/v1/notes/journal/2026-10-11returned 200 in 81.2 ms on this retry, so the prior 30-second timeout did not reproduce.Valid parent-build reference captures (1440 × 900, macOS platform emulation, smoke-fixture Events visibly loaded):
These are baseline references only. Candidate A and B did not produce valid loaded screenshots, and the 820 px baseline capture also had no Calendar Items, as noted above.
Status
Neither product candidate passed the #1557 acceptance rule. Candidate A and Candidate B are reverted; no user-facing optimization remains in this branch. The benchmark and capture harness changes remain.
Changes
e03e8b54e, reverted bya273f76dd) delegated GridColumn card events and deferred tag parsing. B (51c31486e, reverted by4aa828ed2) cached ModeHeader scroll offsets.Surviving changed files:
bench/tab-switch.mjs,bench/tab-switch.test.mjs. Candidate product files were restored by their revert commits.Measurements
.tg.readywith 505 nodes and 11 columns but no Events, Logs, Tasks, or Activities. The parent rendered 105 Event cards. Treat the candidate timings as diagnostic only; the screenshot data states do not match.Valid parent-build reference images are attached above for 1440×900 light and dark. They use macOS platform emulation and show loaded fixture Events. They are baseline references, not candidate comparisons.
Gates
bun run check; echo exit=$?(verbatim summary lines):bun run test -- --maxWorkers=2:bun test bench/tab-switch.test.mjs:No Rust source changed, so Rust format, clippy, and test gates were not run.
cargo cleanoutput:Removed 1 file, 356B total. Web build output was removed.UX gaps left and decisions
git fetch origin && git merge --no-edit origin/devreportedAlready up to date.Head SHA:
83dc31b00d63b647e91c316c07f356bbeb0a893e.Starting escalation round 5 on
job/calact5, base83dc31b00d63b647e91c316c07f356bbeb0a893e. Read CLAUDE.md, CONTEXT.md, DESIGN §59, all round 2–4 reports and calprof attribution. First repair/validate the harness without product changes: parent/parent, five interleaved pairs, abort on per-sample Event-count mismatch, require Mail→Calendar full-paint p50 noise <5%. Browser and server run on perf VM under perf-run. Prior empty candidate and 820 px parent captures must be explained before measuring a candidate. Decision rule for each product change: keep only if Mail→Calendar full-paint p50 improves at least 10% and no measured cell full-paint p95 regresses more than 10%; report Week nodes/listeners and loaded screenshots at 1440/820/390 light/dark. No push or deploy; only the explicitly required origin/dev integration before final gates.Harness findings (no product change yet):
da49f42dd). Empty or different timing data aborts the run.51166a804anded7aff9bfstart on the trusted click and resolve the paint timestamp inside Chromium. The browser-side target wait starts before dispatch, so the runner's later polling does not move that timestamp. A/A and A/B will use the same corrected boundary.+N; the prior screenshot counter omits these controls.showCalendarWeekItem()picks the first attached card, which can be in the off-screen date buffer, and calls scrollIntoViewIfNeeded(). This can change the horizontal window. I am changing capture positioning to the URL's leading date and vertical scrolling only, with an overflow-list capture when a narrow lane holds its Events in+N.The parent-only responsive diagnostic is still in fixture indexing. HDD qualification passed; no A/A or candidate timing is claimed yet. Focused harness tests: 17 pass, 0 fail, 64 expect() calls. No dependency version changed.
Root cause of round 4's "empty Calendar" evidence:
On the live parent at 820 px,
.tgisready compact,--colwis 62 px, and the 11 dates are October 9–19. The populated date columns still announce 60, 60 and 83 Items. There are 32 realbutton.moreoverlap controls, but zero drawn Event/Log/Task/Activity cards. This is the existing #969 overlap rule: a lane that cannot fit a 64 px card plus its overflow control puts the complete group in+N. It is not missing API data.The round-4 saved failures themselves record 43 overflow controls and
compact ready(A-visual.json,B-ab.json). Both artifact trees contain onlybefore/1440-light.pngandbefore/1440-dark.png, andcaptureAbScreenshots()iterates all parent widths before any candidate width. These runs therefore failed at parent 820 px, before candidate capture. The earlier comments saying the candidate capture was empty misidentify the failing variant. Neither run proves that candidate Event data was missing.There is a second capture error: the inherited helper reveals the first attached card from the off-screen date buffer. Each reveal can move the linked Week window backwards. The repaired helper uses the linked leading date and changes only scrollTop. On narrow lanes it opens the largest real overflow group (the thirty fixture Events form that group), then asserts visible Event rows. The changed helper test is intentional: #1557 explicitly requires repair of invalid capture behavior; no product test expectation was changed.
No product change yet. Parent fixture indexing is still running; A/A follows with the corrected harness.
A/A setup found a second harness race before any timing samples: the second identical parent page returned 0 exposed Tabs versus 3 requested.
firstLoadaccepted server-rendered#route-contentbefore Tab Bar hydration because it omitted the target argument to the paint boundary. It now waits for the requested Tab's selected state. Focused regression verifies that target reaches the boundary. Harness head09fb411da;bun test bench/tab-switch.test.mjs:18 pass,0 fail,70 expect() calls. No product change and no timing claim. The seeded fixture reached 100 indexed Photos before failure. Rerun is queued under perf-run; current holder is startup1573-seed.The next A/A attempt reached the complete fixture (100 indexed Photos, all four read probes HTTP 200), then failed before warm-up at the Appearance fixture PUT with Playwright's default 30,000 ms deadline. No timing sample was recorded. This is a setup timeout, not an A/B result.
setThemeContextnow accepts an optional request deadline; existing callers retain 30,000 ms, while this benchmark uses 120,000 ms outside measurements. The public harness addition is only this optional test deadline. Head560a80144also retains content-free front counters, server exit state and a redacted server tail on failure so a repeated timeout can be attributed. Focused harness result:18 pass,0 fail,70 expect() calls. Product files remain unchanged; another strict A/A is running on the perf VM.Fixture finding: the live Calendar had 45 drawn Events while Photos remained at 0 after more than 20 minutes. Direct VM readiness returned 200 (0.48 s); HTTPS-front readiness returned 200 (1.09 s). Photos library roots were the default Home (
[""]). A realPUT /api/v1/photos/library-rootswith the seededPhotosfolder returned 200; the next harness readiness check saw all 100 indexed Photos. This identifies a fixture refresh dependency; it does not prove which startup notification was missed. The harness now makes that explicit library-root assignment before waiting (6e4e6e5cf), outside all measured visits. For the current run I made the same assignment on its authenticated VM page before warm-up; parent and candidate will reuse that exact indexed Home. No product source changed. Focused harness result remains18 pass,0 fail,70 expect() calls.Reservation finding: the third attempt reached its first measured parent sample (Mail→Calendar 1268.5 ms full paint, 135 drawn Events matching the parent warm-up). It then released the VM lock and waited behind consecutive startup1573 phases, including one declared at 24 minutes. That incomplete one-sample run is retained in
metadata3-ab.json; it is not an A/A result and is not used for a gain claim. I cancelled only this run's queued lock request so its normal cleanup can stop its fixture.Harness head
1a65a04dfnow reserves the full bounded paired timing phase through perf-run; snapshots use a separate reservation, and the candidate build wait still holds no reservation. Nested theme setup shares the phase reservation, with a regression test that rejects a second exclusive acquisition. Existing cold/LinkNav setup calls that already hold a reservation use the same flag. Decision: keep each interleaved matrix contiguous so another job cannot split a pair by many minutes. Acceptance thresholds and sample count are unchanged. Focused result:19 pass,0 fail,72 expect() calls.The third attempt produced one incomplete parent sample: Mail→Calendar 1268.5 ms, 135 drawn Events, matching its 135-Event assertion. It is not an A/A result. Per-operation leases then queued behind another job, so I cancelled only our queued request and let fixture cleanup finish. Each validation now holds one bounded perf-run reservation through setup, all five paired samples and captures. It releases the reservation while waiting for the candidate build and reacquires for A/B validation and cleanup. This avoids repeatedly queueing within one validation. The 60-minute cap remains in effect. A fresh parent/parent run is queued; no product change has been applied.
The fourth fixture remained at 0 Photos after an early library-root assignment. Directory listings alone were not a whole-tree readiness check: a read-only Index count showed 372 Files rows and only 1 Photo row, while 100 seeded JPEGs existed on disk. Listing year/month folders schedules asynchronous reconciliation; the first replies can be empty. I browsed only the generated Photo folders through the real Files API (at most four concurrent reads), then confirmed 100 returned JPEGs across 106 folders and made one real library refresh before warm-up. The harness then reported 100 indexed Photos and all three requested Tabs. The running A/A uses this repaired fixture; no product source changed. Commit
5d6fbe1d8makes the same bounded priming automatic for smoke fixtures, retries incomplete API snapshots for at most five minutes, and retains the real Photo readiness check. Regression output:21 pass,0 fail,76 expect() calls. Thumbnail job failures reported the public category “Thumbnails are temporarily unavailable”; no Photo Tab is measured in this job.A/A result: INVALID. Both builds are frozen parent
83dc31b00. Five interleaved pairs ran per cell on the perf VM, with server and Chromium on that VM under perf-run. All 30 samples passed the per-sample 135-Event assertion. No sample is dropped.Mail→Calendar p50 noise: 10.67%, above the required <5%. The responsive parent captures contain Events: 45 drawn cards at 1440 px; 30 real overflow-list Events at 820/390 px, light and dark. Parent/parent 1440-light differs by 0 pixels. Parent/parent 1440-dark differs by 4 pixels, at (31,19), (32,19), (33,19), (19,33), around the Sidebar’s outer corner. The exact-pixel assertion rejected it; I did not weaken that assertion.
Commit
8254ff1d2explicitly brings paired pages to the foreground and assertsdocument.visibilityState === "visible"before trusted input. This removes a harness confound; it is not a proven explanation for the observed noise. Standalone A/A timing runs now also exit with failure if the noise gate fails. Regression output:22 pass,0 fail,79 expect() calls. One final foreground A/A timing-only run is queued behind the current VM reservation. No product source or perf ratchet changed; the candidate remains unpublished because Step 1 has not passed.calact5 final report — INCOMPLETE / NOT READY FOR MERGE.
Calendar activation has no accepted improvement. Step 1 did not pass, so I kept product code unchanged. Branch
job/calact5; base83dc31b00d63b647e91c316c07f356bbeb0a893e; head0a3c064801d04cb9b0ce0e371a640bac8c3057c9. The required origin/dev fetch and merge returnedAlready up to date.No push or deploy.Built and files
bench/tab-switch.mjs: trusted-click timestamps captured inside Chromium; selected-Tab readiness; positive, matching Event counts on every sample; linked-date capture positioning; real overflow Events on narrow captures; strict A/A noise rejection; foreground-page activation and visibility assertions; bounded perf-run validation reservations; explicit smoke Photo Index preparation through four concurrent real Files reads; five-minute abortable setup deadline; content-free failure diagnostics; complete visual-matrix capture checkpoints with DOM/listener counts; early-failure provenance and correct requested conditions.bench/tab-switch.test.mjs: regressions for readiness, data validity, A/A noise, nested reservations, bounded fixture reads, stalled requests and foreground activation.apps/web/e2e/harness.mjs: optional appearance request deadline. The default stays 30 seconds; benchmark setup uses 120 seconds outside measurements.Measurements
Five interleaved parent/parent pairs per cell ran with server and Chromium on the perf VM under perf-run. All 30 samples matched at 135 drawn Events. No sample was dropped.
Mail→Calendar p50 noise was 10.67%, failing the required <5%. Parent/parent desktop light differed by 0 pixels; desktop dark differed by 4 pixels at the Sidebar outer corner. The exact-pixel gate rejected it. The final foreground A/A attempt acquired the VM lock but failed disk qualification at 70.148558 IOPS (required 100–250), before collecting any samples. No further measurement loop was run.
30-sample A/A data, pixel coordinates, final qualification failure, qualification log. The failure artifact predates the last metadata-only commit; future early failures include the loaded harness hash and selected warm/cold conditions.
The old historical baseline 1464.9 / 1813.5 ms uses a different measurement boundary and dataset window; I did not claim a gain against it. Fresh Week DOM/listener counts were lost when the earlier visual helper aborted; the new checkpoint retains them for future runs. No candidate counts exist. The supplied calprof attribution remains the prior evidence of roughly 15k nodes / 1.4k listeners, not a fresh measurement from this job.
Captures — frozen parent
83dc31b00, macOS platform emulationThese are diagnostic parent captures, not candidate proof. The dated Week capture has 45 drawn Event cards at desktop; tablet and phone show 30 real overflow-list Events. The timed default Week has 135 drawn Events. Those are different linked date windows.
A/A parent B desktop light, A/A parent B desktop dark. Round 4's missing tablet capture was a parent capture with populated overflow groups, not proof of an empty candidate. The corrected helper opens a real group and preserves the linked date.
Gates — verbatim summaries
cd apps/web && bun run check; echo exit=$?cd apps/web && bun run test -- --maxWorkers=2bun test bench/tab-switch.test.mjsWeb check summary, full web test output, final harness test output. No Rust source changed; Rust format/clippy/test gates were not needed. No dependency or perf ratchet changed.
Known gaps / work left
Decisions
All strict Event, noise, pixel and disk qualification gates remain enforced. Setup reads use four concurrent requests and a five-minute deadline. A validation holds one bounded perf-run reservation through setup, paired timings and captures, then releases it during candidate build waits. These are harness decisions; no undecided product design was built. The reviewed next candidate is duration-based metadata DOM pruning. Width-based pruning is unsafe because higher-specificity LOD/reveal selectors can restore rows hidden by compact/cramped rules; the draft was never applied.
For follow-up / merge round: rerun the strict five-pair A/A on the perf VM with the foreground fix and qualified disk; then implement one candidate, run
bun run check,bun run test -- --maxWorkers=2,bun test bench/tab-switch.test.mjs, and measure five interleaved pairs per cell with matching Event counts. Keep it only for ≥10% Mail→Calendar p50 improvement and no cell p95 regression >10%; collect DOM/listener counts and all six responsive comparisons.Cleanup completed: cargo clean reported
Removed 1 file, 356B total; web build, .svelte-kit and frozen parent build removed. Capture browser profile removed, saved server PID stopped, no calact5 perf reservation remains. Mac VM was not used. Worktree is clean. Issue stays open.Starting follow-up on
job/calact6, base0a3c064801d04cb9b0ce0e371a640bac8c3057c9(calact5 head). I read CLAUDE.md, CONTEXT.md, DESIGN §59, the calprof attribution, and the calact5 report. The calact5 report has no accepted product optimization: its A/A noise was 10.67%, and its final retry failed disk qualification at 70.148558 IOPS before samples.This round will use the updated rule from the job brief: 9 interleaved pairs for parent/parent calibration, then 9 interleaved pairs for each kept candidate, all under perf-run on the perf VM. Candidate acceptance requires Mail→Calendar full-paint p50 improvement ≥ max(10%, 2×N), at least 7/9 paired improvements in the same direction, and no cell p95 regression above max(10%, 2×N). Each run must retain the Event-count, foreground, timestamp and disk qualification checks. I will report Week node and listener counts for both builds and attach only loaded responsive captures.
The nine-pair measurement rule is implemented in the profile before any timing run. A/A now reports N as the median absolute paired Mail→Calendar full-paint difference; it does not use calact5's superseded 5% cutoff. Candidate acceptance records
max(10%, 2×N), median paired gain, directional count, and each cell's p95 change. The existing per-sample Event, foreground, browser timestamp, and disk qualification gates remain enabled.Regression result after this change:
A/A setup attempt
artifacts/tab-switch-1557/aa9.logended before any timing sample. It failed becausestartHttpsFront()callsmkdtempSync()undertarget/tmp, and this clean worktree did not yet contain that directory.perf-run statusreturnedfreeafter cleanup. The ignored path matches the job's temp-output contract; I am adding directory creation to the profile setup and will rerun calibration.A/A retry #1 stopped at HDD qualification before a timing sample. The live qualified read rate was 68.820786 IOPS; the required range is 100–250 IOPS. The harness retained the redacted server diagnostics, and
perf-run statusis free after cleanup. Per the posted rule, the next qualification attempt will wait at least 15 minutes. No A/A N or product timing is claimed from this run.Retry #2 was stopped by the disk gate before timing: QD1 reported 71.376257 IOPS, below the required 100–250 IOPS range. The perf-run lock was released. I also found that the early-failure report discarded the load average captured inside the lock. Commit
e18896f37now records load, io.max, IOPS, and qualification state before validating the probe; the focused harness test passes (24 pass, 0 fail, 97 expect calls). I will wait at least 15 minutes from the failed probe before the next attempt.A follow-up review found that the process-level failure handler could not see
main()'s local qualification array. Commit18d9d34demoves the accumulator to module scope, so the new incomplete-report path can persist the locked load and failed IOPS measurement.bun test bench/tab-switch.test.mjs: 24 pass, 0 fail, 97 expect calls.A/A attempt 3 reached HDD qualification, but QD1 was just below the lower bound at 99.386748 IOPS (required 100–250). The locked load captured in the saved JSON was [1.93, 0.55, 0.30]; fio reported p50 8.02816 ms and p99 39.583744 ms. It stopped before fixture setup, so raw timing samples remain empty. The perf-run lock is free. The failure report now retains
qualificationwith load, io.max, IOPS andqualified: false; the original log and JSON areartifacts/tab-switch-1557/aa9-attempt3.{log,json}. I will wait at least 15 minutes before the next attempt. The server tail also recorded a native media-sandbox launch error during startup; the profile stopped at HDD qualification before any route was measured.A/A attempt 4 passed HDD qualification (QD1 110.718571 IOPS; QD16 200.611946 IOPS) with locked loads [1.95, 0.60, 0.31] and [1.80, 0.63, 0.33]. The default large fixture then stayed at 0/50,000 indexed Photos for 55 minutes. While it waited, the server logged 1.0–1.14 s WAL checkpoint statements and 2.09–3.01 s DB pool acquisitions (SLOW-only). I stopped the benchmark-owned server at 55 minutes, before the 60-minute perf-run cap; this produced the expected final HTTP 502 during teardown, not a measured route response. The incomplete JSON preserves qualification and has zero timing samples. The lock is free, the owned server is stopped, and no tab-switch browser profile remains under /var/tmp. I will try the existing
--smokefixture next: it keeps the 30 recurring Calendar Events used by this hot path and avoids the unrelated 50k Photo/100k File index that stalled setup.The first
--smokeA/A attempt also failed before timing: QD1 was 71.561834 IOPS (below the 100 IOPS floor), with locked load [3.05, 4.96, 5.84], p50 12.386304 ms and p99 47.972352 ms. The incomplete report preserved this probe and zero raw timing samples.perf-runis free. I will wait at least 15 minutes from this failure before the smoke-calibration retry.The second smoke A/A attempt failed the strict QD1 HDD qualification before fixture timing. Evidence from
aa9-smoke.json: QD1 70.32967 IOPS (p50 12.386304 ms, p99 45.350912 ms), locked load average 2.93 / 0.98 / 2.21, io.max7:0 rbps=157286400 wbps=157286400 riops=200 wiops=200,qualified: false, and 0 raw samples. The perf-run reservation is free after cleanup. I will wait 15 minutes before another attempt; no timing result is inferred from this run.Merge finding for #1557:
origin/devcontains4aa828ed2, which reverted the earlier cached ModeHeader scroll-offset optimization because it depended on cached viewport/scroller positions. The #1557 candidate keeps the current liveoffset()logic and defers only the PageChrome effect's measurement to the existing animation-frame scheduler. This preserves the live position read and the revert's stale-offset correction while removing the synchronous route-update read identified by calprof.The third smoke A/A attempt failed strict QD1 qualification before fixture timing.
aa9-smoke-retry3.jsonrecords QD1 82.084083 IOPS (p50 10.027008 ms, p99 43.25376 ms), locked load average 1.80 / 0.55 / 0.92, io.max7:0 rbps=157286400 wbps=157286400 riops=200 wiops=200,qualified: false, and 0 raw samples. The perf-run reservation is free after cleanup. I will wait 15 minutes before the next retry; no timing result is inferred from this run.The final retry passed strict HDD qualification (QD1 103.797468 IOPS, p50 8.02816 ms, p99 36.438016; QD16 200.531915 IOPS, p50 94.896128 ms, p99 122.159104). It then spent about eight minutes waiting for the smoke Home's 100 Photos to index, although the profile selected only Mail, Files and Calendar. After the fixture reached 100/100, I stopped only the verified #1557 server to end setup and release the reservation; the resulting
target Tab did not mount/HTTP 502 is controlled teardown and produced 0 timing samples. The fixture report confirms 100 Photos, 100 Files and 10,980 seeded Journal entries. I will change the smoke seeder to omit Photos when Photos is not selected, add a test, and rerun the strict A/A. This keeps the Calendar recurrence and measured Files data unchanged.The no-Photos A/A retry failed strict QD1 qualification before fixture setup.
aa9-smoke-no-photos.jsonrecords QD1 70.848315 IOPS (p50 12.517376 ms, p99 42.205184 ms), locked load average 4.86 / 6.04 / 4.33, io.max7:0 rbps=157286400 wbps=157286400 riops=200 wiops=200,qualified: false, and 0 raw samples. The reservation was released; the next startup job then acquired it. I will wait the full cooldown and make one last qualification attempt. No timing result is inferred.The final A/A attempt failed strict QD1 qualification before fixture setup.
aa9-smoke-retry5.jsonrecords QD1 65.657912 IOPS (p50 13.041664 ms, p99 55.836672 ms), locked load average 2.06 / 0.84 / 1.80, io.max7:0 rbps=157286400 wbps=157286400 riops=200 wiops=200,qualified: false, and 0 raw samples. The perf-run reservation is free after cleanup. This failure repeats the QD1 issue even with Photos omitted. I am ending measurement retries within the job timebox; there is no A/A noise value and no A/B acceptance claim.#1557 report
Branch:
job/calact6, based on calact50a3c06480. I mergedorigin/devonce before the final gates and resolved the benchmark conflicts with both branches' profile behavior intact. Final head:2f07739f13d79be5f592f2b06f8c17c2e11c4ead.Built
ModeHeader.sveltenow coalesces its PageChrome route measurement into the existing animation-frame scheduler. The scroller/window offset choice and live read remain unchanged; the route effect no longer reads geometry during the Svelte flush.TimeGrid.sveltekeeps route-restored day focus without a programmatic focus ring. Keyboard navigation still uses the shared focus-visible behavior. Its test checks the focus options.ModeHeader.svelteandTimeGrid.svelte.contracts/perf/ratchet.jsondid not change.Performance evidence
The change adds O(1) scheduling work: at most one queued animation frame per route/scroll burst, followed by the existing offset read. It does not change Calendar data work, DOM size, or event handlers.
No valid A/A/A/B timing result was collected. The locked perf VM repeatedly failed strict QD1 qualification, and the one qualifying attempt stalled while indexing the large Photos fixture before timing began. Later smoke rounds still failed QD1. Reports contain no timing samples, so there is no measured p50/p95 improvement claim. The harness now avoids indexing Photos for this non-Photos profile, but I stopped perf retries after the repeated qualification failures.
A local screenshot-only capture recorded, for 1440 px light, Week DOM 5,119 nodes for both builds; Calendar route DOM 5,199 for both; page listener totals 1,076 parent and 1,072 candidate. Mail was 435 listeners in both captures, giving a Calendar listener delta of 641 and 637. These are single capture counts, not performance acceptance evidence.
Screenshots
The screenshots are from local production builds and a real local server. Chromium reported the macOS platform. Candidate screenshots cover 1440/820/390 px in light and dark, plus post-click and post-⌘-shortcut captures. The candidate interaction captures each showed 15 visible fixture Events and zero
:focus-visibleelements. Narrow Week captures opened the real overflow list, showing 30 fixture Events.Parent screenshots are attached for 1440 light, 820/390 light and dark, and both interactions. I excluded parent 1440 dark because it shows the Calendar error message
Calendar could not be loaded. Try again.The exact-pixel comparison therefore failed; 1440 light also crossed a minute boundary in the current-time line. The complete before/after visual matrix is a known gap.Parent: 1440 light, 820 light, 820 dark, 390 light, 390 dark, pointer, ⌘ shortcut.
Candidate: 1440 light, 1440 dark, 820 light, 820 dark, 390 light, 390 dark, pointer, ⌘ shortcut.
UX gaps closed / left
Closed: programmatic focus after Calendar route activation no longer leaves a ring; pointer and shortcut captures have no visible focus ring; every candidate capture contains real Calendar Events.
Left: the parent 1440 px dark screenshot is unavailable as a clean capture, so the exact before/after pixel matrix is incomplete. No touch-specific capture was added because this change does not change touch interaction.
Decisions
offset()read instead of caching it. The earlier cached-offset change was reverted upstream, and the deferral preserves its current route and scroll behavior.Gates (output excerpts, verbatim)
cd apps/web && bun run check:cd apps/web && bun run test -- --maxWorkers=2:bun test bench/tab-switch.test.mjs:Focused ModeHeader and TimeGrid tests:
cargo clean:No Rust source or API changed, so Rust crate gates and adversarial API probing were not run. Web build output was removed after verification. The working tree is clean.
Starting #1557 work on branch job/calact6.
Base SHA:
8e84096297(origin/dev merge-base).Starting HEAD:
2f07739f13.I am checking the QD1 disk qualification and base-device latency before the interleaved measurements.
#1557 disk qualification finding: under
perf-run calternal base1557 5, fio 3.39 read the undelayed backing file/mnt/hdd/calternal-hdd-emu.imgon/dev/sdbwith QD1 direct random reads. The lock was held; the captured load average was 1.57 / 1.75 / 1.49. The three runs measured p50 9.371648 / 0.207872 / 0.066048 ms and 104.891377 / 226.718219 / 395.320936 IOPS. The first p50 exceeds the required 6 ms substrate ceiling and the p50 spread is about 142x, so the perf VM fails the stability precondition. I changed the qualification bounds to QD1 p50 8..14 ms and IOPS 1000/14..1000/8 (71.43..125), with the QD16 250 IOPS cap retained. This does not loosen the base-device precondition. I am stopping before A/A or A/B timing; no comparison samples are valid from this host state.#1557 report
Branch:
job/calact6Head:
fbb180a134a73e23e53b5a624981b742921418d0git fetch origin && git merge origin/dev: already up to date.Built
riops=200with 25% tolerance.bench/tab-switch.mjs,bench/tab-switch.test.mjs.Perf VM evidence
The base-device probe ran under
perf-run calternal base1557 5with fio 3.39, direct QD1 random reads against the undelayed/mnt/hdd/calternal-hdd-emu.imgfile on/dev/sdb. The load average captured inside the reservation was1.57 1.75 1.49.The first p50 exceeds the 6 ms substrate ceiling. The p50 spread is about 142×, above the 2× stability limit. The perf VM failed the calibration precondition, so I stopped before the delayed-device qualification and A/A/A/B timing. No tab-switch sample from this host state is valid, and I did not loosen the 6 ms limit.
The issue baseline remains 1,464.9 ms p50 / 1,813.5 ms p95. A/A noise N, parent-versus-candidate p50/p95, Week DOM nodes and listener counts remain unavailable. I did not attempt the next attribution item.
UX gaps closed / left
Decisions
Gates
Verbatim summary lines from
bun run check; echo exit=$?(the terminal view truncated perf-lint's large existing debt inventory):Verbatim final summary from
bun run test -- --maxWorkers=2:Verbatim result from
bun test bench/tab-switch.test.mjs:cargo clean:Web
.svelte-kitandbuildoutput were removed. No Rust source changed, so no Rust crate gates were run. No pushes, deploys or issue closure occurred.Starting calact8 on branch job/calact6. Worktree head:
fbb180a134. Branch base: origin/dev at8e8409629; this worktree already contains the branch's intervening commits. I will use the issue's current 9-pair interleaved measurement rule and the delayed-device-only qualification.Qualification finding from #1587: ten locked probes of the delayed device measured p50 8.028–8.847 ms (1.10× spread). The regular-file undelayed path remains host-cache-sensitive even after , so this run now treats it as informational and gates only ten distinct-seed delayed-device QD1 probes: every p50 8–14 ms, with max/min < 1.3×. The perf VM was free when checked (load 0.24 / 0.71 / 1.38); I’m proceeding with the locked comparison.
Correction to my previous comment: the qualification finding is from #1587. Ten locked probes of the delayed
/dev/mapper/calternal-hdd-emudevice measured p50 8.028–8.847 ms (1.10× spread). The regular-file undelayed path remains host-cache-sensitive even afterperf-run --quiesce, so this run treats it as informational and gates only ten distinct-seed delayed-device QD1 probes: every p50 must be 8–14 ms, with max/min < 1.3×. The perf VM was free when checked (load 0.24 / 0.71 / 1.38); I’m proceeding with the locked comparison.Harness finding: the second attempt reached remote server startup but stopped before qualification. Its redacted server log ended with
Error: an outbound network setting contains an invalid CIDR; no timing sample was recorded, andperf-run statusreturnedfree. Inspection found thatcalendarFeedHostandcalendarFeedPortwere declared but never assigned, and the existingstartCalendarFeedServerandaddCalendarSubscriptionFixtureshelpers were never called. I am wiring the read-only feed fixture before server startup and adding its subscriptions during fixture setup, so the server allowlist and real Calendar Events use the same selected address.The corrected #1557 run reached delayed-device qualification under
perf-run calternal calact6-1557with--quiesce. It recorded all ten QD1 p50 values: 11.993, 11.600, 9.765, 8.978, 8.585, 8.225, 8.028, 8.094, 8.094, and 8.028 ms. Every value is within 8–14 ms, but the run spread is 1.494×, so it fails the required <1.3× stability gate. Load average recorded inside the lock declined from 2.16 to 1.05. The run stopped before collecting A/A or candidate timing samples; I will not report it as a valid performance comparison.The attempt also exposed a fixture setup issue: duplicate
fixtureYearsandtabSeeddeclarations in the setup try block shadowed the CLI values and put them in the temporal dead zone when the feed listener started. I removed those declarations so--fixture-yearsand--filesand restored snapshot dimensions remain in force. Commits:1dad8e28e(initialize the private Calendar feed listener and real subscription fixtures) anda06e50fcb(preserve selected fixture dimensions). Focused suite:53 pass, 0 fail.A visual-only local run reached the Home seed after the two earlier fixes. It then found that
addCalDavAccountexpects the complete CalDAV fixture, but the caller passed the anchor string and year count. The resulting failure wasTypeError: undefined is not an object (evaluating 'firstDay.replaceAll')instartCalDAV. The caller now passes the already-builtcaldavFixture; the focused suite passes (53 pass, 0 fail). Commit:ae2e3dc3c.A subsequent visual setup sent the ten fixture subscription POSTs together. The Calendar server returned HTTP 503
service_unavailablewithcalendar fetcher is busy; retry shortly. I changed fixture creation to submit feeds through the single active fetcher and retry only that explicit busy response with capped backoff. A focused test covers the retry and confirms other responses are not retried. Commit:0a522080b; focused suite:54 pass, 0 fail.The smoke visual setup now reaches the server probe. The profile requested Calendar, Mail and Files, but the generic probe also called
/api/v1/notes/journal/<date>; the inactive Notes route returned 404 and stopped setup before any screenshot. I made adjacent route probes conditional on their Tabs being selected and added focused coverage. Commit:263a4cc9e; focused suite:55 pass, 0 fail.After the selected-route probe fix, the local smoke fixture reached
/healthzand the Calendar range probe verified 1,203 Event instances in the window (30 recurring CalDAV Events, 1,000 dated Events and 50 subscription Events in the fixture). Snapshot creation then failed becausewaitForHealthzReady, already called by the cold-restart and snapshot paths, had no implementation. I added the bounded/healthzpoll and a test for the migrating-to-ok transition. Commit:48f9e627c; focused suite:56 pass, 0 fail.The restored server reported
/healthzas{"status":200,"state":"ok","progress":null}. The benchmark's readiness helper expected the olderphase:nullshape and timed out after 60 seconds despite the server being ready. I updated the helper for the currentprogresscontract, retained the older fixture shape for tests, and added current-contract coverage. Commit:de7915f6c; focused suite:56 pass, 0 fail.Responsive visual evidence
The local visual-only run captured the real parent and candidate production builds with macOS platform emulation. The fixture reported 1,203 Calendar Event instances in the range probe. Captures showed 45 visible Events at 1440 px and 80 at 820/390 px. The pointer-click and mode-shortcut captures both reported zero focus-visible elements. Screenshots cover 390, 820 and 1440 px in light and dark, plus the 1440 px pointer and shortcut captures.
Week DOM nodes / total page JS listeners, before → candidate:
At 1440 light, the Mail baseline listener counts were 458 before and 460 after, so the Calendar delta was 421 → 465.
The screenshot tool's exact-pixel gate failed. It recorded differences of 16,190 pixels at 1440 light, 16,895 at 1440 dark, 181,524 at 820 light, 24,903 at 820 dark, and 80,898 in the pointer-click capture. The 390 px images were pixel-identical. The mode-shortcut capture differed by 81,110 pixels and still reported no focus-visible element. Please review the attached images for the intended visual effect; I did not treat this as an accepted timing result.
Before
Candidate
Final report — #1557
Built
perf-run --quiesceand retains all ten QD1 probes./healthzprogress contract.ModeHeaderandTimeGridcomponents.Files changed from
origin/devapps/web/scripts/design-rules-lib.mjs;apps/web/src/lib/calendar/TimeGrid.svelte.test.ts;apps/web/src/lib/modeHeader.svelte.test.ts;bench/tab-switch.mjs;bench/tab-switch.test.mjs;contracts/perf/adoption-1058.json;contracts/perf/exceptions.json;packages/ui/src/components/ModeHeader.svelte;packages/ui/src/components/calendar/TimeGrid.svelte.Measurement and visual evidence
The delayed-device qualification recorded p50 values 11.993, 11.600, 9.765, 8.978, 8.585, 8.225, 8.028, 8.094, 8.094 and 8.028 ms. All are within 8–14 ms, but the 1.494× run spread exceeds the required <1.3× gate. Load average inside the lock declined from 2.16 to 1.05. The run stopped before A/A or candidate timing; there is no performance result and no next attribution run.
The visual-only captures contain real Events: the range probe counted 1,203 instances; 45 Events were visible at 1440 px and 80 at 820/390 px. Pointer-click and mode-shortcut captures reported zero focus-visible elements. All 16 before/after PNGs (390/820/1440 px, light/dark, plus pointer and shortcut captures) are attached in the preceding #1557 comment.
Week DOM nodes / total page JS listeners, before → candidate:
At 1440 light, Mail baseline listeners were 458 before and 460 after; Calendar listener delta was 421 → 465. The exact-pixel screenshot check failed at 1440 light/dark (16,190 / 16,895 pixels), 820 light/dark (181,524 / 24,903), and pointer click (80,898). The mode-shortcut comparison recorded 81,110 changed pixels; the 390 px captures were pixel-identical. The screenshots need the visual reviewer’s assessment.
Gates
bun run check(verbatim result lines):bun run test -- --maxWorkers=2Vitest summary:The Vitest run passed. The shell wrapper then printed
zsh:1: read-only variable: statusbecause it tried to assign to zsh’s reservedstatusvariable; this was a wrapper error after the test summary.bun test bench/tab-switch.test.mjs:No Rust source changed, so Rust crate gates were not run.
cargo cleanoutput:Removed 1 file, 356B total.git fetch origin && git merge origin/dev:Already up to date.The perf VM lock is free.Commits and head
Head:
de7915f6cd721e4250d48a7bcf9b7f3a738b0d1e(job/calact6). The work is committed in atomic steps. No push or deploy was run.Known gaps
Decisions not covered by DESIGN.md
progress: null; the helper also accepts the olderphase: nullfixture shape.Starting calact9 on
job/calact9, base/headde7915f6cd721e4250d48a7bcf9b7f3a738b0d1e. I read CLAUDE.md, CONTEXT.md, DESIGN §59, all #1557 comments, calprof attribution and the #1587 disk report. I will drop the rejected ModeHeader change, preserve benchmark repairs, discard/log the first three disk probes as warm-up, and reduce Calendar remount work without retaining a hidden route. No Rust change is planned. Acceptance uses the posted 9-pair A/A noise and interleaved A/B rule.Commits
f651fdb7aand1bb4921bbremove the rejected ModeHeader candidate and log three warm-up probes before ten measured delayed-device probes. The reserved zshstatuswas in an ad-hoc gate wrapper; this job usesgate_rc/profile_rcand preserves the command exit status.The first locked qualification attempt failed: measured p50 spread 1.363× (probe 4: 10.944512 ms; minimum: 8.02816 ms). It collected no Tab timing sample. All thirteen probes and the failure remain in artifacts/calact9/aa.json. I have started one final qualification attempt with unchanged bounds, not a valid result yet.
Implementation finding: Calendar already caches data, and GridColumn already paints hour rules with CSS backgrounds. The candidate adds measured geometry and complete row restoration to the shared viewSnapshotCache, fenced by Calendar invalidation generation and User identity. It removes only compact/cramped metadata that CSS always hides and delegates Event boundary hover/focus plus captured move/up/cancel. Existing event controls and styles remain. Focused TimeGrid, data, snapshot, route and drag tests passed.
Candidate implementation is committed at
5e259f8e8; the required origin/dev sync isfe6617f13. Final web gates pass:bun run checkexit 0, 321 Vitest files / 2345 tests passed, and 57 benchmark tests passed. No Rust source changed.Responsive evidence: all six real Week image comparisons are pixel-identical at 1440/820/390 px in light/dark. The range probe contains 1,203 Event instances. At 1440, Week nodes fall from 3,783 to 993; the Calendar listener delta falls from 443 to 221 (total page listeners 923 to 702). Tablet and phone use the same overflow UI and have 472 Week nodes before/after. The pointer and shortcut images have zero focus-visible elements and zero changed grid pixels. Their exact-image gate reports 70,949 / 71,765 changed pixels in the Top row chrome; most pointer changes are one RGB step. I am recapturing after the shared chrome animations finish and removing harness hover before captures, without changing the timing boundary.
Strict timing is not accepted: the latest delayed-device run has a stable 1.016× spread but includes 7.962624 ms p50, below the required 8 ms floor. Failed probes remain in the report. I will also collect diagnostic nine-pair A/A and A/B timings using the existing record-only mode, with
timing_qualified: falseand acceptance forced false. These cannot satisfy the issue contract.Screenshots attached (original strict capture):
Candidate implementation is committed at
5e259f8e8; the required origin/dev sync isfe6617f13. Final web gates pass:bun run checkexit 0, 321 Vitest files / 2345 tests passed, and 57 benchmark tests passed. No Rust source changed.Responsive evidence: all six real Week image comparisons are pixel-identical at 1440/820/390 px in light/dark. The range probe contains 1,203 Event instances. At 1440, Week nodes fall from 3,783 to 993; the Calendar listener delta falls from 443 to 221 (total page listeners 923 to 702). Tablet and phone use the same overflow UI and have 472 Week nodes before/after. The pointer and shortcut images have zero focus-visible elements and zero changed grid pixels. Their exact-image gate reports 70,949 / 71,765 changed pixels in the Top row chrome; most pointer changes are one RGB step. I am recapturing after the shared chrome animations finish and removing harness hover before captures, without changing the timing boundary.
Strict timing is not accepted: the latest delayed-device run has a stable 1.016× spread but includes 7.962624 ms p50, below the required 8 ms floor. Failed probes remain in the report. I will also collect diagnostic nine-pair A/A and A/B timings using the existing record-only mode, with
timing_qualified: falseand acceptance forced false. These cannot satisfy the issue contract.Screenshots attached (original strict capture):
Resuming calact9 on job/calact9 at
16b218172c. The worktree is clean. Read the preserved commits, all current issue comments, DESIGN §59 and the calprof report. The rejected ModeHeader candidate is already reverted. The Calendar snapshot and DOM changes are committed, with User/time-zone fences. Prior strict disk qualifications and diagnostic A/A + A/B runs are preserved; A/B is not accepted. No additional qualification retry is planned: the previous run already used its attempts and the job time box. This continuation will explain the final pixel differences, run the required web gates on the resumed head, and post the complete report. The required origin/dev synchronization was already done atfe6617f13; no new merge is planned.calact9: Calendar activation, issue #1557
Status: NOT READY FOR MERGE. This is a time-boxed report. The candidate is committed, but the required performance comparison is not accepted. Do not treat the DOM reduction as proof of faster full paint.
Built
gate_rc, not the zsh reservedstatusvariable.viewSnapshotCachefor completed Calendar rows, selection, scroll and measured column width. Its existing limits are four entries, 8 MiB, 2,000 row objects and two in-flight reservations. No hidden Calendar route stays mounted.47d9cf42fchanges screenshot priming to real Tab switches. The previous full-document Mail navigation destroyed the in-memory snapshot. Old interaction captures cannot prove a warm snapshot return. The new capture path has not been rerun.Shared components: TimeGrid, GridColumn, TagPill, the existing Event/Task controls and ModeHeader. No new visible control or dependency was added. No crate or package version changed. No Rust source changed. The job did not raise
contracts/perf/ratchet.json.Files
Implementation and regression tests:
apps/web/src/lib/calendar/{data.ts,data.test.ts,routeLoad.ts,routeLoad.test.ts,TimeGrid.svelte.test.ts}apps/web/src/lib/{viewSnapshots.ts,viewSnapshots.test.ts,modeHeader.svelte.test.ts}apps/web/src/routes/calendar/[view]/[date]/+page.sveltepackages/ui/src/components/{ModeHeader.svelte,calendar/TimeGrid.svelte,calendar/GridColumn.svelte}bench/{tab-switch.mjs,tab-switch.test.mjs}contracts/perf/{adoption-1058.json,exceptions.json}artifacts/calact9/.Measurement
Prior production runs used the perf VM with
perf-run --quiesce, Chromium on that VM and macOS platform emulation. The release server source was8e840962979acd2bdf58141888618ab5560f728e; SHA-256 was9c27cf74bb2196760c0d5ca7927717267a3edeeb2efd56c7db236222f317024a. The saved A/B report identifies the two production asset directories and harness hash. They are older builds, not a new measurement of the resumed head.The last complete diagnostic A/B run logged warm-up p50 values 11.862016, 11.599872 and 10.289152 ms. Its ten measured p50 values were 9.109504, 8.159232, 8.093696, 8.093696, 8.02816, 8.02816, 8.02816, 8.02816, 8.02816 and 7.962624 ms. The last value fails the 8 ms floor. No bound was changed and no failed value was discarded. Earlier failures remain in the saved reports.
Nine diagnostic A/A pairs produced N = 29.61%. The source report has
timing_qualified: falseandvalid: false. The later localaa-verified.jsonrecalculation marked validity true from disk values alone; that does not supersede the diagnostic source flag. Do not use it as accepted A/A evidence. The diagnostic A/B threshold was max(10%, 2N) = 59.22%.The A/B report has
timing_qualified: falseandaccepted: false. Mail → Calendar fails the directional test and has an 82.28% p95 increase, above the diagnostic threshold. These results do not establish a production regression or improvement because the run is unqualified. No matching snapshot baseline exists indocs/perf/baseline.json. The 100 ms warm-switch budget remains unmet in these diagnostics.The fixture had 100 Files, 20 Notes, 30 recurring CalDAV Events, 1,000 dated Events and 50 subscription Events. The range probe found 1,203 Event instances. It is the smoke fixture, not the largest realistic Home. Expected work is O(retained CalendarDay rows + their items) to restore/map and serialize on unmount, plus existing bounded chunk refreshes. A realistic-size snapshot byte/CPU/RSS measurement is still missing.
Visual evidence
The last local capture set used production builds with real Events, macOS platform emulation, 1440/820/390 px and both themes. It contains 45 grid Events at 1440 px and 80 overflow-list Events at 820/390 px. It is evidence of resting render structure, not accepted warm-return proof.
At 1440 light, Week nodes were 3,783 → 993. Total page listeners were 923 → 702; the Calendar-minus-Mail listener delta was 443 → 221. At 820/390, Week nodes remained 472. These counts belong to the saved capture set.
Five responsive full-image comparisons have zero changed pixels. Desktop dark has four changed pixels, all at the sidebar top-left control (x19–33, y19–33), with maximum RGB-channel change 6; Calendar pixels are unchanged.
The pointer capture has 1,188 changed pixels: 441 in sidebar Tag counts, 716 in the all-day row, and 31 at the current-time label. The images show different completed background data: the candidate has an all-day Task and higher Tag counts. This is a capture-state mismatch, not an explained visual-equivalence pass. The shortcut capture has 70,892 changed pixels, all in the Top row (x287–1359, y0–99); Calendar content has zero changed pixels. Most changes are one RGB step; the maximum is 49. Shared blur/transition capture state needs review. No pixel tolerance was raised. Both candidate interaction captures report zero focus-visible elements.
The visual reviewer remains the orchestrator. Captures are attached to #1557 below. The new SPA-only capture path must be rerun before claiming visual parity for snapshot return.
UX gaps closed
UX gaps left / known gaps
fe6617f13; no additional merge was made on resume, in line with the brief's final no-merges instruction. Current origin/dev at resume was016bf3d5752999223d08cd5d04a6618a50898ad5.Gates on resume (verbatim excerpts)
cd apps/web && bun run check:The command terminated with tool exit code 143 before a Svelte result or the wrapper's
exit=line. This is not a pass. Earlier successful check logs remain as historical evidence only.cd apps/web && bun run test -- --maxWorkers=2:The command stopped before Vitest. The old breadcrumb button is absent from current origin/dev. No guard, ratchet or test expectation was changed to hide this failure.
Focused Calendar, data, route, snapshot and ModeHeader Vitest run:
bun test bench/tab-switch.test.mjsafter the resume repair:No Rust gates ran because no Rust source changed. Module and non-obvious function comments were reread. No existing assertion or fixture expectation was relaxed.
Decisions
Remaining verification
After the orchestrator resolves the current origin/dev changes, run
cd apps/web && bun run checkandbun run test -- --maxWorkers=2. They must prove both the design guard and Svelte/Vitest gates pass.Run
bun bench/tab-switch.mjs --vm-browser --reuse-fixture --aa --ab-before <parent-production-build> --ab-after <same-parent-production-build> --ab-followup <candidate-production-build> --runs 9 --conditions warm --engines chromium --viewports 1440 --themes light --tabs calendar,mail,files --calendar-activation --ab-cells mail:calendar,files:calendar,calendar:files --json <report>with the strict delayed-device qualification andperf-run --quiesce. Require valid A/A N, at least max(10%, 2N) median paired Mail → Calendar improvement, at least 7/9 improved pairs and no cell p95 increase above that threshold. Do not use read-only appearance or diagnostic flags for acceptance.Run
bun bench/tab-switch.mjs --local --reuse-fixture --runs 9 --conditions warm --engines chromium --viewports 1440,820,390 --themes light,dark --tabs calendar,mail,files --calendar-activation --ab-cells mail:calendar,files:calendar,calendar:files --ab-visual-only --ab-before <parent> --ab-after <candidate> --json <report> --screenshots <directory>with the local fixture state selected byTAB_SWITCH_FIXTURE_STATE_PATH. It must prove equal loaded data and viewports, preserved warm snapshot state, no mouse/shortcut rings, and explain every pixel difference. Run the focused Calendar interaction regression tests. No API changed, so this job did not run an API adversarial matrix.No pushes, deploys, new merges, issue closure or macOS VM access occurred on resume. The perf VM reported
freeon the final read-only check.Attached last capture set
Head and cleanup
Final branch head:
6cf6fa03fec38d89737d5465ac54b95e75a3ed99(clean worktree).Implementation head:
47d9cf42f527d44885b35c010fac5e470ade29f2. The documentation commit follows it; the final issue comment records that full head.cargo clean(verbatim):Removed
apps/web/build,apps/web/.svelte-kitand the archived parent/candidate web build directories. Kept review images and raw evidence in the ignored artifacts directory. No credentials were displayed.Started calact10 on
job/calact9at6cf6fa03fec38d89737d5465ac54b95e75a3ed99; merge base with fetchedorigin/devisb8bb41f211312dfdf7accf21c132b5b5acf3636c(origin/devis016bf3d5752999223d08cd5d04a6618a50898ad5). I am reconciling the candidate with current dev first, preserving dev's ModeHeader, then will run the requested gates, real Tab-switch screenshot capture, and one qualified perf-VM A/A followed by A/B only if A/A noise passes.Finding: after the dev merge,
viewSnapshotCachewas User-keyed and cleared oncalternal:session-ended,calternal:auth-changed,calternal:mode-caches-clearandcalternal:plugins-changed, but not oncalternal:access-changedor the immediatecalternal:session-expiredsignal.apps/web/src/lib/files/api.tsandlive.tsemitcalternal:access-changed; DESIGN §59 requires Share revocation to invalidate retained data. I am adding both invalidations and a regression test that dispatches the browser events against the shared cache.