Commit Graph

805 Commits

Author SHA1 Message Date
huangzd1997 cf83752338 task-132: /result 成功确认时机契约(四模块 200+success=true 必在落库后、失败不成功、重试安全)+ 8 条守门测试 2026-09-02 04:44:21 +08:00
huangzd1997 c60ad48be5 task-131: collectdata 事务收缩契约固化(/result 锁内单条写无长事务 + 响应 DTO 写后组装)+ 8 条守门测试 2026-09-02 04:37:14 +08:00
huangzd1997 29ddf5c780 task-130: publish 事务收缩契约固化(prepare 外置/短事务落库/提交后清理已符合 spec 07)+ 8 条守门测试 2026-09-02 04:25:14 +08:00
huangzd1997 5e71e1bb3d task-129: shopdatacrawl 事务收缩(/result 无长事务契约固化 + deleteTask 纯计算抽静态纯函数)+ 8 条边界测试 2026-09-02 04:15:44 +08:00
huangzd1997 ecc62f095b task-128: appearancepatent 事务收缩(flatten/序列化/存储/哈希纯计算抽 prepareSubmittedChunk 移出事务,双事务路径不变)+ 8 条边界测试 2026-09-02 03:54:29 +08:00
huangzd1997 28f61eb70d task-127: similarasin 临时文件清理时机契约固化(提交后清理/回滚不清理/异常吞掉/可重试/幂等)+ 8 条守门测试 2026-09-02 03:44:38 +08:00
huangzd1997 ef4ea8d24b task-126: similarasin DTO 组装位置契约固化(审计结论:/result 无响应 DTO、可移出组装已在事务外、落库行组装顺序不变)+ 8 条守门测试 2026-09-02 03:39:54 +08:00
huangzd1997 79b3efd365 task-125: similarasin /result 纯计算移出事务(payload 哈希在 prepare 阶段预计算,落库直接引用)+ 9 条事务边界守门测试 2026-09-02 03:34:15 +08:00
huangzd1997 56afee0386 task-124: @Transactional 方法审计清单(147 方法/30 模块扫描器 + 13 条测试 + 报告快照,不改生产代码) 2026-09-02 03:24:23 +08:00
huangzd1997 c8250e5320 task-123: dead-code-cleanup diff 守卫仅校验前端提交(后端提交不再误报越界) 2026-09-02 03:20:44 +08:00
huangzd1997 793bd4f9c8 task-123: 性能基准堆采样前先 GC,消除全量套件下残留垃圾导致的 1GB 边界 flaky 2026-09-02 03:20:44 +08:00
huangzd1997 445b7780c5 task-122: N+1 批量化修复(claim/stuck-reset/stale-check 逐行 selectById 改 selectBatchIds 批量回读 + Map 装配,行为等价) 2026-09-02 03:13:05 +08:00
huangzd1997 29625f703c task-121: N+1 扫描审计(循环内单查扫描器 + 10 条测试 + 报告快照,不改生产代码) 2026-09-02 02:40:16 +08:00
huangzd1997 5f4fcad2ef 修复双实例 owner-scoped 结果文件 job 被非归属实例误杀
Build Backend JAR / build (push) Has been cancelled
线上现象:货源查询任务 26402/26400(归属 server-121)在归属机正常推进,
却被 server-110 判为「结果生成失败」,错误为「该任务已绑定到另一台服务实例处理」。

两个缺陷叠加:
1. 两台实例共用一个 RocketMQ consumer group,dispatch 消息被轮询投递;
   worker 对"PENDING + owner 不匹配"的 job 选择本地抢跑,模块层
   ensureTaskOwnedByCurrentInstance 直接抛 TaskOwnerMismatchException,
   异常落进通用 catch 被当成生成失败,5 次抢跑即耗尽 retryCount 并终态失败。
2. runPendingJobs 双重 claim:claimRunnableJobsForOwner 已把 job 翻成 RUNNING,
   随后又走 claimRunning(条件 PENDING/FAILED)必然失败 → job 被静默丢弃,
   归属机的定时兜底从未真正生效。

