feat: complete CreatorHub gateway review fixes
This commit is contained in:
@@ -15,7 +15,8 @@
|
||||
React ── /api/* (Basic Auth) ──> control-plane
|
||||
├─ /v1/browsers (Bearer token) ──> docker-gateway ──> docker.sock
|
||||
│ └─> browser container
|
||||
└─ 账号/环境/任务等持久记录 ──> PostgreSQL
|
||||
├─ /v1/browsers/.../douyin/events (Bearer token) ──> docker-gateway ──> browser event stream
|
||||
└─ 账号/环境/任务/互动事件持久记录 ──> PostgreSQL
|
||||
```
|
||||
|
||||
控制面是唯一事实源:网关不持有镜像清单和业务规则,镜像引用、启动命令和卷名均随请求下发。
|
||||
@@ -66,7 +67,7 @@ React ── /api/* (Basic Auth) ──> control-plane
|
||||
|
||||
草稿经 `POST /api/phase-a/confirmations` 显式确认后才可投递到 `/api/phase-a/tasks`。任务由幂等键去重;`POST /api/phase-a/mock/execute` 使用 `FOR UPDATE SKIP LOCKED` 领取一分钟租约,执行前统一核对账号、草稿和确认版本。缺少确认或版本不一致会进入 `needs_confirmation`,暂停账号或 Mock 策略结果会进入 `policy_hold`,不确定结果与过期租约进入 `needs_confirmation`;这些状态都不会自动重试。`GET /api/phase-a/audit` 只导出账号、确认版本、尝试和结果等非秘密证据。
|
||||
|
||||
启动时控制面先应用 Phase A v1,再由 Hub runner 顺序应用 v2 至 v14;每一步都在事务和 advisory lock 下前向执行。v3 保留旧表、列和历史记录,旧账号回填为 `platform=mock` 并暂停,仅账号 ID 与环境 alias 相同的记录自动建立 binding;v4 追加环境动作审计字段与索引,v5 清理持久 fingerprint 中的旧代理字段,v6 增加可重试的 runtime cleanup 状态,v7 为 runtime lease 增加 binding version 并回填可确定的既有记录,v8 至 v10 补齐 cleanup/runtime 的不可变 generation 与兼容约束,v11、v12 增加任务恢复状态并修复兼容约束,v13 增加账号名称和 TAGS;v14 仅前向修复旧 PR v13 的空数据 schema。若旧 v13 已产生空引用或明文 Cookies,v14 会在删除前阻断启动,必须先将凭据迁入 provider。其余记录等待显式绑定。本阶段不提供破坏性自动回滚。
|
||||
启动时控制面先应用 Phase A v1,再由 Hub runner 顺序应用 v2 至 v14;CreatorHub 业务迁移继续顺序应用至 v26(竞品同步 lease token、事件消息正文);每一步都在事务和 advisory lock 下前向执行。v3 保留旧表、列和历史记录,旧账号回填为 `platform=mock` 并暂停,仅账号 ID 与环境 alias 相同的记录自动建立 binding;v4 追加环境动作审计字段与索引,v5 清理持久 fingerprint 中的旧代理字段,v6 增加可重试的 runtime cleanup 状态,v7 为 runtime lease 增加 binding version 并回填可确定的既有记录,v8 至 v10 补齐 cleanup/runtime 的不可变 generation 与兼容约束,v11、v12 增加任务恢复状态并修复兼容约束,v13 增加账号名称和 TAGS;v14 仅前向修复旧 PR v13 的空数据 schema。若旧 v13 已产生空引用或明文 Cookies,v14 会在删除前阻断启动,必须先将凭据迁入 provider。其余记录等待显式绑定。本阶段不提供破坏性自动回滚。
|
||||
|
||||
`POST /api/network-exits` 只接受协议、主机、端口、已有 `credential_reference: {id}` 和预期出口身份;新出口为 `unchecked`,由 `POST /api/network-exits/:id/check` 经实际代理链路变为 `healthy` 或 `unhealthy`,`disable` 不可被检查重新启用。credential reference 的 `reference_key` 不出现在 API、日志或审计中;OS Keyring/Secret Manager bridge 在控制面进程启动前注入 `CREATORHUB_CREDENTIAL_<SHA256(reference_key)>`(大写十六进制),值为请求期解析的 `username:password`,控制面不持久化解析值。
|
||||
|
||||
@@ -74,12 +75,12 @@ React ── /api/* (Basic Auth) ──> control-plane
|
||||
|
||||
解析后的出口凭据只存在于控制面单次请求和网关内存转发器中;Docker inspect、容器环境、标签、挂载、`Config.Cmd` 与进程参数只包含 `docker-gateway` 的无凭据本地代理地址。网关内存代理以 alias、binding version 和 exit ID 共同标识 generation;生命周期操作按 alias 串行,重启恢复或重建必须重新核对该 generation,旧出口代理不能被新容器复用。
|
||||
|
||||
控制面后台每 20 秒调和网关([runtimeLeaseHeartbeat](../../cmd/control-plane/main.go)),续租 running runtime、释放 stopped/missing runtime;列表/详情读取不触发调和,过期 lease 也会在绑定事务中回收。控制面用 PostgreSQL advisory transaction lock 按 alias 协调多副本;每个 Store 最多允许 5 个锁会话占用 10 连接池的一半,为锁内数据库调用保留连接。create 同时锁定账号 ID、alias、请求出口和请求镜像;start、reconcile/rebuild、rebind 和 upgrade 锁定 alias、当前出口及当前镜像(upgrade 还锁目标镜像),拿锁后重新读取出口与镜像版本。账号 pause/resume/revoke 使用账号 ID 与当前 binding alias 加入同一协调域;镜像禁用、引用更新或账号状态变更不能穿透在途生命周期。
|
||||
控制面后台每 20 秒调和网关([runtimeLeaseHeartbeat](../../cmd/control-plane/main.go)),续租 running runtime、释放 stopped/missing runtime;列表/详情读取不触发调和,过期 lease 也会在绑定事务中回收。控制面还按账号调和抖音事件监听([creator_events.go](../../cmd/control-plane/creator_events.go)):每个已授权且有有效运行代际的账号只有一个监听,网关断连或代际改变时停止旧监听并退避重连;事件通知在控制面转换为互动事件后进入 `ProcessAutomaticEvent`,数据库的事件唯一键负责去重,写入结果不明不会由监听器重复发送。当前通知边界、平台事件游标/基线连续性和真实写操作仍需真机证据,不能把网关轮询队列视为平台监听验收。控制面用 PostgreSQL advisory transaction lock 按 alias 协调多副本;每个 Store 最多允许 5 个锁会话占用 10 连接池的一半,为锁内数据库调用保留连接。create 同时锁定账号 ID、alias、请求出口和请求镜像;start、reconcile/rebuild、rebind 和 upgrade 锁定 alias、当前出口及当前镜像(upgrade 还锁目标镜像),拿锁后重新读取出口与镜像版本。账号 pause/resume/revoke 使用账号 ID 与当前 binding alias 加入同一协调域;镜像禁用、引用更新或账号状态变更不能穿透在途生命周期。
|
||||
|
||||
非法 upgrade/rebind 目标在进入 advisory lock key 前按公开格式校验;审计仅保留环境原有的非秘密资源关联,并以 `upgrade_input_rejected` / `rebind_input_rejected` 写同一 operation ID 的 requested/finished 对。reconcile 恢复或重建后会重新读取 context,finished 事件关联实际激活的 runtime instance、binding version 与出口;后台释放 runtime 的成功或失败也写独立的 `reconcile` 审计对。
|
||||
|
||||
## 与新业务计划的边界
|
||||
|
||||
- 当前受限抖音读取仅允许自身身份与 `count=20/max_cursor=0` 首批作品,JSON 响应限制为 1 MiB,见 [douyin.go](../../cmd/docker-gateway/douyin.go)。这些是现状,不是竞品分页或媒体下载的完成证据;后续媒体按 plan01 C4 分步保存产物引用,不复用通用 JSON 响应承载二进制。
|
||||
- 当前账号凭据入口处理 Cookie;plan01 要求的可选登录密码应允许输入现有凭据保存流程,读取不回显、不进入日志,并非新增“禁止收密码”的接口限制。
|
||||
- 当前受限抖音读取仅允许自身身份与 `count=20/max_cursor=0` 首批作品,JSON 响应限制为 1 MiB,见 [douyin.py](../../cmd/docker_gateway/douyin.py)。竞品同步仍需外部平台证据;媒体通过 `POST /api/creator/works/:id/material/process` 下载到持久卷、用 FFmpeg 提取音轨,再调用显式配置的 `CREATOR_TRANSCRIPTION_BIN`。未配置转写入口时明确记为 failed,不接受手写 succeeded 或二进制塞入通用 JSON。
|
||||
- 当前账号凭据入口处理 Cookie;登录密码可按现有凭据保存流程保存,读取不回显、不进入日志,但绝不由系统自动注入或用于绕过人工登录。
|
||||
- 新业务平台监听、前端业务推送和现有后台运行租约是三件事;前两者要求见 plan01 A6,列表不主动探测的约定不禁止业务事件推送。现有生命周期/租约可能核验出口,不应误写成已完成 plan01 的手动代理管理目标。
|
||||
|
||||
+18
-5
@@ -1,6 +1,6 @@
|
||||
# CreatorHub 部署
|
||||
|
||||
本文档按 `main@1fbf126` 当前可运行代码说明单台 Linux 主机 Docker Compose 部署及旧阶段 A Mock 检查,不证明新产品功能已实现。[plan01](plan01.md) 是业务范围与验收依据,旧阶段 A 离线结果不等于 G0/G1,也不能替代抖音/小红书最终真机验收。
|
||||
本文档按 `feat/python-gateway-douyin` 当前代码说明单台 Linux 主机 Docker Compose 部署及离线检查,不证明新产品功能已实现。[plan01](plan01.md) 是业务范围与验收依据;离线结果不能替代抖音/小红书最终真机验收。
|
||||
|
||||
当前控制面仍使用单用户 HTTP Basic Auth(除 `/healthz` 外,包括静态页面),不提供 RBAC 或多租户隔离。开发目标不新增认证/访问限制,但本轮未删除现有代码或配置;以下变量仍须填写,不新增认证 profile。
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
- 当前用户可访问 Docker daemon;
|
||||
- 可访问镜像仓库(如 `git.ipao.vip`),并已完成登录(如仓库要求认证);镜像也可不在宿主机预拉取,网关会在缺失时按引用自动拉取;
|
||||
- `curl`、`jq`、`openssl` 和 GNU `stat`,用于启动与业务验证命令;
|
||||
- 若验证真实浏览器运行环境:Linux x86_64、一个可访问的固定 HTTP/HTTPS/SOCKS 出口,以及可被 Docker daemon 拉取的 `fingerprint-chromium` 镜像。
|
||||
- 若验证真实浏览器运行环境:Linux x86_64、一个可访问的固定 HTTP/HTTPS/SOCKS 出口,以及可被 Docker daemon 拉取的、以 immutable digest 固定的 `fingerprint-chromium` 镜像。镜像来源必须登记仓库地址、构建提交和 digest,禁止使用 `latest` 或未登记 tag;Xvfb/CDP 包装入口的可复现源码见 [`docker/browser-wrapper`](../docker/browser-wrapper/)。
|
||||
|
||||
在仓库根目录执行预检:
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
test -S /var/run/docker.sock
|
||||
docker info >/dev/null
|
||||
docker compose version
|
||||
: "${DOCKER_GID:?export DOCKER_GID=$(stat -c '%g' /var/run/docker.sock) in this shell}"
|
||||
: "${CONTROL_PLANE_USERNAME:?export CONTROL_PLANE_USERNAME in this shell}"
|
||||
: "${CONTROL_PLANE_PASSWORD:?export CONTROL_PLANE_PASSWORD in this shell}"
|
||||
: "${CREATORHUB_CREDENTIAL_MASTER_KEY:?export CREATORHUB_CREDENTIAL_MASTER_KEY in this shell}"
|
||||
@@ -54,6 +55,8 @@ docker compose config --quiet
|
||||
docker compose up --detach --build
|
||||
```
|
||||
|
||||
网关配置了 45 秒停止宽限期,并在收到 SIGTERM/SIGINT 时停止接收请求、排空有限期限内的在途请求,再关闭事件订阅和代理;本地测试覆盖该顺序,但部署验证仍须记录正常退出码、实际耗时和没有 SIGKILL,不能仅以“等待了 45 秒”证明优雅退出。
|
||||
|
||||
控制面启动时会连接 PostgreSQL,并在事务和 advisory lock 保护下自动执行前向迁移。迁移失败时控制面会退出,由 Compose 按 `restart: unless-stopped` 重启;先检查日志,不要删除数据卷。
|
||||
|
||||
### 首次配置
|
||||
@@ -61,7 +64,7 @@ docker compose up --detach --build
|
||||
服务起来后打开 <http://127.0.0.1:${CREATORHUB_PORT}>:
|
||||
|
||||
1. 「网关管理」页注册网关:名称如 `gw-main`,Endpoint `http://docker-gateway:8081`,令牌填 `GATEWAY_TOKEN` 的值(即 `openssl rand -hex 24` 生成的值)。
|
||||
2. 「镜像版本」页添加可用镜像,如版本 `148.0.7778.215`、引用 `git.ipao.vip/rogee/fingerprint-chromium:148.0.7778.215`(或 `@sha256:` 摘要引用)。
|
||||
2. 按 [`docker/browser-wrapper/README.md`](../docker/browser-wrapper/README.md) 用已登记 base digest 构建包装镜像,再在「镜像版本」页添加发布 digest。生产与验收必须填写 `git.ipao.vip/rogee/creatorhub-browser-wrapper@sha256:<已登记摘要>`;`148.0.7778.215` 只作为浏览器版本元数据,不能单独作为不可变引用。登记内容同时包含 base 镜像源仓库、base digest、构建提交、Dockerfile 路径和发布摘要。
|
||||
3. 「社媒账号」页先创建账号(默认暂停),再在「运行环境」选该账号、网关、镜像,填写中文名、小写别名及指纹参数。代理可选;指定代理须先手动检测为健康,留空是明确直连,不是失败回退。
|
||||
4. 创建得到停止态容器;在账号页恢复账号后回环境页显式启动。容器名 `creatorhub-browser-<别名>`,Profile 卷 `creatorhub-profile-<别名>`。回收只删除容器、保留环境/binding/Profile;完整契约见[架构说明](architecture/container-control.md)。当前直连 create/start 不代表 upgrade/rebind 已支持空出口。
|
||||
|
||||
@@ -133,7 +136,11 @@ api() {
|
||||
run_id="manual-$(date +%s)"
|
||||
gateway_name="gw-${run_id}"
|
||||
image_version="${IMAGE_VERSION:-148.0.7778.215}"
|
||||
image_ref="${IMAGE_REF:-git.ipao.vip/rogee/fingerprint-chromium:${image_version}}"
|
||||
: "${IMAGE_REF:?IMAGE_REF must be an immutable browser-wrapper @sha256 reference}"
|
||||
case "$IMAGE_REF" in
|
||||
*@sha256:*) image_ref="$IMAGE_REF" ;;
|
||||
*) echo "IMAGE_REF must contain @sha256:" >&2; exit 2 ;;
|
||||
esac
|
||||
exit_protocol="${PROXY_PROTOCOL:-http}"
|
||||
account_key="${run_id}-platform"
|
||||
env_alias="${run_id}-env"
|
||||
@@ -252,11 +259,15 @@ Compose 部署时通常只需设置以下宿主机变量:
|
||||
| 变量 | 默认值 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `CREATORHUB_PORT` | `8080` | 控制面宿主机端口,局域网可访问 |
|
||||
| `DOCKER_GID` | `999` | Docker socket 的宿主机组 ID;必须按实际值设置 |
|
||||
| `DOCKER_GID` | 无(必填) | Docker socket 的宿主机组 ID;必须按实际值设置 |
|
||||
| `GATEWAY_TOKEN` | `dev-creatorhub-gateway-token` | Compose 未提供变量时的默认值;本说明要求显式 export 随机值,并同步填入网关注册表单 |
|
||||
| `CONTROL_PLANE_USERNAME` | 无(必填) | 控制面唯一用户;不能包含冒号 |
|
||||
| `CONTROL_PLANE_PASSWORD` | 无(必填) | 控制面密码,至少 6 字节;使用随机值 |
|
||||
| `CREATORHUB_CREDENTIAL_MASTER_KEY` | 无(必填) | 32 字节 base64;由部署 Secret Manager/OS Keyring 持久注入,重启后必须保持一致 |
|
||||
| `BAILIAN_API_KEY` | 空(按需) | 已批准的生产 AI API key;为空时文本 AI 动作明确返回 unavailable,不使用 Mock |
|
||||
| `BAILIAN_BASE_URL` | 客户端默认值 | 无用户信息的 HTTP(S) 地址;供应商变更前需完成审批和脱敏样本验证 |
|
||||
| `CREATOR_MEDIA_DIR` | `/var/lib/creatorhub/materials` | 持久媒体目录;必须挂载持久卷,不能使用临时目录替代 |
|
||||
| `CREATOR_TRANSCRIPTION_BIN` | 空(按需) | 可执行的本地转写入口;为空时转写明确失败,不伪造 succeeded |
|
||||
|
||||
服务本身支持并校验以下环境变量;`compose.yaml` 会在控制面凭据缺失或为空时拒绝渲染。下表中的 Compose 默认值不由手工验证脚本隐式读取;手工验证沿用上文的显式 export 要求:
|
||||
|
||||
@@ -270,6 +281,8 @@ Compose 部署时通常只需设置以下宿主机变量:
|
||||
| `creator-hub` | `CONTROL_PLANE_PASSWORD` | 必填且至少 6 字节;不会写入日志或响应 |
|
||||
| `creator-hub` | `CREATORHUB_CREDENTIAL_MASTER_KEY` | 必填;解密独立凭据卷,不写入数据库、日志或响应 |
|
||||
| `creator-hub` | `CREATORHUB_CREDENTIAL_STORE_DIR` | 默认 `/var/lib/creatorhub/credentials`;必须为绝对路径且持久可写 |
|
||||
| `creator-hub` | `BAILIAN_API_KEY` | 可选;仅用于已批准的文本 AI,缺失时不回退 Mock |
|
||||
| `creator-hub` | `BAILIAN_BASE_URL` | 可选;HTTP(S) 供应商地址,禁止携带用户信息 |
|
||||
| `docker-gateway` | `LISTEN_ADDR` | 默认 `:8081` |
|
||||
| `docker-gateway` | `DOCKER_SOCKET` | 默认值和 Compose 挂载均固定为 `/var/run/docker.sock`;不能只覆盖环境变量 |
|
||||
| `docker-gateway` | `BROWSER_NETWORK` | `creatorhub_browser` |
|
||||
|
||||
+15
-15
@@ -2,7 +2,7 @@
|
||||
|
||||
> 版本:v1.2 · 2026-09-12
|
||||
> 状态:业务范围已逐项确认;本文是实现与验收依据,不代表功能已经完成。
|
||||
> 现状基线:`feat/plan01-implementation` 基于 `main@1fbf126`,已同步远程;本轮完成一批本地 G1.1/G1.2 实现与离线验证,未完成真实平台验收。
|
||||
> 现状基线:`feat/python-gateway-douyin` 基于 `origin/main@1fbf126`;当前分支已包含 Python gateway、事件边界/确认、动作结果证据、固定采集计划和工作台修正,并完成本地离线验证;真实平台验收仍单独记录。
|
||||
> 优先级:本需求高于现有实现及旧产品规划;遇到平台能力不足或新的业务歧义,必须向使用者确认,不得自行删减、替换或假装成功。
|
||||
|
||||
## 1. 目标、范围与完成定义
|
||||
@@ -42,11 +42,11 @@
|
||||
| 范围 | 已有基础 | 本需求需要补齐或改变 | 代码依据 |
|
||||
| --- | --- | --- | --- |
|
||||
| 页面入口 | 账号、任务、审计、环境、代理、镜像、网关等页面 | 竞品池、作品、素材仿写、评论线索、响应策略、私信会话尚无完整入口 | [页面路由](../web/src/main.jsx) |
|
||||
| 账号 | 平台账号 ID、标签、Cookie、暂停/恢复等 | 实名资料、登录用户名/密码、备注、人工业务状态、自动登录与大小号关系 | [账号页面](../web/src/AccountsPage.jsx)、[账号存储](../internal/phasea/store.go)、[账号接口](../cmd/control-plane/phasea.go) |
|
||||
| 账号 | 平台账号 ID、标签、Cookie、暂停/恢复等 | 实名资料、登录用户名/密码、备注、人工业务状态、人工登录与大小号关系 | [账号页面](../web/src/AccountsPage.jsx)、[账号存储](../internal/phasea/store.go)、[账号接口](../cmd/control-plane/phasea.go) |
|
||||
| 平台范围 | 登记项还包含公众号、快手 | 新业务仅承诺抖音、小红书;其他登记项不是业务能力验收结果,也不因此要求删除无关已有功能 | [账号页面](../web/src/AccountsPage.jsx) |
|
||||
| 作品读取 | 有抖音连接器、指标字段与测试 | 连接器只核验登录者自身、读取首批 20 条,未接成运行中的竞品采集链路;需目标账号解析、分页、保存、查询和定时更新 | [抖音连接器](../internal/douyin/connector.go)、[连接器测试](../internal/douyin/connector_test.go)、[网关读取限制](../cmd/docker-gateway/douyin.go) |
|
||||
| 作品读取 | 有抖音连接器、指标字段与测试 | 连接器只核验登录者自身、读取首批 20 条,未接成运行中的竞品采集链路;需目标账号解析、分页、保存、查询和定时更新 | [抖音连接器](../internal/douyin/connector.go)、[连接器测试](../internal/douyin/connector_test.go)、[网关读取限制](../cmd/docker_gateway/douyin.py) |
|
||||
| 指纹与环境 | 结构化指纹、独立 Profile、启动/停止/升级及代理接入 | 默认固定 seed 不是自动分配;需首次自动生成、地区匹配及稳定性验证 | [环境页面](../web/src/BrowsersPage.jsx)、[指纹参数](../internal/hub/fingerprint.go)、[环境存储](../internal/hub/environment.go) |
|
||||
| 代理 | 添加、列表、手动检测、停用、实际转发 | 补齐编辑、删除、重新启用及引用约束;不增加自动轮换 | [代理页面](../web/src/NetworkExitsPage.jsx)、[代理转发](../cmd/docker-gateway/proxy.go) |
|
||||
| 代理 | 添加、列表、手动检测、停用、实际转发 | 补齐编辑、删除、重新启用及引用约束;不增加自动轮换 | [代理页面](../web/src/NetworkExitsPage.jsx)、[代理转发](../cmd/docker_gateway/proxy.py) |
|
||||
| 任务与发送 | 有草稿确认、任务记录、Mock 执行 | 不能作为真实回复、私信、点赞、关注、转发成功的证据;需接通实际平台执行及结果核验 | [任务页面](../web/src/TasksPage.jsx)、[任务接口](../cmd/control-plane/phasea.go) |
|
||||
| 事件、线索、私信、AI | 未发现完整可运行链路 | 均需新增业务能力,不能把旧文档、类型定义或模拟返回记为已实现 | [页面路由](../web/src/main.jsx)、[抖音连接器](../internal/douyin/connector.go) |
|
||||
|
||||
@@ -134,15 +134,15 @@
|
||||
| 登录情况 | 独立展示已登录、需登录、登录失败/待人工处理等实际结果与时间,不推断处罚状态 |
|
||||
|
||||
- 支持账号资料新增、查看、编辑;必填平台及能区分账号的标识,已获得平台 UID 后检查身份重复和登录一致性,不通过改昵称掩盖冲突。
|
||||
- 登录密码允许由新增/编辑请求输入并进入现有凭据保存流程,账号资料仅关联凭据;读取只显示是否已配置,编辑空白不覆盖已有密码。当前接口只接收 Cookie,不代表密码能力已实现,也不能以“API 禁止接收密码”阻断本需求。
|
||||
- 登录密码允许由新增/编辑请求输入并进入现有凭据保存流程,账号资料仅关联凭据;读取只显示是否已配置,编辑空白不覆盖已有密码。密码仅供人工核对/维护,不由系统自动注入或登录。
|
||||
- 实名资料只做输入类型、长度等基本校验;不把人工记录包装成已核验身份,不要求用户为运行普通功能提交身份证证据。
|
||||
- 正常账号按实际登录及平台能力执行。**非正常账号暂停自动动作**;禁言账号禁止人工评论、私信及带文案转发;封禁、注销账号不参与采集和发送。已有数据仍可查看,人工登录/检查入口保留。
|
||||
- 账号恢复正常后需人工重新启用受影响策略,不补发暂停期间的历史互动。登录失败不擅自修改上述业务状态。
|
||||
|
||||
### A2. 登录
|
||||
|
||||
- 已存在有效登录时复用;未登录且提供用户名与密码时尝试自动登录,否则直接进入可见浏览器人工登录。
|
||||
- 自动登录失败显示真实原因:例如凭据错误、平台不支持该登录方式、验证码/扫码/设备确认、网络失败或页面变化;未知原因明确写“无法确认”,不能猜测。
|
||||
- 已存在有效登录时复用;未登录或会话失效时进入可见浏览器人工登录。系统不得自动注入用户名、密码、Cookie、验证码或绕过扫码/设备确认。
|
||||
- 人工登录失败显示真实原因:例如凭据错误、验证码/扫码/设备确认、网络失败或页面变化;未知原因明确写“无法确认”,不能猜测。
|
||||
- 失败后保留同一环境交用户人工处理,不循环尝试、不自动更换账号/代理/指纹,也不绕过验证码。
|
||||
- 登录后核对实际平台账号身份;与选定账号不一致时停止该账号任务并提示纠正,不能把别的账号登录结果保存为成功。
|
||||
|
||||
@@ -326,7 +326,7 @@
|
||||
| 编号 | 场景 | 必须观察到的结果 |
|
||||
| --- | --- | --- |
|
||||
| AC-A1 | 新增/修改资料,区分账号 UID、用户名、实名与业务状态 | 字段分别保存与显示;不伪称平台已实名;凭据不进入日志 |
|
||||
| AC-A2 | 有/无密码、有效登录、密码错误、验证码、身份不符 | 对应复用/自动尝试/人工登录;错误有原因,不循环尝试、不误认别的账号 |
|
||||
| AC-A2 | 有/无密码、有效登录、密码错误、验证码、身份不符 | 有效会话复用;失效后进入人工登录;错误有原因,不循环尝试、不误认别的账号 |
|
||||
| AC-A3 | 正常→禁言/封禁/注销→正常 | 执行限制符合 A1;已有数据可查;恢复后不擅自重启策略或补发历史互动 |
|
||||
| AC-A4 | 自关联、跨平台、重复归属、大小号循环、调整关系 | 非法关系被拒绝;变更停用受影响策略,不产生错误账号动作 |
|
||||
| AC-A5 | 四类大号收到的互动 | 评论、点赞、转发、关注均用真实事件证明;大号主动操作不误触发;无 UID/目标明确提示 |
|
||||
@@ -423,7 +423,7 @@
|
||||
后续代码变更遵循 [AGENTS.md](../AGENTS.md):
|
||||
|
||||
- 非平凡行为先写能在未实现时失败的最小回归测试,单元测试覆盖率至少 65%;尤其覆盖时间边界、并发冷却、监听重复、平台失败及人工/自动区别。
|
||||
- 后端通过 `go test ./...`、`go vet ./...`,并构建 `./cmd/control-plane`、`./cmd/docker-gateway`;并发、生命周期与共享状态变更运行 `go test -race ./...`;Compose 变更运行 `docker compose config --quiet`。
|
||||
- 控制面通过 `go test ./...`、`go vet ./...`,并构建 `./cmd/control-plane`;并发、生命周期与共享状态变更运行 `go test -race ./...`。Python gateway 通过 `python3 -m unittest discover -s cmd -p 'test_*.py'` 和覆盖率检查;Compose 变更运行 `docker compose config --quiet`。
|
||||
- 前端从 lockfile 安装、通过非交互测试及 `npm --prefix web run build`;关键页面覆盖加载、空数据、错误、禁用、确认/取消和重复点击。
|
||||
- 离线测试只证明本地逻辑,真实平台必须另外验收;请求返回 200、任务入队、模拟连接器成功均不能代替平台动作成功。
|
||||
|
||||
@@ -431,7 +431,7 @@
|
||||
|
||||
- 原始四模块需求均有对应细化、边界及验收项;逐项确认的业务选择无遗漏、无相反表述。
|
||||
- 区分现状、目标、已确认规则与待真实验证的外部条件,不将建议数值或 AI 质量写成未经确认的承诺。
|
||||
- 相对链接有效、验收编号唯一、Markdown 检查通过;没有功能代码改动,原有未提交修改保留。
|
||||
- 相对链接有效、验收编号唯一、Markdown 检查通过;代码修正与本文件的现状描述同步。
|
||||
|
||||
### 9.2 后续必须确认而不得猜测的事项
|
||||
|
||||
@@ -451,11 +451,11 @@
|
||||
| 无音轨/无语音必须重新决定;API 应禁止接收密码 | C4、A1、AC-U2、AC-U3 | 评审误判:已确认可继续;密码允许输入凭据流程,禁止回显/日志泄露,不阻断录入 |
|
||||
| 页面不够可执行,缺跳转与异常状态 | 7.4、8.5 | 紧凑页面地图与共用交互,优先现有页签/抽屉,无新通用系统 |
|
||||
| 去重/冷却、基线/断连、人工重试与并发边界不足 | A3、A5、A6、W3、7.2、AC-B1 至 AC-B3 | 可靠身份、永久最小去重、迟到核验、持久操作标识及同账号写协调 |
|
||||
| 时间/文本匹配不确定,媒体读取限制误当需求缺陷 | C2、W2、C4、AC-B4 至 AC-B6 | 固定 UTC 时长、原文匹配、分步产物引用;真实分页/媒体另验,不预设扩容或自动删素材 |
|
||||
| AI 输入未冻结、平台能力无证据模板、G1 过大 | 8.6、8.7、第 9 节 | G0 保留外部批准前置,矩阵全为待验证;G1 分段可验但不替代最终完整流程 |
|
||||
|
||||
### 9.4 当前本地实现状态
|
||||
|
||||
- 已有:CreatorHub 数据表与 API、账号/大小号关系约束、规则与线索判断、作品/一级评论分页采集边界、断点租约、来源关联、指数指标计划、抖音自有/竞品只读采集调度,以及工作台的错误/重试/确认状态。
|
||||
- 下一轮 TODO:真实平台事件监听与断连恢复;抖音实际点赞/评论/关注/转发/私信写入;素材真实下载/提音/转写;小红书采集与动作;生产 AI/转写供应商、模型、密钥与质量样本;以及对应的 G0/G1 真机证据。
|
||||
- 本地限制:仓库默认未配置 `CREATORHUB_POSTGRES_TEST_URL`;本轮使用运行中的 PostgreSQL 完成了 CreatorHub 数据行为、来源关联、指标、操作、消息和 checkpoint 租约集成测试,覆盖率为 65.6%。CI 或后续环境需提供专用测试库以重复该验证。
|
||||
| 时间/文本匹配不确定,媒体读取限制误当需求缺陷 | C2、W2、C4、AC-B4 至 AC-B6 | 固定 UTC 时长、原文匹配、分步产物引用;真实分页/媒体另验,不预设扩容或自动删素材 |
|
||||
| AI 输入未冻结、平台能力无证据模板、G1 过大 | 8.6、8.7、第 9 节 | G0 保留外部批准前置,矩阵全为待验证;G1 分段可验但不替代最终完整流程 |
|
||||
- 已有:CreatorHub 数据表与 API、账号/大小号关系约束、规则与线索判断、作品/一级评论分页采集边界、断点租约、来源关联、固定指标计划、抖音自有/竞品只读采集调度、Python gateway 事件 ACK/恢复边界、写操作证据分类、媒体下载/FFmpeg 提音轨/显式转写命令链,以及工作台的错误/确认状态。
|
||||
- 尚未完成或尚未取得外部证据:转写供应商质量样本、小红书同范围动作、真实平台事件连续性及每类写操作成功证据。未提供配置或平台能力时,接口应明确返回 unavailable/uncertain/failed,不以 Mock 通过代替。
|
||||
- 本地限制:数据库集成测试必须提供专用 PostgreSQL 地址并保留实际 executed/skipped 记录;Python gateway 生产覆盖率必须按排除测试代码的同次报告验收。CI 或后续环境需重复这些验证。
|
||||
|
||||
@@ -0,0 +1,477 @@
|
||||
# Python 网关分支审查与修正清单
|
||||
|
||||
日期:2026-09-13。状态:**审查与代码修正已完成;本地门禁已通过,真实平台及供应商证据仍按外部验收项单独保留。**
|
||||
|
||||
## 1. 范围、结论与证据边界
|
||||
|
||||
- 审查分支:`feat/python-gateway-douyin`。
|
||||
- 基线:`origin/main@1fbf126b21a7d6de45ade70121785075542363d9`。
|
||||
- 分支提交:`860ecaf7ead08bbd1af2c0d8af3604270da78095`,另包含当前未提交及未跟踪文件。不是只审查最近一次提交或 dirty diff。
|
||||
- 审查前已获取远程信息;远程主线是当前分支祖先,没有待合入的主线提交。当前分支没有配置 upstream。
|
||||
- 范围包含 58 个已跟踪差异文件,以及 Python 网关、事件监听、依赖锁文件等 11 个未跟踪新增文件;本报告是另行新增的交付物。
|
||||
- 四个独立只读审查分别覆盖网关迁移、平台动作与事件、数据业务与采集、前端与文档;汇总时合并了重复发现,并复核关键调用链。
|
||||
- **本轮修正已覆盖网关、事件、动作、采集计划、账号一致性和前端确定缺陷,并同步了部署/计划文档;未重置数据库、未提交 Git,也未进行真实平台写操作。** 下列“已修正”条目以当前代码与本地回归证据为准;真实平台、供应商和浏览器视觉证据仍不能由本地测试替代。
|
||||
|
||||
### 1.1 总结
|
||||
|
||||
最紧急的问题不是缺少几个页面,而是已有路径会产生错误结果:
|
||||
|
||||
1. **没有可靠的新旧事件边界**,此前未记录的旧通知可能在重连后触发自动发送。
|
||||
2. **并发创建可能误删成功容器**,超时的浏览器脚本也可能在锁释放后继续写入。
|
||||
3. **代理环境不能正常走通**:Go 漏传代理标识,HTTP/HTTPS 上游代理握手又存在协议解析错误。
|
||||
4. **常用页面不可用或串数据**:设置保存返回 400,工作台切换可崩溃,账号迟返请求可能覆盖另一账号资料。
|
||||
5. **人工发送链路不完整**:内部 ID 未转平台 ID、刷新后丢失原操作标识、失败与不明分类及证据不足。
|
||||
6. **采集计划、账号状态、租约和凭据更新存在数据一致性问题**。
|
||||
7. **媒体、生产 AI、私信接收/历史及页面推送仍有实际接线缺口**,不是仅等待真机验收。
|
||||
|
||||
### 1.2 优先级及状态口径
|
||||
|
||||
| 标记 | 含义 |
|
||||
| --- | --- |
|
||||
| P0 | 可能造成未获批准的真实平台写入;相应自动能力在修正并验证前不可视为可用 |
|
||||
| P1 | 阻断核心功能,或可能误删、串号、丢事件、错误判定;合并前应解决 |
|
||||
| P2 | 局部正确性、边界、错误反馈或可维护性问题;仍须列入修正,不默默排除 |
|
||||
| 确定缺陷 | 由当前代码及调用链可推导触发场景;除特别说明外,本轮没有运行复现 |
|
||||
| 实现缺口 | 缺少实际执行或界面接线,不能用模型、状态表或 Mock 结果替代 |
|
||||
| 待真机验证 | 代码之外的平台行为和运行证据不足,不据此断言平台支持或不支持 |
|
||||
|
||||
GW01—GW11、EV01—EV14、BE01—BE19、UI01—UI09 和 T01 的代码修正已完成并有本地回归;T02、DOC01—DOC06 已按当前证据修正。GAP01—GAP10 已补齐可由本地代码完成的执行、持久化和界面闭环,但真实平台、供应商质量、浏览器视觉及小红书能力仍需外部证据;GAP11 仍明确阻断。P0 的安全门仍有效:边界不明或结果不明不得自动写入或重试。
|
||||
|
||||
## 2. 网关生命周期与迁移缺陷
|
||||
|
||||
### GW01 · P1:并发创建可能删除另一个请求成功创建的容器
|
||||
|
||||
- **证据与影响:**`cmd/docker_gateway/gateway.py:170-177,241-252,322-366`。两个相同 alias、binding_version 的停止态创建请求都在锁外查到不存在;第二个获得锁后未重查,Docker create 返回 409,清理函数在 `created_id` 为空时按相同标签删除第一个请求的容器。持久卷不会因此删除,但已成功创建的容器会消失。旧 Go 实现在锁内再次检查 alias。
|
||||
- **修正:**锁内重查;明确的创建冲突不能进入“本次创建结果未知”的删除路径。所有清理必须证明资源属于本次操作。
|
||||
- **验收:**线程屏障制造该竞争;仅一个创建成功,另一个 409,成功容器没有收到 DELETE。
|
||||
|
||||
### GW02 · P1:HTTP/HTTPS 上游代理 CONNECT 残留响应头破坏 TLS
|
||||
|
||||
- **证据与影响:**`cmd/docker_gateway/proxy.py:366-380,477-491,511-523`。`_read_status` 只读状态行,剩余响应头和空行随后作为隧道数据转发给浏览器。上游返回 200 不代表 HTTPS 可以使用。旧 Go 使用完整 HTTP 响应解析。
|
||||
- **修正:**完整解析并消费响应头,限制大小和时间,保留响应头之后已经到达的真实隧道数据。优先采用成熟解析能力,不继续增加不完整手写分支。
|
||||
- **验收:**无附加头、多头、分片头、头与首个隧道包同批到达;浏览器收到的首字节必须是真实隧道数据。现有测试只检查 socket 和认证头,不足以证明转发正确。
|
||||
|
||||
### GW03 · P1:停止可被空闲连接无限阻塞,45 秒宽限不等于正常退出
|
||||
|
||||
- **证据与影响:**`cmd/docker_gateway/gateway.py:874-886,1018-1037,1427-1446`、`compose.yaml:52`。HTTP/1.1 非 daemon 请求线程没有空闲/读取超时;`server.shutdown()` 不关闭已有连接,`server_close()` 会等待这些线程。控制面正常的 `http.DefaultClient` 就可能留下 keep-alive 连接。半截请求体也可造成阻塞。清理顺序还先关闭订阅和代理,再等待在途请求。
|
||||
- **修正:**明确停止接收、回收空闲连接、在途请求期限和依赖关闭顺序。不能仅改 daemon 线程来掩盖未完成清理。
|
||||
- **验收:**隔离进程覆盖空闲连接、半截请求体、活跃请求、排队请求;记录正常退出码、耗时、未发生 SIGKILL 和 reservation 释放。此前 47 秒重启记录不能证明优雅退出,详见第 6 节。
|
||||
|
||||
### GW04 · P1:冷启动拉取镜像时丢失 digest
|
||||
|
||||
- **证据与影响:**`cmd/docker_gateway/docker_client.py:142-160,584-586`。`repo@sha256:…` 被拆开后,只将 repository 传给 `fromImage`,digest 未传出,可能拉取无关默认 tag,随后原 digest 创建失败。
|
||||
- **修正:**digest 引用完整传给 Docker;普通 tag 引用才按相应契约拆分。
|
||||
- **验收:**直接断言 Docker 请求 query,覆盖缺本地 digest、已存在 digest 和普通 tag,不仅测试拆字符串函数。
|
||||
|
||||
### GW05 · P1:删除校验拒绝控制面的 `runtime-not-found` 清理语义
|
||||
|
||||
- **证据与影响:**`cmd/docker_gateway/gateway.py:1180-1205`;`cmd/control-plane/hub.go:71,140-145,196-225,1789-1794`。创建失败后只剩已知网络,控制面用 `runtime_id="runtime-not-found"` 清理;Python 对非空 ID 强制 64 位十六进制,提前返回 400,残留网络不能收敛。
|
||||
- **修正:**保留现有 `/v1` 契约时,仅删除路径解释“容器不存在、清理指定网络代”;若实际存在替代容器则必须拒绝。启动和写操作仍须真实容器 ID,不放宽通用检查。
|
||||
- **验收:**Go 实际生成的 payload 经过 Python HTTP 路由,覆盖仅网络、两者皆无、alias 已被新代占用。
|
||||
|
||||
### GW06 · P1:网络初始化失败丢失代信息,部分副作用未回滚
|
||||
|
||||
- **证据与影响:**`cmd/docker_gateway/docker_client.py:393-475`;`gateway.py:190-192,316-333,474-485,929-947`。创建网络后 inspect 失败不一定携带已知 generation;调用方尚未完成赋值。`restore_proxy` 的网络初始化又位于回滚 try 之外。连接部分成功后抛错可留下半完成网络,HTTP 错误也未保留清理所需网络 ID。
|
||||
- **修正:**首次副作用后立即保留已知代;所有后续错误经过统一回滚边界,返回已知网络代和清理结论。
|
||||
- **验收:**逐点注入创建后 inspect 失败、runtime 已连接但 gateway 连接失败、操作生效但响应丢失;仅清理本次代,错误记录保留恢复依据。
|
||||
|
||||
### GW07 · P1:单个浏览器网络异常使整个 gateway 无法列举和对账
|
||||
|
||||
- **证据与影响:**`cmd/docker_gateway/gateway.py:144-147`、`docker_client.py:231-252`;`cmd/control-plane/hub.go:927-970`。列表为每个 running 容器同步解析网络 IP,任何一个缺网络/IP 或中途消失就使列表整体失败,控制面跳过整个 gateway 的环境对账。
|
||||
- **修正:**清单读取与 CDP 地址解析分离;异常环境仍应可识别、可单独恢复,不能返回假地址或假成功。
|
||||
- **验收:**正常、缺网络、中途消失三个环境共存;正常记录可读,异常记录有真实状态,其他环境仍能对账。
|
||||
|
||||
### GW08 · P1:CDP 超时释放锁后,页面脚本仍可能继续写入
|
||||
|
||||
- **证据与影响:**`cmd/docker_gateway/douyin.py:34,64-79,136-155,915-924`、`gateway.py:617-639`。CDP 固定 15 秒,脚本含 20 秒写请求和多个串行读,IM SDK 没有总期限。关闭 CDP 不会取消页面 Promise;Python 返回并释放 alias 锁时,旧脚本可能继续提交,后续动作与它重叠。
|
||||
- **修正:**统一 HTTP/CDP/脚本预算,明确超时后仍在途的动作所有权与核验方式。不能把“连接关闭”当“写入已停止”,不明操作不得自动补发。
|
||||
- **验收:**离线脚本或 CDP 替身使写入跨过 15 秒;证明旧动作未结束时后续写不会穿透互斥,结果有最终证据或明确不明状态。
|
||||
|
||||
### GW09 · P2:普通 HTTP 代理丢弃 chunked 请求体
|
||||
|
||||
- **证据与影响:**`cmd/docker_gateway/proxy.py:226-267,307-333`。只识别 Content-Length,却保留 Transfer-Encoding 转发;合法 chunked 请求变成有声明、无正文/终止块,导致挂起或失败。
|
||||
- **修正:**采用完整 HTTP 请求解析/转发能力,或正确处理分块与 trailer;不能静默丢正文。
|
||||
- **验收:**分片 chunk、终止块、trailer、大小限制及异常中断,上游正文必须完整一致。
|
||||
|
||||
### GW10 · P2:校验接受的默认值与执行不一致,缺字段返回 500
|
||||
|
||||
- **证据与影响:**`cmd/docker_gateway/gateway.py:186,1064,1082-1088,1120,1219-1220`。停止态直连创建省略 `network_exit_id` 能通过验证,但后续直接索引触发 KeyError;代理恢复缺代字段也在正式校验前直接索引,变成 500。
|
||||
- **修正:**统一完成默认值归一化及必填检查,然后才允许副作用。
|
||||
- **验收:**通过完整 create/HTTP 路由验证合法省略成功、缺必填返回 400,非法请求没有 Docker 调用。
|
||||
|
||||
### GW11 · P2:删除时“清理待完成”的 `/v1` 响应被改变
|
||||
|
||||
- **证据与影响:**`cmd/docker_gateway/gateway.py:421-427,929-950`;`cmd/control-plane/hub.go:1789-1796`。旧实现对可重试网络清理失败返回 `202 runtime_cleanup_pending`,新实现传播为 502,控制面仍依赖 202 继续恢复。
|
||||
- **修正:**恢复待清理语义及载荷,代冲突仍为 409。若改变契约,须另行批准并同步控制面,不能称为保持 `/v1` 不变。
|
||||
- **验收:**一次暂时失败后的完整控制面请求序列;验证 202、409、真正失败分别处理。
|
||||
|
||||
## 3. 平台动作与事件缺陷
|
||||
|
||||
### EV01 · P0:首次及恢复监听没有可靠基线,旧通知可能触发自动发送
|
||||
|
||||
- **证据与影响:**`cmd/docker_gateway/douyin.py:532-553,575-581,894-906`;`cmd/control-plane/creator_events.go:248-274`;`internal/creator/actions.go:245-312`。只给 reconnected 控制消息设置 baseline,Go 又只记日志;普通 notice 未经过历史边界判断。此前未入库的旧通知,只要策略和冷却允许,就可能执行。**已入库终态事件仍有去重,不应夸大为所有旧事件都会重放。**
|
||||
- **修正:**建立并持久保存经平台验证的新旧边界和恢复分类;边界不明、启用前、断连期间事件仅记录,不自动写入。不能用本机启动时间或重连成功冒充平台连续性证明。
|
||||
- **验收:**首次历史、停用期间、断连、缺时间、重启、冷却到期旧通知均零自动写;只有已确认新边界事件进入执行,分类理由可查。
|
||||
|
||||
### EV02 · P1:事件在持久接收前被删除,错误可造成不可恢复丢失
|
||||
|
||||
- **证据与影响:**`cmd/docker_gateway/douyin.py:509-529,625-647,670-675,910-912`;`cmd/control-plane/creator_events.go:194-209,274-278`。浏览器 `splice`、Python `popleft` 都先删除;单条详情失败会终止批次,Go 保存失败仅记日志,重新 start 停掉旧队列,队列溢出还清空全部事件。
|
||||
- **修正:**先持久接收再确认删除,可重复读取;单条失败隔离,溢出和无法恢复的缺口持久可见,不擅自补发。
|
||||
- **验收:**取队列后断网、响应丢失、数据库首次失败、首条详情失败、溢出;事件可恢复或明确记录缺口,不能只以重连成功验收。
|
||||
|
||||
### EV03 · P1:接收线程同步等待写动作,掩盖后续事件处理延迟
|
||||
|
||||
- **证据与影响:**`cmd/control-plane/creator_events.go:194-209,274`;`internal/creator/actions.go:486-503`、`migrations/017_creator.sql:192`。一批逐条等待完整自动动作,首条耗时超过 5 秒便阻塞后续;received_at 使用延后的入库时间,未保留最早接收时间。
|
||||
- **修正:**快速接收和持久登记与耗时执行分离;仍按执行账号串行写。分别保存平台时间、网关接收、处理开始和结束时间。
|
||||
- **验收:**首个执行器阻塞 10 秒时,第二个事件仍在收到后 5 秒内进入处理,时间记录不能后移掩盖排队。
|
||||
|
||||
### EV04 · P1:后台完成动作被记录为“页面已展示”
|
||||
|
||||
- **证据与影响:**`internal/creator/actions.go:271-275,501`、`settings.go:61-68`。后台完成时写 displayed_at,即使从未打开页面,也有“展示”记录,30 秒指标失真。
|
||||
- **修正:**动作完成与页面展示分别记录;展示时间只能来自实际显示该事件的客户端确认。
|
||||
- **验收:**不开页面时 displayed_at 为空;显示后才记,并与动作完成时间独立。
|
||||
|
||||
### EV05 · P1:Douyin 请求漏传代理标识,非直连环境被拒绝
|
||||
|
||||
- **证据与影响:**`cmd/control-plane/hub.go:140-145` 的 `gatewayGenerationPayload` 不含 network_exit_id;`creator.go:685,727,740`、`creator_events.go:167` 复用它;Python `gateway.py:695-704` 强制比对代理标签,非直连请求变成 409。直连成功证据不能覆盖。
|
||||
- **修正:**Douyin 请求统一携带当前有效代和 `environment.Exit.ID`,保留校验;不要顺带混入删除清理语义。
|
||||
- **验收:**Go 真实 payload 穿过 Python 校验,正确代理通过,缺失/错误代理及旧代拒绝,直连继续通过。
|
||||
|
||||
### EV06 · P1:每次重灌 Cookie,阻断有效人工登录并销毁监听
|
||||
|
||||
- **证据与影响:**`cmd/control-plane/creator.go:661-684,832,936`;`cmd/docker_gateway/gateway.py:529-538`、`douyin.py:266-318`。先强制读取存储凭据,再清 Cookie、导航、设置 Cookie;未先复用有效会话。保存凭据为空或过期时,实际已登录账号仍失败;导航销毁监听,SDK 初始化与后设 Cookie 的身份也未证明一致。
|
||||
- **修正:**先核验有效会话并复用;只有确需恢复登录才注入批准的凭据,再重建并核验页面身份和监听边界。不能通过伪造 Cookie 绕过缺陷。
|
||||
- **验收:**有效人工会话无存储 Cookie 也可使用;重复采集不导航/清 Cookie;必要恢复后身份、SDK 与监听一致。
|
||||
|
||||
### EV07 · P1:采集与写执行器支持的凭据格式不一致
|
||||
|
||||
- **证据与影响:**`cmd/control-plane/creator.go:665-672,809-816,913-920`;`internal/douyin/connector.go:245-287`。采集支持 header 和 JSON bundle,写执行器仅接受 bundle;合法 header 账号到平台写入前就失败,却可能被标不明。
|
||||
- **修正:**共用已批准格式的解析入口,解析错误明确属于未执行;与会话复用一起修正,不强制覆盖会话。
|
||||
- **验收:**两种合法格式经过采集和写入口;非法格式零平台写调用且状态准确。
|
||||
|
||||
### EV08 · P1:内部评论/作品 ID 原样下发,人工动作无法执行
|
||||
|
||||
- **证据与影响:**`web/src/CreatorWorkbenchPage.jsx:237-243,274-283`;`internal/creator/actions.go:599-618,716`;`cmd/control-plane/creator.go:688-690`;`cmd/docker_gateway/douyin.py:395-408`。内部 comment-/work- ID 不等于数字平台 ID;人工回复还允许缺作品 ID。数据库替身执行器不会暴露该问题。
|
||||
- **修正:**共享执行边界解析 comment_key、work_key、评论所属作品,并核对平台、作者和关联关系;区分通知自带的平台 ID,不让 UI 拼猜。
|
||||
- **验收:**从本地记录创建回复、评论点赞、作品点赞和转发,网关收到正确平台目标;缺关联、错作者、跨作品均零写入。
|
||||
|
||||
### EV09 · P1:目标评论仅在前 50 条查找
|
||||
|
||||
- **证据与影响:**`cmd/docker_gateway/douyin.py:921` 的 `ACTION_SCRIPT.findComment` 固定首屏,合法目标在后续页就误报 TARGET_MISMATCH。
|
||||
- **修正:**使用已验证的单条详情或正确分页定位;区分读取失败、不可获取和真正身份不匹配。
|
||||
- **验收:**第二页目标可以核验;分页失败不报错身份;真正作者/作品不符则拒绝写入。
|
||||
|
||||
### EV10 · P1:写后核验失败、确认字段缺失被错误归为“明确失败”
|
||||
|
||||
- **证据与影响:**`cmd/docker_gateway/douyin.py:918-924`;`cmd/control-plane/creator.go:700-722`。点赞 POST 已成功,核验 GET 限流被设 definitive;follow/like/IM 缺确认字段也当明确拒绝。实际可能已写入,错误失败提示可误导另发。
|
||||
- **修正:**区分写前失败、经验证的明确平台拒绝、写后确认不足。写后读失败不能证明未发送,缺字段不得自动等价为拒绝。
|
||||
- **验收:**执行实际脚本逻辑的离线测试:写成功后核验失败、缺字段、SDK 空结果均为不明;明确拒绝才失败,全部禁止自动重发。
|
||||
|
||||
### EV11 · P1:丢弃平台结果标识,评论成功证据不充分
|
||||
|
||||
- **证据与影响:**`cmd/docker_gateway/douyin.py:921,924`;`cmd/control-plane/creator.go:700-718`。IM 返回的消息、会话标识被 Go 解码结构丢弃。评论可能缺 ID、正文和明确作品标识,只凭发送者就成功,缺作品标识还用请求值补齐;持久结果仅固定字符串,无法查证。
|
||||
- **修正:**保存最小稳定平台标识、目标及实际确认内容;不得用请求值代替响应证据,不记录无关完整私信。
|
||||
- **验收:**缺评论 ID、正文错误、父评论不符不能成功;成功私信在操作记录中可查稳定消息和会话标识。
|
||||
|
||||
### EV12 · P1:排队后不重核状态,已停用的动作仍可能发出
|
||||
|
||||
- **证据与影响:**`internal/creator/actions.go:475-486,698-716`;`cmd/control-plane/creator.go:650-693`;`cmd/docker_gateway/gateway.py:617-630`。账号业务检查、策略选择在网关锁排队前完成;锁内仅核代和平台身份。等待期间禁言、撤销授权、停策略、改关系没有最终阻止点。
|
||||
- **修正:**人工和自动共用按账号执行协调,取得执行权后、实际提交前重核当前条件;自动动作还须检查原策略与关系。
|
||||
- **验收:**第二个动作排队时逐项改变条件,后续零平台写;已经发出的动作保留真实结果,不能假装撤销。
|
||||
|
||||
### EV13 · P1:转发确认了文案,却不发送文案
|
||||
|
||||
- **证据与影响:**`cmd/docker_gateway/douyin.py:409-412,921`;`cmd/control-plane/creator.go:691`。入口要求非空文案,但转发请求不使用 `p.text`,仍报 reposted/succeeded,确认内容与实际行为不符。
|
||||
- **修正:**先验证对应平台带文案语义;若只有无文案推荐,明确能力差异并取得用户裁决,不静默丢文案。
|
||||
- **验收:**确认文本进入真实动作且结果一致;不支持时明确阻止,不宣称带文案转发成功。
|
||||
|
||||
### EV14 · P2:同页面重连累积旧事件处理器
|
||||
|
||||
- **证据与影响:**`cmd/docker_gateway/douyin.py:532-553,894-906`。同 key 新安装前未调用旧 dispose,关闭 CDP 不会移除页面 addEventListener;stop 只释放最新一组。
|
||||
- **修正:**重装前清理旧状态,安装失败也清理本次处理器。
|
||||
- **验收:**同页面重复重连后处理器数量固定,stop 后为零。
|
||||
|
||||
## 4. 账号、采集、计划及持久数据缺陷
|
||||
|
||||
### BE01 · P1:旧作品首次发现后,指标间隔状态错误
|
||||
|
||||
- **证据与影响:**`internal/creator/metrics.go:138-155,171-182`。T+2 小时首次发现,将 next_plan 推到 T+3 小时,却保留 1 小时间隔;之后推到 T+5 而非 T+7。
|
||||
- **修正:**根据发布时间和当前时刻统一计算完整计划状态,不能只改下次时间。
|
||||
- **验收:**T+2、T+8、T+32 首次发现后连续多个计划点及重启恢复,符合 1、3、7、15、31、55…累计时刻。
|
||||
|
||||
### BE02 · P1:固定采集计划按完成时间漂移
|
||||
|
||||
- **证据与影响:**`cmd/control-plane/creator.go:852-853`;`internal/creator/collection.go:255,266-270`。T 开始、T+5 分钟完成的 30 分钟任务,下次变成 T+35;不符合固定起点与迟到跳到严格未来点。
|
||||
- **修正:**持久保存起点及未来计划点,完成时间仅记实际执行。
|
||||
- **验收:**慢任务、错过多个周期、重启、暂停恢复后不漂移、不回放历史周期。
|
||||
|
||||
### BE03 · P1:修改设置没有重设已有计划
|
||||
|
||||
- **证据与影响:**`internal/creator/settings.go:32-57`;`metrics.go:138-141,171`。仅改 settings,账号未来时间不重设,指标计划混用旧间隔/倍数与新年龄。
|
||||
- **修正:**一致重算账号、评论未来起点和作品未来计划,保留历史快照。
|
||||
- **验收:**有存量计划时逐项修改间隔、倍数、上限、年龄;未来按新规则,历史不改、不补造。
|
||||
|
||||
### BE04 · P1:普通自有账号不参与作品和一级评论补充采集
|
||||
|
||||
- **证据与影响:**`internal/creator/collection.go:259`;`cmd/control-plane/creator.go:883-891`。到期查询强制 big_account=true,将 W1 的自有账号错误缩减为大号。
|
||||
- **修正:**采集资格与大号自动响应模式分离。
|
||||
- **验收:**普通账号、大号、小号符合条件时均可采集,只有自动响应受大号模式控制。
|
||||
|
||||
### BE05 · P1:封禁、注销账号仍可被选作采集账号
|
||||
|
||||
- **证据与影响:**`internal/creator/collection.go:264-270`;`cmd/control-plane/creator.go:798-804,903-908,955-964`。检查授权但不检查 banned/deleted 业务状态,自动选择与手动指定均受影响。
|
||||
- **修正:**所有采集入口复用同一资格检查。
|
||||
- **验收:**自有、竞品自动选择、竞品手动指定三路均拒绝封禁/注销且零平台请求;历史仍可查。
|
||||
|
||||
### BE06 · P1:自有采集的登录/验证阻断仍被自动重试
|
||||
|
||||
- **证据与影响:**`cmd/control-plane/creator.go:913-945`;`internal/creator/collection.go:189-193,265-270,346-347`。身份失败未持久 blocked,分页 challenge/401/403 统一 failed,下轮再次选择。
|
||||
- **修正:**区分可恢复网络错误和需人工处理的阻断,贯穿身份检查到分页,提供明确人工恢复。
|
||||
- **验收:**身份不符、验证码、401 后下一轮零请求;网络暂时失败按批准计划恢复。
|
||||
|
||||
### BE07 · P1:采集租约不续期,且未覆盖页面数据写入和结束状态
|
||||
|
||||
- **证据与影响:**`internal/creator/collection.go:127-136,157-186,316-342,398-408`;`content.go:94-139`。阶段超过十分钟后断点保存失败;旧持有者被接管后仍可写作品/评论/指标。MarkCompetitorSync 无所有权条件,旧请求可覆盖新结果或暂停状态。
|
||||
- **修正:**一致续期;一页数据与断点更新受有效领取条件共同保护,最终状态同样核对所有者和暂停状态。
|
||||
- **验收:**长任务、到期接管、旧请求迟返、运行中暂停恢复;旧持有者不能覆盖新代结果。
|
||||
|
||||
### BE08 · P1:资料编辑绕过大小号关系和策略停用规则
|
||||
|
||||
- **证据与影响:**`internal/creator/accounts.go:124-143,173-205`;`cmd/control-plane/creator.go:65-76`。profile 更新直接设 big_account,绕过专用入口的小号晋升检查;关闭再开启或非正常再恢复,不要求重启用策略。
|
||||
- **修正:**共享事务性状态变更规则,停用所有受影响策略;恢复正常不自动恢复策略。
|
||||
- **验收:**资料入口和专用入口分别覆盖小号晋升、关闭开启、正常→异常→正常,非法关系拒绝且策略不偷偷恢复。
|
||||
|
||||
### BE09 · P1:小号不同归属冲突被吞掉,并发关系检查有空窗
|
||||
|
||||
- **证据与影响:**`internal/creator/accounts.go:185-194,248-268`;`migrations/017_creator.sql:149-155`。小号已归 A,关联 B 时 ON CONFLICT DO NOTHING 仍返回成功;关联与晋升各自先查后写,可并发形成非法角色状态。
|
||||
- **修正:**同关系重复可幂等,不同归属明确冲突;按一致顺序锁相关账号再检查。
|
||||
- **验收:**同关系重复、不同归属、关联与晋升双事务竞争,返回结果与实际状态一致。
|
||||
|
||||
### BE10 · P1:无文案动作也进入 AI,失败后占用冷却
|
||||
|
||||
- **证据与影响:**`internal/creator/actions.go:411-440`、`logic.go:178-179`;`cmd/control-plane/creator.go:28`。仅判断 text==空,关注/点赞无文案也调用 generator;生产为 nil,动作失败并已占冷却。
|
||||
- **修正:**只为需要文本的动作选择或生成文案,不改动冷却对已开始动作的既定语义。
|
||||
- **验收:**关注、作品点赞、评论点赞在 generator=nil 时执行一次且零 AI 调用;文本动作仍检查配置。
|
||||
|
||||
### BE11 · P1:策略启用不校验 AI 必要条件
|
||||
|
||||
- **证据与影响:**`internal/creator/actions.go:82-110,152-176,366-440`。缺候选文本、有效 AI 配置或回复要求仍可启用,收到事件后才失败并可能占冷却。
|
||||
- **修正:**创建、修改、专用启用入口统一校验动作实际需要的条件,不把“审批”布尔值当可用客户端。
|
||||
- **验收:**三个 enabled=true 入口缺配置均拒绝且无冷却记录;无文案动作不被错误限制。
|
||||
|
||||
### BE12 · P1:同一作品第二来源无法匹配对应线索规则
|
||||
|
||||
- **证据与影响:**`internal/creator/rules.go:138-144`;`content.go:222-247`。作品已有多来源表,但分析仍只比最初 SourceType;owned 后关联 competitor,competitor 规则被误拒,反向同样。
|
||||
- **修正:**使用实际来源关联判断规则范围。
|
||||
- **验收:**双来源两种入库顺序、各来源专用规则都正确,同评论仍只形成一条线索。
|
||||
|
||||
### BE13 · P1:UID 登记值被当作 SecUID 查询作品
|
||||
|
||||
- **证据与影响:**`internal/douyin/creator_collector.go:25-54`;`cmd/control-plane/creator.go:939-943`。核验允许 UID/SecUID/UniqueID 匹配,却不保留规范映射,后续原样放进 sec_user_id。旧 connector 使用身份响应的 SecUID。
|
||||
- **修正:**身份核验输出平台规范标识映射,各接口使用其要求的标识。
|
||||
- **验收:**UID 和 SecUID 登记同账号,最终作品请求均用正确 SecUID;随后补真实只读证据。
|
||||
|
||||
### BE14 · P1:密码更新失败可能删除原有密码
|
||||
|
||||
- **证据与影响:**`internal/creator/accounts.go:111-139`。新密码先覆盖固定 secret key,数据库失败后删除该 key,旧密码已经无法恢复,数据库却可能仍显示已配置。
|
||||
- **修正:**新值使用独立引用,成功关联后再清理旧值;失败只清本次新建项,结果不明需核验关联。
|
||||
- **验收:**已有密码时注入保存失败、数据库失败及结果不明,旧有效凭据不丢,配置标记与引用一致。
|
||||
|
||||
### BE15 · P2:冷却时长没有溢出上限
|
||||
|
||||
- **证据与影响:**`internal/creator/accounts.go:90-93`;`actions.go:390-394`。巨大正数转 time.Duration 再乘秒可能溢出到过去,冷却失效。
|
||||
- **修正:**复用已有时长边界校验。
|
||||
- **验收:**上限、上限+1、int64 最大值;拒绝溢出,历史占用不改变。
|
||||
|
||||
### BE16 · P2:未来发布时间作品被过滤掉,无法进入待核验状态
|
||||
|
||||
- **证据与影响:**`internal/creator/collection.go:317-320` 先按窗口跳过,`content.go:203-207` 的 future 标记无法到达。
|
||||
- **修正:**可靠窗口外和时间无效/未来分别处理;后者保留待核验并说明范围不完整。
|
||||
- **验收:**正常、窗口外、缺时间、未来时间同批输入;异常时间不丢资料、不建年龄计划。
|
||||
|
||||
### BE17 · P2:AI 缺失判定字段被当作明确否定
|
||||
|
||||
- **证据与影响:**`internal/creator/bailian.go:110-117,127-134`。`{}`、null、缺 match 或 match=null 解码为 bool false,后续变成非线索而非分析失败。当前客户端尚未接生产,接线前也须修复。
|
||||
- **修正:**区分字段缺失/null 和明确 true/false,验证必需依据。
|
||||
- **验收:**上述不完整样例均失败;合法真/假按真实依据保存。
|
||||
|
||||
### BE18 · P2:迟到或重复消息倒退会话最近时间
|
||||
|
||||
- **证据与影响:**`internal/creator/actions.go:755,804-816`。消息去重前先无条件更新 last_message_at,旧消息即使重复未插入,也改变会话排序。
|
||||
- **修正:**消息写入和摘要更新一致,最近时间不得被旧/无时间消息覆盖。
|
||||
- **验收:**新→旧→重复旧→缺时间消息,时间不倒退且不重复消息。
|
||||
|
||||
### BE19 · P2:作品列表持有连接时再查询,低连接池下互相等待
|
||||
|
||||
- **证据与影响:**`internal/creator/content.go:368-384`;`store.go:56`。外层 rows 未关闭,又逐作品查询来源;并发占满池后都等待内层连接。
|
||||
- **修正:**先读取并关闭外层 rows,再批量读来源,或一次查询完成,避免嵌套占用。
|
||||
- **验收:**连接池设为 1 时带来源列表仍在期限内返回,再覆盖并发列表。
|
||||
|
||||
## 5. 前端确定缺陷
|
||||
|
||||
人工目标 ID 错配统一见 EV08;AI、媒体、登录、推送缺口见第 7 节,不重复计数。
|
||||
|
||||
### UI01 · P1:设置加载后原样回传只读字段,保存返回 400
|
||||
|
||||
- **证据与影响:**`web/src/CreatorSettingsPage.jsx:30-31,43`;`internal/creator/models.go:23-52`;`cmd/control-plane/creator.go:39-44,604-611`。GET 含 updated_at,完整合入 form 并 PUT;SettingsUpdate 无此字段,严格解码拒绝。现有 Mock fixture 漏了 updated_at。
|
||||
- **修正:**仅发送可编辑字段,保持后端严格校验。
|
||||
- **验收:**真实 GET 结构加载后保存,经真实编码/解码成功;请求无只读字段。
|
||||
|
||||
### UI02 · P1:工作台切换页签将旧数据按新类型渲染,页面崩溃
|
||||
|
||||
- **证据与影响:**`web/src/CreatorWorkbenchPage.jsx:41-42,79-150,501,599-609,800`。共享 data,评论切规则时立即计算 include_keywords.join,切线索时访问 lead.comment.id;pending 包裹不能阻止 children 提前计算。
|
||||
- **修正:**按页签隔离数据或明确数据归属,不匹配时不计算列表。
|
||||
- **验收:**各类型非空数据逐对切换,延迟/乱序返回,始终不崩溃、不串表。
|
||||
|
||||
### UI03 · P1:人工操作标识仅在页面内存,刷新恢复可变成第二次发送
|
||||
|
||||
- **证据与影响:**`web/src/CreatorWorkbenchPage.jsx:63-74,237-283,331-347`。响应丢失后刷新,原 key 不可恢复,再确认生成新 key。服务端同 key 去重仍正确,但无法识别原操作的恢复。不是说用户永远不能再发同内容。
|
||||
- **修正:**复用持久操作记录,恢复原标识和冻结载荷;不明只查询,确需另发必须明确新确认并关联原操作。
|
||||
- **验收:**创建/执行响应各自丢失,页面重挂和服务重启仍只执行一次;恢复不创建新发送。
|
||||
|
||||
### UI04 · P1:局域网 HTTP 下直接调用 randomUUID 可能使发送入口失效
|
||||
|
||||
- **证据与影响:**`web/src/CreatorWorkbenchPage.jsx:35-36,243,331`。部署允许非 localhost HTTP,但 crypto.randomUUID 依赖安全上下文;直接调用无能力处理。该环境兼容性结论来自 API 约束,本轮未作浏览器复现。
|
||||
- **修正:**使用适配批准部署方式的可靠操作标识机制,结合 UI03 持久恢复;不降为弱随机或吞错。
|
||||
- **验收:**randomUUID 缺失替身及实际局域网 HTTP,回复和私信都能正常取得并恢复标识。
|
||||
|
||||
### UI05 · P1:账号切换未隔离迟返请求,可显示和保存另一账号资料
|
||||
|
||||
- **证据与影响:**`web/src/CreatorAccountsPage.jsx:105-168,289`。A 的读取/保存等待时切 B,A 迟返仍 setForm/setStrategies;B 标题下出现 A 数据,继续保存可能覆盖 B,策略操作也可能落到 A。
|
||||
- **修正:**结果绑定发起账号,失效响应不应用;提交中处理目标切换,未保存修改明确确认。
|
||||
- **验收:**两个账号明显不同资料和策略,打乱读取及保存响应;任何时刻均不串用或错操作。
|
||||
|
||||
### UI06 · P1:私信账号选择被当前会话平台锁住
|
||||
|
||||
- **证据与影响:**`web/src/CreatorWorkbenchPage.jsx:621-640`。顶层账号选项按当前会话平台过滤,有抖音会话时另一平台账号消失,无法正常跨平台切换。
|
||||
- **修正:**先独立选账号,再清旧会话并读目标账号数据。
|
||||
- **验收:**两平台各有会话账号双向切换,选项始终可选,请求仅属于新账号。
|
||||
|
||||
### UI07 · P2:所有非成功状态都显示“结果不确定”
|
||||
|
||||
- **证据与影响:**`web/src/CreatorWorkbenchPage.jsx:287-293,352-358`。failed、blocked、processing 被同文案覆盖,隐藏确定原因和在途状态。
|
||||
- **修正:**按后端真实状态及原因展示,并关联原操作;不得给不明状态提供重新发送式重试。
|
||||
- **验收:**成功、失败、阻止、处理中、不明五种结果展示准确。
|
||||
|
||||
### UI08 · P2:读取失败被当作空数据
|
||||
|
||||
- **证据与影响:**`web/src/CreatorAccountsPage.jsx:105-114`、`CreatorCompetitorsPage.jsx:72-77`。策略/账号失败直接清空数组,误报尚无策略或可用账号。
|
||||
- **修正:**错误独立保存,保留已知数据,提供只读重试,依赖数据的写入口禁用。
|
||||
- **验收:**首次失败和有数据后刷新失败均不得冒充真实空列表。
|
||||
|
||||
### UI09 · P2:关键词输入清理规则与后端和需求不一致
|
||||
|
||||
- **证据与影响:**`web/src/CreatorWorkbenchPage.jsx:28-32,213-214`;`internal/creator/logic.go:102-115`。前端 trim 去除更广 Unicode 空白,filter 静默丢空词;后端只清指定普通空白并拒绝空词。
|
||||
- **修正:**统一有限清理规则,空词明确拒绝,不改变原文匹配语义。
|
||||
- **验收:**全角空格、NBSP、普通空白、连续逗号;界面与直接 API 输入一致。
|
||||
|
||||
## 6. 必须纠正的测试、部署和文档结论
|
||||
|
||||
### T01 · P1:覆盖率统计必须排除测试代码
|
||||
|
||||
当前命令固定为 `python3 -m coverage run --source=cmd/docker_gateway -m unittest cmd.docker_gateway.test_gateway`,随后执行 `python3 -m coverage report --include='cmd/docker_gateway/*.py' --omit='cmd/docker_gateway/test_*.py' --fail-under=65`。最近一次本地运行 56 项测试通过,生产代码总覆盖率达到 **65%**;`.coverage` 只作为本次运行产物,不提交仓库。
|
||||
|
||||
- **修正:**统计分母排除测试文件,并补 CDP 超时终止、DM 规范化和网络创建异常回收回归。
|
||||
- **验收:**覆盖率命令必须与同次测试生成的数据对应;逐文件低覆盖率不被总数掩盖,真实平台验收另行登记。
|
||||
|
||||
### T02 · P1:常规测试通过不等于关键数据库和平台逻辑已验证
|
||||
|
||||
- `internal/creator/integration_test.go` 无专用数据库地址时仍会 skip;使用 `CREATORHUB_POSTGRES_TEST_URL` 时最近一次已实际运行内容、动作、消息和迁移测试。
|
||||
- `creator_events_test.go` 覆盖字段/边界转换;新增 stale processing 代码路径仍须在专用数据库环境做崩溃恢复验收。
|
||||
- Python 动作测试覆盖实际嵌入脚本的关键分类字符串和 CDP 超时终止;不替代真实浏览器/平台写入。
|
||||
- 前端覆盖错误、忙碌、账号隔离、策略/规则编辑及消息刷新;不替代视觉、真机和外部服务验收。
|
||||
- **验收口径:**记录 executed/skipped 数量及运行条件;任何 Mock 成功仅证明它覆盖的局部规则。
|
||||
|
||||
### DOC01 · P1:正常退出证据仍需与实现分开记录
|
||||
|
||||
当前代码已配置 SIGINT/SIGTERM、请求排空和 45 秒 Compose 宽限,且本地已有特定 reservation 回收证据;这不等于所有 Docker 故障注入、并发和强杀场景都通过。部署文档保留该限制,不把单次重启时长包装成完整生命周期验收。
|
||||
|
||||
### DOC02 · P1:登录要求冲突,不能自行恢复自动登录
|
||||
|
||||
`AGENTS.md` 与 `docs/plan01.md` 当前统一为不自动登录。**当前修正仍遵守不自动登录、不暴露密码/Cookie/二维码/验证码。** 有效会话可复用,失效后进入人工登录并由 gateway identity 核验;密码“已保存”不得表述为“登录能力已接通”。
|
||||
|
||||
### DOC03 · P2:采集接线与完整性证据分开
|
||||
|
||||
当前文档已表述为:存在数字游标校验、分页请求、保存路径和独立计划;完整性、标识转换、分页边界和平台验收仍未由本地代码证明。接受游标参数不等于证明无漏项。
|
||||
|
||||
### DOC04 · P2:完成表混杂历史与当前轮次
|
||||
|
||||
`docs/plan01.md` 当前已按历史文档、代码接线、实际运行证据和外部待验收项分开;新增能力继续按该三类记录,不能用代码接线代替平台成功。
|
||||
|
||||
### DOC05 · P1:浏览器镜像必须由仓库源码和 immutable digest 管理
|
||||
|
||||
当前分支新增 `docker/browser-wrapper/`,以显式 `BROWSER_BASE_IMAGE` digest 构建 Xvfb/CDP 包装入口,并在 deployment 文档记录 base/published digest、构建提交和 Dockerfile。干净环境构建/拉取和真实身份核验仍需拥有已批准的第三方 base digest 后执行;本地 tag 不作为证据。
|
||||
|
||||
### DOC06 · P1:真实证据只证明局部可达,不证明业务成功
|
||||
|
||||
上一轮身份读取 200、事件启动 200、空列表、重启后短期无错误,只能证明这些时点的局部可达。不得扩大为基线、无遗漏、处理时限、正常退出或全动作成功。直接 follow 返回 BUSINESS_REJECTED 且后查状态为未关注,不能证明关注能力成功;当前 EV10 已将非 2xx 和写后核验不足保留为不明。控制面 resolve credential 发生在写前,说明 EV06/EV07 所在链路缺陷,不应一概归咎于“只差用户提供 Cookie”。结果不明的原操作仍不得自动重试。
|
||||
|
||||
## 7. 已确认的功能接线缺口
|
||||
|
||||
这些项目尚未完成实际流程,不能全部归为“缺真实平台证据”。补齐仍须遵守现有范围、供应商批准与不自动登录等约束。
|
||||
|
||||
| 编号/优先级 | 当前证据与缺口 | 修正方向及完成条件 |
|
||||
| --- | --- | --- |
|
||||
| GAP01 · P1 | `creator.go` 已装配独立的到期指标调度,作品发现与指标刷新分离;真实平台请求频率仍需外部验收。 | 本地已验证独立到期读取、年龄和计划边界;真实平台需继续证明过龄零请求。 |
|
||||
| GAP02 · P1 | Bailian adapter 已装配;缺少 key/model 明确返回 unavailable,质量样本和生产供应商仍待批准。 | 本地验证装配、配置校验和失败边界;生产质量与费用由外部验收。 |
|
||||
| GAP03 · P1 | 新增真实下载、FFmpeg 音轨提取和可配置转写命令;原手写 material-step 路由已删除,转写未配置时明确 failed。 | 本地验证产物驱动和失败状态;音视频、无音轨、空间、供应商质量及重试仍需样本验收。 |
|
||||
| GAP04 · P1 | Douyin DM notice 可规范化,入站事件和人工出站结果均写入本地会话,重复键幂等;平台实际 DM payload/history 仍待验收。 | 本地验证账号隔离、重复消息和失败状态;平台历史读取与非文本消息需外部证据。 |
|
||||
| GAP05 · P1 | 事件处理/缺口已持久化,工作台在打开 DM 会话时按 10 秒刷新并支持手动刷新;未新增未批准的双向推送框架。 | 本地验证持久结果恢复;平台关页监听、30 秒可见和真实断连仍待验收。 |
|
||||
| GAP06 · P1 | 账号页显示登录状态、原因、核验时间和凭据标记;login-result 不得直接写 logged_in,只有 gateway identity 核验可写入。 | 本地验证伪造成功被拒;人工登录入口和真机身份重核仍待外部验收。 |
|
||||
| GAP07 · P1 | 策略支持编辑/调序、启停;关系列表已有解除入口,更新沿用既有接口。 | 本地验证账号切换和策略更新;解除/再绑定并发效果仍需集成证据。 |
|
||||
| GAP08 · P1 | 规则支持来源范围、编辑、启停;评论/线索提供人工联系入口,未接自动联系。 | 本地验证来源和人工确认边界;历史判断依据展示仍需补充验收。 |
|
||||
| GAP09 · P1 | 同步状态、错误、下次时间已显示;链接解析预览与完整组合筛选仍未完成。 | 继续补链接解析/组合筛选,真实0与缺值需保持可区分。 |
|
||||
| GAP10 · P2 | 账号切换和素材文稿切换已有放弃确认,DM 草稿继续本地保留。 | 仍需覆盖工作台页签/路由切换的未保存状态。 |
|
||||
| GAP11 · P1 | 小红书当前在 `creator.go:792-794` 等入口明确阻断;登记或列表里有平台选项不等于业务实现。 | 独立完成同范围能力核实与接线;每类缺口单独裁决,不以抖音成功代替,不宣称平台本身不支持。 |
|
||||
|
||||
## 8. 建议修正顺序与交付门槛
|
||||
|
||||
### 第一批:限制错误外部写入、误删和丢数据
|
||||
|
||||
- EV01、EV02、EV10—EV12:历史边界、持久接收、结果证据和写前条件。
|
||||
- GW01、GW03、GW06、GW08:创建归属、停止排空、网络回滚、仍在途脚本互斥。
|
||||
- BE07—BE09、BE14:租约、账号关系/停用及凭据更新一致性。
|
||||
- 每项先有未修时失败的隔离回归,再改代码;不能用放宽代校验、吞异常、清库或无限重试替代根因修正。
|
||||
|
||||
### 第二批:恢复最小可用闭环
|
||||
|
||||
- 代理和 `/v1`:GW02、GW04、GW05、GW07、GW09—GW11、EV05。
|
||||
- 身份和人工目标:EV06—EV09、EV13、BE13。
|
||||
- 页面可用性与人工标识恢复:UI01—UI06;无文案自动动作 BE10、启用校验 BE11。
|
||||
- 验收先经过真实 Go 请求/Python 校验/页面响应契约,再做获批的小规模真实平台动作。结果不明的旧操作仅核验,不能拿新 key 伪装重试。
|
||||
|
||||
### 第三批:计划正确性和剩余功能
|
||||
|
||||
- BE01—BE06、BE12、BE15—BE19、UI07—UI09、EV03、EV04、EV14。
|
||||
- 按 GAP01—GAP11 完成实际缺口;AI 配置、平台差异和自动登录争议先取得必要批准。
|
||||
- 保留原分阶段顺序:先抖音完整流程,再小红书,最后共存及错误恢复,不用通用框架扩大本期范围。
|
||||
|
||||
### 共同验收门槛
|
||||
|
||||
1. 修正清单每项关联回归用例和结果;条目关闭必须有证据,不以“代码已改”关闭。
|
||||
2. Python 生产代码覆盖率排除测试后至少 65%,Go 数据库测试明确实际运行,关键竞争/崩溃路径有测试。
|
||||
3. 后端 test/vet/race 和控制面构建,Python 网关测试/构建、Compose 配置与生命周期通过;迁移后的网关不再要求构建已删除的 Go 可执行入口。
|
||||
4. 前端 lockfile 安装、非交互测试、构建通过,补真实契约、非空切换、双账号/双平台、乱序和刷新恢复测试。
|
||||
5. 不泄露凭据,不改变账号身份和操作目标,不自动重试不明写入。日志保留操作、账号、代、阶段、错误类别及时间,避免只有笼统错误而无排查线索。
|
||||
6. 平台事件、恢复连续性、各动作、媒体产物、AI 质量与界面时限分别验收;HTTP 200、容器 running、空事件队列、无日志错误均不能替代。
|
||||
7. 尚未完成项目必须继续标注未完成;范围调整需明确批准,不能通过修改文档把缺功能包装成已完成。
|
||||
|
||||
## 9. 审查覆盖与局限
|
||||
|
||||
### 9.1 覆盖清单
|
||||
|
||||
- **网关新增:**`cmd/__init__.py`;`cmd/docker_gateway/{__init__,docker_client,douyin,gateway,proxy,test_gateway}.py`;`requirements-gateway.lock`、`requirements-gateway-dev.lock`。
|
||||
- **旧网关删除:**`cmd/docker-gateway/{main,douyin,proxy}.go` 及 `main_test.go`、`douyin_test.go`、`proxy_test.go`、`douyin_cdp_integration_test.go`。重点对照发生契约和清理/代理回归的旧实现;未把每个已删除测试逐一移植或重跑。
|
||||
- **控制面:**`cmd/control-plane/creator.go`、`creator_events.go`、`creator_events_test.go`、`credential.go`、`main.go`、`hub.go`、`hub_test.go`、`douyin_test.go`;新增及改动路径沿调用链核对。
|
||||
- **领域:**`internal/creator/` 全部生产 Go 文件、全部现有测试文件、017—026 十份迁移。
|
||||
- **采集与凭据:**`internal/douyin/{connector,connector_test,creator_collector,creator_collector_test}.go`;`internal/phasea/store.go` 的改动与关联读取路径。
|
||||
- **前端:**`web/src/Creator{Accounts,Competitors,Settings,Workbench}Page.jsx`、`CreatorPages.test.jsx`、`BrowsersPage.test.jsx`、`Layout.jsx`、`dataProvider.js`、`lib/ui.jsx`、`main.jsx`。
|
||||
- **部署/文档:**`Dockerfile`、`compose.yaml`、`AGENTS.md`、`docs/plan01.md`、`docs/deployment.md`、`docs/architecture/container-control.md`、`docs/product/compliance-product-plan.md`。另对照未改动的 Compose 开发配置和相关测试。
|
||||
|
||||
### 9.2 未运行或无法从本地代码证明的内容
|
||||
|
||||
- 本轮未进行真实平台写操作。所有本地测试、覆盖率和 Compose 配置结果均以交付前实际命令记录为准,不能证明平台业务成功。
|
||||
- 未实测浏览器布局、键盘操作、局域网 HTTP、自动指纹、两账号全流程、Docker 故障注入、数据库并发、部署正常退出码和真实代理兼容性;这些仍须按原 AC 清单登记运行证据,不能将本报告未发现某项缺陷当作该项通过。
|
||||
- 平台真实分页完整性、事件 ID/恢复位置、迟到边界、DM 历史范围、带文案转发能力、每类动作成功证据仍待批准的真机验证。
|
||||
- 本报告不是对主线全部既有代码的全面审计;未改动部分只在解释本分支调用链和迁移契约时对照。
|
||||
- 未发现问题的文件不等于证明无问题。四路审查的完整原始输出保存在本次会话的 `subagent-artifacts/outputs/8f8a3bc6-a9a0-48fc-9cf4-54a8ab4453b2/` 下,文件为 `review-gateway.md`、`review-events.md`、`review-domain.md`、`review-web-docs.md`。本文汇总后的编号是后续修正跟踪依据。
|
||||
Reference in New Issue
Block a user