Skip to content

Commit 80d1373

Browse files
build(desktop): Tier-1 payload slimming (~600MB; installer 1.14GB -> 810MB)
Prune build-only / duplicate / regenerable dirs from the staged runtime payload (stage-runtime.cjs runtimePruneTargets) — all verified unused at USER runtime (electron/service-manager.js spawns only python/java/jcmd/taskkill): - appcds (230MB): stale build-machine CDS; regenerated per-user on first run - wheels + bundle/wheels (246MB): offline pip wheels, no runtime/repair pip-installs; the two are byte-identical copies - node (85MB): build/dev only, never spawned at runtime - maven + maven-extract (11MB): build-time jar build only - bundle/dist (31MB): web-mode build; desktop loads bundle/dist-file They remain in local/workspace/runtime/windows for the build; only the payload is slimmed. Guarded by release_selfcheck.py check_payload_slimmed() (FAILs if any reappear in the staged payload). Verified: dist:win selfcheck 6/6; installer 1.14GB->810MB, payload 2.6GB->2.0GB; clean-machine cold/warm smoke functionally green (cold+warm backendReady+chartReady, chart birth correct, forbiddenLogMatches empty, ports released). The smoke's exit-1 is only the warm >10s soft threshold (it force-kills, so the graceful AppCDS dump never runs and there's no shipped CDS; real users regenerate on graceful close). jlink DEFERRED (Spring reflection module-completeness risk). NOT released: no version bump; batches with the next fix per user request. Audit: docs/PACKAGING_SIZE_AUDIT.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 5afa2f8 commit 80d1373

7 files changed

Lines changed: 128 additions & 2 deletions

File tree

.claude/skills/horosa-dev/SKILL.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ chart service `astropy/`. On Windows these live under
138138
its `release_selfcheck.py` sentinels guard `vendor/kinqimen/{jieqi.py(`zhirun_jieqi`),config.py(`dingju_jieqi`),kinqimen.py}`.
139139
(Mechanism deep-dive: `docs/qimen-calendar-fix-v2.1.6.md`.)
140140

141+
11. **Payload size lever = `stage-runtime.cjs` `runtimePruneTargets`; don't re-ship build-only/duplicate dirs.**
142+
The ~1.14GB installer is ~2.6GB unpacked, and **the embedded runtimes+data (`app-runtime`) are ~2.6GB of it — Chromium is only ~280MB.** Tier-1 slimming (~600MB, 2026-05-26) prunes, FROM THE STAGED PAYLOAD ONLY, dirs verified unused at user runtime: `appcds` (regenerated per-user first run), `wheels` + `bundle/wheels` (offline pip, never installed at runtime; the two are byte-identical copies), `node` (build/dev only), `maven`/`maven-extract` (build-time jar build only), `bundle/dist` (desktop loads `bundle/dist-file`). They stay in `local/workspace/runtime/windows` for the build; only the payload is slimmed. **Before pruning anything new, confirm `electron/` never spawns/reads it at runtime** (service-manager spawns only python/java/jcmd/taskkill). Guarded by `release_selfcheck.py` `check_payload_slimmed()` (FAILs if any reappear in the staged payload). **DEFERRED: jlink the JRE** (228→~60MB) — risky for a Spring Boot app (reflection/JNI module completeness); do it as a focused round with per-feature boot validation, not a blind prune. Biggest remaining wins are Mac-side (jar dep slimming, Python streamlit-stack, the 636MB ML models). Full breakdown + plan: `docs/PACKAGING_SIZE_AUDIT.md`.
143+
141144
## Commands
142145