修复:
- worker:非归属实例一律跳过 owner-scoped job;抽出 processClaimed 供已持有
  claim 的调用方使用;processInternal 单独捕获 TaskOwnerMismatchException,
  只 deferRunning 退回 PENDING,不计入重试。
- TaskFileJobLocalDispatcher 新增 dispatchClaimed。
- dispatch 事件带上 owner,coordinator 按归属路由:本机 owner 直接本地派发不发 MQ,
  他机 owner 不发不跑交由归属机轮询接手,owner 为空维持原有 MQ 行为。
- 新增 owner 路由回归测试两组,回滚配合"本地抢跑"的旧断言。

同时提交此前工作区内已随 JAR 上线的 backend-java 改动:SimilarAsin 解析载荷
groups 内嵌 items(Python 旧链路兼容)与 chunk 类型不匹配跳过、
PermissionMenuSchemaInitializer 与 V103 两级菜单分组迁移、相关测试。
2026-09-01 21:07:25 +08:00
huangzd1997 55517f996b task-120: 大页数据性能回归 + 恢复 similarasin 测试入库
性能回归(SimilarAsinTaskServicePerf500Test,8/8 绿):
- test_perf_light_200 原以墙钟毫秒比较 light 与 batch(assertTrue
  lightMs < batchMs)。两条路径都跑纯内存 stub,耗时在十几毫秒量级,
  JIT/GC/线程调度抖动远大于真实差值,本机实测 light 14ms / batch 13ms
  直接翻红。改为确定性口径:light 结果明细查询数 == 0(batch ≥ 1)、
  light 总查询数 < batch 总查询数、batch 条目携带任务明细对象而 light
  只有白名单字段;墙钟仅保留单侧上界 1s(N+1 退化会放大到秒级从而失败)。
  连续 3 次独立运行稳定通过。
- 类注释同步移除“已知 flaky,隔离重跑即接受”的说明。

恢复测试入库:
- fa5a59e(task-116) 把 similarasin 测试目录整体从 git 删除,并加了
  .gitignore 规则 *.broken/,磁盘上目录改名 similarasin.broken。
  但包声明仍是 com.nanri.aiimage.modules.similarasin.*,javac 照常编译,
  这 40 个测试文件一直在参与构建、并且是 mvn test 的门禁的一部分——
  等于脱离版本控制却仍在 gate 构建。
- 目录改回 similarasin/(现在与包声明一致),移除 *.broken/ 忽略规则,
  40 个测试文件重新入库。mvn test-compile 退出码 0。
2026-09-01 13:45:34 +08:00
huangzd1997 f18d488cea 查询ASIN/最低价ASIN:精简新增弹窗
Build Backend JAR / build (push) Has been cancelled
- 国家由多选下拉改为单选,一次录入一个站点的 ASIN
- 店铺名改为按分组联动的下拉,移除带分页表格的「选择店铺」二级弹窗
- 表单压成两行(分组/店铺名/国家 + ASIN[/最低价]),按钮文案改为「保存」
- 保存成功后保留分组/店铺/国家,仅清空 ASIN 并聚焦,便于连续录入
- 清理随之失效的死代码:选择店铺弹窗 JS、按国家渲染输入框的 render/collect
  函数、.field-with-action/.skip-price-entry 等无引用 CSS
- admin.js 版本号改为 asin-create-v4,避免新 HTML 命中旧 JS 缓存

