From b1dbe4f57ea9a8cfcdce958f2d12a4860bebcbc8 Mon Sep 17 00:00:00 2001 From: Linghong Date: Wed, 2 Sep 2026 03:46:05 +0000 Subject: [PATCH] =?UTF-8?q?=E9=98=B6=E6=AE=B56=EF=BC=9A=E5=AE=8C=E6=88=90I?= =?UTF-8?q?ssue226=E4=BA=A4=E6=8E=A5=E4=B8=8E=E6=9C=80=E7=BB=88=E9=97=A8?= =?UTF-8?q?=E7=A6=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 补充交给Issue225的Header、tracking metadata和认证主体交接契约 新增阶段6验收记录并汇总TS、Rust、正负向及幂等回归结果 更新Issue226实施方案与分阶段计划为已完成并记录发布环境限制 --- ...Issue226-AGC客户端主站请求统一标记-2026-09-01.md | 36 +++++- ...26-AGC客户端主站请求标记分阶段验收-2026-09-01.md | 22 +++- ...收】Issue226阶段6交接与最终门禁-2026-09-02.md | 119 ++++++++++++++++++ 3 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 local-docs/【阶段验收】Issue226阶段6交接与最终门禁-2026-09-02.md diff --git a/local-docs/【实施方案】Issue226-AGC客户端主站请求统一标记-2026-09-01.md b/local-docs/【实施方案】Issue226-AGC客户端主站请求统一标记-2026-09-01.md index bc08957d7..5e0b59e2e 100644 --- a/local-docs/【实施方案】Issue226-AGC客户端主站请求统一标记-2026-09-01.md +++ b/local-docs/【实施方案】Issue226-AGC客户端主站请求统一标记-2026-09-01.md @@ -6,7 +6,7 @@ - `#226 添加客户端特殊标识`:本方案实际实施范围 - `#225 添加客户端埋点统计`:主站接收、落库和后台统计,本文只冻结交接契约,不在本次实施 -状态:阶段 5 已完成,待阶段 6 实施
+状态:阶段 6 已完成(客户端实现、#225 交接与最终门禁已收口)
本方案包含 #226 客户端代码修改,不包含 #225 主站接收、落库和后台统计代码 ## 1. 一句话交付结果 @@ -407,3 +407,37 @@ Rust 层: - OSS、签名 URL、Provider、搜索、loopback 和更新下载不带标记。 - 客户端测试覆盖正向和负向边界。 - 不修改 `#225` 所需的主站数据设计;`#225` 可直接读取 Header 并按本文约定写入 tracking metadata。 + +## 12. 阶段 6 实施记录与交接状态 + +更新时间:`2026-09-02` + +阶段 6 已完成,`#226` 客户端侧可以交付评审;`#225` 不需要因客户端实现回改设计。固定交接材料如下: + +- 请求 Header:`X-Genarrative-Client: agc`。 +- tracking metadata:复用现有 `metadata_json`,写入 `client: "agc"`;缺失时不写空字符串。 +- 主站记录实际收到的 method/path;不能只记录客户端账本中的 External v1 endpoint。 +- 登录账号态按真实用户维度记录;External API Key 态按 `ExternalApiPrincipal.owner_user_id` 记录,必要时保留 `key_id` 维度。 +- Header 只用于来源审计/统计,不参与鉴权、权限、计费或账号归属;不记录 token、API Key 明文或签名 URL。 +- `#225` 应同时覆盖账号态 `/api/auth/*`、`/api/profile/*`、`/api/assets/*`、`/api/editor/*`、`/api/runtime/*` 和 API Key 态 `/api/external/v1/*`。 +- Header 缺失、空值或未知值按未标记处理,不拒绝业务请求;客户端不需要为失败、重试或轮询请求更换标记。 + +最终门禁结果: + +| 门禁 | 结果 | +|---|---| +| TS `clientHttp` 定向测试 | 通过,14 tests passed | +| AGC TS 类型检查(含 skill-pack/config 检查) | 通过 | +| Rust `http_client` factory 测试 | 通过,2 tests passed | +| Rust OSS/签名 URL/Provider/搜索/loopback/更新下载负向测试 | 通过,`omits_agc_marker` 4 tests passed;loopback 认证边界 1 test passed | +| Rust 账号态主站 mock 捕获 | 通过,1 test passed | +| Rust External Key 态主站 mock 捕获 | 通过,1 test passed | +| Rust 签名 URL 下载边界 | 通过,1 test passed | +| Rust 提交响应丢失幂等回归 | 通过,1 test passed | +| Rust fmt、编码、diff 空白检查 | 通过 | + +本阶段未执行真实发布环境线上 smoke;账号态和 External Key 态证据来自本地 mock/custom `apiBaseUrl` fixture。真实发布环境 smoke 属于发布前或 `#225` 联调门禁,不改变本次 `#226` 客户端契约。 + +可直接粘贴到 `#225` 的交接评论: + +> `#226` 客户端侧已完成并冻结交接契约:AGC 主站业务请求统一发送 `X-Genarrative-Client: agc`。账号态 `/api/auth/*`、`/api/profile/*`、`/api/assets/*`、`/api/editor/*`、`/api/runtime/*` 与 External API Key 态 `/api/external/v1/*` 均覆盖;OSS/签名下载、Provider、受控搜索、loopback、更新下载和外部网页请求不带该标记。主站可按实际 method/path 读取 Header,并在现有 tracking `metadata_json` 中写入 `client: "agc"`;Header 缺失/空值/未知值按未标记处理且不拒绝请求。登录态按真实用户维度记录,External Key 态按 `owner_user_id`(必要时 `key_id`)记录,不记录 token/API Key 明文或签名 URL。客户端正向、负向、账号态、External Key 态和幂等回归均已通过,`#225` 不需要让 `#226` 回改设计。` diff --git a/local-docs/【实施计划】Issue226-AGC客户端主站请求标记分阶段验收-2026-09-01.md b/local-docs/【实施计划】Issue226-AGC客户端主站请求标记分阶段验收-2026-09-01.md index e855e3619..74f44384c 100644 --- a/local-docs/【实施计划】Issue226-AGC客户端主站请求标记分阶段验收-2026-09-01.md +++ b/local-docs/【实施计划】Issue226-AGC客户端主站请求标记分阶段验收-2026-09-01.md @@ -6,7 +6,7 @@ - `#226 添加客户端特殊标识`:本计划全部实施范围 - `#225 添加客户端埋点统计`:只接收交接契约,不在本计划实现 -当前状态:阶段 5 已完成;阶段 6 尚未开始。阶段 0 的证据与验收记录见 +当前状态:阶段 6 已完成;阶段 0 的证据与验收记录见 [【阶段验收】Issue226阶段0现状基线与契约冻结-2026-09-01.md](C:/projects/narrative/Genarrative/local-docs/【阶段验收】Issue226阶段0现状基线与契约冻结-2026-09-01.md)。 ## 1. 交付目标 @@ -375,6 +375,26 @@ tracking metadata:client = "agc" - `git diff --check`。 - 检查 `git status --short`,确保没有构建产物、日志、凭据和无关文件。 +### 10.4 阶段 6 实施记录 + +阶段 6 已完成,交给 `#225` 的固定材料已在 +[【实施方案】Issue226-AGC客户端主站请求统一标记-2026-09-01.md](C:/projects/narrative/Genarrative/local-docs/【实施方案】Issue226-AGC客户端主站请求统一标记-2026-09-01.md) +第 12 节集中确认:Header 为 `X-Genarrative-Client: agc`,tracking metadata 使用 `client: "agc"`,主站按实际 method/path 和真实认证主体记录;缺失/空值/未知 Header 不拒绝请求。该交接不要求 `#226` 再回改客户端,也不要求本阶段实现 `#225` 的主站 tracking、数据库或后台代码。 + +最终门禁已通过: + +- TS `clientHttp` 定向测试:14 tests passed。 +- AGC TS 类型检查:通过。 +- Rust `http_client` factory:2 tests passed。 +- Rust `omits_agc_marker`:4 tests passed;loopback 认证边界:1 test passed。 +- 账号态主站 mock 捕获:1 test passed。 +- External Key 态主站 mock 捕获:1 test passed。 +- 签名 URL 下载边界:1 test passed。 +- 提交响应丢失幂等回归:1 test passed。 +- Rust fmt、`npm run check:encoding`、`git diff --check`:通过。 + +发布环境说明:本阶段没有执行真实发布环境线上 smoke;账号态/External Key 态使用本地 mock 和自定义 `apiBaseUrl` fixture 验证。真实发布环境 smoke 留给发布前或 `#225` 联调门禁,不影响 `#226` 客户端实现完成判定。 + ## 11. 建议提交/评审节奏 为方便阶段验收,建议在同一个 `#226` PR 内按以下逻辑组织提交或至少按阶段分组: diff --git a/local-docs/【阶段验收】Issue226阶段6交接与最终门禁-2026-09-02.md b/local-docs/【阶段验收】Issue226阶段6交接与最终门禁-2026-09-02.md new file mode 100644 index 000000000..6b9e418eb --- /dev/null +++ b/local-docs/【阶段验收】Issue226阶段6交接与最终门禁-2026-09-02.md @@ -0,0 +1,119 @@ +# Issue #226 阶段 6:#225 交接与最终门禁验收记录 + +更新时间:`2026-09-02` +实施范围:`#226 添加客户端特殊标识` +交接范围:`#225 添加客户端埋点统计` +执行结论:阶段 6 通过;#226 客户端实现、边界回归、交接材料和最终门禁已收口。未修改 #225 主站代码、数据库、OpenAPI 或后台实现。 + +## 1. 阶段边界 + +本阶段只完成: + +1. 复核并固定交给 `#225` 的 Header、tracking metadata、认证主体和路径边界。 +2. 汇总阶段 1~5 的正向、负向和语义回归证据。 +3. 执行最终定向测试、编码/格式/空白检查和工作树检查。 +4. 更新实施方案与分阶段计划的完成状态。 + +本阶段明确不做: + +- 不修改 `server-rs`、主站 tracking middleware、route tracking 或后台。 +- 不修改 SpacetimeDB `tracking_event` schema、migration、bindings 或索引。 +- 不修改 External v1 OpenAPI、DTO 或请求响应语义。 +- 不执行真实发布环境线上写入或埋点验证。 + +## 2. 当前仓库状态 + +阶段 6 开始时: + +| 项目 | 结果 | +|---|---| +| 分支 | `feat/agc_call_header` | +| HEAD | `8059bbcb5`(已合并最新 `origin/master`) | +| 工作树 | 干净 | +| `origin/master` | `4a2f5be6c`,同步 AGC 更新下载域名门禁 | + +阶段 0~5 的提交保持不变,本阶段只补充交接/验收文档。 + +## 3. 给 #225 的固定交接契约 + +### 3.1 客户端请求标记 + +```http +X-Genarrative-Client: agc +``` + +- Header 名大小写不敏感;值精确为小写 `agc` 时识别为 AGC。 +- 缺失、空值或未知值按未标记处理,不拒绝请求,也不改变业务行为。 +- Header 只用于来源审计和统计,不参与鉴权、权限、计费或账号归属。 +- 不记录 access token、API Key 明文、签名 URL、项目绝对路径、用户隐私或客户端版本号。 + +### 3.2 tracking metadata + +第一阶段复用现有 tracking `metadata_json`,固定 JSON key/value: + +```json +{ + "route": "/api/editor/images/generations", + "method": "POST", + "status": 202, + "operation": "generateExternalEditorImage", + "client": "agc" +} +``` + +约定: + +- `client` key 固定;AGC 值固定为 `agc`。 +- Header 缺失时不写 `client` 空字符串。 +- 记录主站实际收到的 method/path,不只记录客户端账本中的 External v1 endpoint。 +- `/api/external/v1/*` 不能因为缺少完整 route spec 而漏记。 + +### 3.3 认证主体 + +- 登录账号态:沿用主站现有 access token 解析出的用户维度。 +- External API Key 态:使用 `ExternalApiPrincipal.owner_user_id`,必要时保留 `key_id` 维度。 +- Header 与认证主体独立处理;不能用 Header 代替认证,也不能从 `generationInputs.source` 推导客户端标记。 + +### 3.4 路由和边界 + +应识别的主站请求: + +- 账号态 `/api/auth/*`、`/api/profile/*`、`/api/assets/*`、`/api/editor/*`、`/api/runtime/*`。 +- External API Key 态 `/api/external/v1/*`。 +- 生成提交、异步轮询、项目/素材/资源登记和 `/api/assets/read-url` 换签。 + +明确不应识别为 AGC 主站业务请求: + +- OSS multipart 上传。 +- 签名 URL/OSS 媒体下载。 +- LLM/Codex Provider。 +- AGC 受控搜索。 +- loopback 工具桥。 +- 更新清单、更新包下载和任意外部网页请求。 + +## 4. 最终门禁结果 + +| 验收项 | 命令/证据 | 结果 | +|---|---|---| +| TS 统一出口正向测试 | `npm exec vitest run apps/ai-game-creator-shell/tests/clientHttp.test.ts` | 通过,14 tests passed | +| AGC TS 类型和配置检查 | `npm run ai-game-creator-shell:typecheck` | 通过;skill-pack/config 检查通过 | +| Rust 主站 Client factory | `cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml http_client -- --nocapture` | 通过,2 tests passed | +| 第三方请求负向矩阵 | `cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml omits_agc_marker -- --nocapture` | 通过,4 tests passed | +| loopback 认证/请求边界 | `cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml loopback_proxy_strips_false_codex_limit_headers_and_requires_bearer -- --nocapture` | 通过,1 test passed | +| 账号态主站请求捕获 | `cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml background_agent_runtime_can_generate_platform_art_asset -- --nocapture` | 通过,1 test passed | +| External Key 态和自定义 origin | `cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml sync_canvas_project_assets_with_developer_key_uses_external_route_and_marker -- --nocapture` | 通过,1 test passed | +| `read-url` 与签名下载边界 | `cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml sync_canvas_project_assets_downloads_external_resources -- --nocapture` | 通过,1 test passed | +| 结果未知/幂等语义 | `cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml generation_submit_response_loss_is_not_retried -- --nocapture` | 通过,1 test passed | +| Rust 格式 | `cargo fmt --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml -- --check` | 通过 | +| 中文编码 | `npm run check:encoding` | 通过,5653 个文件 | +| Diff 空白 | `git diff --check` | 通过 | + +Rust 测试输出包含仓库既有的 unused/dead-code warning;本任务相关测试均无 error 或 failure。 + +## 5. 发布环境限制与后续交接 + +本阶段没有执行真实发布环境线上 smoke。账号态和 External Key 态的路径、Header、认证/幂等语义来自本地 mock/custom `apiBaseUrl` fixture;OSS/签名 URL/Provider/搜索/loopback/更新下载边界来自本地请求捕获。发布前或 `#225` 联调时,应由主站侧补做真实环境 Header 接收、tracking metadata 写入和后台查询验证,不要求客户端回改本次设计。 + +## 6. 可直接粘贴到 #225 的评论 + +> `#226` 客户端侧已完成并冻结交接契约:AGC 主站业务请求统一发送 `X-Genarrative-Client: agc`。账号态 `/api/auth/*`、`/api/profile/*`、`/api/assets/*`、`/api/editor/*`、`/api/runtime/*` 与 External API Key 态 `/api/external/v1/*` 均覆盖;OSS/签名下载、Provider、受控搜索、loopback、更新下载和外部网页请求不带该标记。主站可按实际 method/path 读取 Header,并在现有 tracking `metadata_json` 中写入 `client: "agc"`;Header 缺失/空值/未知值按未标记处理且不拒绝请求。登录态按真实用户维度记录,External Key 态按 `owner_user_id`(必要时 `key_id`)记录,不记录 token/API Key 明文或签名 URL。客户端正向、负向、账号态、External Key 态和幂等回归均已通过,`#225` 不需要让 `#226` 回改设计。`