Skip to content

test(nightly): 补齐 journey/live-photo/agent 摘要与 AI 批量路由盲区 + 对齐 CI 扫描配置 (2026-10-27) - #396

Merged
LC044 merged 9 commits into
masterfrom
nightly/test-watch-20261027
Oct 28, 2026
Merged

LC044 merged 9 commits into
masterfrom
nightly/test-watch-20261027

Conversation

@LC044

@LC044 LC044 commented Oct 26, 2026 •

Copy link
Copy Markdown
Owner

Nightly Watch 2026-10-27(第 1 轮 + 第 2 轮)

夜间测试值守的两轮结果。唯一事实源:tests/scripts/NIGHTLY-TEST-WATCH.md。

测试结果

项 第 1 轮 第 2 轮
完整 E2E(-Layer e2e -Level full) 420 passed / 4 skipped / 0 failed(exit 0) 420 passed / 4 skipped / 0 failed(exit 0)
后端 unit 全量 3864 passed / 16 skipped(exit 0) 3894 passed / 16 skipped / 0 failed(exit 0)
AI unit 全量 688 passed(exit 0) exit 0
新增用例定向重跑 12 passed(server)/ 26 passed(ai) 21 + 9 passed(server)/ 11 passed(ai)
覆盖率 后端 87% / AI 91% 后端 90.1% / AI 91%(早间)

第 1 轮:修复(A=1 / B=0 / C=1)

fixture scan 本地超时,整套 E2E 一次都没跑起来

  • 表征(首跑):Error: 照片准备超时: scan=completed VISUAL_DESCRIPTION=113,扫描阶段硬超时 5 分钟,0 个用例执行。
  • 表征(第二次):把等待上限临时放宽到 12 分钟仍超时,12 分钟只跑到 VISUAL_DESCRIPTION=51。
  • 根因:本机 CPU 推理下 129 张照片的 VISUAL_DESCRIPTION 串行耗时约 20 分钟。CI 的 tests/.env.test.ci 早已配置 TS_E2E_PREP_DEFERRED_TYPES=VISUAL_DESCRIPTION,RECOGNIZE_TICKET 把这两类远程大模型任务延后,而本地 tests/.env.test.example 缺这一行,本地与 CI 的扫描准备行为不一致。
  • 处置(A 类,只改配置不动断言):在 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_TYPES

  • 表征:Error: 照片准备超时: scan=completed VISUAL_DESCRIPTION=111,扫描阶段 305.6s 硬超时,0 个用例执行。
  • 根因:第 1 轮把该变量补进了已提交的模板 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 从未受影响。
  • 处置(C 类,本地环境):把本地未受版本控制的 tests/.env.test 与已提交模板对齐(补这一行)。该文件被 .gitignore 忽略,不进入仓库,也不影响任何提交产物。本轮未修改 tests/.env.test.example(第 1 轮已经补好了)。
  • 验证:补齐后完整 E2E 首跑即 420 passed / 4 skipped / 0 failed;扫描阶段由「超时失败」降到 fixture processing 182.7s + 82.2s。

2. 本地 pnpm 版本重写 package/website/pnpm-lock.yaml(工具链产物,已回退)

  • 表征:E2E 的「确保 Playwright chromium 已安装」触发 pnpm install,本机新版 pnpm 不再读取 package.json 的 pnpm.overrides / pnpm.patchedDependencies,把 lockfile 重写成不含这两段的版本(+307 / −382)。
  • 处置:按 §1.1「临时文件清理」判定为本地工具链产物并回退,不进入提交。若直接提交会丢掉 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 轮)

模块 第 1 轮后 第 2 轮后 变化
app/api/album.py 106/123 121/123 +15 行
app/api/search.py 139/162 160/162 +21 行
app/service/face_vector_cache.py 143/177 172/177 +29 行
app/service/notification_manager.py 42/48 46/48 +4 行
app/service/tasks/organize.py 160/186 163/186 +3 行(process 的分策略分支仍未覆盖)

后端整体行覆盖率 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 + Face ORM 行来驱动 category / person / location / time 四种分策略。
  • app/utils/portable_conversion.py 46.7%(153 miss):convert_to_portable 主体,需要真实桌面程序目录 fixture。
  • app/utils/automatic_upgrade.py 58.4%(107 miss):finish() 真实清理流程,需要完整 journal / instance.json fixture。
  • app/service/agent/tools.py 71.1%(117 miss)、app/api/media.py 80%(163 miss)、app/api/settings.py 80.5%(111 miss)。
  • AI:services/ticket_parser.py 89.9%(109 miss)、services/ticket_service.py 91.7%(33 miss)。
  • 前端 §4.3 的「子串匹配」判定脚本仍未落进仓库(建议改成 router 表反查)。
  • 建议把本地 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 轮为当日午间。

测试结果

项 第 3 轮(清晨) 第 4 轮(午间)
完整 E2E(-Layer e2e -Level full) 420 passed / 4 skipped / 0 failed 429 passed / 4 skipped / 0 failed(exit 0,17.4 min)
后端 unit 全量 3628 passed(exit 0) 4196 passed / 18 skipped(exit 0)
AI unit 全量 520 passed(exit 0) exit 0
新增用例 7 个模块 / 124 例 5 个模块 / 118 例
覆盖率 后端 88% / AI 93% 后端 88%(28177 语句 / 2475 miss)

第 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。
  • 根因(两条平台假设):
    1. shutil.which 在 Linux 上要求可执行位,tmp 目录里新建的文件没有该位 → 返回 None;
    2. CI 镜像没有中文字体,ImageFont.truetype 对不存在的字体文件抛 OSError,
      capabilities() 因此走到「编码器或中文字体无法使用」的兜底分支而不是 H.264 分支。
  • 处置(A 类,只改测试不动业务代码):探测用例改为 mock shutil.which;
    字体改为运行时探测可用字体文件(Windows msyh/arial、Linux DejaVu、macOS PingFang),
    找不到就 skip;字幕换行断言改用可控的测量宽度(默认字体没有中文字形,宽度恒为 0)。
  • 验证:本地 36/36 通过;修复后 CI Server unit 转绿(见下表)。

第 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 轮,后端)

模块 第 3 轮后 第 4 轮后 变化
app/service/task_manager.py 78.7%(86 miss) 90.6%(38 miss) +12 pt
app/service/daily_frame_render.py 80.1%(49 miss) 85.0%(37 miss) +5 pt
app/utils/automatic_upgrade.py 71.6%(73 miss) 74.3%(66 miss) +3 pt
app/service/memory.py 79.6%(84 miss) 81.3%(77 miss) +2 pt

本轮的环境问题: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 忽略,不进提交):

  • 上传的 blob / tree / commit 与本地 git 对象完全一致(commit sha 相同);
  • 再用 sync-local-with-remote.ps1 把本地分支复位到同一 sha 并重新 merge origin/master,
    下次 git push 仍是 fast-forward;
  • PR 的 CI 与流水线与普通 push 完全相同。

下次待办

  • app/utils/portable_conversion.py 46.7%(153 miss):仍是后端第一大缺口,
    convert_to_portable 主体需要真实桌面程序目录 fixture。
  • app/service/agent/album_p0.py 79.5%(114 miss)、app/api/settings.py 81.2%(117 miss)、
    app/crud/photo.py 81.9%(115 miss)、app/service/agent/actions.py 84.7%(149 miss)。
  • AI services/ticket_parser.py 90.4%(103 miss):parse_ticket_info 的日期兜底表
    (1201-1251 行)本轮仍无法触达——_build_departure_datetime 会先命中并 return。
  • 前端 §4.3 已用「view → 路由 → spec 路径」映射复核,48 个路由级 view 全部被触达,无新增盲区。

报告:tests/artifacts/nightly/2026-10-28/summary.md


Nightly Watch 2026-10-28(第 5 轮 · trailsnap-4)

测试结果

项 结果
完整 E2E(-Layer e2e -Level full) 429 passed / 4 skipped / 0 failed(exit 0,12.9 分钟)
新增用例定向重跑 93 passed(server)/ 16 passed(ai)
新增测试 7 个模块 / 116 个用例
Commit 63921e02

第 5 轮:修复(A=5 / B=0 / C=1)

接手上一轮(被中断)遗留的 7 个未跟踪测试文件,其中 test_nightly_portable_conversion_happy_20261028.py
的 5 个用例全红。逐个判定后全部属于 A 类(测试代码错),未改任何业务代码:

  1. 夹具表结构过期(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,并注明对齐来源。
  2. 桩掉了 _prepare_desktop_database,连带丢掉路径登记

    • 表征:ValueError: 升级前可读取的照片现在无法验证:…复制后的照片路径超出新图库。
    • 根因:生产链路上 desktop_entry._prepare_desktop_database 会调用
      prepare_portable_library(...) 注册便携库的存储根;用例把它整个桩成空函数,
      于是转换后的数据库没有存储根引用,照片解析回落到已被改名删除的暂存目录路径。
    • 处置:桩函数改为调用真实的 prepare_portable_library(os.environ["TS_DESKTOP_ROOT"]),
      只跳过 Alembic 升级与管理员初始化(夹具是最小手写 schema,无法跑迁移)。
  3. 三处断言与真实契约不符

    • 便携布局里照片通过存储根引用定位,photos.file_path 只是历史列;
      断言改为用生产同源的 desktop_verification.photo_paths 解析有效路径,
      并校验文件确实落在新实例内。
    • library.json 的 initialized 由 prepare_portable_library 在发布后置为 True
      (与生产一致),改为断言 lastRoot 指向新实例根。
    • 用户 storage 设置改为断言「不残留指向已被删除的暂存目录的路径」。

第 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)

  • §0 的「影响范围」与 §6.2 的 git add 列表都漏了 package/ai/tests/,
    但 §4.2 / §4.4 明确要求 AI 测试写在该目录——照原文执行会让 §6.1 误判「改动超范围」。
    两处已补上并加 [skip-nightly] 标记。

