27 KiB
schema, ticket, title, consumer, author, change_type, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
| schema | ticket | title | consumer | author | change_type | backend_status | gateway_status | frontend_status | frontend_owner | frontend_ref | target_release | verified_at | status_note | updated_at | base |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| hl-changelog/v2 | 8194 | 配置位守卫 582117 的触发集合扩大到「除 DRIVER / OTHER 以外的全部角色」 | admin | wx(GIT) | 修改接口 | deployed | not_required | not_required | 工单 #8194 补的是 #8148 留下的残留缺口。角色↔人员类型的守卫 582117 判的是「该角色在配置位字典里查不到归属位」,而它的分流判据(GroupBatchStaffSlotResolver#participatesInSlotsByFallback)读的是编译期常量兜底名单,只认 GUIDE / LEADER / PHOTOGRAPHER。问题是 #7079 / #8148 立下的能力恰恰是「业务在字典页面加一行就能把某个人员类型配进配置位、不发版」——靠字典新增出来的角色永远不在这张常量名单里,于是「字典给某位加一行 → 有人按它配了人 → 那行又被删掉」这一形态仍走静默放行分支:接口 200、脏行落库、并异步扇出到团内全部活跃订单,该角色的 582114 当场失效,要到结算对账才发现人岗对不上。关键一点是撞上它不需要有人手搓请求——resolveStoredStaffRole 会把落库的 staff_role 改写成人员的真实类型(字典角色),前端回显后原样提交回来,系统自己就会产出那个落进缺口的 staffRole 值。修法(2026-09-23 定案 B,判据翻面):把「本该有位」的判据从「在不在兜底名单里」换成「不在结构性豁免闭集 STRUCTURALLY_SLOT_EXEMPT_ROLES(= DRIVER / OTHER)里」,豁免闭集落成显式常量集合并从 SettlementStaffRoleEnum 取值,方法名同步改为 requiresSlotMembership(改完它不再读 fallbackTypes(),名字与语义必须同批改)。行为变化:GUIDE_ASSISTANT / STUDY_TEACHER / LIFE_TEACHER 三个「只可能靠字典纳入配置位」的角色,在「字典里查不到归属位」时由静默 200 落库变为返回 582117;DRIVER / OTHER 照旧放行(OTHER 的常态就是不属于任何配置位,保护它会拒掉每一次正常的杂项人员配置,那是删功能不是补洞)。已知边界(按 #8194 决策点 4 有意保留、不在本单修):OTHER 在 VALID_STAFF_TYPES 里,业务能把 OTHER 写进某个位的字典再删掉,那一形态仍走静默放行。生产代码由 PR #8259 合入 dev-v3(squash 提交 f6d21648b)。2026-09-23 测试服已实测:PUT /v3/admin/group-batch/2102640646949105666/staff 提交 staffRole=GUIDE_ASSISTANT 返回 code=582117(HTTP 200,文案完整),读回确认零写入;同端点 staffRole=DRIVER 与 staffRole=OTHER 均返回 code=200 成功;探测插入的两行已用 scopeRoles=[DRIVER,OTHER] + staffList=[] 还原,读回与探测前逐字段一致。契约(路径 / 方法 / 权限 / 入参字段与取值域 / 成功响应结构)零变更——BatchStaffConfigReqVO 只加了 javadoc(含该表)。前端结论(2026-09-23):5821xx 全族在 hl-ui v2.1 无专门分支,统一由拦截器按 code 非成功 toast 后端 message;582117 文案已点名角色并指向配置位字典页,完整直出即可。命中后正确动作是去字典页补行,重试仍被拒不会误操作——与 #8123/#8148 既定拍板一致,维持通用 toast,不做专门引导,零改动闭环。后端订正三处(降级态字典角色同拒 582117/示例 payload 纠错/补缓存窗口与存量脏行边界)前端已审阅:均为后端行为澄清,契约零变化,文案仍拦截器直出,前端 not_required 结论不变。 | 2026-09-23 | dev-v3 |
团期人员配置: 配置位缺失守卫 582117 的触发集合扩大到全部非豁免角色(管理后台)
服务: hl-order-service-v3(端口 8086/8186) PR: #8259(squash 提交
f6d21648b) Issue: #8194(前置 #8148 / #8122 / #7079) 日期: 2026-09-23 影响范围: 管理后台团期详情页的「配导游 / 配摄影」弹窗保存动作
⚠️ 关键变化
这个端点返回 582117 的角色集合变大了,路径、入参、成功响应结构一律不变。
以前只有 GUIDE / LEADER / PHOTOGRAPHER 三个内置角色在「字典里查不到归属位」时会被 582117 拒掉;现在除 DRIVER 与 OTHER 以外的任何角色都会被拒,其中就包括业务自己通过配置位字典启用过的 GUIDE_ASSISTANT / STUDY_TEACHER / LIFE_TEACHER。
调用方以前以为的是:staffRole=GUIDE_ASSISTANT 这类「字典角色」提交时不会触发 582117(它压根不在守卫的名单里)。
实际现在是:它同样会触发 582117,而且这批请求本来就是脏数据(角色没有任何人员类型校验背书)。
DRIVER / OTHER 的行为不变,仍放行。
一、背景
配置位成员集合自 #7079 起由数据字典决定(group_batch_staff_slot_guide / group_batch_staff_slot_photographer),业务在字典管理页面加一行就能把某个人员类型配进这个位,不发版。GroupBatchStaffSlotResolver 的类 javadoc 原文就是这句:「业务在字典管理页面给 group_batch_staff_slot_guide 加一行 STUDY_TEACHER,研学老师就能配进导游位,不发版」。
#8148 把「角色 → 允许的人员类型」这半边也迁到了字典,并引入 582117:当某角色在字典里查不到归属位时,本该有位的角色要被拒,而不是沿袭改前的「一律不校验」。但 #8148 的分流判据读的是编译期常量兜底名单(GUIDE / LEADER / PHOTOGRAPHER),它恰恰不包含任何「靠字典新增出来的角色」——那正是这个新能力的产物。结果是:
| 「查不到归属位」的成因 | #8148 之后的行为 | 是否正确 |
|---|---|---|
DRIVER / OTHER 这类结构性不参与配置位的角色 |
放行 | ✅ 正确 |
内置角色(GUIDE / LEADER / PHOTOGRAPHER)被从仍非空的字典里删掉 |
拒绝 582117 | ✅ 正确 |
字典启用过的角色(GUIDE_ASSISTANT / STUDY_TEACHER / LIFE_TEACHER)被删回 |
静默放行 | ❌ 缺口 |
第三种形态的失败后果与加 582117 之前逐字相同:HTTP 200、Result.success、前端看不到任何异常;落库成功并异步扇出到团内全部活跃订单;静默放行分支一行日志都不打。
而撞上它不需要有人手搓请求:
- 业务给导游位字典加一行
GUIDE_ASSISTANT; - 前端按导游位提交
staffRole=GUIDE、该人真实staffType=GUIDE_ASSISTANT→ 校验通过 →resolveStoredStaffRole把落库的staff_role改写成GUIDE_ASSISTANT; - 下次打开弹窗,回显的既有行角色就是
GUIDE_ASSISTANT,提交回来staffRole=GUIDE_ASSISTANT; - 此后运维把那行字典删掉 ⇒ 第 3 步那种请求走进静默分支,且此时
staffRole=GUIDE_ASSISTANT配任何staffType都能过。
修法(#8194 决策点 5 定案 B:判据翻面):把「本该有位」的判据从「在不在兜底名单里」换成「不在结构性豁免闭集里」。豁免闭集 = {DRIVER, OTHER}(#8194 决策点 4 定案),落成 GroupBatchStaffSlotResolver#STRUCTURALLY_SLOT_EXEMPT_ROLES 这一个显式常量集合。方法随之改名 participatesInSlotsByFallback → requiresSlotMembership——改完它不再读 fallbackTypes(),名字与语义必须同批改,否则留下「命名断言别处行为」的静默漂移点。
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 保存团期人员配置 | PUT | /v3/admin/group-batch/{productBatchId}/staff |
修改接口 | 582117 的触发角色集合扩大;路径 / 入参 / 权限 / 成功响应结构不变 |
网关无改动(没有新增 /admin/ Controller,路由不动)。
三、接口详情
1. 保存团期人员配置 PUT /v3/admin/group-batch/{productBatchId}/staff
VO: BatchStaffConfigReqVO
使用场景
团期详情页「配导游 / 配摄影」弹窗点保存。按 scopeRoles(不传即整期)软删旧配置、写入新配置、异步扇出到各活跃子订单,并按配置结果回填 guide_ready / photographer_ready。
🔴 路径参数是产品侧排期 ID,不是团期聚合主键。端点名叫 group-batch,但 {productBatchId} 吃的是 group_tour_batch.batch_id。响应体里另有一个 groupBatchId,那才是订单侧 order_group_batch 的主键,两者不是同一个值。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| productBatchId | path | Long | 是 | 正整数,产品侧排期 ID | 团期所属班期;未建团返 589553 |
| scopeRoles | body | List<String> | 否 | 传了就不能是空数组;元素非空白且须在员工角色取值域内 | 限定本次覆盖的角色范围,不传则整期覆盖 |
| staffList | body | List<Item> | 是(可在服务层为空数组) | @NotNull;[] 表示清空覆盖范围内的配置 |
覆盖范围内的最终状态 |
| staffList[].staffId | body | Long | 是 | 须命中候选人员 | 人员 ID |
| staffList[].staffRole | body | String | 是 | @NotBlank + @Pattern,须与人员类型相符,否则 582114 |
角色取值域见「六.5」 |
| staffList[].sortOrder | body | Integer | 否 | — | 展示排序,默认 0 |
| staffList[].remark | body | String | 否 | @Size(max=500) |
备注 |
出参 Result<BatchStaffConfigRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| productBatchId | Long | 回显路径参数 |
| groupBatchId | Long | 团期聚合主键,与路径参数不是同一个值 |
| staffList | List | 保存后的整期最终状态(含 staffRoleName / reporterRankName 等中文 Label) |
| affectedOrderCount | Integer | 本次扇出触及的活跃子订单数 |
请求示例
PUT /v3/admin/group-batch/2102640646949105666/staff HTTP/1.1
Host: api.test.1814.love:9443
Authorization: Bearer <admin token>
Content-Type: application/json
{"staffList":[{"staffId":1002,"staffRole":"GUIDE","sortOrder":0,"remark":"hl8194-ok"}]}
⚠️ 把上面的
staffRole换成GUIDE_ASSISTANT(或其他字典角色)在修复后会返回 582117,不再是 200——见「错误响应」。这正是本单的行为变化。
响应示例
成功时:
{
"code": 200,
"message": "成功",
"data": {
"productBatchId": "2102640646949105666",
"groupBatchId": "2102640736900116481",
"affectedOrderCount": 1,
"staffList": [
{"id": "2102640914386284545", "staffId": 1002, "staffRole": "GUIDE", "staffRoleName": "导游", "staffName": "李雪梅", "reporterRank": "NONE"}
]
},
"success": true
}
空数据 / 降级响应
staffList 传空数组即清空覆盖范围内的配置,返回 200,staffList 为空数组、affectedOrderCount 为实际扇出订单数。
配置位字典读挂 / 读空时,typesOf 回落内置默认值(导游位 GUIDE+LEADER、摄影位 PHOTOGRAPHER):内置角色(GUIDE / LEADER / PHOTOGRAPHER)的保存照常成功,这条降级保证本单未动。
⚠️ 但内置名单之外的角色不是这样:GUIDE_ASSISTANT / STUDY_TEACHER / LIFE_TEACHER 不在兜底名单里,字典服务不可用期间它们依然「查不到归属位」⇒ 同样返回 582117。也就是说 582117 现在有两种成因:①字典可读、但该角色不在任何配置位里(修复动作是补回那一行字典);②字典服务不可用、且该角色不是内置兜底成员(修复动作是恢复字典服务)。文案当前不区分两者,排查时请先确认字典服务可用性。
错误响应
新增会命中的情境:字典里查不到该角色的归属位,且该角色不在豁免闭集里({0} 由运行期填入角色名):
{"code": 582117, "message": "角色 GUIDE_ASSISTANT 未归属任何人员配置位,无法校验人员类型;请检查配置位字典是否被误删", "data": null, "success": false}
本端点此前已有、本次不改动的其余业务码(一并列出便于对照):
{"code": 582114, "message": "所选人员的角色与其人员类型不符,请重新选择", "data": null, "success": false}
{"code": 582115, "message": "提交的人员角色超出本次保存声明的范围", "data": null, "success": false}
{"code": 582116, "message": "本次保存声明的角色范围(GUIDE)只覆盖了配置位的一部分,还缺少 LEADER;同一配置位的角色必须一起声明,否则位内其余人员会被留在库里", "data": null, "success": false}
{"code": 100503, "message": "资源被占用,请稍后重试", "data": null, "success": false}
全部走 HTTP 200,不是 5xx。
业务边界
- 582117 有两种成因,排查顺序是先服务后内容:①字典可读、但该角色不在任何配置位里(被删掉,或从来没配过);②字典服务(hl-user-service)不可用而该角色又不是内置兜底成员(
GUIDE/LEADER/PHOTOGRAPHER)。此时文案说的「字典是否被误删」会指错方向——先去字典页面看会发现那行可能压根没删过。 - 被判定的不是「你这个角色对不对」,而是「这个角色的归属位是不是丢了」。角色本身合法(在
@Pattern取值域内)但字典里没有它的位 → 582117;位找得到但人岗不符 → 582114。两者互补。 - 修复动作在配置位字典页面,不在这个弹窗里,所以文案点名角色并指向字典,适合原样透出给运营。
- 豁免闭集是
DRIVER与OTHER,两者在任何字典状态下都不做角色↔人员类型校验,582117 与 582114 都不触发。 - 被 582114 / 582115 / 582116 / 582117 任一码拒绝时零写入——所有校验闸都在写库之前,且发生在注册
afterCommit扇出回调之前,回读会看到与提交前逐字相同的配置。 - 导游位并收
GUIDE与LEADER:只传["GUIDE"]却选了领队会命中 582115,只传["GUIDE"]而位内还有 LEADER 会命中 582116。
四、契约约束与正确调用方式
本节只写后端接受/拒绝 payload 的规则,不写 UI 渲染建议。
契约面零变化,行为面有变化
| 面 | 是否变化 | 依据 |
|---|---|---|
| 路径 / HTTP 方法 / 权限码 | 不变 | Controller 未动 |
入参字段、类型、必填性、@Pattern 取值域 |
不变 | BatchStaffConfigReqVO 只加了 javadoc |
| 成功响应结构 | 不变 | BatchStaffConfigRespVO 未动 |
| 582117 的触发角色集合 | 变化 | Service 的分流判据翻面 |
✅ 正确 / ❌ 错误 payload 对照
| 场景 | payload | 结果 |
|---|---|---|
| ✅ 内置角色、字典正常 | {"staffList":[{"staffId":1002,"staffRole":"GUIDE"}]} |
200,落库 staffRole=GUIDE |
| ✅ 结构性豁免角色 | {"scopeRoles":["DRIVER"],"staffList":[{"staffId":1002,"staffRole":"DRIVER"}]} |
200,落库 staffRole=DRIVER |
| ✅ 结构性豁免角色 | {"scopeRoles":["OTHER"],"staffList":[{"staffId":1002,"staffRole":"OTHER"}]} |
200,落库 staffRole=OTHER |
| ✅ 字典已收录该角色 | 字典里 group_batch_staff_slot_guide 含 GUIDE_ASSISTANT,提交 staffRole=GUIDE 且该人 staffType=GUIDE_ASSISTANT |
200,落库 staffRole=GUIDE_ASSISTANT |
| ❌ 字典角色但字典里已查不到位 | {"staffList":[{"staffId":1002,"staffRole":"GUIDE_ASSISTANT"}]} |
200 + code=582117,零写入 |
| ❌ 提交越界的人 | {"scopeRoles":["GUIDE"],"staffList":[{"staffId":1002,"staffRole":"LEADER"}]} |
200 + code=582115,零写入 |
调用方的正确动作
- 命中 582117 时不要重试,也不要自动改写
staffRole——正确动作是去配置位字典页面把缺的那一行补回来(或确认为什么它被删了),再重试保存。文案里的角色名就是缺的那一个。 - 判成败一律看
code,不要看 HTTP status:本端点的业务失败全是 HTTP 200。 - 保存成功后若调用方缓存了
guide_ready/photographer_ready,需重新拉取团期详情。
五、数据库行为
- 保存:按
scopeRoles范围(不传即整期)软删旧配置行 → 写入新配置行 → 注册afterCommit→ 异步扇出到各活跃子订单(order_staff_assignment中source=GROUP_BATCH的行整删整插)→ 回填团期行的两个 ready 标志。 - 本次改动不改变任何一步的写内容,只改变「哪些请求会被挡在写库之前」。
- 被 582114 / 582115 / 582116 / 582117 任一码拒绝时零写入:校验发生在
buildToInsert与doSaveInTransaction之前,且afterCommit扇出回调尚未注册(注册动作在事务段内部、软删与插入之后)。
六、边界行为
DRIVER/OTHER不受本单影响:两者在任何字典状态下都放行,与改前一致。- 字典读挂 / 读空不降级成拒绝:
typesOf回落内置默认值,内置角色(GUIDE/LEADER/PHOTOGRAPHER)照常保存。 - 将来往
@Pattern里加第 9 个取值而忘了判断它属不属于豁免闭集时,新角色默认落进「本该有位」侧 ⇒ 那一侧是拒绝(响亮失败、当场被发现),不是静默放行。失败方向正确。 - 已知边界,不在本单修:
OTHER在VALID_STAFF_TYPES里,业务能把OTHER写进某个位的字典再删掉,那一形态仍走静默放行。判据是:OTHER的常态化就是不属于任何配置位,把它移出豁免闭集会拒掉每一次正常的杂项人员配置;而「把『其他』纳入『导游位』」本身是配置位语义的误用(等于宣告「其他类型的人算导游」),错的是那行字典。 - 存量脏行的连带影响(本单不修,但必须知道):字典行被删之后库里已有的
staff_role='GUIDE_ASSISTANT'行不再属于任何配置位,整位守卫 582116 也判不到它,这些行不会被scopeRoles的删除窗口覆盖或重建。⚠️ 更要紧的是:这类存量行会被前端原样回显提交,而校验是逐行做的——只要该团期的保存请求里带上这样一行且staffRole仍在缺口集合内,整次保存(含不传scopeRoles的整期覆盖)都会返回 582117。是否已有这类存量行未在本次取证中统计(生产库只读盘点属独立动作)。治理另立工单。 - 缓存窗口:
typesOf是固定 5 分钟 TTL 的实例本地缓存(@VettedLocalCache)。字典改完到全部实例生效之间,同一请求可能一台放行、一台返回 582117。所以「删回后不再静默放行」是有界结论:最长 5 分钟、按实例收敛。 - 判据不认识「历史」:
requiresSlotMembership只看字典当前内容。因此「从没在任何配置位字典里出现过」与「加过又被删回」走同一条拒绝分支,而文案一律写成「是否被误删」。首次配置某类人员(业务还没往字典加那一行)时会看到这句——正确动作是去对应配置位字典加一行,不是去查删除记录。
六.5、枚举 / 数据字典
staffRole(取值域来自 BatchStaffConfigReqVO.STAFF_ROLE_PATTERN)
所属字段: staffList[].staffRole / scopeRoles[] | 类型: String
下表说的是「该角色在配置位字典里查不到归属位时」修复后走哪条分支。分母就是从 @Pattern 常量抄下来的这 8 个(并有单测 GroupBatchStaffRoleSlotGuardTest#patternValueDomain_classifiedOneByOne 机械守住:常量改了而表没跟,用例先红)。
| 取值 | 分支 | 理由 |
|---|---|---|
GUIDE |
拒绝 582117 | 导游位内置成员;默认字典下查得到位,查不到说明那一行被删了 |
LEADER |
拒绝 582117 | 同上(导游位并收导游与领队) |
PHOTOGRAPHER |
拒绝 582117 | 摄影位内置成员;查不到说明那一行被删了 |
GUIDE_ASSISTANT |
拒绝 582117(本单新增覆盖) | 只可能靠字典被纳入配置位;「加过再删回」正是本单修的形态 |
STUDY_TEACHER |
拒绝 582117(本单新增覆盖) | 同上 |
LIFE_TEACHER |
拒绝 582117(本单新增覆盖) | 同上 |
DRIVER |
放行 | 结构性豁免:车务派车投影产生,资源域没有这个人员类型,也配不进任何位的字典 |
OTHER |
放行 + 已知边界 | 结构性豁免:常态就是不属于任何配置位,保护它会拒掉正常的杂项人员配置。代价是「OTHER 被某位字典纳入后再删掉」仍静默放行,本单不修 |
六.6、修改前后对比
行为级对比
| 行为 | 改前 | 改后 |
|---|---|---|
staffRole=GUIDE_ASSISTANT(字典里查不到归属位) |
静默 200 + 落库 + 异步扇出,582114 当场失效 | 582117,零写入 |
staffRole=STUDY_TEACHER / LIFE_TEACHER(同上) |
同上 | 582117,零写入 |
staffRole=LEADER 被从非空字典删掉 |
582117(#8148 已建立) | 不变 |
staffRole=DRIVER / OTHER |
放行 | 不变 |
| 字典读挂 / 读空(内置角色) | 回落内置默认值,放行 | 不变 |
字典读挂 / 读空(字典角色 GUIDE_ASSISTANT 等) |
静默 200 | 582117,零写入(降级态无法区分「被删掉」与「读不到」,见「六、边界行为」) |
| 判据实现 | participatesInSlotsByFallback 读编译期常量 fallbackTypes() |
requiresSlotMembership 判「不在结构性豁免闭集 {DRIVER, OTHER} 里」 |
| 路径 / 入参 / 权限 / 成功响应结构 | — | 零变化 |
字段级对比
无字段变化(BatchStaffConfigReqVO 只增加 javadoc,BatchStaffConfigRespVO 未动)。
六.7、影响评估
- 是否破坏向后兼容: 否(契约零变化)。但存在面向管理后台的行为变化:原本能保存成功的几个角色的请求会开始被 582117 拒——那批请求本就是脏数据(角色没有任何人员类型校验背书)。
- 前端是否必须同步上线: 否。5821xx 这一族在 hl-ui v2.1 上没有专门分支,统一由
src/utils/request.js的响应拦截器按「code 非成功值」toast 后端 message,故 582117 在这几个角色上出现时前端零改动即有基本行为(文案本身已是可直接展示的完整句子,并指向修复动作所在处)。 - 前端可选优化:命中 582117 时提示语可引导运营去「配置位字典」页面,并保留用户已填表单;不引导也不会误操作(重试仍会被拒)。
- 前端 workaround 清理点: 无。
七、不影响范围
- 零影响:
- 路径、HTTP 方法、权限码、网关配置
- 入参字段、类型、必填性、
@Pattern取值域 - 成功响应结构与字段
- 候选人查询(
/staff/candidates、/staff/candidates/page)与配置列表查询(GET /staff) - 报账人等级设置口
PUT /v3/admin/group-batch/{productBatchId}/staff/{staffId}/reporter-rank - 子订单自己单独派的人员(
order_staff_assignment中source非GROUP_BATCH的行) 582114/582115/582116/100503四个既有码的触发条件与文案assertScopeCoversWholeSlots(582116)与scopeRoles的任何判定逻辑DRIVER/OTHER的放行口径- 数据库表结构与 Flyway(本单无表变更、无迁移脚本)
- 小程序端(团期人员配置无小程序写口)
八、测试环境已验证
2026-09-23,api.test.1814.love:9443(网关),分支 dev-v3,order-v3 活体 f6d21648b(双实例 8086 / 8186,滚动部署后均 UP)。
取证批次: productBatchId=2102640646949105666(#8123 / #8148 同一条取证批次),人员 staffId=1002(资源域真实 staffType=GUIDE)。
| 项 | 请求 | 结果 |
|---|---|---|
| 探测前快照 | GET /v3/admin/group-batch/2102640646949105666/staff |
200,1 行(staffId=1002, staffRole=GUIDE) |
| 本单核心(修复后) | PUT 同端点,{"staffList":[{"staffId":1002,"staffRole":"GUIDE_ASSISTANT"}]} |
HTTP 200,code=582117,message「角色 GUIDE_ASSISTANT 未归属任何人员配置位,无法校验人员类型;请检查配置位字典是否被误删」 |
| 零写入 | 上一步之后 GET 同端点读回 |
与探测前快照逐字段一致(拒绝路径未注册 afterCommit 扇出回调,未进事务段) |
阴性对照(DRIVER) |
PUT {"scopeRoles":["DRIVER"],"staffList":[{"staffId":1002,"staffRole":"DRIVER"}]} |
HTTP 200,code=200 成功 |
阴性对照(OTHER) |
PUT {"scopeRoles":["OTHER"],"staffList":[{"staffId":1002,"staffRole":"OTHER"}]} |
HTTP 200,code=200 成功 |
| 现场还原 | PUT {"scopeRoles":["DRIVER","OTHER"],"staffList":[]} |
200;读回与探测前快照逐字段一致 |
测试环境上无法构造、因此未取活体样本的两项(原因是环境性的、与实现无关):
- AC-3「字典读挂回落内置默认值」:需要让测试服的
DictFeignClient整体失败,属环境级故障注入,会波及同环境其他使用者。该行为由真库用例GroupBatchStaffSaveConfigSlotCompletenessMysqlTest#saveConfig_dictFeignFails_fallbackKeepsSlotRolesAccepted与单元用例GroupBatchStaffRoleSlotGuardTest#dictUnavailable_fallbackKeepsBuiltInRolesAccepted覆盖(真实解析器 + 打桩 Feign,回落链路真跑)。 - AC-4 的测试服活体样本(把内置角色从仍非空的配置位字典里删掉):字典是全站共享数据,删行的副作用会落到所有人的角色下拉框上,未构造。该行为由真库用例
#saveConfig_dictDropsLeaderFromGuideSlot_mismatchedStaffTypeRejectedNotSilentlySkipped覆盖。
证据文件(脱敏、非空,已登记进 task capsule 的 evidence manifest):D:/work2/.tmp/issue8194/evidence/(gateway-verification.json / gateway-8194.log / gw-1-before.json … gw-5-after-cleanup.json / gw-summary.json)。
十、相关文档
- Issue #8194(本单)、#8148(582117 的引入与残留缺口)、#8122(582116 整位覆盖守卫)、#7079(配置位字典化)
- PR #8259(squash 提交
f6d21648b) - 同端点上一版条目:
changelogs-v2/2026-09/23_8123_团期staff保存新增并发抢锁与配置位字典守卫错误码-修改接口-管理后台.md - 错误码定义:
hl-order-service-v3/src/main/java/com/hulalv/order/assignment/errorcode/AssignmentErrorCode.java(582117) - 判据与豁免闭集:
hl-order-service-v3/src/main/java/com/hulalv/order/assignment/service/GroupBatchStaffSlotResolver.java(STRUCTURALLY_SLOT_EXEMPT_ROLES/requiresSlotMembership)
关联 / 联系人
链接
联系人
- 后端负责人: @wx
- 前端: mmg(582117 提示语可引导至配置位字典页面,非必须)