提交报文格式不变(countries:[code] + asin_mappings:{code:asin}),后端无需改动
2026-09-01 13:39:50 +08:00
huangzd1997 ac2b15d72f 去重数据汇总:按钮文案改为新增导入/删除导入
Build Backend JAR / build (push) Has been cancelled
2026-09-01 13:01:50 +08:00
huangzd1997 fa5a59e5cd task-116: 后台管理新增/导入表单弹窗化 + 分组管理独立菜单与UI优化 + 轻量进度端点
Build Backend JAR / build (push) Has been cancelled
- 后台管理页(admin)所有面板的新增/导入表单改为弹窗操作,原有字段 ID 全部保留、提交逻辑不变;导入删除入口不再触发二次确认拦截
- 分组管理升级为独立菜单(V102 + schema initializer),移除 5 个面板内的管理分组按钮;分组列表改为蓝白主题、增加权限分组横幅
- Python 侧 group-manage 权限守卫(_ensure_backend_menu_access 补充 group-manage)
- 引入 V101(biz_task_file_job 复合索引)+ 新增 TaskProgressLight/TaskFileJob 轻量端点与进度聚合作
- 前端 progress-light / page-separated-loads / dispatch-guard 共享模块及单元测试
2026-09-01 12:54:13 +08:00
huangzd1997 759f0b15d8 task-101: 上传/解析/入队三道前端拦截,阻止坏数据卡死 Python 自动化
Build Backend JAR / build (push) Has been cancelled
新增 shared/dispatch-guard.ts(纯 TS 校验,可单测)与 dispatch-guard-ui.ts
(ElMessageBox 弹窗层),在数据流的三个位置设闸:

- 选文件:空选择、非 xlsx/xls/csv、空路径直接拦;重复文件弹确认
- 解析结果:taskId 非法、totalRows 为 0、整批行被丢弃、需要分组却无分组直接拦;
  部分行被丢弃弹确认后才允许推送
- 入队前:结构不符、必填字段缺失、items/groups/country_codes 为空数组、
  行数页数为 0、JSON 不安全值(NaN/Infinity/BigInt/循环引用/数组洞)

覆盖 11 个推 Python 队列的 Tab 与 dedupe/split/convert 三个纯 Java Tab。
闸位按 Tab 挑选以免留下孤儿后端状态:collect-data 校验前置到
activateCollectDataTask 之前(任务保持 PENDING 无需回滚)、product-risk 的国家
检查提到建任务之前;已建任务后才拦下的复用各 Tab 原有失败补偿路径。

两处边界:对象属性 undefined 放行(taskNo 这类可选字段是惯用写法),只拦数组
元素 undefined 与数组洞;price-track 的 asin_rows_by_country 仅在 mode=asin
时要求非空,status 模式下 loadAsinRowsForAppClient 本就返回 {}。

顺带修复 similar-asin / appearance-patent 的 selectFiles 缺少 try/catch,
上传失败会残留上一批文件与解析结果。

测试:tests/dispatch-guard.test.ts 新增 37 个 test_task_101_* 用例。
2026-09-01 12:53:12 +08:00
huangzd1997 e2607ab723 task-98: 移除 similar-asin/appearance-patent 模块 Coze,状态机与共享组件改名 LLM
Build Backend JAR / build (push) Has been cancelled
- similarasin/appearancepatent 模块全部 Coze 工作流调用改走 direct-LLM(已确认唯一运行路径)
- 共享组件改名:CozeTaskQueueGate→TaskQueueGate、CozeGroupResultPropagator→GroupResultPropagator
- 状态机改名:biz_task_scope_state 的 coze_* 列→llm_*、stateJson coze 键→llm(V100 迁移已应用生产)
- 删除 biz_coze_credential 表、CozeCredential* 类、SimilarAsinCozeClient、AppearancePatentCozeClient→LlmClient
- 前端 brand 页 Coze 文案→LLM;Python 后端删除 cozepy 依赖与死配置
- 修复 TaskResultFileJobWorker 启动失败:TaskFileJobConfig 注册 ResultFileJobHandlerRegistry 与 13 个 handler bean(含 validateCoverage 启动校验)
2026-09-01 02:20:50 +08:00
huangzd1997 0cc7380205 task-47: 轮询 baseline 统计补强测试 2026-08-31 22:47:47 +08:00
huangzd1997 969c5a2a67 task-46: 双页面同 key 行为记录测试
只读断言现状(不改实现):同 storageKey 双页面各自独立轮询集合、
互不实时同步、storage 写互相覆盖、dispose 一方不影响另一方、
不同 key 完全隔离。共 8 个测试。
2026-08-31 21:17:59 +08:00
huangzd1997 5314fa7745 task-45: 轮询与历史刷新分离测试
轮询不触发历史接口、终态独立触发一次历史刷新、无 refreshHistory
时流程照常、TTL 缓存合并历史请求、force 跳过缓存、多页面并行
不阻塞、历史刷新失败恢复后轮询照常。共 8 个测试。
2026-08-31 21:14:47 +08:00
huangzd1997 a9bc9ff52e task-44: 轻量端点切换能力测试
fetchProgress 切轻量端点(taskId/status/fileStatus)后请求走轻量
实现;轻量结构解析、默认仍走旧端点、缺可选字段容错、终态判定、
缓存写入、onUpdate 收到、新旧结构同轮兼容。共 8 个测试。
2026-08-31 21:12:33 +08:00
huangzd1997 6bf87aff13 task-43: progressCache TTL 惰性清理边界测试
命中返回、过期读取即清理、超上限淘汰最旧、空缓存 get undefined、
同 key 覆盖并刷新 TTL、TTL 边界立即过期、惰性清理不主动扫描、
轮询周期内缓存可用。共 8 个测试。
2026-08-31 21:07:43 +08:00
huangzd1997 9af7a5170a task-42: 退避恢复测试
失败→退避序列→成功→恢复正常间隔;连续失败计数归零后从
attempt 0 重新起;多次失败成功循环;部分成功算成功;前台
刷新下恢复;长失败链后恢复。共 8 个测试。
2026-08-31 21:06:26 +08:00
huangzd1997 50518b5420 task-41: storage 恢复与清理测试
恢复过滤非正数/非数字、空列表清除过期 key、终态同步 storage、
写失败不抛、坏 JSON 容错、恢复即轮询、无 key 不操作。修复恢复
出空列表时遗留 key 未清理的问题。共 8 个测试。
2026-08-31 21:02:52 +08:00
huangzd1997 d33316f093 task-40: 页面隐藏降频与可见恢复测试
隐藏 60s/可见 10s 间隔自适应、切回可见立即刷新、开关关闭不刷
新、延迟刷新生效、隐藏仍轮询、事件绑定/解绑、隐藏不触发即时
刷新。修复 scheduleNextDelayed 被轮询定时器阻塞导致延迟前台刷
新永不触发的缺陷。共 8 个测试。
2026-08-31 20:58:05 +08:00
huangzd1997 93943bb51a task-39: in-flight 合并测试补强
in-flight 期间不叠加 timer、不并发请求;完成按退避续轮;
重复 ensure(true) 不叠加;add 期间请求含新任务;失败释放锁。
共 8 个测试。
2026-08-31 20:54:35 +08:00
huangzd1997 89fff86333 task-38: 同轮多任务终态分别回调测试
同一轮响应多任务同时终态:各自回调带各自 detail/status、
按响应顺序(非注册顺序)、一个抛错不影响其他、全部移除、
异步回调逐个 await。共 8 个测试。
2026-08-31 20:52:02 +08:00
huangzd1997 01e00f4b98 task-37: onTerminal 抛错语义测试
覆盖 onTerminal 回调抛错时的语义:不打断轮询、任务照常移除、
可重新 add 恢复、不影响同轮其他终态、抛错被吞掉不进 onError、
不自动重试、恢复后重新触发。共 8 个测试。
2026-08-31 20:45:56 +08:00
huangzd1997 9e8ecb57e5 task-36: 终态任务仅一次 onTerminal
8 个测试固化 markTerminal 语义:同一任务终态只回调一次(幂等)、
终态任务从轮询集合移除、重复响应不回调、重新 add 后可再触发、
多任务各自回调、markTerminal 先于移除、终态后 localStorage 同步
清理、停止轮询不触发回调。
2026-08-31 20:36:18 +08:00
huangzd1997 745e3fe2c4 task-35: 未知状态不判终态固化
8 个测试固化未知状态语义:PENDING/SYNCING/空串/undefined 均为
非终态(FSM 层走重试语义、循环层不触发 onTerminal、任务保留在
轮询集合);同批终态+未知分开处理;自定义 isTerminal 生效;
小写值不误判。
2026-08-31 20:35:10 +08:00
huangzd1997 e16aa63974 task-34: HTTP 4xx/5xx 分类
8 个测试固化 HTTP 错误语义:4xx/5xx 记 onError 并进入退避、
不触发 onTerminal(5xx 不可解析明细时不误判 FAILED)、不清空已有
状态、恢复后继续轮询且部分 items 照常处理、未知状态不受影响。