本轮的环境问题(C=1)

  • 本机 Docker Desktop 无法启动(docker-desktop WSL 发行版起不来,
    后端日志报 dockerInference socket The file cannot be accessed by the system),
    因此 docker-compose/docker-compose-pg.yml 的 PostgreSQL(端口 5532)拉不起来。
  • 处置:本地完整 E2E 改用 SQLite 跑(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.py 84.7%(149 miss)、app/api/media.py 84.5%(126 miss)。
  • AI services/ticket_parser.py:parse_ticket_info 的日期兜底表(1201-1251 行)仍无法触达。
  • 本机 Docker Desktop 需修复(WSL 发行版起不来),否则本地 E2E 只能退回 SQLite。

报告:tests/artifacts/nightly/2026-10-28/summary.md


第 5 轮:CI 红灯与修复(3 次推送)

推送 SHA 结果
#1 63921e02 Server unit 红灯:15 failed / 4298 passed
#2 b8a81cb3 Server unit 红灯:1 failed / 4312 passed(跨平台假设)
#3 691f7ed1 全绿:Server unit / E2E / Server integration / AI unit / CLI unit / Pi Agent + 全部构建

红灯 #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 轮:本地验证

  • 完整 E2E:429 passed / 4 skipped / 0 failed(exit 0,12.9 分钟)
  • 后端 unit 全量:exit 0(4312 passed / 39 skipped)
  • AI unit 全量:exit 0
  • CI:Server unit 4m21s、E2E 15m42s、Server integration 53s、AI unit 46s、CLI unit 19s、Pi Agent 22s,
    其余 build / installer 全部 success。

@LC044 LC044 added the codex-automation PRs opened by codex automation label Oct 26, 2026
@LC044

LC044 commented Oct 26, 2026

Copy link
Copy Markdown
Owner Author

Nightly Watch 2026-10-27 · CI 全绿

Commit 7d9836d6(本地与远端分支 SHA 一致)。

检查项 结果
Server unit (pytest) pass 6m8s
AI unit (pytest) pass 34s
CLI unit (pytest) pass 14s
Server integration (pytest + live server) pass 1m4s
E2E (Playwright + docker compose) pass 11m0s
Pi Agent (TypeScript) pass 27s
Build Server amd64 / arm64 pass 5m18s / 5m22s
build-and-push-server / -ai (cpu/gpu/openvino) pass
Build Linux / Windows / macOS installer pass 12m27s / 22m42s / 17m11s
Add desktop installers to PR preview release pass 51s
Add desktop installers to GitHub release skipping(release 专用 job,非 PR 触发)

17 pass / 1 skipped(预期)/ 0 fail。 PR 状态 OPEN + MERGEABLE + CLEAN。

本轮没有改动任何前端代码或既有测试,第二次完整 E2E 由上面的 CI 容器 job 执行并通过。

🤖 Generated with Codex

@LC044

LC044 commented Oct 27, 2026

Copy link
Copy Markdown
Owner Author

第 2 轮测试结果补充(2026-10-27 12:30)

新增 commit b34f2569,本地测试通过后已直接 push 到本 PR。

本地证据

项 结果
完整 E2E(-Layer e2e -Level full) 420 passed / 4 skipped / 0 failed,exit 0(scan 1 passed / setup 1 passed / teardown 1 passed)
后端 unit 全量 3894 passed / 16 skipped / 0 failed,exit 0
AI unit 全量 exit 0
新增用例定向重跑 21 + 9 passed(server)、11 passed(ai)
夹具扫描准备 fixture processing 182.7s + 82.2s(TS_E2E_PREP_DEFERRED_TYPES 生效)
后端行覆盖率 87% → 90.1%

本轮修复的 2 个 C 类环境问题

  1. 本地 tests/.env.test(2026-08-06)缺少 TS_E2E_PREP_DEFERRED_TYPES=VISUAL_DESCRIPTION,RECOGNIZE_TICKET,导致 task-poller.ts 把本机 CPU 推理的 VISUAL_DESCRIPTION 当作必需项等待,5 分钟超时后整套 E2E 一次都没跑起来(照片准备超时: scan=completed VISUAL_DESCRIPTION=111)。已把本地未受版本控制的 tests/.env.test 与已提交模板对齐;tests/.env.test.example 在第 1 轮已补齐,本轮未再改动模板。
  2. 本机新版 pnpm 不再读取 package.json 的 pnpm.overrides / pnpm.patchedDependencies,pnpm install 会重写 package/website/pnpm-lock.yaml 并丢掉 page-flip 的补丁依赖。判定为本地工具链产物,已回退,未进入提交。

新增测试:7 个模块 / 41 个用例

  • package/server/tests/unit/test_nightly_album_notify_vec_20261027.py(21)— app/api/album.py、app/service/notification_manager.py、app/service/face_vector_cache.py
  • package/server/tests/unit/test_nightly_organize_search_20261027.py(9)— app/service/tasks/organize.py、app/api/search.py
  • package/ai/tests/test_nightly_ai_model_providers_20261027.py(11)— app/services/onnx_providers.py、app/services/unified_model_manager.py

覆盖率提升:api/album 106→121/123、api/search 139→160/162、face_vector_cache 143→172/177、notification_manager 42→46/48。

CI:本轮新增 commit 已触发新一轮流水线,结果见下方 checks。本 PR 保持 OPEN,不合入 master。

@LC044

LC044 commented Oct 27, 2026

Copy link
Copy Markdown
Owner Author

CI 结果:全部通过 ✅

第 2 轮 commit b34f2569 的流水线已跑完,16 pass / 1 skip / 0 fail,PR 保持 OPEN(不合入 master)。

Job 结果 耗时
E2E (Playwright + docker compose) pass 20m55s
Server unit (pytest) pass 4m28s
Server integration (pytest + live server) pass 54s
AI unit (pytest) pass 38s
CLI unit (pytest) pass 14s
Pi Agent (TypeScript) pass 23s
Build Windows installer pass 21m37s
Build macOS installer pass 15m49s
Build Linux installer pass 17m3s
Build Server (amd64 / arm64) pass 1m20s / 53s
build-and-push-server pass 1m0s
build-and-push-ai (cpu / gpu / openvino) pass 1m5s / 3s / 4s
Add desktop installers to PR preview release pass 2m0s
Add desktop installers to GitHub release skip release 专用 job,PR-only 场景预期跳过

CI 的 E2E 用 tests/.env.test.ci(含 TS_E2E_PREP_DEFERRED_TYPES),容器内 420 用例全绿,验证了本地第二轮 E2E 的结论。

@LC044

LC044 commented Oct 28, 2026

Copy link
Copy Markdown
Owner Author

Nightly Watch 2026-10-28 第 4 轮(午间)· 测试结果

分支 nightly/test-watch-20261027 → 远端 head 556b6dab(本地分支头 246d4e89 = 同一 commit + 未推送的 master merge)
PR #396 base=master,OPEN,不合入 master。

本地验证

项 结果
完整 E2E(-Layer e2e -Level full) 429 passed / 4 skipped / 0 failed(exit 0,17.4 min;fixture scan 328s)
后端 unit 全量(含新增 108 例) 4196 passed / 18 skipped(exit 0,15.9 min)
AI unit 全量(含新增 10 例) exit 0
后端行覆盖率 88%(28177 语句 / 2475 miss)

新增测试(5 个模块 / 118 例)

  • test_nightly_daily_frame_render_gaps_20261028.py(36)— app/service/daily_frame_render.py
  • test_nightly_automatic_upgrade_gaps_20261028.py(23)— app/utils/automatic_upgrade.py
  • test_nightly_task_manager_lifecycle_gaps_20261028.py(32)— app/service/task_manager.py
  • test_nightly_memory_service_content_gaps_20261028.py(17)— app/service/memory.py
  • test_nightly_ai_ticket_parser_datetime_seat_20261028.py(10)— app/services/ticket_parser.py

覆盖率提升:task_manager 78.7% → 90.6%、daily_frame_render 80.1% → 85.0%、
automatic_upgrade 71.6% → 74.3%、memory 79.6% → 81.3%。

修复(A=8)

test_nightly_daily_frame_render_gaps_20261028.py 本地全绿但 Linux CI 失败 8 例:
shutil.which 在 Linux 需要可执行位(tmp 文件没有 → 返回 None),CI 镜像又没有中文字体
(ImageFont.truetype 抛 OSError)。已改为 mock shutil.which + 运行时探测可用字体
(找不到则 skip)+ 可控的字幕测量宽度。修复后本地 36/36 通过。

网络说明

本机 github.com:443 不可达(git push 报 "Failed to connect to github.com port 443"),
但 api.github.com 正常,本轮通过 GitHub Git Data API 推送。上传的 blob/tree/commit 与
本地 git 对象 sha 完全一致,因此 CI 与普通 push 无差别;本地分支也已复位到同一 sha,
后续 push 仍是 fast-forward。

仍未触碰

  • app/utils/portable_conversion.py 46.7%(153 miss)— 连续三轮未啃动,需要真实桌面程序目录 fixture
  • AI services/ticket_parser.py 90.4%(103 miss)— parse_ticket_info 的日期兜底表(1201-1251 行)被 _build_departure_datetime 抢先 return,仍无法触达

@LC044

LC044 commented Oct 28, 2026

Copy link
Copy Markdown
Owner Author

✅ CI 全绿(PR #396 · head 556b6dab)

检查 结果 耗时
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)全绿。

codex and others added 7 commits October 28, 2026 15:03
- 修复失败用例: 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>
@LC044
LC044 force-pushed the nightly/test-watch-20261027 branch from 556b6da to 63921e0 Compare October 28, 2026 13:45
codex added 2 commits October 28, 2026 22:19
- 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>
@LC044

LC044 commented Oct 28, 2026

Copy link
Copy Markdown
Owner Author

第 5 轮(trailsnap-4)测试结果 — 2026-10-28

接手上一轮被中断的 7 个未跟踪测试文件,跑通后补齐盲区并修掉 CI 红灯。

本地

  • 完整 E2E(-Layer e2e -Level full):429 passed / 4 skipped / 0 failed(exit 0,12.9 分钟)
  • 后端 unit 全量:exit 0(4312 passed / 39 skipped)
  • AI unit 全量:exit 0
  • 新增测试定向重跑:93 passed(server)/ 16 passed(ai)

新增覆盖(7 个模块 / 116 个用例)

  • test_nightly_portable_conversion_happy_20261028.py(5)— app/utils/portable_conversion.py
    的 convert_to_portable 主体:连续 4 轮的最大覆盖率缺口(47%,153 miss)终于被覆盖。
  • test_nightly_album_p0_db_timeline_gaps_20261028.py(13)— app/service/agent/album_p0.py
  • test_nightly_crud_photo_recycle_lifecycle_20261028.py(17)— app/crud/photo.py 回收站生命周期
  • test_nightly_memory_story_merge_gaps_20261028.py(14)— app/service/memory.py AI 故事生成/合并
  • test_nightly_settings_filter_task_gaps_20261028.py(11)— app/api/settings.py 过滤任务
  • test_nightly_storage_error_paths_20261028.py(24)— app/service/storage.py 错误路径
  • test_nightly_ai_ticket_parser_datetime2_gaps_20261028.py(16)— package/ai 车票日期/时间兜底

修复(A 类,14 个用例)

  1. tasks.payload 列缺失、桩掉了 _prepare_desktop_database 的路径登记、三处断言与真实契约不符
    → test_nightly_portable_conversion_happy_20261028.py
  2. patch 打在 ConfigManager 类上,被 test_gallery_service.py:195 永久替换的单例实例属性遮蔽
    → test_nightly_memory_story_merge_gaps_20261028.py 改为 patch 实例
  3. 新用例泄漏 TS_DESKTOP* / TS_DATA_DIR,把整个会话的照片路径指到临时图库
    → 夹具快照并还原 os.environ
  4. os.path.isabs 的跨平台假设 → 绝对路径参数按 os.name 选择

环境(C=1):本机 Docker Desktop 起不来(docker-desktop WSL 发行版停止),
PostgreSQL(5532) 拉不起来,本地 E2E 改用 SQLite 跑(tests/.env.test 未改),
结果与 postgres 基线一致;CI 仍在 docker + postgres 下跑。

CI:3 次推送,63921e02 红 → b8a81cb3 红 → 691f7ed1 全绿。

报告:tests/artifacts/nightly/2026-10-28/summary-r5-trailsnap-4.md

@LC044
LC044 merged commit 4f0612c into master Oct 28, 2026
21 checks passed
@LC044
LC044 deleted the nightly/test-watch-20261027 branch October 28, 2026 15:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

codex-automation PRs opened by codex automation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants