diff --git a/docs/development/iterations/iteration-3/30-release-e2e-regression.md b/docs/development/iterations/iteration-3/30-release-e2e-regression.md new file mode 100644 index 0000000..8a66c95 --- /dev/null +++ b/docs/development/iterations/iteration-3/30-release-e2e-regression.md @@ -0,0 +1,313 @@ +# 30 首次发布门禁:M2+M3 双份 E2E 回归(checklist 第 2 步) + +- 执行人:QA(Explore / 回归执行) +- 日期:2026-09-10 +- 依据:iteration-3/08 号《Git 工作流规划》**§3.3 发布 checklist 第 2 步**—— + 「compose 全栈起,跑 M2+M3 两份 E2E 烟囱脚本,全场景 PASS,证据入波次报告」 +- 环境:`patbond-api`(docker compose 六容器)+ `patbond-flutter`(dart 脚本直连) +- 测试脚本:`patbond-flutter/test_e2e_m2_manual.dart`(M2 收官版,11 场景) + 与 `patbond-flutter/test_e2e_m3_manual.dart`(M3 收官版,14 场景),均取 `flutter@0e87413` +- 冻结契约:`patbond-doc/docs/api/openapi.yaml` **v1.3.0**(`doc@f848476`) +- 参照模式:iteration-2/28 与 iteration-3/28 号收官报告(格式与取证标准沿用) + +> **三仓代码零改动**:本次只起 compose、跑两份既有脚本、做只读 psql/git 取证。 +> 未修改、未 commit、未 push 任何代码仓;未改 `mkdocs.yml`。 + +--- + +## 0. 执行概要 + +### 门禁结论 + +**PASS**——发布 checklist 第 2 步满足。 + +| 项目 | 结果 | +| --- | --- | +| M2 场景通过数 | **11 / 11**(44 条断言全绿,`exit 0`) | +| M3 场景通过数 | **14 / 14**(88 条断言全绿,`exit 0`) | +| 契约偏差数 | **0 个**(对照冻结契约 v1.3.0) | +| 失败项 | **0 项** | +| 稳定性 | 同一 compose 环境内 **两份脚本各连跑 3 轮**,6 次全通过、零 flake | +| 两域共存 | M2→M3→M2→M3 交叉执行,pet_health 与 community 数据同库共存,互不干扰 | +| 容器异常 | 六容器 RestartCount 全 0;四个应用容器日志 `ERROR`/`Exception` 计数全 0 | + +### 本单目标(与 M3 收官报告的区别) + +M3 版脚本已在 M3 收官(iteration-3/28)跑过 14/14。**本单的增量价值在于复跑 M2 版**: +M3 期间 pets 域未做功能变更,但两域共享 `patbond-common`、契约快照文件、CI 流水线与同一 +数据库实例——需要实测确认 M3 交付没有回归 M2 的宠物健康档案域。为把「共存」也一并证实, +两份脚本在**同一次** compose 生命周期内交叉执行。 + +### 脱敏声明 + +token 一律截断至前 20 字符 + ``(脚本内置 `redact()`);MinIO 预签名 URL 的 +查询串替换为 ``;幂等键显示为 ``;密码与 `.env` 内容不出现在 +任何输出。 + +--- + +## 1. 环境记录 + +### 1.1 构建与启动(patbond-api 代码零改动) + +```bash +cd <你的工作区>/patbond-api +JAVA_HOME=/usr/lib/jvm/java-17-openjdk ./mvnw -DskipTests package +# BUILD SUCCESS —— Total time: 4.263 s(增量编译,五模块 reactor 全 SUCCESS) +# 产出四个 -exec.jar:auth 36MB / community 51MB / pet 25MB / user 41MB + +docker compose up -d --build +# Container patbond-postgres-1 Healthy +# Container patbond-minio-1 Healthy +# Container patbond-user-1 / auth-1 / community-1 / pet-1 Started +``` + +### 1.2 六容器状态与镜像版本 + +```text +CONTAINER REPOSITORY TAG SIZE STATUS +patbond-postgres-1 postgres 18 162MB Up (healthy) +patbond-minio-1 minio/minio RELEASE.2025-04-22T22-12-26Z 64MB Up (healthy) +patbond-auth-1 patbond-auth latest(本次重建) 141MB Up :8081 +patbond-user-1 patbond-user latest(本次重建) 147MB Up :8082 +patbond-pet-1 patbond-pet latest(本次重建) 132MB Up :8083 +patbond-community-1 patbond-community latest(本次重建) 155MB Up :8084 +``` + +| 组件 | 版本 | +| --- | --- | +| PostgreSQL | 18.6 (Debian 18.6-1.pgdg13+2) | +| MinIO | RELEASE.2025-04-22T22-12-26Z | +| 容器内 JRE | Temurin OpenJDK 17.0.20+8 | +| 宿主 Docker | 29.7.2 / Docker Compose 5.5.1 | +| Dart SDK(跑脚本) | 3.12.2 (stable) | + +### 1.3 启动耗时与就绪验证 + +依赖顺序符合编排:postgres/minio 先 Healthy,四应用容器随后 Started(容器创建到启动 +约 3 秒),Spring Boot 自身启动耗时: + +```text +Started AuthApplication in 9.752 seconds +Started UserApplication in 13.194 seconds +Started PetApplication in 9.255 seconds +Started CommunityApplication in 11.135 seconds +``` + +无 token 探活(预期 401 信封): + +```bash +curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8082/api/v1/me # 401 +curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8083/api/v1/pets # 401 +curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8084/api/v1/feed # 401 +``` + +### 1.4 脚本执行耗时(第三轮,取权威计时) + +| 脚本 | 场景数 | 耗时 | 退出码 | `✓` 断言数 | 失败标记 | +| --- | --- | --- | --- | --- | --- | +| `test_e2e_m2_manual.dart` | 11 | **1149 ms** | 0 | 44 | 0 | +| `test_e2e_m3_manual.dart` | 14 | **1662 ms** | 0 | 88 | 0 | + +### 1.5 数据残留说明(非缺陷) + +`pgdata` / `minio-data` 卷延续自 M3 收官那次运行(compose 只重建容器与镜像,未 `down -v`)。 +两份脚本均以时间戳随机账号运行、且 M3 的全量翻页断言按「本轮新增 26 条 vs 全量 117 条」 +的相对口径校验,因此**残留数据不影响判定,反而额外证明了跨轮数据共存无干扰**。 + +--- + +## 2. M2 版 E2E 逐场景结果(11/11 PASS) + +本轮取证账号 `e2e_m2_a_1789025850872`,petId `01a08a40-1ad6-7a26-962c-a5f6cd3706a1`。 + +| # | 场景 | 结果 | 关键断言实测 | +| --- | --- | --- | --- | +| 1 | 注册账号 A → 登录 | ✓ PASS | register 200 / login 200,token `eyJhbGciOiJSUzI1NiJ9...` | +| 2 | 建档(含品种)→ 列表/详情读回 | ✓ PASS | 品种目录 16 条;POST /pets **201**;`myRole=owner`、`version=0`、`breedDisplayName=中华田园犬`;列表/详情四字段一致 | +| 3 | 记体重 ×2 → cursor 分页 | ✓ PASS | 8.20/8.45kg 各 201;第一页 8.45 在前 + `hasMore=true`;第二页 8.20 + `hasMore=false`、`nextCursor=null` | +| 4 | 疫苗登记(scheduled)→ 标记完成 | ✓ PASS | 疫苗目录 6 条;PATCH 200,`version 0→1`,`administeredOn`/`nextDueOn` 回读一致 | +| 5 | 健康事件(整数分)→ 时间线 | ✓ PASS | `amountCents=12500` 原样回读;`createdByUserId` = token subject;时间线 1 条 | +| 6 | 提醒创建 → 标记完成 | ✓ PASS | 创建恒 `pending` + `completedAt=null`;PATCH 后 `completedAt` = 客户端提交时刻 | +| 7 | `/summary?tz=Asia/Shanghai` 四项聚合 | ✓ PASS | 最新体重 8.45kg;疫苗进度 1/1;下次接种 2027-09-10(`source=nextDue`);当月花费 12500 分、`month=2026-09`、tz 回显 | +| 8 | 账号 B 越权访问 A 的宠物四路(防枚举) | ✓ PASS | 详情/体重/疫苗/摘要四路全 **404 / 40401**,响应体逐字节一致 `{"code":40401,"message":"宠物不存在","data":null}`;B 列表为空 | +| 9 | 账号 A 第二设备重新登录 → 全量读回 | ✓ PASS | 新会话 token 与设备 1 不同(独立 token family);宠物 1 / 体重 2 / 疫苗 1 / 事件 1 / 提醒 1 全量一致 | +| 10 | `/api/v1/events` v2 事件上报 | ✓ PASS | 4 条 → **202**,`accepted=4, duplicated=0, rejected=0` | +| 11 | 乐观锁冲突明确性 | ✓ PASS | 第一次 PATCH 200(`version 0→1`);同过期 version 第二次 **409 / 40902**;读回确认先写者数据保留 | + +--- + +## 3. M3 版 E2E 逐场景结果(14/14 PASS) + +本轮取证账号 `e2e_m3_a_1789025861236`,postId `01a08a40-422a-7d60-a915-f04d7b0061be`。 +(三轮运行的断言输出逐条一致,仅随机账号名与 UUID 不同;下表的字面值取自取证轮输出。) + +| # | 场景 | 结果 | 关键断言实测 | +| --- | --- | --- | --- | +| 1 | 注册 A/B 两账号 → 登录 | ✓ PASS | 两账号注册 200 且为两个独立 userId(模拟两客户端) | +| 2 | 两步上传直传 MinIO(`/media/uploads` → complete) | ✓ PASS | 登记 201 返回 SigV4 预签名凭据、`requiredHeaders` 恒且仅 `{Content-Type}`;344 字节直传 200;complete 后 `uploading→ready`(`byteSize=344`、`readyAt` 已写);重复 complete 幂等 200 同一 asset | +| 3 | 草稿创建 → 发布(PATCH draft→published) | ✓ PASS | 草稿 `status=draft`/`publishedAt=null`、media 挂接 `position=0` 且服务端置唯一 `isCover`;发布后 `status=published`、`publishedAt` 已写、`version 0→1` | +| 4 | **验收①** B 拉 `/feed` A 的帖首位可见 | ✓ PASS | `published_at DESC` 首位命中;FeedCard 必填齐备;`AuthorSummary` 不露 bio/username;裁剪生效(无 content 全文/media 整组/version) | +| 5 | 预签名 GET 字节往返 + 桶私有 | ✓ PASS | 344 字节逐字节一致;去签名直访 **403** | +| 6 | **验收②** 连续 3 次 PUT like → count 恰 1 | ✓ PASS | 三次均 200 权威终态 `{liked:true,likeCount:1}`(非 409);DELETE → 0;重复 DELETE 幂等 | +| 7 | 收藏 → `/me/bookmarks` → 取消 | ✓ PASS | 列表项形态 = FeedCard,视角字段为 B;取消后不含 | +| 8 | 评论 ×2 / 作者软删 / 帖主越权删被拒 | ✓ PASS | B 删自己 200;A(帖主)删 B 的 **403 / 40301**;`commentCount` 同事务 +1/-1 准确 | +| 9 | 关注幂等 + follow-stats + 自关注拒绝 | ✓ PASS | 重复 PUT 幂等 200;自关注 **422 / 42204**;自取关 200 no-op;A 查自己 `followedByMe` 恒 false | +| 10 | **验收③** 25 帖 → 双粒度全量翻页比对 | ✓ PASS | limit=7 → 17 页 117 条;limit=100 → 2 页 117 条;两种页大小**逐位一致**,零重复零遗漏 | +| 11 | **验收④** 软删一帖 → 出 Feed + 直接 GET 404 | ✓ PASS | 删后全量恰少 1;B 与作者 A 直接 GET 均 **404 / 40403** 且响应体逐字节一致 | +| 12 | 防枚举:草稿 vs 随机 UUID 响应体一致 | ✓ PASS | 四路全 **404 / 40403** 一致 `{"code":40403,"message":"帖子不存在","data":null}`;互动面恒为公开面;草稿对作者详情仍可见、不入公共 Feed | +| 13 | v3 社区事件上报 + 白名单/字典兜底 | ✓ PASS | 8 条 → **202** `accepted=8`;白名单外键剥离后仍 accepted;字典外 `post_impression` 整条 rejected(`unknown_event_name`),批次仍 202 | +| 14 | 幂等重放:同键同 hash / 异 hash / 缺头 / 跨作者 | ✓ PASS | 同键同 hash 返回原帖不产生第二帖;异 hash **409 / 40905**;缺 `Idempotency-Key` **400 / 40000**;幂等键按作者隔离 | + +--- + +## 4. 数据库证据(两域共存,只读 psql) + +### 4.1 schema 与 Flyway 迁移 + +```sql +-- \dn +community | identity | media | pet_health | platform | public + +-- select installed_rank, version, description, success from public.flyway_schema_history; + 1 | 1 | identity media baseline | t + 2 | 2 | create platform product events | t + 3 | 3 | pet health baseline | t + 4 | 4 | pet health dictionary seed | t + 5 | 5 | community baseline | t +``` + +V1~V5 全 `success=t`,M3 的 V5 未触碰 M2 的 V3/V4(不可变迁移纪律保持)。 + +### 4.2 两域数据行数(六次脚本运行累计,含既有残留) + +```sql + pet_health.pets | 8 community.posts | 131 + pet_weight_records | 9 community.comments | 10 + pet_vaccinations | 7 community.post_likes | 3 + health_events | 6 community.user_follows | 3 + care_reminders | 6 media.assets | 17 + pet_owners | 8 platform.product_events | 61 +``` + +两域各 8 张表并存于同一实例,交叉执行无外键/唯一键冲突、无死锁。 + +### 4.3 埋点落库核对 + +M2 本轮会话(`session_id=1e1a8388-…`,共 4 条 = 上报数): + +```sql + health_record_create_succeeded | android | 1.0.0+e2e | 2 + page_viewed | android | 1.0.0+e2e | 1 + pet_create_succeeded | android | 1.0.0+e2e | 1 +``` + +M3 本轮会话(`session_id=a28da209-…`,8 白名单事件 + 1 条隐私兜底事件): + +```sql + comment_create_succeeded | 1 post_liked | 2 + feed_viewed | 1 post_media_upload_succeeded | 1 + page_viewed | 1 post_publish_succeeded | 1 + post_favorited | 1 user_followed | 1 +``` + +隐私红线兜底与字典守门实测: + +```sql +-- 字典外事件未落库 +select count(*) from platform.product_events where event_name='post_impression'; -- 0 + +-- 混入白名单外 postId 的 post_liked:落库 props 已剥离 +select props from platform.product_events where event_id='bc13cbbd-…'; + {"source": "feed"} -- 无 postId +``` + +--- + +## 5. 契约偏差声明与共享面回归分析 + +### 5.1 契约偏差数:**0 个** + +两份脚本共 132 条断言覆盖 HTTP 状态码、业务错误码、信封结构、字段形态、分页语义、 +幂等语义、乐观锁语义与防枚举一致性,与冻结契约 **v1.3.0** 全部一致,无需修复项。 + +### 5.2 M2 契约面在 v1.3.0 中零漂移(结构化取证) + +M3 期间四模块契约快照从 `openapi-v1.2.0.yaml` 换名到 `openapi-v1.3.0.yaml`, +是本次回归最需要盯的共享面。对 `doc@511617b`(v1.2.0 冻结)与 `doc@f848476`(v1.3.0 冻结) +做结构化比对(YAML 解析后按键排序序列化对比,非文本 diff): + +```text +info.version: 1.2.0 -> 1.3.0 +paths:18 -> 31(+13,全部为 community/media 新增;removed: NONE) + v1.2.0 的 18 条 path 定义 —— CHANGED/MISSING: NONE(全部完全一致) +schemas:45 -> 72(+27) + removed schemas: NONE + changed schemas: NONE +``` + +即 **v1.3.0 相对 v1.2.0 严格增量**:M2 的 18 条路径与 45 个 schema 一字未改, +M2 版脚本对照 v1.3.0 运行等价于对照 v1.2.0 运行。 + +### 5.3 共享代码面回归分析(`64c9b72..8089c06`,即 M3 全区间) + +```text +patbond-pet/src/main/ → 0 个文件变更(pets 域生产代码 M3 期间未被触碰) +patbond-pet/ 变更仅在测试侧:ContractConformanceTest / ContractValidator / + OpenApiContract + 快照文件改名(v1.2.0 → v1.3.0) +patbond-common/ → 仅 ErrorCode.java +9 行,纯新增枚举常量: + POST_ACCESS_DENIED(40301) / POST_NOT_FOUND(40403) / IDEMPOTENCY_PAYLOAD_MISMATCH(40905) + MEDIA_NOT_FOUND(40405) / COMMENT_NOT_FOUND(40404) / TARGET_USER_NOT_FOUND(40406) + MEDIA_NOT_READY(42203) / FOLLOW_RULE_VIOLATION(42204) / MEDIA_UPLOAD_STATE_INVALID(42205) + —— 无任何 `-` 行,M2 错误码(40401/40902/40000…)定义未被修改或删除 +``` + +三条共享面(契约快照、`patbond-common`、同一数据库实例)均验证为纯增量, +与实测的 11/11 结果互为印证:**M3 交付未破坏 M2 功能,无回归**。 + +--- + +## 6. 失败项 + +**无。** 六次脚本运行(M2 ×3、M3 ×3)全部 `exit 0`,输出中 `✗`/`FAIL` 计数为 0, +无需区分「脚本环境问题」与「真实回归」。 + +--- + +## 7. 三仓状态(零改动核验) + +```bash +cd <你的工作区>/patbond-api && git status --short # 空 +cd <你的工作区>/patbond-flutter && git status --short # 空 +cd <你的工作区>/patbond-doc && git status --short # 仅本报告(未 commit) +``` + +| 仓 | HEAD | +| --- | --- | +| patbond-api | `8089c06` feat: 事件字典 v3 白名单扩充…(T3-20) | +| patbond-flutter | `0e87413` test: M3 E2E 烟囱脚本(T3-21 收官) | +| patbond-doc | `3ebe562` docs: M3 收官——E2E 报告与收官总结入档,验收 PASSED | + +(`patbond-api/*/target/` 下的重建产物为 gitignore 覆盖项,不产生工作区脏状态。) + +--- + +## 8. 环境清理 + +```bash +cd <你的工作区>/patbond-api && docker compose down +``` + +数据卷 `pgdata` / `minio-data` 按既往做法保留(未加 `-v`),便于下次复跑与事后取证。 + +--- + +## 9. 遗留与后续 + +1. **真机挂起项不变**:M2 的两项(Android 事件落库真机观察、SessionTracker 30min 手测)与 + M3 的真机项仍按方案 A 挂起,本次脚本直连不替代真机验证——见 `docs/development/device-verification.md`。 +2. **发布 checklist 后续步骤**:本报告只闭合 §3.3 第 2 步;第 3 步(命名统一 + api `main` 重建)、 + 第 4~8 步(合并/打标/分支保护/发布说明/hotfix 纪律)待拍板后执行。 +3. **E2E 自动化仍为手动模式**:iteration-3/08 §5 的结论(保持「波次收尾手动跑、证据入档」, + 自动化做成 `workflow_dispatch` 手动工作流,低优先)未变;本次两份脚本 3 秒内跑完, + 手动成本极低,暂无自动化紧迫性。 diff --git a/docs/development/releases.md b/docs/development/releases.md new file mode 100644 index 0000000..193a70a --- /dev/null +++ b/docs/development/releases.md @@ -0,0 +1,61 @@ +# 发布记录(常设) + +> **定位**:跨迭代常设文档——每次 `dev → main` 发布在此追加一条记录:版本号、三仓 tag 与哈希、门禁证据、已知遗留。 +> **维护约定**:按[发布 checklist](iterations/iteration-3/08-git-workflow-plan.md)(§3.3) 执行,完成后在此登记。最新版本在最上。 +> 发布分支为 `main`(ADR-011 原写 master,ADR-021 更正);日常开发直推 `dev`。 + +--- + +## v0.3.0 — M3 社区(2026-09-10) + +**首次正式发布**,发布流程首次演练。 + +### 三仓 tag + +| 仓库 | tag | 提交 | 内容 | +| --- | --- | --- | --- | +| patbond-api | `v0.3.0` | `8089c06` | 五模块(common/auth:8081/user:8082/pet:8083/community:8084),334 测试 | +| patbond-flutter | `v0.3.0` | `0e87413` | 502 测试 + 三份 E2E 烟囱脚本(M1/M2/M3) | +| patbond-doc | `v0.3.0` | 本记录所在提交 | 契约 v1.3.0 + 三迭代全部报告(20+30+30 份) | + +### 版本内容 + +- **M1 认证纵切**:JWT RS256、refresh 轮换、多设备会话、登录锁定 +- **M2 宠物健康档案**:宠物 CRUD + 三角色权限 + 体重/疫苗/健康事件/提醒 + 档案聚合(18 操作) +- **M3 社区**:图片媒体上传闭环(自托管 MinIO,ADR-016)+ 帖子草稿/发布/删除 + 公共 Feed 游标分页 + 单层评论 + 点赞收藏幂等 + 关注(13 路径/19 操作) +- **契约**:openapi.yaml **v1.3.0 冻结**,31 路径/43 操作/72 schema;契约一致性测试矩阵 173 格、43/43 操作零漂移 +- **部署形态**:docker compose 六容器(postgres:18 + MinIO + auth + user + pet + community),应用容器无状态(ADR-007) +- **数据库**:Flyway V1~V5(identity/media、platform 埋点、pet_health、字典种子、community) +- **决策**:ADR-001~021 + +### 发布门禁证据 + +| 门禁项 | 结果 | 证据 | +| --- | --- | --- | +| 三仓 CI 绿 | ✅ | Gitea commit status API 直查 success | +| 全量测试 | ✅ | api 334 / flutter 502,`mvnw clean test` 与 `flutter test` 双绿 | +| E2E 回归(M2+M3 同环境) | ✅ | **M2 11/11 + M3 14/14**,各连跑 3 轮零 flake,契约偏差 0 — [30 号报告](iterations/iteration-3/30-release-e2e-regression.md) | +| M3 验收标准逐条取证 | ✅ | 四条全过 — [28 号报告](iterations/iteration-3/28-e2e-smoke-report.md) | +| 契约向后兼容 | ✅ | v1.2.0→v1.3.0 结构化比对:paths/schemas **removed 与 changed 均为 NONE**(严格增量) | +| 共享代码面回归分析 | ✅ | M3 全区间 `patbond-pet/src/main/` 0 文件变更;`patbond-common` 仅 ErrorCode +9 行纯新增 | +| 凭证防泄漏 | ✅ | `check-secrets.sh --all` 三仓 exit 0(9 规则两层检查,ADR-021) | + +### 发布操作记录(首次一次性项) + +1. **命名统一**:ADR-011 的 `master` 更正为 `main`(ADR-021);api 本地孤儿 master 已删。 +2. **api main 重建**(方案 A,用户拍板):远端 main 原为建仓自动生成的单提交 `ff876bc "Add README"`,与 dev **无共同祖先**,无法 ff 也不宜缝合孤儿历史。操作:Gitea 默认分支临时切 dev → 删除远端 main → `git push origin dev:refs/heads/main` 重建 → 默认分支切回 main。结果:main 41 提交、与 dev 同点位、零 force push。原孤儿提交保留本地备份 ref `refs/backup/old-main-ff876bc`。 +3. **flutter main 快进**:main 本就是 dev 祖先,用 `git push origin dev:main` 完成——**较 checklist 第 4 步的 `checkout main && merge --ff-only` 改进**:不切换工作区(当时有 E2E 脚本正在该工作区运行),且非快进推送会被 git 自动拒绝,等于内建 ff-only 保护。建议固化此写法。 + +### 已知遗留(不阻塞发布) + +**真机验证四项挂起**(步骤已备齐在[真机验证清单](device-verification.md)):媒体上传弱网、乐观更新手感、Feed 图片加载、社区事件落库;另有 M2 两项(Android 事件落库、SessionTracker 30min)。桌面/脚本不可替代——`platform=linux` 埋点整批 400 属契约内行为。 + +**功能遗留**:完整草稿列表与自动保存、大图下滑关闭手势、`widthPx/heightPx` 恒 null(单图帖回落 4:3)、`eventVersion` 口径未定型、uploading 超时清理任务、429 限流(连带客户端 Retry-After 分支)、话题/关注列表/作者主页(ADR-018 剪出)。 + +**跨迭代技术债**:access token 黑名单(退出后已签发 access 在剩余 ≤15 分钟内仍有效)、`/internal` 改 mTLS。 + +### 发布后生效的纪律 + +- 影响 `main` 的 hotfix 一律走短命分支 + PR(ADR-021 强制情形之二正式生效) +- `main` 分支保护(禁直推、合并需 CI 状态检查通过)在 Gitea 平台启用;`dev` 保持直推流 +- 下次发布 `dev → main` 应能 `--ff-only` 通过;过不了说明 main 被绕过 dev 改动,先查明原因 diff --git a/mkdocs.yml b/mkdocs.yml index 63d2448..c27f894 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -8,6 +8,7 @@ nav: - Git 工作流规范: development/git-workflow.md - 功能完成清单: development/feature-checklist.md - 真机验证清单: development/device-verification.md + - 发布记录: development/releases.md - CI Runner 部署手册: development/ci-runner-setup.md - 第一迭代: - 进展看板: development/iterations/iteration-1/index.md @@ -94,6 +95,7 @@ nav: - 27 第三波收口: development/iterations/iteration-3/27-wave3-closure.md - 28 E2E 烟囱收官: development/iterations/iteration-3/28-e2e-smoke-report.md - 29 M3 收官总结: development/iterations/iteration-3/29-m3-summary.md + - 30 发布 E2E 回归: development/iterations/iteration-3/30-release-e2e-regression.md - API: - 契约说明: api/index.md - 架构: