From 90fe0480702604a391b34fed1d1eb6712c66699c Mon Sep 17 00:00:00 2001 From: Haoyu Xi Date: Wed, 11 Nov 2026 11:44:31 +0800 Subject: [PATCH] chore(release): v5.23.4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 桌面导出真落盘 + 依赖锁文件可解性修复。 - 版本面:version.py 5.23.4 / sw.js CACHE_NAME / 顶栏(源片段 + 重建 index.html)/ build.gradle 52304 / README(badge、Tests 3040-3054、亮点、下载表、版本历史三轮)。 - CHANGELOG 新增 v5.23.4(修复:桌面导出假成功、lock 不可解;内部:依赖批量升级、 actions-cache v6、依赖治理判据;已知限制含桌面壳未真机验证与本地测试噪声)。 - PROJECT_OVERVIEW 当前状态同步;work.log 记录判据与「CI 不读 lock」的缺口。 本地(项目级 .venv,已按 lock 升级):3040 passed / 3054 collected。 --- CHANGELOG.md | 30 +++++++++++++++++++++ README.md | 45 ++++++++++++++++---------------- WORKMEMORY/PROJECT_OVERVIEW.md | 6 ++++- WORKMEMORY/work.log | 9 +++++++ android/app/build.gradle | 4 +-- delector/core/version.py | 2 +- static/index.html | 2 +- static/layout/header.html | 2 +- static/sw.js | 2 +- tests/test_app_version_source.py | 4 +-- 10 files changed, 75 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a43b07b..877d0ee9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,36 @@ 5. README.md 的「版本历史」表只保留最近 3 版,旧版只进本文件。 --> +## v5.23.4 - 2026-11-11 + +### 修复 + +- **桌面壳导出「假成功」**(PR #344):桌面版点导出时磁盘上没有文件,界面却弹「已导出」。根因是 pywebview / WebView2 默认不放行下载(`ALLOW_DOWNLOADS` 为假时 `DownloadStarting` 被静默取消),前端 `download()` 后无条件报成功。改为 `POST /api/wb/backup/save` 由 Python 显式落盘并返回真实 path / bytes,前端只在拿到 path 时提示成功;Android 仍保持 501 回退系统下载。 +- **`requirements.lock.txt` 装不上**(PR #352):两个依赖冲突让锁文件不可解——`numpy==2.5.4` 要求 Python>=3.12 而项目 `.venv` 固定 3.11,`pydantic-core==2.50.4` 与 `pydantic==2.14.2` 精确要求的 `2.50.2` 冲突。已分别回退到 `2.4.6` 与 `2.50.2`。 + +### 内部 + +- **批量依赖升级**(PR #351):fastapi 0.162.0→0.162.2、click 8.5.0→8.5.1、typer 0.27.3→0.28.0、typing-inspection 0.4.4→0.4.5;`actions/cache` v4→v6(8 处)。六个 dependabot PR 合成一笔,避免逐个把 lock 文件整文件重写。 +- **依赖治理**:`.github/dependabot.yml` 对 numpy 暂缓 minor/major(解除条件=项目最低 Python 升到 3.12)。dependabot 对 `requirements*.txt` 的单包升级不做整体一致性求解,CI 又只装 `requirements.txt`(不读 lock),因此合并此类 PR 前必须真跑 `uv pip install --dry-run -r requirements.lock.txt`。 +- **新增守卫**:`tools/wb_export_probe.mjs`(5 场景,钉「无 path 不报成功」)+ `tests/test_wb_export_save.py`(6 用例)。 + +### 已知限制(Known Limitations) + +- **桌面导出只在 `desktop.py` 实跑验证**:冻结后的 exe、真实磁盘写失败路径、macOS / Linux 均未验证。 +- **arm64 真机仍未点检**:v5.23.3 的两处修复(阅读页模板、退出重进补载)只在 x86_64 模拟器(`emulator` 渠道 debug 包)验证;本版 Android 侧无功能变化,但含 `static/` 改动 ⇒ 仍需覆盖安装才生效。 +- **本地测试环境有既有噪声**:本机全量为 3040 passed,另有 2 failed + 3 errors 属环境问题——`test_frontend_layers` 的 GBK 控制台解码,以及 `test_player_tray_probe` / `test_probe_json_contract`(在未改动的 master 上同样失败)。CI 上全部通过。 +- **重复卡存量未合并**:写入侧已幂等,未建 UNIQUE,历史重复仍在库中。 + +### 回滚(Rollback) + +- **代码 / 产物**:可回退至 `v5.23.3` 发布包(`v5.23.1` 白屏、`v5.23.2` 阅读页不可用,均不宜作为回退目标);`build-release.yml` 由 tag 触发。 +- **Android**:`versionCode` 由 `52303` 升至 `52304`,不可回滚;只能卸载重装旧 APK(会清应用私有数据,须先备份);`versionCode` 不得回拨。 +- **数据位置 / 格式**:未搬移数据目录、未改变数据文件格式。 +- **Schema**:零 DDL、零迁移,旧版可直接读同一 SQLite。 +- **配置 / 发布通道**:无新增必需配置或密钥;git revert 可回退代码。桌面导出改由 Python 落盘后,回退版本会恢复「导出假成功」的旧行为。 + +--- + ## v5.23.3 - 2026-11-11 ### 修复 diff --git a/README.md b/README.md index adc53b2e..dd83a36e 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,26 @@ # DeLector · 德语欧标沉浸精读与考点剖析工作台