行为由 http 层抛错与既有 catch 路径实现,本次为验证型测试。
2026-08-31 20:31:48 +08:00
huangzd1997 dd0a32e89a task-33: 网络错误走退避且不触发终态
8 个测试固化网络错误语义:fetch 拒绝不触发 onTerminal、不修改
taskStatuses、任务集合不丢失、onError 上报、失败后不立即自动重试
(退避)、恢复后继续轮询并正常触发终态。

行为由任务 31 的失败计数与既有 catch 路径实现,本次为验证型测试。
2026-08-31 20:30:45 +08:00
huangzd1997 3e45aa2a91 task-32: 退避封顶
8 个测试固化退避封顶语义:达到 maxMs 后保持恒定(含低 maxMs、
高 factor 提前封顶)、成功后从基数重新起算、恰等于 maxMs 不溢出、
循环内失败计数映射退避间隔的集成、非法 maxMs 配置拒绝。

行为由任务 29/30 的 factor 与 maxMs 配置已实现,本次为验证型测试。
2026-08-31 20:27:29 +08:00
huangzd1997 ab55b20edd task-31: 连续失败计数
useTaskProgressLoop 轮询循环维护连续失败计数:refreshOnce 成功
(收到响应)归零;失败递增(封顶 100);onError 回调增加第二参数
attempt(0 起),供上层决定退避策略;dispose 后不再上报。

同时把该组合式函数内部 @/ 别名 import 改为相对路径(带 .ts 扩展),
使其可在 node --test 下直接运行(此前无任何测试覆盖该文件)。
新增 8 个测试:递增、成功后归零、收到响应归零、onError 带 attempt、
初始 0、交错、封顶、dispose 清理。
2026-08-31 20:26:31 +08:00
huangzd1997 9e224929fb task-30: getTaskPollBackoffMs 递增序列
getTaskPollBackoffMs 签名改为 attempt 可选(省略视为 0,向后兼容),
序列 500×factor^attempt、封顶 maxMs 行为由任务 29 的 factor 配置驱动。
新增 8 个测试:attempt0/1/2 值、序列单调、封顶、省略参数默认、
负 attempt 当 0、自定义 factor。
2026-08-31 20:16:30 +08:00
huangzd1997 37eabcbb2e task-29: 退避配置项(MaxMs/Factor)
task-progress-config.ts 新增 getTaskPollBackoffMaxMs()(默认 10000,
由 5000 提升)与 getTaskPollBackoffFactor()(默认 2,<1 钳制为 1);
configureTaskPolling 支持 backoffFactor;getTaskPollBackoffMs 改用
base × factor^attempt 计算。

既有 task-086 边界测试中封顶 5000 的快照随新默认更新为 10000。
新增 8 个测试:max/factor 默认、可覆盖、非正钳制、factor 下限、
配置隔离、默认值快照。
2026-08-31 20:14:43 +08:00
huangzd1997 71606e9fe5 task-28: 死代码清理
删除拆分后失去引用的 API 残留文件:
- src/shared/api/call.ts(已由 http.ts 取代)
- src/shared/api/download.ts(已由 download-url.ts 取代)
- src/shared/api/status.ts(页面内已有本地实现)
及其孤儿测试 tests/call.test.ts / call-abort.test.ts / download.test.ts / status.test.ts。
endpoints/url/user 仍被模块文件引用,保留。

