From 02c2963fa6415ac775e008e4c0aed97bfaf274b7 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Sun, 18 Oct 2026 10:26:37 +0200 Subject: [PATCH 1/4] chore(ci): refresh browser shard weights after the narrow callout split Browser shard 2 drifted from the 840 s qualification bar to its 900 s job bound (887 s on main 7f22bb6ac, 917 s cancelled on a ready PR). Refresh measured weights from successful main run 39109891338 attempt 1, which includes the #2393 split. Scored by the fresh weights, the slowest project per shard drops from 628 s to 573 s on both shards. Closes #2414 Co-Authored-By: Claude Opus 5.5 --- scripts/browser-shard-costs.json | 633 +++++++++++++++---------------- 1 file changed, 316 insertions(+), 317 deletions(-) diff --git a/scripts/browser-shard-costs.json b/scripts/browser-shard-costs.json index 8a88ec474..208e05d83 100644 --- a/scripts/browser-shard-costs.json +++ b/scripts/browser-shard-costs.json @@ -1,19 +1,18 @@ { "measurements": { "browser": { - "head": "d0a65205db16fc05486e6a0cf46ef61650a6ca6f", - "checkout": "e84e683b01b9cd4a01f3195d36e6f01942dce42a", - "tree": "6fb1e0e35a2751b15cb897ab3baf0d712cfdba57", + "head": "7f22bb6ac2892360f3a5c4d3a1f93d9997af43e8", + "checkout": "7f22bb6ac2892360f3a5c4d3a1f93d9997af43e8", + "tree": "27c3c0e90cae100b8581d03594d468aeadd2b6b9", "parents": [ - "2a0b77f675da2f01c32adba3f4920650a5ee09fa", - "d0a65205db16fc05486e6a0cf46ef61650a6ca6f" + "cf4098cb9bfe7a22c476fba727f52ff6fb0db6d2" ], "image": "mcr.microsoft.com/playwright@sha256:eff16c30e6f3f4af0a03fa4b706120d5e9b0891c344a27d64559aff5900a4a27", - "run": 39062246171, + "run": 39109891338, "attempt": 1, "jobs": [ - 117482652349, - 117482652319 + 117623667345, + 117623667361 ], "units": "seconds", "aggregation": "median reported project/file elapsed time", @@ -40,280 +39,280 @@ } }, "seconds": { - "diagrams-chromium::packages/ui-react/tests/browser/diagrams-axis.layout.tsx": 27.858, - "diagrams-chromium::packages/ui-react/tests/browser/diagrams-callouts.layout.tsx": 71.667, - "diagrams-chromium::packages/ui-react/tests/browser/diagrams-export.layout.tsx": 38.395, - "diagrams-chromium::packages/ui-react/tests/browser/diagrams-node-link.layout.tsx": 42.012, - "diagrams-chromium::packages/ui-react/tests/browser/diagrams-positional.layout.tsx": 33.227, - "diagrams-chromium::packages/ui-react/tests/browser/diagrams-renderer.layout.tsx": 17.272, - "diagrams-webkit::packages/ui-react/tests/browser/diagrams-axis.layout.tsx": 27.64, - "diagrams-webkit::packages/ui-react/tests/browser/diagrams-callouts.layout.tsx": 118.544, - "diagrams-webkit::packages/ui-react/tests/browser/diagrams-export.layout.tsx": 43.645, - "diagrams-webkit::packages/ui-react/tests/browser/diagrams-node-link.layout.tsx": 48.89, - "diagrams-webkit::packages/ui-react/tests/browser/diagrams-positional.layout.tsx": 35.063, - "diagrams-webkit::packages/ui-react/tests/browser/diagrams-renderer.layout.tsx": 29.729, - "dictation::packages/ui-kit/tests/visual/dictation-panel.visual.tsx": 102.724, - "keyboard-hints-live::packages/ui-react/tests/browser/keyboard-hints.pointer.tsx": 9.445, - "module-settings::packages/ui-kit/tests/visual/module-settings.visual.tsx": 48.396, - "rail-coarse::packages/ui-kit/tests/visual/button-hover-contrast.visual.tsx": 5.839, - "rail-coarse::packages/ui-kit/tests/visual/native-buttons.visual.tsx": 15.992, - "rail-coarse::packages/ui-kit/tests/visual/overlay-targets.visual.tsx": 4.961, - "rail-coarse::packages/ui-kit/tests/visual/palette-reasons.visual.tsx": 0.757, - "rail-coarse::packages/ui-kit/tests/visual/pending-follow-ups.visual.tsx": 2.593, - "rail-coarse::packages/ui-kit/tests/visual/session-strip.visual.tsx": 8.487, - "rail-coarse::packages/ui-kit/tests/visual/side-rail-targets.visual.tsx": 6.345, - "rail-coarse::packages/ui-react/tests/browser/desktop-navigation.pointer.tsx": 67.724, - "rail-coarse::packages/ui-react/tests/browser/destination-press.pointer.tsx": 62.82, - "rail-coarse::packages/ui-react/tests/browser/dictation-notice.pointer.tsx": 21.127, - "rail-coarse::packages/ui-react/tests/browser/keyboard-hints.pointer.tsx": 2.163, - "rail-coarse::packages/ui-react/tests/browser/navigation-reach.pointer.tsx": 381.348, - "rail-coarse::packages/ui-react/tests/browser/overlay-stacking.pointer.tsx": 81.773, - "rail-coarse::packages/ui-react/tests/browser/phone-navigation.pointer.tsx": 94.842, - "rail-coarse::packages/ui-react/tests/browser/recordings-tray.offline.tsx": 119.094, - "rail-coarse::packages/ui-react/tests/browser/session-drafts.pointer.tsx": 136.627, - "rail-coarse::packages/ui-react/tests/browser/session-profile.pointer.tsx": 3.404, - "rail-coarse::packages/ui-react/tests/browser/turn-budget.pointer.tsx": 1.536, - "rail-coarse::packages/ui-react/tests/browser/working-sessions.pointer.tsx": 58.907, - "rail-fine::packages/ui-kit/tests/visual/button-hover-contrast.visual.tsx": 5.888, - "rail-fine::packages/ui-kit/tests/visual/native-buttons.visual.tsx": 17.773, - "rail-fine::packages/ui-kit/tests/visual/overlay-targets.visual.tsx": 1.27, - "rail-fine::packages/ui-kit/tests/visual/palette-reasons.visual.tsx": 0.958, - "rail-fine::packages/ui-kit/tests/visual/pending-follow-ups.visual.tsx": 1.755, - "rail-fine::packages/ui-kit/tests/visual/session-strip.visual.tsx": 6.735, - "rail-fine::packages/ui-kit/tests/visual/side-rail-targets.visual.tsx": 4.706, - "rail-fine::packages/ui-react/tests/browser/desktop-navigation.pointer.tsx": 53.824, - "rail-fine::packages/ui-react/tests/browser/destination-press.pointer.tsx": 62.502, - "rail-fine::packages/ui-react/tests/browser/dictation-notice.pointer.tsx": 21.43, - "rail-fine::packages/ui-react/tests/browser/keyboard-hints.pointer.tsx": 1.896, - "rail-fine::packages/ui-react/tests/browser/navigation-reach.pointer.tsx": 352.751, - "rail-fine::packages/ui-react/tests/browser/overlay-stacking.pointer.tsx": 51.473, - "rail-fine::packages/ui-react/tests/browser/phone-navigation.pointer.tsx": 82.485, - "rail-fine::packages/ui-react/tests/browser/recordings-tray.offline.tsx": 137.145, - "rail-fine::packages/ui-react/tests/browser/session-drafts.pointer.tsx": 122.854, - "rail-fine::packages/ui-react/tests/browser/session-profile.pointer.tsx": 3.704, - "rail-fine::packages/ui-react/tests/browser/turn-budget.pointer.tsx": 1.751, - "rail-fine::packages/ui-react/tests/browser/working-sessions.pointer.tsx": 70.337, - "rail-mixed::packages/ui-kit/tests/visual/button-hover-contrast.visual.tsx": 5.942, - "rail-mixed::packages/ui-kit/tests/visual/native-buttons.visual.tsx": 15.999, - "rail-mixed::packages/ui-kit/tests/visual/overlay-targets.visual.tsx": 5.415, - "rail-mixed::packages/ui-kit/tests/visual/palette-reasons.visual.tsx": 0.785, - "rail-mixed::packages/ui-kit/tests/visual/pending-follow-ups.visual.tsx": 2.706, - "rail-mixed::packages/ui-kit/tests/visual/session-strip.visual.tsx": 8.907, - "rail-mixed::packages/ui-kit/tests/visual/side-rail-targets.visual.tsx": 8.813, - "rail-mixed::packages/ui-react/tests/browser/desktop-navigation.pointer.tsx": 67.089, - "rail-mixed::packages/ui-react/tests/browser/destination-press.pointer.tsx": 59.844, - "rail-mixed::packages/ui-react/tests/browser/dictation-notice.pointer.tsx": 21.668, - "rail-mixed::packages/ui-react/tests/browser/keyboard-hints.pointer.tsx": 1.646, - "rail-mixed::packages/ui-react/tests/browser/navigation-reach.pointer.tsx": 472.35, - "rail-mixed::packages/ui-react/tests/browser/overlay-stacking.pointer.tsx": 28.415, - "rail-mixed::packages/ui-react/tests/browser/phone-navigation.pointer.tsx": 96.783, - "rail-mixed::packages/ui-react/tests/browser/recordings-tray.offline.tsx": 125.378, - "rail-mixed::packages/ui-react/tests/browser/session-drafts.pointer.tsx": 90.654, - "rail-mixed::packages/ui-react/tests/browser/session-profile.pointer.tsx": 3.317, - "rail-mixed::packages/ui-react/tests/browser/turn-budget.pointer.tsx": 1.984, - "rail-mixed::packages/ui-react/tests/browser/working-sessions.pointer.tsx": 80.883, - "rank-footer-touch::packages/ui-kit/tests/visual/rank-footer-touch.visual.tsx": 29.414, - "storybook-light::packages/ui-kit/stories/agents/AgentOrbit.stories.tsx": 2.175, - "storybook-light::packages/ui-kit/stories/agents/AgentRunCard.stories.tsx": 2.153, - "storybook-light::packages/ui-kit/stories/agents/GraphView.stories.tsx": 3.222, - "storybook-light::packages/ui-kit/stories/agents/LaneChart.stories.tsx": 2.267, - "storybook-light::packages/ui-kit/stories/blocks/CodeBlock.stories.tsx": 0.807, - "storybook-light::packages/ui-kit/stories/blocks/ContactCard.stories.tsx": 2.191, - "storybook-light::packages/ui-kit/stories/blocks/Disclosure.stories.tsx": 2.81, - "storybook-light::packages/ui-kit/stories/blocks/FeedbackRow.stories.tsx": 2.096, - "storybook-light::packages/ui-kit/stories/blocks/InPrint.stories.tsx": 3.208, - "storybook-light::packages/ui-kit/stories/blocks/LinkPreviewCard.stories.tsx": 4.338, - "storybook-light::packages/ui-kit/stories/blocks/MapView.stories.tsx": 8.6, - "storybook-light::packages/ui-kit/stories/blocks/PlaceMap.stories.tsx": 6.446, - "storybook-light::packages/ui-kit/stories/blocks/QuoteCard.stories.tsx": 1.585, - "storybook-light::packages/ui-kit/stories/blocks/ScheduleList.stories.tsx": 1.26, - "storybook-light::packages/ui-kit/stories/blocks/StatTiles.stories.tsx": 1.443, - "storybook-light::packages/ui-kit/stories/blocks/StepList.stories.tsx": 1.709, - "storybook-light::packages/ui-kit/stories/blocks/TimelineList.stories.tsx": 1.391, - "storybook-light::packages/ui-kit/stories/blocks/TrackerPillList.stories.tsx": 3.619, - "storybook-light::packages/ui-kit/stories/blocks/TrackMap.stories.tsx": 2.342, - "storybook-light::packages/ui-kit/stories/blocks/TrendChart.stories.tsx": 1.902, - "storybook-light::packages/ui-kit/stories/chrome/BottomSheet.stories.tsx": 1.944, - "storybook-light::packages/ui-kit/stories/chrome/Composer.stories.tsx": 8.924, - "storybook-light::packages/ui-kit/stories/chrome/ComposerRow.stories.tsx": 1.584, - "storybook-light::packages/ui-kit/stories/chrome/DiscButton.stories.tsx": 3.02, - "storybook-light::packages/ui-kit/stories/chrome/MessageBubble.stories.tsx": 1.695, - "storybook-light::packages/ui-kit/stories/chrome/ModelPicker.stories.tsx": 1.824, - "storybook-light::packages/ui-kit/stories/chrome/Overlay.stories.tsx": 1.684, - "storybook-light::packages/ui-kit/stories/chrome/PendingFollowUps.stories.tsx": 2.624, - "storybook-light::packages/ui-kit/stories/chrome/PhoneFrame.stories.tsx": 2.379, - "storybook-light::packages/ui-kit/stories/chrome/ScreenBody.stories.tsx": 2.665, - "storybook-light::packages/ui-kit/stories/chrome/ScreenHeader.stories.tsx": 1.6, - "storybook-light::packages/ui-kit/stories/chrome/SessionStrip.stories.tsx": 2.725, - "storybook-light::packages/ui-kit/stories/chrome/TabBar.stories.tsx": 4.643, - "storybook-light::packages/ui-kit/stories/conversation/AccountTheme.stories.tsx": 6.216, - "storybook-light::packages/ui-kit/stories/conversation/AttachmentRow.stories.tsx": 2.229, - "storybook-light::packages/ui-kit/stories/conversation/CodeFenceTheme.stories.tsx": 1.484, - "storybook-light::packages/ui-kit/stories/conversation/ComparisonTable.stories.tsx": 1.655, - "storybook-light::packages/ui-kit/stories/conversation/ComposerTheme.stories.tsx": 2.621, - "storybook-light::packages/ui-kit/stories/conversation/DigestCard.stories.tsx": 1.238, - "storybook-light::packages/ui-kit/stories/conversation/EmptyState.stories.tsx": 1.875, - "storybook-light::packages/ui-kit/stories/conversation/GraphUnavailable.stories.tsx": 2.205, - "storybook-light::packages/ui-kit/stories/conversation/GroupedQuestionExchange.stories.tsx": 3.728, - "storybook-light::packages/ui-kit/stories/conversation/InlineToast.stories.tsx": 2.421, - "storybook-light::packages/ui-kit/stories/conversation/JournalTheme.stories.tsx": 4.926, - "storybook-light::packages/ui-kit/stories/conversation/RelatedFiles.stories.tsx": 1.869, - "storybook-light::packages/ui-kit/stories/conversation/SessionTheme.stories.tsx": 1.836, - "storybook-light::packages/ui-kit/stories/conversation/StreamingAnswer.stories.tsx": 3.722, - "storybook-light::packages/ui-kit/stories/conversation/SuggestionChips.stories.tsx": 2.918, - "storybook-light::packages/ui-kit/stories/conversation/TurnErrorCard.stories.tsx": 5.028, - "storybook-light::packages/ui-kit/stories/conversation/TurnErrorReview.stories.tsx": 1.504, - "storybook-light::packages/ui-kit/stories/decisions/ActionCard.stories.tsx": 4.461, - "storybook-light::packages/ui-kit/stories/decisions/ApprovalCard.stories.tsx": 2.534, - "storybook-light::packages/ui-kit/stories/decisions/AskUserCard.stories.tsx": 6.487, - "storybook-light::packages/ui-kit/stories/decisions/AskUserFormCard.stories.tsx": 10.586, - "storybook-light::packages/ui-kit/stories/decisions/AskUserRankCard.stories.tsx": 7.629, - "storybook-light::packages/ui-kit/stories/decisions/DispositionBar.stories.tsx": 2.029, - "storybook-light::packages/ui-kit/stories/decisions/EffectPreview.stories.tsx": 1.793, - "storybook-light::packages/ui-kit/stories/decisions/HygieneBlocker.stories.tsx": 0.458, - "storybook-light::packages/ui-kit/stories/decisions/HygieneCard.stories.tsx": 3.079, - "storybook-light::packages/ui-kit/stories/decisions/HygieneEnd.stories.tsx": 0.579, - "storybook-light::packages/ui-kit/stories/decisions/NotificationCard.stories.tsx": 1.909, - "storybook-light::packages/ui-kit/stories/decisions/QuestionAndMask.stories.tsx": 31.434, - "storybook-light::packages/ui-kit/stories/desktop/CommandPalette.stories.tsx": 5.714, - "storybook-light::packages/ui-kit/stories/desktop/SideRail.stories.tsx": 9.975, - "storybook-light::packages/ui-kit/stories/evidence/BarList.stories.tsx": 1.716, - "storybook-light::packages/ui-kit/stories/evidence/DataTable.stories.tsx": 1.383, - "storybook-light::packages/ui-kit/stories/evidence/Receipt.stories.tsx": 3.633, - "storybook-light::packages/ui-kit/stories/evidence/SearchResultCard.stories.tsx": 3.593, - "storybook-light::packages/ui-kit/stories/evidence/TraceSteps.stories.tsx": 1.509, - "storybook-light::packages/ui-kit/stories/primitives/BrandMark.stories.tsx": 1.08, - "storybook-light::packages/ui-kit/stories/primitives/Button.stories.tsx": 2.209, - "storybook-light::packages/ui-kit/stories/primitives/Callout.stories.tsx": 1.616, - "storybook-light::packages/ui-kit/stories/primitives/Chip.stories.tsx": 1.855, - "storybook-light::packages/ui-kit/stories/primitives/DiffBlock.stories.tsx": 1.391, - "storybook-light::packages/ui-kit/stories/primitives/Icon.stories.tsx": 1.747, - "storybook-light::packages/ui-kit/stories/primitives/IconButton.stories.tsx": 4.21, - "storybook-light::packages/ui-kit/stories/primitives/Label.stories.tsx": 0.895, - "storybook-light::packages/ui-kit/stories/primitives/Meter.stories.tsx": 1.869, - "storybook-light::packages/ui-kit/stories/primitives/PathRef.stories.tsx": 1.282, - "storybook-light::packages/ui-kit/stories/primitives/StatusDot.stories.tsx": 0.876, - "storybook-light::packages/ui-kit/stories/primitives/Surface.stories.tsx": 2.225, - "storybook-light::packages/ui-kit/stories/primitives/TextButton.stories.tsx": 5.641, - "storybook-light::packages/ui-kit/stories/primitives/Toggle.stories.tsx": 2.001, - "storybook-light::packages/ui-kit/stories/rows/ChoiceOption.stories.tsx": 3.173, - "storybook-light::packages/ui-kit/stories/rows/FileRow.stories.tsx": 4.552, - "storybook-light::packages/ui-kit/stories/rows/FilterRow.stories.tsx": 3.265, - "storybook-light::packages/ui-kit/stories/rows/ListRow.stories.tsx": 2.348, - "storybook-light::packages/ui-kit/stories/rows/QueueItemRow.stories.tsx": 2.722, - "storybook-light::packages/ui-kit/stories/rows/RecordingRow.stories.tsx": 1.774, - "storybook-light::packages/ui-kit/stories/rules/Keyboard.stories.tsx": 2.067, - "storybook-light::packages/ui-kit/stories/rules/NonNegotiables.stories.tsx": 2.691, - "storybook-light::packages/ui-kit/stories/screens/ActionsTriage.stories.tsx": 3.475, - "storybook-light::packages/ui-kit/stories/screens/ChatAnswer.stories.tsx": 4.667, - "storybook-light::packages/ui-kit/stories/screens/FileViewer.stories.tsx": 3.284, - "storybook-light::packages/ui-kit/stories/screens/FirstRun.stories.tsx": 4.315, - "storybook-light::packages/ui-kit/stories/screens/MorningDigest.stories.tsx": 3.208, - "storybook-light::packages/ui-kit/stories/screens/RunDetail.stories.tsx": 2.842, - "storybook-light::packages/ui-kit/stories/screens/WeeklyReview.stories.tsx": 3.861, - "storybook-light::packages/ui-kit/stories/states/GhostSweep.stories.tsx": 2.435, - "storybook-light::packages/ui-kit/stories/states/Placeholder.stories.tsx": 6.112, - "storybook::packages/ui-kit/stories/agents/AgentOrbit.stories.tsx": 1.949, - "storybook::packages/ui-kit/stories/agents/AgentRunCard.stories.tsx": 2.102, - "storybook::packages/ui-kit/stories/agents/GraphView.stories.tsx": 2.637, - "storybook::packages/ui-kit/stories/agents/LaneChart.stories.tsx": 2.213, - "storybook::packages/ui-kit/stories/blocks/CodeBlock.stories.tsx": 0.913, - "storybook::packages/ui-kit/stories/blocks/ContactCard.stories.tsx": 1.869, - "storybook::packages/ui-kit/stories/blocks/Disclosure.stories.tsx": 2.651, - "storybook::packages/ui-kit/stories/blocks/FeedbackRow.stories.tsx": 2.452, - "storybook::packages/ui-kit/stories/blocks/InPrint.stories.tsx": 3.688, - "storybook::packages/ui-kit/stories/blocks/LinkPreviewCard.stories.tsx": 5.114, - "storybook::packages/ui-kit/stories/blocks/MapView.stories.tsx": 7.089, - "storybook::packages/ui-kit/stories/blocks/PlaceMap.stories.tsx": 6.692, - "storybook::packages/ui-kit/stories/blocks/QuoteCard.stories.tsx": 1.579, - "storybook::packages/ui-kit/stories/blocks/ScheduleList.stories.tsx": 1.166, - "storybook::packages/ui-kit/stories/blocks/StatTiles.stories.tsx": 1.575, - "storybook::packages/ui-kit/stories/blocks/StepList.stories.tsx": 1.727, - "storybook::packages/ui-kit/stories/blocks/TimelineList.stories.tsx": 0.771, - "storybook::packages/ui-kit/stories/blocks/TrackerPillList.stories.tsx": 3.712, - "storybook::packages/ui-kit/stories/blocks/TrackMap.stories.tsx": 2.428, - "storybook::packages/ui-kit/stories/blocks/TrendChart.stories.tsx": 1.53, - "storybook::packages/ui-kit/stories/chrome/BottomSheet.stories.tsx": 1.942, - "storybook::packages/ui-kit/stories/chrome/Composer.stories.tsx": 8.41, - "storybook::packages/ui-kit/stories/chrome/ComposerRow.stories.tsx": 1.788, - "storybook::packages/ui-kit/stories/chrome/DiscButton.stories.tsx": 2.554, - "storybook::packages/ui-kit/stories/chrome/MessageBubble.stories.tsx": 1.885, - "storybook::packages/ui-kit/stories/chrome/ModelPicker.stories.tsx": 1.925, - "storybook::packages/ui-kit/stories/chrome/Overlay.stories.tsx": 1.499, - "storybook::packages/ui-kit/stories/chrome/PendingFollowUps.stories.tsx": 2.725, - "storybook::packages/ui-kit/stories/chrome/PhoneFrame.stories.tsx": 2.431, - "storybook::packages/ui-kit/stories/chrome/ScreenBody.stories.tsx": 2.639, - "storybook::packages/ui-kit/stories/chrome/ScreenHeader.stories.tsx": 2.326, - "storybook::packages/ui-kit/stories/chrome/SessionStrip.stories.tsx": 3.58, - "storybook::packages/ui-kit/stories/chrome/TabBar.stories.tsx": 3.535, - "storybook::packages/ui-kit/stories/conversation/AccountTheme.stories.tsx": 5.261, - "storybook::packages/ui-kit/stories/conversation/AttachmentRow.stories.tsx": 2.62, - "storybook::packages/ui-kit/stories/conversation/CodeFenceTheme.stories.tsx": 1.284, - "storybook::packages/ui-kit/stories/conversation/ComparisonTable.stories.tsx": 1.768, - "storybook::packages/ui-kit/stories/conversation/ComposerTheme.stories.tsx": 2.4, - "storybook::packages/ui-kit/stories/conversation/DigestCard.stories.tsx": 1.57, - "storybook::packages/ui-kit/stories/conversation/EmptyState.stories.tsx": 1.814, - "storybook::packages/ui-kit/stories/conversation/GraphUnavailable.stories.tsx": 2.31, - "storybook::packages/ui-kit/stories/conversation/GroupedQuestionExchange.stories.tsx": 3.701, - "storybook::packages/ui-kit/stories/conversation/InlineToast.stories.tsx": 2.399, - "storybook::packages/ui-kit/stories/conversation/JournalTheme.stories.tsx": 4.974, - "storybook::packages/ui-kit/stories/conversation/RelatedFiles.stories.tsx": 2.037, - "storybook::packages/ui-kit/stories/conversation/SessionTheme.stories.tsx": 1.64, - "storybook::packages/ui-kit/stories/conversation/StreamingAnswer.stories.tsx": 3.211, - "storybook::packages/ui-kit/stories/conversation/SuggestionChips.stories.tsx": 3.394, - "storybook::packages/ui-kit/stories/conversation/TurnErrorCard.stories.tsx": 4.913, - "storybook::packages/ui-kit/stories/conversation/TurnErrorReview.stories.tsx": 1.173, - "storybook::packages/ui-kit/stories/decisions/ActionCard.stories.tsx": 4.351, - "storybook::packages/ui-kit/stories/decisions/ApprovalCard.stories.tsx": 2.503, - "storybook::packages/ui-kit/stories/decisions/AskUserCard.stories.tsx": 5.886, - "storybook::packages/ui-kit/stories/decisions/AskUserFormCard.stories.tsx": 9.263, - "storybook::packages/ui-kit/stories/decisions/AskUserRankCard.stories.tsx": 7.292, - "storybook::packages/ui-kit/stories/decisions/DispositionBar.stories.tsx": 1.53, - "storybook::packages/ui-kit/stories/decisions/EffectPreview.stories.tsx": 1.776, - "storybook::packages/ui-kit/stories/decisions/HygieneBlocker.stories.tsx": 0.854, - "storybook::packages/ui-kit/stories/decisions/HygieneCard.stories.tsx": 2.95, - "storybook::packages/ui-kit/stories/decisions/HygieneEnd.stories.tsx": 0.752, - "storybook::packages/ui-kit/stories/decisions/NotificationCard.stories.tsx": 1.62, - "storybook::packages/ui-kit/stories/decisions/QuestionAndMask.stories.tsx": 30.024, - "storybook::packages/ui-kit/stories/desktop/CommandPalette.stories.tsx": 6.566, - "storybook::packages/ui-kit/stories/desktop/SideRail.stories.tsx": 11.536, - "storybook::packages/ui-kit/stories/evidence/BarList.stories.tsx": 2.21, - "storybook::packages/ui-kit/stories/evidence/DataTable.stories.tsx": 1.354, - "storybook::packages/ui-kit/stories/evidence/Receipt.stories.tsx": 3.615, - "storybook::packages/ui-kit/stories/evidence/SearchResultCard.stories.tsx": 3.038, - "storybook::packages/ui-kit/stories/evidence/TraceSteps.stories.tsx": 1.433, - "storybook::packages/ui-kit/stories/primitives/BrandMark.stories.tsx": 1.04, - "storybook::packages/ui-kit/stories/primitives/Button.stories.tsx": 2.428, - "storybook::packages/ui-kit/stories/primitives/Callout.stories.tsx": 1.443, - "storybook::packages/ui-kit/stories/primitives/Chip.stories.tsx": 2.183, - "storybook::packages/ui-kit/stories/primitives/DiffBlock.stories.tsx": 1.637, - "storybook::packages/ui-kit/stories/primitives/Icon.stories.tsx": 1.667, - "storybook::packages/ui-kit/stories/primitives/IconButton.stories.tsx": 4.014, - "storybook::packages/ui-kit/stories/primitives/Label.stories.tsx": 1.381, - "storybook::packages/ui-kit/stories/primitives/Meter.stories.tsx": 1.53, - "storybook::packages/ui-kit/stories/primitives/PathRef.stories.tsx": 1.527, - "storybook::packages/ui-kit/stories/primitives/StatusDot.stories.tsx": 0.635, - "storybook::packages/ui-kit/stories/primitives/Surface.stories.tsx": 3.235, - "storybook::packages/ui-kit/stories/primitives/TextButton.stories.tsx": 4.765, - "storybook::packages/ui-kit/stories/primitives/Toggle.stories.tsx": 1.587, - "storybook::packages/ui-kit/stories/rows/ChoiceOption.stories.tsx": 3.609, - "storybook::packages/ui-kit/stories/rows/FileRow.stories.tsx": 3.395, - "storybook::packages/ui-kit/stories/rows/FilterRow.stories.tsx": 2.76, - "storybook::packages/ui-kit/stories/rows/ListRow.stories.tsx": 2.513, - "storybook::packages/ui-kit/stories/rows/QueueItemRow.stories.tsx": 3.185, - "storybook::packages/ui-kit/stories/rows/RecordingRow.stories.tsx": 1.611, - "storybook::packages/ui-kit/stories/rules/Keyboard.stories.tsx": 2.071, - "storybook::packages/ui-kit/stories/rules/NonNegotiables.stories.tsx": 3.457, - "storybook::packages/ui-kit/stories/screens/ActionsTriage.stories.tsx": 2.886, - "storybook::packages/ui-kit/stories/screens/ChatAnswer.stories.tsx": 4.259, - "storybook::packages/ui-kit/stories/screens/FileViewer.stories.tsx": 3.456, - "storybook::packages/ui-kit/stories/screens/FirstRun.stories.tsx": 2.791, - "storybook::packages/ui-kit/stories/screens/MorningDigest.stories.tsx": 3.773, - "storybook::packages/ui-kit/stories/screens/RunDetail.stories.tsx": 2.172, - "storybook::packages/ui-kit/stories/screens/WeeklyReview.stories.tsx": 3.591, - "storybook::packages/ui-kit/stories/states/GhostSweep.stories.tsx": 2.541, - "storybook::packages/ui-kit/stories/states/Placeholder.stories.tsx": 5.559, - "subjects::packages/ui-kit/tests/visual/subjects.visual.tsx": 64.963, + "diagrams-chromium::packages/ui-react/tests/browser/diagrams-axis.layout.tsx": 27.528, + "diagrams-chromium::packages/ui-react/tests/browser/diagrams-callouts.layout.tsx": 102.857, + "diagrams-chromium::packages/ui-react/tests/browser/diagrams-export.layout.tsx": 48.024, + "diagrams-chromium::packages/ui-react/tests/browser/diagrams-node-link.layout.tsx": 54.862, + "diagrams-chromium::packages/ui-react/tests/browser/diagrams-positional.layout.tsx": 37.143, + "diagrams-chromium::packages/ui-react/tests/browser/diagrams-renderer.layout.tsx": 25.349, + "diagrams-webkit::packages/ui-react/tests/browser/diagrams-axis.layout.tsx": 37.317, + "diagrams-webkit::packages/ui-react/tests/browser/diagrams-callouts.layout.tsx": 166.01, + "diagrams-webkit::packages/ui-react/tests/browser/diagrams-export.layout.tsx": 31.297, + "diagrams-webkit::packages/ui-react/tests/browser/diagrams-node-link.layout.tsx": 50.215, + "diagrams-webkit::packages/ui-react/tests/browser/diagrams-positional.layout.tsx": 41.917, + "diagrams-webkit::packages/ui-react/tests/browser/diagrams-renderer.layout.tsx": 40.988, + "dictation::packages/ui-kit/tests/visual/dictation-panel.visual.tsx": 156.739, + "keyboard-hints-live::packages/ui-react/tests/browser/keyboard-hints.pointer.tsx": 9.365, + "module-settings::packages/ui-kit/tests/visual/module-settings.visual.tsx": 52.549, + "rail-coarse::packages/ui-kit/tests/visual/button-hover-contrast.visual.tsx": 5.847, + "rail-coarse::packages/ui-kit/tests/visual/native-buttons.visual.tsx": 16.155, + "rail-coarse::packages/ui-kit/tests/visual/overlay-targets.visual.tsx": 4.814, + "rail-coarse::packages/ui-kit/tests/visual/palette-reasons.visual.tsx": 0.843, + "rail-coarse::packages/ui-kit/tests/visual/pending-follow-ups.visual.tsx": 2.693, + "rail-coarse::packages/ui-kit/tests/visual/session-strip.visual.tsx": 8.638, + "rail-coarse::packages/ui-kit/tests/visual/side-rail-targets.visual.tsx": 7.875, + "rail-coarse::packages/ui-react/tests/browser/desktop-navigation.pointer.tsx": 64.966, + "rail-coarse::packages/ui-react/tests/browser/destination-press.pointer.tsx": 67.691, + "rail-coarse::packages/ui-react/tests/browser/dictation-notice.pointer.tsx": 21.314, + "rail-coarse::packages/ui-react/tests/browser/keyboard-hints.pointer.tsx": 1.962, + "rail-coarse::packages/ui-react/tests/browser/navigation-reach.pointer.tsx": 411.57, + "rail-coarse::packages/ui-react/tests/browser/overlay-stacking.pointer.tsx": 74.771, + "rail-coarse::packages/ui-react/tests/browser/phone-navigation.pointer.tsx": 96.459, + "rail-coarse::packages/ui-react/tests/browser/recordings-tray.offline.tsx": 129.355, + "rail-coarse::packages/ui-react/tests/browser/session-drafts.pointer.tsx": 114.675, + "rail-coarse::packages/ui-react/tests/browser/session-profile.pointer.tsx": 3.837, + "rail-coarse::packages/ui-react/tests/browser/turn-budget.pointer.tsx": 1.739, + "rail-coarse::packages/ui-react/tests/browser/working-sessions.pointer.tsx": 104.656, + "rail-fine::packages/ui-kit/tests/visual/button-hover-contrast.visual.tsx": 5.897, + "rail-fine::packages/ui-kit/tests/visual/native-buttons.visual.tsx": 16.612, + "rail-fine::packages/ui-kit/tests/visual/overlay-targets.visual.tsx": 1.486, + "rail-fine::packages/ui-kit/tests/visual/palette-reasons.visual.tsx": 0.887, + "rail-fine::packages/ui-kit/tests/visual/pending-follow-ups.visual.tsx": 1.965, + "rail-fine::packages/ui-kit/tests/visual/session-strip.visual.tsx": 7.277, + "rail-fine::packages/ui-kit/tests/visual/side-rail-targets.visual.tsx": 5.621, + "rail-fine::packages/ui-react/tests/browser/desktop-navigation.pointer.tsx": 54.948, + "rail-fine::packages/ui-react/tests/browser/destination-press.pointer.tsx": 63.249, + "rail-fine::packages/ui-react/tests/browser/dictation-notice.pointer.tsx": 21.772, + "rail-fine::packages/ui-react/tests/browser/keyboard-hints.pointer.tsx": 1.864, + "rail-fine::packages/ui-react/tests/browser/navigation-reach.pointer.tsx": 481.912, + "rail-fine::packages/ui-react/tests/browser/overlay-stacking.pointer.tsx": 28.194, + "rail-fine::packages/ui-react/tests/browser/phone-navigation.pointer.tsx": 85.08, + "rail-fine::packages/ui-react/tests/browser/recordings-tray.offline.tsx": 148.397, + "rail-fine::packages/ui-react/tests/browser/session-drafts.pointer.tsx": 96.188, + "rail-fine::packages/ui-react/tests/browser/session-profile.pointer.tsx": 3.705, + "rail-fine::packages/ui-react/tests/browser/turn-budget.pointer.tsx": 1.709, + "rail-fine::packages/ui-react/tests/browser/working-sessions.pointer.tsx": 31.276, + "rail-mixed::packages/ui-kit/tests/visual/button-hover-contrast.visual.tsx": 5.916, + "rail-mixed::packages/ui-kit/tests/visual/native-buttons.visual.tsx": 18.596, + "rail-mixed::packages/ui-kit/tests/visual/overlay-targets.visual.tsx": 5.134, + "rail-mixed::packages/ui-kit/tests/visual/palette-reasons.visual.tsx": 0.742, + "rail-mixed::packages/ui-kit/tests/visual/pending-follow-ups.visual.tsx": 2.607, + "rail-mixed::packages/ui-kit/tests/visual/session-strip.visual.tsx": 9.09, + "rail-mixed::packages/ui-kit/tests/visual/side-rail-targets.visual.tsx": 7.564, + "rail-mixed::packages/ui-react/tests/browser/desktop-navigation.pointer.tsx": 69.581, + "rail-mixed::packages/ui-react/tests/browser/destination-press.pointer.tsx": 69.024, + "rail-mixed::packages/ui-react/tests/browser/dictation-notice.pointer.tsx": 21.061, + "rail-mixed::packages/ui-react/tests/browser/keyboard-hints.pointer.tsx": 1.964, + "rail-mixed::packages/ui-react/tests/browser/navigation-reach.pointer.tsx": 428.836, + "rail-mixed::packages/ui-react/tests/browser/overlay-stacking.pointer.tsx": 89.283, + "rail-mixed::packages/ui-react/tests/browser/phone-navigation.pointer.tsx": 99.204, + "rail-mixed::packages/ui-react/tests/browser/recordings-tray.offline.tsx": 162.47, + "rail-mixed::packages/ui-react/tests/browser/session-drafts.pointer.tsx": 111.232, + "rail-mixed::packages/ui-react/tests/browser/session-profile.pointer.tsx": 3.899, + "rail-mixed::packages/ui-react/tests/browser/turn-budget.pointer.tsx": 2.023, + "rail-mixed::packages/ui-react/tests/browser/working-sessions.pointer.tsx": 37.514, + "rank-footer-touch::packages/ui-kit/tests/visual/rank-footer-touch.visual.tsx": 35.274, + "storybook-light::packages/ui-kit/stories/agents/AgentOrbit.stories.tsx": 1.896, + "storybook-light::packages/ui-kit/stories/agents/AgentRunCard.stories.tsx": 2.55, + "storybook-light::packages/ui-kit/stories/agents/GraphView.stories.tsx": 2.817, + "storybook-light::packages/ui-kit/stories/agents/LaneChart.stories.tsx": 1.369, + "storybook-light::packages/ui-kit/stories/blocks/CodeBlock.stories.tsx": 1.219, + "storybook-light::packages/ui-kit/stories/blocks/ContactCard.stories.tsx": 1.583, + "storybook-light::packages/ui-kit/stories/blocks/Disclosure.stories.tsx": 2.291, + "storybook-light::packages/ui-kit/stories/blocks/FeedbackRow.stories.tsx": 1.262, + "storybook-light::packages/ui-kit/stories/blocks/InPrint.stories.tsx": 3.766, + "storybook-light::packages/ui-kit/stories/blocks/LinkPreviewCard.stories.tsx": 7.373, + "storybook-light::packages/ui-kit/stories/blocks/MapView.stories.tsx": 13.504, + "storybook-light::packages/ui-kit/stories/blocks/PlaceMap.stories.tsx": 8.756, + "storybook-light::packages/ui-kit/stories/blocks/QuoteCard.stories.tsx": 2.163, + "storybook-light::packages/ui-kit/stories/blocks/ScheduleList.stories.tsx": 1.704, + "storybook-light::packages/ui-kit/stories/blocks/StatTiles.stories.tsx": 2.344, + "storybook-light::packages/ui-kit/stories/blocks/StepList.stories.tsx": 1.048, + "storybook-light::packages/ui-kit/stories/blocks/TimelineList.stories.tsx": 2.058, + "storybook-light::packages/ui-kit/stories/blocks/TrackerPillList.stories.tsx": 2.28, + "storybook-light::packages/ui-kit/stories/blocks/TrackMap.stories.tsx": 1.792, + "storybook-light::packages/ui-kit/stories/blocks/TrendChart.stories.tsx": 1.354, + "storybook-light::packages/ui-kit/stories/chrome/BottomSheet.stories.tsx": 1.428, + "storybook-light::packages/ui-kit/stories/chrome/Composer.stories.tsx": 5.936, + "storybook-light::packages/ui-kit/stories/chrome/ComposerRow.stories.tsx": 2.444, + "storybook-light::packages/ui-kit/stories/chrome/DiscButton.stories.tsx": 3.213, + "storybook-light::packages/ui-kit/stories/chrome/MessageBubble.stories.tsx": 1.393, + "storybook-light::packages/ui-kit/stories/chrome/ModelPicker.stories.tsx": 1.591, + "storybook-light::packages/ui-kit/stories/chrome/Overlay.stories.tsx": 1.479, + "storybook-light::packages/ui-kit/stories/chrome/PendingFollowUps.stories.tsx": 3.286, + "storybook-light::packages/ui-kit/stories/chrome/PhoneFrame.stories.tsx": 1.513, + "storybook-light::packages/ui-kit/stories/chrome/ScreenBody.stories.tsx": 1.857, + "storybook-light::packages/ui-kit/stories/chrome/ScreenHeader.stories.tsx": 2.436, + "storybook-light::packages/ui-kit/stories/chrome/SessionStrip.stories.tsx": 3.122, + "storybook-light::packages/ui-kit/stories/chrome/TabBar.stories.tsx": 5.663, + "storybook-light::packages/ui-kit/stories/conversation/AccountTheme.stories.tsx": 6.871, + "storybook-light::packages/ui-kit/stories/conversation/AttachmentRow.stories.tsx": 1.804, + "storybook-light::packages/ui-kit/stories/conversation/CodeFenceTheme.stories.tsx": 1.936, + "storybook-light::packages/ui-kit/stories/conversation/ComparisonTable.stories.tsx": 1.272, + "storybook-light::packages/ui-kit/stories/conversation/ComposerTheme.stories.tsx": 1.626, + "storybook-light::packages/ui-kit/stories/conversation/DigestCard.stories.tsx": 1.482, + "storybook-light::packages/ui-kit/stories/conversation/EmptyState.stories.tsx": 1.594, + "storybook-light::packages/ui-kit/stories/conversation/GraphUnavailable.stories.tsx": 1.448, + "storybook-light::packages/ui-kit/stories/conversation/GroupedQuestionExchange.stories.tsx": 2.666, + "storybook-light::packages/ui-kit/stories/conversation/InlineToast.stories.tsx": 1.645, + "storybook-light::packages/ui-kit/stories/conversation/JournalTheme.stories.tsx": 8.227, + "storybook-light::packages/ui-kit/stories/conversation/RelatedFiles.stories.tsx": 1.804, + "storybook-light::packages/ui-kit/stories/conversation/SessionTheme.stories.tsx": 1.025, + "storybook-light::packages/ui-kit/stories/conversation/StreamingAnswer.stories.tsx": 3.147, + "storybook-light::packages/ui-kit/stories/conversation/SuggestionChips.stories.tsx": 2.273, + "storybook-light::packages/ui-kit/stories/conversation/TurnErrorCard.stories.tsx": 6.345, + "storybook-light::packages/ui-kit/stories/conversation/TurnErrorReview.stories.tsx": 1.78, + "storybook-light::packages/ui-kit/stories/decisions/ActionCard.stories.tsx": 7.397, + "storybook-light::packages/ui-kit/stories/decisions/ApprovalCard.stories.tsx": 1.921, + "storybook-light::packages/ui-kit/stories/decisions/AskUserCard.stories.tsx": 6.744, + "storybook-light::packages/ui-kit/stories/decisions/AskUserFormCard.stories.tsx": 12.353, + "storybook-light::packages/ui-kit/stories/decisions/AskUserRankCard.stories.tsx": 4.748, + "storybook-light::packages/ui-kit/stories/decisions/DispositionBar.stories.tsx": 0.969, + "storybook-light::packages/ui-kit/stories/decisions/EffectPreview.stories.tsx": 1.14, + "storybook-light::packages/ui-kit/stories/decisions/HygieneBlocker.stories.tsx": 0.714, + "storybook-light::packages/ui-kit/stories/decisions/HygieneCard.stories.tsx": 4.16, + "storybook-light::packages/ui-kit/stories/decisions/HygieneEnd.stories.tsx": 1.005, + "storybook-light::packages/ui-kit/stories/decisions/NotificationCard.stories.tsx": 1.276, + "storybook-light::packages/ui-kit/stories/decisions/QuestionAndMask.stories.tsx": 33.886, + "storybook-light::packages/ui-kit/stories/desktop/CommandPalette.stories.tsx": 7.139, + "storybook-light::packages/ui-kit/stories/desktop/SideRail.stories.tsx": 9.25, + "storybook-light::packages/ui-kit/stories/evidence/BarList.stories.tsx": 1.441, + "storybook-light::packages/ui-kit/stories/evidence/DataTable.stories.tsx": 2.034, + "storybook-light::packages/ui-kit/stories/evidence/Receipt.stories.tsx": 5.122, + "storybook-light::packages/ui-kit/stories/evidence/SearchResultCard.stories.tsx": 2.422, + "storybook-light::packages/ui-kit/stories/evidence/TraceSteps.stories.tsx": 2.269, + "storybook-light::packages/ui-kit/stories/primitives/BrandMark.stories.tsx": 1.269, + "storybook-light::packages/ui-kit/stories/primitives/Button.stories.tsx": 1.542, + "storybook-light::packages/ui-kit/stories/primitives/Callout.stories.tsx": 1.689, + "storybook-light::packages/ui-kit/stories/primitives/Chip.stories.tsx": 1.369, + "storybook-light::packages/ui-kit/stories/primitives/DiffBlock.stories.tsx": 1.807, + "storybook-light::packages/ui-kit/stories/primitives/Icon.stories.tsx": 1.215, + "storybook-light::packages/ui-kit/stories/primitives/IconButton.stories.tsx": 5.655, + "storybook-light::packages/ui-kit/stories/primitives/Label.stories.tsx": 1.785, + "storybook-light::packages/ui-kit/stories/primitives/Meter.stories.tsx": 1.402, + "storybook-light::packages/ui-kit/stories/primitives/PathRef.stories.tsx": 2.079, + "storybook-light::packages/ui-kit/stories/primitives/StatusDot.stories.tsx": 1.179, + "storybook-light::packages/ui-kit/stories/primitives/Surface.stories.tsx": 4.075, + "storybook-light::packages/ui-kit/stories/primitives/TextButton.stories.tsx": 4.893, + "storybook-light::packages/ui-kit/stories/primitives/Toggle.stories.tsx": 2.172, + "storybook-light::packages/ui-kit/stories/rows/ChoiceOption.stories.tsx": 3.493, + "storybook-light::packages/ui-kit/stories/rows/FileRow.stories.tsx": 5.887, + "storybook-light::packages/ui-kit/stories/rows/FilterRow.stories.tsx": 2.507, + "storybook-light::packages/ui-kit/stories/rows/ListRow.stories.tsx": 1.597, + "storybook-light::packages/ui-kit/stories/rows/QueueItemRow.stories.tsx": 5.2, + "storybook-light::packages/ui-kit/stories/rows/RecordingRow.stories.tsx": 0.908, + "storybook-light::packages/ui-kit/stories/rules/Keyboard.stories.tsx": 3.659, + "storybook-light::packages/ui-kit/stories/rules/NonNegotiables.stories.tsx": 4.971, + "storybook-light::packages/ui-kit/stories/screens/ActionsTriage.stories.tsx": 5.404, + "storybook-light::packages/ui-kit/stories/screens/ChatAnswer.stories.tsx": 5.046, + "storybook-light::packages/ui-kit/stories/screens/FileViewer.stories.tsx": 3.285, + "storybook-light::packages/ui-kit/stories/screens/FirstRun.stories.tsx": 3.54, + "storybook-light::packages/ui-kit/stories/screens/MorningDigest.stories.tsx": 4.332, + "storybook-light::packages/ui-kit/stories/screens/RunDetail.stories.tsx": 2.384, + "storybook-light::packages/ui-kit/stories/screens/WeeklyReview.stories.tsx": 7.055, + "storybook-light::packages/ui-kit/stories/states/GhostSweep.stories.tsx": 2.193, + "storybook-light::packages/ui-kit/stories/states/Placeholder.stories.tsx": 8.272, + "storybook::packages/ui-kit/stories/agents/AgentOrbit.stories.tsx": 1.89, + "storybook::packages/ui-kit/stories/agents/AgentRunCard.stories.tsx": 1.376, + "storybook::packages/ui-kit/stories/agents/GraphView.stories.tsx": 2.843, + "storybook::packages/ui-kit/stories/agents/LaneChart.stories.tsx": 1.549, + "storybook::packages/ui-kit/stories/blocks/CodeBlock.stories.tsx": 1.254, + "storybook::packages/ui-kit/stories/blocks/ContactCard.stories.tsx": 1.502, + "storybook::packages/ui-kit/stories/blocks/Disclosure.stories.tsx": 1.557, + "storybook::packages/ui-kit/stories/blocks/FeedbackRow.stories.tsx": 1.549, + "storybook::packages/ui-kit/stories/blocks/InPrint.stories.tsx": 2.172, + "storybook::packages/ui-kit/stories/blocks/LinkPreviewCard.stories.tsx": 6.269, + "storybook::packages/ui-kit/stories/blocks/MapView.stories.tsx": 10.274, + "storybook::packages/ui-kit/stories/blocks/PlaceMap.stories.tsx": 6.086, + "storybook::packages/ui-kit/stories/blocks/QuoteCard.stories.tsx": 3.233, + "storybook::packages/ui-kit/stories/blocks/ScheduleList.stories.tsx": 1.458, + "storybook::packages/ui-kit/stories/blocks/StatTiles.stories.tsx": 2.387, + "storybook::packages/ui-kit/stories/blocks/StepList.stories.tsx": 1.401, + "storybook::packages/ui-kit/stories/blocks/TimelineList.stories.tsx": 2.203, + "storybook::packages/ui-kit/stories/blocks/TrackerPillList.stories.tsx": 2.34, + "storybook::packages/ui-kit/stories/blocks/TrackMap.stories.tsx": 1.852, + "storybook::packages/ui-kit/stories/blocks/TrendChart.stories.tsx": 2.134, + "storybook::packages/ui-kit/stories/chrome/BottomSheet.stories.tsx": 1.578, + "storybook::packages/ui-kit/stories/chrome/Composer.stories.tsx": 7.921, + "storybook::packages/ui-kit/stories/chrome/ComposerRow.stories.tsx": 1.233, + "storybook::packages/ui-kit/stories/chrome/DiscButton.stories.tsx": 3.261, + "storybook::packages/ui-kit/stories/chrome/MessageBubble.stories.tsx": 1.365, + "storybook::packages/ui-kit/stories/chrome/ModelPicker.stories.tsx": 1.415, + "storybook::packages/ui-kit/stories/chrome/Overlay.stories.tsx": 2.15, + "storybook::packages/ui-kit/stories/chrome/PendingFollowUps.stories.tsx": 2.439, + "storybook::packages/ui-kit/stories/chrome/PhoneFrame.stories.tsx": 1.142, + "storybook::packages/ui-kit/stories/chrome/ScreenBody.stories.tsx": 1.924, + "storybook::packages/ui-kit/stories/chrome/ScreenHeader.stories.tsx": 1.356, + "storybook::packages/ui-kit/stories/chrome/SessionStrip.stories.tsx": 3.46, + "storybook::packages/ui-kit/stories/chrome/TabBar.stories.tsx": 7.205, + "storybook::packages/ui-kit/stories/conversation/AccountTheme.stories.tsx": 6.669, + "storybook::packages/ui-kit/stories/conversation/AttachmentRow.stories.tsx": 1.482, + "storybook::packages/ui-kit/stories/conversation/CodeFenceTheme.stories.tsx": 2.225, + "storybook::packages/ui-kit/stories/conversation/ComparisonTable.stories.tsx": 1.387, + "storybook::packages/ui-kit/stories/conversation/ComposerTheme.stories.tsx": 1.517, + "storybook::packages/ui-kit/stories/conversation/DigestCard.stories.tsx": 1.8, + "storybook::packages/ui-kit/stories/conversation/EmptyState.stories.tsx": 1.554, + "storybook::packages/ui-kit/stories/conversation/GraphUnavailable.stories.tsx": 1.511, + "storybook::packages/ui-kit/stories/conversation/GroupedQuestionExchange.stories.tsx": 2.875, + "storybook::packages/ui-kit/stories/conversation/InlineToast.stories.tsx": 1.731, + "storybook::packages/ui-kit/stories/conversation/JournalTheme.stories.tsx": 6.811, + "storybook::packages/ui-kit/stories/conversation/RelatedFiles.stories.tsx": 1.4, + "storybook::packages/ui-kit/stories/conversation/SessionTheme.stories.tsx": 1.804, + "storybook::packages/ui-kit/stories/conversation/StreamingAnswer.stories.tsx": 4.767, + "storybook::packages/ui-kit/stories/conversation/SuggestionChips.stories.tsx": 2.269, + "storybook::packages/ui-kit/stories/conversation/TurnErrorCard.stories.tsx": 4.796, + "storybook::packages/ui-kit/stories/conversation/TurnErrorReview.stories.tsx": 1.913, + "storybook::packages/ui-kit/stories/decisions/ActionCard.stories.tsx": 6.078, + "storybook::packages/ui-kit/stories/decisions/ApprovalCard.stories.tsx": 1.88, + "storybook::packages/ui-kit/stories/decisions/AskUserCard.stories.tsx": 4.93, + "storybook::packages/ui-kit/stories/decisions/AskUserFormCard.stories.tsx": 11.725, + "storybook::packages/ui-kit/stories/decisions/AskUserRankCard.stories.tsx": 5.486, + "storybook::packages/ui-kit/stories/decisions/DispositionBar.stories.tsx": 1.647, + "storybook::packages/ui-kit/stories/decisions/EffectPreview.stories.tsx": 1.136, + "storybook::packages/ui-kit/stories/decisions/HygieneBlocker.stories.tsx": 0.867, + "storybook::packages/ui-kit/stories/decisions/HygieneCard.stories.tsx": 3.59, + "storybook::packages/ui-kit/stories/decisions/HygieneEnd.stories.tsx": 1.016, + "storybook::packages/ui-kit/stories/decisions/NotificationCard.stories.tsx": 3.509, + "storybook::packages/ui-kit/stories/decisions/QuestionAndMask.stories.tsx": 35.678, + "storybook::packages/ui-kit/stories/desktop/CommandPalette.stories.tsx": 13.773, + "storybook::packages/ui-kit/stories/desktop/SideRail.stories.tsx": 9.342, + "storybook::packages/ui-kit/stories/evidence/BarList.stories.tsx": 1.339, + "storybook::packages/ui-kit/stories/evidence/DataTable.stories.tsx": 2.031, + "storybook::packages/ui-kit/stories/evidence/Receipt.stories.tsx": 5.16, + "storybook::packages/ui-kit/stories/evidence/SearchResultCard.stories.tsx": 4.069, + "storybook::packages/ui-kit/stories/evidence/TraceSteps.stories.tsx": 1.896, + "storybook::packages/ui-kit/stories/primitives/BrandMark.stories.tsx": 1.244, + "storybook::packages/ui-kit/stories/primitives/Button.stories.tsx": 1.472, + "storybook::packages/ui-kit/stories/primitives/Callout.stories.tsx": 2.243, + "storybook::packages/ui-kit/stories/primitives/Chip.stories.tsx": 1.22, + "storybook::packages/ui-kit/stories/primitives/DiffBlock.stories.tsx": 3.023, + "storybook::packages/ui-kit/stories/primitives/Icon.stories.tsx": 1.205, + "storybook::packages/ui-kit/stories/primitives/IconButton.stories.tsx": 5.698, + "storybook::packages/ui-kit/stories/primitives/Label.stories.tsx": 1.5, + "storybook::packages/ui-kit/stories/primitives/Meter.stories.tsx": 1.718, + "storybook::packages/ui-kit/stories/primitives/PathRef.stories.tsx": 2.269, + "storybook::packages/ui-kit/stories/primitives/StatusDot.stories.tsx": 1.117, + "storybook::packages/ui-kit/stories/primitives/Surface.stories.tsx": 3.395, + "storybook::packages/ui-kit/stories/primitives/TextButton.stories.tsx": 6.951, + "storybook::packages/ui-kit/stories/primitives/Toggle.stories.tsx": 1.949, + "storybook::packages/ui-kit/stories/rows/ChoiceOption.stories.tsx": 4.517, + "storybook::packages/ui-kit/stories/rows/FileRow.stories.tsx": 6.044, + "storybook::packages/ui-kit/stories/rows/FilterRow.stories.tsx": 3.18, + "storybook::packages/ui-kit/stories/rows/ListRow.stories.tsx": 1.817, + "storybook::packages/ui-kit/stories/rows/QueueItemRow.stories.tsx": 4.712, + "storybook::packages/ui-kit/stories/rows/RecordingRow.stories.tsx": 2.278, + "storybook::packages/ui-kit/stories/rules/Keyboard.stories.tsx": 3.264, + "storybook::packages/ui-kit/stories/rules/NonNegotiables.stories.tsx": 3.698, + "storybook::packages/ui-kit/stories/screens/ActionsTriage.stories.tsx": 3.534, + "storybook::packages/ui-kit/stories/screens/ChatAnswer.stories.tsx": 4.724, + "storybook::packages/ui-kit/stories/screens/FileViewer.stories.tsx": 4.568, + "storybook::packages/ui-kit/stories/screens/FirstRun.stories.tsx": 2.679, + "storybook::packages/ui-kit/stories/screens/MorningDigest.stories.tsx": 2.323, + "storybook::packages/ui-kit/stories/screens/RunDetail.stories.tsx": 1.517, + "storybook::packages/ui-kit/stories/screens/WeeklyReview.stories.tsx": 6.087, + "storybook::packages/ui-kit/stories/states/GhostSweep.stories.tsx": 2.306, + "storybook::packages/ui-kit/stories/states/Placeholder.stories.tsx": 5.376, + "subjects::packages/ui-kit/tests/visual/subjects.visual.tsx": 87.668, "ui-react-layout::packages/ui-react/tests/browser/activity-report.layout.tsx": 2.883, "ui-react-layout::packages/ui-react/tests/browser/agent-orbit.layout.tsx": 2.022, "ui-react-layout::packages/ui-react/tests/browser/auth-expiry.offline.tsx": 1.735, @@ -370,40 +369,40 @@ "ui-react-layout::packages/ui-react/tests/browser/track-share-review.layout.tsx": 1.365, "ui-react-layout::packages/ui-react/tests/browser/turn-status.layout.tsx": 5.831, "ui-react-layout::packages/ui-react/tests/browser/worker-host-notice.layout.tsx": 1.73, - "visual::packages/ui-kit/tests/visual/brand-mark.visual.tsx": 0.907, - "visual::packages/ui-kit/tests/visual/button-hover.visual.tsx": 15.28, - "visual::packages/ui-kit/tests/visual/comparison-text.visual.tsx": 1.41, - "visual::packages/ui-kit/tests/visual/composer-caret.visual.tsx": 1.28, - "visual::packages/ui-kit/tests/visual/connection-refusals.visual.tsx": 2.184, - "visual::packages/ui-kit/tests/visual/contact-card-fact-keys.visual.tsx": 4.95, - "visual::packages/ui-kit/tests/visual/design-fonts.visual.tsx": 2.68, - "visual::packages/ui-kit/tests/visual/empty-state-meta.visual.tsx": 0.396, - "visual::packages/ui-kit/tests/visual/files-close.visual.tsx": 2.478, - "visual::packages/ui-kit/tests/visual/focus-frames.visual.tsx": 31.926, - "visual::packages/ui-kit/tests/visual/form-consumer.visual.tsx": 0.304, - "visual::packages/ui-kit/tests/visual/geo-closure-probes.visual.tsx": 1.899, - "visual::packages/ui-kit/tests/visual/ghost-handoff.visual.tsx": 3.626, - "visual::packages/ui-kit/tests/visual/ghost-media.visual.tsx": 3.574, - "visual::packages/ui-kit/tests/visual/ghost-sweep.visual.tsx": 23.539, - "visual::packages/ui-kit/tests/visual/hygiene-review.visual.tsx": 29.681, - "visual::packages/ui-kit/tests/visual/link-card.visual.tsx": 2.517, - "visual::packages/ui-kit/tests/visual/map-labels.visual.tsx": 5.551, - "visual::packages/ui-kit/tests/visual/meter-label.visual.tsx": 2.278, - "visual::packages/ui-kit/tests/visual/nowrap-scroll.visual.tsx": 6.281, - "visual::packages/ui-kit/tests/visual/overlay.visual.tsx": 32.508, - "visual::packages/ui-kit/tests/visual/rank-footer.visual.tsx": 12.697, - "visual::packages/ui-kit/tests/visual/rank-touch.visual.tsx": 5.885, - "visual::packages/ui-kit/tests/visual/receipt-key-column.visual.tsx": 1.234, - "visual::packages/ui-kit/tests/visual/receipt-value-budget.visual.tsx": 0.37, - "visual::packages/ui-kit/tests/visual/recording-row.visual.tsx": 2.744, - "visual::packages/ui-kit/tests/visual/sheet-adapters.visual.tsx": 12.54, - "visual::packages/ui-kit/tests/visual/sheet-swipe.visual.tsx": 27.497, - "visual::packages/ui-kit/tests/visual/stat-layout.visual.tsx": 1.649, - "visual::packages/ui-kit/tests/visual/streaming-handoff.visual.tsx": 6.646, - "visual::packages/ui-kit/tests/visual/track-intake.visual.tsx": 16.039, - "visual::packages/ui-kit/tests/visual/track-map.visual.tsx": 8.653, - "visual::packages/ui-kit/tests/visual/tracker-pills.visual.tsx": 5.37, - "visual::packages/ui-kit/tests/visual/turn-error.visual.tsx": 17.249, - "visual::packages/ui-kit/tests/visual/turn-failure-observations.visual.tsx": 13.605 + "visual::packages/ui-kit/tests/visual/brand-mark.visual.tsx": 0.487, + "visual::packages/ui-kit/tests/visual/button-hover.visual.tsx": 25.701, + "visual::packages/ui-kit/tests/visual/comparison-text.visual.tsx": 0.57, + "visual::packages/ui-kit/tests/visual/composer-caret.visual.tsx": 0.393, + "visual::packages/ui-kit/tests/visual/connection-refusals.visual.tsx": 2.482, + "visual::packages/ui-kit/tests/visual/contact-card-fact-keys.visual.tsx": 8.611, + "visual::packages/ui-kit/tests/visual/design-fonts.visual.tsx": 2.212, + "visual::packages/ui-kit/tests/visual/empty-state-meta.visual.tsx": 0.333, + "visual::packages/ui-kit/tests/visual/files-close.visual.tsx": 7.515, + "visual::packages/ui-kit/tests/visual/focus-frames.visual.tsx": 36.394, + "visual::packages/ui-kit/tests/visual/form-consumer.visual.tsx": 0.358, + "visual::packages/ui-kit/tests/visual/geo-closure-probes.visual.tsx": 1.735, + "visual::packages/ui-kit/tests/visual/ghost-handoff.visual.tsx": 4.985, + "visual::packages/ui-kit/tests/visual/ghost-media.visual.tsx": 3.361, + "visual::packages/ui-kit/tests/visual/ghost-sweep.visual.tsx": 23.613, + "visual::packages/ui-kit/tests/visual/hygiene-review.visual.tsx": 12.626, + "visual::packages/ui-kit/tests/visual/link-card.visual.tsx": 5.492, + "visual::packages/ui-kit/tests/visual/map-labels.visual.tsx": 8.462, + "visual::packages/ui-kit/tests/visual/meter-label.visual.tsx": 2.257, + "visual::packages/ui-kit/tests/visual/nowrap-scroll.visual.tsx": 25.291, + "visual::packages/ui-kit/tests/visual/overlay.visual.tsx": 40.406, + "visual::packages/ui-kit/tests/visual/rank-footer.visual.tsx": 15.632, + "visual::packages/ui-kit/tests/visual/rank-touch.visual.tsx": 4.163, + "visual::packages/ui-kit/tests/visual/receipt-key-column.visual.tsx": 0.878, + "visual::packages/ui-kit/tests/visual/receipt-value-budget.visual.tsx": 0.428, + "visual::packages/ui-kit/tests/visual/recording-row.visual.tsx": 2.821, + "visual::packages/ui-kit/tests/visual/sheet-adapters.visual.tsx": 11.555, + "visual::packages/ui-kit/tests/visual/sheet-swipe.visual.tsx": 34.38, + "visual::packages/ui-kit/tests/visual/stat-layout.visual.tsx": 3.144, + "visual::packages/ui-kit/tests/visual/streaming-handoff.visual.tsx": 7.838, + "visual::packages/ui-kit/tests/visual/track-intake.visual.tsx": 23.383, + "visual::packages/ui-kit/tests/visual/track-map.visual.tsx": 9.041, + "visual::packages/ui-kit/tests/visual/tracker-pills.visual.tsx": 7.71, + "visual::packages/ui-kit/tests/visual/turn-error.visual.tsx": 31.965, + "visual::packages/ui-kit/tests/visual/turn-failure-observations.visual.tsx": 8.642 } } From 3f1b2c5d0b718c0870b3570f52c0676d19742e1c Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Sun, 18 Oct 2026 10:42:57 +0200 Subject: [PATCH 2/4] chore(ci): raise the browser job bound to 20 minutes Browser shard 2 reached 887 s on main and 917 s on a ready PR against the 900 s bound; refreshed weights brought the slower shard to 845 s, still above the 840 s qualification bar. The bound now leaves real buffer, and a test pins it so it cannot shrink silently. Refs #2414 Co-Authored-By: Claude Opus 5.5 --- .github/workflows/ci.yml | 2 +- docs/decisions/ci-utility.md | 3 +++ tests/ci-workflows.test.ts | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3b401850e..69a2c10f9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -302,7 +302,7 @@ jobs: needs: changeset if: needs.changeset.outputs.browser == 'true' && needs.changeset.outputs.run_browser == 'true' runs-on: ubuntu-24.04 - timeout-minutes: 15 + timeout-minutes: 20 strategy: fail-fast: false matrix: diff --git a/docs/decisions/ci-utility.md b/docs/decisions/ci-utility.md index f312de029..5cf3ad226 100644 --- a/docs/decisions/ci-utility.md +++ b/docs/decisions/ci-utility.md @@ -142,6 +142,9 @@ fresh job and never becomes an ordinary browser/layout weight. Requalify timing inputs after scenario ownership changes: the former combined recording-file measurement includes endurance and is not its current ordinary-layout cost. Two layout shards, per-project serial execution and all deadlines remain unchanged. +Browser jobs have a 20-minute bound. It was raised from 15 minutes after browser +(2) reached 887 s on main and 917 s on a ready PR ([#2414](https://github.com/schlessera/brain-kit/issues/2414)). A weight refresh still +qualifies by measured whole-job elapsed time, not by the bound. Hosted unit partitions use a queue capped at two serial Bun test processes (`scripts/unit-workers.ts`), or one when only one file is selected. Native diff --git a/tests/ci-workflows.test.ts b/tests/ci-workflows.test.ts index bfca6c27e..7c08c8acd 100644 --- a/tests/ci-workflows.test.ts +++ b/tests/ci-workflows.test.ts @@ -139,6 +139,8 @@ describe("the authoritative jobs retain their important phases", () => { expect(ci.jobs.changeset!["timeout-minutes"]).toBe(3); expect(ci.jobs.verify!["timeout-minutes"]).toBe(3); expect(ci.jobs.pack!["timeout-minutes"]).toBe(5); + // Browser shards keep buffer above the measured ~900 s whole-job peak (#2414). + expect(ci.jobs.browser!["timeout-minutes"]).toBe(20); }); test("the contract checks exact PR heads and carries title/labels as environment data", () => { const contract = workflows.find(w => w.file === "contract.yml")!.workflow; From b34a8162a0ecce8bddbe3da1673b69aa60f10ede Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Sun, 18 Oct 2026 10:46:43 +0200 Subject: [PATCH 3/4] chore(ci): run browser proof in three measured shards Refreshed weights brought the slower browser shard to 845 s, above the 840 s bar. Scored by fresh weights, three shards bring each shard's slowest project to 482 s, the cost of the single heaviest file. Layout stays at two shards. One table, PROOF_SHARDS in scripts/proof-shards.ts, now feeds retention receipts and source validation, the weight refresh, the input-partition fingerprint and a workflow guard that matches each domain's matrix and --shard divisor. A receipt from the two-shard era names another partition and is never admitted. Refs #2414 Co-Authored-By: Claude Opus 5.5 --- .github/workflows/ci.yml | 4 ++-- CONTRIBUTING.md | 2 +- docs/decisions/ci-utility.md | 7 ++++--- docs/process/proof-domains.md | 4 ++-- scripts/check-ci-workflows.ts | 7 +++++++ scripts/inclusion-inputs.ts | 3 ++- scripts/proof-reuse.ts | 11 ++++++----- scripts/proof-shards.ts | 8 ++++++++ scripts/refresh-browser-costs.ts | 11 ++++++----- tests/ci-workflows.test.ts | 8 ++++++++ tests/proof-reuse.test.ts | 12 ++++++++---- tests/refresh-browser-costs.test.ts | 13 +++++++++---- 12 files changed, 63 insertions(+), 27 deletions(-) create mode 100644 scripts/proof-shards.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 69a2c10f9..9776188d1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -306,7 +306,7 @@ jobs: strategy: fail-fast: false matrix: - shard: [1, 2] + shard: [1, 2, 3] steps: - uses: actions/checkout@v7 with: @@ -323,7 +323,7 @@ jobs: HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} run: bun scripts/ci-plan.ts - name: Complete browser proof - run: bun scripts/ci-proof.ts browser --shard=${{ matrix.shard }}/2 + run: bun scripts/ci-proof.ts browser --shard=${{ matrix.shard }}/3 - name: Proof receipts and failure diagnostics if: always() uses: actions/upload-artifact@v7 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5ffcbf8d6..519c33df8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -272,7 +272,7 @@ feature test should use these helpers instead of building its own. The complete dictation browser fixture has its own `dictation` project so its Chromium touch emulation and consumer styles stay outside the shared `visual` -page. The default browser wrapper includes it in both shards; use +page. The default browser wrapper includes it in every shard; use `node scripts/visual.mjs --project=dictation` for a focused container run. Tests and typecheck run from live TS source — no build needed. The diff --git a/docs/decisions/ci-utility.md b/docs/decisions/ci-utility.md index 5cf3ad226..f2387f371 100644 --- a/docs/decisions/ci-utility.md +++ b/docs/decisions/ci-utility.md @@ -111,7 +111,8 @@ one PR share a cancellable group. Different PRs never cancel one another. After cheap gates, packaging, strict verification, unit shards, runtime probes, browser shards, layout shards, a separate endurance job and captures start independently. -There are four measured-cost unit partitions and two browser/layout partitions, +There are four measured-cost unit partitions, three browser and two layout partitions +(`PROOF_SHARDS`, `scripts/proof-shards.ts`, which the workflow guard matches against the matrices), with full coverage assertions and original per-browser file concurrency bounds. The first two-unit-partition hosted run reached its 20-minute budgets while still making progress. Completed-file observations in @@ -142,7 +143,7 @@ fresh job and never becomes an ordinary browser/layout weight. Requalify timing inputs after scenario ownership changes: the former combined recording-file measurement includes endurance and is not its current ordinary-layout cost. Two layout shards, per-project serial execution and all deadlines remain unchanged. -Browser jobs have a 20-minute bound. It was raised from 15 minutes after browser +Browser proof runs in three shards and its jobs have a 20-minute bound. It was raised from 15 minutes after browser (2) reached 887 s on main and 917 s on a ready PR ([#2414](https://github.com/schlessera/brain-kit/issues/2414)). A weight refresh still qualifies by measured whole-job elapsed time, not by the bound. @@ -343,7 +344,7 @@ and actual merge-result parent/tree validation remain binding. ### Retaining complete browser domains -Under #1333, ready-PR metadata can retain both shards of a complete browser or +Under #1333, ready-PR metadata can retain every shard of a complete browser or layout domain from up to three recent successful automatic runs of that same contribution. Unit, types, packaging, native runtime and editorial checks remain fresh: their Git-sensitive or broader process inputs do not have an admitted diff --git a/docs/process/proof-domains.md b/docs/process/proof-domains.md index 18db6e55f..5ecbbab38 100644 --- a/docs/process/proof-domains.md +++ b/docs/process/proof-domains.md @@ -77,8 +77,8 @@ Reconcile each final command as follows: | --- | --- | --- | --- | | Curated contract/integrity files in `FAST_TESTS` | Fast | Affected subset with strict types | Included once by complete affected unit discovery | | Every other product Bun test in `packages/` and `tests/` | Unit confirmation | Deferred | Complete affected discovery plus root tests | -| Storybook dark/light, visual, pointer and isolated browser projects | Browser confirmation | Deferred | Every discovered project/file instance in the existing two shards | -| `.layout.tsx` and `.offline.tsx` in `ui-react-layout` | Layout confirmation | Deferred | Every discovered project/file instance in the existing two shards | +| Storybook dark/light, visual, pointer and isolated browser projects | Browser confirmation | Deferred | Every discovered project/file instance in the three browser shards | +| `.layout.tsx` and `.offline.tsx` in `ui-react-layout` | Layout confirmation | Deferred | Every discovered project/file instance in the two layout shards | | `.endurance.tsx` in `ui-react-endurance` | Endurance confirmation | Deferred | Every discovered file in a separate concurrent job | | Native permission/enforcement/delegation/capability/host/cleanup probes | Runtime confirmation | Deferred | Existing complete command inventory and offline namespaces | | Packed consumer probes and editorial capture verification | Packaging/capture confirmation | Deferred | Existing affected commands, pins and artifacts | diff --git a/scripts/check-ci-workflows.ts b/scripts/check-ci-workflows.ts index 4c87e0b52..d0de95bc1 100644 --- a/scripts/check-ci-workflows.ts +++ b/scripts/check-ci-workflows.ts @@ -1,6 +1,7 @@ /** GitHub is the sole CI provider; contributions share read-only workflows. */ import { existsSync, readFileSync, readdirSync } from "node:fs"; import { join, resolve } from "node:path"; +import { PROOF_SHARDS, shardNumbers, type ShardedDomain } from "./proof-shards"; export const CI_WORKFLOWS = ["ci.yml", "contract.yml"] as const; const RUN_EXPRESSIONS = new Set(["matrix.shard", "github.event_name", "github.base_ref", "github.event.before"]); @@ -56,6 +57,12 @@ export function workflowProblems(text: string, file: string): string[] { const selection = `needs.changeset.outputs.${name} == 'true'` + (["browser", "layout"].includes(name) ? ` && needs.changeset.outputs.run_${name} == 'true'` : ""); if (job?.if !== selection) fail(`${name}: proof must use its explicit planner selection and validated retention`); } + // Matrices, retention and refresh share one shard table; a drifted matrix would strand a partition. + for (const domain of Object.keys(PROOF_SHARDS) as ShardedDomain[]) { + const job = workflow.jobs?.[domain] as any; + if (JSON.stringify(job?.strategy?.matrix?.shard) !== JSON.stringify(shardNumbers(domain)) || + !job?.steps?.some((step: any) => step.run === `bun scripts/ci-proof.ts ${domain} --shard=\${{ matrix.shard }}/${PROOF_SHARDS[domain]}`)) fail(`${domain}: matrix and shard divisor must match PROOF_SHARDS`); + } const proof = workflow.jobs?.proof; if (proof?.name !== "${{ github.event_name == 'pull_request' && 'proof' || 'integrated or exhaustive proof' }}") fail("proof: manual or main runs must not impersonate candidate confirmation"); if (JSON.stringify(proof?.needs) !== JSON.stringify(["changeset", ...names])) fail("proof: aggregate must observe every selected category"); diff --git a/scripts/inclusion-inputs.ts b/scripts/inclusion-inputs.ts index 802f2f801..823af8c19 100644 --- a/scripts/inclusion-inputs.ts +++ b/scripts/inclusion-inputs.ts @@ -9,6 +9,7 @@ import { tmpdir } from "node:os"; import { dirname, join } from "node:path"; import { discoverInputClosure, type InputDeclaration } from "./browser-input-closure"; import { balanceBrowserSpecs, readBrowserCosts } from "./browser-shards"; +import { PROOF_SHARDS } from "./proof-shards"; import { selectedSpecs, treeEntries, type Inputs, type Reusable, type Spec } from "./proof-inputs"; const required = ["package.json", "bun.lock", "tsconfig.json", "bunfig.toml", ".github/workflows/ci.yml", @@ -114,7 +115,7 @@ export function inclusionInputs(root: string, category: Reusable, inventory: Spe if (!["100644", "100755"].includes(paths.get(path)!.mode)) throw new Error("Unsupported symbolic input requires fresh proof"); } const partitions = balanceBrowserSpecs(selected.map(spec => ({ key: `${spec.project}::${spec.file}`, project: spec.project })), - 2, readBrowserCosts(join(snapshot, "scripts/browser-shard-costs.json"))).map(part => part.map(spec => spec.key)); + PROOF_SHARDS[category], readBrowserCosts(join(snapshot, "scripts/browser-shard-costs.json"))).map(part => part.map(spec => spec.key)); const files = entries.filter(entry => included.has(entry.path)); const material = { version: 2, category, runner, inventory, partitions, directories: closure.directories ?? [], external: closure.external ?? [], ...(closure.nativeDiagram?{nativeDiagram:closure.nativeDiagram}:{}), files }; return { version: 2, category, runner, inventory, partitions, excluded: [], ...(closure.nativeDiagram?{nativeDiagram:closure.nativeDiagram}:{}), diff --git a/scripts/proof-reuse.ts b/scripts/proof-reuse.ts index 3759cf5ee..f9c1e2f72 100644 --- a/scripts/proof-reuse.ts +++ b/scripts/proof-reuse.ts @@ -2,6 +2,7 @@ import {logWorkerAuditDiagnostic} from "./browser-worker-audit"; /** Bounded immutable GitHub receipts; no passing-result cache or privileged event. */ import { appendFileSync } from "node:fs"; import { join, resolve } from "node:path"; +import { PROOF_SHARDS, shardNumbers } from "./proof-shards"; import { browserInventory, checkout, git, normalizeInventory, proofInputs, REUSABLE, runnerIdentity, type Checkout, type Inputs, type Reusable } from "./proof-inputs"; import { proofSelections, type CheckPlan } from "./ci-plan"; @@ -73,7 +74,7 @@ export function receiptFromLog(text: string, category: Reusable, shard: number): const rows = clean.split("\n").filter(line => /^\S+ BRAIN_PROOF_RECEIPT /.test(line)); if (rows.length !== 1) throw new Error("Missing or ambiguous fresh execution receipt"); const receipt = JSON.parse(rows[0]!.slice(rows[0]!.indexOf(RECEIPT_MARKER) + RECEIPT_MARKER.length)) as FreshReceipt; - if (receipt.version !== 1 || receipt.category !== category || receipt.shard !== `${shard}/2` || + if (receipt.version !== 1 || receipt.category !== category || receipt.shard !== `${shard}/${PROOF_SHARDS[category]}` || !SHA.test(receipt.checkout?.sha ?? "") || !SHA.test(receipt.checkout?.tree ?? "") || !receipt.inputs) throw new Error("Wrong fresh execution receipt"); if (!clean.split("\n").some(line => /^\S+ /.test(line) && line.trim().endsWith(`Z ${receipt.checkout.sha}`))) throw new Error("Receipt is not the actual job checkout"); return receipt; @@ -83,7 +84,7 @@ export function receiptFromLog(text: string, category: Reusable, shard: number): export async function validateSource(root: string, category: Reusable, source: Source, inputs: Inputs, context: Context, api: API): Promise { if (!validID(source?.run) || source.run === context.run || !validID(source.attempt) || - !Array.isArray(source.jobs) || source.jobs.length !== 2 || source.jobs.some(id => !validID(id)) || new Set(source.jobs).size !== 2 || + !Array.isArray(source.jobs) || source.jobs.length !== PROOF_SHARDS[category] || source.jobs.some(id => !validID(id)) || new Set(source.jobs).size !== PROOF_SHARDS[category] || source.inputs?.fingerprint !== inputs.fingerprint || JSON.stringify(source.inputs) !== JSON.stringify(inputs)) throw new Error("Missing complete input equivalence"); const run = await api.json(`actions/runs/${source.run}/attempts/${source.attempt}`); if (run.id !== source.run || run.run_attempt !== source.attempt || run.event !== "pull_request" || @@ -93,7 +94,7 @@ export async function validateSource(root: string, category: Reusable, source: S const page = await api.json(`actions/runs/${source.run}/attempts/${source.attempt}/jobs?per_page=100`); if (!Array.isArray(page.jobs) || page.total_count !== page.jobs.length || page.jobs.length > 30) throw new Error("Incomplete source job inventory"); const found: FreshReceipt[] = []; - for (let shard = 1; shard <= 2; shard++) { + for (const shard of shardNumbers(category)) { const matching = page.jobs.filter((j: any) => j.name === `${category} (${shard})`); const job = matching[0]; if (matching.length !== 1 || job?.id !== source.jobs[shard - 1] || job.run_id !== source.run || job.head_sha !== run.head_sha || @@ -120,7 +121,7 @@ export async function validateSource(root: string, category: Reusable, source: S git(root, "rev-parse", `${source.checkout.sha}:.github/workflows/ci.yml`).trim() !== git(root, "rev-parse", "HEAD:.github/workflows/ci.yml").trim()) throw new Error("Source workflow or Git identity changed"); const recomputed = proofInputs(root, category, normalizeInventory(source.inputs.inventory), inputs.runner, source.checkout.sha, inputs.excluded); - if (recomputed.fingerprint !== inputs.fingerprint || JSON.stringify(recomputed.partitions) !== JSON.stringify(inputs.partitions) || found.length !== 2) throw new Error("Immutable source inputs do not establish input equivalence"); + if (recomputed.fingerprint !== inputs.fingerprint || JSON.stringify(recomputed.partitions) !== JSON.stringify(inputs.partitions) || found.length !== PROOF_SHARDS[category]) throw new Error("Immutable source inputs do not establish input equivalence"); } export async function findRetained(root: string, selected: Record, context: Context, api: API, @@ -143,7 +144,7 @@ export async function findRetained(root: string, selected: Record jobs.jobs.find((j: any) => j.name === `${category} (${shard})` && j.conclusion === "success")); + const pair = shardNumbers(category).map(shard => jobs.jobs.find((j: any) => j.name === `${category} (${shard})` && j.conclusion === "success")); if (pair.some(j => !j)) continue; // Never form transitive chains through skipped/reused jobs. const first = receiptFromLog(await api.log(pair[0].id), category, 1); const inputs = currentInputs.get(category)!; diff --git a/scripts/proof-shards.ts b/scripts/proof-shards.ts new file mode 100644 index 000000000..8ea658395 --- /dev/null +++ b/scripts/proof-shards.ts @@ -0,0 +1,8 @@ +/** Hosted shard counts for the measured browser domains. The ci.yml matrices, + * retention, weight refresh and input partitions all read this one table (#2414). */ +export const PROOF_SHARDS = { browser: 3, layout: 2 } as const; +export type ShardedDomain = keyof typeof PROOF_SHARDS; + +export function shardNumbers(domain: ShardedDomain): number[] { + return Array.from({ length: PROOF_SHARDS[domain] }, (_, index) => index + 1); +} diff --git a/scripts/refresh-browser-costs.ts b/scripts/refresh-browser-costs.ts index 89bebf46a..54e646822 100644 --- a/scripts/refresh-browser-costs.ts +++ b/scripts/refresh-browser-costs.ts @@ -1,6 +1,7 @@ /** Explicit reviewed measurement refresh; never called by contribution CI. */ import { resolve } from "node:path"; import { browserCostsFromLogs, browserTimingReports, type BrowserCosts } from "./browser-shards"; +import { PROOF_SHARDS, shardNumbers } from "./proof-shards"; import { browserPinUsesProducer, parseBrowserPin, resolveBrowserPin } from "./captures/provenance"; import type { API } from "./proof-reuse"; @@ -19,16 +20,16 @@ export async function refreshBrowserCosts(domain: Domain, run: number, attempt: !["push", "pull_request", "workflow_dispatch", "schedule"].includes(info.event) || !SHA.test(info.head_sha)) throw new Error("A successful attributed CI run/attempt is required"); const page = await api.json(`actions/runs/${run}/attempts/${attempt}/jobs?per_page=100`); if (!Array.isArray(page.jobs) || page.total_count !== page.jobs.length || - page.jobs.filter((job: any) => typeof job.name === "string" && job.name.startsWith(`${domain} (`)).length !== 2) throw new Error("Incomplete job inventory"); - const selected = [1, 2].map(shard => { + page.jobs.filter((job: any) => typeof job.name === "string" && job.name.startsWith(`${domain} (`)).length !== PROOF_SHARDS[domain]) throw new Error("Incomplete job inventory"); + const selected = shardNumbers(domain).map(shard => { const matches = page.jobs.filter((job: any) => job.name === `${domain} (${shard})`); const job = matches[0]; if (matches.length !== 1 || !Number.isSafeInteger(job.id) || job.id <= 0 || job.run_id !== run || job.head_sha !== info.head_sha || job.status !== "completed" || job.conclusion !== "success" || - !job.steps?.some((step: any) => step.name === `Complete ${domain} proof` && step.status === "completed" && step.conclusion === "success")) throw new Error("Two fresh successful domain jobs are required"); + !job.steps?.some((step: any) => step.name === `Complete ${domain} proof` && step.status === "completed" && step.conclusion === "success")) throw new Error("Fresh successful domain jobs are required for every shard"); return job; }); - if (selected[0].id === selected[1].id) throw new Error("Duplicate job identity"); + if (new Set(selected.map(job => job.id)).size !== selected.length) throw new Error("Duplicate job identity"); const logs = await Promise.all(selected.map(job => api.log(job.id))); const identities: string[] = [], keys = new Set(); let inventorySize: number | undefined; @@ -39,7 +40,7 @@ export async function refreshBrowserCosts(domain: Domain, run: number, attempt: identities.push(checkoutRows[0]![1]!); const images = [...log.matchAll(/Status: (?:Downloaded newer image|Image is up to date) for ([^\s]+)/g)].map(match => match[1]); if (images.length !== 1 || images[0] !== image) throw new Error("Pinned execution image evidence is missing or mismatched"); - const partitions = [...log.matchAll(/Measured browser shard ([12])\/2: (\d+)\/(\d+) specs;/g)]; + const partitions = [...log.matchAll(new RegExp(`Measured browser shard (\\d+)\\/${PROOF_SHARDS[domain]}: (\\d+)\\/(\\d+) specs;`, "g"))]; const summaries = [...log.matchAll(/Test Files\s+(\d+) passed \((\d+)\)/g)]; const reports = browserTimingReports(raw); const partition = partitions[0], summary = summaries[0]; diff --git a/tests/ci-workflows.test.ts b/tests/ci-workflows.test.ts index 7c08c8acd..b48c759f0 100644 --- a/tests/ci-workflows.test.ts +++ b/tests/ci-workflows.test.ts @@ -348,6 +348,14 @@ test("workflow cannot check out a different tree or impersonate candidate proof expect(workflowProblems(text.replace("name: ${{ github.event_name == 'pull_request' && 'proof' || 'integrated or exhaustive proof' }}", "name: proof"), "ci.yml").join("\n")).toContain("must not impersonate candidate confirmation"); }); +test("browser and layout matrices match the shared shard table (#2414)", () => { + const text = readFileSync(join(ROOT, ".github/workflows/ci.yml"), "utf8"); + expect(workflowProblems(text, "ci.yml")).toEqual([]); + expect(workflowProblems(text.replace("shard: [1, 2, 3]", "shard: [1, 2]"), "ci.yml").join("\n")).toContain("browser: matrix and shard divisor must match PROOF_SHARDS"); + expect(workflowProblems(text.replace("browser --shard=${{ matrix.shard }}/3", "browser --shard=${{ matrix.shard }}/2"), "ci.yml").join("\n")).toContain("browser: matrix and shard divisor must match PROOF_SHARDS"); + expect(workflowProblems(text.replace("layout --shard=${{ matrix.shard }}/2", "layout --shard=${{ matrix.shard }}/3"), "ci.yml").join("\n")).toContain("layout: matrix and shard divisor must match PROOF_SHARDS"); +}); + test("small exact inventories wire bounded planner partitions into actual unit execution", () => { expect(ci.jobs.unit!.strategy).toEqual({"fail-fast": false, matrix: {shard: "${{ fromJSON(needs.changeset.outputs.unit_shards) }}"}}); const step = ci.jobs.unit!.steps.find(s => s.name === "Complete unit proof")!; diff --git a/tests/proof-reuse.test.ts b/tests/proof-reuse.test.ts index 762a2f435..1e4904391 100644 --- a/tests/proof-reuse.test.ts +++ b/tests/proof-reuse.test.ts @@ -6,6 +6,7 @@ import { browserInventory, checkout, git, normalizeInventory, proofInputs, runne import { boundedLedger, contextFromEvent, findRetained, receiptFromLog, retainedCategories, validateSource, type API, type Context, type FreshReceipt, type Source } from "../scripts/proof-reuse"; import { proofProblems, PROOF_JOBS } from "../scripts/ci-proof"; import * as workerAudit from "../scripts/browser-worker-audit"; +import { PROOF_SHARDS, shardNumbers } from "../scripts/proof-shards"; const roots: string[] = []; // These are synthetic receipt/API protocol fixtures, not browser execution // qualification. Keep real immutable fingerprint/source recomputation while @@ -52,19 +53,20 @@ function fixture() { const context: Context = { repository: "schlessera/brain-kit", headRepository: "schlessera/brain-kit", branch: "chore/fixture", pr: 42, run: 100 }; function evidence(root: string, inputs: Inputs) { const identity = checkout(root); - const receipts: FreshReceipt[] = [1, 2].map(shard => ({ version: 1, category: "browser", shard: `${shard}/2`, checkout: identity, inputs })); - const source: Source = { run: 90, attempt: 1, jobs: [101, 102], checkout: identity, inputs }; + const ids = shardNumbers("browser").map(shard => 100 + shard); + const receipts: FreshReceipt[] = shardNumbers("browser").map(shard => ({ version: 1, category: "browser", shard: `${shard}/${PROOF_SHARDS.browser}`, checkout: identity, inputs })); + const source: Source = { run: 90, attempt: 1, jobs: ids, checkout: identity, inputs }; const calls: string[] = []; const run = { id: 90, event: "pull_request", status: "completed", conclusion: "success", run_attempt: 1, head_sha: identity.parents[1], head_branch: context.branch, path: ".github/workflows/ci.yml", head_repository: { full_name: context.headRepository }, repository: { full_name: context.repository }, created_at: new Date().toISOString() }; - const jobs = [101, 102].map((id, i) => ({ id, run_id: 90, head_sha: identity.parents[1], name: `browser (${i + 1})`, status: "completed", conclusion: "success", check_run_url: `https://api.github.com/repos/${context.repository}/check-runs/${id}`, + const jobs = ids.map((id, i) => ({ id, run_id: 90, head_sha: identity.parents[1], name: `browser (${i + 1})`, status: "completed", conclusion: "success", check_run_url: `https://api.github.com/repos/${context.repository}/check-runs/${id}`, steps: [{ name: "Complete browser proof", status: "completed", conclusion: "success" }] })); const logs = receipts.map(r => `2026-07-12T00:00:00Z ${identity.sha}\n2026-07-12T00:00:01Z refs/remotes/pull/42/merge\n2026-07-12T00:00:02Z BRAIN_PROOF_RECEIPT ${JSON.stringify(r)}\n`); const api: API = { async json(path) { calls.push(path); if (path === "actions/runs/90/attempts/1") return run; - if (path === "actions/runs/90/attempts/1/jobs?per_page=100") return { total_count: 2, jobs }; + if (path === "actions/runs/90/attempts/1/jobs?per_page=100") return { total_count: jobs.length, jobs }; if (path.startsWith("check-runs/")) return { id: Number(path.split("/").at(-1)), head_sha: identity.parents[1], status: "completed", conclusion: "success", app: { slug: "github-actions" } }; if (path === `git/commits/${identity.sha}`) return { sha: identity.sha, tree: { sha: identity.tree }, parents: identity.parents.map(sha => ({ sha })) }; throw new Error(`Unexpected API ${path}`); @@ -103,6 +105,8 @@ test("logs must contain one fresh receipt tied to the actual checkout and correc expect(() => receiptFromLog(logs[0]! + logs[0], "browser", 1)).toThrow("ambiguous"); expect(() => receiptFromLog(logs[0]!.split("\n").slice(1).join("\n"), "browser", 1)).toThrow("actual job checkout"); expect(() => receiptFromLog(logs[0]!, "browser", 2)).toThrow("Wrong fresh"); + // A receipt from the two-shard era names another partition and is never admitted (#2414). + expect(() => receiptFromLog(logs[0]!.replace(`"shard":"1/${PROOF_SHARDS.browser}"`, `"shard":"1/2"`), "browser", 1)).toThrow("Wrong fresh"); }); test("successful immutable source receipts validate against APIs", async () => { const root = fixture(), inputs = proofInputs(root, "browser", inventory, runner); diff --git a/tests/refresh-browser-costs.test.ts b/tests/refresh-browser-costs.test.ts index 3840b187b..ba2618098 100644 --- a/tests/refresh-browser-costs.test.ts +++ b/tests/refresh-browser-costs.test.ts @@ -3,26 +3,28 @@ import {readFileSync} from "node:fs"; import {resolve} from "node:path"; import { refreshBrowserCosts } from "../scripts/refresh-browser-costs"; import type { API } from "../scripts/proof-reuse"; +import { PROOF_SHARDS, shardNumbers } from "../scripts/proof-shards"; const sha = "a".repeat(40), parent = "b".repeat(40), tree = "c".repeat(40); const image = "mcr.microsoft.com/playwright:v1.63.0-noble"; const stamp = "2026-07-12T00:00:00Z "; function fixture(domain: "browser" | "layout" = "layout") { const project = domain === "layout" ? "ui-react-layout" : "visual"; - const logs = [1, 2].map(shard => [ + const count = PROOF_SHARDS[domain]; + const logs = shardNumbers(domain).map(shard => [ `${stamp}[command]/usr/bin/git log -1 --format=%H`, `${stamp}${sha}`, `${stamp}Status: Downloaded newer image for ${image}`, - `${stamp}Measured browser shard ${shard}/2: 1/2 specs; 0 recorded weights, 2 positive defaults`, + `${stamp}Measured browser shard ${shard}/${count}: 1/${count} specs; 0 recorded weights, ${count} positive defaults`, `${stamp}✓ ${project} (chromium) ../ui-react/tests/browser/odysseus-${shard}.layout.tsx (1 test) ${shard * 1000}ms`, `${stamp}Test Files 1 passed (1)`, ].join("\n")); const run = { id: 42, run_attempt: 1, status: "completed", conclusion: "success", event: "push", path: ".github/workflows/ci.yml", head_sha: sha, repository: { full_name: "schlessera/brain-kit" } }; - const jobs = [1, 2].map(shard => ({ id: shard, run_id: 42, head_sha: sha, name: `${domain} (${shard})`, status: "completed", conclusion: "success", + const jobs = shardNumbers(domain).map(shard => ({ id: shard, run_id: 42, head_sha: sha, name: `${domain} (${shard})`, status: "completed", conclusion: "success", steps: [{ name: `Complete ${domain} proof`, status: "completed", conclusion: "success" }] })); const commit = { sha, tree: { sha: tree }, parents: [{ sha: parent }] }; const source = { encoding: "base64", content: Buffer.from(`const IMAGE = "${image}";`).toString("base64") }; - const page = { total_count: 2, jobs }; + const page = { total_count: jobs.length, jobs }; const api: API = { async json(path) { if (path === "actions/runs/42/attempts/1") return run; @@ -51,6 +53,9 @@ test("attributed layout refresh preserves browser costs and provenance, then bro expect(refreshed.seconds["ui-react-layout::packages/ui-react/tests/browser/odysseus-1.layout.tsx"]).toBe(1); expect(refreshed.measurements?.layout).toEqual(layout.measurements?.layout); expect(refreshed.seconds["visual::packages/ui-kit/tests/visual/odysseus.visual.tsx"]).toBeUndefined(); + // Browser measurements come from every configured shard, not a fixed pair (#2414). + expect(refreshed.measurements?.browser).toMatchObject({ jobs: shardNumbers("browser") }); + expect(Object.keys(refreshed.seconds).filter(key => key.startsWith("visual::"))).toHaveLength(PROOF_SHARDS.browser); }); test("cancelled layout job cannot supply admitted measurements despite passing file logs", async () => { From d4cc90500ec9ac0e9a8457f0f203ac494407661a Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Sun, 18 Oct 2026 10:52:36 +0200 Subject: [PATCH 4/4] test(ci): reject a drifted layout shard matrix independently Also state that the inclusion fingerprint binds each domain's measured partitions rather than two, and that layout keeps two shards. Refs #2414 Co-Authored-By: Claude Opus 5.5 --- docs/decisions/ci-utility.md | 4 ++-- tests/ci-workflows.test.ts | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/decisions/ci-utility.md b/docs/decisions/ci-utility.md index f2387f371..e9979186e 100644 --- a/docs/decisions/ci-utility.md +++ b/docs/decisions/ci-utility.md @@ -142,7 +142,7 @@ inputs, never runtime dependencies. Layout refresh admits ordinary fresh job and never becomes an ordinary browser/layout weight. Requalify timing inputs after scenario ownership changes: the former combined recording-file measurement includes endurance and is not its current ordinary-layout cost. -Two layout shards, per-project serial execution and all deadlines remain unchanged. +Layout keeps two shards; per-project serial execution and all test deadlines remain unchanged. Browser proof runs in three shards and its jobs have a 20-minute bound. It was raised from 15 minutes after browser (2) reached 887 s on main and 917 s on a ready PR ([#2414](https://github.com/schlessera/brain-kit/issues/2414)). A weight refresh still qualifies by measured whole-job elapsed time, not by the bound. @@ -560,7 +560,7 @@ locked installed resources. No current output or untracked image enters this snapshot, and baseline changes cannot inherit old passing comparisons. The inclusion fingerprint binds relevant immutable Git paths, blob identities -and modes, selected discovery ownership/order, the two measured partitions and +and modes, selected discovery ownership/order, the domain's measured partitions (`PROOF_SHARDS`) and runner identity. It also includes every proof/tooling script and workflow, root/package manifests and lockfiles, compiler configuration and expanded build source inventories. These conservative shared harness inputs can invalidate diff --git a/tests/ci-workflows.test.ts b/tests/ci-workflows.test.ts index b48c759f0..fbb794b9d 100644 --- a/tests/ci-workflows.test.ts +++ b/tests/ci-workflows.test.ts @@ -354,6 +354,9 @@ test("browser and layout matrices match the shared shard table (#2414)", () => { expect(workflowProblems(text.replace("shard: [1, 2, 3]", "shard: [1, 2]"), "ci.yml").join("\n")).toContain("browser: matrix and shard divisor must match PROOF_SHARDS"); expect(workflowProblems(text.replace("browser --shard=${{ matrix.shard }}/3", "browser --shard=${{ matrix.shard }}/2"), "ci.yml").join("\n")).toContain("browser: matrix and shard divisor must match PROOF_SHARDS"); expect(workflowProblems(text.replace("layout --shard=${{ matrix.shard }}/2", "layout --shard=${{ matrix.shard }}/3"), "ci.yml").join("\n")).toContain("layout: matrix and shard divisor must match PROOF_SHARDS"); + const layoutMatrix = text.indexOf("shard: [1, 2]\n", text.indexOf(" layout:\n")); + expect(layoutMatrix).toBeGreaterThan(0); + expect(workflowProblems(text.slice(0, layoutMatrix) + "shard: [1, 2, 3]\n" + text.slice(layoutMatrix + "shard: [1, 2]\n".length), "ci.yml").join("\n")).toContain("layout: matrix and shard divisor must match PROOF_SHARDS"); }); test("small exact inventories wire bounded planner partitions into actual unit execution", () => {