# 项目当前总览 > 当前阶段:导航任务 1—10、TAC 认证客户端、领域上下文基础与 M07 反馈客户端已经完成;T01、认证、家谱工作区、G03 原子创建、M06 帮助、个人资料读写、通知读写、M10 服务端退出、M04 登录态改密和 M05 手机号换绑后端接口门禁均为红灯,继续逐域关闭真实接口 > 当前状态:A01/A04/A05 已接入统一 TAC、真实短信和认证请求代码,M07 已接真实反馈提交 owner;G01/G05、G03、M06、M01/M02/M03 个人资料读写、N01/N02/M01/G01 通知域、M10 退出域、M04 密码凭证域与 M05 换绑域已完成三人接口审查和失败门禁,均未猜测接线;`runtimeConfig.mode` 仍为 `mock`,MuMu 原生矩阵和真实环境联调待执行 > 当前基准 HEAD:`9b0ad62df467f4e2c58b7689087683c77755e07b`(`main`,工作区有本轮未提交变更) > 更新日期:2026-07-23 ## 2026-07-23 换机续作断点 ### 总目标与完成定义 本项目的总目标不可缩减为“只写规划”或“只让静态测试通过”:必须在 `main` 工作区内持续推进整个 UniApp 家谱项目,按测试先行和三人交叉评审完成导航、T01 长世代世系树、TAC/认证、家谱领域数据、G/T/F/R/N/M 全量页面与接口、异常恢复、无障碍、构建及上线验证,最终交付能够正常上线使用的项目。若本地可完成的工作全部完成后只剩后端合同重导、有效测试账号、应用签名、发布凭证或 MuMu 人工操作等外部状态,才允许停在明确硬阻塞;每项阻塞必须有失败门禁、复现证据、唯一所有者、解除条件和继续步骤,不能用 mock、fixture、定时器或宽松兼容伪装完成。 协作固定为当前主代理加两位评审者,共三人。三人都必须独立检查接口/字段、页面/业务闭环、交互/异常/视觉,再交叉质询并统一结论;主代理是唯一写入者,不再创建旧专家身份或增加并发评审者。普通技术取舍由三人自行收敛,不反复交给用户。系统保存的目标记录仍存在,但在 2026-07-23 读取时状态为 `paused`;换机后的执行者不得据此把任务视为取消,应以上述总目标和本节断点继续。只有项目真实达到完成定义时才能标记完成。 ### 仓库与保护基线 - 当前分支为 `main`,HEAD 为 `9b0ad62df467f4e2c58b7689087683c77755e07b`,上游显示 `main...origin/main`。工作区含大量本轮未提交的修改、删除和新增文件,均属于当前连续治理成果;换机后先运行 `git status -sb` 和 `git rev-parse HEAD` 核对,禁止用 `restore/checkout/reset` 清理,也禁止自行改分支或 worktree。 - 本节仅记录断点,没有执行 `git add/commit/push`。由用户自行上传;换机后必须保留当前完整工作区,而不能只依赖旧远端基线。 - 后端唯一目标地址是 `https://backend-api.ddxcjp.cn/`。受保护 `APP.openapi.yaml` 的 SHA-256 为 `8964CD583CE172425B63BBFD802F7EB587EB3641EADFD6F9D3B264FAA8090C6C`,`APP.openapi.json` 为 `87DB1DC148C5E6E877815AFF7B3A7FC7C7ECA95A2CEC50A88B42F3908961F31A`;两文件相对 HEAD 无差异。不得修改、格式化、覆盖或删除,只接受后端同一版本重新导出的双文件。 - 不得启动、关闭或调整 MuMu。浏览器截图和源码检查不能冒充 Android 原生视觉、TalkBack、系统字号、软键盘或返回键验收。 - 当前物理测试库存仍是 PowerShell `140`、Node `47`。最近一次完整记录为 PowerShell `126/140`,14 项均是预期发布红灯;Node 语法 `47/47`、纯 Node `19/19`、活动 Vue 脚本 `64/64` 通过。G03 最后一次布尔类型加固后又单独通过聚焦合同;换机后应先重跑完整套件,不能把这些历史数字冒充新机器证据。 ### 已完成到哪里 导航任务 1—10、统一 TAC 客户端、领域上下文基础和 M07 真实反馈客户端已经完成本地可完成部分。T01、认证/TAC、家谱工作区、M06、个人资料读写、通知读写、退出、密码、手机号换绑均已经三人审查并建立明确 OpenAPI 红灯。任务 35 已完成 G03 原子创建合同:否决空谱加通用人物的两写方案,固定一次 atomic bootstrap、无 PII operation-status、统一 accessPreset、可信地区、词法 ID、始祖不变量及客户端激活门禁;`openapi-yaml-json-parity-runtime-smoke.js` 已升级为严格 YAML mapping 和任意精度数字的完整双源深比较。尚未批量把这些红灯域接到宽松线上接口,`runtimeConfig.mode` 仍诚实保持 `mock`。 ### 当前精确断点:任务 36 普通加入申请闭环 三人已经完成 G06/G08/G09/G10 与 2026-07-22 线上 OpenAPI 的只读核对,范围只包括“鉴权搜索公开可申请家谱 → 普通申请 → 我的申请/撤回 → 待审列表/单条审核”。邀请码校验和直接加入仍是后续独立任务,产品结论保持“邀请码成功后直接加入且不生成审核记录”,不得混入普通审核合同。 已统一的最小正确方案如下: - 搜索、我的申请和待审列表使用各自专用最小投影与稳定 cursor 分页,不返回 `total`,所有 `genealogyId/applyId` 都是有界词法字符串。搜索项只暴露识别家谱所需字段和当前查看者状态;我的申请完整表达 `PENDING/APPROVED/REJECTED/WITHDRAWN`;待审项只含 `applyId/applicantName/relationDesc/applyReason?/submittedAt`,不得泄漏手机号、用户 ID、邀请人或审核人内部字段。 - 申请 body 闭合为 `applicantName/relationDesc/applyReason?`,前两项必填;删除 `phone/inviterUserId`。同账号、租户、家谱最多一个活动 `PENDING`,由数据库唯一约束而非先查后插保证。 - 申请 POST 必须带无 PII 的 `Idempotency-Key`。同 key、同 canonical body 重放同一结果;同 key、不同 body 返回 409。客户端只持久 `{sessionEpoch,requestKey,startedAt}`,不持久姓名、关系和理由。 - 冷启动恢复不复用 `mine` 查询,也不持久表单 PII;新增唯一只读 owner `GET /genealogy/app/genealogies/join-apply-requests/{requestKey}`,以显式 discriminator 返回 `PENDING {resolveBy,retryAfterSeconds}`、`SUCCEEDED {applyId/genealogyId/...无 PII 回执}` 或 `FAILED_NO_COMMIT`。只允许 `ABSENT→PENDING→SUCCEEDED/FAILED_NO_COMMIT`,两个终态不可变;GET 纯读,跨账号/租户/client 统一非泄漏 404,PENDING 必须有收敛期限,从未到达的 key 也必须在可计算时间边界后成为零写 `FAILED_NO_COMMIT`。 - 不引入 `applicationVersion`、`If-Match` 或审核详情端点。申请在 PENDING 时不可编辑,撤回、通过和拒绝都以 `WHERE status=PENDING` 的数据库 CAS 决定唯一赢家。重复相同撤回返回同一 200;重复相同审核决定返回原 200,拒绝时只有规范化后理由相同才算相同动作;相反决定、不同拒绝理由或撤回/审核竞态败方返回 typed 409 和当前最小状态。终态不可改,重新申请创建新 `applyId`。 - 审核 body 只允许 `APPROVE`,或 `REJECT+必填申请人可见 rejectionReason`。批准必须在同一事务完成唯一成员关系和申请终态;G05 的 `canReviewJoinApplications` 只是入口 capability,服务端在事务/CAS 时仍重新验证权限、家谱状态和 `PUBLIC_APPLY`。 - 所有操作 required SaToken 和非空 `clientid`,仅使用 `application/json`、`Cache-Control: private, no-store`,429 带 `Retry-After`。线上三个匿名 GET 当前实测为 HTTP 200 加业务 `code=401`,却与文档 HTTP 401 string 冲突;发布合同必须统一为真实 HTTP 状态与 typed JSON,禁止 `*/*`、200 包装认证错误、`default` 响应和 int64 JSON 身份。 - 客户端结果未知时禁止乐观改列表:申请查专用 operation;撤回刷新 mine 并可安全重放同一 DELETE;审核刷新 pending,行消失只能说“状态已变化/已被处理”,不能冒充本次审核成功。首版不承诺消息中心通知;G09 的 `onShow` 与手动刷新是当前业务真相。 **尚未实施的边界必须原样保留:** `tests/join-application-openapi-contract.ps1` 还没有创建,任务 36 尚未写入实施计划和接口映射,测试计数仍为 140/47;G06/G08/G09/G10 业务代码也没有在本任务中修改。换机后的第一项写操作应是用 `apply_patch` 新增该 OpenAPI 失败门禁,先运行并取得精确 `JOIN-APPLICATION-OPENAPI-CONTRACT BLOCKED`,再把 `API-JOIN-001`—`006`、七个 operation、状态机、隐私投影、竞态和部署反例同步写入现有四份中文权威文档及文档合同。后端门禁通过前页面继续保持诚实本地预览,不写只适配当前宽松线上模型的临时代码。 完成任务 36 的本地门禁、全量回归和三人终审后,继续按独立批次推进邀请码直入、G11 设置写入、G12 字辈真实保存,以及其余 G/T/F/R/N/M 业务域;不得一次混合导航、验证码、领域持久化和无障碍多个阶段。最终仍须完成真实后端联调、构建、签名/隐私配置、MuMu 全流程矩阵和发布终审。 ## 当前目标 阶段 0 的清理和验证基线已经完成。当前主代理与两位固定评审者已完成导航任务 1—10,建立路由注册表、导航网关和零债务门禁,并迁移共享组件与认证、G、T、F、R、N/M 全部活动页面。T01、认证/TAC、G01/G05 家谱工作区、G03 原子创建、M06 帮助、M01/M02/M03 个人资料读取、M02 个人资料写入、N01/N02/M01/G01 通知读写、M10 当前设备退出、M04/全认证密码凭证及 M05 手机号换绑的规范 OpenAPI 合同都已测试先行落地;TAC 客户端批次已经完成,A01 短信登录、A04 注册和 A05 忘记密码当前共用严格验证组件、服务端 `validToken`、4 位短信码与可取消请求,但生产 OTP 目标已收紧为统一 6 位,须等待后端同版原子迁移后再替换客户端,禁止 4/6 双接受。领域基础已把会话与当前家谱 ID 收紧为词法字符串:账号切换和损坏存储清理上下文;给定新列表发现历史 ID 消失或显式目标无权时写入持久失效标记,跨重载也禁止静默切谱;T01 也会在写入路由家谱前拒绝已有失效标记和无访问权限的夹具。M07 已按 `POST /genealogy/app/feedback` 接入严格真实提交,mock 模式固定返回 `WRITE_UNAVAILABLE`,不再伪造成功。后端认证门禁未关闭前保持 `mock`;其余尚未接真实写接口的页面仍是明确本地预览或硬关闭。 ## 当前权威资料 - 治理设计:`docs/家谱项目全量治理设计.md` - 当前实施计划:`docs/家谱项目全量治理实施计划.md` - 视觉资产与构建:`docs/视觉资产与构建基线.md` - 页面、流程与接口关系:`docs/接口与页面映射总表.md` - 接口导出:`APP.openapi.json`、`APP.openapi.yaml` - schema v3 视觉资产注册表:`design-pipeline/manifests/runtime-assets.json` - 九宫格所有者:`styles/adaptive-frame-profiles.scss` - 当前预览密码策略所有者:`utils/validation.js`;生产目标 wire/policy owner 等待 `API-PASSWORD-001`—`005` 关闭后原子替换,禁止单页双轨。 - 响应式覆盖:`tests/responsive-layout-coverage.json` - 固定尺寸例外:`tests/responsive-layout-allowlist.json` - 活动路由:`pages.json`;项目固定使用 Vue 3,`uni.scss` 是 Sass 设计令牌唯一入口。 阶段 0 的临时清理清单已在长期结论迁入当前唯一所有者后删除。旧设计记录、规格、计划、交接和 H5/静态设计图中的有效事实已经迁移,旧文件已删除,不再存在并行入口。 ## 接口文档所有权 后端维护的 Apifox 项目是接口合同的唯一编辑源。`APP.openapi.json` 用于离线自动扫描和测试,`APP.openapi.yaml` 用于人工阅读与跨工具导入;两份文件都只接受来自同一后端版本的重新导出,不得分别手工维护。部署地址的 `/v3/api-docs` 只作为当前线上实现证据,发现差异时必须推动同版本双导出更新,不能反向覆盖受保护文件。 当前 JSON 文档为 OpenAPI `3.0.1`,包含 `112` 条路径、`153` 个操作和 `72` 个模型。`tests/openapi-yaml-json-parity-runtime-smoke.js` 已使用无第三方依赖、无损任意精度数字且严格校验 mapping 分隔符的结构化解析器深比较完整 JSON/YAML;相邻不安全大整数差一反例已先红后绿,当前两份受保护快照语义一致。后端今后必须同版本双导出,任何单边漂移都会在领域合同前失败。 后端在 2026-07-22 新提供 `https://backend-api.ddxcjp.cn/`。同日 21:52(Asia/Shanghai)只读获取其 `/v3/api-docs`,线上为 OpenAPI `3.1.0`、`722` 条路径、`858` 个操作和 `507` 个模型;本地 112 条路径中有 109 条仍在线,`/genealogy/app/files/reference`、`/genealogy/app/files/upload`、`/genealogy/pc/files/upload` 三条不在当前线上文档,线上另有 613 条路径。线上模型已把部分 `Genealogy*Body` 重命名为 `AppGenealogy*Body`,`GenerationPoemBatchBody` 也新增了由路径写入的 `genealogyId` 字段,因此本地双导出是明确的旧快照,不能再代表当前部署的完整合同。`utils/config.js` 的唯一 `baseUrl` 已更新为无尾斜杠的 HTTPS 地址;`mode` 仍保持 `mock`,在页面接口和安全合同逐批闭合前不得提前切换远端。 线上文档已经提供 `/captcha/require`、`/captcha/challenge`、`/captcha/verify`:挑战与校验绑定 `tenantId/clientId/sceneCode/subject`,校验成功响应可返回 `validToken`,而发送短信的 `AppSmsCodeBody` 已把 `validToken` 列为必填。客户端已按 `APP_SMS_LOGIN/APP_REGISTER/APP_FORGOT_PASSWORD` 三个精确场景实现“查询要求→取得挑战→供应商完成→服务端校验→携票发送短信”,注册和找回提交不重复执行 TAC;认证请求只接受 HTTP 200 的严格 JSON envelope,统一 15 秒超时,离页或返回会中止当前 RequestTask。密码登录体尚无 `validToken`,因此 A01 以短信登录为默认且密码登录入口保持不可用,绝不以客户端先滑动冒充服务端强制校验。 认证后端门禁仍有四组问题:`API-AUTH-TAC-001` 要求密码登录加入服务端可消费的同语义票据;`API-AUTH-TAC-002` 记录线上 `/captcha/challenge` 在 `APP_REGISTER` 实测返回 HTTP 500 且空响应;`API-AUTH-TAC-003` 要求验证请求以 provider discriminator/`oneOf` 严格关闭根对象和各 payload 的额外字段,并补齐必填 `providerCode/captchaType/payload`;`API-AUTH-TAC-004` 要求同一验证中心返回服务端绑定的 verification session、可验证方法和同一类短时单次 `validToken`,`required=false` 也必须直接签发可供短信接口消费的票据,不得形成无障碍绕过。`tests/auth-tac-openapi-contract.ps1` 当前输出 `AUTH-TAC-OPENAPI-CONTRACT BLOCKED`。密码登录、短信登录和注册的线上成功响应已统一为 `RAppLoginVo → AppLoginVo.access_token`,客户端旧令牌字段读取已删除。线上文档自身仍发布 `http://backend-api.ddxcjp.cn` server URL,与已验证可用的 HTTPS 地址不一致;客户端只能使用显式 HTTPS,后端还需修正文档 server 声明。对 `http://localhost:5173` 的预检已返回允许 `content-type/clientid`,这不能替代正式 H5 域名的 CORS 验证。 家谱工作区只读审查已固定 `/genealogy/app/genealogies/mine` 为可访问集合 owner、`/genealogy/app/genealogies/{genealogyId}/overview` 为 G05 唯一详情 owner;首批不同时请求语义重复的 `/{genealogyId}`。线上 `AppGenealogyVo.genealogyId` 仍是 JSON `integer/int64`,最大合法值进入 JavaScript 后会不可逆失真;三个相关模型均无 `required`,也没有必填 `canView`,`roleType` 无枚举。无令牌实测三条读取均返回 HTTP 200、`application/json;charset=UTF-8` 与 `{code:401,msg,data:null}`,但文档只列 200/401 且 401 为字符串,尚不能稳定区分登录失效、对象无权、已删除和服务故障。问题单 `API-GENEALOGY-WORKSPACE-001`—`003` 与 `tests/genealogy-workspace-openapi-contract.ps1` 已建立;同版本双导出通过前不写 G01/G05 专属 adapter,不用本地字段猜测替代服务端 owner。 M06 三人审查选择 `GET /genealogy/app/help-articles` 的完整列表作为唯一远端 owner;线上列表模型已经包含 `helpContent`,因此页面不调用详情端点、不消费 `helpId`,也不让 JSON `int64` 进入页面模型。每次响应只允许显式投影 `helpCategory/helpTitle/helpContent`,分类从当前列表动态派生,展开键只在当前响应生命周期内使用并在搜索、分类、刷新前清空。当前受保护双导出仍返回通用 `ListResult/RList`,线上 `RListHelpArticleVo/HelpArticleVo` 又没有 `required`,正文格式、仅发布内容、展示顺序和认证失败承载也未形成一致合同;匿名实测列表与详情均为 HTTP 200+业务 `code=401`,而线上文档声明 HTTP 401 string。问题单 `API-M06-001`—`003` 与 `tests/help-center-openapi-contract.ps1` 已建立;门禁通过前保留明确本地 FAQ,不写 live-only adapter。 个人资料读取三人审查固定 `GET /genealogy/app/auth/profile` 为 M01/M02/M03 共用的唯一接口 owner。首批只要求 canonical 11 位 `phone` 必填;`nickName/realName/email` 未设置时唯一省略,出现时必须是非空规范字符串,姓名最多 30、邮箱格式有效且最多 100。adapter 立即把明文手机号变为掩码和读屏标签,只输出固定页面模型;`userId/avatar/status` 等字段全部丢弃,因此它们的 int64/枚举不阻塞本批。受保护双导出仍是通用 `ObjectResult/RObject`,线上 `RAppProfileVo/AppProfileVo` 则无 required 和字段边界;匿名实测仍是 HTTP 200+业务 401,与文档 401 string 冲突。问题单 `API-PROFILE-READ-001`—`003` 与 `tests/profile-openapi-contract.ps1` 已建立;门禁通过前不把 live-only 字段接进页面。 通知三人审查把读取与写入拆成两个原子批次。读取唯一使用 `GET /genealogy/app/notifications` 和 `GET /genealogy/app/notifications/unread-count`:列表必须完整返回当前账号最多 200 条活动通知并按最新优先,未读数精确统计同一集合;页面只消费完整纯文本标题/正文、带时区时间和 `READ/UNREAD`,所有服务端 ID、发送者与业务目标都不进入公开页面模型。N02 没有详情接口,首批只能以当前内存 `generation+ordinal` 的 `snapshotKey` 打开完整快照,重启、账号切换或成功刷新后的旧 key 均提示返回消息中心重新打开。已读写入另由两个 POST 持有,要求无损字符串 `notificationId`、当前账号幂等、read-all 截止点和并发新消息语义;通过前删除伪本地已读而不发请求。当前受保护双导出的列表仍是通用模型且没有未读数路径,线上模型无 required/枚举/容量,所有 ID 仍为 int64,匿名实测又是 HTTP 200+业务 401。问题单 `API-NOTIFICATION-READ-001`—`003`、`API-NOTIFICATION-STATE-001`—`003` 以及两项失败合同已经建立,均不以猜测代码绕过。 M02 资料写入三人审查保留现有 `PUT /genealogy/app/auth/profile` 作为唯一 App owner,但要求后端把它正式定义为原子 dirty-only merge,而非全资源替换或依赖 DTO 惯例猜测。请求只允许脏的 `nickName/realName/email`:省略保持,昵称出现时必须非空,真实姓名/邮箱的精确空串表示清空,null、纯空白和边界空白非法;成功返回完整 canonical `RAppProfileVo`,清空后的可选字段仍省略。并发沿用 T01 的单一版本模型:`AppProfileVo.profileVersion` 是 opaque string,PUT 必带同形状 `If-Match`,旧版本返回 409 `PROFILE_VERSION_CHANGED`,H5 CORS 同步允许该 header。受保护双导出还是旧 `ProfileUpdateBody → RObject`,线上则是无 required/merge/version/security 的 `AppProfileUpdateBody → RAppProfileVo`;当前页面还把同一 fixture 名称同时填入昵称和真实姓名,并用 500ms 定时器伪造本地校验。问题单 `API-PROFILE-UPDATE-001`—`004` 与 `tests/profile-update-openapi-contract.ps1` 已建立;GET 门禁和本门禁通过前不接写入。 M10 退出三人审查固定 `DELETE /genealogy/app/auth/logout` 只撤销请求中 bearer 所属的当前设备凭证族;同账号其他设备保持登录,“全部设备退出”必须另立接口。活动、已撤销和已过期但仍可验证为本 client 签发的历史凭证重复 DELETE 都返回同一个 200 `RVoid`,且成功后旧 token 对任何受保护接口均不可用;伪造、格式非法或 client 不匹配才返回 typed 401 拒绝。客户端唯一 `logoutCoordinator` 在同一同步临界段捕获 A 的 token/clientid、清本地 token/家谱上下文并 bump epoch、用显式快照创建不绑定 M10 生命周期的请求,然后立即 `goRoot(A01)`;异步回调永不再次 clear,避免误删随后登录的 B。线上 endpoint 虽存在,却无 security/clientid、required RVoid、范围/幂等/复用反例和 JSON/no-store;问题单 `API-LOGOUT-001`—`003` 与 `tests/logout-openapi-contract.ps1` 已建立。任何远端失败都不恢复本地 token,只区分“已从本机退出;服务器撤销已确认/未确认/未能撤销”。 M04 改密三人审查否决当前登录/注册/找回/改密共用的静态 32 个十六进制字符 MD5 wire:它是可直接重放的密码等价物,也使服务端无法执行真实新密码策略。唯一生产目标是四条入口原子迁移到 HTTPS 中的 raw `writeOnly` 密码;当前密码与登录兼容 1—64 Unicode code point,新密码统一 15—64 code point、NFC、允许空格与 Unicode、无组成规则,并由服务端执行常见/泄露密码 blocklist、账号限速和带独立盐的自适应慢哈希。M04 当前密码就是重新认证,TAC 不替代身份;用户明确要求的 A01/A04/A05 TAC 仍由原认证门禁持有。严格 200 前服务端必须原子落密、提升 `credentialEpoch` 并撤销包括调用者在内的所有 access/refresh session,客户端清本机回 A01;网络、超时、畸形响应或 5xx 也是结果未知,同样清本机且不自动重试。问题单 `API-PASSWORD-001`—`005` 与 `tests/password-change-openapi-contract.ps1` 已建立;门禁通过前 M04 保持诚实本地预览。 M05 换绑三人审查否决“活动 bearer+新号验证码”直接改号:这只能证明控制新号码,不能证明当前账号本人。唯一生产流程是活动 session、最终 PUT 内 raw `currentPassword` 重新认证、`APP_PHONE_CHANGE` TAC 和新号严格 6 位 OTP;不强制旧号 OTP,避免用户丢失旧号时永久锁死,但成功事务必须持久写入旧号安全通知 outbox。标准 OpenAPI 无法按公共发码 body 的 `sceneCode` 条件化鉴权,因此采用独立且强制 SaToken 的 `POST /genealogy/app/auth/phone/sms/code`,scene 由路径固定;公共 `/auth/sms/code` 删除 `APP_PHONE_CHANGE`,两个 operation 仍复用同一 OTP 生成、限速和存储 owner。最终 `PUT /auth/phone` body 只含 `currentPassword/phone/smsCode`,在同一事务内消费 OTP、执行号码唯一约束、更新号码、提升 `credentialEpoch`、撤销包括当前在内的全部 access/refresh session并写通知 outbox,严格 200 返回 `RVoid`。无密码账号返回 `STEP_UP_UNAVAILABLE`,不能降级;最终 PUT 的超时、5xx、畸形响应或进程终止均按结果未知清本机回 A01且不自动重试。问题单 `API-PHONE-001`—`005` 与 `tests/phone-change-openapi-contract.ps1` 已建立;M04 raw-password 门禁、认证/TAC 门禁和本门禁通过前,M05 保持诚实本地预览。 G03 创建链路三人反向质询后否决“先建空谱、再写始祖”的 `ROOT_REQUIRED` 两写方案:当前产品没有跨会话保存空谱的需求,而两写会凭空增加半成品配额、可见性、恢复、取消、过期和第二次未知结果。唯一生产目标是第一步只在本页收集资料,最终按钮以 `AppGenealogyBootstrapBody` 一次原子创建家谱、OWNER 成员关系、带数据库权威标记的唯一一世始祖、READY 状态和幂等回执;通用人物 collection、人物 DELETE 与 parents mutation 必须阻断第二根、删除根和重挂父母,人物 PUT 对根的可编辑白名单精确只有 `name/sex/birthDate/biography`,其他字段全部 typed 422。首次 POST 先以短控制事务认领 PENDING/digest/fencing,再由业务事务完成全部写入,任一步失败全回滚并 CAS 终态;结构化转换只允许 `ABSENT→PENDING→SUCCEEDED/FAILED_NO_COMMIT` 且终态不可变,FAILED 机器保证零领域写与零 quota,PENDING 的 `resolveBy<=claimedAt+2 分钟`。`GenealogyBootstrapOperationKey` 由 13 位服务端判定的 issuedAt 毫秒与至少 128 位 CSPRNG 组成,`acceptUntil=issuedAt+10 分钟`、最大未来偏差 5 分钟,并由 600/300 秒扩展锁定;operation-status GET 无 body、纯读且只返回显式 discriminator 的三个状态,截止前 404 保持同 key,截止后无记录按 key 计算 FAILED 而不写墓碑。请求使用受鉴权 `/genealogy/app/region/search`、词法 `GenealogyRegionCode`、服务端 `selectable` 和统一 `GenealogyAccessPreset=MEMBER_ONLY/PUBLIC_APPLY`,同版删除公共地区旧路由,并递归清除组合 schema 中的 `visibility/joinMode` 及旧 create/update DTO;G11 在本批只取得共享字段形状,其 If-Match、版本/CAS、权限刷新与结果未知仍是独立门禁。客户端仅持久 `{sessionEpoch,operationKey,startedAt}`;`IDEMPOTENCY_KEY_REUSED` 必须进入 fatal/quarantined,禁止查询或安装 status、自动换 key,只有用户明确放弃才能清理;其他分支按可证明未提交与 unknown 分离。成功固定按 receipt→`/mine` cache→context→G05 收口,context/导航失败只重试本地闭环。问题单 `API-G03-001`—`005`、完整双源深比较、后端 `tests/g03-bootstrap-openapi-contract.ps1` 和实际执行状态机套件的客户端 `tests/g03-bootstrap-client-release-gate.ps1` 已建立;G03 两门禁转绿仍不能绕过家谱工作区读取门禁、聚焦/全量回归与 MuMu 原生验收,全部通过前保留诚实本地预览,不接 `appApi.createGenealogy`。 当前 JSON 的 SHA-256 为 `87db1dc148c5e6e877815aff7b3a7fc7c7eca95a2cec50a88b42f3908961f31a`,YAML 的 SHA-256 为 `8964cd583ce172425b63bbfd802f7eb587eb3641eadfd6f9d3b264faa8090c6c`。两份文件均已被 Git 跟踪,当前相对 HEAD 无差异;本轮没有改写、格式化或覆盖接口导出。 ## 必须保护的用户文件 - `APP.openapi.yaml`、`APP.openapi.json`:后端接口离线源快照,只接受同一后端版本的双导出替换,不得手工修改。 - `static/tac/`:当前共 5 个文件,其中 4 个是后端提供且不可改写的供应商文件,第 5 个是项目适配器 `static/tac/js/jiapu-tac-adapter.js`;A01/A04/A05 已形成真实运行时消费者,文件集合与供应商哈希由 `tests/auth-tac-integration-contract.ps1` 唯一保护。 - 当前五份中文治理文档:长期唯一入口,随已验证进度同步更新,不另建平行计划。 任何清理批次都不得覆盖、恢复或删除以上文件。 ## 清理前基线 - 五个核心验证:全部通过。 - PowerShell 合同:`129` 个,`128` 个通过,`1` 个旧 A01 固定画布合同失败。 - Vue 覆盖:实际 `66`、清单 `66`、缺失 `0`、陈旧 `0`。 - Vue 中 `100% 100% no-repeat`:`0`。 - Vue 中直接声明 `border-image-slice`:`0`。 - 文档:`261` 个;PowerShell 测试:`129` 个;Node 测试:`29` 个。 - `static/`:`128` 个正式文件,约 `95.45 MiB`。 以上数字只记录清理起点,不是必须保持的目标。 ## 阶段 0 最终结果 - 旧 A01 固定画布、PSD、Photoshop、v2 按钮和旧卷轴入口已经三人一致退役;没有通过重建旧预览制造假绿。 - schema v3 注册表已经完整覆盖当前 `static/assets`:认证直接资产、其余应用直接资产、共享卷轴、六张长页面背景和 G01 空态边框各有唯一 owner;旧 G01 候选与模块背景清单及注册例外已经删除。 - `design-pipeline/manifests/shared-scroll-skins-v3.json` 只拥有母版、处理、物理输出和质量规则,不再拥有页面槽位或 `uni-app mode`。 - 阶段 0 验收时,`tests/runtime-assets-contract.ps1` 精确闭合 `79` 个正式输出、物理文件和源码消费者;导航任务 3 又删除了退役通用页面唯一虚构消费的两张 notification frame,当前正式输出为 `77` 个,并由 `tests/retired-module-page-contract.ps1` 防止旧入口与孤立资产回归。 - 设计管线当前为 Node `25/25 PASS`、Python `19/19 PASS`;四张共享卷轴、六张长背景和 G01 空态边框均可真实重建并通过质量审计。 - 质量报告只含工作区相对路径;确定性测试证明相同输入连续两次得到相同字节哈希与报告。 - 六张长背景与 G01 空态边框迁移后的可见像素哈希逐张等于迁移前正式图;连续两次构建的文件 SHA-256 也完全一致。旧 Sharp 单用途依赖和专用构建器已删除。 - 已删除 `28` 个无运行时消费者的 `static/assets`、`3` 个旧 `static/icons`、`4` 个未接入业务的 TAC 文件和 `8` 个候选或伪母版;两张用户批准的 A01 选型图作为 `reference-only / non-runtime` 视觉锚点保留。 - 阶段 0 验收时的 MuMu 证据:`emulator-5554` 当时在线,ADB 设备字段为 `model:SDY_AN00`,系统型号为 `SDY-AN00`,物理尺寸 `720×1280`,density `320 dpi`。本轮原生截图逐张打开复核了 A01、G01、T01 和 F01,未见缺图、透明错误、异常裁切或样式回退;复核结束后已回到 A01 页面,未启动、关闭或调整模拟器。 - `docs/接口与页面映射总表.md` 已按 `pages.json` 建立 `52/52` 活动页面映射;A04、G 系列第一轮、T01 和新线上 OpenAPI 差异已有专项结论,其余具体接口仍标记为“待对应业务阶段 OpenAPI 审查”。 - 第一轮六项产品优化已经完成:G01/G06 统一读取受控查询参数,G03 在本轮进一步删除了无业务参数的 `onLoad`;AppDialog 统一安全区与高度预算;AppTabbar/GenealogyCard 补齐可访问点击语义;G10 拒绝原因建立错误关联与失败聚焦;A04/A05/M04 统一消费唯一密码策略;T01 可在视图漂移后精确回到当前成员。 - 后续产品阶段按顺序为导航栈语义统一、T01 大规模世系树、短信验证码完整状态机、跨页面领域数据持久化、全局文字层级和无障碍第二轮;不得混合实施。 - 文档权威迁移已删除 `198` 个旧 Markdown、`35` 张旧 H5/静态设计图、`4` 个只保护旧资料的测试和 `.superpowers/sdd` 的 `12` 个过程文件;阶段 0 临时清单随后也已删除,当前 `docs/` 只保留 `5` 个长期中文 Markdown 入口。 - 浏览器截图链已把 G03、G06、G08—G12、T06、F02、N01 的有效状态断言迁回各自现有运行时合同;G01、T03—T08、T07 三个有价值的浏览器测试只剥离截图写盘,继续验证状态、滚动、溢出与交互。 - 已删除固定 Chrome 截图助手、联系表、8 个只保护截图助手的合同,以及迁移后重复的 N01/A02 合同;`tests/mumu-visual-acceptance-boundary-contract.ps1` 现在唯一约束“仓库不维护自动截图证据链、最终视觉通过只来自 MuMu”。 当前物理库存为 `140` 个 PowerShell 合同、`47` 个 Node 文件和 `4` 个 JSON 合同数据文件。最新 fresh 结果为 PowerShell `126/140` 通过;其余 14 项不是可删除的普通回归,而是保留真实外部或发布阻塞的 `tests/lineage-openapi-contract.ps1`、`tests/auth-tac-openapi-contract.ps1`、`tests/genealogy-workspace-openapi-contract.ps1`、`tests/g03-bootstrap-openapi-contract.ps1`、`tests/g03-bootstrap-client-release-gate.ps1`、`tests/help-center-openapi-contract.ps1`、`tests/profile-openapi-contract.ps1`、`tests/profile-update-openapi-contract.ps1`、`tests/notification-read-openapi-contract.ps1`、`tests/notification-read-state-openapi-contract.ps1`、`tests/logout-openapi-contract.ps1`、`tests/password-change-openapi-contract.ps1`、`tests/phone-change-openapi-contract.ps1` 和缺少 MuMu 人工证据时必须失败的 `tests/auth-android-accessibility-release-gate.ps1`。十四个输出分别为 `LINEAGE-OPENAPI-CONTRACT BLOCKED`、`AUTH-TAC-OPENAPI-CONTRACT BLOCKED`、`GENEALOGY-WORKSPACE-OPENAPI-CONTRACT BLOCKED`、`G03-BOOTSTRAP-OPENAPI-CONTRACT BLOCKED`、`G03-BOOTSTRAP-CLIENT-RELEASE BLOCKED`、`HELP-CENTER-OPENAPI-CONTRACT BLOCKED`、`PROFILE-OPENAPI-CONTRACT BLOCKED`、`PROFILE-UPDATE-OPENAPI-CONTRACT BLOCKED`、`NOTIFICATION-READ-OPENAPI-CONTRACT BLOCKED`、`NOTIFICATION-READ-STATE-OPENAPI-CONTRACT BLOCKED`、`LOGOUT-OPENAPI-CONTRACT BLOCKED`、`PASSWORD-CHANGE-OPENAPI-CONTRACT BLOCKED`、`PHONE-CHANGE-OPENAPI-CONTRACT BLOCKED` 和 `ANDROID-AUTH-ACCESSIBILITY-RELEASE BLOCKED`。Node 语法 `47/47` 通过,纯 Node 冒烟 `19/19` 通过,活动 Vue 脚本模块语法 `64/64` 通过;导航源码扫描保持 `MIGRATION-DEBT=0`。依赖 `127.0.0.1:9222` 调试页的浏览器运行时文件本轮只做语法检查,没有执行;这不能冒充浏览器行为或 MuMu 原生视觉通过。 阶段 0 清理结束时,`static/` 的正式基线为 `79` 个文件、共 `70,414,397` 字节。任务 3 退役两张孤立通知 frame 后,正式 `static/assets` 为 `77` 个文件、共 `69,093,742` 字节;`static/tac/` 当前 5 个文件、共 `68,190` 字节,因而当前 `static/` 物理库存为 `82` 个文件、共 `69,161,932` 字节。4 个供应商文件保持原字节并由哈希合同保护,新增适配器是唯一项目映射层;TAC 已进入 A01/A04/A05 业务运行时,但不属于可重建视觉资产注册表。`tmp/`、`unpackage/` 和 `design-pipeline/generated/` 均不存在;正式生成资产仍由清单和构建器恢复,质量报告不作为长期资料保留。 ## 当前规划结论 ### 导航栈 - 迁移前 52 个活动页面只读统计为 `navigateTo 59`、`navigateBack 11`、`redirectTo 14`、`reLaunch 7`,活动页面合计 91 次;活动组件另有 4 次,封存 A06 另有 2 次。任务 3—9 已依次迁移共享组件、认证、G、T、F、R、N/M,任务 10 删除最后一个无消费者旧表单组件并关闭门禁。当前 pages/components 中 `navigateTo`、`navigateBack`、`redirectTo`、`reLaunch`、`getCurrentPages` 和业务页面路径字面量均为 `0`,`switchTab` 全项目为零;五种 Uni 导航调用和页面栈读取只允许由 `utils/navigation.js` 持有,业务路径只允许由 `utils/navigation-routes.js` 持有。 - MuMu 已复现 F01→F03 返回后残留两个 F01、A01→A04→登录后残留两个 A01、T03 同路由连续叠页,以及栈深为 1 时 F03 错回 G01。 - 三人终选并已实现两个唯一所有者:`utils/navigation-routes.js` 持有 52 条路由、父页参数映射和结果操作枚举,`utils/navigation.js` 持有五种 Uni 导航 API、五个公开导航语义方法、一次性结果与统一返回优先级;没有真实替换边,因此不公开替换方法。 - G01、F01、M01 保持自定义 Tab 根页;A01 是认证根页。T03 只保留一个原生页面实例,初始路由 `personId` 是不可变宿主页身份,亲属浏览使用页内成员轨迹和可变活动成员;T05 本地预览离开使用 `goBack()`,不会把活动成员误写成宿主页路由身份。 - 任务 1—10 已完成测试先行和静态实现;一次性结果绑定真实目标路由与业务参数上下文,只能由当前真实栈顶目标页消费。52 个活动路由、共享组件、四个根语义以及认证、G、T、F、R、N/M 系列均已迁移;通知目标只能由本地类型白名单映射,未知或越权目标失败关闭。未接真实写接口的页面只能形成明确的本地预览或硬关闭,不再展示伪保存、伪邀请码、伪订单或伪安全结论。任务 4—10 的 MuMu 原生流程复核仍因本轮禁止触碰模拟器而待执行,静态零债务不能替代该验收。 ### T01 大规模世系树 - 此前默认 6 人数据中的 103→106 断线已通过唯一成员 owner 与字符串 `parentId` 修复;普通节点实际半高与全局常量仍相差约 4rpx,10×12 压力数据约 45/54 个父分组仍会断线,而旧测试只检查线段数量。 - 当前布局最坏为 `O(G×N)`,单人一代时接近 `O(N²)`;页面与 mock 已统一当前阶段的 `id/parentId` 夹具,但 OpenAPI 仍使用递归 `children/spouses`,无法直接对接未来规范图窗口。 - 产品终选“焦点成员渐进窗口+独立全谱概览”,初始上二代/下二代;主世系为骨架,配偶并排,每段家庭关系有独立联合点,子女从对应联合点向下。 - 技术终选视口大小的单 Canvas 同画节点和边;纯 JavaScript 按“规范化→严格校验→可见投影→确定性布局→Scene/空间索引→相机”处理,DOM 只保留页头、工具条、两档抽屉、搜索、概览和无障碍线性列表。 - 本地旧导出和 2026-07-22 线上 OpenAPI 都只有 v1 `/lineage/tree`,仍是递归模型,并缺少 overview、locator、稳定关系寻址和树版本并发合同。最新线上文档的 `722` 条路径中没有任何 `/genealogy/app/v2/`,`507` 个模型中也没有新图辨识字段,四个稳定业务码同样缺失。后端问题单 `API-T01-001` 已固定四条 v2 路径、FOCUS/BOUNDARY 查询、`schemaVersion/treeVersion`、EMPTY/POPULATED 空谱判别、窗口入口与全谱根分离、严格匿名节点、以 `relationshipKind` 判别的可寻址伴侣/父子关系、空 PATCH 错误码和 Scene 原子版本;`tests/lineage-openapi-contract.ps1` 已建立严格红灯,在同版本线上文档与双导出通过前,T01 客户端不得开始任务 12。 - 当前实施轮没有改写 OpenAPI 文件,也没有启动、关闭或调整 MuMu;已完成导航共享所有者、共享组件/根页头部语义、退役死入口、认证、G 系列、T 系列和 F 系列导航合同,以及树成员与家族内容夹具统一。认证请求代码已对准真实端点,但运行模式仍失败关闭;G/T/F 系列真实写接口与 T01 新图尚未接入。 ### TAC 认证与无障碍安全边界 - `utils/auth-verification.js` 是当前认证场景、4 位短信码和服务端票据形状的唯一客户端 owner;生产目标由后端 `SmsCodeSecret` 和 `tests/phone-change-openapi-contract.ps1` 锁定为严格 6 位,门禁通过时必须一次替换所有活动消费者并删除旧 owner 的四位规则。`components/TacVerification.vue` 是验证浮层与 renderjs 生命周期 owner;`static/tac/js/jiapu-tac-adapter.js` 是 TianAi challenge/proof/verify 映射 owner;`utils/api.js` 是严格 HTTP 200 envelope、15 秒超时、离页中止、认证会话写入和反馈 wire payload 的唯一 owner。旧认证专用请求控制器入口、占位验证、伪验证码、宽松令牌兼容和 M07 假提交均已删除。 - A01 默认短信登录;密码登录因 `API-AUTH-TAC-001` 保持可见但不可用。A04/A05 都只在发送短信前验证一次,并在手机号改变后使旧验证码上下文失效;成功、失败、取消、重复回调、空响应、非 JSON、超时、离页和返回键均有静态或纯运行时合同。短信发送与重设密码的 `RVoid` 没有声明 `data` 必填,客户端因此只要求合法 HTTP 200 与整数成功 `code`,并把“省略 data”或 `data:null` 都精确归一为 `null`;登录、注册和 challenge 等有实体响应仍强制 `data`。 - 当前客户端浮层已补齐对话框命名、说明关联、初始聚焦、Tab 圈定、Escape/Android 返回、焦点恢复、原生刷新与关闭按钮、48px 目标及小视口内部滚动;这只是客户端壳层预检,不代表第三方滑块本身可由 TalkBack 或键盘完成。`tests/auth-android-accessibility-release-gate.ps1` 要求 MuMu 原生证据与非拖动等价验证方式,证据缺失时固定输出 `ANDROID-AUTH-ACCESSIBILITY-RELEASE BLOCKED`。 - 三人交叉质询后的唯一方向是“同一验证中心、同一短时单次 `validToken`、供应商无关的服务端决策”,永久禁止 `accessibility=true`、跳过 TAC 或无票据发短信。中国大陆非交互风控供应商只进入限时 POC,必须在真实 UniApp Android WebView 中证明 TalkBack、外接键盘和 Switch Access 无焦点陷阱且误杀、防刷、弱网与故障指标达标,不能预先写成无障碍完成。已安全绑定设备只能作为加权信号;供应商不确定或不可用时进入支持文字/中继的可审计人工兜底或稍后重试,绝不 fail-open;音频验证码仅为后续独立 POC 候选,不能作为 P0 或唯一替代。 ### 领域上下文与 M07 反馈 - `utils/genealogy-context.js` 只接受无边界空白的非空词法字符串 ID,并持有独立失效标记;`utils/session.js` 在损坏令牌、退出和账号令牌变化时同步清理 ID 与标记。首次且没有历史选择或标记时可确定选择首个可用家谱;针对调用方提供的新列表,历史选择消失或显式目标不可用时写入标记并由 G01 要求用户明确重选,跨重载也禁止静默串谱。真实后台撤权能否被及时发现仍取决于后续 workspace 的 onShow/事件刷新。 - `appApi.submitFeedback` 是反馈提交唯一 owner:只接受 `feedbackContent` 必填、`feedbackType/contactInfo` 可选的三个字符串字段,trim 后删除空选填值;调用方不能关闭认证头。remote 精确 POST `/genealogy/app/feedback`,只认 HTTP 200 且 `code` 为整数成功码的 envelope;反馈响应没有声明 `data` 必填,页面也不消费返回实体。mock 固定失败关闭且不调用网络。 - M07 提交中禁用输入并使用提交前快照;成功后保留回执内容并禁止原样重复提交,请求期若仍有迟到输入则明确区分“上一份已提交”和“当前修改未提交”。超时、断网、意外 2xx/3xx、HTTP 408/5xx 或响应无效进入 `uncertain`,同一快照禁止重提;unknown 回流也会重新比较当前表单,迟到输入保持可提交而不冒充旧快照。只有确定拒绝才允许重试。`tests/m07-feedback-state-runtime-smoke.js` 已直接执行这些页面状态;真实服务联调仍受认证远端门禁约束。 ### 家谱工作区远端门禁 - 三人反向质询后没有要求后端把 `AppGenealogyVo` 全部字段设为必填,也不把缺少 `security` 注解或文档媒体类型 `*/*` 单独宣称为数据泄漏。首批只消费 `genealogyId/genealogyName/canView/canManage/canEditContent/roleType`;前五项需明确类型并必填,`roleType` 还需非空正式枚举。地点、堂号、人数和简介可选并由页面诚实降级,未知额外响应字段允许忽略。 - JSON 响应身份必须使用非空词法字符串。仅在客户端拒绝 unsafe number 虽可避免串谱,却会让 OpenAPI 合法的 int64 用户永久不可用,不能作为普遍上线方案;URL path 在 wire 上本就是文本,不机械要求为了同一问题改类型。 - `/mine` 必须以必填 `canView` 或等价、可自动验证的投影保证只把当前账号仍可查看的家谱送入 context;G01 只有成功取得新列表才 reconcile。网络、超时和 5xx 保留旧现场并显示错误,明确撤权/无权/不存在才写 tombstone。G05 使用 `/overview`,取消迟到请求并在新身份加载前清掉旧数据,远端失败绝不回退 fixture 角色。 - OpenAPI 注解修复后仍须用有效账号执行无凭证、跨账号、撤权、删除、5xx、畸形 JSON 和取消反例;当前无令牌 HTTP 200+业务 `code=401` 的承载方式可以保留,也可改规范 HTTP 状态,但文档、运行时 validator 与部署行为必须一致。 ### M06 帮助内容远端门禁 - 首批只使用 `/genealogy/app/help-articles` 一次取得完整正文;详情接口、文章深链、封面、浏览量和业务 ID 均不属于 M06。adapter 只准输出 `{category,title,content}` 与当前响应生命周期的展示键,必须显式丢弃 `helpId/status/sortOrder/viewCount/coverOssId/remark`。 - 响应 envelope 的 `code/data` 和每行 `helpCategory/helpTitle/helpContent` 必须 required;三项均为非空字符串,分类是可直接展示标签,正文首版固定为纯文本。用户侧列表只返回已发布内容,数组顺序就是展示顺序;客户端不猜分类码、不解释 HTML/Markdown。 - 搜索与筛选只作用于已投影数组;筛选后不得重新编号。搜索、分类和刷新先收起正文,新请求以 controller+generation 拒绝迟到响应,离页取消请求;空列表、搜索无结果、加载失败和认证失效必须分别表达。 - M06 现有分类和问题标题使用 `` 且触控高度不足;真正接线时改为原生按钮语义,补 `aria-pressed/aria-expanded/aria-controls`、状态播报、重试和至少 44dp 目标。源码审查不能替代 MuMu 的系统字号、TalkBack、焦点与视觉验收。 ### 个人资料读取远端门禁 - 唯一 profile adapter 在 mock/remote 两种模式都产出同一窄模型;运行模式必须经 `resolveRuntimeMode()` 校验,错误配置不得静默回 fixture。remote 使用严格 envelope、15 秒超时、请求取消和 generation 防迟到,不建立跨账号缓存或经路由传递个人资料。 - 原始手机号只在 adapter 局部验证 canonical 格式,输出仅含 `maskedPhone` 与“绑定手机号,尾号 xxxx”读屏标签;页面、日志、错误、缓存和路由都不得接触明文。可选昵称、实名、邮箱只有真正省略时规范为内部空串;出现 null、空白、超长或非法邮箱时整份失败关闭。 - M01 的加载/失败只替换身份卡,服务菜单与底栏保持可用,并删除查询参数制造的假错误和“重试即成功”;通知 fixture 不得与真实身份混装为线上数量。M02 完成异步填表后才建立 dirty baseline,GET 不冒充 PUT 保存;M03 只让手机号行局部加载/失败,密码入口不受普通读取失败影响,并删除不属于账号资料的“创建者”角色。 - 真正实施时原子替换禁止页面调用 API 的旧静态断言,使用 `AppLoading` 和原生按钮,补 M02 的 `aria-invalid/aria-describedby`、失败聚焦、状态播报、44dp 目标、长昵称换行和装饰图隐藏;MuMu 仍须验证系统字号、TalkBack、焦点与真实纹理对比。 ### 通知读取与已读状态远端门禁 - 读取批次以无筛选列表作为当前账号完整活动集合 owner,`RListNotificationVo.data` 允许空但最多 200 条并按 `publishTime` 最新优先;`RNotificationUnreadCount.data` 为 0—200,精确等于同一活动集合中 `readStatus=UNREAD` 的数量。两个请求之间发生并发新消息时允许瞬时差异,客户端不得据此判错。 - `NotificationVo` 的首批 required 字段为 `noticeTitle/noticeContent/publishTime/readStatus`:标题 1—50、完整正文 1—1000 且为纯文本,时间必须是带时区 RFC3339,状态只允许 `READ/UNREAD`。N01 摘要最多显示 160 个字素,N02 展示同一快照的完整正文;长文本必须换行,不解释 HTML、Markdown、URL 或服务端跳转字段。 - 读取 adapter 只公开 `{snapshotKey,title,content,publishedAt,unread}`,key 由成功响应 generation 与映射前 ordinal 组成;不持久化、不使用裸序号,也不把 `notificationId/genealogyId/bizId/bizType/senderPhone` 暴露给页面。成功刷新原子替换 generation,退出和账号切换立即清空;N02 不能解析 key 时只提示“请返回消息中心重新打开”。 - 首批删除通用“前往入谱审核”、详情目标按钮和从消息字段猜路由;后端将来只有提供闭合的 `bizType → route key+必填词法参数+权限/失效语义` 字典后才可独立恢复 CTA。M01/G01 共同消费未读数 owner,文案统一为“未读消息”,可见角标封顶 `99+`,读屏仍播报真实数量。 - 写批次通过前,打开 N01/N02、点击“标记已读”或“全部已读”都不得只改本地 clone。写合同通过后,唯一通知 controller 才能私有保留 1—128 位 URL-safe opaque `notificationId`;页面仍只持有 `snapshotKey`。单条和全部已读必须对当前账号幂等;read-all 只覆盖服务端接收时已存在的活动通知,并发新消息保持未读;超时或结果未知时重新读取列表和计数收敛。 - 两个失败门禁分别是 `tests/notification-read-openapi-contract.ps1` 与 `tests/notification-read-state-openapi-contract.ps1`。当前分别输出 `NOTIFICATION-READ-OPENAPI-CONTRACT BLOCKED` 和 `NOTIFICATION-READ-STATE-OPENAPI-CONTRACT BLOCKED`;后端同版本双导出、有效账号反例和 MuMu 状态矩阵完成前不能宣称通知闭环上线。 ### M02 个人资料写入远端门禁 - PUT 请求体唯一 owner 固定为关闭额外字段的 `AppProfileMergeUpdateBody`,只能包含 1—3 个真正脏的 `nickName/realName/email`。昵称出现时为去边界空白的 1—30 字符;真实姓名和邮箱的精确 `""` 是唯一清空命令,非空真实姓名 1—30、邮箱 1—100 且格式有效。省略表示保持,null、纯空白、边界空白、空 body、头像/性别/生日或任意额外字段全部早失败。 - `AppProfileVo` 新增 required `profileVersion`,形状为 1—128 位 URL-safe opaque string;写请求只在 required `If-Match` header 携带,不在 body 建第二版本字段。服务端按当前账号和租户原子 CAS,成功返回含新版本的完整 canonical profile,旧版本固定 409 `PROFILE_VERSION_CHANGED`;相同字段集重复执行不产生通知、审计之外的额外业务副作用。 - M02 首次 GET 完成后才建立 baseline;保存时冻结三个输入和提交快照,成功用响应回填并重置 baseline。确定失败保留草稿;超时、断网、408/5xx 或畸形成功响应属于结果未知,先 GET 逐项核对本次脏字段,匹配则确认成功、仍为旧值才允许重试、第三值进入冲突,不盲目重复 PUT。 - session generation 是账号隔离边界:账号切换、退出和页面卸载中止等待、清空未持久草稿并拒绝旧账号迟到响应;取消 RequestTask 不等于服务端未写。真实姓名、邮箱、提交 payload 和版本不得进入日志、路由、持久缓存或遥测。 - 当前假定昵称必填,所以旧账号昵称省略时可以只改其他字段,但不能把已有昵称清空。头像选择、相册权限、OSS ID、性别和生日全部留到独立批次;当前 `` 假头像动作在写入实施时删除。邮箱没有验证与送达合同,页面不得继续承诺“用于接收通知”。 - `tests/profile-update-openapi-contract.ps1` 当前输出 `PROFILE-UPDATE-OPENAPI-CONTRACT BLOCKED`。后端关闭 `API-PROFILE-UPDATE-001`—`004`、同版本双导出通过、读取 owner 可用、有效账号/CORS 反例和 MuMu 表单矩阵完成前,M02 保持诚实本地校验而不发写请求。 ### M10 当前设备退出远端门禁 - 后端 DELETE 只撤销当前请求 bearer 及同一可续签凭证族;其他设备 token 保持有效。合法签发给同一 client 的 active/revoked/expired token 重复调用统一返回 200 RVoid,操作幂等且无额外副作用;成功后用旧 token 调 profile 等受保护接口必须失败。非法或 client 不匹配返回 `RLogoutRejected`,业务码只允许 `TOKEN_INVALID/TOKEN_CLIENT_MISMATCH`,不能冒充远端已撤销。 - operation 必须 required SaToken 与非空 clientid、禁止 request body、200/401 使用 application/json 并带 `Cache-Control: private, no-store`;RVoid 的整数 code required,另声明 400/429/500。线上仅有文字“需要登录”和 `*/*`,本地虽有 security/clientid 但 RVoid 无 required、只列 200,均未达到发布合同。 - `logoutCoordinator` 是唯一跨页 owner:同步捕获 token/clientid 与 logoutEpoch,立即调用 session owner 清 token、家谱上下文和账号缓存并 bump epoch,再以显式 A 快照创建 RequestTask;整个同步段不 await,M10 页面拿不到 token。创建失败也不恢复;请求不绑定页面 controller,reLaunch/A01/M10 卸载不 abort。 - coordinator 的公开内存态只含 `{attemptId,logoutEpoch,status}`,状态为 pending/confirmed/unconfirmed/not-revoked,不保存 token、请求头或错误 payload。A01 仅在 session 仍为空且 epoch 未变化时原子消费一次提示;B 登录后 A 的迟到结果直接丢弃。进程被杀允许丢提示,但旧 token 不落盘、不排队、不跨重启重试。 - 唯一用户承诺始终是“已从本机退出”。200 显示服务器撤销已确认;network/timeout/408/429/5xx/畸形响应与 generic 401 显示未确认;typed 401/400/403 显示未能撤销。所有分支都留在 A01,不恢复 token、不返回 M10、不重新开放登录后页面;异步 callback/finally 绝不能再次 `session.clear()`。 - `tests/logout-openapi-contract.ps1` 当前输出 `LOGOUT-OPENAPI-CONTRACT BLOCKED`。同版本双导出、两设备 token 隔离/复用反例、真实网络异常和 MuMu 退出提示完成前,只能称现有行为为本机退出,不能宣称服务端注销完成。 ### M04 登录态修改密码远端门禁 - 密码 wire 是跨 A01 登录、A04 注册、A05 找回和 M04 登录态改密的单一合同。`PasswordLoginBody.password` 与 `PasswordChangeBody.oldPassword` 只引用 `CurrentPasswordSecret`;注册、找回和改密的新密码只引用 `NewPasswordSecret`。生产入口不再接受 MD5、十六进制摘要或两套兼容分支;确认密码只留客户端。 - `CurrentPasswordSecret` 是原样、不 trim 的 1—64 Unicode code point;`NewPasswordSecret` 是 NFC 后 15—64 code point,允许空格、Unicode 和密码管理器粘贴,不强制字母/数字组成。服务端才是策略权威,必须执行常见/泄露密码 blocklist、当前密码验证、新旧不同、账号级限速和带盐慢哈希;页面校验只是即时提示。 - PUT required SaToken、非空 clientid 与关闭额外字段的 JSON body;200/400/401/409/422/429/500 均为 typed JSON、`private, no-store`,429 带 `Retry-After`。409/422 用 `RPasswordChangeRejected` 区分 `CREDENTIAL_VERSION_CONFLICT/CURRENT_PASSWORD_INCORRECT/NEW_PASSWORD_SAME_AS_CURRENT/PASSWORD_POLICY_VIOLATION`,不解析 `msg`。 - 唯一会话方案是 ALL:严格 200 前原子写入新 verifier、提升 credential epoch,并让所有设备/所有 client 的旧 access/refresh session 跨节点失效;不返回新 token,也不让当前 bearer 继续存活。200、401、409 和传输结果未知都清秘密与对应本机会话并回 A01;只有明确未写的 400/422/429 可清 `credentialChangeInFlight` 后留页。 - 为关闭 PUT 已发出后进程被杀的窗口,session owner 在发送前只持久化 `{sessionEpoch,startedAt}` marker,禁止保存 token、密码、摘要或 body。冷启动发现同 epoch marker 时必须在任何账号缓存渲染前清会话并进 A01;新登录 bump epoch,使旧 marker 和迟到响应失效。客户端不自动重试、不建 operation-status;重新登录就是最小对账路径。 - `tests/password-change-openapi-contract.ps1` 当前输出 `PASSWORD-CHANGE-OPENAPI-CONTRACT BLOCKED`。后端关闭 `API-PASSWORD-001`—`005`、原子重导双文件、密码登录 TAC 可用、两设备/并发/故障注入与 MuMu 无障碍矩阵完成前,M04 继续显示“不提交服务器”。 ## 三人规则 - 总共三人:主代理与两位固定评审者。 - 三个人都完整检查文档、测试和资产,不割裂分工。 - 审查阶段只读,实际文件变更只由主代理执行。 - 删除候选必须三人一致确认;任意一人提出有效疑点时继续调查。 - 用户已授权三人一致后直接删除,无需逐文件再次确认。 ## 当前禁止事项 - 不执行 Git add、commit、push、restore、checkout 或 reset。 - 不启动、关闭或调整 MuMu。 - 不删除活动业务源码、接口导出、当前权威设计或用户改动;只有三人以消费者、合同和资产清单共同证明已经退役的旧入口才可同轮删除。 - 不因测试失败而删除测试。 - 不因静态搜索无匹配而直接删除资产。 - 不归档确认失效的旧内容,不保留兼容入口。 ## 下一步 1. T01 后端接口门禁已经建立并运行出预期红灯;等待后端按 `API-T01-001` 发布四条 v2 操作并提供同一版本重新导出的 JSON/YAML,不手改当前快照,也不提前实施任务 12。 2. TAC 客户端批次已经完成。认证后端仍须关闭 `API-AUTH-TAC-001`—`004`、提供同版本双导出并修复 challenge 500;随后才允许把 `runtimeConfig.mode` 从 `mock` 切为 `remote`,执行正式 H5 CORS、真实票据重放/限流和 MuMu Android 流程。 3. 并行推进非交互风控的限时 POC 与文字/中继人工兜底合同;只有 POC、服务端原子消费和 `ANDROID-AUTH-ACCESSIBILITY-RELEASE` 全部通过,才可宣称认证达到上线门槛。 4. 新图合同通过后,按规范化与校验、布局、Scene 与空间索引、单 Canvas、页面交互、接口回流的顺序实施 T01。 5. 家谱工作区三人审查和失败合同已经完成;等待后端关闭 `API-GENEALOGY-WORKSPACE-001`—`003` 并提供同版本双导出。门禁通过后再测试先行实现唯一 adapter、G01 `onShow` 列表现场和 G05 `/overview` 读取,不提前固化字段或枚举。 6. G03 原子创建三人审查和失败合同已经完成;等待后端关闭 `API-G03-001`—`005`、以同版本双导出交付 bootstrap POST、状态查询、地区选择与统一 accessPreset。通过前不接当前宽松 `createGenealogy`;通过后先实现严格 coordinator、无 PII 恢复 marker、地区选择器、context/G05/G01 闭环,再独立完成 MuMu 表单与无障碍矩阵。 7. M06 三人审查和失败合同已经完成;等待后端关闭 `API-M06-001`—`003` 并提供同版本双导出。通过后测试先行实现 list-only adapter、加载/空/失败/重试、动态分类、纯文本手风琴和无障碍语义,不接详情或文章 ID。 8. 个人资料读取三人审查和失败合同已经完成;等待后端关闭 `API-PROFILE-READ-001`—`003` 并提供同版本双导出。通过后测试先行实现唯一掩码 adapter 与 M01/M02/M03 局部状态,M05 当前手机号展示随同一只读 owner 原子迁移但不接换绑写接口。 9. 通知读取与已读写入已分别完成三人审查和失败合同;等待后端关闭 `API-NOTIFICATION-READ-001`—`003` 与 `API-NOTIFICATION-STATE-001`—`003`。读取通过后先实现无 ID 的内存快照和 M01/G01 未读数;写入另批迁移私有 ID、删除伪本地写并验证并发收敛,不恢复不可信目标 CTA。 10. M02 个人资料 PUT 已完成三人审查和失败合同;等待后端关闭 `API-PROFILE-UPDATE-001`—`004`。读取与写入门禁都通过后,按 normalizer、严格 API、M02 状态机和 MuMu 表单矩阵独立实施,不混头像或账号安全。 11. M10 服务端退出已完成三人审查和失败合同;等待后端关闭 `API-LOGOUT-001`—`003` 后,再测试先行实现 session epoch、唯一 logoutCoordinator、A01 一次性提示和两设备撤销矩阵。 12. M04 登录态改密与四条密码 wire 已完成三人审查和失败合同;等待后端关闭 `API-PASSWORD-001`—`005` 后,才原子迁移共享密码策略、MD5 调用、session marker、M04 状态机和全设备撤销矩阵。 13. M05 手机号换绑三人审查和失败合同已经完成;等待后端关闭 `API-PHONE-001`—`005`,且 M04 raw-password 与认证/TAC 前置门禁同时通过后,再原子迁移全活动 OTP、实现专用受保护发码、共享 credential marker 与 M05 状态机。 14. 继续审查下一个不依赖现有红灯的业务域;按 G/F/R 逐域推进。随后逐批完成文字层级与无障碍,不混合验证码、账号写入、领域数据或支付。