| 1 | # CI and release execution |
| 2 | |
| 3 | [中文](CI_PERFORMANCE.zh-CN.md) |
| 4 | |
| 5 | ## Desktop PR checks |
| 6 | |
| 7 | `scripts/ci-paths.mjs` is the shared path classifier for normal and memory CI. |
| 8 | It distinguishes frontend, Go, generated protocol, Electron, native and |
| 9 | packaging inputs. Explicit documentation such as `desktop/AGENTS.md` skips |
| 10 | build and soak work, while Markdown inside the frontend remains a build input. |
| 11 | Unknown paths and unavailable diffs fail closed. Pull requests use merge-base |
| 12 | diffs; pushes use `before..sha`; normal `main-v2` pushes keep the complete |
| 13 | qualification matrix after the existing release-notes-only exception. |
| 14 | |
| 15 | `desktop-prepare` regenerates the desktop host contract (failing on drift) and |
| 16 | produces the required `electron/stable` and `electron/canary` frontend variants |
| 17 | once on Linux. Each artifact carries a versioned manifest with checkout, |
| 18 | workflow attempt, variant, build inputs, toolchain and every `dist` file hash. |
| 19 | Linux, macOS and Windows consumers verify it before compilation or packaging. |
| 20 | Explicit reuse fails on a missing, stale or damaged manifest and never falls |
| 21 | back to a hidden rebuild. Static frontend files are portable; dependencies, |
| 22 | native modules and Electron binaries are not shared. Build-input verification |
| 23 | streams every committed blob through one Git batch process instead of starting |
| 24 | one process per file; the version-one digest remains byte-for-byte compatible. |
| 25 | |
| 26 | The protected `lint` job aggregates `lint-code` and, when selected, the |
| 27 | complete `desktop-frontend` result. Motion unit tests remain in that frontend |
| 28 | plan and run once. `desktop-browser-group` runs application/settings/motion and |
| 29 | Transcript as two groups with `max-parallel: 2`; the `desktop-browser` summary |
| 30 | rejects failed, cancelled or unexpected skips. Go-only changes retain protocol |
| 31 | and native validation without launching browser or memory work. |
| 32 | |
| 33 | `node desktop/frontend/scripts/run-ci-tests.mjs --list` prints the unit test |
| 34 | plan. It expands the existing dedicated scripts and lifecycle hooks, discovers |
| 35 | new tests, and schedules each TypeScript suite once with its original loader. |
| 36 | Unsupported script syntax and conflicting explicit invocations fail closed. |
| 37 | CI runs two isolated processes at a time; the history performance benchmark |
| 38 | runs alone after them. Local dedicated `pnpm test:*` commands remain available. |
| 39 | |
| 40 | ## Timing reports |
| 41 | |
| 42 | The CI and memory workflow summaries report stage execution without queue time, |
| 43 | workflow wall time, recorded job queue time and the sum of runner execution. |
| 44 | Frontend builds, dependency and browser installation, each browser group and |
| 45 | each memory shard are listed separately. These measurements describe a single |
| 46 | run; comparisons should use the same candidate and report the median and range |
| 47 | of three runs so runner variance is visible. The Windows Desktop Go step keeps |
| 48 | native non-verbose output because Go's JSON mode made Windows spend several |
| 49 | minutes finalizing verbose test-cache output; the central report records its |
| 50 | step execution time from the Actions API without wrapping the test process. |
| 51 | |
| 52 | ## Memory screening |
| 53 | |
| 54 | Protocol v4 records the selected screening profile in every manifest, shard and |
| 55 | aggregate. Ordinary frontend pull requests use the `short` profile: one process |
| 56 | completes 32 full, 32 windowed, 32 safety and 128 mixed round trips. Pull requests |
| 57 | that change App lifecycle, Transcript, navigation, subscription ownership, memory |
| 58 | fixtures or CI routing use the `full` profile. Pushes to `main-v2`, the daily |
| 59 | scheduled run and manual dispatches also use `full`: three independent processes |
| 60 | each complete 128 full, 128 windowed, 128 safety and 512 mixed round trips. |
| 61 | |
| 62 | Both profiles keep the same evidence requirements: exact checkpoints, five heap |
| 63 | snapshots per process, GC, frame settling, source/build identity and screening |
| 64 | thresholds. Aggregation rejects missing shards and profile or protocol mismatches. |
| 65 | Only the explicit mock memory-soak URL removes the fixture's artificial |
| 66 | 1.5-second hydration latency. Hydration still crosses an asynchronous timer |
| 67 | task. Default browser and native geometry fixtures retain the delayed path. |
| 68 | |
| 69 | The pointer rests outside topic rows and the warmed baseline follows a complete |
| 70 | round trip after layout switching, avoiding samples of temporary menu state. |
| 71 | Reports declare the profile and protocol, and aggregation rejects older protocols. |
| 72 | `timings.json` records host-side counts, total time and maximum time for |
| 73 | navigation, frame settling, GC and heap capture/analysis. Aggregate results label |
| 74 | their `screeningLevel`, so a passing short PR screen cannot be mistaken for full |
| 75 | qualification. A green gate still does not prove offline heap-retainer attribution. |
| 76 | |
| 77 | ## Signed release artifacts |
| 78 | |
| 79 | The successful stable SignPath preflight hands its full native matrix to the |
| 80 | desktop publisher. The publisher revalidates authorization, candidate identity, |
| 81 | signing contract and cache/docs guards, then verifies and publishes the same |
| 82 | signed bytes without rebuilding or signing them again. CLI and npm publication |
| 83 | still wait for the entire preflight; no public surface starts early. |
| 84 | |
| 85 | Each platform bundle binds file sizes and SHA-256 hashes to candidate/control |
| 86 | SHAs, version, tag, channel, signing fingerprint, run, invocation and producer |
| 87 | attempt. Missing/extra platforms, conflicting identities, symlinks, duplicate |
| 88 | filenames or modified bytes stop publication. These transport hashes supplement |
| 89 | the existing Authenticode/minisign checks; they are not signature verification. |
| 90 | |
| 91 | A failed-job retry may reuse earlier successful platforms from the same run |
| 92 | and invocation. A rebuilt platform replaces only its own fully verified bundle. |
| 93 | New workflow runs prepare a new artifact set. Standalone recovery still builds |
| 94 | and validates its own full matrix. pnpm dependencies are cached by lockfile; |
| 95 | signed release artifacts are transported as artifacts, never dependency caches. |
| 96 |