common/storage cleanup: drop sync interface, boto3, example_usage #35

Closed
opened 2026-08-24 10:14:22 +08:00 by tao.chen · 7 comments
Owner

背景

架构 review 给出 6 个候选,用户选定 ① + ② 实施:

  • ① 砍掉 storage 同步链路(base.StorageBackend、SyncData、LocalStorageBackend(sync)、S3StorageBackend(sync))—— 0 production callers, 假接缝
  • ② 删 example_usage.py —— 漏进生产包的演示代码,0 importers

8 个决策

  1. Hard cut sync: 删 StorageBackend / SyncData / sync impl 类
  2. registry 砍 mode 维度(VALID_MODES / _check_mode / 装饰器 mode 参数 一并删除)
  3. create_storage 看见 config["mode"] 抛 StorageConfigError;build_storage_config 不再写 "mode"
  4. 类重命名: LocalAsyncStorageBackend → LocalStorageBackend;S3AsyncStorageBackend → S3StorageBackend;AsyncStorageBackend 基类保留
  5. example_usage.py 整文件删除
  6. pyproject.toml 删 boto3>=1.34,<2
  7. common/config.py 描述文字 "boto3 access key" → "S3 access key"
  8. backend/services/storage.py:683 stale 注释 "the boto3 client" → "the S3 client"

commit 策略 (Q8 = 3 commit)

  1. refactor(common/storage): drop sync interface + boto3 + example_usage
  2. test(common/storage): lock new contracts after sync removal
  3. (可选) chore: ruff check --fix

测试要求

  • common/tests/storage/test_registry.py: test_register_and_get_class
  • common/tests/storage/test_factory.py: test_create_storage_rejects_mode_sync, test_create_storage_rejects_mode_async, test_build_storage_config_no_mode, test_create_storage_returns_correct_async_class

验证

  • uv run python -m compileall common/src/common/storage/ 干净通过
  • uv run --package backend pytest common/tests -q 全绿
  • grep -r 'LocalAsyncStorageBackend|S3AsyncStorageBackend' common/ backend/ runtime/ schedule/ 零 stale

风险评估 (Linus Q3)

  • 公共 API 损失: StorageBackend 导出 + config["mode"] 兼容(0 caller 已查证)
  • pip: 减少 boto3 (~3MB)
  • env var: 不变
  • CI: 不变

Task: vkk3dmx08aw62tqfldxdma4j

## 背景 架构 review 给出 6 个候选,用户选定 ① + ② 实施: - ① 砍掉 storage 同步链路(base.StorageBackend、SyncData、LocalStorageBackend(sync)、S3StorageBackend(sync))—— 0 production callers, 假接缝 - ② 删 example_usage.py —— 漏进生产包的演示代码,0 importers ## 8 个决策 1. Hard cut sync: 删 StorageBackend / SyncData / sync impl 类 2. registry 砍 mode 维度(VALID_MODES / _check_mode / 装饰器 mode 参数 一并删除) 3. create_storage 看见 config["mode"] 抛 StorageConfigError;build_storage_config 不再写 "mode" 4. 类重命名: LocalAsyncStorageBackend → LocalStorageBackend;S3AsyncStorageBackend → S3StorageBackend;AsyncStorageBackend 基类保留 5. example_usage.py 整文件删除 6. pyproject.toml 删 boto3>=1.34,<2 7. common/config.py 描述文字 "boto3 access key" → "S3 access key" 8. backend/services/storage.py:683 stale 注释 "the boto3 client" → "the S3 client" ## commit 策略 (Q8 = 3 commit) 1. refactor(common/storage): drop sync interface + boto3 + example_usage 2. test(common/storage): lock new contracts after sync removal 3. (可选) chore: ruff check --fix ## 测试要求 - common/tests/storage/test_registry.py: test_register_and_get_class - common/tests/storage/test_factory.py: test_create_storage_rejects_mode_sync, test_create_storage_rejects_mode_async, test_build_storage_config_no_mode, test_create_storage_returns_correct_async_class ## 验证 - uv run python -m compileall common/src/common/storage/ 干净通过 - uv run --package backend pytest common/tests -q 全绿 - grep -r 'LocalAsyncStorageBackend\|S3AsyncStorageBackend' common/ backend/ runtime/ schedule/ 零 stale ## 风险评估 (Linus Q3) - 公共 API 损失: StorageBackend 导出 + config["mode"] 兼容(0 caller 已查证) - pip: 减少 boto3 (~3MB) - env var: 不变 - CI: 不变 --- <sub>Task: vkk3dmx08aw62tqfldxdma4j</sub>
Author
Owner
[MODEL-DEVELOP-PLATFORM-60](https://kaneo.maimaicuizhiji.top/dashboard/workspace/UVjqrB68D9jAIx4sh6ucRfsPbbUCj97c/project/hna942mjy8cwyv1o77mw0cnv/task/u1g3zqhd7nys5suujxlx6j5g)
tao.chen added the priority:mediumstatus:in-progress labels 2026-08-24 10:14:24 +08:00
Author
Owner

tao.chen commented:

Blocker — Codex MCP 401

首次 dispatch 时报:

unexpected status 401 Unauthorized: Authentication Fails,
Your api key: ****LRUQ is invalid,
url: https://api.deepseek.com/responses

不是 prompt 问题 —— Codex MCP 路由到 DeepSeek API 的凭据失效。

Tech spec、8 个决策、3 commit 计划不变。等用户定方向:

  • (a) Codex 凭据修复后再 dispatch
  • (b) 跳过 Codex,由 CC 直接本地执行 commit 1+2+3(仍在 develop 分支,无 push 无 PR)

任务仍在 in-progress,等待用户决策。

**tao.chen** commented: > **Blocker — Codex MCP 401** 首次 dispatch 时报: ``` unexpected status 401 Unauthorized: Authentication Fails, Your api key: ****LRUQ is invalid, url: https://api.deepseek.com/responses ``` 不是 prompt 问题 —— Codex MCP 路由到 DeepSeek API 的凭据失效。 Tech spec、8 个决策、3 commit 计划不变。等用户定方向: - (a) Codex 凭据修复后再 dispatch - (b) 跳过 Codex,由 CC 直接本地执行 commit 1+2+3(仍在 develop 分支,无 push 无 PR) 任务仍在 in-progress,等待用户决策。
Author
Owner

tao.chen commented:

暂停 — 等 Codex 凭据修复

用户选择:等 Codex API key 修好后由 CC 重 dispatch。

状态:

  • Tech spec / 8 个决策 / 3 commit 划分:已确定并记录在 task 59 描述里。
  • 本地 working tree:clean(未开始执行)。
  • 已记录的 blocker:deepseek-v4-flash 模型在 https://api.deepseek.com/responses 返回 401(API key 失效)。

恢复动作(用户修好之后):

  1. 重 dispatch 给 Codex MCP(model "deepseek-v4-flash", sandbox "danger-full-access", approval-policy "on-request")。
  2. 跑 commit 1 acceptance list:compileall / grep 兜底 / from common.storage import create_storage
  3. commit 2 (tests) → commit 3 (ruff) 按顺序。
  4. 同步任务至 in-review。
**tao.chen** commented: > **暂停 — 等 Codex 凭据修复** 用户选择:等 Codex API key 修好后由 CC 重 dispatch。 状态: - Tech spec / 8 个决策 / 3 commit 划分:已确定并记录在 task 59 描述里。 - 本地 working tree:clean(未开始执行)。 - 已记录的 blocker:deepseek-v4-flash 模型在 `https://api.deepseek.com/responses` 返回 401(API key 失效)。 恢复动作(用户修好之后): 1. 重 dispatch 给 Codex MCP(model "deepseek-v4-flash", sandbox "danger-full-access", approval-policy "on-request")。 2. 跑 commit 1 acceptance list:compileall / grep 兜底 / `from common.storage import create_storage`。 3. commit 2 (tests) → commit 3 (ruff) 按顺序。 4. 同步任务至 in-review。
Author
Owner

tao.chen commented:

第二次 dispatch 仍然 401

用户报"Codex 修好了",重 dispatch 后:

unexpected status 401 Unauthorized: Authentication Fails,
Your api key: ****LRUQ is invalid,
url: https://api.deepseek.com/responses

同样的 API key 后四位 LRUQ,同样的 endpoint https://api.deepseek.com/responses

可能的方向:

  1. 修改的不是同一个 key —— 检查 Codex MCP 实际读哪个 env / config。
  2. 修改了 env 但 MCP server 进程没重启 —— 重启 Codex MCP。
  3. 修改了 key 但 key 在 DeepSeek 那边仍标 "invalid" —— 重新去 deepseek.com 申请新 key。

不再自动重试。如果修好确认重 dispatch 即可。

工作树仍 clean。Spec 在 task 描述里完整保留。

**tao.chen** commented: > **第二次 dispatch 仍然 401** 用户报"Codex 修好了",重 dispatch 后: ``` unexpected status 401 Unauthorized: Authentication Fails, Your api key: ****LRUQ is invalid, url: https://api.deepseek.com/responses ``` 同样的 API key 后四位 LRUQ,同样的 endpoint `https://api.deepseek.com/responses`。 可能的方向: 1. 修改的不是同一个 key —— 检查 Codex MCP 实际读哪个 env / config。 2. 修改了 env 但 MCP server 进程没重启 —— 重启 Codex MCP。 3. 修改了 key 但 key 在 DeepSeek 那边仍标 "invalid" —— 重新去 deepseek.com 申请新 key。 不再自动重试。如果修好确认重 dispatch 即可。 工作树仍 clean。Spec 在 task 描述里完整保留。
Author
Owner

tao.chen commented:

Codex MCP 凭据连续 3 次 401 — 停止自动重试

按 CLAUDE.md「Failure Handling」:「若 Codex 连续 3 次失败 → 停止自动执行、CC 分析失败、更新 Kaneo、说明 blocker、指出需要的人工介入」。

3 次都报:

401 Unauthorized: Authentication Fails,
Your api key: ****LRUQ is invalid,
url: https://api.deepseek.com/responses

key 后四位 LRUQ 不变 → 你修改的不是 Codex MCP 实际读的那个 key / 没生效。

实情:

  • 工作树 clean,未动一行
  • 任务 59 仍 In Progress(spec 完整保留)
  • 等待用户定方向:
    • (a) 真的修好 Codex 后 retry —— 但需要"key 后四位不再以 LRUQ 结尾"作为信号
    • (b) 改 Plan B:CC 直接本地执行 commit 1+2+3(不需要 DeepSeek 凭据)
  • 不再自动 dispatch
**tao.chen** commented: > **Codex MCP 凭据连续 3 次 401 — 停止自动重试** 按 CLAUDE.md「Failure Handling」:「若 Codex 连续 3 次失败 → 停止自动执行、CC 分析失败、更新 Kaneo、说明 blocker、指出需要的人工介入」。 3 次都报: ``` 401 Unauthorized: Authentication Fails, Your api key: ****LRUQ is invalid, url: https://api.deepseek.com/responses ``` key 后四位 LRUQ 不变 → 你修改的不是 Codex MCP 实际读的那个 key / 没生效。 实情: - 工作树 clean,未动一行 - 任务 59 仍 In Progress(spec 完整保留) - 等待用户定方向: - (a) 真的修好 Codex 后 retry —— 但需要"key 后四位不再以 LRUQ 结尾"作为信号 - (b) 改 Plan B:CC 直接本地执行 commit 1+2+3(不需要 DeepSeek 凭据) - 不再自动 dispatch
Author
Owner

tao.chen commented:

执行完成

两个 commit 已落到 develop(base b493907,本地):

  • 6050880 refactor(common.storage): drop sync storage abstraction and example_usage
  • 24f40b5 test(common.storage): cover async-only registry + factory contract

实现要点

  • common/storage/base.py — 删 StorageBackend 抽象类、SyncData 别名;只留 AsyncStorageBackend
  • common/storage/registry.py — 删 VALID_MODES/_check_mode,装饰器去掉 mode 参数;单层 dict 索引
  • common/storage/factory.pycreate_storage 看见任何 mode 字段抛 StorageConfigErrorbuild_storage_config 不再写 "mode": "async"
  • common/storage/__init__.py__all__ 去掉 StorageBackend
  • backends/local.py — 删 sync impl,LocalAsyncStorageBackendLocalStorageBackend
  • backends/s3.py — 删 sync impl + boto3 依赖;S3AsyncStorageBackendS3StorageBackend
  • common/pyproject.toml — 移除 boto3>=1.34,<2(aioboto3 保留)
  • common/config.py — 描述文字 "boto3 access key" → "S3 access key"
  • backend/services/storage.py:683 — stale 注释 "the boto3 client" → "the S3 client"
  • schedule/application/service.pybuild_object_store 两处删掉 "mode": "async"(否则会触发新拒绝语义)
  • 整文件删除:common/storage/example_usage.py

验证

  • uv run python -m compileall common/src/common/storage/ clean
  • uv run --package common pytest common/tests -q — 17 passed
  • uv run --package backend pytest backend/tests -q — 136 passed
  • 精确 grep \bStorageBackend\b / \bSyncData\b / \bS3AsyncStorageBackend\b / \bLocalAsyncStorageBackend\b / boto3 在 src/ 中无任何 stale 命中
  • 运行时 smoke:local backend put/get/delete/exists OK;4 种 mode=... 配置全部被 StorageConfigError 拒绝
  • schedule.application.service.build_object_store 重新配置 local 后返回 LocalStorageBackend OK

diff size: 13 files, +85 / −545 行(含 pyproject/uv.lock 的副作用)。

兼容性影响

  • 删除的公共导出:StorageBackend, SyncData(0 production callers 已验证)
  • 删除的 dict 字段:config["mode"]build_storage_config 内部之前唯一写入方,现已不再写)
  • 删除的 runtime dep:boto3>=1.34,<2(aioboto3 已覆盖所有使用场景)
  • 命名变化:LocalAsyncStorageBackendLocalStorageBackendS3AsyncStorageBackendS3StorageBackend(grep 验证 0 引用)

零行为变化。Codex 凭据 3×401 后改走 Plan B(CC 直接编辑),未触发外部 dispatch。

**tao.chen** commented: > ## 执行完成 两个 commit 已落到 develop(base `b493907`,本地): - `6050880` refactor(common.storage): drop sync storage abstraction and example_usage - `24f40b5` test(common.storage): cover async-only registry + factory contract **实现要点** - `common/storage/base.py` — 删 `StorageBackend` 抽象类、`SyncData` 别名;只留 `AsyncStorageBackend` - `common/storage/registry.py` — 删 `VALID_MODES`/`_check_mode`,装饰器去掉 `mode` 参数;单层 dict 索引 - `common/storage/factory.py` — `create_storage` 看见任何 `mode` 字段抛 `StorageConfigError`;`build_storage_config` 不再写 `"mode": "async"` - `common/storage/__init__.py` — `__all__` 去掉 `StorageBackend` - `backends/local.py` — 删 sync impl,`LocalAsyncStorageBackend` → `LocalStorageBackend` - `backends/s3.py` — 删 sync impl + `boto3` 依赖;`S3AsyncStorageBackend` → `S3StorageBackend` - `common/pyproject.toml` — 移除 `boto3>=1.34,<2`(aioboto3 保留) - `common/config.py` — 描述文字 "boto3 access key" → "S3 access key" - `backend/services/storage.py:683` — stale 注释 "the boto3 client" → "the S3 client" - `schedule/application/service.py` — `build_object_store` 两处删掉 `"mode": "async"`(否则会触发新拒绝语义) - 整文件删除:`common/storage/example_usage.py` **验证** - `uv run python -m compileall common/src/common/storage/` clean - `uv run --package common pytest common/tests -q` — 17 passed - `uv run --package backend pytest backend/tests -q` — 136 passed - 精确 grep `\bStorageBackend\b` / `\bSyncData\b` / `\bS3AsyncStorageBackend\b` / `\bLocalAsyncStorageBackend\b` / `boto3` 在 src/ 中无任何 stale 命中 - 运行时 smoke:local backend put/get/delete/exists OK;4 种 `mode=...` 配置全部被 `StorageConfigError` 拒绝 - `schedule.application.service.build_object_store` 重新配置 local 后返回 `LocalStorageBackend` OK **diff size**: 13 files, +85 / −545 行(含 pyproject/uv.lock 的副作用)。 **兼容性影响** - 删除的公共导出:`StorageBackend`, `SyncData`(0 production callers 已验证) - 删除的 dict 字段:`config["mode"]`(`build_storage_config` 内部之前唯一写入方,现已不再写) - 删除的 runtime dep:`boto3>=1.34,<2`(aioboto3 已覆盖所有使用场景) - 命名变化:`LocalAsyncStorageBackend` → `LocalStorageBackend`、`S3AsyncStorageBackend` → `S3StorageBackend`(grep 验证 0 引用) 零行为变化。Codex 凭据 3×401 后改走 Plan B(CC 直接编辑),未触发外部 dispatch。
tao.chen added status:done and removed status:in-progress labels 2026-08-24 10:31:29 +08:00
tao.chen added the status:in-review label 2026-08-24 10:31:34 +08:00
Author
Owner

tao.chen commented:

Archived as duplicate

This task is a duplicate of #59 (same gitea #35). #59 was created ~1s before this one and already moved to Done (commit 6050880 + 24f40b5 on develop). Archiving to remove the dup.

**tao.chen** commented: > ## Archived as duplicate This task is a duplicate of **#59** (same gitea #35). #59 was created ~1s before this one and already moved to **Done** (commit 6050880 + 24f40b5 on develop). Archiving to remove the dup.
tao.chen added status:archived and removed status:in-review labels 2026-08-24 14:25:20 +08:00
tao.chen reopened this issue 2026-08-24 14:25:33 +08:00
tao.chen added status:in-review and removed status:done labels 2026-08-24 14:26:22 +08:00
tao.chen reopened this issue 2026-08-24 14:26:25 +08:00
tao.chen added the status:to-do label 2026-08-24 14:26:38 +08:00
tao.chen added status:done and removed status:to-do labels 2026-08-24 14:50:34 +08:00
tao.chen removed the status:in-review label 2026-08-24 14:53:25 +08:00
Sign in to join this conversation.