- Release Version + Release Version Python Version FastAPI spaCy CEFR Ladder AI Model - Pytest + Pytest License

- +

专为德语学习者与歌德(A1–C1)/ 德福(TestDaF)/ DSH 备考打造的学术级伴读与句法剖析系统。
@@ -57,22 +59,21 @@ docker compose up -d --build # 或 Docker 容器化一键部署 ## 多平台下载发布包 -> **v5.23.3 最新版本亮点(2026-11-11)**: -> - **修复「点开文章毫无反应」**:阅读页状态模板引用了已删除的变量,一进阅读页就抛 `ReferenceError`(v5.23.1 / v5.23.2 都带)。本版已修,并用 x86_64 模拟器实测:点开文章能正常渲染正文、CEFR 光谱与跟读条。 -> - **修复 Android「退出重进后停在 Webpage not available」**:首帧导航早于本地服务就绪,Service Worker 的 network-first 拿不到页面;旧逻辑见「已经在应用 origin 上」就跳过重载,于是永远停在错误页。本版在服务就绪后发现窗口里没有我们的 JS 就补载一次。 -> - **若你装了 v5.23.1 或 v5.23.2,请直接升级本版**(前者白屏、后者阅读页不可用);也可回退 v5.23.0。 -> - **阅读页不再把「还没准备好」显示成「加载错误」**:详情不再在请求里同步等 spaCy 分词;有旧结果先给你读,没有时显示「正在准备德语分词模型」并自动重试,只有真的打不开才给出带「重试」按钮的提示。 -> - **健康检查暴露分词状态**:`/api/health` 新增 `nlp` 字段(ready / loading / error / unavailable),排障时能直接看出是模型未就绪还是真的出错。 +> **v5.23.4 最新版本亮点(2026-11-11)**: +> - **桌面版导出不再「假成功」**:以前点导出会弹「已导出」但磁盘上没有文件(WebView2 默认不放行下载、请求被静默取消)。现在由 Python 显式落盘并回传真实路径与字节数,只有真正写成功才提示成功。 +> - **修复依赖锁文件装不上的问题**:`requirements.lock.txt` 里 numpy 被升到只支持 Python 3.12 的版本、pydantic-core 与 pydantic 精确版本冲突;已回退到与 Python 3.11 兼容的组合。 +> - **依赖批量升级**:fastapi 0.162.2、click 8.5.1、typer 0.28.0、typing-inspection 0.4.5,CI 缓存动作升到 v6。 +> - **v5.23.3 的阅读页修复仍在本版**(阅读页状态模板、Android 退出重进自动补载);若你装了 v5.23.1 / v5.23.2,请直接升级本版。 > **Android 用户注意**:含 `static/` 改动的版本需**覆盖安装**才生效。 > 完整版本变更细节见 [CHANGELOG.md](CHANGELOG.md)。 | 平台 | 版本 | 说明 | 下载通道 | | ------------------ | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | -| **Windows x64** | `v5.23.3` | 原生桌面窗口 + 系统托盘,免装 Python,解压双击 `DeLector.exe`;需 Win10+ 与 WebView2 运行时(Win11 自带;Win10 缺运行时的表现见[已知限制](#已知限制));首次启动把数据放到 `%LOCALAPPDATA%\DeLector` | [下载 ZIP 包 (GitHub Releases)](https://github.com/ROM4n2/DeLector/releases/tag/v5.23.3) | -| **macOS** | `v5.23.3` | 解压后进入 `DeLector-v5.23.3-macOS/`,运行其中的裸可执行文件 `./DeLector`(不是 `.app` 包)。正常 `tar -xzf` 解压会保留可执行位,若权限丢失先 `chmod +x DeLector`。包未做代码签名与公证,若被 Gatekeeper 拦截请右键「打开」,或在终端执行 `xattr -d com.apple.quarantine DeLector`。 | [下载 TAR.GZ 包 (GitHub Releases)](https://github.com/ROM4n2/DeLector/releases/tag/v5.23.3) | -| **Linux x64** | `v5.23.3` | 解压后进入 `DeLector-v5.23.3-Linux-x64/`,运行 `./DeLector`(正常 `tar -xzf` 解压会保留可执行位,若权限丢失先 `chmod +x DeLector`)。包在 CI 的 Ubuntu 环境构建,未在其他发行版验证。 | [下载 TAR.GZ 包 (GitHub Releases)](https://github.com/ROM4n2/DeLector/releases/tag/v5.23.3) | -| **Android** | `v5.23.3` | 内嵌 Python 运行时与 spaCy 离线模型,单机独立运行;正式包只出 **arm64-v8a**,CI 用 `keytool` 校验 APK 与 keystore 的 SHA256 证书指纹一致。**arm64 真机未验证**(仅 x86_64 模拟器)。 | [下载 APK 安装包 (GitHub Releases)](https://github.com/ROM4n2/DeLector/releases/tag/v5.23.3) | +| **Windows x64** | `v5.23.4` | 原生桌面窗口 + 系统托盘,免装 Python,解压双击 `DeLector.exe`;需 Win10+ 与 WebView2 运行时(Win11 自带;Win10 缺运行时的表现见[已知限制](#已知限制));首次启动把数据放到 `%LOCALAPPDATA%\DeLector` | [下载 ZIP 包 (GitHub Releases)](https://github.com/ROM4n2/DeLector/releases/tag/v5.23.4) | +| **macOS** | `v5.23.4` | 解压后进入 `DeLector-v5.23.4-macOS/`,运行其中的裸可执行文件 `./DeLector`(不是 `.app` 包)。正常 `tar -xzf` 解压会保留可执行位,若权限丢失先 `chmod +x DeLector`。包未做代码签名与公证,若被 Gatekeeper 拦截请右键「打开」,或在终端执行 `xattr -d com.apple.quarantine DeLector`。 | [下载 TAR.GZ 包 (GitHub Releases)](https://github.com/ROM4n2/DeLector/releases/tag/v5.23.4) | +| **Linux x64** | `v5.23.4` | 解压后进入 `DeLector-v5.23.4-Linux-x64/`,运行 `./DeLector`(正常 `tar -xzf` 解压会保留可执行位,若权限丢失先 `chmod +x DeLector`)。包在 CI 的 Ubuntu 环境构建,未在其他发行版验证。 | [下载 TAR.GZ 包 (GitHub Releases)](https://github.com/ROM4n2/DeLector/releases/tag/v5.23.4) | +| **Android** | `v5.23.4` | 内嵌 Python 运行时与 spaCy 离线模型,单机独立运行;正式包只出 **arm64-v8a**,CI 用 `keytool` 校验 APK 与 keystore 的 SHA256 证书指纹一致。**arm64 真机未验证**(仅 x86_64 模拟器)。 | [下载 APK 安装包 (GitHub Releases)](https://github.com/ROM4n2/DeLector/releases/tag/v5.23.4) | --- @@ -197,9 +198,9 @@ DeLector/ | 版本 | 发布日期 | 里程碑概要 | | :--- | :--- | :--- | +| **v5.23.4** | 2026-11-11 | 桌面导出改为 Python 显式落盘(不再假成功)· 修复 requirements.lock.txt 不可解(numpy / pydantic-core 与 Python 3.11 冲突)· 依赖批量升级与 CI 缓存动作 v6 | | **v5.23.3** | 2026-11-11 | 修复「点开文章无反应」(阅读页模板引用已删除变量)· 修复 Android 退出重进停在 Webpage not available(就绪后补载一次)· x86_64 模拟器实测通过 | -| **v5.23.2** | 2026-11-10 | 修复 v5.23.1 全平台白屏(前端模块图重复导出导致解析期崩溃)· 新增「node 真链接整张模块图」守卫;**阅读页仍不可用,请用 v5.23.3** | -| **v5.23.1** | 2026-11-10 | 阅读页「未就绪显示成加载错误」修复的设计与实现;**本版前端白屏,请用 v5.23.3** | +| **v5.23.2** | 2026-11-10 | 修复 v5.23.1 全平台白屏(前端模块图重复导出导致解析期崩溃)· 新增「node 真链接整张模块图」守卫;**阅读页不可用,请用 v5.23.4** | > 更早的版本(v5.14.0–v5.21.1 等)已完整迁入 [CHANGELOG.md](CHANGELOG.md),本页只保留最近三版。 diff --git a/WORKMEMORY/PROJECT_OVERVIEW.md b/WORKMEMORY/PROJECT_OVERVIEW.md index 1a9bf370..b89b4a71 100644 --- a/WORKMEMORY/PROJECT_OVERVIEW.md +++ b/WORKMEMORY/PROJECT_OVERVIEW.md @@ -23,7 +23,11 @@ ## 当前状态 -- **最新发布 v5.23.3(2026-11-11)** —— **修复「点开文章毫无反应」+ Android「退出重进停在 Webpage not available」**(x86_64 模拟器实测通过)。 +- **最新发布 v5.23.4(2026-11-11)** —— **桌面导出真落盘 + 依赖锁文件可解性修复**。 + - 桌面导出(#344):pywebview/WebView2 默认不放行下载、`DownloadStarting` 被静默取消,旧前端仍无条件报成功;改为 `POST /api/wb/backup/save` 由 Python 落盘并回传真实 path/bytes,前端只在拿到 path 时报成功。 + - 依赖(#351/#352):fastapi 0.162.2 / click 8.5.1 / typer 0.28.0 / typing-inspection 0.4.5 / `actions/cache` v6;并把 lock 里 numpy 2.5.4→2.4.6(要求 Py≥3.12)、pydantic-core 2.50.4→2.50.2(与 pydantic 2.14.2 精确 pin 冲突)。dependabot 对 numpy 暂缓 minor/major。 + - 教训:dependabot 对 `requirements*.txt` 单包升级不做整体求解,CI 只装 `requirements.txt` 不读 lock ⇒ 合并前必须跑 `uv pip install --dry-run -r requirements.lock.txt`。 +- **上一版 v5.23.3(2026-11-11)** —— **修复「点开文章毫无反应」+ Android「退出重进停在 Webpage not available」**(x86_64 模拟器实测通过)。 - ① 阅读页 `_readerStateHtml` 删了 `const bar` 却留着 `${bar}` ⇒ 点文章抛 `ReferenceError`,交互静默失效(v5.23.1/v5.23.2 均带)。 - ② 首帧导航早于本地服务就绪时,SW 的 network-first fetch 不经过 `shouldInterceptRequest` ⇒ ERR_FAILED;错误页 URL 仍是应用 origin 且不触发 `onPageFinished`,旧 `skip_reload` 判据把它当加载成功。修法:就绪后探针发现窗口里没有 `window.notifyServerReady` 就补载一次(一次性)。 - 新守卫:`test_reader_state_template_uses_only_declared_vars`(变异自证)。 diff --git a/WORKMEMORY/work.log b/WORKMEMORY/work.log index 64ebe2b7..411f55ab 100644 --- a/WORKMEMORY/work.log +++ b/WORKMEMORY/work.log @@ -566,3 +566,12 @@ dependabot 积压 6 个 PR 一次性处理:合 1 个批量 PR(#351),其 - 顺带发现:`requirements.txt` 的 **blob 是 CRLF**(早于 .gitattributes 契约写入),`requirements.lock.txt` 与 3 个 workflow 的 blob 是 LF —— 同一仓库两种存量,任何编辑这两个方向都会触发整文件重写。本次让 `requirements.txt` 由 git `text` 属性规范化成 LF(一次性 43 行 diff,已在提交信息与 PR 正文写明),lock 与 workflow 保持 LF 零噪声。 - 验证口径:本地 `.venv` 仍是旧版本,**没有**本地证明新依赖兼容 —— 由 CI 的 `pip install -r requirements.txt` + 全量门禁裁决。PR CI 全绿(13 项);合并后 master push run `815afe9` 也 success(actions/cache v6 在 GH 托管 runner 上可用,8 处替换无告警)。 - 本地补跑:CI 定义/依赖清单相关守卫 116 passed;3 个 workflow YAML 可解析(jobs 8/5/1 不变)。 + +### 2026-11-11 06:05 | deepseek-v4.1-flash | DECISION +Caps: filesystem-read, filesystem-write, shell-exec, git +发版 v5.23.4(判据驱动:`git diff --stat v5.23.3..origin/master -- static/` 非空 ⇒ 有用户可见面)。 +- 用户可见面来自 PR #344(桌面导出真落盘:原先 WebView2 不放行下载、请求被静默取消,前端仍报「已导出」;改为 `POST /api/wb/backup/save` 由 Python 落盘并回传真实 path/bytes)。 +- 同一区间还有 #351(批量依赖升级 + actions/cache v6)与 #352(lock 可解性修复),属内部改动,不单独构成发版理由。 +- **依赖事故(本轮新发现)**:#351 合并后 `uv pip install -r requirements.lock.txt` **不可解**——① `numpy==2.5.4` 要求 Python≥3.12 而项目 .venv 固定 3.11(dependabot 早先 a8ab228 单包 bump 引入)② `pydantic-core==2.50.4` 与 `pydantic==2.14.2` 精确要求的 2.50.2 冲突。修法:numpy→2.4.6、pydantic-core→2.50.2,并在 dependabot.yml 对 numpy 暂缓 minor/major(解除条件=最低 Python 升到 3.12)。 +- **判据缺口**:CI 只装 `requirements.txt`、**不读 lock**,所以 dependabot 把 lock 改成不可解组合时 CI 全绿。此后合并任何依赖 PR 前必须真跑 `uv pip install --dry-run -r requirements.lock.txt`(等价「锁文件可解」探针)。 +- 本地验证(项目级 .venv,不用全局 pip):`uv pip install --python ./.venv/Scripts/python.exe -r requirements.lock.txt` 成功,实际版本 fastapi 0.162.2 / click 8.5.1 / typer 0.28.0 / typing-inspection 0.4.5 / numpy 2.4.6 / pydantic 2.14.2 + core 2.50.2;升级后全量 pytest 3040 passed / 3054 collected(2 failed + 3 errors 为本地既有噪声:GBK 解码、player_tray_probe、probe_json_contract —— 已在纯 master 上用 stash 复验同样红)。 diff --git a/android/app/build.gradle b/android/app/build.gradle index 5f0265e5..13605d45 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -5,8 +5,8 @@ plugins { // 版本号只维护一个源头:git tag。CI 从 tag 推导后通过环境变量注入, // 本地构建无环境变量时用 fallback 默认值。 -def releaseVersionName = System.getenv("DELECTOR_VERSION_NAME") ?: "5.23.3" -def releaseVersionCode = (System.getenv("DELECTOR_VERSION_CODE") ?: "52303").toInteger() +def releaseVersionName = System.getenv("DELECTOR_VERSION_NAME") ?: "5.23.4" +def releaseVersionCode = (System.getenv("DELECTOR_VERSION_CODE") ?: "52304").toInteger() // 钉死的签名 keystore。CI 把它从 secret 解到 $RUNNER_TEMP(永不进工作树), // 本地开发与 fork 没有这个环境变量,签名配置整段不生效、回落到 AGP 自动生成的 diff --git a/delector/core/version.py b/delector/core/version.py index 5e3fb920..f3ed8a9c 100644 --- a/delector/core/version.py +++ b/delector/core/version.py @@ -12,7 +12,7 @@ __all__ = ["APP_VERSION", "version_code"] # 与 android/app/build.gradle:8 的 versionName fallback 同口径:不带 'v' 前缀。 -APP_VERSION: str = "5.23.3" +APP_VERSION: str = "5.23.4" # 每段版本号只有两位空间(minor/patch < 100),故步进 100 / 10000。 _MINOR_STEP = 100 diff --git a/static/index.html b/static/index.html index 54e99668..9eda619b 100644 --- a/static/index.html +++ b/static/index.html @@ -37,7 +37,7 @@ title="点击检查更新" role="button" tabindex="0" - >System · v5.23.3System · v5.23.4