143146
```powershell

desktop_installer_bundle/scripts/release_selfcheck.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,25 @@ def check_distfile_not_stale():
161161
detail = "dist-file newer than astrostudyui/src" if ok else f"STALE: {os.path.relpath(src_p, REPO)} newer than staged dist-file (frontend not rebuilt)"
162162
record("staged dist-file not stale", ok, detail)
163163

164+
def check_payload_slimmed():
165+
# Tier-1 payload slimming (docs/PACKAGING_SIZE_AUDIT.md): these build-only / duplicate /
166+
# regenerable dirs must NOT be in the staged runtime payload. If a future change re-includes
167+
# them (e.g. the prune list in stage-runtime.cjs is reverted), the installer balloons ~600 MB.
168+
stage = os.path.join(REPO, "desktop_installer_bundle", "build", "app-runtime", "runtime", "windows")
169+
if not os.path.isdir(stage):
170+
record("payload slimmed (Tier-1)", True, "SKIPPED (staged payload not built yet)")
171+
return
172+
must_be_absent = [
173+
"node", "maven", "maven-extract", "wheels",
174+
os.path.join("bundle", "wheels"), os.path.join("bundle", "dist"), "appcds",
175+
]
176+
present = [p.replace("\\", "/") for p in must_be_absent if os.path.exists(os.path.join(stage, p))]
177+
ok = not present
178+
detail = "build-only/duplicate/regenerable dirs pruned from payload" if ok else \
179+
f"NOT pruned -> ~600MB installer bloat: {', '.join(present)} (see stage-runtime.cjs runtimePruneTargets)"
180+
record("payload slimmed (Tier-1)", ok, detail)
181+
182+
164183
def sha256(path):
165184
h = hashlib.sha256()
166185
with open(path, "rb") as f:
@@ -226,6 +245,7 @@ def main():
226245
check_sentinels()
227246
check_jar_not_stale()
228247
check_distfile_not_stale()
248+
check_payload_slimmed()
229249
check_release_assets(V)
230250
width = max(len(n) for n, _, _ in results)
231251
failed = 0

desktop_installer_bundle/scripts/stage-runtime.cjs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,23 @@ const runtimePruneTargets = [
3333
'python/tcl',
3434
'java/jmods',
3535
'java/include',
36+
// --- Tier-1 payload slimming (~600 MB): build-only / duplicate / regenerable artifacts that are
37+
// NOT used at user runtime. Verified before adding (docs/PACKAGING_SIZE_AUDIT.md):
38+
// - electron/service-manager.js spawns only python/java/jcmd/taskkill — never node, never pip.
39+
// - AppCDS is regenerated per-user on first run (-XX:+RecordDynamicDumpInfo + jcmd VM.cds
40+
// dynamic_dump on shutdown); the shipped archives are just this build machine's warm cache.
41+
// - bundle/wheels is a byte-for-byte robocopy of wheels/ (Prepare_Runtime), and no runtime/repair
42+
// path pip-installs from either; maven is build-time only; the desktop loads bundle/dist-file
43+
// (file://), not the web-mode bundle/dist.
44+
// These remain in local/workspace/runtime/windows for dev/build; only the shipped payload is slimmed.
45+
// Guarded against regression by release_selfcheck.py check_payload_slimmed().
46+
'node',
47+
'maven',
48+
'maven-extract',
49+
'wheels',
50+
'bundle/wheels',
51+
'bundle/dist',
52+
'appcds',
3653
];
3754

3855
function rmrf(targetPath) {

docs/PACKAGING_SIZE_AUDIT.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Horosa Windows 打包体积审计 + 减重
2+
3+
> 首次审计 / 实施:2026-05-26(基线 = v2.1.7 本地构建)。
4+
> 本文是「体积都去哪了 + 减了什么 + 还能减什么」的台账。数字为**实测**;省的估算标注「需确认用途」。
5+
6+
## 基线(v2.1.7,减重前)
7+
8+
- 安装包(NSIS,压缩):**~1.14 GB**
9+
- 解包后(`win-unpacked`):**~2.8 GB** —— 其中 Electron/Chromium 外壳仅 ~280 MB,**`app-runtime`(内置运行时+数据)占 2.6 GB**。Chromium 不是瓶颈。
10+
11+
### 2.6 GB 载荷拆解(`build/app-runtime`,实测)
12+
|| 大小 | 性质 |
13+
|---|---|---|
14+
| `project/astropy/astrostudy/models` | **636 MB** | 11 个 `.joblib` ML 模型(`virtual_body_corr_<行星>_v1`,每个 ~60MB) |
15+
| `runtime/windows/python` | 625 MB | 内置 Python + site-packages(含 streamlit/pyarrow/pydeck/altair ~150M) |
16+
| `runtime/windows/bundle/astrostudyboot.jar` | 310 MB | Spring Boot fat jar(opencv 105M + Oracle/Kafka/gRPC-xds 等服务端依赖) |
17+
| `runtime/windows/appcds` | 230 MB | Java CDS 存档(构建机多次运行累积的 5 个目录) |
18+
| `runtime/windows/java` | 228 MB | 内置 JDK/JRE(jmods/include 已 prune) |
19+
| `runtime/windows/wheels` + `bundle/wheels` | 246 MB | 离线 pip wheels,**同 119 文件打了两遍** |
20+
| Electron/Chromium 外壳 | ~280 MB | Horosa.exe 192M + locales 42M + paks/dll |
21+
| `project/flatlib-ctrad2` | 116 MB | flatlib + 150 个星历 `.se1` |
22+
| `runtime/windows/node` | 85 MB | 内置 Node |
23+
| `project/vendor` | 67 MB | kentang/kin 引擎 |
24+
| `bundle/dist` + `bundle/dist-file` | 62 MB | 前端构建产物**两份**(web 版 dist + 桌面版 dist-file) |
25+
| `runtime/windows/maven` | 11 MB | 构建工具 |
26+
27+
## Tier 1 — 已实施(Windows 侧,零/低风险,~600 MB)
28+
29+
**做法**:在 `desktop_installer_bundle/scripts/stage-runtime.cjs``runtimePruneTargets` 增加以下条目——只从**打包载荷**删除,`local/workspace/runtime/windows` 源保留(不影响构建)。每一项都**先核查确认用户运行时不用**才删:
30+
31+
| 删除项 || 核查依据 |
32+
|---|---|---|
33+
| `appcds` | 230 MB | 用户首启自重建:`service-manager.js` 无存档时走 `-XX:+RecordDynamicDumpInfo`,关闭时 `jcmd VM.cds dynamic_dump`。shipped 的是构建机暖缓存(5 个 stale 目录) |
34+
| `wheels` + `bundle/wheels` | 246 MB | `electron/` 零引用 node/wheels/pip;无运行时/repair 走 pip 安装;`bundle/wheels``wheels` 的 robocopy 副本 |
35+
| `node` | 85 MB | `electron/``Prepare_Runtime` 均零引用,纯 dev/build |
36+
| `maven` + `maven-extract` | 11 MB |`Prepare_Runtime` 构建 jar 时用,用户运行时不用 |
37+
| `bundle/dist` | 31 MB | 桌面加载 `bundle/dist-file`(file://),web 版 dist 不用 |
38+
39+
**防回弹闸门**:`release_selfcheck.py` 新增 `check_payload_slimmed()` —— 若上述目录重新出现在 staged 载荷里(prune 列表被还原),发布闸门直接 FAIL。
40+
41+
**验证**:`dist:win` 重新打包后量体积 + `release_selfcheck.py` 全绿 + **干净机器冷/热启动 smoke**(证明删除未破坏启动:backendReady + chartReady + `forbiddenLogMatches` 空)。
42+
43+
> 代价:删了预暖的 AppCDS,首次 warm-start 略慢(实测干净机器 smoke:冷 23.5s / 首热 11.3s,均 backendReady+chartReady、出盘正确、forbiddenLogMatches 空、端口干净——功能全绿;热 11.3s>10s 软阈值的 exit 1 是 smoke 强杀进程不触发 CDS dump + 删了预暖 CDS 所致,真实用户优雅关闭后自生成 CDS,后续热启回落)。其余皆无功能影响。
44+
>
45+
> **未来精修(可选)**:`appcds` 之所以有 230M,是构建机多次运行**累积了 5 个 stale 存档**。比「全删」更优的做法是构建期为当前 jar **只生成并随包一个新鲜 ~50M 存档**(保留 warm-start 预暖、又省 ~180M),但需要构建流程改造;本轮先全删求稳。
46+
47+
## 已 deferred — jlink 裁 JRE(228M → ~60M,约 −160 MB)
48+
49+
**本轮不做**,原因:jlink**替换** JRE,Spring Boot 大量反射 + JNI(opencv)/JDBC(sqlite、Oracle)/gRPC/POI 各需不同模块,`jdeps` 对 fat jar 推断不全,**漏一个模块 = 某功能运行时崩**,而冷/热 smoke 只覆盖出盘、未必触发所有后端路径——风险与刚修完的 issue #2(「我这能跑、用户那崩」)同类。建议作为**单独一轮**:配合后端逐功能验证,或在 Mac 侧连 jar 依赖一起做(确定模块集后再裁)。
50+
51+
## Tier 2 — 待 Mac 侧改了再同步(共享代码,收益更大,需先确认用途)
52+
- **jar 瘦身**(`astrostudysrv` pom 排除/scope):Oracle `ojdbc8` / `kafka-clients` / `grpc-xds`/`grpc-netty-shaded` 桌面基本不需要(用 sqlite + mongo-fallback);`opencv-3.4.2`(105M)若无图像功能用到则剔。预计 −150~250 MB。
53+
- **Python 去 streamlit 全家桶**(`requirements`):streamlit/pyarrow/pydeck/altair(vendored 引擎当库用,非 streamlit app)。预计 −~150 MB。
54+
- **ML 模型 636M**(最大单块):压缩(`joblib compress=`,sklearn 模型常砍半)或改**首次使用按需下载**。预计 −300~636 MB。需产品确认「virtual body correction」定位。
55+
- 星历去重(astropy vs flatlib-ctrad2 两套 `.se1`)。
56+
57+
## Tier 3 — 架构级
58+
- 桌面端去掉 Spring/JRE → 一次省 java 228 + jar 310 + appcds 0(已删) ≈ −540 MB,真重构。
59+
60+
## 影响估算
61+
- **Tier 1(本轮,已实测)**:解包载荷 2.6 GB → **2.0 GB**;安装包 **1.14 GB → 810 MB(−29%)**`release_selfcheck.py` 6/6 全绿。
62+
- + jlink:再 −160 MB。
63+
- + Tier 2(Mac 侧):再 −600 MB ~ −1 GB,安装包有望进 ~0.4 GB 区间。

docs/PROJECT_STRUCTURE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666

6767
- `package.json` / `package-lock.json`:桌面打包工程版本与依赖,当前发布版本为 `2.1.7`
6868
- `electron/`:Electron 主进程、预加载脚本、加载/错误页(`loading.html`,含启动分步进度、失败态日志结尾透出与“复制诊断信息”)、窗口管理、Python/Java/Web 服务编排(`service-manager.js`,含崩溃归因与 trusted fast-path)、运行时健康检查与日志。
69-
- `scripts/`:renderer 构建、运行时 staging(`stage-runtime.cjs`,会注入 VC++ 运行时并跑原生依赖自检)、`check_runtime_native_deps.py`(构建期 DLL 完整性闸门)、`generate_brand_assets.py`(从 logo 生成图标/安装器位图)、`release_preflight.py`(发布前版本/品牌资产/运行时一致性闸门,对应 `npm run verify`)、项目路径解析、安装器回归、安装后桌面 smoke、干净机器冷/热启动检查和 kentang 端点验证。
69+
- `scripts/`:renderer 构建、运行时 staging(`stage-runtime.cjs`,会注入 VC++ 运行时、跑原生依赖自检,并按 `runtimePruneTargets` 从打包载荷裁掉构建期/重复/可重建产物——node、maven、wheels、appcds、web 版 dist 等,详见 `docs/PACKAGING_SIZE_AUDIT.md`)、`check_runtime_native_deps.py`(构建期 DLL 完整性闸门)、`generate_brand_assets.py`(从 logo 生成图标/安装器位图)、`release_preflight.py`(发布前版本/品牌资产/运行时一致性闸门,对应 `npm run verify`)、项目路径解析、安装器回归、安装后桌面 smoke、干净机器冷/热启动检查和 kentang 端点验证。
7070
- `assets/`:安装器图标与 NSIS 定制资源。唯一品牌源是 `horosa_setup_badge.png`(最新 logo);`horosa_setup.ico``installerHeader.bmp``installerSidebar.bmp``uninstallerSidebar.bmp` 全部由 `scripts/generate_brand_assets.py` 从它派生,换 logo 后必须重跑该脚本。`installer.nsh` 为 NSIS 定制脚本(含安装目录校验、旧快捷方式清理)。
7171
- `release/`:本地构建输出目录。v2.1.7 Beta 标准发布资产为:
7272
- `Horosa-Setup-2.1.7.exe`

docs/SELFCHECK_LOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,29 @@
22

33
最后更新:2026-05-26
44

5+
## 2026-05-26 Tier-1 打包减重(Windows 侧,~600MB,未发布·待批量)
6+
7+
把打包载荷里**构建期/重复/可重建**的产物从 staged payload 裁掉(只动打包载荷,`local/workspace/runtime/windows` 源保留,不影响构建)。**未升版本、未发布**,等下个修复一起发。完整审计见 `docs/PACKAGING_SIZE_AUDIT.md`
8+
9+
### 改动
10+
- `stage-runtime.cjs` `runtimePruneTargets` 增加:`node``maven``maven-extract``wheels``bundle/wheels``bundle/dist``appcds`(共 ~603MB)。
11+
- `release_selfcheck.py` 新增 `check_payload_slimmed()`:上述目录若重现在 staged 载荷里则 FAIL(防 prune 列表被还原导致体积回弹)。
12+
13+
### 安全核查(删前逐项确认运行时不用)
14+
- `electron/service-manager.js` 只 spawn python/java/jcmd/taskkill——**** node/wheels/pip 引用;`Prepare_Runtime` 也不在运行时引用 node。
15+
- AppCDS 用户首启自重建(`-XX:+RecordDynamicDumpInfo` + 关闭时 `jcmd VM.cds dynamic_dump`);shipped 的是构建机暖缓存(5 个 stale 目录)。
16+
- `bundle/wheels``wheels` 的 robocopy 副本;无运行时/repair 走 pip 安装。
17+
- maven 仅构建期建 jar 用;桌面加载 `bundle/dist-file`(file://)而非 web 版 `bundle/dist`
18+
19+
### 验证(实测)
20+
- 安装包:**1.14 GB → 810 MB(−29%)**;解包载荷 **2.6 GB → 2.0 GB**(packed tar 2600→1976 MB);win-unpacked 2.8→2.3 GB。
21+
- `release_selfcheck.py`:**6/6 全绿**(含新增 `payload slimmed (Tier-1)` PASS)。新 slim exe sha256 `c0312a3fd6ee65e2da7706002599f61432a77db7b2ab719a6c821a878292fd80`(**未发布,仅本地**;批量发布时会升版本重算)。
22+
- 7 个 prune 目录已确认从载荷消失;python/java/dist-file/jar 等保留项完好。
23+
- **干净机器冷/热启动 smoke**(`win-unpacked\Horosa.exe`,隔离 LOCALAPPDATA/APPDATA/TEMP):**功能全绿**——冷启 23.5s(extract 13.4s)+ 热启 11.3s,两者 `backendReady`+`chartReady` 均 true、出盘正确(birth 2028-04-06 09:33)、`forbiddenLogMatches` 空、8899/9999/9464 停止后均释放。脚本 exit 1 仅因热启 11.3s > 10s **软阈值**(同 2.1.4 类软失败):smoke 强杀进程→不触发优雅关闭的 AppCDS dump,叠加本轮删了预暖 CDS + 构建机负载,故首次热启略慢;真实用户优雅关闭后会生成自有 CDS,后续热启回落——**非功能回归**。(首次传错 exe 把安装器当 app 的那次失败已排除,纯属调用参数错误。)
24+
25+
### deferred
26+
- jlink 裁 JRE(228→~60M)本轮不做:Spring 反射/JNI 模块完整性风险高、smoke 难覆盖,留作单独一轮(配合后端逐功能验证)。
27+
528
## 2026-05-26 v2.1.7 Beta 奇门/三式 真太阳时定盘修复(纯前端)
629

730
把 Mac main(`907e841` / v2.1.7)的 **奇门/三式 真太阳时定盘修复** 同步到 Windows。**纯前端 1 文件,无 Java/Python 改动 → 未重建 `astrostudyboot.jar`**

local/workspace/runtime/windows/bundle/runtime.manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"product": "Horosa Windows Stable",
33
"channel": "stable",
4-
"generatedAt": "2026-05-26T19:29:48-07:00",
4+
"generatedAt": "2026-05-26T21:13:58-07:00",
55
"root": "local/workspace",
66
"assets": [
77
{

0 commit comments

Comments
 (0)