新增 8 个验证测试(dead-code-cleanup.test.ts):无重复导出、
vue-tsc 零错误、全量测试绿、无调试日志、无残留函数体、
16+ HTML 入口存在、build 产物齐全、提交变更仅限 frontend-vue。
2026-08-31 20:11:49 +08:00
huangzd1997 3fe8d5d05c task-27: api-field-compat 高频响应 schema
新增 src/shared/api-field-schemas.ts:task 核心字段、result 文件阶段
字段、task-result 组合 schema 注册表(带版本号);12 个业务模块
注册同一 task-result schema;getApiFieldSchema()/createModuleFieldChecker()
供契约测试与联调前跑字段漂移检查。

10 个测试:schema 必填/结果字段声明、checker 合法/缺必填/类型不符/
批量、模块注册齐全、版本标记、未知模块抛错。
2026-08-31 20:07:02 +08:00
huangzd1997 e896e0bef4 task-26: 模块 API 快照契约测试基建
新增集中式 assertApiCall() helper(tests/helpers/api-snapshot.ts):
断言 url/method/params/data 快照,params/data 白名单外字段报错,
失败信息含实际与期望 URL 上下文;isApiModule() 覆盖 16 个已拆模块。

8 个测试:helper url/method/params/body、all_modules_covered、
fail_message、allowlist、regression_guard。
2026-08-31 20:05:53 +08:00
huangzd1997 f177a15105 task-25: applyFilePhaseDefaults 兼容旧 Java 响应的文件阶段字段默认值 2026-08-31 20:01:52 +08:00
huangzd1997 eaf457c6c0 task-24: java-modules.ts 改为纯 re-export 聚合器,upload helpers 移至 upload.ts 2026-08-31 20:00:45 +08:00
huangzd1997 21c92afa7a task-23: 拆分 image-video / brand / permission / digital-human 模块 API 至 types/modules/,旧文件转 re-export 存根 2026-08-31 19:57:38 +08:00
huangzd1997 8f119198fd task-22: 拆分 collect-data 模块 API 至 types/modules/collect-data.ts,java-modules.ts re-export 2026-08-31 19:50:53 +08:00
huangzd1997 79e3513056 task-21: 拆分 withdraw / patrol-delete 模块 API 至 types/modules/withdraw.ts,java-modules.ts re-export 2026-08-31 19:48:49 +08:00
huangzd1997 71b482df6d task-20: 拆分 shop-data-crawl / query-asin 模块 API 至 types/modules/query-asin.ts,java-modules.ts re-export 2026-08-31 19:45:59 +08:00
huangzd1997 be02833b11 task-19: 拆分 shop-match / product-risk 模块 API 至 types/modules/shop-match.ts,java-modules.ts re-export
- product-risk 15 函数 + shop-match 17 函数 + 全套类型(含 ShopMatch 对 ProductRisk 的 type alias)
- 保留模块的 PatrolDelete/QueryAsin/Withdraw alias 通过 import type 兜底引用
- QueryAsinCountryAsins 内联定义避免跨模块循环依赖
- 10 个测试:双模块 CRUD/preference/match/task 系列/progressBatch 双端/dashboard/skip-asins/download/export compat
2026-08-31 19:42:18 +08:00
huangzd1997 173ea3b074 task-18: 拆分 price-track 模块 API 至 types/modules/price-track.ts,java-modules.ts re-export
- candidates/preference/matchShops/createTask/tasksBatch/progressBatch/loopRun 系列/skipAsin 系列/dispatchFailed/pendingShopResult/dashboard/history/delete/download 共 23 函数
- price-track 全套类型(含 LoopRun/ExecutionMode/SkipPriceAsin 类型)随模块迁移
- 12 个测试:CRUD/preference/match/create/batch/loopRun/progressBatch/skipAsin 系列/dashboard/download/unwrap/export compat
2026-08-31 19:39:00 +08:00