Repository navigation
test(nightly): 补齐 journey/live-photo/agent 摘要与 AI 批量路由盲区 + 对齐 CI 扫描配置 (2026-10-27) - #396
Conversation
Nightly Watch 2026-10-27 · CI 全绿Commit
17 pass / 1 skipped(预期)/ 0 fail。 PR 状态 OPEN + MERGEABLE + CLEAN。 本轮没有改动任何前端代码或既有测试,第二次完整 E2E 由上面的 CI 容器 job 执行并通过。 🤖 Generated with Codex |
第 2 轮测试结果补充(2026-10-27 12:30)新增 commit 本地证据
本轮修复的 2 个 C 类环境问题
新增测试:7 个模块 / 41 个用例
覆盖率提升: CI:本轮新增 commit 已触发新一轮流水线,结果见下方 checks。本 PR 保持 OPEN,不合入 master。 |
CI 结果:全部通过 ✅第 2 轮 commit
CI 的 E2E 用 |
Nightly Watch 2026-10-28 第 4 轮(午间)· 测试结果分支 本地验证
新增测试(5 个模块 / 118 例)
覆盖率提升: 修复(A=8)
网络说明本机 仍未触碰
|
✅ CI 全绿(PR #396 · head
|
| 检查 | 结果 | 耗时 |
|---|---|---|
| Server unit (pytest) | pass | 4m20s |
| Server integration (pytest + live server) | pass | 46s |
| AI unit (pytest) | pass | 42s |
| CLI unit (pytest) | pass | 15s |
| Pi Agent (TypeScript) | pass | 25s |
| E2E (Playwright + docker compose) | pass | 15m3s |
| build-and-push-server | pass | 58s |
| build-and-push-frontend | pass | 2m19s |
| build-and-push-ai (cpu / gpu / openvino) | pass ×3 | 12m6s / 5s / 3s |
| Build Server (amd64 / arm64) | pass ×2 | 53s / 51s |
| Build Android debug APK | pass | 2m17s |
| Add APK to PR preview release | pass | 14s |
| Build macOS installer | pass | 15m20s |
| Build Linux installer | pass | 16m1s |
| Build Windows installer | pass | 25m44s |
| Add APK to GitHub release | skipped(tag-only 预期) | — |
| Add desktop installers to GitHub release | skipped(tag-only 预期) | — |
合计 19 pass / 2 skipped / 0 failed。 PR 保持 OPEN、base=master,不合入 master,等待 review。
本轮共 4 次 CI:首次(3e2e325b)Server unit 因以图搜图旧断言红 → 第二轮(3adfcccf)因新用例的
Linux 跨平台假设红 8 例 → 第三轮(556b6dab)全绿。
- 修复失败用例: photo-fixtures::fixture-scan-timeout(类型 A/C —— tests/.env.test.example 补齐 CI 已有的 TS_E2E_PREP_DEFERRED_TYPES=VISUAL_DESCRIPTION,RECOGNIZE_TICKET, 本地扫描不再串行跑 129 张照片的 VISUAL_DESCRIPTION,扫描准备由超时失败降到 165s+86s) - 新增覆盖: service/tasks/journey.py, service/live_photo/base.py, service/agent/tools.py, ai/routers/face.py, ai/routers/ocr.py, ai/routers/image_classification.py, ai/routers/tickets.py, ai/routers/llm.py 新增 38 个用例(后端 12 / AI 26);完整 E2E 420 passed / 4 skipped / 0 failed, 后端 unit 3864 passed / 16 skipped,AI unit 688 passed。 Nightly watch run 2026-10-27 Co-authored-by: Codex <noreply@openai.com>
- 新增覆盖: api/album.py, api/search.py, service/notification_manager.py, service/face_vector_cache.py, service/tasks/organize.py, ai/services/onnx_providers.py, ai/services/unified_model_manager.py - 修复失败用例: 本地 tests/.env.test 缺少 TS_E2E_PREP_DEFERRED_TYPES 导致 夹具扫描等待 CPU 推理的 VISUAL_DESCRIPTION 而超时 [C] - 覆盖率提升: api/album 106->121/123, api/search 139->160/162, face_vector_cache 143->172/177, notification_manager 42->46/48 新增测试: 7 个模块 / 41 个用例 本地完整 E2E: 420 passed / 4 skipped / 0 failed 后端 unit: 3894 passed / 16 skipped / 0 failed Nightly watch run 2026-10-27 Co-authored-by: Codex <noreply@openai.com>
- 新增覆盖: service/gallery_service.py, crud/album.py, service/tasks/tickets.py, utils/automatic_upgrade.py, utils/portable_conversion.py, services/ticket_service.py, services/ticket_parser.py Nightly watch run 2026-10-27 Co-authored-by: Codex <noreply@openai.com>
… / 任务 SSE / 车票编辑页盲区 - 修复失败用例: 无(本轮无失败用例,未改业务代码) - 新增覆盖: - app/utils/video_meta.py(_iter_boxes 大小/64 位头、udta/keys/ilst/meta 解析、mvhd/tkhd/mdhd 轨道头) - app/api/media.py(live backup pairs 校验、_verify_replacement、_finalize/_replace 备份替换、分片上传生命周期) - app/api/system.py(/desktop/runtime 身份校验、媒体校验失败落盘、天地图代理转发) - app/service/daily_frame.py(check_range、photo_day 时区、source_path、serialize_photo/frame、validate_selection) - app/api/tasks.py(SSE token 校验、hello 事件、断开后取消订阅) - app/service/agent/tools.py(search_photos_tool / search_photos_v2 全部筛选器分支) - package/website 前端:views/More.vue(/toolbox/ticket-edit)为唯一无 spec 的路由级 view Nightly watch run 2026-10-28 Co-authored-by: Codex <noreply@openai.com>
- 修复失败用例: tests/unit/test_nightly_organize_search_20261027.py::test_search_by_image_returns_vector_results(A)
master 合入 REQ-205(0307e30b)后 /api/search/image 改为 POST /embedding/image 并期望返回向量数组,
旧用例仍按 {"embedding": [...]} 封套断言,且期望 500;新实现对上游失败统一返回 502。
按 §3.3 优先 A 修正断言,并补充非图片/空文件两个拒绝分支。
- 新增覆盖:
- package/server app/service/daily_frame_render.py(FFmpeg/字体探测、能力报告、时长探针、合成、编码器、片段构建、取消守卫)36 例
- package/server app/utils/automatic_upgrade.py(_inventory、_check_journal、prepare/finish 安全守卫)23 例
- package/server app/service/task_manager.py(worker 启动/停止/排空/重启、看门狗、暂停分类)32 例
- package/server app/service/memory.py(_normalize_ai_story、归属守卫、票据/照片序列化)17 例
- package/ai app/services/ticket_parser.py(粘连时间修复、车厢座位修复、姓名低证据规则)10 例
- package/website 前端 views/search/ImageSearch.vue(/search/image),4 个用例
Nightly watch run 2026-10-28
Co-authored-by: Codex <noreply@openai.com>
- 修复失败用例: tests/unit/test_nightly_daily_frame_render_gaps_20261028.py(8 例,类型 A) Linux CI 镜像没有中文字体、且 tmp 文件没有可执行位,导致 shutil.which 返回 None、 ImageFont.truetype 抛 OSError:ffmpeg/ffprobe 发现、capabilities 报告、字幕排版 与合成共 8 例失败。改为运行时探测可用字体(找不到就 skip)、探测用例改用 mock 的 shutil.which,并给 captions 换行断言改用可控的测量宽度。 Nightly watch run 2026-10-28 Co-authored-by: Codex <noreply@openai.com>
- 修复失败用例: test_nightly_portable_conversion_happy_20261028.py::test_convert_to_portable_*(类型 A,夹具缺 tasks.payload 列 + 桩掉了 _prepare_desktop_database 的路径登记) - 新增覆盖: utils/portable_conversion, service/agent/album_p0, crud/photo, service/memory, api/settings, service/storage, AI services/ticket_parser Nightly watch run 2026-10-28 Co-authored-by: Codex <noreply@openai.com>
556b6da to
63921e0
Compare
- test_nightly_memory_story_merge: 改为 patch config_manager 单例实例;tests/unit/test_gallery_service.py 用裸赋值永久替换了实例属性,实例属性会遮蔽类属性,导致整轮跑时 patch 失效 - test_nightly_portable_conversion_happy: 转换会写 TS_DESKTOP*/TS_DATA_DIR,夹具改为快照并还原环境变量,避免把后续用例的照片路径指到临时图库 Nightly watch run 2026-10-28 Co-authored-by: Codex <noreply@openai.com>
- _validate_upload_folder 依赖 os.path.isabs,只认识当前平台的绝对路径;C:\\Windows\\System32 在 Linux 上是相对名,/etc/passwd 在 Windows 上是相对名 - 拆分参数:遍历片段全平台保留,绝对路径按 os.name 选择 Nightly watch run 2026-10-28 Co-authored-by: Codex <noreply@openai.com>
第 5 轮(trailsnap-4)测试结果 — 2026-10-28接手上一轮被中断的 7 个未跟踪测试文件,跑通后补齐盲区并修掉 CI 红灯。 本地
新增覆盖(7 个模块 / 116 个用例)
修复(A 类,14 个用例)
环境(C=1):本机 Docker Desktop 起不来( CI:3 次推送, 报告: |
Nightly Watch 2026-10-27(第 1 轮 + 第 2 轮)
夜间测试值守的两轮结果。唯一事实源:
tests/scripts/NIGHTLY-TEST-WATCH.md。测试结果
-Layer e2e -Level full)第 1 轮:修复(A=1 / B=0 / C=1)
fixture scan 本地超时,整套 E2E 一次都没跑起来
Error: 照片准备超时: scan=completed VISUAL_DESCRIPTION=113,扫描阶段硬超时 5 分钟,0 个用例执行。VISUAL_DESCRIPTION=51。VISUAL_DESCRIPTION串行耗时约 20 分钟。CI 的tests/.env.test.ci早已配置TS_E2E_PREP_DEFERRED_TYPES=VISUAL_DESCRIPTION,RECOGNIZE_TICKET把这两类远程大模型任务延后,而本地tests/.env.test.example缺这一行,本地与 CI 的扫描准备行为不一致。tests/.env.test.example补上与 CI 一致的TS_E2E_PREP_DEFERRED_TYPES。扫描准备由「超时失败」降到 fixture processing 165s + 86s,两段均稳定完成。未修改tests/.env.test,未改动任何既有测试代码或断言。前端 E2E 盲区复核(§4.3):子串匹配给出 0 个盲区,改词边界匹配得到 4 个候选,逐个核对 router 与 spec 后确认全部为误报(
/forgot-password、/mobile-search、/search均由路由访问覆盖,TicketHeader由票夹子页面渲染)。前端 view 层无真实盲区,本轮不补前端 E2E。第 1 轮:新增测试(8 个模块 / 38 个用例)
package/server/tests/unit/test_nightly_journey_agent_search_20261027.py(12 个用例)app/service/tasks/journey.py:AssociateJourneysStrategy的 category / resource_key;缺 owner_id 抛 ValueError;process经asyncio.to_thread委派_run;_run<200 条不入队 / ≥200 条入队一次;_run依据源库车票读取车站名。app/service/live_photo/base.py:抽象基类不可直接实例化;子类回落到基类实现时执行两个pass体。app/service/agent/tools.py:_build_search_summary中城市聚合 / 标签聚合异常时互不影响。package/ai/tests/test_nightly_ai_router_batch_errors_20261027.py(26 个用例)app/routers/face.py/ocr.py/image_classification.py:_select_max_workers的 GPU / CPU / CUDA 探测异常分支;空批次 400;单图失败隔离;未预期异常 500。app/routers/tickets.py:_predict_batch去 data URL 前缀;空批次 400;ValueError → 400;其他异常 → 500。app/routers/llm.py:上游httpx.RequestError→ 502。第 2 轮:修复(C=2)
1. 本地
tests/.env.test过期,缺少TS_E2E_PREP_DEFERRED_TYPESError: 照片准备超时: scan=completed VISUAL_DESCRIPTION=111,扫描阶段 305.6s 硬超时,0 个用例执行。tests/.env.test.example,但本地tests/.env.test(最后修改于 2026-08-06)仍然没有这一行。package/website/e2e-system/helpers/task-poller.ts的deferredTypes()靠这个变量把远程大模型任务从「通用夹具准备」的必需项里摘掉;缺了它,本机 CPU 推理的VISUAL_DESCRIPTION必须跑完(≈20 分钟),而waitForTasksToSettle的等待上限是 5 分钟,必然超时。CI 用tests/.env.test.ci,该文件一直有这一行,所以 CI 从未受影响。tests/.env.test与已提交模板对齐(补这一行)。该文件被.gitignore忽略,不进入仓库,也不影响任何提交产物。本轮未修改tests/.env.test.example(第 1 轮已经补好了)。2. 本地 pnpm 版本重写
package/website/pnpm-lock.yaml(工具链产物,已回退)pnpm install,本机新版 pnpm 不再读取package.json的pnpm.overrides/pnpm.patchedDependencies,把 lockfile 重写成不含这两段的版本(+307 / −382)。page-flip的补丁依赖。第 2 轮:新增测试(7 个模块 / 41 个用例)
package/server/tests/unit/test_nightly_album_notify_vec_20261027.py(3 个模块 / 21 个用例)app/api/album.py:smart 相册按描述生成 query embedding 并排入SCAN_ALBUM任务;普通相册两者都不触发;封面自动取最早的一张照片;封面落库失败不影响相册读取;删除相册 / 上传照片的归属校验(404、403);上传转发到upload_photo_generic;从相册移除照片时「照片不在相册内」返回 404。app/service/notification_manager.py:按user_id精确投递;user_id为 None 时广播;事件循环已关闭时静默丢弃;队列满时丢弃最旧一条;退订只移除目标队列;订阅者中途消失不打断发布。app/service/face_vector_cache.py:_env_int的非整数 / 非正数 / 缺省回落;_pack对 None 与维度不符的向量保持零行;_Shard.append的维度推断、缓冲区扩容与水位线;invalidate的单 owner 与全量;按预算淘汰最旧分片;stats的行数与已分配行数。package/server/tests/unit/test_nightly_organize_search_20261027.py(2 个模块 / 9 个用例)app/service/tasks/organize.py:_commit_transfer的 move / copy 正常路径;commit 失败时回滚并把文件放回原处(move)与删除残留副本(copy);文件恢复也失败时抛出带「请保留文件」指引的RuntimeError。app/api/search.py:以图搜图的正常返回、AI 服务非 200、AI 未返回 embedding;文本搜索查询异常时转成 500 而非泄漏异常。package/ai/tests/test_nightly_ai_model_providers_20261027.py(2 个模块 / 11 个用例)app/services/onnx_providers.py:没有任何 execution provider 时回落 CPU;Apple 性能核的 sysctl 探测成功 / 失败回落;不带 session options 时交由 onnxruntime 决定;未选中 CoreML 时直接建会话。app/services/unified_model_manager.py:按runtimeKey解析模型;未知键抛KeyError;get_model_file拒绝越界路径;ModelScope 下载透传revision与allowPatterns;trigger_download拒绝不可用模型、且不重复启动同一下载。覆盖率变化(第 2 轮)
app/api/album.pyapp/api/search.pyapp/service/face_vector_cache.pyapp/service/notification_manager.pyapp/service/tasks/organize.pyprocess的分策略分支仍未覆盖)后端整体行覆盖率 87% → 90.1%(
tests/artifacts/nightly/2026-10-27/coverage-backend-round2.xml)。未在本地跑第二次完整 E2E
两轮都没有改动任何前端代码或既有测试,回归风险仅来自新增后端/AI 用例;第二次完整 E2E 交由 CI 容器执行(与 10-20 / 10-22 / 10-23 轮一致)。
下次待办
app/service/tasks/organize.py的process主体(约 23 行)仍未覆盖:需要真实Photo+PhotoMetadata+FaceORM 行来驱动 category / person / location / time 四种分策略。app/utils/portable_conversion.py46.7%(153 miss):convert_to_portable主体,需要真实桌面程序目录 fixture。app/utils/automatic_upgrade.py58.4%(107 miss):finish()真实清理流程,需要完整 journal / instance.json fixture。app/service/agent/tools.py71.1%(117 miss)、app/api/media.py80%(163 miss)、app/api/settings.py80.5%(111 miss)。services/ticket_parser.py89.9%(109 miss)、services/ticket_service.py91.7%(33 miss)。tests/.env.test的同步机制固化,避免再次落后于模板。报告:
tests/artifacts/nightly/2026-10-27/summary.md🤖 Generated with Codex
Nightly Watch 2026-10-28(第 3 轮 + 第 4 轮)
唯一事实源:
tests/scripts/NIGHTLY-TEST-WATCH.md。第 3 轮为当日清晨,第 4 轮为当日午间。测试结果
-Layer e2e -Level full)第 4 轮:修复(A=8,CI 红灯)
test_nightly_daily_frame_render_gaps_20261028.py本地全绿、Linux CI 失败 8 例test_ffmpeg_path_prefers_the_configured_binary、test_ffprobe_path_prefers_the_adjacent_binary、test_capabilities_report_a_missing_h264_encoder、test_capabilities_are_available_with_ffmpeg_and_h264、test_make_overlay_*(3 例)、test_compose_still_*→8 failed, 4167 passed, 39 skipped。shutil.which在 Linux 上要求可执行位,tmp 目录里新建的文件没有该位 → 返回None;ImageFont.truetype对不存在的字体文件抛OSError,capabilities()因此走到「编码器或中文字体无法使用」的兜底分支而不是 H.264 分支。shutil.which;字体改为运行时探测可用字体文件(Windows msyh/arial、Linux DejaVu、macOS PingFang),
找不到就
skip;字幕换行断言改用可控的测量宽度(默认字体没有中文字形,宽度恒为 0)。第 4 轮:新增测试(5 个模块 / 118 个用例)
package/server/tests/unit/test_nightly_daily_frame_render_gaps_20261028.py(36 例)app/service/daily_frame_render.py:FFmpeg/FFprobe/字体探测;capabilities()的缺 FFmpeg / 缺字体 / 缺 H.264 / 正常 / 编码器异常五条分支;FFprobe 与 OpenCV 两条
时长探针;输出目录创建、只删自己目录下的 mp4/jpg;字幕排版与静帧合成;
编码器的非零退出、超时、取消与成功;片段构建的 still / portrait preview /
时长变化 / 无时长 / 视频滤镜;
render_work对未知与已结束任务的取消。package/server/tests/unit/test_nightly_automatic_upgrade_gaps_20261028.py(23 例)app/utils/automatic_upgrade.py:_inventory的清理标记、进度回调、链接拒绝与排除项;_check_journal的 schema / uuid / 新图库内来源三类守卫;prepare的已有实例、已完成任务、实例身份变更、多候选、坏候选、已是便携库、userdata 非空、
非法版本号;
finish的未验证禁止清理、标记 validated、重复 validated、目标变更。package/server/tests/unit/test_nightly_task_manager_lifecycle_gaps_20261028.py(32 例)app/service/task_manager.py:启动后推送快照、worker 已在跑时保持安静、迁移排空时不启动、唤醒事件、只有存在可派发任务才起 worker、复用存活 worker、回收僵尸 worker;
停止 / 强杀 / 忽略停止;排空 join 与崩溃抛错;立即重启与优雅排空重启;
看门狗启停;bundled AI 恢复;暂停/恢复分类与系统状态读写。
package/server/tests/unit/test_nightly_memory_service_content_gaps_20261028.py(17 例)app/service/memory.py:_normalize_ai_story的推理块剥离、标题剥离、长文按句截断、长文无标点补句号;归属 404、空照片列表、部分照片不存在 400、顺序保持、去重;
照片载荷(缺元数据/无时间);票据载荷(未知类型 / 已删除的火车票 / 已删除的机票)。
package/ai/tests/test_nightly_ai_ticket_parser_datetime_seat_20261028.py(10 例)app/services/ticket_parser.py:粘连时间 4 位 / 6 位拆分为「日 + 时」、非法小时(94 点)被拒绝、紧凑
2020年08月29日2054还原;03车03A号/03车/12C号/二等座0206F号的车厢座位修复;掩码证件号后的姓名、站名不被当作姓名。
覆盖率变化(第 4 轮,后端)
app/service/task_manager.pyapp/service/daily_frame_render.pyapp/utils/automatic_upgrade.pyapp/service/memory.py本轮的环境问题:github.com:443 不可达
本机
git push持续报Failed to connect to github.com port 443,而api.github.com正常。本轮改用 GitHub Git Data API 推送(仓库内
tests/artifacts/nightly/push-via-api.ps1,该目录被 .gitignore 忽略,不进提交):
sync-local-with-remote.ps1把本地分支复位到同一 sha 并重新 mergeorigin/master,下次
git push仍是 fast-forward;下次待办
app/utils/portable_conversion.py46.7%(153 miss):仍是后端第一大缺口,convert_to_portable主体需要真实桌面程序目录 fixture。app/service/agent/album_p0.py79.5%(114 miss)、app/api/settings.py81.2%(117 miss)、app/crud/photo.py81.9%(115 miss)、app/service/agent/actions.py84.7%(149 miss)。services/ticket_parser.py90.4%(103 miss):parse_ticket_info的日期兜底表(1201-1251 行)本轮仍无法触达——
_build_departure_datetime会先命中并 return。报告:
tests/artifacts/nightly/2026-10-28/summary.mdNightly Watch 2026-10-28(第 5 轮 · trailsnap-4)
测试结果
-Layer e2e -Level full)63921e02第 5 轮:修复(A=5 / B=0 / C=1)
接手上一轮(被中断)遗留的 7 个未跟踪测试文件,其中
test_nightly_portable_conversion_happy_20261028.py的 5 个用例全红。逐个判定后全部属于 A 类(测试代码错),未改任何业务代码:
夹具表结构过期(
tasks.payload列缺失)sqlite3.OperationalError: no such column: payload(app/utils/portable_library.py:197会对每条任务做
SELECT id,payload FROM tasks WHERE payload IS NOT NULL的路径改写)。CREATE TABLE tasks (id TEXT PRIMARY KEY)没有payload列,而真实模型
app/db/models/task.py自 2026-10-18(feat(desktop): 统一便携实例更新并完善 AI 模型等待 #331)起就有该列。payload TEXT,并注明对齐来源。桩掉了
_prepare_desktop_database,连带丢掉路径登记ValueError: 升级前可读取的照片现在无法验证:…复制后的照片路径超出新图库。desktop_entry._prepare_desktop_database会调用prepare_portable_library(...)注册便携库的存储根;用例把它整个桩成空函数,于是转换后的数据库没有存储根引用,照片解析回落到已被改名删除的暂存目录路径。
prepare_portable_library(os.environ["TS_DESKTOP_ROOT"]),只跳过 Alembic 升级与管理员初始化(夹具是最小手写 schema,无法跑迁移)。
三处断言与真实契约不符
photos.file_path只是历史列;断言改为用生产同源的
desktop_verification.photo_paths解析有效路径,并校验文件确实落在新实例内。
library.json的initialized由prepare_portable_library在发布后置为True(与生产一致),改为断言
lastRoot指向新实例根。第 5 轮:新增测试(7 个模块 / 116 个用例)
package/server/tests/unit/test_nightly_portable_conversion_happy_20261028.py(5 例)app/utils/portable_conversion.py:连续 4 轮的最大覆盖率缺口(47%,153 miss)终于被覆盖到主体
convert_to_portable:完整转换成功并发布实例、库身份轮换、secret key 重新生成、源库保持不变、用户 storage 设置改写。
package/server/tests/unit/test_nightly_album_p0_db_timeline_gaps_20261028.py(13 例)app/service/agent/album_p0.py:相册/时间线相关的数据库时间线与守卫分支。package/server/tests/unit/test_nightly_crud_photo_recycle_lifecycle_20261028.py(17 例)app/crud/photo.py:回收站软删除 → 还原 → 永久删除的生命周期。package/server/tests/unit/test_nightly_memory_story_merge_gaps_20261028.py(14 例)app/service/memory.py:AI 故事合并(未配置模型 / 陈旧生成可重启 / 落库并清理状态 /prompt 只含有据事实 / 模型空返回 / 模型异常 / 剥离 think 标签与标题)。
package/server/tests/unit/test_nightly_settings_filter_task_gaps_20261028.py(11 例)app/api/settings.py:文件/文件夹过滤任务,含非法正则跳过而不中断其余过滤。package/server/tests/unit/test_nightly_storage_error_paths_20261028.py(24 例)app/service/storage.py:存储层的错误路径与守卫。package/ai/tests/test_nightly_ai_ticket_parser_datetime2_gaps_20261028.py(16 例)package/ai/app/services/ticket_parser.py:日期/时间兜底解析的第二组用例。文档修正(
tests/scripts/NIGHTLY-TEST-WATCH.md)git add列表都漏了package/ai/tests/,但 §4.2 / §4.4 明确要求 AI 测试写在该目录——照原文执行会让 §6.1 误判「改动超范围」。
两处已补上并加
[skip-nightly]标记。本轮的环境问题(C=1)
docker-desktopWSL 发行版起不来,后端日志报
dockerInferencesocketThe file cannot be accessed by the system),因此
docker-compose/docker-compose-pg.yml的 PostgreSQL(端口 5532)拉不起来。tests/.env.test未修改,另存一份临时 env 文件),结果与今天上午 postgres 基线完全一致(429 passed / 4 skipped / 0 failed)。
CI 仍在 docker + postgres 下运行,以 CI 为准。
下次待办
app/utils/portable_conversion.py:主体已覆盖,但copy_external=True分支(外部图库复制)仍未触达。
app/service/agent/actions.py84.7%(149 miss)、app/api/media.py84.5%(126 miss)。services/ticket_parser.py:parse_ticket_info的日期兜底表(1201-1251 行)仍无法触达。报告:
tests/artifacts/nightly/2026-10-28/summary.md第 5 轮:CI 红灯与修复(3 次推送)
63921e02b8a81cb3691f7ed1红灯 #1(15 failed):新用例污染了整个测试会话。
test_nightly_memory_story_merge_gaps_20261028.py:7 个用例整轮跑时红、单跑绿。原因是 patch 打在
ConfigManager类上,而tests/unit/test_gallery_service.py:195用裸赋值
gallery_service.config_manager.get_user_config = MagicMock(...)永久替换了单例实例上的同名方法——实例属性遮蔽类属性,patch 直接失效,
于是真实配置被读了出来(报「当前 AI 连接不可用」而不是「配置 AI 对话模型」)。
→ 改为 patch 单例实例(monkeypatch 会还原原值,不影响既有污染)。
test_nightly_portable_conversion_happy_20261028.py:真实转换会写TS_DESKTOP/TS_DESKTOP_PORTABLE/TS_DESKTOP_ROOT/TS_DATA_DIR,而存储层用这些变量解析所有照片路径 → 泄漏后整个会话的照片路径都被指到临时图库。
连带把 6 个既有文件打成红:
test_user_storage的断言路径变成new-instance\userdata\...,test_nightly_priority_gaps/test_tasks_organize/test_scan_folder_helpers报
'_NewPhoto' object has no attribute '_file_path'。→ 夹具改为快照并在 teardown 还原
os.environ。红灯 #2(1 failed):
test_validate_upload_folder_rejects_escaping_paths[C:\Windows\System32]在 Linux 上没抛
ValueError——_validate_upload_folder依赖os.path.isabs,只认识当前平台的绝对路径,
C:\Windows\System32在 Linux 上只是相对名。→ 拆分参数:遍历片段全平台保留,绝对路径按
os.name选择。第 5 轮:本地验证
其余 build / installer 全部 success。