Skip to content

chore(release): v2.2.4 —— 引擎直切 503 与 onclick 注入修复 + 发布链路收口 - #129

Merged
ReSerendipity merged 1 commit into
mainfrom
chore/release-2.2.4
Sep 22, 2026
Merged

ReSerendipity merged 1 commit into
mainfrom
chore/release-2.2.4

Conversation

@ReSerendipity

Copy link
Copy Markdown
Owner

v2.2.4 手工发版提交

owner 指示:关掉 #120 走手工路径。#120 的内容是健康的(合 #121 后 RP 第一次在真 release PR 上
被验,重新 groom 的 diff 是 7 files, +17/−6config.yaml 的整份重写已消失),关它的唯一理由是
release PR 拿不到 CIgh pr checks 120 是空数组;GitHub 固定行为:GITHUB_TOKEN 产生的提交
不级联触发 workflow)—— 于是 5 类手工同步位不会在 PR 上拦,只会红在发布之后的 main 上。
手工路径能在打 tag 之前把 9 处一次改齐并跑完闸。

版本位:9 处 + 1 处本地装配物

谁负责
pyproject.toml / desktop/package.json / tauri.conf.json / Cargo.toml / version.json$.version 2.2.3 → 2.2.4 RP 也会改(本次手工)
config.yaml 2.2.4 手工(type: yaml 有副作用,已在 #123 摘掉)
desktop/src-tauri/Cargo.lock 2.2.4(本地包那一条,全文件只出现 1 次) 手工(归 cargo 生成)
deploy/kubernetes/deployment.yaml 2.2.4 ×2 处 image: 手工
scripts/installer/setup.nsi OutFile / APP_VERSION / VIProductVersion 三条 手工
version.jsonchangelog + release_date 重写成本版说明 手工(RP 只抬 $.version
.release-please-manifest.json 2.2.4 让 RP 下次不再往 2.2.5 抬(v2.2.3 之后定下的规矩)
scripts/installer/version.json(gitignore 的装配中间物) assemble_release_staging.ps1 的行为从根 version.json 同步一份 本地;不入库

每处替换都要求恰好命中预期次数config.yaml 1、k8s 2、nsi 各 1…),不满足就一个文件都不写。
version.json 的新 changelog 明确写了"不含 26 GB 分卷与增量包、NSIS 真装未验收",
因为壳的 updater.rs 会把这行显示给用户。

CHANGELOG

[2.2.4] 段按本仓口径写:两处用户可见修复(#84 直切 503 的先清场再预检、#99 的 onclick
属性注入改事件闭包 + 同源裸插值收口)、发布链路收口(#118 判据换 median 单向 50% 与
三级基线原本三条都不通extra-files 的 yaml 整份重写、release PR 无 CI、§7b 复算账、
治理文件 LF + mailmap 补 249 个提交)、版本语义(约定式提交算下来也是 patch)、
以及已知未覆盖四条

已经跑过的 / 还没跑完的

已跑:test_version_consistency + test_dependency_consistency + test_integrity_selfcheck_packaging
= 31 passedruff check 通过;ruff format --check 404 files already formatted;
pre-commit(ruff / trailing / eof / ast / secrets / engine specs / capabilities / integrity sync /
structure guard)与 pre-push(ruff、format、mypy 棘轮 103 不变)全过。

合并前还要看完:全量 pytest(含 e2e,本地后台跑,数字贴在本 PR 最后一条评论)与这条 PR 的 CI。
两样没同时绿之前不打 tag。

产物侧验收计划(合并之后,与 v2.2.3 同形)

  1. git tag -a v2.2.4 指向合并后的 main(注解 tag,不 GPG 签名 —— GPG_PRIVATE_KEY 这个
    secret 不存在,与本仓历史一致)→ push;
  2. python -m build → wheel + sdist,twine check 双过,生成 SHA256SUMS.txt
  3. gh release create 挂轻资产(不含 26 GB 分卷 / 增量包 / Setup.exe);
  4. 从 Release 页面下载回读:比哈希 + 解包核对三件事 —— 完整性三件套在场、
    METADATAVersion: 2.2.4、解到临时目录后 run_startup_selfcheck(enforce=True)
    16/16/0/signed=True(v2.2.3 就是靠这一步才发现并修好缺口的,这次继续按产物验收而不是按声明)。
  5. 顺手核对 docker-publish.yml 是否为 v2.2.4 产出 :2.2.4 镜像 —— 本机这个 token 看不到
    ghcr(匿名 403、gh api packages 404),所以这条只能报"流水线是否绿",不能报"镜像已在"。

按 owner 指示走手工发版(关掉 RP 的 #120)。理由不是 #120 内容有问题,而是它拿不到 CI:
GITHUB_TOKEN 产生的提交不级联触发 workflow,所以 5 类手工同步位不会在 release PR 上红,
只会红在发布之后的 main 上。手工路径可以一次把 9 处版本位改齐并在打 tag 前跑完闸。

本次改动:
- 9 处版本位 2.2.3 -> 2.2.4:pyproject.toml、config.yaml、version.json(含 changelog 与
  release_date 两个手工位)、desktop/package.json、tauri.conf.json、Cargo.toml、Cargo.lock、
  deploy/kubernetes/deployment.yaml(两处 image tag)、scripts/installer/setup.nsi
  (OutFile / APP_VERSION / VIProductVersion)
- .release-please-manifest.json 同步抬到 2.2.4,避免 RP 在下一条 release PR 上把版本号再抬一格
- CHANGELOG 新增 [2.2.4] 段:两处用户可见修复(#84 直切 503、#99 onclick 属性注入)+
  发布链路收口(#118 性能门禁判据与三级基线存储、extra-files 的 yaml 副作用、release PR 无 CI、
  §7b 复算账、治理文件 LF 与 mailmap 的 249 个提交)+ 版本语义 + 已知未覆盖四条
- docs/release-governance.md §1 的"已发布最新"跟到 v2.2.4

本地门禁:tests/test_version_consistency.py + test_dependency_consistency.py +
test_integrity_selfcheck_packaging.py = 31 passed;ruff check 通过、ruff format --check 404 files
already formatted。scripts/installer/version.json(gitignore 的装配中间物)按 assemble_release_staging.ps1
的行为从根 version.json 同步了一份,否则本地那条"若在场则必须等于源"会红。

Signed-off-by: ReSerendipity <zengyangc@outlook.com>
@ReSerendipity

Copy link
Copy Markdown
Owner Author

真机验收结果(打 tag 之前跑的,与 CI 并列)

1. 全量测试(非 e2e,与 CI 同口径 --ignore=tests/e2e --timeout=180

2131 passed, 38 skipped, 9 warnings in 77.71s        (collected 2169)

38 skipped 是 benchmarks(要 --benchmark-only)与平台条件项,不是失败。
ruff check 通过;ruff format --check 404 files already formatted。

2. #84 的那条路:12GB 卡上连续直切四个引擎,全程不手动 unload

服务真起(integrated_app.app_serverTTS_AUTO_LOAD_MODEL=false;下表是第二次跑的那轮,第 1 步的 2266 MiB 空闲是因为上一轮探针退出前 voxcpm2 还挂着 —— 那反而更像真实使用场景),
每步都只调 /api/model/load,让服务端自己"先清场再预检"——这正是 #84 修的行为。
判据是"有没有 503",所以客户端不再替服务端做显存决定(第一版我加了个
"空闲 < 5200 MiB 就硬停"的闸,结果它把被测行为本身抹掉了 —— 已改掉)。

目标引擎 load 前空闲 HTTP 耗时 服务端报已用
1 voxcpm2 2266 MiB 200 ok 32.2 s 6177 MiB
2 indextts2 (2.5) 2108 MiB 200 ok 36.9 s 6799 MiB
3 indextts20 (2.0) 886 MiB 200 ok 33.9 s 7090 MiB
4 voxcpm2(切回) 609 MiB 200 ok 33.0 s 6178 MiB

第 2–4 步的"load 前空闲"都低于目标引擎的占用量 —— 旧行为就是在这里 503。
一次没有 503,也没有 status=error

3. 切完的引擎是能出声的,不只是"加载成功"

POST /api/generate/voxcpm_design(文本 + 音色描述)→ HTTP 200,返回 htmx 片段
content-type: text/html,里面 <audio src="/api/audio/voxcpm_design_1790074448.wav">),
按片段引用回读音频:206,580 B,头 b'RIFF'。与历史基线同量级(voxcpm2 一段约 230 KB)。

这里我第一版也写错了判据:拿 len(content) > 10 KB 判裸音频,
结果 783 B 的 HTML 片段被判"合成失败"。真实契约是片段 + /api/audio/... 回读。

4. 显存卫生(收尾核实)

POST /api/model/unload -> 200 {"status":"ok","message":"Model unloaded, VRAM released"}
nvidia-smi used:  9489 MiB -> 3344 MiB      (服务端报 vram_used = 32 MiB)
停服务后:7869 无 LISTENING、无 app_server 进程、used 2790 MiB / free 9155 MiB

5. #99 那一面(persona/历史接线)

  • 本 PR 不改模板/JS,所以 CI 的 Playwright E2E 不触发(它的 paths 只认 templates/**
    static/**routes/**);它在该改动合入的那次 push 上跑过并成功
    777bfe1Playwright E2E Tests: completed/success
  • 我这轮的独立读数:服务端吐出的 command_palette.jsgotoTab( 1 处、activateTab( 0 处;
    仓库内 onclick= 拼接 JS 变量的写法 0 处grep 三种形状:+ var${}{{ }})。

6. 顺手挖出来的一件事,已立账不塞进这个版本

{{ }} 那一类里查出 7 处服务端模板onclick 属性内用 HTML 转义保护 JS 字符串
tabs/persona.html:108tabs/history.html:119-122partials/error_message.html:7
partials/post_processing.html:21)。这不是推论:Jinja 渲染出 'a&#39;-alert(1)-&#39;b'
而属性值在解析时会被解回 ' —— 单引号数从 2 变 4,字符串字面量被截断。
persona 名是用户敲的,所以有真实控制点。

模板改动会进被 tag 的产物,且这类改动要浏览器侧验收,所以没有塞进 v2.2.4:
→ issue #130(含可复现探针与两种修法,其中 |tojson 的用法有个反直觉的顺序要求)。

结论

CI 28 项通过(Docker 两条在途,非必需检查)+ 本地全量 2131 passed + 真机四向直切全 200 +
音频回读 206,580 B + 显存与进程收尾核实。按这个验收口径放行打 tag。

@ReSerendipity
ReSerendipity merged commit d4d80b7 into main Sep 22, 2026
31 checks passed
@ReSerendipity

Copy link
Copy Markdown
Owner Author

v2.2.4 已发布(手工路径,按 owner 指示)

tag v2.2.4(注解 tag,无 GPG 签名)→ tag 对象 c200fec,指向本 PR 的合并提交 d4d80b7
Release https://github.com/ReSerendipity/TTS_MultiModel/releases/tag/v2.2.4
资产 wheel 28,381,997 B / sdist 28,333,402 B / SHA256SUMS.txt(GitHub 给的 asset.digest 与我本地算的 sha256 逐字符相同:6fd8d5fe… / 82ff57bf…
twine check 双 PASSED
解包验收 run_startup_selfcheck(enforce=True)total=16 passed=16 failed=0 manifest_signed=true;wheel 1065 条、三件套在场
tag 触发的作业 release-gate success、GPG-Signed Release success(无 secret → notice 跳过那条路)、Docker Build & Publish 在跑(:2.2.4 由它产出,本文不预先声称镜像已在)

release-please 与手工发版没有互踩(这次是量出来的)

main 上 d4d80b7 的第一次 Release 作业因 GitHub 侧超时红了
release-please failed: We couldn't respond to your request in time.,不是配置问题;
重跑 attempt 2 = success)。那一跑里两条读数正好把"两条路会不会互踩"这件事钉死:

发版链路自证:manifest=2.2.4  最新 tag=v2.2.4        ← 我在 #129 里一起抬的 manifest 生效
release-please:Found release for path ., v2.2.4
               release for path: ., version: 2.2.4, sha: d4d80b75d902327…

也就是 RP 认了这个手工 tag,没有再往 2.2.5 抬、也没有开新的 release PR。
当前 open PR 只剩 #89/#90/#91 三条 dependabot(仍排在 §7b 的 ④ 真装之后)。

顺带挖到一条独立的账

验收 #99 那一面时量出:服务端模板里还有 7 处onclick 属性内用 HTML 转义保护 JS 字符串
tabs/persona.html:108tabs/history.html:119-122partials/error_message.html:7
partials/post_processing.html:21)。探针:Jinja 渲染出 'a&#39;-alert(1)-&#39;b'
属性值解析时实体被解回 ' → 单引号从 2 个变 4 个,字符串字面量被截断;persona 名是用户敲的,
所以有真实控制点。没有塞进这个被 tag 的构建(模板改动要浏览器侧验收)→ 立为 issue #130

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant