## 30 天变更索引(按窗口聚合发布与行为变化计数,按功能聚合能力增量并以新增场景开头,输出 Markdown 变更索引。) - [ ] EC-1(边界情况)情境:统计窗口内没有发布|操作:渲染变更索引|结果:输出「统计窗口内没有发布」 - [ ] EC-2(边界情况)情境:窗口内功能增量超过 20 个|操作:渲染变更索引|结果:只列前 20 个功能,其余以「其余 N 个功能有零星变化」一行收尾 - [ ] EC-3(边界情况)情境:功能改名后历史变化仍存旧 feature_key|操作:loadWindowFeatureDeltas 执行|结果:按 feature_aliases 归并到当前功能,显示名取当前规格功能名 - [ ] EC-4(边界情况)情境:窗口内发布超过 100 次|操作:loadRecentReleasesWithChanges 执行|结果:按提交时间倒序最多返回 100 条发布 - [ ] HP-1(正常路径)情境:需要 30 天变更索引|操作:renderProgressSummary 执行|结果:输出标题为「30 天变更索引 · 产品名」的 Markdown,含窗口合计、能力进展与发布明细 - [ ] HP-2(正常路径)情境:窗口内存在锚定上线前的全量重建口径发布|操作:渲染变更索引|结果:附口径注释说明重建口径含同义改写噪音 ## AI 规格分析与发布变化(连接仓库后由 AI 提取功能与场景,push 或手动触发分析,生成带源码证据的规格与发布行为变化;上一版规格措辞锚定与措辞漂移折叠,回归清单附带场景行为文本;PR 预演在 PR 中评论受影响规格并挂完成检查;额度闸门拒绝时返回可用额度与升级指引,并支持显式补分析最新 SHA。) - [ ] EC-1(边界情况)情境:全量重建模式分析(无 affectedKeys)|操作:写入规格版本并计算 diff|结果:diffSpec 第三参数为 undefined,不应用行为窗口,新功能正常记为 added - [ ] EC-10(边界情况)情境:增量模式下存在未命中规格索引的行为变更文件|操作:analyzeWithAI 组装增量 prompt|结果:未归属行为变更文件清单显式写入 prompt,请模型特别核对 - [ ] EC-11(边界情况)情境:增量窗口中发现不属于清单内既有功能的新入口或功能拆分|操作:analyzeWithAI 组装增量 prompt|结果:prompt 要求必须作为独立功能输出,不得因不在清单里而省略 - [ ] EC-19(边界情况)情境:模型输出的单个功能场景数超过 schema 上限 40(增量锚定回显叠加变体累积)|操作:parseAnalysisContent 在 schema 校验前执行 capScenariosPerFeature|结果:该功能场景保序截断为前 40 条并打 warn 日志记录丢弃,分析继续解析成功而非整次 run 失败 - [ ] EC-2(边界情况)情境:AI 输出中同一行为从不同角色/视角/措辞重复建条|操作:按锚定规则处理输出|结果:与锚中既有场景语义相同的输出按沿用处理,不新增重复场景 - [ ] EC-32(边界情况)情境:模型把 features 数组漂移到未知顶层键|操作:normalizeTopLevelCollections 执行|结果:按 {name,scenarios} 形状识别并提升为 features,打 warn 日志 - [ ] EC-33(边界情况)情境:增量模式存在受影响功能且上一版规格锚超过 24k 字符预算|操作:loadPreviousSpecText 以 affectedFeatureNames 作为 prioritize 装载锚|结果:受影响功能稳定排到最前,其余功能保持 position 序,截断时先保住受影响功能的旧场景 - [ ] EC-34(边界情况)情境:增量模式组装 prompt 且锚段存在|操作:specAnchoringSection 生成锚段文本|结果:锚段包含「同一行为只允许一条场景」约束,禁止同一行为从不同角色或措辞重复建条 - [ ] EC-35(边界情况)情境:增量分析中受影响功能在上一版规格锚的 24k 预算内|操作:loadPreviousSpecText 按受影响功能名定向装入锚|结果:受影响功能稳定排到锚最前,其余功能保持 position 序,截断时先保受影响功能的旧场景 - [ ] EC-36(边界情况)情境:增量分析中模型为同一行为从不同角色或措辞重复建条|操作:analyzeWithAI 组装增量 prompt|结果:锚段明确「同一行为只允许一条场景」,与锚中既有场景语义相同的输出按沿用处理 - [ ] EC-37(边界情况)情境:增量分析中受影响功能在上一版规格锚中不存在|操作:AI 按增量契约处理该功能|结果:允许重新枚举,通常每功能 3-8 个场景,happy/edge/error 全部类别逐一检查,边界与错误路径不得省略 - [ ] EC-38(边界情况)情境:removed 与 added 场景 category 不同(如 happy 与 error)。|操作:运行规格差异分析。|结果:不判定为变体,不折叠,仍作为独立的移除与新增变化行输出。 - [ ] EC-39(边界情况)情境:removed 与 added 场景操作或结果中的数字 token 不一致(如 404 与 400)。|操作:运行规格差异分析。|结果:variantFieldGate 拒绝,不折叠为变体,变化行保留。 - [ ] EC-4(边界情况)情境:场景证据为空数组|操作:调用 isTestOnlyEvidence 判定|结果:返回 false,不显示「测试佐证」徽标 - [ ] EC-40(边界情况)情境:removed 与 added 场景否定词计数不同。|操作:运行规格差异分析。|结果:不判定为变体,变化行保留。 - [ ] EC-41(边界情况)情境:场景 source 为 manual 或存在于 spec_verifications(entity_type=scenario)。|操作:运行合并提案脚本。|结果:该场景被跳过并在报告中标注「人工/已核实」,不进入删除提案。 - [ ] EC-42(边界情况)情境:分析调用方未传 outputLanguage|操作:调用 analyzeWithAI|结果:字段可选,调用不受影响 - [ ] EC-43(边界情况)情境:产品未设置 output_language|操作:执行分析运行|结果:outputLanguage 为 undefined,提取按缺省 zh-CN 处理 - [ ] EC-44(边界情况)情境:存量 spec_versions 无语言记录。|操作:迁移执行。|结果:存量版本 output_language 置为 zh-CN。 - [ ] ER-1(错误路径)情境:加载上一版场景全文时数据库调用失败|操作:runAnalysisBody 执行 loadPreviousSpecText|结果:错误被捕获并记录日志,previousSpecText 置为空数组,分析继续执行(锚定降级为仅命名约束,不阻塞分析) - [ ] ER-6(错误路径)情境:场景既无 outcome 也无 result 字符串|操作:parseAnalysisContent 解析模型输出|结果:schema 校验失败并抛错,不静默放行 - [ ] ER-7(错误路径)情境:模型输出缺 product 或 release|操作:解析分析结果|结果:不回填 product/release,解析失败交由重试与 run 失败如实暴露 - [ ] ER-8(错误路径)情境:removed 与 added 场景操作/结果不等价且合并文本 contentJaccard 低于 0.5。|操作:运行规格差异分析。|结果:不折叠,作为独立变化行输出,不产生 variant 审计条目。 - [ ] ER-9(错误路径)情境:未提供 --repository 参数,或仓库不存在/无规格版本。|操作:运行合并提案脚本。|结果:打印用法或抛出错误,进程以退出码 1 结束。 - [ ] HP-1(正常路径)情境:产品已注册且仓库可读|操作:在 push 后由 webhook 触发分析|结果:生成新的规格快照与发布行为变化,每条结论带证据路径 - [ ] HP-10(正常路径)情境:指定仓库最新规格版本内存在措辞变体场景,且非 manual、未被人工核实。|操作:运行 merge-variant-scenarios.ts --repository (不带 --apply)。|结果:输出按功能分组的删除/并入提案与跳过项,提示 dry-run 未改动数据。 - [ ] HP-11(正常路径)情境:已人工审阅 dry-run 提案。|操作:运行 merge-variant-scenarios.ts --repository --apply。|结果:按提案删除被合并的变体场景行并打印删除行数,历史 changes 的 before/after JSON 不动。 - [ ] HP-12(正常路径)情境:产品已设置输出语言为 en 且分析 run 已加载该产品|操作:runAnalysisBody 组装 analyzeWithAI 上下文|结果:上下文携带 outputLanguage=en,主提取与分区提取均按该语言生成规格与发布稿 - [ ] HP-13(正常路径)情境:分析调用方传入 outputLanguage|操作:调用 analyzeWithAI|结果:context 接受该可选字段,调用正常完成 - [ ] HP-14(正常路径)情境:产品 output_language 为 en|操作:执行分析运行|结果:loadRun 读取 outputLanguage=en,单分区与多分区提取 context 均携带 en - [ ] HP-15(正常路径)情境:产品输出语言发生切换。|操作:触发首个分析 run。|结果:新 spec_version 记录新 output_language 并强制全量重建。 - [ ] HP-2(正常路径)情境:上一版规格全文超过 24k 字符且包含受影响功能|操作:runAnalysisBody 在受影响集计算后加载上一版场景全文并传入受影响功能名|结果:受影响功能优先装入锚,截断时先保留受影响功能的旧场景 - [ ] HP-3(正常路径)情境:多分区提取结果中同一功能出现同一行为的措辞变体|操作:mergeChunkResults 对场景做去重合并|结果:行为等价或近似变体的场景被折叠为一条,scenariosDeduped 计数增加 - [ ] HP-4(正常路径)情境:规格工作区展示一个证据全部来自测试/文档的场景|操作:渲染 ScenarioCard|结果:reference 之后显示「测试佐证」徽标,悬停提示证据全部来自测试/文档、行为以人工核实为准 - [ ] HP-5(正常路径)情境:仓库已有上一版规格快照|操作:再次执行分析|结果:上一版场景全文作为锚点注入 prompt,未变行为要求逐字沿用,功能简介同样逐字沿用 - [ ] HP-6(正常路径)情境:增量/carry 模式分析(存在 affectedKeys)|操作:写入规格版本并计算 diff|结果:diffSpec 收到 behavioralChangePaths,窗口外证据的新增功能可被证伪 - [ ] HP-7(正常路径)情境:增量分析中上一版规格锚包含受影响功能的旧场景|操作:AI 按增量契约对受影响功能做修订|结果:未变场景逐字沿用原编号与文字,变化行为改写对应条目,新增行为才新增条目,消失行为不再输出,每功能输出条数不超过锚中该功能条数 +3 - [ ] HP-8(正常路径)情境:同一功能内一个场景被移除、另一个措辞近似(同义替换)的场景被新增,category 一致且操作/结果通过严守护。|操作:运行规格差异分析。|结果:该 removed↔added 对被折叠,不产生 added/removed 变化行,折叠明细中出现 reason=variant 的审计条目,原始 before/after 保留。 - [ ] HP-9(正常路径)情境:分析前读取上一版规格全文作为锚,且已知受影响功能名列表。|操作:调用 loadPreviousSpecText 并传入 prioritize 受影响功能名。|结果:受影响功能按名称匹配稳定排到返回列表最前,其余功能保持 position 序,24k 锚预算优先覆盖受影响功能。 ## Archify 运行时准备与命令调用(按 release.json 校验 MIT 许可与归档 SHA-256,解压到固定运行时目录并以标记文件复用;通过子进程调用 Archify 的 deliver 与 visual-check 命令,解析 JSON 回执,失败时抛出携带回执的命令错误。) - [ ] EC-1(边界情况)情境:运行时目录缺失或标记文件与发布 SHA-256 不一致|操作:prepareArchify 执行|结果:清空运行时目录、重新解压归档并写入标记文件 - [ ] ER-1(错误路径)情境:归档文件 SHA-256 与 release.json 不符|操作:verifyArchifyArchive 执行|结果:抛出 Archify archive SHA-256 mismatch - [ ] ER-2(错误路径)情境:Archify 命令返回 ok=false 或子进程失败但 stdout 含回执|操作:runArchify 执行|结果:抛出携带回执的 ArchifyCommandError,消息取首条诊断或 error - [ ] HP-1(正常路径)情境:运行时目录已存在且标记文件与发布 SHA-256 一致|操作:prepareArchify 执行|结果:直接返回 bin/archify.mjs 路径,不重复解压 - [ ] HP-2(正常路径)情境:需要生成架构产物|操作:deliverArchify 执行|结果:以 deliver architecture 参数调用 Archify,默认 quality=showcase 并解析 JSON 回执 - [ ] HP-3(正常路径)情境:需要验收已生成的架构 HTML|操作:visualCheckArchify 执行|结果:调用 visual-check 并返回解析后的回执 ## Chandler OAuth 登录(通过 Chandler OAuth 授权码加 PKCE 换取令牌并拉取用户信息,按邮箱白名单校验登录资格。) - [ ] EC-1(边界情况)情境:配置了邮箱白名单且用户邮箱不在名单内|操作:assertChandlerAllowed 执行|结果:抛出 forbidden - [ ] ER-1(错误路径)情境:令牌交换或用户信息请求失败|操作:completeChandlerOAuth 执行|结果:抛出 token_exchange_failed 或 userinfo_failed - [ ] HP-1(正常路径)情境:用户完成 Chandler 授权回调|操作:completeChandlerOAuth 执行|结果:返回用户资料与访问令牌 ## Chandler webhook 处理(验签后事件先落库(唯一键防重),重复事件直接 ACK;订单定位后按平台状态推进 paid 履约或 refunded 退款确认,未知单返回 404 让平台重试。) - [ ] EC-1(边界情况)情境:同一平台单号与状态的事件重复投递|操作:processChandlerWebhook 执行|结果:撞唯一键直接 ACK,返回 duplicate - [ ] EC-2(边界情况)情境:平台状态为 closed 等其他态|操作:processChandlerWebhook 执行|结果:仅记录 raw_notify,不推进状态机,返回 200 - [ ] ER-1(错误路径)情境:平台单号在本地不存在|操作:processChandlerWebhook 执行|结果:返回 404 unknown_order,让平台重试 - [ ] ER-2(错误路径)情境:事件落库或订单推进抛错|操作:processChandlerWebhook 执行|结果:返回 500,平台重试 - [ ] ER-3(错误路径)情境:签名缺失或不匹配|操作:processChandlerWebhook 执行|结果:返回 401 invalid_signature - [ ] HP-1(正常路径)情境:签名正确且事件首次到达|操作:processChandlerWebhook 执行|结果:事件落库并推进订单状态,返回 200 ok ## Chandler 支付客户端与回调验签(以服务端 Apikey 建单与退款、用户 token 预支付与查单,幂等键分别为本地商户单号与 refund-平台单号;webhook 以 HMAC-SHA256 恒时验签并解析平台单号与状态。) - [ ] EC-1(边界情况)情境:建单响应缺少平台单号|操作:createChandlerOrder 执行|结果:抛出 chandler create_order returned no platform order number - [ ] EC-2(边界情况)情境:未配置 CHANDLER_API_KEY|操作:createChandlerOrder 执行|结果:回退使用用户 token 的 Bearer 鉴权建单 - [ ] ER-1(错误路径)情境:webhook 签名缺失或与 HMAC 计算结果不符|操作:verifyChandlerWebhookSignature 执行|结果:返回 false,拒绝该回调 - [ ] ER-2(错误路径)情境:webhook body 不是合法 JSON 或缺平台单号与状态|操作:parseChandlerWebhookPayload 执行|结果:返回 null,不推进订单 - [ ] ER-3(错误路径)情境:Chandler 接口返回非 2xx|操作:chandlerRequest 执行|结果:抛出携带 chandlerStatus 与解析后 chandlerBody 的错误 - [ ] HP-1(正常路径)情境:需要创建支付订单|操作:createChandlerOrder 执行|结果:以本地商户单号为幂等键建单并返回平台单号 - [ ] HP-2(正常路径)情境:订单已建且用户持有 token|操作:prepayChandlerOrder 执行|结果:返回微信扫码、H5 与支付宝跳转参数 - [ ] HP-3(正常路径)情境:需要核对远端订单状态|操作:queryChandlerOrder 执行|结果:返回平台订单状态字符串,缺失时返回 unknown - [ ] HP-4(正常路径)情境:需要按平台单号退款|操作:refundChandlerOrder 执行|结果:以 refund-平台单号 为幂等键、携带必填正数金额与原因调用退款接口 ## Chandler 用户令牌刷新(按用户持久化 Chandler access/refresh token 并加密落库,临期 60 秒内用用户级 GET_LOCK 串行刷新;远端明确拒绝清行引导重登录,超时或 5xx 保留行可重试。) - [ ] EC-1(边界情况)情境:同一用户并发刷新|操作:getValidUserToken 执行|结果:GET_LOCK 串行化,拿不到锁抛 refresh_failed - [ ] ER-1(错误路径)情境:刷新被远端 4xx 明确拒绝|操作:getValidUserToken 执行|结果:清除该用户令牌行并抛 refresh_rejected,引导重新登录 - [ ] ER-2(错误路径)情境:刷新请求超时或远端 5xx|操作:getValidUserToken 执行|结果:保留令牌行并抛 refresh_failed,可重试 - [ ] HP-1(正常路径)情境:用户已绑定 Chandler 且 access token 未临期|操作:getValidUserToken 执行|结果:解密返回现有 access token,不发起刷新 - [ ] HP-2(正常路径)情境:access token 已临期且存在 refresh token|操作:getValidUserToken 执行|结果:持用户级锁刷新并写回新令牌,返回新 access token ## CoDelphi dogfood 技能与 MCP 直连脚本(以项目级技能文档固化 CoDelphi 自身的 dogfood 循环(红线、日常对账与验收、生产只读核查、部署),并提供从本地配置读取凭据直连生产 MCP 的命令行脚本。) - [ ] EC-1(边界情况)情境:调用 MCP 工具返回 RPC error|操作:执行 mcp-call.py ''|结果:错误 JSON 打印到 stderr 并以退出码 1 结束 - [ ] EC-2(边界情况)情境:未提供任何命令行参数|操作:执行 mcp-call.py|结果:打印用法文档并以退出码 2 结束 - [ ] EC-3(边界情况)情境:search 或 lookup 返回空结果|操作:按技能文档判断账本覆盖|结果:视为账本未覆盖该行为,不反推「没有这个行为」,也不当 bug 修 - [ ] HP-1(正常路径)情境:会话未连接 codelphi MCP,需要验收工具面|操作:执行 mcp-call.py tools-list|结果:从 ~/.zcode/cli/config.json 读取端点与 key,调用 tools/list 并逐行打印工具名 - [ ] HP-2(正常路径)情境:需要直连生产调用某个 MCP 工具|操作:执行 mcp-call.py ''|结果:以 Bearer 鉴权发起 tools/call,打印 structuredContent 的 JSON - [ ] HP-3(正常路径)情境:push 或部署 CoDelphi 之后需要对账|操作:按技能文档执行 list_releases 与 get_release|结果:核对变化清单是否属于本次 push 意图、全量重建的 added 行数是否等于真实新功能数、summary 与 changes 是否脱节,异常走 send_feedback 上报 ## Digest 内容组装与受众分桶(按发布顺序组装本期变更清单,并按 Highlight 类别确定性分桶到 support/sales/marketing 三段;每条宣布项带 specChangeId 可回溯到 spec_changes。) - [ ] EC-1(边界情况)情境:变更无 Highlight 类别|操作:audienceBuckets 执行|结果:该变更只进变更清单与 support 段,不进 sales/marketing - [ ] EC-2(边界情况)情境:变更 Highlight 为 Security/Access/Limits|操作:audienceBuckets 执行|结果:该变更置顶到 support 段 - [ ] HP-1(正常路径)情境:窗口内存在行为变化|操作:buildDigest 执行|结果:返回周期、带 specChangeId 的变更清单与三段受众分桶 ## Digest 周报编排(滚动 7 天窗口(UTC,止于昨日)按产品汇总行为变化,确定性组装 Digest 内容并落库投递;无变化的周不生成不发,已生成过的周期不重发。) - [ ] EC-1(边界情况)情境:窗口内产品没有任何行为变化|操作:runDigestSweepOnce 执行|结果:buildDigest 返回 null,不生成不发,也不留空行 - [ ] EC-2(边界情况)情境:该产品本期已生成过 Digest|操作:runDigestSweepOnce 执行|结果:按 product_id 与 period_start 命中已有记录,skipped 计数加一,不重发 - [ ] HP-1(正常路径)情境:产品在窗口内有行为变化且本期未生成过 Digest|操作:runDigestSweepOnce 执行|结果:buildDigest 落 digests 表并投递通知,generated 计数加一 - [ ] HP-2(正常路径)情境:需要把 Digest 内容转成渠道或邮件文本|操作:renderDigestText 执行|结果:输出含周期标题、变更清单与受众分节的确定性文本,每条附证据路径 ## Docker 生产部署与回滚(以 Docker 镜像部署生产:拉镜像、幂等迁移、切换应用、冒烟检查,失败自动回滚到上一好版本并记录版本状态。) - [ ] EC-1(边界情况)情境:目标镜像已是当前运行版本|操作:deploy.sh 执行|结果:报错退出,不重复部署 - [ ] EC-2(边界情况)情境:另一个部署或回滚正在运行|操作:deploy.sh 执行|结果:获取部署锁失败并退出 - [ ] ER-1(错误路径)情境:冒烟检查失败|操作:deploy.sh 执行|结果:回滚到上一好版本并记录状态后以错误退出 - [ ] ER-2(错误路径)情境:镜像不在本地|操作:require_image 执行|结果:报错提示先 docker pull - [ ] HP-1(正常路径)情境:新镜像已推送且本地可拉取|操作:deploy.sh 执行|结果:迁移、切换、冒烟通过后记录 last_good 并输出 DEPLOY OK ## Explainer 渲染缓存(按产品与当前规格版本缓存 Explainer HTML,命中零 Chromium 调用;读写均 best-effort,缓存故障不阻断导出。) - [ ] EC-1(边界情况)情境:产品尚无规格版本|操作:loadCachedExplainerHtml 执行|结果:返回 null,退化为直接渲染 - [ ] ER-1(错误路径)情境:缓存读写数据库失败|操作:loadCachedExplainerHtml 或 saveExplainerCache 执行|结果:仅记录告警,不阻断导出 - [ ] HP-1(正常路径)情境:产品已有规格版本且缓存命中|操作:loadCachedExplainerHtml 执行|结果:返回缓存的 HTML,不重新渲染 ## GitHub App 凭据与安装令牌(生成 App Manifest 与 JWT,转换 Manifest 得到凭据,按安装 ID 换取安装访问令牌并读取安装信息(挂起时拒绝)。) - [ ] ER-1(错误路径)情境:安装已被挂起|操作:getAppInstallation 执行|结果:抛出 GitHub installation is suspended - [ ] ER-2(错误路径)情境:GitHub App API 返回非 2xx|操作:appApiFetch 执行|结果:抛出携带状态码与响应体的错误 - [ ] HP-1(正常路径)情境:需要创建 GitHub App|操作:codelphiManifest 执行|结果:返回含回调、webhook 与最小权限的 Manifest - [ ] HP-2(正常路径)情境:已有 Manifest 转换码|操作:convertManifestCode 执行|结果:返回 appId、clientId、clientSecret、pem 与 webhookSecret - [ ] HP-3(正常路径)情境:需要以安装身份访问仓库|操作:getInstallationAccessToken 执行|结果:返回安装令牌与过期时间 ## GitHub App 安装与仓库列表(通过 App Manifest 创建并安装 GitHub App,校验安装回调 state,按安装令牌分页列出可接入仓库。) - [ ] EC-1(边界情况)情境:安装回调 state 不匹配或缺失|操作:完成安装回调|结果:返回 installation_state 错误,不保存安装 - [ ] ER-1(错误路径)情境:GitHub App 无权读取仓库列表或安装已断开|操作:列出仓库|结果:返回 400 权限或安装不存在错误 - [ ] HP-1(正常路径)情境:工作区 editor 在集成页|操作:提交 App Manifest 并完成转换回调|结果:凭据加密保存,进入安装步骤 - [ ] HP-2(正常路径)情境:已安装 GitHub App|操作:分页浏览可接入仓库|结果:返回该安装下的仓库列表与 hasMore ## GitHub App 连接管理(集成页展示 GitHub App 与各安装连接,可重新检查、断开连接,未创建 App 时引导创建。) - [ ] EC-1(边界情况)情境:App 已创建但尚未安装|操作:渲染连接列表|结果:显示「尚未安装到任何 GitHub 账号或组织」 - [ ] EC-2(边界情况)情境:连接状态非 active|操作:渲染操作按钮|结果:不显示断开连接按钮 - [ ] ER-1(错误路径)情境:连接操作接口返回错误|操作:执行检查或断开|结果:显示接口错误消息 - [ ] HP-1(正常路径)情境:已创建 GitHub App 且存在安装|操作:渲染集成卡片|结果:列出各安装账号、状态与操作按钮 - [ ] HP-2(正常路径)情境:编辑者点击重新检查|操作:handleConnectionAction 执行|结果:调用检查接口并刷新页面 ## GitHub PR 文件与评论检查操作(分页读取 PR 变更文件,列出与原地更新 Issue 评论,并创建带结论的 check run,供 PR 预演使用。) - [ ] HP-1(正常路径)情境:PR 变更文件超过 100 个|操作:getPullRequestFiles 执行|结果:逐页拉取直到不足 100 条,返回全部文件 - [ ] HP-2(正常路径)情境:需要更新已有预演评论|操作:upsertIssueComment 执行|结果:携带 commentId 时 PATCH 原评论,否则新建评论并返回 id - [ ] HP-3(正常路径)情境:预演完成需要挂检查|操作:createCheckRun 执行|结果:以指定结论创建 completed 检查并返回 id ## GitHub webhook 验签与投递幂等(校验 GitHub webhook HMAC 签名,按 X-GitHub-Delivery 两阶段持久化接收事实并幂等推进状态机,重复投递返回原结果。) - [ ] EC-1(边界情况)情境:push 为分支删除或非默认分支|操作:处理 push webhook|结果:返回 202 ignored,不入队 - [ ] EC-2(边界情况)情境:仓库触发模式为 daily 或 push_count 且未达阈值|操作:处理 push webhook|结果:pending_push_count 加一,投递标记 skipped 并返回 202 deferred_trigger,不入队 - [ ] ER-1(错误路径)情境:签名缺失或不匹配|操作:处理 webhook|结果:返回 401 invalid_signature - [ ] ER-2(错误路径)情境:阶段二入队抛可重试异常|操作:处理 push webhook|结果:投递标记 failed_retryable 并返回 500 delivery_retryable - [ ] HP-1(正常路径)情境:签名正确且投递首次到达|操作:processGitHubWebhook 执行|结果:阶段一落库 received,阶段二推进为 queued 并返回 202 与 runId - [ ] HP-2(正常路径)情境:同一 delivery 已 queued 或 skipped|操作:再次处理该投递|结果:幂等返回原结果,不重复入队 ## GitHub 仓库选择器(添加产品时按连接分页读取可访问仓库,支持筛选、下拉选择与手动输入,最多加载 5 页。) - [ ] EC-1(边界情况)情境:仓库数量超过 10 个|操作:渲染选择器|结果:显示筛选输入框 - [ ] EC-2(边界情况)情境:已加载 5 页仍有更多|操作:渲染加载更多|结果:提示已显示前 500 个仓库,其余请手动输入 - [ ] ER-1(错误路径)情境:仓库列表读取失败|操作:加载仓库|结果:显示「仓库列表读取失败」错误 - [ ] HP-1(正常路径)情境:已选择 GitHub 连接|操作:打开仓库选择器|结果:加载首屏仓库列表并展示下拉选项 - [ ] HP-2(正常路径)情境:仓库列表仍有下一页|操作:点击加载更多仓库|结果:追加下一页仓库并更新 hasMore ## GitHub 安装回调 state 校验(签发带组织与 App 身份的短期 JWT 作为安装 state,回调时校验签名、签发方、受众与组织/App 匹配。) - [ ] EC-1(边界情况)情境:state 缺失、与预期不一致或组织/App 不匹配|操作:verifyGitHubInstallationState 执行|结果:返回 false,不保存安装 - [ ] HP-1(正常路径)情境:发起 GitHub App 安装|操作:createGitHubInstallationState 执行|结果:返回 10 分钟有效的 HS256 state ## GitHub 源码快照与变更上下文(从 GitHub 拉取仓库树与源码快照,按入口点、文档与目录分组优先级选取候选文件并做预算截断;同时把 push 变更上下文归一化为提交信息与预算内的文件 patch。) - [ ] EC-1(边界情况)情境:push 提交数超过 2000 字符预算|操作:normalizeChangeContext 执行|结果:保留最新提交主题并注明省略最早的若干条 - [ ] EC-2(边界情况)情境:变更文件数超过 120 或 patch 总量超过 56000 字符|操作:normalizeChangeContext 执行|结果:按顶层目录轮转选取并截断 patch,保持各目录代表性 - [ ] HP-1(正常路径)情境:仓库树可读|操作:getSourceSnapshot 执行|结果:按优先级选取源码文件并返回带行号的源码内容,总预算 160000 字符 - [ ] HP-2(正常路径)情境:push 含多个提交与多个文件|操作:getChangeContext 执行|结果:返回提交信息、提交时间、URL 与预算内文件 patch 列表 ## GitHub 访问令牌解析(按显式 token、连接安装令牌或环境变量 GITHUB_TOKEN 的顺序解析 GitHub 访问令牌,安装令牌带缓存并在临期前刷新。) - [ ] EC-1(边界情况)情境:未提供连接与 token|操作:resolveGitHubToken 执行|结果:回退读取环境变量 GITHUB_TOKEN - [ ] ER-1(错误路径)情境:连接状态不是 active|操作:resolveGitHubToken 执行|结果:抛出 GitHub installation is disconnected - [ ] HP-1(正常路径)情境:请求显式携带 token|操作:resolveGitHubToken 执行|结果:直接返回该 token - [ ] HP-2(正常路径)情境:请求携带连接 ID 与组织 ID 且缓存剩余有效期超过 5 分钟|操作:resolveGitHubToken 执行|结果:直接复用缓存的安装令牌 ## GitHub 连接检查(按连接 ID 与工作区读取 GitHub App 安装信息并刷新安装记录,失败时把连接标记为 disconnected 并返回 503。) - [ ] ER-1(错误路径)情境:连接不存在或不属于该工作区|操作:checkGitHubConnection 执行|结果:返回 404 connection_not_found - [ ] ER-2(错误路径)情境:读取安装信息抛错|操作:checkGitHubConnection 执行|结果:连接标记 disconnected 并返回 503 与错误消息 - [ ] HP-1(正常路径)情境:连接存在且安装可读取|操作:checkGitHubConnection 执行|结果:保存安装信息并返回 active ## GitHub 集成凭据存储(GitHub App 凭据(client secret、pem、webhook secret)加密落库,按 slug 或最新一条读取解密;安装记录按组织归属保存,跨工作区安装被拒绝。) - [ ] EC-1(边界情况)情境:安装已归属其他工作区|操作:saveInstallation 执行|结果:抛出 GitHub installation belongs to another workspace - [ ] HP-1(正常路径)情境:完成 App Manifest 转换|操作:saveGitHubApp 执行|结果:凭据加密后按 slug 幂等写入 github_apps - [ ] HP-2(正常路径)情境:需要读取已保存的 App 凭据|操作:getGitHubAppBySlug 或 getLatestGitHubApp 执行|结果:解密返回 clientSecret、pem 与可选 webhookSecret ## GitLab 接入层(以 PRIVATE-TOKEN 访问 GitLab API,解析多级 namespace 仓库路径,拉取分支头、变更上下文与成员仓库列表;webhook 以明文 secret token 头恒时比较验签。) - [ ] EC-1(边界情况)情境:首次接入且 before 为空|操作:getGitlabChangeContext 执行|结果:取最新一次提交及其 diff 作为变更上下文 - [ ] ER-1(错误路径)情境:未提供 token 且未配置 GITLAB_TOKEN|操作:gitlabToken 执行|结果:抛出 GITLAB_TOKEN is not configured - [ ] ER-2(错误路径)情境:webhook 缺少 secret token 头或长度不符|操作:verifyGitlabSignature 执行|结果:返回 false,拒绝该回调 - [ ] HP-1(正常路径)情境:已配置 GitLab token 且项目可读|操作:getGitlabChangeContext 执行|结果:返回最新提交信息、时间、URL 与 diff 文件列表 - [ ] HP-2(正常路径)情境:需要浏览可接入 GitLab 项目|操作:listGitlabRepositories 执行|结果:返回成员项目列表与 hasMore ## LLM 调用回执记账(所有结构化 LLM 调用统一经 requestStructuredCompletion 发起,超时、失败、结构不可解析与成功均写入调用回执,独立生成调用以 runId 为 null 加 callKind 标注。) - [ ] ER-1(错误路径)情境:调用超时或网络失败|操作:requestStructuredCompletion 执行|结果:写入 outcome=timeout 或 failed 的 unknown-usage 回执后抛出错误 - [ ] ER-2(错误路径)情境:网关返回非 2xx|操作:requestStructuredCompletion 执行|结果:写入 outcome=failed 的 unknown-usage 回执后抛出网关错误 - [ ] HP-1(正常路径)情境:LLM 调用成功返回|操作:requestStructuredCompletion 执行|结果:写入 outcome=success 的回执,含 usage 与 providerRequestId ## locale 感知日期格式化(formatDateIn/formatDateTimeIn 按界面语言用 Intl 格式化日期,空值与非法日期返回「—」;仪表盘、设置页、成本观测页与产品总览的日期标签统一走该函数。) - [ ] EC-1(边界情况)情境:日期值为空或无法解析为合法日期|操作:formatDateIn 执行|结果:返回「—」,不抛错 - [ ] EC-2(边界情况)情境:传入空值或无法解析的日期字符串|操作:formatDateIn 执行|结果:返回「—」 - [ ] HP-1(正常路径)情境:界面语言为 en 且设置页存在计费周期与订单记录|操作:渲染设置页|结果:计费周期、宽限期、额度钱包到期与订单时间以英文日期时间格式展示 - [ ] HP-2(正常路径)情境:界面语言为 en 且产品总览存在发布时间线|操作:buildProductOverview 传入 locale=en 执行|结果:时间线条目与最近一次有行为变化发布的日期标签按英文月份格式展示 - [ ] HP-3(正常路径)情境:传入合法日期与 locale|操作:formatDateIn 执行|结果:返回该 locale 下的格式化日期字符串,可自定义 dateStyle 等选项 - [ ] HP-4(正常路径)情境:需要展示日期与时间|操作:formatDateTimeIn 执行|结果:返回 medium 日期加 short 时间的本地化字符串 ## MCP key 管理与只读工具面(MCP 连接指南、OAuth 自动发现、动态客户端注册与授权/令牌流程。) - [ ] EC-1(边界情况)情境:尚无任何 key|操作:渲染 key 列表|结果:显示「尚无 key」 - [ ] EC-10(边界情况)情境:授权请求使用未注册 client_id 或回跳地址不匹配|操作:GET 或 POST /api/mcp/oauth/authorize|结果:返回 400 client 校验失败(未注册或回跳地址不匹配)。 - [ ] EC-11(边界情况)情境:用户在授权页选择拒绝|操作:POST /api/mcp/oauth/authorize,decision=deny|结果:带 error=access_denied 回跳 redirect_uri(含 state)。 - [ ] EC-12(边界情况)情境:令牌请求缺少 client_id|操作:POST /api/mcp/oauth/token|结果:返回 400 invalid_request。 - [ ] EC-13(边界情况)情境:refresh_token 分支缺少 refresh_token|操作:POST /api/mcp/oauth/token,grant_type=refresh_token|结果:返回 400 invalid_request。 - [ ] EC-14(边界情况)情境:设置页 06 面板已签发 key 并展示明文|操作:查看明文区与配置卡片|结果:明文 key 仍单独显示一次并可复制;配置卡片同时提供烤入该 key 的 JSON,两者互不影响 - [ ] EC-15(边界情况)情境:无管理权限的成员查看设置页 06 面板|操作:查看连接向导|结果:仍可见端点、配置 JSON 与客户端说明,但不显示签发输入框与撤销按钮 - [ ] EC-2(边界情况)情境:viewer 打开 MCP 面板|操作:渲染面板|结果:不显示签发与撤销入口,仅可查看列表 - [ ] EC-3(边界情况)情境:调用工具时未提供 JSON 参数|操作:运行 mcp-call.py |结果:以空对象作为 arguments 发送 tools/call - [ ] EC-4(边界情况)情境:尚未签发 key 或刚签发前|操作:查看连接配置|结果:Authorization 头显示可见占位符 ,签发后替换为真实 key - [ ] EC-5(边界情况)情境:尚未签发 key 或 key 为空白|操作:渲染连接配置|结果:Authorization 头回退为可见占位符 ,不写入空值 - [ ] EC-7(边界情况)情境:尚未签发 key 或签发后未保留明文|操作:查看连接配置|结果:Authorization 使用可见占位符 ,提示签发 key 后自动写入真实值 - [ ] EC-8(边界情况)情境:注册请求体不是合法 JSON 或缺少 client_name|操作:POST /api/mcp/oauth/register|结果:返回 400 invalid_client_metadata。 - [ ] EC-9(边界情况)情境:注册请求的 redirect_uris 为空、超过 5 个、超长或非 http/https|操作:POST /api/mcp/oauth/register|结果:返回 400 invalid_redirect_uri。 - [ ] ER-1(错误路径)情境:签发或撤销请求失败|操作:提交操作|结果:显示接口错误消息或「签发失败」「撤销失败」 - [ ] ER-11(错误路径)情境:调用 lookup_by_files 时 paths 为空或超过 20 个|操作:handleMcpRpc 处理 tools/call|结果:返回 JSON-RPC 错误码 -32602(INVALID_PARAMS) - [ ] ER-12(错误路径)情境:调用不存在的工具或方法|操作:handleMcpRpc 处理 tools/call 或未知 method|结果:返回 JSON-RPC 错误码 -32601(METHOD_NOT_FOUND) - [ ] ER-8(错误路径)情境:设置页 06 面板签发 key 失败|操作:点击「签发 key」且接口返回错误|结果:面板显示错误信息,不产生明文与配置变更,pending 状态复位 - [ ] ER-9(错误路径)情境:客户端以无效凭据访问 /api/mcp|操作:发送带无效 Bearer token 的请求|结果:返回 401 JSON-RPC 错误(code -32001),响应头携带指向资源元数据的 WWW-Authenticate - [ ] HP-1(正常路径)情境:工作区 editor/owner 在设置页|操作:填写名称并签发 key|结果:返回明文仅显示一次,列表展示 key 提示与创建者 - [ ] HP-10(正常路径)情境:连接器启动连接时自动注册客户端|操作:POST /api/mcp/oauth/register,提交 client_name 与 1-5 个 http/https redirect_uris|结果:返回 201,含 client_id、client_id_issued_at、client_name、redirect_uris。 - [ ] HP-11(正常路径)情境:已登录用户批准已注册客户端的授权请求|操作:GET 授权页携带 client_id、redirect_uri、code_challenge、S256,随后 POST decision=approve|结果:页面展示注册应用名与回跳地址;批准后带授权码回跳 redirect_uri(含 state)。 - [ ] HP-12(正常路径)情境:连接器用授权码换取令牌|操作:POST /api/mcp/oauth/token,grant_type=authorization_code 并携带 client_id、code、code_verifier、redirect_uri|结果:返回 access_token、token_type Bearer、expires_in 与 refresh_token。 - [ ] HP-13(正常路径)情境:访问令牌过期后静默续期|操作:POST /api/mcp/oauth/token,grant_type=refresh_token 并携带 client_id 与 refresh_token|结果:返回新的 access_token、token_type Bearer、expires_in 与旋转后的 refresh_token。 - [ ] HP-14(正常路径)情境:管理员在设置页 06 MCP 集成面板|操作:输入 key 名称并点击「签发 key」|结果:key 签发成功,明文只显示一次;连接配置卡片标题切换为「已写入刚签发的 key,复制即用」,配置 JSON 中已烤入真实 key - [ ] HP-15(正常路径)情境:设置页 06 MCP 集成面板已展示连接配置|操作:点击「复制配置」|结果:通用 mcpServers JSON 被写入剪贴板,按钮文案变为「已复制」 - [ ] HP-16(正常路径)情境:未签发 key 时查看设置页 06 面板|操作:查看连接配置卡片|结果:卡片标题显示「签发 key 后自动写入真实值」,配置 JSON 以占位符形式展示端点与 key 位置 - [ ] HP-17(正常路径)情境:访客未登录访问 /mcp|操作:打开 /mcp 页面|结果:以公开外壳渲染连接指南,含端点、通用 mcpServers JSON、各客户端文件位置、OAuth 连接器说明、13 个工具清单与工作流约定,并显示「返回产品总览」链接 - [ ] HP-18(正常路径)情境:已登录用户访问 /mcp|操作:打开 /mcp 页面|结果:以应用外壳渲染同一连接指南内容,侧栏 MCP 项高亮 - [ ] HP-19(正常路径)情境:支持 OAuth 自动发现的连接器(ChatGPT/Claude 网页版)|操作:以无凭据请求访问 /api/mcp|结果:返回 401 JSON-RPC 错误,WWW-Authenticate 头为 Bearer resource_metadata="/.well-known/oauth-protected-resource/api/mcp",连接器据此发现授权服务器 - [ ] HP-2(正常路径)情境:已签发 key 需要失效|操作:点击撤销|结果:key 标记已撤销,使用该 key 的连接立即失效 - [ ] HP-20(正常路径)情境:用户在设置页 MCP 卡片查看连接向导,且刚签发了新 key。|操作:渲染通用 mcpServers JSON 模板。|结果:模板中 Authorization 为 Bearer 加新签发 key(去空白),并展示各客户端文件位置提示与连接/验证说明。 - [ ] HP-21(正常路径)情境:用户尚未签发 key 时查看连接向导。|操作:渲染 mcpServers JSON 模板。|结果:Authorization 使用占位符 ,提示用户先签发 key。 - [ ] HP-22(正常路径)情境:ChatGPT/Claude Web 连接器请求受保护资源元数据。|操作:GET 资源元数据端点。|结果:返回 resource=/api/mcp、authorization_servers=[base]、scopes_supported=[mcp:read]、resource_documentation=/mcp,并带 access-control-allow-origin:* 与 5 分钟缓存头。 - [ ] HP-23(正常路径)情境:连接器请求授权服务器元数据。|操作:GET 授权服务器元数据端点。|结果:返回 issuer、authorize/token/register 端点、response_types=[code]、grant_types=[authorization_code,refresh_token]、code_challenge_methods=[S256]、token_endpoint_auth_method=none、scopes_supported=[mcp:read]。 - [ ] HP-24(正常路径)情境:连接器进行 RFC 7591 动态客户端注册。|操作:提交 client_name 与 redirect_uris。|结果:返回 mcp_ 前缀的 client_id,客户端信息落库(名称截断 191,回跳地址 JSON 存储)。 - [ ] HP-25(正常路径)情境:用户已批准授权,连接器持授权码、PKCE verifier、回跳地址与 client_id 换取 token。|操作:调用授权码换 token。|结果:校验通过后返回 access token(expiresIn=3600)与 refresh token,授权码一次性作废。 - [ ] HP-26(正常路径)情境:客户端 access token 过期,持有效 refresh token 与相同 client_id 续期。|操作:调用 refresh 换新 token。|结果:返回新的 access 与 refresh token,refresh 有效期顺延 30 天,旧 refresh 立即失效。 - [ ] HP-27(正常路径)情境:客户端发起 MCP initialize 握手|操作:handleMcpRpc 处理 initialize 请求|结果:响应含 protocolVersion、tools 能力、serverInfo 与 instructions 工作流约定(覆盖 lookup_by_files、get_release、send_feedback 等时机) - [ ] HP-28(正常路径)情境:agent 读取工具列表|操作:handleMcpRpc 处理 tools/list 请求|结果:返回 13 个只读工具,描述中标注调用时机(list_projects 先匹配 slug、lookup_by_files 改前必查、list_releases/get_release push 后对账、send_feedback 带三要素) - [ ] HP-29(正常路径)情境:客户端发起 initialize 握手|操作:handleMcpRpc 处理 initialize 请求|结果:响应除 protocolVersion、capabilities.tools 与 serverInfo 外,还携带 instructions 字段,内容含 lookup_by_files、get_release、send_feedback 等工作流约定 - [ ] HP-3(正常路径)情境:需要接入 AI 客户端|操作:查看 MCP 集成面板|结果:展示 Streamable HTTP 端点、通用 mcpServers JSON 连接配置与 Claude Code / ZCode / Cursor 文件位置提示 - [ ] HP-30(正常路径)情境:客户端请求 tools/list|操作:handleMcpRpc 处理 tools/list 请求|结果:返回只读工具清单,其中 list_projects 描述提示先用 git remote 的 owner/name 匹配产品取 slug,lookup_by_files 描述标注做计划或改文件前必查,list_releases 与 get_release 描述标注 push 后对账,send_feedback 描述要求带场景、证据、代码实际行为三要素 - [ ] HP-32(正常路径)情境:agent 查看工具清单以决定调用时机|操作:tools/list 返回工具定义|结果:list_projects 描述提示先用 git remote 的 owner/name 匹配产品取 slug,lookup_by_files 标注做计划或改文件前必查,list_releases 标注 per-push 一条且 push 后用本次 sha 找发布,get_release 标注 push 后对账,send_feedback 标注带场景/证据/实际行为三要素 - [ ] HP-33(正常路径)情境:coding agent 以 API key 或 OAuth 身份连接 MCP 端点并发送 initialize 请求|操作:客户端调用 initialize|结果:响应包含 protocolVersion、capabilities、serverInfo,并新增 instructions 字段,值为四条工作流约定文本(计划前 lookup_by_files 反查、search_scenarios/get_feature 理解行为、push 后 list_releases/get_release 对账、send_feedback 三要素上报) - [ ] HP-4(正常路径)情境:本地已配置 ~/.zcode/cli/config.json 中的 codelphi MCP 服务|操作:运行 mcp-call.py tools-list|结果:逐行打印 MCP 工具名列表 - [ ] HP-5(正常路径)情境:本地已配置 codelphi MCP 服务|操作:运行 mcp-call.py '' 调用工具|结果:以缩进 JSON 打印 result.structuredContent - [ ] HP-8(正常路径)情境:连接器读取授权服务器元数据|操作:GET /.well-known/oauth-authorization-server|结果:返回 RFC 8414 授权服务器元数据 JSON(issuer 为站点 origin),附带发现响应头。 - [ ] HP-9(正常路径)情境:连接器读取受保护资源元数据|操作:GET /.well-known/oauth-protected-resource 或 /.well-known/oauth-protected-resource/api/mcp|结果:返回 RFC 9728 受保护资源元数据 JSON,附带发现响应头。 ## MCP OAuth 自动发现与动态客户端注册(为 ChatGPT/Claude 网页连接器提供 OAuth 自动发现:RFC 8414 授权服务器元数据与 RFC 9728 受保护资源元数据(根路径与路径插入式两条推导),RFC 7591 动态客户端注册;授权页要求已注册 client 且回跳地址精确匹配,token 端点支持授权码与 refresh_token 旋转(access 1 小时、refresh 30 天顺延),MCP 端点 401 指向资源元数据。) - [ ] EC-1(边界情况)情境:未携带凭据访问 MCP 端点|操作:POST /api/mcp|结果:返回 401,WWW-Authenticate 为 Bearer 且 resource_metadata 指向 /.well-known/oauth-protected-resource/api/mcp - [ ] EC-10(边界情况)情境:授权码已交换过、verifier 错误、回跳地址或 client 不匹配|操作:POST /api/mcp/oauth/token 以 authorization_code 换取令牌|结果:返回 400 invalid_grant - [ ] EC-11(边界情况)情境:注册请求的 redirect_uris 缺失、非 http(s)、格式非法、为空或超过 5 条|操作:POST /api/mcp/oauth/register|结果:返回 400 invalid_redirect_uri,不注册客户端 - [ ] EC-12(边界情况)情境:授权页缺少 client_id、redirect_uri、code_challenge 或 method 非 S256|操作:GET 授权页|结果:返回 400 缺少 PKCE 参数 - [ ] EC-13(边界情况)情境:授权请求缺少 client_id、redirect_uri 或 code_challenge,或 code_challenge_method 非 S256|操作:GET /api/mcp/oauth/authorize|结果:返回 400「缺少 PKCE 参数」 - [ ] EC-14(边界情况)情境:token 请求未携带 client_id|操作:POST /api/mcp/oauth/token|结果:返回 400 invalid_request - [ ] EC-3(边界情况)情境:refresh token 已被旋转重放、过期、已撤销、30 天未使用或 client 不匹配|操作:POST /api/mcp/oauth/token 以 refresh_token 授权类型刷新|结果:返回 400 invalid_grant - [ ] EC-4(边界情况)情境:授权请求的 client_id 未注册或 redirect_uri 与注册值不完全一致|操作:GET 或 POST /api/mcp/oauth/authorize|结果:返回 400 client 校验失败,不签发授权码 - [ ] EC-6(边界情况)情境:注册请求的 client_name 为空白|操作:POST /api/mcp/oauth/register|结果:返回 400 invalid_client_metadata,不写入客户端 - [ ] EC-9(边界情况)情境:client_id 未注册或回跳地址与注册值不精确匹配|操作:访问授权页或提交批准|结果:返回 400 client 校验失败,不签发授权码 - [ ] ER-1(错误路径)情境:注册请求 client_name 为空白或 JSON 体非法|操作:POST /api/mcp/oauth/register|结果:返回 400 invalid_client_metadata,不写入客户端 - [ ] ER-10(错误路径)情境:client_id 未注册或回跳地址与注册值不精确匹配|操作:GET 或 POST /api/mcp/oauth/authorize|结果:返回 400 client 校验失败(未注册或回跳地址不匹配) - [ ] ER-11(错误路径)情境:token 请求缺少 client_id 或授权码参数|操作:POST /api/mcp/oauth/token|结果:返回 400 invalid_request - [ ] ER-12(错误路径)情境:授权码无效、已使用、过期,或 verifier/回跳地址/client 不匹配;refresh_token 无效|操作:POST /api/mcp/oauth/token|结果:返回 400 invalid_grant - [ ] ER-13(错误路径)情境:token 请求的 grant_type 不是 authorization_code 或 refresh_token|操作:POST /api/mcp/oauth/token|结果:返回 400 unsupported_grant_type - [ ] ER-14(错误路径)情境:注册请求 redirect_uris 缺失、超过 5 个、非 http(s) 或格式非法|操作:POST /api/mcp/oauth/register|结果:返回 400 invalid_redirect_uri,不写入客户端 - [ ] ER-17(错误路径)情境:client_id 未注册或回跳地址与注册值不精确匹配|操作:GET 或 POST 授权页|结果:返回 400 client 校验失败(未注册或回跳地址不匹配) - [ ] ER-18(错误路径)情境:token 请求缺少 client_id、缺少授权码参数或授权类型不受支持|操作:POST /api/mcp/oauth/token|结果:返回 400 invalid_request 或 unsupported_grant_type - [ ] ER-20(错误路径)情境:token 端点收到 authorization_code 与 refresh_token 之外的 grant_type|操作:POST /api/mcp/oauth/token|结果:返回 400 unsupported_grant_type - [ ] ER-3(错误路径)情境:client_id 未注册或回跳地址与注册值不精确匹配|操作:GET 或 POST /api/mcp/oauth/authorize|结果:返回 400「client 校验失败(未注册或回跳地址不匹配)」,不签发授权码 - [ ] ER-4(错误路径)情境:token 请求缺少 client_id,或授权码交换时 verifier/回跳地址/client 不匹配、码已用过或已过期|操作:POST /api/mcp/oauth/token|结果:缺少 client_id 返回 400 invalid_request;交换失败返回 400 invalid_grant - [ ] ER-5(错误路径)情境:注册请求 client_name 为空白或 body 不是合法 JSON|操作:POST /api/mcp/oauth/register|结果:返回 400 invalid_client_metadata - [ ] HP-1(正常路径)情境:连接器读取受保护资源元数据|操作:GET /.well-known/oauth-protected-resource 或 /.well-known/oauth-protected-resource/api/mcp|结果:两条路径返回相同元数据(resource、authorization_servers、scopes_supported、resource_documentation),带 access-control-allow-origin: * 与 5 分钟缓存 - [ ] HP-10(正常路径)情境:用户已登录且 client 已注册、回跳地址匹配|操作:在授权页批准|结果:签发绑定 client_id 的一次性授权码并回跳 - [ ] HP-11(正常路径)情境:连接器持有有效授权码与 code_verifier|操作:POST /api/mcp/oauth/token(grant_type=authorization_code)|结果:返回 access_token、token_type=Bearer、expires_in 与 refresh_token - [ ] HP-12(正常路径)情境:access token 过期但 refresh token 有效|操作:POST /api/mcp/oauth/token(grant_type=refresh_token)|结果:返回新的 access_token 与旋转后的 refresh_token - [ ] HP-13(正常路径)情境:连接器读取受保护资源元数据|操作:GET /.well-known/oauth-protected-resource 或 /.well-known/oauth-protected-resource/api/mcp|结果:两条路径返回相同元数据:resource 为站点 /api/mcp、authorization_servers 为站点 origin、scopes_supported 为 mcp:read,带 CORS 与 5 分钟缓存 - [ ] HP-14(正常路径)情境:连接器读取授权服务器元数据|操作:GET /.well-known/oauth-authorization-server|结果:返回 issuer、authorize/token/register 端点、code 响应类型、authorization_code 与 refresh_token 授权类型、S256 PKCE、token_endpoint_auth_method=none - [ ] HP-15(正常路径)情境:用户已登录且 client 已注册、回跳地址匹配|操作:在授权页批准|结果:生成绑定该 client 的一次性授权码并回跳 - [ ] HP-16(正常路径)情境:已持有有效 refresh_token|操作:POST /api/mcp/oauth/token 以 grant_type=refresh_token 提交|结果:返回新的 access_token(1 小时)与旋转后的 refresh_token(30 天顺延) - [ ] HP-17(正常路径)情境:未认证请求访问 MCP 端点|操作:POST /api/mcp|结果:返回 401,WWW-Authenticate 指向 /.well-known/oauth-protected-resource/api/mcp - [ ] HP-18(正常路径)情境:连接器读取发现元数据|操作:请求 /.well-known/oauth-authorization-server 与 /.well-known/oauth-protected-resource|结果:返回 issuer 为站点 origin 的授权服务器元数据与资源元数据,端点指向既有 /api/mcp/oauth/*,带 CORS 与 5 分钟缓存 - [ ] HP-19(正常路径)情境:连接器启动连接需要注册客户端|操作:POST /api/mcp/oauth/register 提交 client_name 与 redirect_uris|结果:返回 201 与一次性 client_id、client_name、redirect_uris - [ ] HP-20(正常路径)情境:已注册客户端发起授权且用户已登录|操作:GET 授权页并批准|结果:展示注册应用名与回跳地址,批准后带授权码回跳 - [ ] HP-21(正常路径)情境:已持有授权码与 PKCE verifier|操作:POST /api/mcp/oauth/token 以 authorization_code 换取令牌|结果:返回 access_token、token_type、expires_in 与 refresh_token - [ ] HP-22(正常路径)情境:access token 过期且持有 refresh token|操作:POST /api/mcp/oauth/token 以 refresh_token 换取令牌|结果:返回新的 access_token 与旋转后的 refresh_token,refresh 有效期顺延 - [ ] HP-25(正常路径)情境:连接器启动连接需要注册客户端|操作:POST /api/mcp/oauth/register 携带 client_name 与 redirect_uris|结果:返回 201 与 client_id、client_id_issued_at、client_name、redirect_uris - [ ] HP-26(正常路径)情境:已注册客户端发起授权且用户已登录|操作:GET 授权页后 POST 批准|结果:校验 client 与回跳地址后建授权记录并带一次性授权码回跳 - [ ] HP-27(正常路径)情境:已持有授权码与 refresh token|操作:POST /api/mcp/oauth/token 分别以 authorization_code 或 refresh_token 授权类型换取|结果:返回 access_token、token_type、expires_in 与旋转后的 refresh_token - [ ] HP-28(正常路径)情境:连接器读取受保护资源元数据|操作:GET /.well-known/oauth-protected-resource 或 /.well-known/oauth-protected-resource/api/mcp|结果:返回 resource、authorization_servers、scopes_supported 与 resource_documentation,两条路径载荷一致并带 CORS 头 - [ ] HP-31(正常路径)情境:access token 过期但持有有效 refresh token|操作:以 grant_type=refresh_token 调用 token 端点|结果:返回新的 access_token 与旋转后的 refresh_token,refresh 有效期顺延 - [ ] HP-5(正常路径)情境:持有授权码与 code_verifier|操作:POST /api/mcp/oauth/token 以 authorization_code 授权类型换取 token|结果:返回 access_token、token_type、expires_in 与 refresh_token,授权码一次性失效 - [ ] HP-6(正常路径)情境:access token 过期但 refresh token 有效|操作:POST /api/mcp/oauth/token 以 refresh_token 授权类型刷新|结果:返回新的 access_token 与旋转后的 refresh_token,refresh 有效期顺延 30 天 - [ ] HP-7(正常路径)情境:连接器读取受保护资源元数据|操作:GET /.well-known/oauth-protected-resource 或 /.well-known/oauth-protected-resource/api/mcp|结果:两条路径返回相同元数据(resource、authorization_servers、scopes_supported、resource_documentation),带 CORS 与 300 秒缓存 ## MCP 连接指南公开页(以公开或应用外壳渲染 MCP 连接指南:端点、通用 mcpServers JSON、各客户端文件位置、OAuth 连接器说明、工具清单与工作流约定,配置与指令段可一键复制。) - [ ] EC-1(边界情况)情境:未传入 locale 的 CopyBlock 使用方|操作:点击复制按钮|结果:按钮文案以默认 zh-CN 显示「复制」/「已复制」 - [ ] EC-18(边界情况)情境:团队希望把同一约定共享给所有成员|操作:查看 /mcp 指南的指令文件说明|结果:指南说明可再把同段贴进仓库根目录 AGENTS.md 作为可选加强,并说明已连接 agent 会随连接收到相同约定(MCP instructions) - [ ] EC-21(边界情况)情境:用户尚未签发 key|操作:查看通用 mcpServers JSON 配置块|结果:Authorization 使用占位符 ,提示签发后自动写入真实值 - [ ] EC-26(边界情况)情境:已签发 key 后查看连接配置|操作:查看通用 mcpServers JSON 代码块|结果:Authorization 为真实 key,可点击复制按钮一键复制 - [ ] ER-1(错误路径)情境:浏览器不支持或拒绝剪贴板写入|操作:点击 CopyBlock 的「复制」按钮|结果:复制失败,按钮文案不切换为「已复制」 - [ ] HP-1(正常路径)情境:访客未登录访问 /mcp|操作:打开 /mcp 页面|结果:以公开外壳渲染连接指南,含端点、通用 mcpServers JSON、各客户端文件位置、OAuth 连接器说明、13 个工具清单与工作流约定,并显示「返回产品总览」链接 - [ ] HP-2(正常路径)情境:已登录用户访问 /mcp|操作:打开 /mcp 页面|结果:以应用外壳渲染同一连接指南内容,侧栏 MCP 项高亮 - [ ] HP-27(正常路径)情境:用户需要让 agent 在所有仓库自觉执行工作流约定|操作:在 /mcp 指南中点击用户级常驻指令段的「复制」|结果:门控片段(未连接 codelphi MCP 或 remote 匹配不到时自动跳过)写入剪贴板,按钮显示「已复制」,可贴进 ~/.zcode/AGENTS.md 或 ~/.claude/CLAUDE.md - [ ] HP-28(正常路径)情境:用户需要复制通用 mcpServers 连接配置|操作:在 /mcp 指南的「通用 mcpServers JSON」块点击「复制」|结果:配置 JSON 写入剪贴板,按钮文案变为「已复制」 - [ ] HP-29(正常路径)情境:英文界面语言下查看 MCP 连接指南|操作:点击复制按钮|结果:按钮文案由 Copy 变为 Copied,文本写入剪贴板 ## OAuth 回调校验(校验授权码、PKCE verifier 与 state 后放行回调,失败按错误码跳转登录页或 forbidden。) - [ ] EC-1(边界情况)情境:next 参数为外站地址或含换行|操作:safeNextPath 执行|结果:回退为 / - [ ] EC-2(边界情况)情境:回调缺少 code 或 verifier|操作:parseOAuthCallback 执行|结果:返回 null - [ ] ER-1(错误路径)情境:state 缺失或不匹配|操作:requireOAuthCallback 执行|结果:抛出 invalid_oauth_state - [ ] ER-2(错误路径)情境:OAuth 失败且错误为 forbidden|操作:oauthFailurePath 执行|结果:返回 /forbidden - [ ] HP-1(正常路径)情境:回调携带 code、verifier 且 state 与预期一致|操作:parseOAuthCallback 执行|结果:返回 code、verifier 与安全化的 next 路径 ## patch 行为性判定(检测同一功能内同一错误/状态码 token 的否定陈述与肯定陈述并存冲突;否定判定要求「不再」与 token 紧邻、中间无句读。) - [ ] EC-1(边界情况)情境:变更文件无 patch、语言未知或 patch 超过 4000 字符疑似截断|操作:分析期执行 behavioralChangePaths|结果:保守视为行为变更,文件进入行为变更集 - [ ] EC-2(边界情况)情境:同一功能内一条场景为「创建不再因 MissingOAuth2TokenError 返回 422」,另一条场景肯定陈述同一 token。|操作:调用 detectOutcomeConflicts 处理该功能场景。|结果:「不再」与 token 之间无句读,判为否定,与肯定陈述构成冲突对并输出。 - [ ] EC-3(边界情况)情境:token 前 16 字符窗口内不存在「不再」。|操作:调用 isNegated 判定该 token。|结果:返回 false,该 token 按肯定陈述处理。 - [ ] ER-1(错误路径)情境:场景结果陈述中不包含待判定 token|操作:调用 isNegated 判定该 token|结果:indexOf 返回 -1,直接返回 false - [ ] HP-1(正常路径)情境:实现文件 patch 仅含注释或空白变动|操作:behavioralChangePaths 执行|结果:该文件不进入行为变更集 ## PR 预演(PR 触碰文件与规格索引求交,在 PR 中原地更新预演评论并挂 codelphi/behavior-preview 检查;未命中规格也挂 success,预演自身失败挂 neutral 不阻塞合并。) - [ ] EC-1(边界情况)情境:PR 无变更文件|操作:runPrPreview 执行|结果:直接返回,不生成评论与检查 - [ ] EC-2(边界情况)情境:预演开关关闭|操作:runPrPreview 执行|结果:静默返回 - [ ] ER-1(错误路径)情境:预演自身失败(权限/网络等)|操作:runPrPreview 执行|结果:挂 neutral 检查并附失败原因与重试提示,不阻塞合并 - [ ] HP-1(正常路径)情境:PR 触碰文件命中规格索引|操作:runPrPreview 执行|结果:按功能分组渲染场景编号与证据路径评论,并挂 success 检查 - [ ] HP-2(正常路径)情境:PR 触碰文件未命中已知规格|操作:runPrPreview 执行|结果:挂 success 检查并说明未命中已知功能或场景 ## QA 回归清单(按发布的行为变化生成回归任务清单,按功能分组展示场景行为文本与命中原因,支持标记通过/未通过/跳过/待验证并附备注,可导出 Markdown;无行为变化时提示瘦身回归。) - [ ] EC-1(边界情况)情境:回归任务只有仅措辞变化来源且无文件命中理由|操作:loadRegressionTasks 执行|结果:该任务被过滤,不进入回归清单 - [ ] ER-1(错误路径)情境:更新回归任务状态但任务不属于该产品|操作:setRegressionTask 执行|结果:抛出 regression_task_invalid - [ ] HP-1(正常路径)情境:发布存在场景级行为变化与文件索引命中|操作:planRegressionTasks 执行|结果:同一场景的多个来源合并为一个任务,理由去重,输出顺序确定 - [ ] HP-3(正常路径)情境:需要导出发布回归清单|操作:renderRegressionTaskMarkdown 执行|结果:按功能分组输出 Markdown,任务附理由、状态与场景情境/操作/结果 ## spec 文件反向索引与影响面查询(用最新 spec 快照重建 path → 规格的反向索引,供 PR 预演与增量分析按 diff 文件反查受影响功能与场景。) - [ ] EC-1(边界情况)情境:传入空文件清单|操作:loadAffectedFeatureKeys 或 loadAffectedScenarios 执行|结果:直接返回空结果,不查询数据库 - [ ] ER-1(错误路径)情境:影响面查询接口失败|操作:SpecImpactQuery 发起查询|结果:显示「查询暂时不可用,请稍后重试。」 - [ ] HP-1(正常路径)情境:输入若干文件路径查询行为|操作:SpecImpactQuery 发起查询|结果:按功能聚合展示受影响场景引用、行为文本与证据路径 - [ ] HP-2(正常路径)情境:生成新规格版本|操作:rebuildSpecFileIndex 在同一事务内执行|结果:按证据路径重建 repository 的 spec_file_index - [ ] HP-3(正常路径)情境:给定 diff 触碰的文件清单|操作:loadAffectedScenarios 执行|结果:按功能聚合返回受影响场景的引用、证据路径与情境/操作/结果 ## 中断与积压分析恢复(启动时把重启遗留的 running 孤儿 run 重新排队并派发,周期 sweep 对超阈值仍无人认领的 queued run 只补跑每仓库最新一条,更旧标记 superseded。) - [ ] EC-1(边界情况)情境:补跑闸门不允许派发(额度不足等)|操作:dispatchCandidates 执行|结果:保持 queued 不标 failed,等条件满足后下一轮补跑 - [ ] EC-2(边界情况)情境:并发派发方已认领该 run|操作:dispatchCandidates 原子认领|结果:认领失败静默跳过,不重复派发 - [ ] HP-1(正常路径)情境:服务重启后存在遗留 running run|操作:recoverInterruptedRuns 执行|结果:run 重置为 queued 并过闸门派发,用户无需手工处理 - [ ] HP-2(正常路径)情境:某仓库存在多条超阈值 queued run|操作:dispatchStuckQueuedRuns 执行|结果:只派发最新一条,更旧标记 superseded 终态 ## 产品反馈提交与失败自动记录(成员在产品页提交反馈;分析失败时系统按可报告性自动记录失败反馈(去重键 product+revision+error_message),管理员可把反馈转为 GitHub Issue。) - [ ] EC-1(边界情况)情境:同一产品同一 revision 同一错误已记录过|操作:createFeedbackReport 执行|结果:返回已有反馈 id,不重复插入 - [ ] ER-1(错误路径)情境:反馈接口返回错误|操作:submitProductFeedback 执行|结果:抛出接口错误或「反馈提交失败」 - [ ] ER-2(错误路径)情境:GitHub Issue 创建失败|操作:submitFeedbackToGitHub 执行|结果:反馈标记 failed 并记录 submission_error,错误上抛 - [ ] HP-1(正常路径)情境:成员在产品页提交反馈|操作:submitProductFeedback 执行|结果:返回反馈 id - [ ] HP-2(正常路径)情境:分析 run 失败且错误可报告|操作:recordRunFailureFeedback 执行|结果:按去重键落 feedback_reports,来源为系统自动记录 - [ ] HP-3(正常路径)情境:管理员把反馈转为 GitHub Issue|操作:submitFeedbackToGitHub 执行|结果:创建 Issue 并回写 submitted 与 issue URL;已存在则直接返回原 URL ## 产品反馈转 GitHub Issue(管理员在反馈管理页把已提交反馈转为 GitHub Issue,成功后展示 Issue 链接,失败可重试。) - [ ] ER-1(错误路径)情境:GitHub Issue 创建失败|操作:handleGithubIssue 执行|结果:显示错误消息并把状态置为 failed,按钮变为「重试提交」 - [ ] HP-1(正常路径)情境:管理员对一条反馈点击提交到 GitHub|操作:handleGithubIssue 执行|结果:记录 Issue 链接并把状态置为 submitted,按钮变为「查看 Issue」 ## 产品发布入口(总览页「发布产品」按钮打开对话框,勾选本次要宣布的功能(默认全选)后生成发布稿草稿并跳转发布卡校对;只读成员看到禁用按钮与权限说明,匿名演示访客不渲染该入口。) - [ ] EC-1(边界情况)情境:本次发布没有规格行为变化|操作:打开发布对话框|结果:提示无可宣布项,历史发布可在发布卡手动生成 - [ ] EC-2(边界情况)情境:匿名演示访客查看总览页|操作:渲染发布入口|结果:不渲染任何发布按钮或登录链接 - [ ] EC-3(边界情况)情境:登录只读成员查看总览页|操作:渲染发布入口|结果:显示禁用的「发布产品 · 需编辑权限」按钮 - [ ] EC-5(边界情况)情境:匿名 demo 访客查看总览页|操作:渲染发布入口|结果:不渲染任何发布入口,登录引导集中在顶栏 - [ ] ER-1(错误路径)情境:生成发布稿接口返回错误|操作:点击「生成发布稿」|结果:对话框内显示错误消息,不跳转 - [ ] ER-2(错误路径)情境:生成发布稿草稿的接口返回错误|操作:提交生成请求|结果:面板显示接口错误消息,不跳转发布卡 - [ ] HP-1(正常路径)情境:编辑者打开产品总览页|操作:点击「发布产品」|结果:打开发布对话框,列出本次发布的功能及新增/更新/移除计数,默认全选 - [ ] HP-2(正常路径)情境:发布对话框已勾选若干功能|操作:点击「生成发布稿」|结果:POST release-notes 生成草稿,成功后显示「去校对并发布 →」链接 - [ ] HP-3(正常路径)情境:编辑者打开产品总览页|操作:点击「发布产品」并勾选功能后生成草稿|结果:生成发布稿草稿并跳转到发布卡校对发布 ## 产品变化列表与发布卡(产品变化视图按发布倒序展示发布卡与行为变化,支持加载更多发布并导出 30 天变更索引。) - [ ] EC-1(边界情况)情境:产品还没有发布记录|操作:ProductChanges 渲染|结果:显示「还没有发布记录」空状态 - [ ] ER-1(错误路径)情境:加载更多发布失败|操作:点击加载更多|结果:显示「加载更多发布失败」错误 - [ ] HP-1(正常路径)情境:产品已有发布记录|操作:ProductChanges 渲染|结果:按发布展示发布卡与变化条目,并提供导出 30 天变更索引链接 - [ ] HP-2(正常路径)情境:发布总数超过已加载数量|操作:点击加载更多|结果:追加下一页发布与变化并更新剩余数量 ## 产品总览与产品页(登录用户在产品总览查看已接入产品、活跃功能与发布统计及最近变化。产品页展示标题、仓库链接、运行状态、漂移提示与各视图 Tab,公开演示产品可匿名只读浏览。) ## 产品总览仪表盘(按产品聚合当前规格与最新变化:能力清单、最新发布的行为变化统计与按功能分组、用户影响投影、发布时间线(连续零变化发布折叠)、任务入口与信任统计。) - [ ] EC-1(边界情况)情境:最近发布中某场景级变化的对侧证据全部来自测试/文档|操作:buildProductOverview 计算发布稿功能勾选计数|结果:该变化不计入 changeGroups,但发布时间线 changeStats 仍按全量统计 - [ ] EC-14(边界情况)情境:某功能影响文本已满每功能上限|操作:buildUserImpact 执行|结果:后续文本计入 moreCount,不再追加到 userImpacts - [ ] EC-15(边界情况)情境:界面语言为英文,某产品处于分析中且已有历史功能或发布|操作:查看产品卡片|结果:卡片显示英文「分析中,历史规格可查看」文案并保持可点击链接 - [ ] EC-2(边界情况)情境:界面语言为英文,最近变化列表为空|操作:查看最近变化区块|结果:显示英文空态提示「Release changes will appear here after the first code analysis completes.」 - [ ] EC-3(边界情况)情境:连续多条零行为变化发布|操作:buildProductOverview 执行|结果:折叠为 quiet-run 分组,单条零变化发布不分组 - [ ] EC-4(边界情况)情境:最新发布没有非空用户影响文本|操作:buildProductOverview 执行|结果:按确定性变化统计回退,不用更早发布的影响冒充 - [ ] ER-1(错误路径)情境:产品尚无任何发布|操作:buildProductOverview 执行|结果:userImpact.state 为 none,任务入口给出「尚无发布」等真实禁用原因 - [ ] HP-1(正常路径)情境:产品存在最近一次发布且含行为变化|操作:buildProductOverview 执行|结果:返回按功能聚合的发布稿勾选计数、发布时间线与用户影响投影 - [ ] HP-10(正常路径)情境:界面语言为 en 的用户打开仪表盘|操作:访问 /|结果:日期 chip 以英文格式显示当前日期(月/日/星期) - [ ] HP-11(正常路径)情境:用户以英文界面语言打开仪表盘|操作:访问首页仪表盘|结果:标题、副标题、添加产品按钮、统计卡标签与单位、区块标题说明以英文渲染,日期 chip 按英文格式显示 - [ ] HP-12(正常路径)情境:界面语言为英文,产品总览存在已接入产品|操作:打开产品总览页|结果:产品卡片的功能/发布计数单位与时间线日期以英文呈现 - [ ] HP-13(正常路径)情境:界面语言为英文,产品总览无任何产品|操作:打开产品总览页|结果:空态标题、正文与尾部提示以英文呈现,仍包含 npm run db:seed 命令 - [ ] HP-2(正常路径)情境:仪表盘存在产品与最近发布|操作:查看产品空间与最近变化区块|结果:ProductGrid 与 ReleaseTimeline 按传入 locale 渲染卡片、时间线与空状态文案 - [ ] HP-3(正常路径)情境:产品已有最新发布与行为变化|操作:buildProductOverview 执行|结果:返回能力清单、最新发布变化统计、按功能分组与发布时间线 - [ ] HP-4(正常路径)情境:最新发布存在已落库的用户影响文本|操作:buildProductOverview 执行|结果:按功能合并影响文本,每组最多 3 条并给出溢出计数,最多 3 个功能组 - [ ] HP-5(正常路径)情境:最新发布的变化中场景证据全为测试/文档|操作:buildProductOverview 执行|结果:该变化不进发布稿功能勾选计数,changeStats 仍计入全量 - [ ] HP-6(正常路径)情境:最新发布同时存在实现证据与测试佐证的影响文本|操作:buildProductOverview 执行|结果:实现证据的影响文本排在前面,测试佐证文本在有余位时补充 ## 产品总览页(产品页聚合本次发布用户影响、规格问答、快速导航、发布时间线、核心能力、覆盖率披露与知识健康面板,连续零变化发布折叠展示。) - [ ] EC-1(边界情况)情境:最新发布没有任何非空用户影响|操作:渲染用户影响区|结果:有行为变化时展示确定性功能级变化统计与发布深链,无行为变化时展示「本次未发现规格行为变化」 - [ ] EC-2(边界情况)情境:时间线中存在连续零行为变化发布|操作:渲染发布时间线|结果:连续零变化发布折叠为一组 details,展开后保留每个原始发布条目 - [ ] EC-3(边界情况)情境:产品尚无任何功能规格|操作:渲染核心能力面板|结果:显示「尚无功能规格。」 - [ ] HP-1(正常路径)情境:产品已有最新发布且落库了用户影响说明|操作:渲染 ProductOverview|结果:展示「本次发布对用户的影响」面板,按功能列出用户影响文本与前后差异深链 - [ ] HP-2(正常路径)情境:最新发布未附用户影响说明但检测到规格行为变化|操作:渲染用户影响面板|结果:展示变化处数与前 3 个功能的变化分组,并给出查看前后差异链接 - [ ] HP-3(正常路径)情境:产品已有功能规格|操作:渲染核心能力面板|结果:按场景覆盖排序列出功能名、场景数、来源(人工维护/代码生成)与简介,点击进入规格工作台 ## 产品成员与邀请(产品级成员邀请与移除:工作区 owner 邀请邮箱,已是用户则直接加入产品成员,否则生成 7 天邀请令牌并发邮件;成员面板列出工作区成员、产品成员与待接受邀请。) - [ ] EC-1(边界情况)情境:尝试移除属于工作区的成员|操作:removeProductMember 执行|结果:返回 organization_member,不删除产品成员行 - [ ] ER-1(错误路径)情境:接受邀请时登录邮箱与邀请邮箱不一致|操作:acceptProductInvitation 执行|结果:抛出 invitation_email_mismatch - [ ] HP-1(正常路径)情境:工作区 owner 邀请的邮箱已是注册用户|操作:inviteProductMember 执行|结果:直接写入 product_members 并返回 member_added,不发邮件 - [ ] HP-2(正常路径)情境:被邀请邮箱尚未注册|操作:inviteProductMember 执行|结果:写入待接受邀请、签发 7 天令牌并发送邀请邮件,返回 invitation_pending 与邀请链接 - [ ] HP-3(正常路径)情境:受邀用户携带有效令牌登录|操作:acceptProductInvitation 执行|结果:校验邮箱一致后写入产品成员并把邀请标记 accepted ## 产品成员管理(设置页展示工作区成员与产品级成员,owner 可邀请成员、取消邀请,可移除产品级成员。) - [ ] EC-1(边界情况)情境:邀请邮箱为空|操作:提交邀请|结果:提示「请输入邮箱」,不提交 - [ ] ER-1(错误路径)情境:邀请或移除成员接口失败|操作:提交操作|结果:显示对应失败错误消息 - [ ] HP-1(正常路径)情境:owner 在成员管理表单填写邮箱与角色|操作:点击邀请成员|结果:成员已加入或创建邀请并展示邀请链接 - [ ] HP-2(正常路径)情境:存在待接受邀请|操作:点击取消|结果:邀请取消并刷新页面 ## 产品改名与旧链接重定向(更新产品显示名与 slug,slug 变更时校验同工作区唯一并写入旧 slug 历史;旧 slug 访问按调用者可访问工作区解析到 canonical 地址。) - [ ] EC-1(边界情况)情境:新 slug 与同工作区其他产品冲突|操作:updateProductIdentity 执行|结果:返回 slug_conflict,不更新 - [ ] HP-1(正常路径)情境:工作区内的产品需要改 slug|操作:updateProductIdentity 执行|结果:更新 products 行并把旧 slug 写入 product_slug_history,返回 updated - [ ] HP-2(正常路径)情境:用户访问已改名的旧 slug 链接|操作:findProductByOldSlug 执行|结果:返回调用者可访问且优先当前工作区的现 slug 与 orgSlug - [ ] HP-3(正常路径)情境:产品需要切换分析输出语言|操作:updateProductIdentity 以 outputLanguage 执行部分更新|结果:UPDATE 语句以 COALESCE 写入 output_language,返回 updated,名称与 slug 不变 ## 产品标识设置(设置页可修改产品显示名与 slug,保存后按新地址跳转,旧链接自动重定向。) - [ ] EC-1(边界情况)情境:产品名称为空白|操作:点击保存|结果:提示「请输入产品名称」,不提交 - [ ] ER-1(错误路径)情境:重命名接口失败|操作:点击保存|结果:显示保存失败错误消息 - [ ] HP-1(正常路径)情境:编辑者在设置页修改产品名称|操作:点击保存|结果:保存成功并提示「产品信息已保存」 - [ ] HP-2(正常路径)情境:编辑者修改了 slug|操作:点击保存|结果:跳转到新 slug 的设置页 ## 产品概况人工维护(人工编辑产品概况时写入 manual 来源并清空自动证据,自动分析不覆盖非空人工文本。) - [ ] ER-1(错误路径)情境:产品不属于该工作区|操作:updateProductDescription 执行|结果:返回 null - [ ] HP-1(正常路径)情境:工作区成员编辑产品概况|操作:updateProductDescription 执行|结果:写入 description 并标记 description_source=manual ## 产品注册与移除(注册产品时解析仓库、读取默认分支头并在事务内写入产品与仓库,按工作区默认触发模式继承;移除产品时校验归属与进行中分析,并在无同名共享产物时清理生成文件。) - [ ] EC-1(边界情况)情境:首次分析入队被额度闸门拒绝|操作:registrationError 执行|结果:quota_exceeded 映射为 402 并提示升级套餐或购买超额包 - [ ] EC-2(边界情况)情境:注册请求未指定输出语言且工作区默认输出语言为 en|操作:registerProduct 执行|结果:products 行继承工作区默认,写入 output_language=en - [ ] EC-3(边界情况)情境:注册请求未指定输出语言且工作区无默认值|操作:registerProduct 执行|结果:回退写入 output_language=zh-CN - [ ] EC-4(边界情况)情境:存量工作区未配置默认语言。|操作:读取 default_output_language。|结果:取默认值 zh-CN。 - [ ] ER-1(错误路径)情境:产品 slug 或仓库已注册|操作:registrationError 执行|结果:返回 409 产品 Slug 或代码仓库已经注册 - [ ] ER-2(错误路径)情境:产品存在 queued 或 running 分析|操作:removeProduct 执行|结果:抛出 409 当前产品正在分析,请完成后再移除 - [ ] HP-1(正常路径)情境:仓库可读且输入合法|操作:registerProduct 执行|结果:事务内写入产品与仓库行,返回 slug、repositoryId 与 afterSha - [ ] HP-2(正常路径)情境:注册时勾选立即分析|操作:queueRegistrationAnalysis 执行|结果:以 manual 来源入队首次分析并返回 run - [ ] HP-3(正常路径)情境:注册请求显式指定输出语言|操作:registerProduct 执行|结果:products 行以请求语言写入 output_language - [ ] HP-4(正常路径)情境:工作区已设置 default_output_language。|操作:在该工作区注册新产品且未显式指定语言。|结果:新产品 output_language 继承工作区默认值。 ## 产品注册入口与凭据前置校验(添加产品页在无 GitHub 连接或服务器 Token 时引导先连接 GitHub,具备凭据后展示产品信息、仓库选择与立即分析选项的表单。) - [ ] EC-1(边界情况)情境:工作区无任何 GitHub 凭据|操作:打开添加产品页|结果:显示「先连接 GitHub」引导卡片与 Integrations 链接 - [ ] EC-2(边界情况)情境:工作区未设置默认输出语言|操作:打开新建产品页|结果:defaultOutputLanguage 为可选属性,表单按缺省语言处理 - [ ] EC-3(边界情况)情境:界面语言为英文,已具备 GitHub 凭据|操作:打开添加产品页|结果:渲染添加产品表单,表单内文案为英文 - [ ] ER-1(错误路径)情境:创建产品接口失败|操作:提交产品表单|结果:显示「添加产品失败」错误消息 - [ ] HP-1(正常路径)情境:工作区已有 GitHub 连接或服务器 Token|操作:打开添加产品页|结果:渲染产品创建表单 - [ ] HP-2(正常路径)情境:工作区默认输出语言为 en|操作:打开添加产品页|结果:表单「分析输出语言」下拉默认选中 English,提交时随创建请求携带 - [ ] HP-3(正常路径)情境:工作区成员打开新建产品页|操作:页面加载并渲染新建产品表单|结果:表单预填工作区默认输出语言,注册产品继承该默认值 - [ ] HP-4(正常路径)情境:editor 以英文界面语言打开新建产品页|操作:访问 /products/new|结果:返回链接、标题、副标题以英文渲染,NewProductContent 按传入 locale 渲染 - [ ] HP-5(正常路径)情境:界面语言为英文,未安装 GitHub App 且无服务端令牌|操作:打开添加产品页|结果:显示英文「Connect GitHub first」标题、说明与「Open Integrations」链接 ## 产品注册提交区(添加产品表单提供「添加后立即分析」选项,提交按钮按是否立即分析显示不同文案,失败显示错误消息。) - [ ] ER-1(错误路径)情境:创建产品接口失败|操作:提交产品表单|结果:显示错误消息 - [ ] HP-1(正常路径)情境:用户填写产品信息|操作:勾选添加后立即分析并提交|结果:提交按钮显示分析态文案,成功后进入产品页 ## 产品视图导航与工作区切换(产品页按 view 参数在概览、产品地图、产品规格、发布稿、发布变化与设置之间切换,发布稿入口仅在存在发布时出现,设置入口按权限展示。) - [ ] EC-1(边界情况)情境:产品尚无任何发布|操作:渲染 ProductTabs|结果:不渲染发布稿入口,发布变化入口计数为 0 - [ ] EC-2(边界情况)情境:当前用户无编辑权限|操作:渲染 ProductTabs|结果:不渲染设置入口 - [ ] EC-3(边界情况)情境:选择发布稿视图但产品没有最新发布|操作:渲染 ProductView|结果:显示「尚无发布,先生成一次分析。」 - [ ] HP-1(正常路径)情境:产品已有发布且当前用户可编辑|操作:渲染 ProductTabs 与 ProductView|结果:展示概览、产品地图、产品规格、发布稿、发布变化与设置入口,并按 view 渲染对应视图 ## 产品移除(设置页可移除产品:二次确认后调用删除接口,成功跳回首页,失败显示错误消息。) - [ ] EC-1(边界情况)情境:尚未确认移除|操作:渲染移除控件|结果:只显示「移除产品」按钮,不显示确认框 - [ ] ER-1(错误路径)情境:删除接口失败|操作:点击确认移除|结果:显示接口错误消息或「移除产品失败」,停留在当前页 - [ ] HP-1(正常路径)情境:编辑者点击移除产品|操作:在确认框点击确认移除|结果:调用删除接口成功后跳转首页并刷新 ## 产品简介编辑(在产品页头部展示产品简介全文,空简介对编辑者显示引导文案;编辑者可通过 ✎ 打开对话框手写或由 AI 生成简介,保存后刷新页面。) - [ ] EC-1(边界情况)情境:产品简介为空且当前用户可编辑|操作:渲染产品页头部|结果:显示「尚无产品简介——点击 ✎ 由 AI 生成或手写。」与编辑入口 - [ ] EC-2(边界情况)情境:产品简介为空且当前用户不可编辑|操作:渲染产品页头部|结果:不渲染简介行 - [ ] EC-3(边界情况)情境:产品简介超过 90 字|操作:渲染产品页头部|结果:仍全文展示,不出现截断或「展开全文」按钮 - [ ] EC-4(边界情况)情境:只读或匿名用户查看有简介的产品页|操作:查看简介行|结果:简介全文展示,不显示编辑入口,也不显示展开/收起按钮。 - [ ] ER-1(错误路径)情境:保存简介时接口返回错误|操作:在编辑对话框点击保存|结果:对话框内显示错误消息,保持打开可重试 - [ ] HP-1(正常路径)情境:产品已有非空简介且当前用户可编辑|操作:渲染产品页头部|结果:简介全文展示,右侧显示 ✎ 编辑入口 - [ ] HP-2(正常路径)情境:编辑者点击 ✎ 打开编辑对话框|操作:修改内容并点击保存|结果:调用 updateDescription 保存后关闭对话框并刷新页面 - [ ] HP-3(正常路径)情境:编辑者打开有简介的产品页|操作:查看简介行|结果:简介全文展示,右侧显示 ✎ 编辑入口。 ## 产品管理与成员管理客户端(前端完成产品创建、删除、概况与改名、公开演示开关、成员与邀请管理、手动分析与仓库触发模式设置。) - [ ] EC-1(边界情况)情境:产品名含大写与符号|操作:slugifyProductName 执行|结果:转为小写连字符 slug 并截断 64 字符 - [ ] ER-1(错误路径)情境:分析请求被额度闸门拒绝|操作:requestAnalysis 执行|结果:抛出带友好中文 message 的错误 - [ ] ER-2(错误路径)情境:删除产品响应状态不是 deleted|操作:deleteProduct 执行|结果:抛出接口 error 或「移除产品失败」 - [ ] ER-3(错误路径)情境:保存输出语言接口返回错误|操作:setOutputLanguage 执行|结果:抛出接口 error 或「保存输出语言设置失败」 - [ ] HP-1(正常路径)情境:需要添加产品|操作:createProduct 执行|结果:返回新产品的 slug - [ ] HP-2(正常路径)情境:需要改产品名或 slug|操作:renameProduct 执行|结果:返回新 slug 与 organizationSlug 供跳转 - [ ] HP-3(正常路径)情境:需要手动触发分析|操作:requestAnalysis 执行|结果:返回 runId - [ ] HP-4(正常路径)情境:需要切换产品分析输出语言|操作:setOutputLanguage 执行|结果:PATCH /api/products/[slug] 携带 outputLanguage,返回 updated ## 产品行为地图(产品行为地图(B3.2,docs/product-map-plan.md §4):功能树节点 + B3 确定性连接边的产品级一页合成。) - [ ] EC-1(边界情况)情境:连接边总数超过 60 条|操作:buildProductMap 执行|结果:只保留权重前 60 条边,truncatedEdgeCount 显式记录被截断数量 - [ ] EC-2(边界情况)情境:顶层功能之间没有任何共享证据连接|操作:clusterOrder 执行|结果:保持功能树原有名称序,不做聚簇重排 - [ ] HP-1(正常路径)情境:产品已有功能、场景与共享证据文件|操作:buildProductMap 执行|结果:返回按连接强度聚簇分带的节点布局与按共享引用数降序的边,前 20 条强连接默认可见 ## 产品行为地图连线降噪开关(产品行为地图的客户端开关:默认用 CSS 隐藏前 N 条强连接之外的连线,点击后仅切换容器类名展开全部连线,不发起数据请求。) - [ ] EC-1(边界情况)情境:地图无被折叠的额外连线|操作:渲染地图|结果:不渲染开关按钮 - [ ] HP-1(正常路径)情境:地图存在被折叠的额外连线|操作:点击「显示全部连线(+N)」|结果:容器切换为 map--all-edges,全部连线显示,按钮变为「只看强连接」 ## 产品访问鉴权(工作区成员按组织角色、非成员按 product_members 授权行鉴权;URL 携带 org 段时以 URL 为权威,无权限一律返回 null 由调用方按 404 处理。) - [ ] EC-1(边界情况)情境:URL 携带 org 段且调用者属于该工作区|操作:requireProductAccess 执行|结果:按 URL 工作区鉴权,不依赖 cookie 当前工作区 - [ ] ER-1(错误路径)情境:产品不存在、跨工作区或角色不足|操作:requireProductAccess 执行|结果:返回 null,由调用方按 404 处理 - [ ] HP-1(正常路径)情境:调用者是产品所属工作区成员且角色足够|操作:requireProductAccess 执行|结果:返回产品、真实所属工作区与 via=organization 的访问结果 - [ ] HP-2(正常路径)情境:调用者不是工作区成员但持有产品级成员授权|操作:requireProductAccess 执行|结果:返回 via=product 的访问结果与产品级角色 ## 产品详情与发布变化读取(按产品读取功能、场景、发布、行为变化与折叠差异,为证据补 blob 链接并标注疑似改名;发布变化支持按 offset 分页加载。) - [ ] EC-1(边界情况)情境:发布对应的规格版本无覆盖率回执|操作:getProductDetails 执行|结果:沿版本链向上取最近有效回执,合成零回执视为无 - [ ] ER-1(错误路径)情境:产品 slug 不存在或不属于指定工作区|操作:getProductDetails 执行|结果:返回 null - [ ] HP-1(正常路径)情境:产品已有功能、场景与发布数据|操作:getProductDetails 执行|结果:返回产品、仓库、最新运行、功能与场景、发布、行为变化、回归任务、折叠差异与覆盖率回执 - [ ] HP-2(正常路径)情境:需要加载更多发布变化|操作:loadReleasePage 执行|结果:按 offset 与 limit 返回与首屏同构的发布、变化与折叠差异 - [ ] HP-3(正常路径)情境:产品行已设置输出语言|操作:getProductDetails 执行|结果:返回的 product 含 outputLanguage 字段供设置页展示 ## 产品说明单页渲染(把产品总览数据渲染为自带主题切换与打印样式的纯文本 Explainer 单页,含能力、最近变化与证据覆盖率三块。) - [ ] EC-1(边界情况)情境:本次分析未发现规格行为变化|操作:renderProductExplainerHtml 执行|结果:最近变化区显示「本次分析未发现规格行为变化。」 - [ ] HP-1(正常路径)情境:产品已有能力、变化与可信度数据|操作:renderProductExplainerHtml 执行|结果:输出含核心能力表、最近变化表与证据覆盖率表的 HTML 单页 ## 产品输出语言设置面板(产品设置页提供分析输出语言面板:展示中文与 English 选项及全量重建提示,保存后刷新页面;只读成员不渲染该面板。) - [ ] EC-1(边界情况)情境:产品只读成员打开产品设置页|操作:渲染 ProductOutputLanguageSettings|结果:canEdit 为 false 时组件返回 null,不渲染面板 - [ ] ER-1(错误路径)情境:保存输出语言接口返回错误|操作:点击保存|结果:显示接口错误消息或「保存输出语言设置失败」 - [ ] HP-1(正常路径)情境:产品编辑者打开产品设置页|操作:选择 English 并保存|结果:调用 setOutputLanguage 提交 PATCH,成功后提示下一次分析将全量重建为新语言版本并刷新页面 ## 产品页地址构造(站内产品页链接统一经 helper 构造为 /products/{orgSlug}/{slug} 的 canonical 地址,slug 单段地址降级为重定向入口。) - [ ] HP-1(正常路径)情境:需要为产品页生成站内链接|操作:productBasePath 执行|结果:返回 /products/{orgSlug}/{slug},两段均做 URL 编码 ## 产品页头部与演示只读入口(产品页头部按访问者身份决定写入口:编辑者见可用的分析按钮,登录只读成员见禁用按钮与权限说明,匿名演示访客不渲染任何写入口,登录引导集中在演示外壳顶栏。) - [ ] EC-1(边界情况)情境:匿名演示访客打开演示产品页|操作:渲染头部操作区|结果:不渲染分析按钮、只读提示与登录链接,页面标记 data-can-edit=false - [ ] EC-2(边界情况)情境:登录只读成员打开产品页|操作:渲染头部操作区|结果:显示禁用的「发起分析 · 需编辑权限」按钮与只读权限说明 - [ ] ER-1(错误路径)情境:分析请求失败|操作:点击「立即分析」|结果:显示错误消息,按钮恢复可用 - [ ] ER-2(错误路径)情境:分析因额度不足被拒绝|操作:点击「立即分析」|结果:显示额度不足提示与升级套餐链接 - [ ] ER-3(错误路径)情境:匿名 demo 访客尝试触发写操作|操作:服务端校验写权限|结果:服务端拒绝写请求,demo guard 与服务端校验仍是最终边界 - [ ] HP-1(正常路径)情境:编辑者打开产品页|操作:渲染头部操作区|结果:显示可点击的「立即分析」主按钮 - [ ] HP-2(正常路径)情境:编辑者点击「立即分析」|操作:请求分析接口|结果:提示「分析已排队,稍后刷新查看」并刷新页面 - [ ] HP-3(正常路径)情境:编辑者访问产品页|操作:渲染头部写操作入口|结果:显示可用的分析、编辑与发布入口 - [ ] HP-5(正常路径)情境:匿名演示访客打开公开演示产品页|操作:渲染产品页头部|结果:页面以 data-can-edit=false 渲染,不出现分析登录引导与发布入口 ## 产品页头部与简介展示(产品页头部整合简介行:全文展示不截断,编辑者可见 ✎ 编辑入口,空简介对编辑者给生成提示、对只读用户不渲染占位。) - [ ] EC-1(边界情况)情境:产品简介为空|操作:buildProductOverview 执行|结果:headline 回退为「产品概览」 - [ ] EC-2(边界情况)情境:产品简介为空且当前用户可编辑|操作:渲染产品简介行|结果:显示「尚无产品简介——点击 ✎ 由 AI 生成或手写」与编辑入口 - [ ] EC-3(边界情况)情境:产品简介为空且当前用户只读|操作:渲染产品简介行|结果:不渲染任何占位内容 - [ ] EC-5(边界情况)情境:场景证据为空数组|操作:isTestOnlyEvidence 执行|结果:返回 false,不显示测试佐证徽标 - [ ] ER-1(错误路径)情境:保存产品简介接口失败|操作:在编辑对话框点击保存|结果:对话框内显示错误消息,保持打开可重试 - [ ] HP-1(正常路径)情境:产品简介由分析生成并带证据|操作:buildProductOverview 执行|结果:headline 取简介文本,headlineSource 为 generated,headlineEvidence 返回证据路径 - [ ] HP-2(正常路径)情境:产品已有简介且当前用户可编辑|操作:渲染产品简介行|结果:展示完整简介文本与 ✎ 编辑入口 - [ ] HP-3(正常路径)情境:场景证据全部来自测试/文档|操作:渲染规格工作台场景卡片|结果:场景标签行显示「测试佐证」徽标,悬停说明行为以人工核实为准 ## 介绍材料生成(休眠)(从行为账本组装事实清单、生成带锚点的 PPT 大纲并做锚定校验与 Markdown/HTML 渲染;模块已按用户裁决暂停,保留为休眠资产。) - [ ] ER-1(错误路径)情境:大纲某页锚定的功能或变化不在事实清单内|操作:validateIntroDraft 执行|结果:返回 ok=false 并指出该页锚定对象不在事实清单内 - [ ] ER-2(错误路径)情境:模型输出不含 JSON 结构或不符合 schema|操作:parseIntroMaterial 执行|结果:抛出「AI 输出不含 JSON 结构」或「AI 大纲结构不合格」错误 - [ ] HP-1(正常路径)情境:产品已有功能、场景与带 Highlight 的行为变化|操作:buildIntroFactPack 执行|结果:返回按场景数排序截断的功能事实、去重后的亮点变化、最新发布与可信度统计 - [ ] HP-2(正常路径)情境:已生成大纲草稿且事实清单完整|操作:validateIntroDraft 执行|结果:锚点均可解析、首页 COVER 末页 BACK_COVER 时返回 ok ## 仓库分析触发模式设置(设置页按仓库选择分析触发模式(每次 push / 每天低峰一次 / 每 N 次 push + 当天兜底),可设阈值与低峰小时并显示待分析推送数。) - [ ] EC-1(边界情况)情境:选择每 N 次 push 模式|操作:渲染设置表单|结果:显示每 N 次推送下拉(3/5/10)与低峰分析时间下拉 - [ ] EC-2(边界情况)情境:当前用户无编辑权限或产品无仓库|操作:渲染触发设置面板|结果:不渲染该面板 - [ ] ER-1(错误路径)情境:保存触发设置接口失败|操作:点击保存|结果:显示接口错误消息或「保存分析触发设置失败」 - [ ] HP-1(正常路径)情境:编辑者在设置页查看仓库触发设置|操作:选择触发模式并点击保存|结果:保存成功提示「分析触发设置已保存」并刷新页面 ## 代码仓库连接管理(以访问令牌接入 Gitee、GitLab 或自有 Gitea 仓库,校验凭据后加密保存连接,支持列出、重新检查与删除;检查失败把连接标记为 disconnected。) - [ ] EC-1(边界情况)情境:自有 Git 服务地址不是 HTTPS 或含账号、查询参数|操作:normalizeRepositoryConnectionInput 执行|结果:抛出 400 提示必须使用 HTTPS 且地址不得含账号密码或查询参数 - [ ] EC-2(边界情况)情境:自有 Git 服务主机不在 REPOSITORY_HOST_ALLOWLIST|操作:assertAllowedRepositoryHost 执行|结果:抛出 400 提示联系管理员配置主机白名单 - [ ] ER-1(错误路径)情境:连接不存在或不属于当前工作区|操作:checkRepositoryConnection 执行|结果:返回 404 连接不存在或不属于当前工作区 - [ ] ER-2(错误路径)情境:凭据校验失败或平台不可用|操作:checkRepositoryConnection 执行|结果:连接标记 disconnected 并返回 503 与错误消息 - [ ] HP-1(正常路径)情境:用户提交有效的平台类型、服务地址与访问令牌|操作:createRepositoryConnection 执行|结果:校验账号后加密保存连接并返回 active 与账号登录名 - [ ] HP-2(正常路径)情境:已保存的连接需要重新检查|操作:checkRepositoryConnection 执行|结果:校验通过后刷新账号信息并返回 active ## 令牌式代码托管连接(集成页以私人令牌连接 Gitee 或自有 Git 服务(GitLab/Gitea):填写平台类型、服务地址与令牌后验证并加密保存,列出已保存连接与状态,可执行连接操作。) - [ ] EC-1(边界情况)情境:尚无已保存连接|操作:渲染连接列表|结果:显示「还没有已保存的连接。」 - [ ] EC-2(边界情况)情境:自有服务未配置主机白名单|操作:渲染连接指引|结果:提示需联系管理员设置 REPOSITORY_HOST_ALLOWLIST,GitLab.com 可直接连接 - [ ] EC-3(边界情况)情境:当前用户为查看者|操作:渲染集成卡片|结果:不显示连接表单,提示联系编辑者或所有者配置 - [ ] ER-1(错误路径)情境:连接保存失败|操作:提交连接表单|结果:显示接口错误消息或「连接保存失败」 - [ ] HP-1(正常路径)情境:编辑者在集成页填写令牌|操作:点击验证并保存连接|结果:验证账号后保存并提示已连接账号,刷新连接列表 ## 公开演示开关(设置页可开启或关闭产品公开演示:开启后任何人可匿名查看产品全部内容,编辑操作只作演示不保存。) - [ ] EC-1(边界情况)情境:公开演示已开启|操作:渲染设置面板|结果:显示公网可见风险提示 - [ ] EC-2(边界情况)情境:当前用户无管理权限|操作:渲染设置面板|结果:不渲染该面板 - [ ] ER-1(错误路径)情境:保存公开演示设置失败|操作:点击开启或关闭|结果:显示接口错误消息或「保存公开演示设置失败」 - [ ] HP-1(正常路径)情境:有管理权限的成员在设置页|操作:点击开启或关闭公开演示|结果:调用设置接口并刷新,状态显示公开中或未公开 ## 公开演示访问(产品可标记为公开演示,匿名访问按 (orgSlug, slug) 精确解析仅放行 demo 产品,环境变量白名单作为过渡兜底,登录页展示 demo 入口。) - [ ] EC-1(边界情况)情境:产品存在但未标记 demo 且不在环境变量白名单|操作:resolvePublicDemoProduct 执行|结果:返回 null,匿名访问不放行 - [ ] EC-2(边界情况)情境:旧一段地址无 org 段且跨工作区存在同名产品|操作:resolveLegacyPublicDemoProduct 执行|结果:取第一个公开 demo 行解析,非 demo 返回 null - [ ] HP-1(正常路径)情境:产品已在设置中标记为公开演示|操作:resolvePublicDemoProduct 执行|结果:返回该产品的 id、slug、名称与所属工作区 slug,供匿名只读渲染 - [ ] HP-2(正常路径)情境:登录页需要展示公开演示入口|操作:loadPublicDemoProduct 执行|结果:优先返回数据库标记的 demo 产品,无则取环境变量白名单首个,都没有返回 null ## 凭据加密存储(以 SESSION_SECRET 派生密钥对敏感凭据做 AES-256-GCM 加密,密文含随机 IV 与认证标签并以 base64url 存储,解密时校验完整性。) - [ ] ER-1(错误路径)情境:密文被篡改或密钥不匹配|操作:decryptSecret 执行|结果:认证标签校验失败抛错,不返回明文 - [ ] HP-1(正常路径)情境:需要保存访问令牌等敏感凭据|操作:encryptSecret 执行|结果:返回含 IV、认证标签与密文的 base64url 字符串 - [ ] HP-2(正常路径)情境:需要读取已保存的凭据|操作:decryptSecret 执行|结果:校验认证标签后返回明文 ## 分析失败解释与上报(把分析失败的技术错误归类为可读人话与下一步指引,区分是否值得自动上报,并按类别与首因生成去重签名。) - [ ] EC-1(边界情况)情境:失败原因为被更新的分析取代|操作:explainRunFailure 执行|结果:返回 superseded 类别且 reportable=false,不自动上报 - [ ] EC-2(边界情况)情境:错误信息不属于任何已知类别|操作:explainRunFailure 执行|结果:兜底为 unknown 类别,提示意外错误并标记可上报 - [ ] HP-1(正常路径)情境:分析失败原因为 AI 输出结构不符合 schema|操作:explainRunFailure 执行|结果:返回 ai_output_format 类别、可读提示与 reportable=true - [ ] HP-2(正常路径)情境:同类同因的失败需要合并上报|操作:runFailureSignature 执行|结果:zod 错误取首个 path 与 code 生成签名,其余取首行前 120 字符 ## 分析完整性账本(run 级汇总一次成功分析完成了什么、没完成什么:六维度各自 complete/partial/failed/not_applicable,整体状态取最差维度,禁止合并成单一百分比;账本随 run 成功 best-effort 落库,可按 run 或规格版本读取。) - [ ] EC-1(边界情况)情境:实现文件装配数为 0|操作:deriveSourceCoverage 执行|结果:sourceCoverage 状态为 failed - [ ] EC-2(边界情况)情境:分区被截断或 diff 有省略路径|操作:deriveSourceCoverage 执行|结果:sourceCoverage 状态为 partial - [ ] EC-3(边界情况)情境:某趟候选全部被证据清洗拒绝|操作:deriveEvidenceIntegrity 执行|结果:evidenceIntegrity 状态为 failed,并累计 allCandidatesRejectedPasses - [ ] EC-4(边界情况)情境:增量 run 未执行 M9 影子且无结果冲突|操作:deriveVerification 执行|结果:verification 状态为 not_applicable,humanVerification 固定为 external - [ ] ER-1(错误路径)情境:账本写入数据库失败|操作:saveCompletenessLedger 执行|结果:异常上抛,由调用方 best-effort 处理,不回滚分析 - [ ] HP-1(正常路径)情境:一次分析 run 成功且各维度数据齐备|操作:saveCompletenessLedger 执行|结果:写入 analysis_completeness_ledger,六维度状态与 overall 一并落库 - [ ] HP-2(正常路径)情境:需要查看某次分析的完整性|操作:loadCompletenessLedger 或 loadCompletenessLedgerBySpecVersion 执行|结果:返回该 run 的六维度状态、overall 与 details;无记录返回 null ## 分析完整性账本展示(把分析完整性账本六维度(源码覆盖、行为枚举、提取完成度、证据完整性、合并完整性、核验)解析为视图形状,给出总体文案、问题短因清单与维度状态行。) - [ ] EC-1(边界情况)情境:账本 details 结构不符或状态值非法|操作:toLedgerDetailsView 执行|结果:返回 null,不渲染维度 - [ ] HP-1(正常路径)情境:账本六维度全部 complete|操作:describeLedgerOverall 执行|结果:返回「完整分析」与 ok 语气 - [ ] HP-2(正常路径)情境:存在 partial/failed 维度|操作:summarizeLedgerIssues 执行|结果:按固定维度顺序返回「标签:短因」清单,可隐藏已在别处披露的维度 ## 分析覆盖率回执与继承(读取最新规格版本的场景级全文作为分析锚,加载失败降级为仅命名约束不阻塞分析;受影响功能优先装入锚,保证 24k 预算先覆盖它们。) - [ ] EC-1(边界情况)情境:分析运行无覆盖率回执|操作:buildProductOverview 执行|结果:coverageByte 与 coverageFiles 为 null,不展示覆盖率行 - [ ] EC-2(边界情况)情境:本次分析无覆盖率回执|操作:渲染总览信任行|结果:覆盖率位置显示「源码装配覆盖率 —(无覆盖率回执)」 - [ ] EC-3(边界情况)情境:上一版为回填快照或沿用版本,无有效回执|操作:loadInheritedCoverageReceipt 执行|结果:沿版本链向上最多回看 10 版,跳过 implFilesTotal=0 的合成零回执,取最近有效回执 - [ ] EC-4(边界情况)情境:提取趟数达到上限|操作:isCoverageCapped 执行|结果:返回 true,展示层显式警示本规格未覆盖全部实现面 - [ ] EC-5(边界情况)情境:分区被截断或 diff 有未选路径|操作:deriveSourceCoverage 执行|结果:状态为 partial,并保留 diffTotalPaths/diffSelectedPaths/diffOmittedPaths 计数 - [ ] EC-6(边界情况)情境:传入的受影响功能名在上一版规格中不存在|操作:loadPreviousSpecText 执行|结果:无命中,功能顺序保持原 position 序不变 - [ ] EC-7(边界情况)情境:仓库没有任何规格版本|操作:loadPreviousSpecText 执行|结果:返回空数组,锚定降级为仅命名约束 - [ ] ER-1(错误路径)情境:版本链上全部回执均无效|操作:loadInheritedCoverageReceipt 执行|结果:返回 null - [ ] ER-2(错误路径)情境:未装配任何实现文件|操作:deriveSourceCoverage 执行|结果:状态为 failed - [ ] ER-3(错误路径)情境:读取上一版规格文本抛错|操作:runAnalysisBody 加载锚|结果:记录错误日志,previousSpecText 置空,本次分析不因锚加载失败而中断 - [ ] HP-1(正常路径)情境:分析运行带覆盖率回执|操作:buildProductOverview 执行|结果:返回 coverageByte 与 coverageFiles 展示标签 - [ ] HP-2(正常路径)情境:本次分析产生覆盖率回执|操作:渲染总览信任行|结果:展示源码装配覆盖率字节、证据文件数与 Spec 版本号 - [ ] HP-3(正常路径)情境:分析完成并写入规格版本|操作:computeCoverageReceipt 与 saveCoverageReceipt 执行|结果:回执记录装配文件数/字节、总面、覆盖率、趟数与 diff 覆盖口径并落库 - [ ] HP-4(正常路径)情境:分析 run 完成源码装配|操作:deriveSourceCoverage 执行|结果:覆盖率回执含 implFilesAssembled/implFilesTotal/coverageRatio,全部装配且未截断时状态为 complete - [ ] HP-5(正常路径)情境:仓库已有上一版规格且本次为增量分析|操作:loadPreviousSpecText 传入受影响功能名执行|结果:受影响功能按传入顺序排最前,其余功能保持 position 序返回 - [ ] HP-6(正常路径)情境:仓库已有上一版规格且本次为全量分析|操作:loadPreviousSpecText 不传 prioritize 执行|结果:全部功能按 position 序返回场景全文锚 ## 分析触发模式与兜底 sweep(按仓库触发模式(push/daily/push_count)决定 push 后立即分析或延后,首分析任何模式都立即派发;每小时 sweep 对当天仍有未处理 push 的仓库排队累计分析,失败保留 pending 下小时重试。) - [ ] EC-1(边界情况)情境:sweep 时 before 与 after 相同或无提交|操作:runAnalysisTriggerSweepOnce 执行|结果:noCommits 计数加一并清零 pending,不排队 - [ ] ER-1(错误路径)情境:单仓库排队失败(如额度闸门拒绝)|操作:runAnalysisTriggerSweepOnce 执行|结果:deferredSkip 计数加一、错误入 errors,pending 保留下小时重试 - [ ] HP-1(正常路径)情境:仓库尚无成功分析|操作:resolvePushTriggerAction 执行|结果:返回 immediate,接入即见规格 - [ ] HP-3(正常路径)情境:daily/push_count 仓库当天有未处理 push 且到达触发小时|操作:runAnalysisTriggerSweepOnce 执行|结果:以 before=上次成功 SHA、after=当前 HEAD 排队一次累计分析并清零 pending ## 分析输出语言设置(产品级与工作区级分析输出语言设置:语言枚举限定简体中文与 English,产品设置页可切换本产品语言并提示下一次分析全量重建,工作区设置页可改新仓库默认语言,接口按编辑权限校验。) - [ ] EC-1(边界情况)情境:只读成员(viewer)打开设置页或产品设置页|操作:渲染输出语言面板|结果:面板返回空,不渲染任何语言选项 - [ ] EC-2(边界情况)情境:提交不受支持的语言值(如 fr 或 zh)|操作:PATCH 产品或工作区默认语言接口|结果:schema 校验失败返回 400,不写入数据库 - [ ] EC-3(边界情况)情境:注册时既未指定输出语言且工作区无默认值|操作:registerProduct 执行|结果:回退写入 zh-CN - [ ] EC-6(边界情况)情境:viewer 调用工作区默认输出语言 PATCH|操作:请求 /api/settings/output-language-default|结果:返回 403 只有工作区成员可以修改此设置,不更新 - [ ] ER-1(错误路径)情境:非工作区编辑者调用工作区默认语言接口|操作:PATCH /api/settings/output-language-default|结果:返回 403「只有工作区成员可以修改此设置」,不更新 - [ ] ER-2(错误路径)情境:保存产品输出语言接口返回错误|操作:产品设置页点击保存|结果:展示接口错误消息或「保存输出语言设置失败」 - [ ] ER-4(错误路径)情境:保存工作区默认输出语言失败|操作:设置页保存|结果:显示接口错误消息或「保存默认输出语言失败」 - [ ] HP-1(正常路径)情境:工作区编辑者打开设置页|操作:渲染「新仓库默认输出语言」面板并选择 English 后保存|结果:PATCH /api/settings/output-language-default 返回 updated,提示此后新接入产品继承此语言 - [ ] HP-10(正常路径)情境:编辑者打开产品设置页|操作:渲染分析输出语言面板|结果:显示中文(简体)与 English 两个选项、当前语言选中,并提示切换后下一次分析全量重建、历史版本保持原语言 - [ ] HP-11(正常路径)情境:编辑者把产品输出语言从中文切换为 English|操作:点击保存|结果:调用 setOutputLanguage 提交 PATCH,成功后提示已保存并刷新页面 - [ ] HP-12(正常路径)情境:工作区编辑者打开设置页|操作:渲染新仓库默认输出语言面板|结果:显示两个语言选项与当前默认值,说明此后新接入产品继承此设置、已有产品不受影响 - [ ] HP-13(正常路径)情境:工作区查看者读取默认输出语言|操作:GET /api/settings/output-language-default|结果:返回 status=ok 与当前语言,缺省为 zh-CN - [ ] HP-14(正常路径)情境:注册新产品时未显式指定输出语言|操作:registerProduct 执行|结果:继承工作区 default_output_language 写入 products.output_language,均无则回退 zh-CN - [ ] HP-15(正常路径)情境:分析 run 已加载产品输出语言|操作:runAnalysisBody 调用 analyzeWithAI|结果:提取上下文携带 outputLanguage,按产品语言生成规格与发布稿 - [ ] HP-2(正常路径)情境:产品编辑者打开产品设置页|操作:在「分析输出语言」面板切换语言并保存|结果:调用 setOutputLanguage 提交 PATCH,提示下一次分析将全量重建为新语言版本、历史版本保持原语言 - [ ] HP-3(正常路径)情境:注册新产品且工作区默认输出语言为 en|操作:打开添加产品页|结果:表单「分析输出语言」默认选中 English,提交时随产品创建请求携带 outputLanguage ## 功能实现文件聚合(按实现文件聚合一组场景的证据:路径去重、行区间合并计数、场景编号归并,供规格页展示实现面。) - [ ] EC-1(边界情况)情境:证据条目缺少行号|操作:aggregateImplementationFiles 执行|结果:该条目只贡献路径与场景编号,行数计 0 - [ ] HP-1(正常路径)情境:多个场景引用同一实现文件的不同行区间|操作:aggregateImplementationFiles 执行|结果:按路径合并行区间并返回去重后的场景编号,结果按路径排序 ## 功能树与功能编辑(规格工作台左侧功能树支持筛选与新建功能,功能表单可编辑名称与说明,子功能按层级展示。) - [ ] ER-1(错误路径)情境:保存功能接口失败|操作:提交功能表单|结果:显示「保存功能失败」错误 - [ ] HP-1(正常路径)情境:规格工作台已加载功能树|操作:在筛选框输入关键词|结果:只展示名称匹配的功能与子功能 - [ ] HP-2(正常路径)情境:需要新增功能|操作:点击「+ 新功能」并提交功能表单|结果:保存功能并回调新功能 id ## 功能树与功能详情(规格工作台左侧功能树支持选择功能与新建顶级功能,右侧展示功能详情、场景列表与语义流程,未选择功能时给出空态与新建入口。) - [ ] EC-1(边界情况)情境:未选择任何功能|操作:渲染 SpecDetail|结果:显示「选择一个功能」空态与「+ 新功能」按钮 - [ ] ER-1(错误路径)情境:删除功能接口失败|操作:点击删除功能|结果:显示接口错误消息或「删除功能失败」 - [ ] HP-1(正常路径)情境:产品已有功能|操作:在功能树选择功能|结果:右侧展示该功能详情、场景与实现面场景 ## 功能树与场景筛选(把功能列表按父子关系组装为树(父节点缺失时提升为根),默认选中根功能,并按关键词与类别筛选场景。) - [ ] EC-1(边界情况)情境:功能的父节点不在列表中|操作:buildFeatureTree 执行|结果:该功能被提升为根节点 - [ ] EC-2(边界情况)情境:未指定选中功能|操作:selectFeature 执行|结果:返回第一个根功能,无根时返回首个功能 - [ ] HP-1(正常路径)情境:功能存在父子关系|操作:buildFeatureTree 执行|结果:返回按名称排序的根节点与各自子节点 ## 功能流程图(按已验证的场景关系生成功能流程图,支持节点点击查看场景与代码证据,并列出不纳入主流程的场景。) - [ ] EC-1(边界情况)情境:自动布局计算失败|操作:FeatureFlow 渲染|结果:显示「自动布局暂时不可用」提示,场景清单仍可在场景标签查看 - [ ] EC-2(边界情况)情境:存在不纳入主流程的场景|操作:FeatureFlow 渲染|结果:折叠展示不纳入主流程的场景数量与原因 - [ ] HP-1(正常路径)情境:功能存在可布局的场景关系图|操作:FeatureFlow 渲染|结果:计算布局后渲染可缩放平移的流程图,点击节点展示关联场景与证据 ## 功能流程图布局与空态解释(用 ELK 分层布局把流程图排成自上而下的正交连线图并转为 React Flow 元素;无图时按护栏拒绝码输出面向用户的中文原因。) - [ ] EC-1(边界情况)情境:功能无流程图且无失败码|操作:describeFeatureFlowEmptyState 执行|结果:提示流程图尚未生成、将随下次分析自动生成 - [ ] EC-2(边界情况)情境:护栏拒绝码为 MAIN_CHAIN_MISSING|操作:describeFeatureFlowEmptyState 执行|结果:解释场景间无先后主链、强行画图会制造假流程,并指回场景清单 - [ ] HP-1(正常路径)情境:已有通过校验的流程图|操作:layoutSemanticFeatureFlow 执行|结果:返回带坐标、尺寸与折线点的节点与边,画布宽高按内容计算 - [ ] HP-2(正常路径)情境:需要渲染流程图组件|操作:toReactFlowElements 执行|结果:节点按场景引用挂载场景数据,边带标签与箭头标记 ## 功能流程图生成与校验(把功能场景交给 LLM 生成可验证的用户执行图,经确定性护栏校验(节点/边/入口上限、场景引用、重试与终态证据),校验失败自动整图重生成一次;护栏拒绝码落库供空态解释。) - [ ] EC-1(边界情况)情境:首次输出未通过护栏校验|操作:generateFeatureFlowGraph 执行|结果:携带校验错误整图重新生成一次并再次校验 - [ ] EC-2(边界情况)情境:场景集未变且已有有效图,本次生成被护栏拒绝|操作:saveFeatureFlowError 执行|结果:保留旧图,仅记录失败码与时间 - [ ] EC-3(边界情况)情境:场景集已变化且生成被护栏拒绝|操作:loadFeatureFlowErrors 执行|结果:旧图作废,指纹一致时返回失败码供空态解释 - [ ] ER-1(错误路径)情境:流程图未通过校验且重生成仍失败|操作:syncFeatureFlowsForVersion 执行|结果:failed 计数加一,落库失败码,不中断其他功能生成 - [ ] HP-1(正常路径)情境:功能场景可形成主链|操作:generateFeatureFlowGraph 执行|结果:返回通过 validateFeatureFlowGraph 校验的流程图 - [ ] HP-2(正常路径)情境:新规格版本生成且上一版存在同场景集流程图|操作:syncFeatureFlowsForVersion 执行|结果:指纹一致的图被继承复制,其余按受影响键并发生成(最多 3 并发) ## 功能行为变迁史(按功能稳定键取跨发布的行为变化(排除仅措辞变化),按发布倒序分组,回答「这个行为最后一次变化是哪个版本、证据是什么」。) - [ ] EC-1(边界情况)情境:功能只有措辞变化记录|操作:loadFeatureHistory 执行|结果:wording_only=1 的记录被过滤,不进入变迁史 - [ ] HP-1(正常路径)情境:功能在多个发布中有行为变化|操作:loadFeatureHistory 执行|结果:按发布倒序返回每个发布的变更条目,默认最多 15 条 ## 功能详情与场景工作台(功能详情页展示功能名、简介、来源、稳定链接、实现分布、行为变迁史与关联功能,并在场景与流程图两个视图间切换。) - [ ] EC-1(边界情况)情境:功能没有任何关联功能|操作:FeatureConnectionsPanel 加载|结果:不渲染关联功能面板 - [ ] ER-1(错误路径)情境:关联功能接口失败|操作:FeatureConnectionsPanel 加载|结果:显示「功能连接加载失败」错误 - [ ] HP-1(正常路径)情境:打开某功能详情|操作:FeatureDetail 渲染|结果:展示功能头、实现分布、行为变迁史、关联功能与场景/流程图标签 - [ ] HP-2(正常路径)情境:功能存在共享证据文件的关联功能|操作:FeatureConnectionsPanel 加载|结果:展示关联功能数量与共享文件及两侧场景引用 ## 功能连接图与文件影响面反查(以共享证据文件构建功能间确定性连接(每对最多列 5 个共享文件),并支持按文件反查以该文件为证据的功能与场景,单功能场景截前 10 条且披露真实总数。) - [ ] EC-1(边界情况)情境:传入空文件清单|操作:lookupFilesImpact 或 buildFileImpact 执行|结果:直接返回空数组,不查询数据库 - [ ] EC-2(边界情况)情境:按路径过滤时 SQL LIKE 子串误中(lib/auth.tsx ← lib/auth.ts)|操作:loadFeatureConnections 执行|结果:建图前按证据路径精确筛一次,误中行被剔除 - [ ] HP-1(正常路径)情境:产品已有功能、场景与共享证据文件|操作:loadFeatureConnections 执行|结果:返回按功能分组的连接,共享文件按共享场景数降序截前 5 - [ ] HP-2(正常路径)情境:改动前需要知道哪些功能以这些文件为证据|操作:lookupFilesImpact 执行|结果:按请求路径保序返回命中功能与场景,每功能场景截前 10 条并给出 scenarioCount ## 匿名演示态分析入口(匿名演示访客在产品页不渲染分析入口与只读提示,登录引导集中在演示外壳顶栏;登录只读成员仍看到禁用按钮与权限说明,服务端写校验是最终边界。) - [ ] EC-1(边界情况)情境:匿名演示访客查看演示外壳顶栏|操作:渲染顶栏|结果:显示「使用 Chandler 登录」链接作为唯一登录引导 - [ ] EC-2(边界情况)情境:登录只读成员打开产品页|操作:渲染分析入口组件|结果:显示禁用的「发起分析 · 需编辑权限」按钮与只读权限说明 - [ ] EC-3(边界情况)情境:匿名演示访客在演示页触发写操作|操作:调用 demo guard|结果:弹出 Demo 模式只读提示对话框,写操作被拦截 - [ ] ER-1(错误路径)情境:分析请求返回错误|操作:提交分析|结果:显示接口错误消息,不进入分析中状态 - [ ] ER-2(错误路径)情境:分析请求被额度闸门拒绝|操作:点击「立即分析」|结果:展示接口返回的额度提示消息 - [ ] HP-1(正常路径)情境:匿名演示访客打开演示产品页|操作:渲染分析入口组件|结果:组件返回空,不输出任何按钮或提示 - [ ] HP-2(正常路径)情境:编辑者在产品页|操作:点击「立即分析」|结果:提交分析请求并刷新页面 ## 发布卡与回归清单(发布卡展示发布日期、标题、摘要与提交链接,行为变化与变更说明可展开;回归清单按功能分组展示场景行为文本与命中理由,支持标记通过/未通过/跳过/待验证并附备注,可导出 Markdown;无行为变化时提示瘦身回归。) - [ ] EC-1(边界情况)情境:发布没有任何回归任务|操作:渲染 BehaviorList|结果:有规格版本时提示本次未发现规格行为变化并建议瘦身回归 - [ ] EC-2(边界情况)情境:发布存在仅措辞/编号调整的折叠差异|操作:渲染 ReleaseCard|结果:折叠区展示「另有 N 条差异判定为仅措辞/编号调整」,展开可见明细 - [ ] ER-1(错误路径)情境:保存回归状态接口返回错误|操作:选择回归状态|结果:显示接口错误消息或「保存验证状态失败」 - [ ] HP-1(正常路径)情境:发布存在行为变化与变更说明|操作:展开 ReleaseCard 详情|结果:展示回归清单与「变更说明(AI)」列表,并附发布稿面板 - [ ] HP-2(正常路径)情境:回归任务需要标记状态|操作:在回归清单选择状态|结果:提交状态到 regression-tasks 接口并刷新页面,跳过与未通过可填备注 - [ ] HP-3(正常路径)情境:需要导出发布回归清单|操作:点击导出 Markdown|结果:跳转 /api/products/{slug}/releases/{id}/regression 下载 Markdown ## 发布变化分页加载(发布变化页按固定页大小分页读取发布、变更与折叠变化,首屏与「加载更多」各取一页,失败时抛出接口错误。) - [ ] ER-1(错误路径)情境:分页接口返回非 2xx|操作:loadMoreReleases 执行|结果:抛出接口 error 或「加载更多发布失败」 - [ ] HP-1(正常路径)情境:发布变化页需要加载下一页|操作:loadMoreReleases 执行|结果:按 offset 与页大小请求接口并返回发布、变更、行为变化与折叠变化 ## 发布稿一级视图(发布稿一级视图(?view=notes)全宽展示最新一次发布的客户向说明,支持编辑公告标题与重点强调、按功能分组校对块文案、发布/下线、复制公开链接与导出 Markdown。) - [ ] EC-1(边界情况)情境:本次发布没有行为变化|操作:渲染候选勾选列表|结果:显示「本次发布没有行为变化,无可宣布项。」 - [ ] ER-1(错误路径)情境:加载发布稿失败|操作:打开发布稿视图|结果:显示失败原因,未登录时提示登录后可在工作区生成并发布 - [ ] HP-1(正常路径)情境:最新发布尚无发布稿|操作:打开发布稿视图并勾选变更生成|结果:生成草稿并按功能分组展示块文案与证据 - [ ] HP-2(正常路径)情境:草稿可编辑|操作:修改公告标题或重点强调并失焦|结果:保存标题或强调语并刷新,提示已保存 - [ ] HP-3(正常路径)情境:发布稿已发布|操作:点击复制公开链接或下线|结果:复制公开链接提示已复制,下线后公开链接不再展示 ## 发布稿文案 AI 改写(发布稿文案的 AI 通道:合成公告标题、按功能合并变化记录成文、改写导语与单块润色,只改写措辞不新增事实,机械剥除场景编号,单功能失败回退原文不阻塞整篇。) - [ ] EC-1(边界情况)情境:模型输出中残留 EC-n/ER-n/HP-n 场景编号|操作:parseEnhancedSummary 执行|结果:stripScenarioRefs 确定性剥除编号与「场景」字样,锚定数据不变 - [ ] ER-1(错误路径)情境:单个功能成文调用失败或结构不合格|操作:rewriteReleaseNoteCopy 执行|结果:该功能保留原始条目并计入 failed,不阻塞整篇文案 - [ ] HP-1(正常路径)情境:发布稿存在多个功能的变化记录|操作:rewriteReleaseNoteCopy 执行|结果:按功能各调用一次合并成文,再合成标题与导语并写回 release_notes - [ ] HP-2(正常路径)情境:需要手动润色单个发布稿块|操作:buildEnhancePrompt 执行|结果:生成只基于原文事实、20-60 字行为陈述式的改写 prompt ## 发布稿校对与发布(发布稿动线:勾选变更(仅预勾选带 Highlight 分类的项)生成草稿,按功能分组块级校对与 AI 润色,人工发布后生成公开链接,可下线与导出 Markdown。) - [ ] EC-1(边界情况)情境:本次发布没有行为变化|操作:渲染候选勾选列表|结果:显示「本次发布没有行为变化,无可宣布项。」 - [ ] EC-2(边界情况)情境:发布稿已发布|操作:渲染发布稿面板|结果:只读展示,需先下线才能修改或重新生成 - [ ] ER-1(错误路径)情境:加载发布稿失败|操作:打开发布稿面板|结果:显示失败原因,未登录时提示登录后可在工作区生成并发布 - [ ] HP-1(正常路径)情境:发布存在可宣布的行为变化且尚无发布稿|操作:勾选变更并点击生成发布稿|结果:生成草稿并按功能分组展示块文案与证据路径 - [ ] HP-2(正常路径)情境:草稿需要人工校对|操作:修改块文案失焦或点击 AI 润色|结果:失焦保存块级改写并标记已人工改写,AI 润色只替换文本框内容待失焦落库 - [ ] HP-3(正常路径)情境:草稿校对完成|操作:点击发布|结果:状态变为已发布并展示公开页链接与复制链接按钮 ## 发布稿生成与发布(从发布的行为变化勾选生成发布稿草稿,块必须锚定真实 spec_change 且证据不越界,人工校对后可发布并生成公开分享链接,支持 Markdown 导出。) - [ ] EC-1(边界情况)情境:草稿块携带的证据路径不在锚定变化的证据集内|操作:validateDraft 执行|结果:返回 ok=false 与越界路径错误,草稿不允许落库 - [ ] ER-1(错误路径)情境:草稿为空或存在锚定不存在的 spec_change|操作:canPublish 执行|结果:返回 empty draft 或 anchor missing 错误,禁止发布 - [ ] HP-1(正常路径)情境:发布存在行为变化且已勾选要宣布的条目|操作:buildDraftBlocks 执行|结果:按 Highlight 固定顺序生成带 position 与锚定 specChangeId 的草稿块 - [ ] HP-2(正常路径)情境:草稿块均锚定本次发布的行为变化|操作:canPublish 执行|结果:返回 null 允许人工发布,发布后生成 share_token 公开链接 - [ ] HP-3(正常路径)情境:需要复制发布稿为 Markdown|操作:renderReleaseNoteMarkdown 执行|结果:输出含产品、提交、公开页与逐块摘要及证据路径的 Markdown ## 变体场景合并提案脚本(一次性运维脚本:对指定仓库最新规格版本内的措辞变体场景生成合并提案,默认 dry-run,--apply 才写入;复用运行时同一变体判定,跳过人工维护与已核实条目。) - [ ] EC-1(边界情况)情境:功能或场景来源为 manual,或场景已被人工核实|操作:脚本生成提案|结果:跳过该功能/场景,不产出合并提案 - [ ] ER-1(错误路径)情境:未提供 --repository 参数|操作:执行脚本|结果:打印用法并以退出码 1 结束 - [ ] ER-2(错误路径)情境:指定仓库不存在或没有规格版本|操作:执行脚本|结果:抛出错误并结束 - [ ] HP-1(正常路径)情境:指定仓库存在措辞变体场景|操作:执行 merge-variant-scenarios.ts --repository |结果:输出合并提案(保留哪条、丢弃哪条),不写库 - [ ] HP-2(正常路径)情境:人工审阅 dry-run 报告后确认合并|操作:追加 --apply 执行|结果:按提案合并变体场景 ## 变体场景存量清理脚本(对指定仓库最新规格版本内的措辞变体场景生成合并提案,默认 dry-run 只打印,--apply 才删除被并入的重复场景;跳过人工功能/场景与已核实场景。) - [ ] EC-1(边界情况)情境:场景来源为 manual 或已人工核实|操作:生成合并提案|结果:该场景列入跳过项,不参与合并 - [ ] ER-1(错误路径)情境:未提供 --repository 参数|操作:执行脚本|结果:打印用法并以退出码 1 结束 - [ ] ER-2(错误路径)情境:指定仓库不存在或没有规格版本|操作:执行脚本|结果:抛出「仓库不存在」或「该仓库没有规格版本」并以退出码 1 结束 - [ ] HP-1(正常路径)情境:仓库最新规格版本存在措辞变体场景|操作:执行 merge-variant-scenarios.ts --repository |结果:按功能打印删除→并入的提案与跳过项,dry-run 不改数据 - [ ] HP-2(正常路径)情境:人工审阅 dry-run 报告后确认执行|操作:追加 --apply 执行|结果:删除被并入的变体场景行,历史 changes 的 before/after JSON 不动 ## 变体场景清理提案脚本(对指定仓库最新规格版本内的措辞变体场景做合并提案,默认 dry-run,复用运行时同一变体判定,跳过 manual 与人工核实过的场景。) - [ ] EC-1(边界情况)情境:功能来源为 manual 或场景已被人工核实|操作:脚本生成提案|结果:跳过该功能或场景,不纳入合并提案 - [ ] EC-2(边界情况)情境:功能或场景来源为 manual,或场景已被人工核实|操作:脚本生成提案|结果:跳过不碰 - [ ] ER-1(错误路径)情境:未提供 --repository 参数|操作:执行脚本|结果:打印用法并以退出码 1 结束 - [ ] ER-2(错误路径)情境:指定仓库不存在或没有规格版本|操作:执行脚本|结果:抛出仓库不存在或该仓库没有规格版本错误 - [ ] ER-3(错误路径)情境:仓库不存在或该仓库没有规格版本|操作:执行脚本|结果:抛出错误终止 - [ ] ER-4(错误路径)情境:指定仓库不存在或该仓库没有规格版本|操作:执行脚本|结果:抛出错误并结束 - [ ] HP-1(正常路径)情境:指定仓库存在最新规格版本且含措辞变体场景|操作:执行 merge-variant-scenarios.ts --repository |结果:输出合并提案(保留哪条、丢弃哪条),默认不写库 - [ ] HP-2(正常路径)情境:指定仓库存在措辞变体场景|操作:执行 merge-variant-scenarios.ts --repository |结果:输出合并提案报告,不写库 - [ ] HP-3(正常路径)情境:人工审阅 dry-run 报告后决定执行|操作:追加 --apply 执行|结果:按提案合并变体场景 - [ ] HP-4(正常路径)情境:已人工审阅 dry-run 报告|操作:执行 merge-variant-scenarios.ts --repository --apply|结果:按提案执行合并 ## 变体场景清理脚本(对指定仓库最新规格版本内的措辞变体场景产出合并提案,默认 dry-run,--apply 才写库,跳过 manual 功能与已人工核实的场景。) - [ ] EC-1(边界情况)情境:功能来源为 manual 或场景已被人工核实|操作:脚本生成提案|结果:跳过该功能或场景,不产出合并提案 - [ ] ER-1(错误路径)情境:未提供 --repository 参数|操作:执行脚本|结果:打印用法并以退出码 1 结束 - [ ] ER-2(错误路径)情境:指定仓库不存在或该仓库没有规格版本|操作:执行脚本|结果:抛出错误并终止 - [ ] HP-1(正常路径)情境:维护者对指定仓库运行清理脚本且未加 --apply|操作:执行 merge-variant-scenarios.ts --repository |结果:输出变体合并提案报告,不写库 - [ ] HP-2(正常路径)情境:维护者审阅 dry-run 报告后决定执行|操作:执行 merge-variant-scenarios.ts --repository --apply|结果:按提案合并变体场景并写库 ## 只读演示下的分析入口(只读演示态下分析入口不渲染,编辑面板与保存动作由 demo guard 拦截,服务端校验兜底。) - [ ] EC-1(边界情况)情境:登录只读成员查看分析入口|操作:渲染组件|结果:显示「当前账号对该产品为只读权限。」说明,不渲染主按钮 - [ ] EC-2(边界情况)情境:匿名 demo 访客尝试打开场景编辑面板|操作:点击编辑或新建场景|结果:demo guard 拦截,不打开编辑面板 - [ ] EC-5(边界情况)情境:演示产品按组织与 slug 精确解析|操作:打开演示详情页|结果:按 (org, slug) 精确解析产品,不使用全局 slug 兜底 - [ ] ER-1(错误路径)情境:匿名 demo 访客绕过前端提交写请求|操作:服务端校验写权限|结果:服务端拒绝,写能力以服务端校验为准 - [ ] ER-2(错误路径)情境:匿名访客访问非 demo 产品地址|操作:解析公开演示产品|结果:返回 null,页面按 404 处理 - [ ] HP-1(正常路径)情境:登录只读成员打开产品页|操作:渲染分析入口|结果:显示禁用的次要按钮「发起分析 · 需编辑权限」 - [ ] HP-2(正常路径)情境:匿名 demo 访客浏览产品规格|操作:查看场景工作区|结果:可浏览规格内容,不出现分析入口 ## 可复制代码块组件(客户端组件 CopyBlock:渲染标题行、复制按钮与 pre/code 文本块,点击后把文本写入剪贴板并切换按钮文案为「已复制」。) - [ ] EC-1(边界情况)情境:用户尚未点击复制|操作:查看代码块|结果:按钮显示「复制」,文本以 pre/code 完整展示 - [ ] ER-1(错误路径)情境:浏览器不支持或拒绝剪贴板写入|操作:点击「复制」按钮|结果:复制失败,按钮文案不切换为「已复制」 - [ ] HP-1(正常路径)情境:指南页展示可复制的配置或指令文本|操作:点击「复制」按钮|结果:文本写入剪贴板,按钮文案变为「已复制」 ## 启动副作用防护与恢复(生产启动时恢复遗留 running 分析并启动账务 sweep;development 环境默认跳过这些副作用,需显式放行。) - [ ] EC-1(边界情况)情境:development 环境未设置 ALLOW_PROD_SIDE_EFFECTS|操作:register 执行|结果:跳过启动恢复与账务 sweep 并打印跳过日志 - [ ] HP-1(正常路径)情境:生产环境启动|操作:register 执行|结果:恢复中断分析并启动账务 sweep ## 场景导出(把功能与场景导出为 Gherkin 骨架(HP/EC/ER 编号作 tag)或 Markdown 复选框用例清单,按功能树层级组织。) - [ ] HP-1(正常路径)情境:需要把规格场景放进 Cucumber/Playwright 项目|操作:toGherkin 执行|结果:按功能树输出 Feature/Rule 与带分类 tag 的 Given/When/Then 场景块 - [ ] HP-2(正常路径)情境:需要把场景贴进测试计划或工单|操作:toMarkdownChecklist 执行|结果:按功能与子功能层级输出带复选框、分类标签与情境/操作/结果的清单 ## 增量分析模式判定(纯函数判定本次分析走增量还是全量:无上一版规格、受影响集为空、受影响占比超 60% 或 diff 文件超 200 时保守回退全量。) - [ ] EC-1(边界情况)情境:受影响集为空|操作:resolveAnalysisMode 执行|结果:回退 full,避免漏掉索引未覆盖的新功能 - [ ] EC-2(边界情况)情境:受影响功能占比超过 0.6 或 diff 文件超过 200|操作:resolveAnalysisMode 执行|结果:回退 full - [ ] HP-1(正常路径)情境:存在上一版规格且受影响功能占比未超阈值|操作:resolveAnalysisMode 执行|结果:返回 incremental ## 增量影子对比(对比增量分析与全量分析的功能 key 集合与 (reference, category) 集合,按功能 key 零容忍与宏平均 Jaccard ≥ 0.70 判定一致性。) - [ ] EC-1(边界情况)情境:增量分析缺少全量分析中的某个功能|操作:compareIncrementalShadow 执行|结果:该功能 key 进入 missingKeys,该功能 Jaccard 记 0 并列入 inconsistentFeatures,consistent 为 false - [ ] EC-2(边界情况)情境:两侧功能场景集合的 Jaccard 低于 0.70 门槛|操作:compareIncrementalShadow 执行|结果:referenceConsistency 低于 SHADOW_REFERENCE_GATE,consistent 为 false,该功能列入 inconsistentFeatures - [ ] HP-1(正常路径)情境:增量与全量分析的功能 key 集合完全一致且各功能场景编号与类别集合相同|操作:compareIncrementalShadow 执行|结果:consistent 为 true,missingKeys 与 extraKeys 为空,referenceConsistency 为 1 ## 多趟提取确定性合并(把多个分区窗口的提取结果按功能稳定键分组、场景行为等价与变体近似去重、引用冲突重编号、changes 去重并截断到 150 条,产出完整规格。) - [ ] EC-1(边界情况)情境:两场景骨架词共享但行为不同(如跳转 dashboard 与锁定账户)|操作:scenarioVariantSimilar 判定|结果:返回 false,两条场景都保留 - [ ] EC-2(边界情况)情境:合并后 changes 超过 150 条|操作:mergeChunkResults 执行|结果:截断到前 150 条并打日志,onStats 回报 changesTruncated - [ ] EC-3(边界情况)情境:同一功能内两条场景行为确实不同|操作:mergeChunkResults 执行|结果:两条场景都保留,不误合 - [ ] EC-4(边界情况)情境:两条场景骨架词共享但行为不同(如「跳转 dashboard」与「锁定账户」)|操作:mergeChunkResults 执行|结果:不折叠,两条场景均保留 - [ ] EC-5(边界情况)情境:两条场景骨架词共享但行为不同(如跳转 dashboard 与锁定账户)|操作:mergeChunkResults 执行|结果:变体判定拒绝合并,两条均保留 - [ ] EC-6(边界情况)情境:两条场景骨架词共享但行为不同(如「跳转 dashboard」与「锁定账户」)|操作:mergeChunkResults 执行|结果:变体判定拒绝折叠,两条场景都保留 - [ ] EC-7(边界情况)情境:两条场景情境/操作/结果同义且 category 相同|操作:mergeChunkResults 执行|结果:scenarioBehaviorEqual 命中直接去重,不进入变体判定 - [ ] HP-1(正常路径)情境:多个分区返回同名功能|操作:mergeChunkResults 执行|结果:按功能稳定键合并,摘要取场景数最多的趟,场景按引用冲突规则重编号 - [ ] HP-10(正常路径)情境:同一分区输出内同一行为以不同措辞重复建条|操作:mergeChunkResults 执行|结果:scenarioVariantSimilar 命中,后一条被去重,scenariosDeduped 计数加一 - [ ] HP-2(正常路径)情境:单分区输出中同一行为从不同角色重复建条(措辞变体)|操作:mergeChunkResults 执行|结果:变体近似判定命中后折叠,scenariosDeduped 计数加一,不落库并存 - [ ] HP-3(正常路径)情境:多个分区各自提取出同一功能|操作:mergeChunkResults 执行|结果:按功能 key 归并为一条功能,场景合并保留 - [ ] HP-4(正常路径)情境:单分区输出内同一行为以不同措辞重复建条|操作:mergeChunkResults 执行|结果:变体场景折叠为一条,保留先到者,changes 不受影响 - [ ] HP-5(正常路径)情境:实现面被切分为多个提取分区|操作:mergeChunkResults 合并各趟 AnalysisResult|结果:同名功能归并为一条,场景按顺序合并为完整规格 - [ ] HP-6(正常路径)情境:单分区输出内同一行为以不同角色或措辞重复建条|操作:mergeChunkResults 执行|结果:scenarioVariantSimilar 判定为变体后折叠,scenariosDeduped 计数加一 - [ ] HP-7(正常路径)情境:多个分区窗口输出同一功能|操作:mergeChunkResults 执行|结果:按功能稳定键归并场景并统计去重数量 - [ ] HP-8(正常路径)情境:多个分区窗口各自产出功能与场景|操作:mergeChunkResults 执行|结果:按功能稳定键归并场景,返回合并后的规格与去重/截断统计 - [ ] HP-9(正常路径)情境:实现面超出单窗口被分成多个分区|操作:mergeChunkResults 执行|结果:各分区功能按 key 归并,场景合并为一份完整规格并回报合并统计 ## 套餐购买面板(定价页展示套餐与超额包,下单后展示微信扫码或 H5 支付参数并轮询订单至终态。) - [ ] EC-1(边界情况)情境:套餐列表为空|操作:渲染定价面板|结果:显示「定价校准中」暂不开放购买 - [ ] ER-1(错误路径)情境:下单接口返回未登录或支付不可用|操作:点击订阅或购买|结果:显示「请先登录后再购买」或当前无法购买提示 - [ ] HP-1(正常路径)情境:定价页已加载套餐|操作:点击订阅|结果:创建订单并展示支付二维码或 H5 收银台链接,轮询至支付成功 ## 子进程命令执行(以 execFile 且 shell=false 执行外部命令,失败时抛出携带 stdout 与 stderr 的错误。) - [ ] ER-1(错误路径)情境:外部命令以非零码退出|操作:execCommand 执行|结果:抛出错误并在错误对象上附带 stdout 与 stderr - [ ] HP-1(正常路径)情境:外部命令正常退出|操作:execCommand 执行|结果:返回 stdout 与 stderr 字符串 ## 导出限流(导出接口按登录用户或匿名 IP 做 MySQL 固定窗口限流,键为 HMAC 摘要不落原始身份,行锁串行化防超发,超限返回 429 与 Retry-After,限流器故障时放行并告警。) - [ ] EC-1(边界情况)情境:同一身份在本窗口内已达上限|操作:consumeRateLimit 执行|结果:返回 allowed=false 与窗口剩余秒数,路由返回 429 与 Retry-After - [ ] EC-2(边界情况)情境:请求经反向代理携带 X-Forwarded-For|操作:clientIpFrom 执行|结果:按 TRUSTED_PROXY_COUNT 从右数取可信跳的 IP,不无条件信任客户端头 - [ ] ER-1(错误路径)情境:未配置 RATE_LIMIT_KEY_SECRET 或限流数据库操作失败|操作:consumeRateLimit 执行|结果:记录告警并放行(fail-open),不阻断导出 - [ ] HP-1(正常路径)情境:登录用户在本窗口内未超导出次数|操作:enforceExportRateLimit 执行|结果:消费一次配额并放行,返回 null 让导出继续 ## 工作区默认触发模式设置(设置页配置新接入仓库默认继承的分析触发模式,已有仓库不受影响。) - [ ] EC-1(边界情况)情境:选择每 N 次 push 或每天低峰模式|操作:渲染设置表单|结果:显示每 N 次推送与低峰分析时间下拉 - [ ] ER-1(错误路径)情境:保存默认触发设置接口失败|操作:点击保存|结果:显示接口错误消息或「保存默认触发设置失败」 - [ ] HP-1(正常路径)情境:编辑者打开设置页|操作:选择默认触发模式并保存|结果:提示默认触发设置已保存,此后新接入仓库继承该模式 ## 工作区默认输出语言设置(设置页提供工作区默认输出语言(中文/English)读写接口与面板:editor 可修改、viewer 可读取,非法语言返回 400,无权限返回 403;新接入产品注册时继承该默认值,已有产品不受影响。) - [ ] EC-1(边界情况)情境:提交的语言不在 zh-CN/en 枚举内|操作:PATCH /api/settings/output-language-default 执行|结果:返回 400 与「输出语言无效」,不更新 - [ ] ER-1(错误路径)情境:调用者不是工作区 editor|操作:PATCH /api/settings/output-language-default 执行|结果:返回 403「只有工作区成员可以修改此设置」,不更新 - [ ] HP-1(正常路径)情境:工作区 editor 在设置页选择默认输出语言|操作:PATCH /api/settings/output-language-default 提交 language=en|结果:更新 organizations.default_output_language 并返回 status=updated 与 language - [ ] HP-2(正常路径)情境:工作区 viewer 打开设置页|操作:GET /api/settings/output-language-default 执行|结果:返回 status=ok 与当前默认语言 ## 平台管理员判定(按 CODELPHI_ADMIN_EMAILS 白名单判定平台管理员,未配置时回退为 default 工作区 owner。) - [ ] EC-1(边界情况)情境:未配置管理员邮箱白名单|操作:isPlatformAdmin 执行|结果:回退判定 default 工作区 owner 为管理员 - [ ] ER-1(错误路径)情境:非管理员调用管理接口|操作:requirePlatformAdmin 执行|结果:抛出 forbidden - [ ] HP-1(正常路径)情境:配置了管理员邮箱白名单且用户邮箱在名单内|操作:isPlatformAdmin 执行|结果:返回 true ## 我的工作区页(展示用户创建或加入的工作区列表,所有者可邀请成员加入整个工作区,并可切换当前工作区;页面文案按界面语言渲染。) - [ ] EC-1(边界情况)情境:界面语言为 en 的成员打开我的工作区页|操作:渲染页面|结果:标题、邀请表单、表头与角色标签取英文字典条目 - [ ] EC-2(边界情况)情境:当前工作区不是列表中的某个工作区|操作:查看该行操作列|结果:显示「切换」按钮,提交后切换当前工作区 - [ ] EC-3(边界情况)情境:当前工作区对应行|操作:查看操作列|结果:显示「当前工作区」徽标,不提供切换按钮 - [ ] HP-1(正常路径)情境:工作区成员打开我的工作区页|操作:渲染页面|结果:显示工作区表格(名称、slug、角色、当前工作区徽章或切换按钮) - [ ] HP-2(正常路径)情境:工作区 owner 打开我的工作区页|操作:渲染邀请表单|结果:显示邮箱与角色输入及邀请按钮,提交后展示成员已加入或邀请链接与邮件发送状态 - [ ] HP-3(正常路径)情境:工作区所有者打开我的工作区页|操作:访问 /organizations|结果:渲染邀请成员表单(邮箱、角色、邀请按钮)与工作区列表 - [ ] HP-4(正常路径)情境:所有者提交邀请且成员已加入|操作:提交邀请表单|结果:显示「成员已加入。」提示 - [ ] HP-5(正常路径)情境:所有者提交邀请且对方尚未注册|操作:提交邀请表单|结果:显示邀请已创建提示与邀请链接,按是否发送注册邮件给出对应说明 ## 我的工作区页面(我的工作区页展示当前工作区、所有者邀请成员表单与用户所属工作区列表,支持切换工作区并显示邀请结果。) - [ ] EC-1(边界情况)情境:当前用户不是工作区所有者|操作:渲染我的工作区页|结果:不渲染邀请成员表单,仅显示工作区列表 - [ ] EC-2(边界情况)情境:列表中的工作区即当前工作区|操作:查看成员表格操作列|结果:显示「当前工作区」徽标而非切换按钮 - [ ] HP-1(正常路径)情境:工作区所有者打开我的工作区页|操作:渲染页面|结果:显示邀请成员表单(邮箱、角色、邀请按钮)与工作区列表表格 - [ ] HP-2(正常路径)情境:所有者提交邀请后返回页面|操作:查看邀请结果|结果:显示「成员已加入」或「邀请已创建」提示,并给出邀请链接与邮件发送状态 - [ ] HP-3(正常路径)情境:用户属于多个工作区|操作:查看工作区列表|结果:当前工作区显示「当前工作区」徽标,其他工作区显示「切换」按钮 - [ ] HP-4(正常路径)情境:工作区所有者打开我的工作区页|操作:填写邮箱与角色后提交邀请表单|结果:显示成员已加入或邀请已创建提示,并给出邀请链接与邮件发送状态 - [ ] HP-5(正常路径)情境:用户打开我的工作区页|操作:查看工作区表格|结果:列出所属工作区、角色(所有者/编辑者/查看者)与操作列,当前工作区显示徽标,其他工作区提供切换按钮 - [ ] HP-6(正常路径)情境:界面语言为 en 的用户打开我的工作区页|操作:渲染 /organizations|结果:标题、邀请表单、表头、角色标签与切换按钮取 ORGANIZATIONS 字典英文条目 ## 我的工作区页面双语(我的工作区页按界面语言渲染返回链接、标题、邀请成员表单、邀请结果提示、成员表格表头与角色标签、当前工作区徽标与切换按钮。) - [ ] HP-1(正常路径)情境:界面语言为 en 的工作区所有者打开我的工作区|操作:访问 /organizations|结果:标题、邀请成员表单、邮箱与角色标签、邀请按钮显示英文 - [ ] HP-2(正常路径)情境:界面语言为 en 且邀请已创建|操作:查看邀请结果区块|结果:成员已加入或邀请已创建提示、打开邀请链接与邮件发送状态文案显示英文 - [ ] HP-3(正常路径)情境:界面语言为 en 的工作区成员查看工作区列表|操作:渲染成员表格|结果:表头、所有者/编辑者/查看者角色标签、当前工作区徽标与切换按钮显示英文 ## 手动分析定位(按产品 slug(可选工作区)定位仓库,经代码托管适配器读取仓库元数据与默认分支头,返回 repositoryId 与 afterSha。) - [ ] EC-1(边界情况)情境:产品 slug 不存在或不属于指定工作区|操作:resolveManualAnalysis 执行|结果:返回 null - [ ] HP-1(正常路径)情境:产品 slug 存在且仓库可读|操作:resolveManualAnalysis 执行|结果:返回 repositoryId 与默认分支最新 afterSha ## 支付订单与退款(建单四段边界(本地 pending 复用 30 分钟内同参数单 → 远端建单 → 回写 → prepay 回写),查单超 20 秒未收 webhook 时向 Chandler 对账;退款按剩余天数/SAU 折算,明确 4xx 记 refund_failed,超时停 refund_submitted 由 sweep/webhook 推进确认并回收钱包。) - [ ] EC-1(边界情况)情境:30 分钟内存在同账户同参数 pending 单|操作:createPaymentOrder 执行|结果:复用原订单号并更新渠道,不新建订单 - [ ] EC-2(边界情况)情境:退款确认时钱包仍有预留未结清|操作:reclaimWalletIfSettled 执行|结果:保持 reclaiming 状态返回 false,等下一轮重试 - [ ] ER-1(错误路径)情境:订单状态不是 paid/fulfilled 或已退款|操作:requestRefund 执行|结果:抛出 billing_state_conflict 表示不可退款 - [ ] ER-2(错误路径)情境:退款金额非正整数或超过订单金额|操作:requestRefund 执行|结果:抛出 billing_state_conflict 拒绝退款 - [ ] HP-1(正常路径)情境:用户选择订阅或超额包并发起支付|操作:createPaymentOrder 执行|结果:写入本地 pending 单、以本地商户单号为幂等键远端建单并回写平台单号与 prepay 参数 - [ ] HP-2(正常路径)情境:订单已支付且平台回调 paid|操作:markPaidAndFulfill 执行|结果:订单置为 paid 并调用履约函数发放权益 - [ ] HP-3(正常路径)情境:管理员对已支付订单发起退款|操作:requestRefund 执行|结果:订单置 refund_pending 后提交 Chandler,成功或超时置 refund_submitted,明确 4xx 置 refund_failed ## 数据库连接配置(从 DATABASE_URL 解析 MySQL 连接池配置(默认 3306、utf8mb4、UTC、连接上限 10),默认启用 TLSv1.2 且校验证书,可用 DATABASE_SSL=false 关闭。) - [ ] EC-1(边界情况)情境:DATABASE_SSL 设为 false|操作:databaseConfig 执行|结果:ssl 为 undefined,不启用 TLS - [ ] ER-1(错误路径)情境:DATABASE_URL 协议不是 mysql:|操作:databaseUrl 执行|结果:抛出 DATABASE_URL must be a mysql:// URL - [ ] HP-1(正常路径)情境:DATABASE_URL 为合法 mysql:// 地址|操作:databaseConfig 执行|结果:返回含主机、端口、库名与 TLS 选项的连接池配置 ## 架构产物访问(仅对 accepted 状态的架构文档返回 HTML,附带沙箱 CSP 与 no-store 头;未验收返回 409,文件缺失返回 404。) - [ ] EC-1(边界情况)情境:架构文档状态不是 accepted|操作:architectureArtifactResponse 执行|结果:返回 409 架构产物尚未通过验收 - [ ] ER-1(错误路径)情境:产物文件不存在|操作:architectureArtifactResponse 执行|结果:返回 404 架构产物不存在 - [ ] HP-1(正常路径)情境:架构文档已通过验收|操作:architectureArtifactResponse 执行|结果:返回 HTML 与沙箱安全响应头 ## 架构文档生成与版本记录(按仓库证据构建确定性架构文档(Radar/AIVlog 专用模板或通用规则),调用 Archify 交付与视觉验收,成功记 accepted、失败按阶段记 rendered/failed 并保存回执与错误;产物路径限定在受管目录内。) - [ ] EC-1(边界情况)情境:仓库分析覆盖率不可发布|操作:prepareArchitecture 执行|结果:不生成架构文档,仅写分析回执并以 standard 质量返回 - [ ] EC-2(边界情况)情境:通用仓库识别到的组件少于 2 个或连接为空|操作:buildArchitectureDocument 执行|结果:抛出 No architecture components detected 或 no component relationships detected - [ ] ER-1(错误路径)情境:交付或视觉验收阶段失败|操作:generateArchitecture 执行|结果:按阶段记录 rendered/failed 状态、回执与错误消息后返回 - [ ] ER-2(错误路径)情境:产物路径越出受管 artifacts/products 目录|操作:safeArtifactAbsolutePath 执行|结果:抛出 Artifact path is outside managed artifact directory - [ ] HP-1(正常路径)情境:仓库源码可读且证据完整|操作:generateArchitectureVersion 执行|结果:写 spec、交付 HTML、视觉验收通过后以 accepted 落库 - [ ] HP-2(正常路径)情境:通用仓库存在至少两个可识别组件与连接|操作:buildArchitectureDocument 执行|结果:返回含组件、连接与证据行号的架构文档 ## 演示模式分析入口(演示外壳以 DemoModeProvider 包裹页面,写操作经 demo guard 拦截并弹出只读提示对话框;匿名演示访客不再看到分析或发布入口,登录引导集中在顶栏。) - [ ] EC-1(边界情况)情境:匿名演示访客查看产品页头部|操作:渲染分析入口|结果:不渲染分析按钮与只读提示 - [ ] EC-10(边界情况)情境:登录页需要展示公开演示入口|操作:加载公开演示产品|结果:优先取数据库标记的 demo 产品,无则取环境变量白名单首个,都没有则不渲染入口 - [ ] EC-2(边界情况)情境:匿名演示访客查看总览页|操作:渲染发布入口|结果:不渲染发布按钮与登录链接 - [ ] EC-6(边界情况)情境:匿名演示访客查看发布入口|操作:渲染发布入口组件|结果:组件输出为空字符串,不渲染发布链接 - [ ] EC-7(边界情况)情境:以 writeAccess=readonly 渲染 AnalyzeButton|操作:渲染组件|结果:渲染禁用按钮并写明需编辑权限 - [ ] ER-1(错误路径)情境:绕过前端直接向写接口发请求|操作:服务端处理写请求|结果:由服务端写权限校验拒绝,前端隐藏不改变强制边界 - [ ] HP-1(正常路径)情境:匿名演示访客打开演示产品页|操作:渲染页面|结果:以演示外壳渲染,侧栏标注 DEMO MODE 只读演示 - [ ] HP-2(正常路径)情境:演示访客触发任一写操作|操作:调用 useDemoGuard 返回的守卫|结果:弹出「Demo 模式」对话框说明编辑不会保存 - [ ] HP-3(正常路径)情境:匿名 demo 访客打开产品页|操作:渲染页面头部|结果:不出现分析、发布等写入口,顶栏提供登录引导 ## 环境变量与功能开关(集中读取必需环境变量与可选开关:应用地址、Chandler 地址、邮箱白名单、公开演示 slug、PR 预演开关、增量影子、AI 上下文预算、分区上限与行为枚举参数,均带默认值。) - [ ] EC-1(边界情况)情境:邮箱白名单配置含空格与大写|操作:allowedEmails 执行|结果:去空格转小写后返回集合 - [ ] ER-1(错误路径)情境:必需环境变量缺失或为空|操作:requiredEnv 执行|结果:抛出「变量名 is not configured」 - [ ] HP-1(正常路径)情境:未设置可选开关|操作:prPreviewEnabled 或 analysisMaxPartitions 执行|结果:PR 预演默认开启,分区上限默认 6 ## 界面语言切换(界面语言由 codelphi_locale cookie 驱动:服务端组件读取 locale 渲染导航、外壳文案、html lang 与 metadata,顶栏语言切换 pill 提交同源重定向请求写入一年期 cookie 并刷新当前页;未设置或非法值回退 zh-CN,与分析输出语言相互独立。) - [ ] EC-1(边界情况)情境:请求未携带 codelphi_locale cookie 或 cookie 值非法|操作:resolveUiLocale 执行|结果:回退为 zh-CN - [ ] EC-2(边界情况)情境:切换请求的 locale 不在 zh-CN/en 内,或 redirectTo 为绝对地址或 // 开头|操作:POST /api/ui-locale|结果:返回 400,不写 cookie 不重定向 - [ ] EC-3(边界情况)情境:点击当前已选中的语言|操作:LanguageSwitcher 的 switchTo 执行|结果:直接返回,不发请求不刷新 - [ ] ER-1(错误路径)情境:切换请求进行中|操作:再次点击任一语言按钮|结果:按钮 disabled 且 pending 期间不重复提交 - [ ] HP-1(正常路径)情境:用户在顶栏点击另一种界面语言|操作:LanguageSwitcher 读取当前路径并 POST /api/ui-locale|结果:服务端写入 codelphi_locale cookie 并 303 重定向回原页,随后 router.refresh() 刷新 - [ ] HP-2(正常路径)情境:界面语言为 en 时渲染外壳|操作:AppShell/PublicShell/DemoShell/Brand 渲染|结果:导航、侧栏说明、演示徽标、登录/退出与品牌标语输出英文文案,切换器标记 English 为当前项 - [ ] HP-3(正常路径)情境:界面语言为 en 时加载页面|操作:根布局与页面渲染|结果:html lang 为 en,metadata 描述输出英文,日期按 en 格式化 ## 界面语言切换与双语外壳(界面语言(与分析输出语言独立)由 cookie 驱动服务端渲染:顶栏语言 pill 提交 POST /api/ui-locale 写一年期 SameSite=Lax cookie 并同源重定向,三种外壳与根布局按 locale 输出双语导航、品牌与 metadata,日期按 locale 格式化。) - [ ] EC-1(边界情况)情境:请求体 locale 为 fr 或 redirectTo 为 https://evil.example、//evil.example、null|操作:POST /api/ui-locale|结果:返回 400 与校验错误消息,不写 cookie、不重定向 - [ ] EC-2(边界情况)情境:cookie 缺失或值为未知语言(如 fr)|操作:resolveUiLocaleValue 执行|结果:回退为 zh-CN,页面按中文渲染 - [ ] EC-3(边界情况)情境:用户点击当前已选中的语言按钮或切换请求尚未完成|操作:点击语言切换器按钮|结果:不发起请求(next === locale 或 pending 时直接返回),按钮在 pending 期间禁用 - [ ] ER-1(错误路径)情境:提交的 locale 不在 zh-CN/en 内,或 redirectTo 为站外地址、协议相对地址、非 / 开头|操作:POST /api/ui-locale|结果:返回 400 与校验错误消息,不写 cookie 不重定向 - [ ] ER-2(错误路径)情境:切换请求网络失败|操作:LanguageSwitcher 的 switchTo 执行|结果:finally 中恢复 pending 状态,按钮重新可用 - [ ] HP-1(正常路径)情境:界面语言为中文的用户在任意外壳页面|操作:点击顶栏语言切换器中的 English|结果:POST /api/ui-locale 携带 locale=en 与当前路径,服务端写 codelphi_locale=en 并 303 重定向回原页,页面以英文文案重新渲染 - [ ] HP-10(正常路径)情境:界面语言为 en 时查看仪表盘、设置页、成本观测页或产品总览|操作:页面调用 formatDateIn/formatDateTimeIn 渲染日期|结果:日期按 en 的 Intl 格式输出,不再使用硬编码 zh-CN - [ ] HP-14(正常路径)情境:cookie 中 codelphi_locale 为 en|操作:渲染根布局与外壳|结果:html lang 为 en,metadata 描述为英文,导航与品牌标语取英文字典条目 - [ ] HP-2(正常路径)情境:界面语言为英文的用户打开应用外壳页面|操作:渲染侧栏与顶栏|结果:导航项显示 Products/Workspaces/Settings 等英文标签,品牌标语为 Product change radar,html lang 为 en - [ ] HP-3(正常路径)情境:匿名访客打开公开外壳页面|操作:渲染顶栏|结果:显示语言切换器与英文/中文对应的登录入口文案,站点导航按 locale 取值 - [ ] HP-4(正常路径)情境:用户在任意外壳顶栏点击另一种界面语言|操作:LanguageSwitcher 提交 POST /api/ui-locale 携带当前路径|结果:接口写入一年期 codelphi_locale cookie 并 303 回跳,切换器调用 router.refresh 刷新当前页 - [ ] HP-5(正常路径)情境:界面语言 cookie 为 en|操作:根布局与外壳渲染|结果:html lang 为 en,metadata description、导航、登录、演示提示与品牌标语取英文条目 - [ ] HP-6(正常路径)情境:界面语言为 en 且页面展示日期|操作:仪表盘、设置页、成本页或产品总览渲染日期|结果:日期经 formatDateIn/formatDateTimeIn 按 en 的 Intl 格式输出 ## 登录与 403 页面(登录页展示品牌主张、Chandler 统一账号登录入口、数据说明与公开演示入口(含五个匿名导出链接);403 页说明账号无权限并引导返回登录。两页均按界面语言渲染中英文案。) - [ ] EC-1(边界情况)情境:部署未配置公开演示产品|操作:打开登录页|结果:不渲染公开演示入口区块,仅显示登录卡片 - [ ] ER-1(错误路径)情境:账号无 CoDelphi 访问权限|操作:打开 /forbidden|结果:显示 403 标题、受限说明与「返回登录」链接,文案按界面语言渲染 - [ ] HP-1(正常路径)情境:未登录访客打开登录页且存在公开演示产品|操作:渲染 /login|结果:显示登录卡片、Chandler 登录按钮、数据说明,以及公开演示入口与规格清单、Gherkin、Markdown、30 天变更索引、Explainer 五个导出链接 - [ ] HP-2(正常路径)情境:界面语言为 en 的访客打开登录页|操作:渲染 /login|结果:标题、说明、登录按钮、数据说明与演示入口文案取 LOGIN 字典英文条目 - [ ] HP-3(正常路径)情境:已登录用户访问登录页|操作:打开 /login|结果:重定向到首页 ## 登录页与 403 访问受限页(登录页展示品牌陈述、Chandler 统一账号登录入口、数据说明与公开演示入口(含五个匿名导出链接);403 页提示当前部署启用专用登录限制并引导返回登录。两页均按界面语言渲染文案。) - [ ] EC-1(边界情况)情境:界面语言为 en 的账号无访问权限|操作:打开 403 页|结果:标题、说明与返回登录链接取英文字典条目 - [ ] EC-2(边界情况)情境:部署未配置公开演示产品|操作:打开登录页|结果:不渲染公开演示入口区块,仅显示登录卡片 - [ ] EC-3(边界情况)情境:界面语言为英文的账号无访问权限|操作:访问 /forbidden|结果:显示英文 403 标题、说明与 Back to sign-in 链接 - [ ] ER-1(错误路径)情境:账号无 CoDelphi 访问权限|操作:访问受限页面被导向 403 页|结果:显示「这个账号还没有 CoDelphi 权限」提示与「返回登录」链接 - [ ] ER-2(错误路径)情境:已登录用户访问登录页|操作:访问 /login|结果:重定向到首页,不渲染登录表单 - [ ] HP-1(正常路径)情境:未登录访客打开登录页且存在公开演示产品|操作:渲染登录页|结果:显示登录陈述、Chandler 登录按钮、数据说明与公开演示入口及五个匿名导出链接 - [ ] HP-2(正常路径)情境:界面语言为 en 的访客打开登录页|操作:渲染登录页|结果:标题、陈述、登录按钮、数据说明与演示导出名称均取英文字典条目 - [ ] HP-3(正常路径)情境:账号无 CoDelphi 访问权限|操作:打开 403 页|结果:显示无权限标题与说明,并提供「返回登录」链接 - [ ] HP-4(正常路径)情境:未登录访客打开登录页且存在公开演示产品|操作:访问 /login|结果:渲染登录卡片与公开演示入口,列出规格清单、Gherkin 回归用例、Markdown 规格书、30 天变更索引与 Explainer 五个匿名导出链接 - [ ] HP-5(正常路径)情境:界面语言为 en 的访客打开登录页|操作:访问 /login|结果:标题、说明、Chandler 登录按钮、数据说明与演示入口文案以英文渲染 - [ ] HP-6(正常路径)情境:已登录用户访问登录页|操作:访问 /login|结果:重定向到首页 - [ ] HP-7(正常路径)情境:界面语言为英文的访客打开登录页|操作:访问 /login|结果:渲染英文标题 Understand every product change.、Sign in with Chandler 按钮与英文数据说明 - [ ] HP-8(正常路径)情境:存在公开演示产品且访客打开登录页|操作:查看公开演示区块|结果:显示演示入口与五个匿名导出链接,链接名称按界面语言渲染 ## 登录页与 403 页双语入口(登录页与 403 页按界面语言渲染文案:登录页含品牌标题、Chandler 登录按钮、数据说明、公开演示入口与五个匿名导出标签;403 页含权限说明与返回登录链接。) - [ ] EC-1(边界情况)情境:未配置公开演示产品|操作:渲染登录页|结果:不渲染公开演示区块,仍显示 Chandler 登录按钮 - [ ] EC-2(边界情况)情境:账号无 CoDelphi 权限|操作:打开 /forbidden|结果:按界面语言显示 403 标题、说明与「返回登录」链接 - [ ] EC-3(边界情况)情境:界面语言为 zh-CN 的访客打开登录页|操作:访问 /login|结果:页面文案与默认中文一致,不出现英文条目 - [ ] HP-1(正常路径)情境:界面语言为中文的访客打开 /login|操作:渲染登录页|结果:显示中文标题「读懂每一次产品变化。」、Chandler 登录按钮与数据说明 - [ ] HP-2(正常路径)情境:界面语言为 en 的访客打开 /login|操作:渲染登录页|结果:标题、说明、登录按钮、数据说明与公开演示入口按英文字典条目渲染 - [ ] HP-3(正常路径)情境:存在公开演示产品且访客未登录|操作:查看登录页公开演示区块|结果:显示演示入口链接与五个匿名导出入口(spec.json、Gherkin、Markdown、30 天变更索引、Explainer) - [ ] HP-4(正常路径)情境:存在公开演示产品且界面语言为 en|操作:登录页渲染公开演示区块|结果:演示标题、说明、进入链接与五个匿名导出链接名称显示英文 - [ ] HP-5(正常路径)情境:界面语言为 en 的用户访问 403 页|操作:打开 /forbidden|结果:标题、说明与「返回登录」链接显示英文文案 ## 知识健康统计(只展示事实性统计:漂移条目、已核实条目、最新发布回归任务四态与近 90 天编辑归因,不计算综合健康分数。) - [ ] EC-1(边界情况)情境:编辑记录缺少编辑者归因|操作:buildKnowledgeHealth 执行|结果:该编辑计入 unattributedEdits,不进入 maintenance 分布 - [ ] HP-1(正常路径)情境:产品存在漂移条目、已核实条目与最新发布回归任务|操作:buildKnowledgeHealth 执行|结果:返回 staleCount 与最多 10 条 staleItems、verifiedCount、回归四态计数与按编辑数降序的维护分布 ## 知识健康面板(产品页展示知识健康事实统计:待核实漂移、核实覆盖、最近核实时间、最新发布回归四态与人工编辑分布,无综合分。) - [ ] EC-1(边界情况)情境:知识健康接口失败|操作:KnowledgeHealthPanel 加载|结果:面板不渲染,不显示错误占位 - [ ] HP-1(正常路径)情境:产品已有规格与核实数据|操作:KnowledgeHealthPanel 加载|结果:展示漂移数、核实覆盖比例、最近核实日期与回归通过统计 ## 组织邀请与工作区引导(owner 邀请邮箱:已是用户直接加入组织成员,否则写入待接受邀请、签发 7 天令牌并发邮件;登录时自动认领未签发令牌的邀请并幂等创建个人工作区与 Trial 额度。) - [ ] EC-1(边界情况)情境:邀请邮箱尚未签发令牌|操作:claimOrganizationInvitations 执行|结果:登录时按邮箱认领邀请并写入组织成员,标记 accepted - [ ] ER-1(错误路径)情境:非 owner 发起邀请|操作:inviteOrganizationMember 执行|结果:抛出 forbidden - [ ] ER-2(错误路径)情境:请求角色低于所需最低角色|操作:requireOrganization 执行|结果:抛出 forbidden - [ ] HP-1(正常路径)情境:owner 邀请的邮箱已是注册用户|操作:inviteOrganizationMember 执行|结果:直接写入 organization_members 并返回 member_added,不发邮件 - [ ] HP-2(正常路径)情境:被邀请邮箱尚未注册|操作:inviteOrganizationMember 执行|结果:写入待接受邀请、签发 7 天令牌并发送邀请邮件,返回 invitation_pending 与邀请链接 - [ ] HP-3(正常路径)情境:用户首次登录且无个人工作区|操作:ensureUserWorkspace 执行|结果:创建 u- 前缀随机 slug 的个人工作区、写入 owner 成员并幂等发放 Trial 额度 ## 行为面两步提取(把窗口 diff 的行为文件按路径序分组做定向微任务提取,逐文件显式提问行为或无行为,按 hunk 公平预算读取变更区上下文,失败重试一次后跳过并披露枚举指标。) - [ ] EC-1(边界情况)情境:复述输出含未知路径或畸形条目|操作:parseBehavioralDescriptions 执行|结果:只保留已知路径的合法条目,畸形条目丢弃 - [ ] EC-2(边界情况)情境:判定输出缺 product 或 release 且 features 为空数组|操作:analyzeBehavioralGroup 执行|结果:注入占位 product/release,features 空数组合法 - [ ] EC-3(边界情况)情境:窗口内无实现级行为变更(纯文档/注释/格式提交)|操作:runAnalysisBody 执行|结果:跳过全部 AI 提取,上一版规格原样沿用、零变化 - [ ] EC-4(边界情况)情境:行为文件数超过组数上限|操作:enumerateBehavioralChunks 执行|结果:只处理前 maxGroups 组,其余计入 pathsOmitted,状态为 partial - [ ] EC-5(边界情况)情境:单文件 hunk 总需求超过 400 行预算|操作:allocateHunkReads 执行|结果:每 hunk 先保底核心区间,剩余按需求比例分配,未满足的 hunk 标记 truncated 并计数披露 - [ ] ER-1(错误路径)情境:某组定向提取连续两次失败|操作:enumerateBehavioralChunks 执行|结果:跳过该组,groupsFailed 计数增加,状态为 partial 而非完整成功 - [ ] HP-1(正常路径)情境:行为变更文件含多个变更块|操作:analyzeBehavioralGroup 执行|结果:先调用复述 prompt 逐块给出改前改后,再调用判定 prompt 输出场景 - [ ] HP-2(正常路径)情境:push 变更包含行为文件|操作:runAnalysisBody 计算 behavioralPaths 并进入提取|结果:行为文件清单跨模式共享,供 RC2 与定向枚举使用 - [ ] HP-3(正常路径)情境:窗口存在实现级行为变更|操作:runAnalysisBody 执行|结果:按行为面文件清单分区逐趟提取后合并为完整规格 - [ ] HP-4(正常路径)情境:窗口 diff 含行为文件|操作:enumerateBehavioralChunks 执行|结果:按组定向提取,每组结果用组文件与全部 diff 文件作证据允许集清洗后返回 ## 行为面枚举提取(把窗口 diff 的行为文件按路径稳定分组,逐文件定向读取变更区上下文并显式提问行为/无行为,组失败重试一次后跳过;输出枚举完整性指标(complete/partial/failed/not_applicable)与 hunk 公平预算截断计数。) - [ ] EC-1(边界情况)情境:行为文件组数超过上限|操作:enumerateBehavioralChunks 执行|结果:只处理前 maxGroups 组,打 warn 日志,状态记为 partial - [ ] EC-2(边界情况)情境:行为文件在窗口内被删除或不可读|操作:enumerateBehavioralChunks 执行|结果:跳过该文件读取,patch 仍在组 prompt 中提供 - [ ] ER-1(错误路径)情境:某组定向提取重试后仍失败|操作:enumerateBehavioralChunks 执行|结果:跳过该组,groupsFailed 计数增加,不阻塞主提取产出 - [ ] HP-1(正常路径)情境:窗口存在行为变更文件且枚举开关开启|操作:enumerateBehavioralChunks 执行|结果:按组定向提取并清洗证据,返回 chunks 与 pathsEnumerated/groupsCompleted 等指标 - [ ] HP-2(正常路径)情境:单文件多个 hunk 且总需求超过 400 行预算|操作:allocateHunkReads 执行|结果:每 hunk 先保底核心区间,剩余按需求比例分配,未满足的标记 truncated ## 覆盖率展示口径(覆盖率展示唯一入口:按文件字节计算百分比并固定一位小数,显式声明字节口径,文件装配数作为独立事实并排展示,不合成百分比。) - [ ] HP-1(正常路径)情境:已有覆盖率回执|操作:coverageByteLabel 与 coverageFilesLabel 执行|结果:输出「源码装配覆盖率(按文件字节)12.1%」与「已装配实现文件 X/Y 个」 ## 规格工作区场景卡片(在规格工作区渲染单个场景的类别、编号、来源与证据链接,并对证据全部来自测试/文档的场景显示「测试佐证」徽标。) - [ ] EC-1(边界情况)情境:场景同时带 staleSince 与测试佐证|操作:渲染 ScenarioCard|结果:「测试佐证」与「可能过时」两个徽标同时显示,互不覆盖 - [ ] HP-1(正常路径)情境:场景证据包含实现代码路径|操作:渲染 ScenarioCard|结果:正常展示类别、编号、情境/操作/结果与证据链接,不显示测试佐证徽标 - [ ] HP-2(正常路径)情境:场景证据全部来自测试或文档|操作:渲染 ScenarioCard|结果:编号旁显示「测试佐证」徽标,悬停提示行为以人工核实为准 ## 规格工作台与场景编辑(规格工作台展示功能树与功能详情,支持新建/编辑/删除功能与场景,场景按 happy/edge/error 筛选、按核实状态筛选、搜索与列表/表格切换,并可标记已核实。) - [ ] EC-1(边界情况)情境:筛选后没有匹配场景|操作:渲染场景列表|结果:显示「没有匹配场景,调整筛选或新建一个场景。」 - [ ] EC-2(边界情况)情境:只读 demo 下点击编辑入口|操作:打开场景或功能编辑|结果:demo guard 拦截,不打开编辑面板 - [ ] ER-1(错误路径)情境:保存场景接口失败|操作:提交场景表单|结果:显示接口错误消息或「保存场景失败」 - [ ] ER-2(错误路径)情境:删除场景接口失败|操作:点击删除场景|结果:显示接口错误消息或「删除场景失败」 - [ ] HP-1(正常路径)情境:编辑者在功能详情点击新场景|操作:填写情境、操作、结果与分类并保存|结果:保存场景后关闭编辑面板并刷新页面 - [ ] HP-2(正常路径)情境:功能下存在多个场景|操作:切换分类筛选、搜索或列表/表格视图|结果:按分类计数与搜索词过滤场景,并以所选视图展示 - [ ] HP-3(正常路径)情境:场景需要人工核实|操作:点击标记已核实|结果:调用核实接口并刷新,徽章显示已核实与核实人 ## 规格工作台场景卡片(在规格工作台逐条展示场景的类别、编号、来源与情境/操作/结果,附证据链接与校验、编辑、删除操作,并对可能过时与仅有测试/文档佐证的场景给出标记。) - [ ] EC-1(边界情况)情境:场景证据全部来自测试或文档路径|操作:渲染 ScenarioCard|结果:场景标签行显示「测试佐证」徽标,悬停提示行为以人工核实为准 - [ ] EC-2(边界情况)情境:场景证据为空数组|操作:isTestOnlyEvidence 判定|结果:返回 false,不显示「测试佐证」徽标 - [ ] EC-3(边界情况)情境:场景被标记可能过时|操作:渲染场景卡片|结果:同时显示「可能过时」徽标,与「测试佐证」徽标并列 - [ ] HP-1(正常路径)情境:场景证据包含实现代码路径|操作:渲染 ScenarioCard|结果:正常展示场景标签与证据链接,不显示「测试佐证」徽标 - [ ] HP-2(正常路径)情境:场景证据全部来自测试或文档|操作:渲染场景卡片|结果:标签行显示「测试佐证」徽标,悬停提示行为以人工核实为准 - [ ] HP-3(正常路径)情境:场景证据含实现代码|操作:渲染场景卡片|结果:不显示「测试佐证」徽标,其余标签与证据链接照常展示 ## 规格工作台披露与影响面查询(规格工作台顶部披露分析完整性与源码装配覆盖率,并说明静态提取盲区的人工补充入口;同时提供按文件反查受影响功能与场景的影响面查询。) - [ ] EC-1(边界情况)情境:产品尚无完整性账本或覆盖率回执|操作:渲染 SpecWorkspace|结果:不渲染对应披露行 - [ ] HP-1(正常路径)情境:产品存在完整性账本与覆盖率回执|操作:渲染 SpecWorkspace|结果:展示分析完整性状态、覆盖率字节与文件数、提取趟数及未覆盖提示 ## 规格差异变体折叠(比较前后两版规格产出变化行,并把行为等价、换编号与措辞近似的差异折叠进审计面;变体判定宁漏勿错合,折叠不删除数据。) - [ ] EC-1(边界情况)情境:两条场景 category 不同(happy 与 edge)|操作:scenarioVariantSimilar 执行|结果:返回 false,不折叠 - [ ] EC-2(边界情况)情境:两条场景结果数字不同(404 与 400)|操作:scenarioVariantSimilar 执行|结果:数字签名不一致,返回 false,不折叠 - [ ] EC-3(边界情况)情境:两条场景结果否定词计数不同(可以重试 与 不可以重试)|操作:scenarioVariantSimilar 执行|结果:返回 false,不折叠 - [ ] EC-4(边界情况)情境:两条场景情境被同义改写但操作与结果行为等价|操作:scenarioVariantSimilar 执行|结果:返回 true,判为同一行为 - [ ] ER-1(错误路径)情境:两条场景骨架词共享但结果语义相反(跳转 dashboard 与 锁定账户)|操作:scenarioVariantSimilar 执行|结果:返回 false,真差异不被误合 - [ ] HP-1(正常路径)情境:同功能内一条场景被移除、另一条措辞近似的新场景被加入|操作:diffSpecWithFolded 执行|结果:该对折叠为 reason=variant 进入 folded,changes 中不产生变化行 - [ ] HP-2(正常路径)情境:同功能内 removed↔added 且行为字段逐项等价|操作:diffSpecWithFolded 执行|结果:折叠为 reason=renumber,不产生变化行 ## 规格检索与问答(规格工作台提供产品内搜索(功能名/摘要、场景文本与证据路径,防抖并支持点击外部或 Escape 收起)与检索式问答(一次问句返回规格原文卡片,未命中明确声明未覆盖,限流明示恢复时间)。) - [ ] EC-1(边界情况)情境:搜索无匹配结果|操作:渲染搜索结果|结果:显示「没有匹配的功能或场景。」 - [ ] EC-2(边界情况)情境:提问频率超过每 IP 每小时 10 次|操作:点击查规格|结果:提示提问频率已达上限与可再试时间 - [ ] ER-1(错误路径)情境:搜索接口失败|操作:输入关键词|结果:显示「搜索暂时不可用,请稍后重试。」 - [ ] ER-2(错误路径)情境:问答接口失败|操作:点击查规格|结果:显示「查询暂时不可用,请稍后重试。」 - [ ] HP-1(正常路径)情境:用户在产品内搜索关键词|操作:在搜索框输入|结果:防抖后请求搜索接口,下拉展示命中的功能与场景并直达对应功能视图 - [ ] HP-2(正常路径)情境:用户向规格提问|操作:输入问句并点击查规格|结果:返回规格原文卡片,命中时展示功能与最多 8 条场景及证据,并标注基于的规格版本 ## 规格版本落库与发布记录(分析结果在单事务内写入规格版本、重建文件索引、标记漂移、保存覆盖率回执、下线旧生成规格并写入发布与改动文件清单,失败整体回滚。) - [ ] EC-1(边界情况)情境:发布已存在 changes 记录|操作:upsertRelease 执行|结果:跳过 changes 插入,直接确保回归任务后返回 releaseId - [ ] EC-10(边界情况)情境:仓库没有任何规格版本|操作:loadPreviousSpecText 执行|结果:返回空数组,锚定降级为仅命名约束 - [ ] EC-2(边界情况)情境:增量模式下 AI 输出命中 carried 键|操作:insertSpecVersion 执行|结果:该 AI 功能被丢弃并计数,carried 内容保全 - [ ] EC-3(边界情况)情境:新版场景数较上一版骤降超过阈值|操作:detectSpecCollapse 执行|结果:返回坍缩告警,只告警不阻断落库 - [ ] EC-4(边界情况)情境:前后场景行为相反或数字/否定冲突(如 404 与 400、可以重试与不可以重试)|操作:scenarioVariantSimilar 判定|结果:返回 false,不折叠,两条变化均保留 - [ ] EC-5(边界情况)情境:前后场景 category 不一致(happy 与 edge)|操作:scenarioVariantSimilar 判定|结果:直接返回 false,不折叠 - [ ] EC-6(边界情况)情境:同功能内 removed↔added 且行为字段逐项等价|操作:scenarioChanges 执行|结果:折叠为 reason=renumber,不产生变化行 - [ ] EC-7(边界情况)情境:同功能内 removed↔added 措辞近似但语义相同|操作:scenarioChanges 执行|结果:折叠为 reason=variant 进 folded 审计面,不产生变化行、不删数据 - [ ] EC-8(边界情况)情境:两条场景行为相反、主体互换、数字或否定冲突|操作:scenarioVariantSimilar 执行|结果:返回 false,保留为真实变化 - [ ] EC-9(边界情况)情境:prioritize 中的功能名在上一版规格中不存在|操作:loadPreviousSpecText 执行|结果:顺序不变,全部功能按 position 序返回 - [ ] ER-1(错误路径)情境:保存过程中任一步抛错|操作:saveResult 执行|结果:事务回滚并抛出错误,run 不标记成功 - [ ] ER-2(错误路径)情境:当前 run 已被更新的 run 取代|操作:assertLatestRun 执行|结果:抛出 Analysis superseded by run N,事务回滚 - [ ] ER-3(错误路径)情境:新增功能的实现证据文件本次均无行为性行变更|操作:diffFeature 执行|结果:折叠为 reason=tests-only,不落行为变化 - [ ] HP-1(正常路径)情境:分析成功且存在上一版规格|操作:saveResult 执行|结果:事务内写入规格版本、覆盖率回执、发布记录与改动文件清单,run 标记 succeeded - [ ] HP-2(正常路径)情境:发布已存在同 sha 记录|操作:upsertRelease 执行|结果:按唯一键更新 analysis_run_id 与 spec_version_id,不重复插入 - [ ] HP-3(正常路径)情境:增量模式存在受影响集之外的既有功能|操作:insertSpecVersion 执行|结果:未受影响功能原样沿用上一版,AI 输出与人工条目按优先级合并 - [ ] HP-4(正常路径)情境:同功能内 removed↔added 场景措辞近似但语义相同|操作:diffSpec 计算变化|结果:该对折叠为 reason=variant 的审计明细,不产生变化行 - [ ] HP-5(正常路径)情境:分析产出的场景与上一版行为等价但编号变化|操作:diffSpec 计算场景差异|结果:removed↔added 对折叠为 reason=renumber,不产生变化行 - [ ] HP-6(正常路径)情境:分析产出的场景与上一版为同义改写(如「演示访客」改为「demo 访客」)|操作:diffSpec 计算场景差异|结果:removed↔added 对折叠为 reason=variant,写入 folded 审计,changes 为空 - [ ] HP-7(正常路径)情境:分析产出新规格|操作:insertSpecVersion 执行|结果:写入规格版本并在同事务内重建 path→规格反向索引 - [ ] HP-8(正常路径)情境:仓库已有最新规格版本|操作:loadPreviousSpecText 执行|结果:返回按 position 序的功能与场景全文,供 prompt 锚定 - [ ] HP-9(正常路径)情境:增量分析已确定受影响功能清单|操作:loadPreviousSpecText 传入 prioritize 执行|结果:受影响功能稳定排到最前,其余保持 position 序 ## 规格编辑接口错误映射(规格编辑路由统一解析实体 ID 与错误:非法 ID 抛 400,服务错误按 specEditorErrorInfo 映射状态码与消息。) - [ ] ER-1(错误路径)情境:实体 ID 非正整数|操作:routeEntityId 执行|结果:抛出 400「无效的资源 ID」 - [ ] ER-2(错误路径)情境:编辑操作抛错|操作:editorAction 执行|结果:返回映射后的状态码与错误消息 - [ ] HP-1(正常路径)情境:编辑操作成功|操作:editorAction 执行|结果:返回操作结果与指定成功状态码 ## 证据清洗与提取重试(对每趟提取结果按分区允许集清洗证据,剔除不可溯源声明并留日志;单趟硬失败先重试一次,两次都失败才让 run 失败。) - [ ] EC-1(边界情况)情境:模型引用了本趟未读的文件|操作:sanitizeEvidence 执行|结果:剔除该证据及整条场景/变化,打 warn 日志,其余产出保留 - [ ] EC-2(边界情况)情境:候选全部被清洗后为空|操作:sanitizeEvidence 执行|结果:标记 allCandidatesRejected 并打 error 日志,不伪装成正常空结果 - [ ] EC-3(边界情况)情境:模型输出缺 changes 键|操作:parseAnalysisContent 执行|结果:changes 归一化为空数组 - [ ] EC-4(边界情况)情境:证据数组为空|操作:isTestOnlyEvidence 执行|结果:返回 false,不标记为测试佐证 - [ ] EC-5(边界情况)情境:证据以 JSON 字符串或带 evidence 字段的场景对象传入|操作:isTestOnlyEvidence 执行|结果:解析出证据数组后按同一口径判定 - [ ] EC-6(边界情况)情境:证据含 CI/锁文件等基础设施文件|操作:evidenceKind 执行|结果:仍判为 implementation,不标记为测试佐证 - [ ] EC-7(边界情况)情境:部分证据路径不在允许集内|操作:sanitizeEvidence 执行|结果:剔除不可溯源声明,droppedClaims 计数增加,证据完整性维度为 partial - [ ] ER-1(错误路径)情境:单趟提取重试后仍失败|操作:extractPassWithRetry 执行|结果:错误向上抛出,run 失败 - [ ] ER-2(错误路径)情境:响应不含完整 JSON 对象|操作:parseAnalysisContent 执行|结果:抛出 AI response did not contain a JSON object - [ ] ER-3(错误路径)情境:模型输出结构不可解析|操作:parseAnalysisContent 解析|结果:schema 校验失败并抛错,交由重试与 run 失败如实暴露 - [ ] ER-4(错误路径)情境:某趟候选全部被清洗|操作:deriveEvidenceIntegrity 执行|结果:allCandidatesRejectedPasses 计数增加,证据完整性维度为 failed - [ ] HP-1(正常路径)情境:模型引用的证据路径都在本分区允许集内|操作:sanitizeEvidence 执行|结果:证据全部保留,返回清洗摘要且 droppedClaims 为 0 - [ ] HP-2(正常路径)情境:单趟提取首次调用抛错|操作:extractPassWithRetry 执行|结果:重试一次,重试调用照常落 LLM 回执,成功则继续 - [ ] HP-3(正常路径)情境:模型在合法 diff 路径前后带零宽字符|操作:parseAnalysisContent 执行|结果:证据路径去除不可见字符后通过允许集校验 - [ ] HP-4(正常路径)情境:模型输出证据列表超过上限|操作:parseAnalysisContent 在 schema 校验前执行 capEvidence|结果:证据截断为前 5 条,解析继续成功 - [ ] HP-5(正常路径)情境:模型输出证据为 JSON 字符串或带 evidence 字段的场景对象|操作:isTestOnlyEvidence 读取证据|结果:兼容三种形状解析出证据数组并判定是否全部非实现代码 - [ ] HP-6(正常路径)情境:场景证据含实现代码路径|操作:isTestOnlyEvidence 执行|结果:返回 false,按实现证据对待 - [ ] HP-7(正常路径)情境:模型输出的证据路径都在允许集内|操作:sanitizeEvidence 执行|结果:证据保留,keptClaims 计数增加,证据完整性维度为 complete ## 证据链接与证据强度分级(按路径把证据分为实现、测试、文档等强度等级,并识别证据全部来自测试/文档的场景,供展示标记与发布影响降权使用。) - [ ] EC-1(边界情况)情境:证据入参为带 evidence 字段的场景对象|操作:isTestOnlyEvidence 执行|结果:递归取出 evidence 数组后判定,全部非实现代码时返回 true - [ ] EC-10(边界情况)情境:证据数组为空|操作:isTestOnlyEvidence 执行|结果:返回 false,不把无证据场景判为测试佐证 - [ ] EC-11(边界情况)情境:证据路径为 CI 工作流或锁文件等基础设施文件|操作:isTestOnlyEvidence 执行|结果:evidenceKind 仍判为 implementation,返回 false,保持可见不冒进 - [ ] EC-2(边界情况)情境:证据路径为 CI 工作流或锁文件|操作:isTestOnlyEvidence 执行|结果:evidenceKind 仍判为 implementation,不视为测试佐证 - [ ] EC-3(边界情况)情境:传入空证据数组|操作:isTestOnlyEvidence 执行|结果:返回 false,不判为测试佐证 - [ ] EC-4(边界情况)情境:传入带 evidence 字段的场景对象或 JSON 字符串|操作:isTestOnlyEvidence 执行|结果:递归取出证据数组后按同一口径判定 - [ ] EC-5(边界情况)情境:证据包含任一实现代码文件|操作:isTestOnlyEvidence 执行|结果:返回 false,不标记为测试佐证 - [ ] EC-6(边界情况)情境:证据路径为测试或文档文件|操作:evidenceKind 执行|结果:返回 test 或 document,全部非实现时 isTestOnlyEvidence 为 true - [ ] EC-7(边界情况)情境:证据路径为绝对路径、含反斜杠或含 ..|操作:evidenceUrl 执行|结果:返回 null,不生成链接 - [ ] EC-8(边界情况)情境:证据路径为 CI 配置或锁文件|操作:evidenceKind 判定|结果:仍按实现代码处理,isTestOnlyEvidence 返回 false - [ ] EC-9(边界情况)情境:传入的是 behavior_changes 的 before/after 场景对象|操作:isTestOnlyEvidence 执行|结果:读取对象上的 evidence 字段继续判定,不因非数组形状返回 false - [ ] HP-1(正常路径)情境:证据路径为普通源码文件|操作:evidenceKind 执行|结果:返回 implementation - [ ] HP-2(正常路径)情境:证据路径为 tests/ 目录或 .test./.spec. 文件|操作:evidenceKind 执行|结果:返回 test - [ ] HP-3(正常路径)情境:场景证据全部来自测试或文档|操作:isTestOnlyEvidence 执行|结果:返回 true,展示层可打「测试佐证」标 - [ ] HP-4(正常路径)情境:场景证据含至少一条实现代码路径|操作:isTestOnlyEvidence 执行|结果:返回 false,按实现证据对待 - [ ] HP-5(正常路径)情境:证据路径指向测试或文档文件|操作:EvidenceLinks 渲染证据|结果:链接前显示 [测试] 或 [文档] 标记 - [ ] HP-6(正常路径)情境:场景证据全部来自测试/文档|操作:isTestOnlyEvidence 执行|结果:返回 true,供场景卡片打「测试佐证」标与总览影响降权 - [ ] HP-7(正常路径)情境:证据路径指向实现代码且提交 SHA 合法|操作:evidenceUrl 执行|结果:返回带 #L 行号锚点的 GitHub blob 链接 - [ ] HP-8(正常路径)情境:场景证据全部来自测试/文档|操作:isTestOnlyEvidence 执行|结果:返回 true,供展示层打「测试佐证」标与影响投影降权 - [ ] HP-9(正常路径)情境:场景证据全部来自测试或文档路径|操作:isTestOnlyEvidence 执行|结果:返回 true,场景被标记为测试佐证 ## 超管手工充值(超管按邮箱给用户个人工作区 Trial 钱包发放 SAU,同一 reason 幂等不重复发放。) - [ ] EC-1(边界情况)情境:邮箱、数量或原因不合法|操作:渲染充值表单|结果:发放按钮禁用并提示待填写项 - [ ] ER-1(错误路径)情境:充值接口返回错误|操作:点击发放|结果:显示失败状态码与错误消息 - [ ] HP-1(正常路径)情境:超管填写合法邮箱、SAU 数量与原因|操作:点击发放|结果:发放成功并显示钱包余额,或提示同 reason 已发放过 ## 超管支付操作面板(超管支付页可创建 0.01 元联调测试单并展示支付参数,查看最近 20 笔订单台账并对已支付订单发起退款。) - [ ] EC-1(边界情况)情境:订单台账为空|操作:渲染订单表格|结果:显示「暂无订单。先创建一笔测试单。」 - [ ] ER-1(错误路径)情境:测试单创建或退款接口失败|操作:提交操作|结果:显示对应失败消息 - [ ] HP-1(正常路径)情境:超管需要联调支付链路|操作:点击创建 0.01 元测试单|结果:展示微信二维码或 H5/支付宝链接并提示 webhook 自动履约 - [ ] HP-2(正常路径)情境:订单已支付且未退款|操作:点击退款|结果:提交退款请求并提示退款状态与金额 ## 远程源码分区装配(按仓库树与预算规划源码切片,多趟分区提取并排除已选路径,按字节硬顶整文件包含,证据允许集与实际进 prompt 的文件对齐。) - [ ] EC-1(边界情况)情境:装配后文件总字节超过 AI 上下文预算|操作:sliceToSourceFiles 执行|结果:贪心整文件包含,超预算即停,被排除文件不留在证据允许集 - [ ] ER-1(错误路径)情境:仓库没有任何可分析源码|操作:getPartitionedAnalysisSources 执行|结果:抛出 No supported source files found - [ ] HP-1(正常路径)情境:仓库存在可分析源码且预算充足|操作:getPartitionedAnalysisSources 执行|结果:返回按规划顺序装配的分区源码与共享索引 - [ ] HP-2(正常路径)情境:单窗仓库实现面不超过窗口|操作:getRemoteAnalysisSources 执行|结果:返回恰好 1 个分区,行为与分区装配一致 ## 连接检查接口(按连接 ID 与工作区校验编辑权限后执行连接检查,ID 非法返回 404。) - [ ] ER-1(错误路径)情境:连接 ID 非正整数|操作:POST 连接检查接口|结果:返回 404 与「连接 ID 无效」 - [ ] HP-1(正常路径)情境:编辑者请求检查连接|操作:POST 连接检查接口|结果:返回检查结果状态与响应体 ## 通知渠道与投递(管理产品级 Slack/webhook 通知渠道(目标加密落库、UI 只显示 host+path)与成员邮件偏好;分析成功后 best-effort 投递行为变化摘要,单渠道失败只记 deliveries 不回滚分析。) - [ ] EC-1(边界情况)情境:本次分析没有行为变化|操作:renderNotificationText 执行|结果:返回 null,不发送任何通知 - [ ] EC-2(边界情况)情境:检测到规格坍缩或单功能坍缩|操作:renderNotificationText 执行|结果:通知正文附带坍缩警告行,提示核实变化明细 - [ ] ER-1(错误路径)情境:单个渠道投递失败|操作:deliverAnalysisNotifications 执行|结果:记录 failed 投递与错误,继续投递其他渠道,不回滚分析状态 - [ ] HP-1(正常路径)情境:产品配置了启用的通知渠道且本次分析产生行为变化|操作:deliverAnalysisNotifications 执行|结果:按渠道发送 Slack 文本或 webhook payload,并记录 sent 投递 - [ ] HP-2(正常路径)情境:成员开启了该产品的邮件偏好|操作:deliverAnalysisNotifications 执行|结果:经 Chandler /v1/mail/send 发送摘要邮件并记录 sent 投递 ## 通知渠道设置(产品设置页配置 Slack 与通用 Webhook 通知渠道,可启停、测试、删除,并可开关个人邮件摘要。) - [ ] EC-1(边界情况)情境:尚未配置任何通知渠道|操作:渲染渠道列表|结果:显示「尚未配置通知渠道。」 - [ ] ER-1(错误路径)情境:通知渠道操作接口失败|操作:执行保存、测试、启停或删除|结果:显示操作失败错误消息 - [ ] HP-1(正常路径)情境:编辑者填写 Webhook 地址并保存渠道|操作:提交通知渠道表单|结果:渠道保存并刷新列表 - [ ] HP-2(正常路径)情境:已配置通知渠道|操作:点击测试|结果:发送测试消息并提示「测试消息已发送」 ## 邀请邮件与邀请令牌(邀请令牌以 SHA-256 哈希落库、7 天有效;邀请邮件经 Chandler 注册验证码接口发送,接受邀请时校验邮箱一致并写入组织成员。) - [ ] EC-1(边界情况)情境:令牌不存在、已接受或已过期|操作:getInvitationByToken 执行|结果:返回 null,接受邀请时抛 invitation_invalid - [ ] ER-1(错误路径)情境:接受邀请时登录邮箱与邀请邮箱不一致|操作:acceptOrganizationInvitation 执行|结果:抛出 invitation_email_mismatch - [ ] ER-2(错误路径)情境:Chandler 注册邮件接口返回 400 或 409|操作:sendInvitationEmail 执行|结果:返回 false 表示邮件未发送 - [ ] HP-1(正常路径)情境:受邀用户携带有效令牌登录且邮箱与邀请一致|操作:acceptOrganizationInvitation 执行|结果:写入 organization_members 并把邀请标记 accepted ## 集成连接客户端(前端调用仓库列表、GitHub 连接检查/断开、仓库连接检查/删除与第三方仓库连接保存接口,统一解析错误消息。) - [ ] ER-1(错误路径)情境:仓库列表接口返回非 2xx|操作:fetchGitHubRepositories 执行|结果:抛出接口 error 或「仓库列表读取失败」 - [ ] ER-2(错误路径)情境:连接保存响应缺少 accountLogin|操作:saveRepositoryConnection 执行|结果:抛出接口 error 或「连接保存失败」 - [ ] HP-1(正常路径)情境:已选择 GitHub 连接且需要浏览仓库|操作:fetchGitHubRepositories 执行|结果:按 connectionId 与 page 请求 /api/repositories 并返回仓库列表与 hasMore - [ ] HP-2(正常路径)情境:需要保存 Gitee/GitLab/Gitea 仓库连接|操作:saveRepositoryConnection 执行|结果:POST /api/integrations/repositories 并返回含 accountLogin 的连接结果 ## 集成页反馈与连接状态展示(集成页把接口错误码或成功码映射为提示文案并区分样式,按连接状态显示已连接/已断开,按是否具备凭据决定展示 App 安装还是 PAT 回退。) - [ ] EC-1(边界情况)情境:连接状态非 active|操作:connectionStatusLabel 执行|结果:显示「已断开」 - [ ] EC-2(边界情况)情境:未配置 Personal Access Token|操作:patPresentation 执行|结果:返回禁用态、未配置标签与「选择 GitHub App 安装」选项 - [ ] HP-1(正常路径)情境:连接操作返回成功码|操作:integrationFeedback 执行|结果:返回成功文案且 isError 为 false ## 零行为变更窗口沿用(窗口内无实现级行为变更(纯文档/注释/格式提交)时跳过全部 AI 提取,上一版规格原样沿用、零变化,并沿版本链继承覆盖率回执。) - [ ] EC-1(边界情况)情境:零行为变更窗口但整条版本链无覆盖率回执|操作:runAnalysisBody 执行|结果:写入诚实的零回执并打 warn 日志 - [ ] EC-2(边界情况)情境:仓库尚无上一版规格|操作:loadLatestSpecFeatures 执行|结果:返回 null,无法沿用 - [ ] EC-3(边界情况)情境:零行为变更窗口且仓库无上一版规格|操作:runAnalysisBody 执行|结果:无规格可沿用,按既有空态处理 - [ ] EC-4(边界情况)情境:零行为变更窗口且上一版无有效覆盖率回执|操作:loadInheritedCoverageReceipt 执行|结果:沿版本链向上取最近有效回执,避免落合成零回执 - [ ] EC-5(边界情况)情境:窗口内无实现级行为变更但 diff 命中功能证据面|操作:runAnalysisBody 执行|结果:不激活增量重提取,避免文档内容被写成假场景 - [ ] ER-1(错误路径)情境:零行为变更窗口但找不到上一版规格|操作:runAnalysisBody 执行|结果:抛出 no-behavioral-change window but no previous spec found - [ ] HP-1(正常路径)情境:已有上一版规格且本窗口无行为变更文件|操作:runAnalysisBody 执行|结果:跳过 AI 提取,规格原样沿用上一版,release 说明声明无行为变化 - [ ] HP-2(正常路径)情境:零行为变更窗口且版本链上存在有效覆盖率回执|操作:loadInheritedCoverageReceipt 执行|结果:继承最近有效回执作为本版覆盖率 - [ ] HP-3(正常路径)情境:窗口内只有文档或注释变更|操作:runAnalysisBody 执行|结果:跳过 AI 提取,上一版规格整体沿用,不产生行为变化 - [ ] HP-4(正常路径)情境:窗口内仅有文档/注释/格式提交|操作:runAnalysisBody 执行|结果:上一版规格原样沿用,零变化,不调用 AI 提取 - [ ] HP-5(正常路径)情境:窗口无实现级行为变更且存在上一版规格|操作:runAnalysisBody 执行|结果:上一版规格原样沿用,零变化