返回 DeepSeek-Reasonix
check-bundle-budget.mjs
根目录 / desktop / frontend / scripts / check-bundle-budget.mjs
1 import { readFileSync, readdirSync, statSync } from "node:fs";
2 import { basename, resolve } from "node:path";
3 import { gzipSync } from "node:zlib";
4
5 const distDir = resolve("dist");
6 const indexPath = resolve(distDir, "index.html");
7 const html = readFileSync(indexPath, "utf8");
8
9 function gzipBytes(path) {
10 return gzipSync(readFileSync(path), { level: 9 }).byteLength;
11 }
12
13 function initialAssetPaths(extension) {
14 const pattern = extension === ".js"
15 ? /<(?:script|link)\b[^>]+(?:src|href)=["']([^"']+\.js)["'][^>]*>/g
16 : /<link\b[^>]+href=["']([^"']+\.css)["'][^>]*>/g;
17 return [...new Set([...html.matchAll(pattern)].map((match) => resolve(distDir, match[1])))];
18 }
19
20 function formatKiB(bytes) {
21 return `${(bytes / 1024).toFixed(1)} KiB`;
22 }
23
24 function assertBudget(label, actual, budget) {
25 if (actual > budget) {
26 throw new Error(`${label} is ${formatKiB(actual)} (${actual} B); budget is ${formatKiB(budget)} (${Math.floor(budget)} B)`);
27 }
28 process.stdout.write(` PASS ${label}: ${formatKiB(actual)} / ${formatKiB(budget)}\n`);
29 }
30
31 const initialJS = initialAssetPaths(".js");
32 const initialCSS = initialAssetPaths(".css");
33 if (!initialJS.length) throw new Error("no initial JavaScript assets found in dist/index.html");
34 // initial CSS 允许为空:styles.css 走 ?url 延迟加载,feature 样式走 lazy chunk。
35
36 // main.tsx intentionally loads styles.css before mounting React so the inline
37 // boot shell can paint without waiting for the full application stylesheet.
38 // Vite emits that entry as styles-<hash>.css; keep it in the startup budget
39 // while also proving it never drifts back into the render-blocking HTML path.
40 const appShellCSS = readdirSync(resolve(distDir, "assets"))
41 .filter((name) => /^styles-.+\.css$/.test(name))
42 .map((name) => resolve(distDir, "assets", name));
43 if (appShellCSS.length !== 1) {
44 throw new Error(`expected exactly one deferred app-shell stylesheet, found ${appShellCSS.length}`);
45 }
46 if (initialCSS.some((path) => appShellCSS.includes(path))) {
47 throw new Error("app-shell stylesheet must not block the inline boot shell's first paint");
48 }
49
50 const initialJSGzip = initialJS.reduce((total, path) => total + gzipBytes(path), 0);
51 const initialCSSGzip = initialCSS.reduce((total, path) => total + gzipBytes(path), 0);
52 const appShellCSSGzip = appShellCSS.reduce((total, path) => total + gzipBytes(path), 0);
53 const largestInitialJS = Math.max(...initialJS.map(gzipBytes));
54 const largestInitialJSRaw = Math.max(...initialJS.map((path) => statSync(path).size));
55 const localeChunks = readdirSync(resolve(distDir, "assets"))
56 .filter((name) => /^(?:zh|zh-TW)-.+\.js$/.test(name))
57 .map((name) => resolve(distDir, "assets", name));
58
59 console.log("\nbundle budgets");
60 // React Virtuoso replaces the transcript's custom measurement/anchor engine.
61 // Its production runtime adds 16.9 KiB gzip (4.2%) over the 402 KiB baseline.
62 // This exceptional overrun is locally attributable and trades ~1400 lines of
63 // competing state machines for a maintained library. Native-tail finish helpers
64 // then sat on the 423.5 KiB gate (Windows CI: 423.5 / 423.5); this 0.5 KiB
65 // raise (0.12%) absorbs that leave-cancel / remasure-once code without
66 // widening the original Virtuoso exception. The project-tree archive race
67 // guards add 611 bytes gzip over main-v2's 423.988 KiB startup path after the
68 // blank-project flow landed; project-topic sort invalidation and request
69 // ordering add another bounded 0.2 KiB. Retain both owner boundaries with a
70 // narrowly rounded 1 KiB ratchet.
71 // Diagnostic builds intentionally keep content-free row geometry and scroll
72 // transition probes in the initial transcript path. Stable builds retain the
73 // existing production ratchet. Per-row measurement versions and a bounded
74 // recovery probe add less than 0.1% gzip; retain them with a 0.5 KiB (0.118%)
75 // production ratchet rather than weakening either recovery contract. The
76 // bounded allowance also covers small gzip drift from the embedded build SHA.
77 // Reader extent stabilization adds 1.2 KiB gzip (0.28%) in production for its
78 // bounded input, collapse, rebound, and ownership transaction. Retain it with
79 // a 1.5 KiB (0.35%) ratchet instead of weakening the Windows scroll invariant.
80 // Complete-history navigation adds 0.3 KiB gzip (0.070%) to that production
81 // path while keeping its 1.68 KiB question rail lazy-loaded. Test diagnostics
82 // plus the navigation owner add 0.7 KiB gzip (0.164%) over the merged test gate.
83 // DingTalk channel status and locale wiring move the current-base production
84 // build from 427.2 to 427.7 KiB and test from 428.6 to 429.1 KiB. The unified
85 // state-aware geometry contract, session diagnostics counters, and guarded
86 // native-scroll probes add 2.4 KiB gzip to the initial path. The current
87 // main-v2 merge adds another 0.3 KiB of deterministic shared startup code.
88 // Keep the increase explicit and bounded instead of hiding it in a broad
89 // percentage ratchet.
90 // The retained-transcript surface adds a small, bounded navigation owner to
91 // the startup path (overlay state + stale-completion guard). Keep the increase
92 // explicit and narrow; the measured build is 431.1 KiB gzip.
93 // The web-search tool card now resolves the same display projection lazily so
94 // its filtered count matches the assistant Sources panel. The measured build
95 // is 431.509 KiB gzip; keep 0.1 KiB of explicit headroom for hash/toolchain
96 // drift instead of relying on a rounded equality.
97 // Remote onboarding [0.5/3] adds project-group and credential-chain wiring on
98 // top of the lazy wizard. Exact-turn routing, the extracted event-gap
99 // projector, checkpoint resets, and the navigation surface transaction bring
100 // the current main-v2 path to 437.36 KiB gzip.
101 // The full remote-session surface adds the lazy transcript bridge and tab
102 // lifecycle on top of [0.5/3]. Keep the measured stack's narrow ratchet.
103 // Remote approval hardening adds authoritative composer-profile hydration,
104 // scoped rewind dispatch, and attachment/inbox fences to the always-mounted
105 // remote hook. The measured production path is 438.38 KiB gzip after keeping
106 // the integration modules below repolint's ownership ceilings; retain 0.12 KiB
107 // toolchain headroom with a bounded 1.4 KiB ratchet.
108 // Remote status isolation keeps the always-mounted status bar on the active
109 // remote transcript and routes job cancellation to that host. Parsers and
110 // retry policy remain lazy; the measured selector adds under 0.1 KiB gzip.
111 // Remote runtime parity adds scoped approvals, status-only reconciliation,
112 // session quality-floor routing, dropped-frame reconciliation, and remote
113 // runtime-command dispatch. The measured initial path is 439.60 KiB;
114 // retain 0.10 KiB of bounded toolchain headroom.
115 // Closing the remaining review gaps adds generation-fenced hydration plus
116 // remote-only tool payload, Todo, and terminal isolation. The measured path is
117 // 439.74 KiB; retain 0.06 KiB of headroom with a 0.1 KiB ratchet.
118 // The final remote-runtime parity pass adds remote run-strip telemetry,
119 // explicit session verbs, and specialized plan decisions. The measured path
120 // is 440.02 KiB. The current main-v2 turn-event, finish-protocol, and session
121 // repair runtime then moves the combined path to 445.097 KiB; retain 0.103 KiB
122 // of bounded build/toolchain headroom.
123 // Atomic remote profile changes, exact approval draining, and generation-safe
124 // history handoff bring the measured path to 445.228 KiB. Retain 0.072 KiB of
125 // headroom with the smallest existing decimal ratchet.
126 // Direct pending-prompt recovery and authoritative remote Goal state bring the
127 // measured path to 445.473 KiB. Retain 0.027 KiB of bounded headroom.
128 // Restored remote shells now activate their backend session immediately and
129 // keep disconnected state out of the mounted surface. The merged production
130 // path measures 445.614 KiB; retain 0.086 KiB of bounded build/toolchain
131 // headroom with the smallest existing decimal ratchet.
132 // Runtime-aware Todo presentation plus exact-tab continuation adds 0.3 KiB gzip
133 // to the always-mounted footer path. Keep the state/routing guard with a narrow
134 // ratchet rather than showing idle restored work as actively running. The
135 // combined path measures 445.9 KiB; retain 0.1 KiB of toolchain headroom.
136 // Transcript surface ownership and the token-fenced unloaded-question commit
137 // move the exact main-v2 baseline from 445.865 to 447.587 KiB gzip (+0.39%).
138 // The final 0.266 KiB retains jump ownership through paint-ready instead of
139 // allowing a native scrollend to release it. Keep only 0.213 KiB headroom;
140 // native validation hosts and test fixtures stay outside the production graph.
141 // Cross-platform shell inventory, current-session vs after-reload rows,
142 // manual repair guidance, and exact download-host allowlisting move the merged
143 // path from 448.692 to 449.758 KiB (+1.066 KiB). Retain 0.142 KiB of bounded
144 // build/toolchain headroom.
145 // The reader transaction contract (geometry revisions, generation-fenced
146 // writer requests, gesture travel proof, stabilized-shrink extent acceptance,
147 // and the blank-rebound prepaint lane) adds a measured 3.978 KiB gzip on the
148 // merged main-v2 baseline. MCP elicitation and the inline Apps lifecycle remain
149 // on that startup graph; the combined path measures 455.0 KiB. Retain 0.2 KiB
150 // of bounded build/toolchain headroom.
151 // Generic elicitation validation adds field-specific localized accessibility
152 // copy to the English startup dictionary. The interaction code and CSS remain
153 // lazy; the measured path is 455.437 KiB. Retain 0.163 KiB of headroom.
154 // Stream-failure visibility (#9560) adds the last-discard reason and one
155 // terminal-notice dedupe flag, while provider no_proxy copy now states the
156 // custom-proxy precedence. The merged path measures 455.9 KiB; retain 0.1 KiB
157 // of bounded build/toolchain headroom.
158 // Exhausted tail repair now releases ownership so jump-bottom remains usable
159 // after a stranded native WebView extent. The WebView2 reachable-tail clamp
160 // then absorbs a second post-quiet extent without an unbounded write loop.
161 // The combined path measures 456.316 KiB; retain 0.084 KiB with the smallest
162 // one-decimal ratchet.
163 // The generation-bound history-prepend lease adds stable-key reader anchoring,
164 // full mounted coverage, and one final arbiter-owned correction. The measured
165 // path is 457.406 KiB after extracting the lease owner to satisfy repolint.
166 // Latest-base transcript settle ownership measures 457.523 KiB with this UX.
167 // Isolated conversation forks and their extracted browser mock adapter bring
168 // the combined tree to 458.158 KiB; completion uncertainty adds a terminal
169 // outcome and notice without exposing evaluator audits to the frontend,
170 // measuring 458.287 KiB gzip.
171 // Transactional Ask resolution and authoritative rejected-submit recovery add
172 // 0.3 KiB gzip to the initial controller path. Retain the exact turn fence,
173 // bounded ListTabs retry, and stale-prompt guard.
174 // Session-catalog repair presentation stays in the lazy project-tree chunk;
175 // compact shared helpers keep the combined initial path within the same gate.
176 // Merge-Back adds identity-bound inspection, navigation, and retained-recovery
177 // orchestration on top. The merged stable build measures 461.338 KiB and the
178 // test channel measures 461.323 KiB. Deferring selection ownership until a
179 // real range exists (#9703/#9711) and adding the session takeover banners
180 // move the combined path to 462.2 KiB. Local spectator reclaim adds the
181 // desktop-vs-remote command branch. Sticky Context's session-scoped file chips
182 // bring the merged stable path to 462.587 KiB. Windows' embedded build metadata
183 // lands just above the rounded 462.6 KiB boundary; retain one cross-platform
184 // decimal step without widening any chunk or raw gate.
185 // Reading the applied item-list transform (instead of the remembered offset)
186 // keeps the reader/anchor visual guards from compounding under reduced-motion
187 // WebView2; the merged path measures 462.827 KiB. Retain one decimal step.
188 // Generation-bound native-thumb transactions and the rebased custom-scrollbar
189 // drag add 0.3 KiB gzip; the merged path measures 463.102 KiB.
190 // Absorbing content-preserving block-window prepends into the active reader
191 // transaction adds 0.2 KiB gzip on top; the merged path measures 463.292 KiB,
192 // 8 bytes under the next decimal. Retain one cross-platform decimal step.
193 // The subagent outcome envelope, partial-state card, and history hydration add
194 // 0.5 KiB gzip on the initial path. The model-capability resolver and its
195 // read-only provider badges add a measured 0.2 KiB including gzip/toolchain
196 // rounding. The integrated management shell, image capability controls, and
197 // upstream updater refresh measure 465.4 KiB gzip (base: 464.7 KiB).
198 // Keep the next decimal ceiling and leave feature editors lazy.
199 // Durable protocol recovery controls and search-source status add 1.2 KiB
200 // over the same-environment main-v2 build (465.4 -> 466.6 KiB gzip).
201 // Keep one decimal of cross-platform headroom for this measured shell change.
202 // Integrating main-v2 rich-link menus measures 466.905 KiB combined.
203 // The AskCard session-draft wiring adds a bounded 30-byte gzip drift on the
204 // initial route. The session-runtime ordering fence adds 56 bytes and
205 // cross-platform zlib rounding reaches the same startup path; retain the
206 // explicit budget rather than failing on a rounded 467.0 KiB display value.
207 // The latest main-v2 session-runtime fence and exact prompt protocol measure
208 // 468.2 KiB here; retain a 0.1 KiB ceiling for platform zlib rounding.
209 // Mainline provider/settings integration measures 469.230 KiB gzip.
210 const initialJSBudgetKiB = 469.3;
211 assertBudget("initial JavaScript gzip", initialJSGzip, initialJSBudgetKiB * 1024);
212 assertBudget("largest initial JavaScript chunk gzip", largestInitialJS, 280 * 1024);
213 // Render-blocking CSS is intentionally absent: styles.css loads deferred via
214 // ?url, and feature styles (heartbeat) live in lazy chunks loaded on demand.
215 // An empty initial CSS list is the desired state, not a build error.
216 if (initialCSS.length > 0) {
217 assertBudget("render-blocking CSS gzip", initialCSSGzip, 4 * 1024);
218 } else {
219 process.stdout.write(" PASS render-blocking CSS: none (all styles deferred)\n");
220 }
221 // Extension surfaces, Task Monitor, and compact decision receipts share the
222 // application stylesheet loaded before React mounts. Keep their combined
223 // allowance bounded even though the file is no longer render-blocking.
224 // Navigation overlay styles add a bounded 0.1 KiB to the deferred shell.
225 // The cleaned source panel adds 0.1 KiB gzip to the deferred shell on top of
226 // the retained-transcript navigation allowance; keep the ratchet explicit.
227 // The navigation mask's stable composer footprint and remote tab/surface
228 // states bring the merged shell to roughly 115.7 KiB gzip.
229 // The one-row model configuration list, responsive stacking, Automation's
230 // shared title-safe shell, and the shared harness decision surface measure
231 // 116.9 KiB gzip while reusing existing layout primitives. Retain a bounded
232 // 0.1 KiB headroom ratchet.
233 // Workbench welcome and recovery styles measure 122869 B gzip on main-v2.
234 // Turn result styles add 388 B after removing obsolete metrics (123257 B).
235 // The dock launcher, tab container and tab picker add ~0.6 KiB (the ported
236 // card, branch switcher, tab strip, add menu, empty-state picker and the
237 // spacer that starts the panel below the topic bar).
238 assertBudget("deferred app-shell CSS gzip", appShellCSSGzip, 121.2 * 1024);
239 if (localeChunks.length !== 2) {
240 throw new Error(`expected 2 on-demand Chinese locale chunks, found ${localeChunks.length}`);
241 }
242 for (const path of localeChunks) {
243 const name = basename(path);
244 // Task Monitor, billing, indexed history, Task Center, Extension UI, and
245 // runtime controls plus execution-setting receipts add localized copy. The
246 // write-access approval card adds four scoped actions and a home-risk
247 // warning (~0.15 KiB gzip, +0.27% over the old 54.75 gate). Context
248 // compaction settings add 40 bytes gzip of policy guidance to simplified
249 // Chinese, while scheduled billing adds compact rate-band labels/tooltips.
250 // The three StepFun presets add localized names/descriptions (~0.1 KiB
251 // gzip); the two pay-as-you-go presets add the same again. The delivery
252 // floor segmented control adds two labels plus one explanatory tooltip,
253 // measured at 23 B gzip for zh and 8 B for zh-TW. Completion receipts add
254 // six short status labels in each locale, requiring another 0.2 KiB per
255 // language. DingTalk setup and mention guidance add at most 0.2 KiB more
256 // (0.36%); retain the complete security and group-chat copy instead of
257 // abbreviating user-facing instructions to fit the old locale ratchet.
258 // Recovery-copy and catalog-only sidebar labels can move the simplified
259 // Chinese chunk across the rounded 55.9 KiB boundary on CI's Node/zlib;
260 // retain a narrow 0.1 KiB headroom rather than making gzip output a
261 // platform-dependent gate. The OpenCode one-key setup adds product-level
262 // connection, fallback, and legacy-state copy while removing protocol
263 // choices from the primary UI; keep that complete guidance with a bounded
264 // 0.4–0.5 KiB locale-only ratchet.
265 // Git-Bash installation guidance adds localized copy across dialects.
266 // MCP elicitation adds fourteen short labels per locale (~40 B gzip).
267 // Generic schema validation adds complete field-error, privacy, and safe-
268 // fallback copy. Measured chunks are 58.574 KiB zh and 59.368 KiB zh-TW;
269 // retain roughly 0.13 KiB of platform headroom for each.
270 // Stream-failure diagnostics add five strings per dialect. Together with the
271 // reachable-tail recovery copy, the merged chunks measure 58.923 KiB zh and
272 // 59.710 KiB zh-TW. The isolated-fork guidance brings the measured chunks
273 // to 59.1 KiB zh and 59.9 KiB zh-TW; retain a narrow one-decimal ratchet.
274 // Merge-Back lifecycle and recovery guidance measure 59.819 KiB zh and
275 // 60.612 KiB zh-TW; retain only the next one-decimal ceiling for each.
276 // The retained-recovery receipt and copy action move zh to 59.911 KiB;
277 // session-catalog recovery guidance on the merged base moves zh-TW to
278 // 60.757 KiB; retain only its exact one-decimal ceiling.
279 // Session takeover adds ~20 locale keys per dialect (banners, dialog,
280 // reclaim), while Sticky Context adds file-state and limit diagnostics. The
281 // merged stable chunks measure 60.395 KiB zh and 61.232 KiB zh-TW; retain
282 // only the next one-decimal ceiling for each dialect.
283 // The outcome card adds one short localized status label per dialect. CI's
284 // Windows zlib measured zh at 60.4 KiB exactly; capability-status copy adds
285 // a small 0.1 KiB ratchet, so retain the next decimal ceiling rather than
286 // dropping the unknown-state explanation.
287 // Image input mode, provenance and unknown-state guidance measure 60.724 KiB
288 // zh and 61.570 KiB zh-TW. Keep the next decimal ceiling per locale.
289 // Protocol recovery and source-availability copy measure 60.927 KiB zh
290 // and 61.789 KiB zh-TW (base: 60.8 / 61.6 rounded).
291 // Rich-link action copy on the current base brings these to
292 // 61.027/61.881 KiB; retain bounded cross-platform headroom.
293 // Recovery retry copy reaches the rounded 61.1 KiB boundary on Node/zlib
294 // toolchains; keep the next one-decimal ceiling for cross-platform CI.
295 // The #9889/#9890 series adds recovery-wait, dialog-failure, and stall copy:
296 // zh-TW measures 63492 B (62.004 KiB) with the four PRs merged together.
297 // Integrated settings and ownership copy measures 61.415 / 62.212 KiB.
298 // Session-log head versions (head kinds, current/covered wording, and the
299 // three head notices) measure 61.7 / 62.4 KiB; keep the next one-decimal
300 // ceiling for cross-platform CI.
301 // Search assignment copy adds 239 / 231 B over main-v2 (63147 / 63920 B).
302 // Measured result: 63386 / 64151 B; retain bounded cross-platform headroom.
303 // Saved/pending/apply-failure guidance adds 233 / 245 B: 63619 / 64396 B
304 // with gzip level 9. Keep the next decimal ceiling for these four keys.
305 // Session recovery guidance adds 173 / 156 B over main-v2, measuring
306 // 62.173 / 62.887 KiB. Keep only the next one-decimal ceiling.
307 // Combined recovery and model-application copy measures 63791 / 64557 B.
308 // Turn result copy adds 554 / 566 B to the latest-base chunks, measuring
309 // 64219 / 64964 B with recovery guidance included. Round to the next tenth.
310 // Combined turn-result and model-application copy measures 64342 / 65119 B.
311 // Runtime/receipt confirmation copy adds 89 / 99 B to the integrated
312 // turn-result base (64219 / 64964 B). Measured: 64308 / 65063 B.
313 // Read-pause copy merges on top of that base: the combined chunks measure
314 // 64606 / 65349 B, so both dialect ceilings ratchet to the next tenth.
315 // Model-application copy on the read-pause base measures 64734 / 65499 B,
316 // adding 128 / 150 B. Retain only the next one-decimal ceiling.
317 const budget = name.startsWith("zh-TW-") ? 64.0 * 1024 : 63.3 * 1024;
318 assertBudget(`${name} gzip`, gzipBytes(path), budget);
319 }
320
321 const rawInitialBytes = [...initialJS, ...initialCSS, ...appShellCSS]
322 .reduce((total, path) => total + statSync(path).size, 0);
323 // The maintained Virtuoso engine adds 49.1 KiB raw (2.2%) over the previous
324 // 2268.7 KiB gate. Navigation remains inside the 2341 KiB production ceiling;
325 // its combined diagnostic wiring adds 2.2 KiB (0.094%) to the test channel.
326 // DingTalk startup wiring moves current-base production from 2341.0 to 2343.6
327 // KiB and test from 2346.2 to 2348.8 KiB; the pinned heading adds 0.5 KiB raw
328 // (0.021%). The workspace panel rework (change-row hover/revert, status badges,
329 // More menu, completion summary) makes the latest-base merge 2353.1 KiB in
330 // production and test channels both measure 2357.92 KiB after project-group
331 // wiring. Exact-turn routing, checkpoint resets, and failure-atomic navigation
332 // bring the current main-v2 path to 2379.22 KiB. The remote approval
333 // fences, extracted ownership modules, and remote status-bar isolation bring
334 // the measured initial payload to 2380.9 KiB; retain 0.1 KiB of bounded
335 // raw/toolchain headroom. Scoped remote approvals, status reconciliation, and
336 // runtime command dispatch bring the measured payload to 2382.9 KiB. The
337 // remaining review fences measure 2383.2 KiB; retain 0.1 KiB of headroom.
338 // Final remote-runtime parity measures 2384.4 KiB raw. The current main-v2
339 // runtime additions bring the combined path to 2404.364 KiB. The final merged
340 // restored-shell activation and disconnected-state revival path measures
341 // 2404.898 KiB; retain 0.102 KiB of bounded headroom alongside the gzip
342 // ratchet above.
343 // Runtime-aware Todo status and exact-tab continuation then add to the same
344 // initial path. The combined payload measures 2406.2 KiB; retain 0.1 KiB of
345 // raw/toolchain headroom for both owners.
346 // The same transcript transaction measures 2413.012 KiB raw (+0.28%) against
347 // the 2406.204 KiB baseline. Retain 0.188 KiB of bounded headroom.
348 // The notification-volume control adds one persisted master gain, per-source
349 // loudness trims, and its accessible Settings surface. Current main-v2 moves
350 // from 2413.183 to 2414.879 KiB raw (+1.696 KiB); retain 0.121 KiB of bounded
351 // headroom.
352 // Owner-lifecycle reasoning disclosure, pre-paint tail pinning, and the live
353 // footer growth floor then add 2.390 KiB after extracting ownership modules
354 // below repolint's source ceilings. Lifecycle fencing adds 0.258 KiB; the
355 // combined path measures 2417.526 KiB. Retain 0.074 KiB while preventing
356 // phase-boundary reverse flashes and cross-surface floor leaks.
357 // The same shell-support surface moves the merged path from 2417.526 to
358 // 2422.371 KiB raw (+4.845 KiB). Retain 0.129 KiB of bounded headroom without
359 // widening unrelated chunk ceilings.
360 // The WebView2 extent rebound prepaint handoff adds 0.204 KiB raw so a native
361 // scroll delivery can restore mounted coverage before the next visible frame.
362 // Retain 0.096 KiB of headroom without widening gzip or chunk ceilings.
363 // The reader transaction contract then adds a measured 15.317 KiB raw on the
364 // merged main-v2 baseline (including its own prepaint port). MCP elicitation
365 // and Apps add their bounded payload on the shared graph; the combined path
366 // measures 2442.6 KiB. Retain 0.4 KiB of bounded build/toolchain headroom.
367 // The browser MCP interaction preview adds 0.6 KiB of route wiring while its
368 // 0.75 KiB form fixture and lifecycle remain lazy. The combined path measures
369 // 2443.2 KiB; retain 0.1 KiB of bounded build/toolchain headroom.
370 // Generic field copy adds 1.134 KiB raw to the startup dictionary; all schema
371 // parsing, rendering, and CSS remain lazy. The measured path is 2444.334 KiB;
372 // retain 0.166 KiB of bounded build/toolchain headroom.
373 // The off-flow composer measurement mirror adds 0.472 KiB raw while removing
374 // live-textarea layout mutation. The merged path measures 2444.806 KiB; retain
375 // 0.194 KiB of bounded toolchain headroom without widening gzip/chunk gates.
376 // Stream-failure visibility and corrected proxy guidance bring the merged path
377 // to 2446.6 KiB; retain the smallest existing decimal ratchet.
378 // The stranded-tail recovery transition plus the WebView2 reachable-tail clamp
379 // bring the measured initial payload to 2447.953 KiB. Retain 0.047 KiB with
380 // the smallest one-decimal ratchet.
381 // The extracted history-prepend owner adds 3.953 KiB of bounded transaction
382 // state and stable-key coverage checks. Together with the compact
383 // session-version host, they measure 2452.7 KiB; the recovery coordinator and
384 // dialog remain lazy. Completion uncertainty adds a distinct terminal notice
385 // and localized startup copy without collapsing into recovery-paused UX.
386 // 2454.719 KiB on the release toolchain. Completion uncertainty brings the
387 // final merged payload to 2455.154 KiB.
388 // Ask turn fencing, rejection reconciliation, and the localized submit-failure
389 // notice measure 2456.044 KiB raw; retain 0.056 KiB of one-decimal headroom.
390 // Merge-Back's startup ownership and failure-atomic navigation fence add the
391 // remaining bounded payload. The retained recovery receipt makes the stable
392 // path 2465.105 KiB raw; the merged test channel measures 2464.979 KiB.
393 // Session takeover banners and #9703/#9711's provisional-selection handoff
394 // combine with Sticky Context's pinned-file state at 2469.125 KiB raw on the
395 // merged stable path. Retain only the next one-decimal ceiling.
396 // The passive reader-anchor lease for delayed WebView2 range commits measures
397 // 2469.347 KiB raw (+0.222 KiB, +0.009%). Retain only the next one-decimal
398 // ceiling; gzip and largest-chunk budgets remain unchanged.
399 // Reading the applied item-list transform for the reader/anchor visual guards
400 // adds 0.5 KiB raw on top; the merged path measures 2469.815 KiB.
401 // The scrollbar generation fence and drag rebase add 1.1 KiB raw; the merged
402 // path measures 2470.932 KiB.
403 // The reader-transaction offset absorption adds 0.8 KiB raw on top; the merged
404 // path measures 2471.741 KiB. Controller-owned management dispositions and
405 // optimistic management settlement add 0.6 KiB raw; retain the smallest
406 // one-decimal ceiling with bounded headroom.
407 // The outcome card and history hydration add 2.3 KiB raw on the initial path
408 // (2474.0 KiB measured in CI). Keep this narrowly attributable ratchet rather
409 // than removing persisted-result visibility or changing chunk ownership.
410 // On the current main-v2 base, the combined measured path is 2474.6 KiB;
411 // the model-capability helper and localized status copy add 0.9 KiB; retain
412 // the smallest bounded cross-platform ceiling.
413 // Retain the upstream updater ceiling and independent chunk gates.
414 // Recovery controls add 3.6 KiB raw over the measured 2480.9 KiB base;
415 // current payload is 2484.509 KiB. Retain only bounded toolchain headroom.
416 // With the current-base rich-link menus: 2485.715 KiB raw.
417 // The shared harness decision surface adds a bounded startup stylesheet
418 // payload. The current base plus exact prompt identity and stale-card recovery
419 // measure 2496.4 KiB locally; retain the smallest bounded ceiling.
420 // The context truncation-rescue notice and its three locale strings measure
421 // 2496.6 KiB; retain the smallest bounded ceiling.
422 // Deferred presentation measured 2381.4 KiB before first-materialization
423 // preloading. Mainline Stop brings the payload to 2381.8 KiB;
424 // Mainline recovery UI brings it to 2384.5 KiB, and tool elapsed/liveness
425 // UI to 2384.9 KiB. Retain 0.2 KiB headroom.
426 // Mainline provider/settings integration measures 2398.2 KiB in the
427 // extracted shell. Retain the same bounded 0.2 KiB build headroom.
428 // The head-version dialog copy and its covered-version cleanup control
429 // measure 2399.2 KiB; retain the same bounded 0.2 KiB build headroom.
430 // Search-assignment bridge and metadata add 1.0 KiB over the measured
431 // main-v2 baseline (2399.3 KiB); result 2400.3 KiB plus 0.2 KiB headroom.
432 // Workbench welcome plus toolbar-refresh integration measures 2401.108 KiB
433 // against the 2398.0 KiB base; retain only the next one-decimal ceiling.
434 // Shared availability, visible recovery and retry controls measure 2407.215 KiB
435 // (+6.107 KiB, 0.25% over the prior welcome head). Retain the next tenth.
436 // Integrated model settings and bounded receipt mock measure 2468523 B
437 // (2410.667 KiB); retain 0.2 KiB headroom on the combined startup payload.
438 // Turn results add 12585 B (0.51%) over main-v2's 2464923 B: bounded receipt
439 // projection, status presentation and view bindings. Result: 2477508 B.
440 // Combined turn-result and model-settings startup payload is 2481108 B
441 // (2422.957 KiB), retaining the same bounded 0.2 KiB build headroom.
442 // The integrated turn-result base measures 2477492 B. Runtime state and
443 // session-bound receipt confirmation and its mock session contract add
444 // 5944 B (0.240%): 2483436 B total.
445 // Durable session isolation and missed-completion reconciliation add 1232 B
446 // (0.050% over that head), measuring 2484668 B total.
447 // The read-status line, read-pause card and their host wiring merge on top and
448 // measure 2488853 B. Keep the next tenth; gzip, CSS, and chunk limits unchanged.
449 // Combined model-settings and read-evidence integration measures 2492541 B,
450 // adding 3688 B (0.148%) over the base. Retain the next one-decimal ceiling.
451 // SessionRef bridge methods, active-row identity and the mock hydration event
452 // contract measure 2439.8 KiB. Extracting exact-tab mock rebinding from the
453 // startup bridge measures 2439.6 KiB; retain 0.3 KiB bounded toolchain headroom.
454 // History preparation and cancellation across startup and paging add 884 B
455 // (0.035%) to the 2498286 B base. Measured 2499170 B; retain 0.1 KiB headroom.
456 // Independent-session identity, organization CAS and unread/lifecycle guards
457 // measure 2443.0 KiB against the same-toolchain main-v2 base of 2440.7 KiB
458 // (+2.3 KiB, 0.095%). Retain one tenth; all other limits stay unchanged.
459 // Complete export execution/rendering remains lazy; only bounded progress,
460 // lifecycle observation, and cross-page tool-state hydration enter startup.
461 // A full 40-character identity measures 2064513 B in the browser build and
462 // 2064459 B in Electron, versus 2064077 B on current main-v2 (+436 B, 0.021%).
463 // Retain the smallest one-decimal ceiling; all other limits stay unchanged.
464 // Reasoning capability recovery copy moves the same-toolchain local build from
465 // 2064327 B to 2064614 B (+287 B, 0.014%). The stable build with a full source
466 // identity measures 2064746 B; retain the next one-decimal ceiling.
467 // The React error-family field adds 177 B to the same production build. The
468 // measured 2064923 B payload keeps the existing gzip, CSS, and chunk limits.
469 // Approval outcome recovery measures 2065149 B on current main-v2, versus the
470 // 2015.6 KiB base. Retain 0.15 KiB headroom; all other limits stay unchanged.
471 // Live-default draft fencing and frozen-model recovery measure 2066040 B
472 // (2017.617 KiB). Retain 0.183 KiB; gzip, chunk, CSS, and locale gates stay fixed.
473 // Session-id migration and cross-client takeover measure 2073794 B merged onto
474 // that main-v2 payload, 7754 B (0.375%) over it. The startup-path growth is
475 // attributable to this branch's remote session identity work: the remote
476 // telemetry and status modules become static imports of useRemoteSession (they
477 // leave their lazily loaded surface chunk), plus the canonical session-id
478 // plumbing, the spectator reconcile loop and its ownership classification, the
479 // pre-activation history prime, the rebased optimistic-submission settlement,
480 // and the project tree's canonical row identity. The CI Linux stable build
481 // measures 2073980 B (2025.4 KiB), 186 B above the same-toolchain macOS build;
482 // the ceiling follows the CI producer. Retain 0.13 KiB headroom at the next
483 // one-decimal ceiling; gzip, CSS, and chunk limits are unchanged.
484 // Combining that migration with restored historical-tab preparation measures
485 // 2074127 B locally. Preserve the measured 186 B Linux producer difference
486 // above (2074313 B combined), with 0.11 KiB headroom. Historical preparation
487 // remains lazy; compressed, chunk, CSS, and locale limits stay unchanged.
488 // Native window ownership, stopping-state handling and bounded transcript crash
489 // context measure 2075238 B locally (+1111 B, 0.054%). Preserve the same 186 B
490 // Linux producer difference (2075424 B) and retain the next one-decimal ceiling;
491 // gzip, chunk, CSS, and locale limits remain unchanged.
492 const rawInitialBudgetKiB = 2_027.0;
493 assertBudget("initial raw JavaScript and CSS", rawInitialBytes, rawInitialBudgetKiB * 1024);
494 assertBudget("largest initial JavaScript chunk raw", largestInitialJSRaw, 1_000 * 1024);
495
495 lines Plain Text