docs(changelog): #8064 双维度收缩补活体实测 + 写明机制是逐维度各自收缩
changelog-filename-gate / validate (push) Failing after 2s

原文「若该派单同时参与两条共用关系,两条都会受影响」是源码推演,本次补 2026-09-22
自建班期下的双维度活体读数(两条关系同刻 RELEASED/AUTO_SINGLE_MEMBER、4 条成员行
同刻 left_at、未被软清那条派车行完全未动)。

新增一节写明机制:onClaimReleased 只接单个资源维度、方法体内无跨维度查询,
「两条同时 RELEASED」的成因是同一个动作释放了两个维度的占用,不是维度间有传导。
该区别对前端的实际后果落在手工解除关系上——是否连带另一维度取决于释放集算法,
前端别预测,操作后两个维度都重新拉取。

Refs #8064

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
这个提交包含在:
API Changelog Bot
2026-09-22 00:47:32 +08:00
共同撰写人 Claude Opus 5
父节点 3e4133f7a0
当前提交 798b7bcd83
@@ -13,7 +13,7 @@ frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "本条无任何接口出入参或错误码变化,变的是同一请求的副作用:共用关系现在会在成员失去占用时自动收缩、剩余不足 2 人时自动解除。gateway_status=verified 的依据是 2026-09-21 经网关 https://api.test.1814.love:9443 的真实调用(建关系 + 两次 soft-clear-assignment),调用流水与库内终态逐条对照一致,不是只看部署登记。本条会让共用关系『自己消失』,前端是否需要改代码取决于两点:有没有缓存 activeShareGroupId、有没有「关系只能人工解除」的假设。这两点后端查证不了,已由前端侧自查确认(见下文 mmg 的实证)。⚠️ 存量收敛已于 2026-09-21 执行完毕(AC-5):经应用路径点名收敛,摘除成员行 10 条、整体释放关系 4 条;另有 2 条关系在摘除成员后仍保持 ACTIVE——那是正确终态,收缩规则是「剩余成员 < 2 时才整体释放」,这 2 条原各 3 名成员、摘 1 名后仍剩 2 名。本轮为点名执行而非全库扫,名单外可能仍存在同类历史数据,前端展示逻辑该兜的仍要兜。前端实证 not_required(mmg 2026-09-21):按「四、前端要做什么」逐项自查——activeShareGroupId/shareGroup/share-groups/shareEligible 前端 src 全仓零命中(共用关系属 #7444 未接入挂起域,同 #8051/#8061 实证口径),前端无任何共用关系状态缓存、无「关系只能人工解除」的假设;未来接入时均为操作后实时拉取,自动收缩不产生前端脏读。"
updated_at: "2026-09-21"
updated_at: "2026-09-22"
base: "dev-v3"
---
@@ -94,6 +94,26 @@ if (!context.dualWrite()) {
软清会把该派车行的**车与司机一起清空**(车辆 id / 车牌 / 车型 / 司机 id / 姓名 / 电话全部置空,并把当日车辆用量归零)。⇒ 若该派单同时参与了 VEHICLE 维度与 DRIVER 维度的两条共用关系,**两条都会受影响**,不是只动一条。
**2026-09-22 双维度活体实测坐实**(此前这一段是源码推演,现补实测):自建班期下造 2 条派单共用**同一辆车 + 同一个司机**,于是 VEHICLE 与 DRIVER 各成一条 2 人共用关系;软清其中一条派单后,两条关系**各自独立**收缩,**同时**转 `RELEASED`:
| 维度 | 关系状态 | `release_reason` | `released_at` |
|---|---|---|---|
| VEHICLE | `RELEASED` | `AUTO_SINGLE_MEMBER` | `2026-09-21 16:32:26` |
| DRIVER | `RELEASED` | `AUTO_SINGLE_MEMBER` | `2026-09-21 16:32:26` |
两条关系下的**全部 4 条成员行**(含**未被软清**的那一户在两条关系里的成员行)都落 `left_at = 2026-09-21 16:32:26`、`leave_reason = AUTO_OCCUPANCY_RELEASE`;未被软清那条派单的派车行本身**完全未动**(车、司机、状态原样)。
⇒ **前端含义**:一次软清会让该派单参与的**每一个**维度的关系消失。若界面按维度分别渲染共用关系,操作后**两块都要重新拉取**,不能只刷新其中一块。
### 机制是「每个维度各自收缩」,不是「一个维度带动另一个」
自动收缩的触发口是**占用被释放**:`GroupDispatchShareOccupancyRefService#onClaimReleased` 按 `(服务日, 资源维度, 资源 ID, 来源)` 判定,只接**单个**资源维度,方法体内没有任何跨维度查询;上游 `OccupancyDualWriteCoordinator#notifyShareGroupOfRelease` 按**单条**占用行取它自己的维度调一次。⇒ 上一节看到的「两条同时 RELEASED」,成因是**同一个动作释放了两个维度的占用**(软清清整行),钩子因此被各调了一次,**不是**维度之间有传导。
这个区别对前端有实际后果,体现在**手工解除关系**上:
- 调解除接口解除 VEHICLE 维度的关系时,后端按释放集算法决定哪些成员的占用真被释放(被释放的那些会走软清 ⇒ 它们在 DRIVER 维度的关系也随之收缩),**留任的成员占用不变**⇒ 它们在 DRIVER 维度的关系**原样保留**。
- ⇒ **别预测**「解除一个维度会不会连带另一个」——它取决于这次解除把谁判进了释放集。**操作后两个维度都重新拉取**是唯一可靠的做法。
### 整团解除不会被改写成自动收缩
整团解除时,关系的 `release_reason` 仍记录整团解除的原因,不会被自动收缩改写成 `AUTO_SINGLE_MEMBER`(PR #8077)。审计与对账按 `release_reason` 区分来源时,这一点是可靠的。