9.9 KiB
V1.1 新增写入点展示 — 整改方案
版本:v1.1
日期:2026-08-03
状态:已落地
关联:docs/配置说明.md§5、docs/V1.1-非结构写入收敛整改方案.md(建点收敛已落地,本方案只改展示层)
约束:不新增配置项;文案与染色为工具默认行为
1. 背景与实跑样本
1.1 企微原文(问题形态)
- Topic --> duty_im_notice_topic
通道: RocketMQ
位置: DutyDelayQueueImNoticeService#addMq:43
类型: DutyImNotice
value 新增为: “{"objectId":"","content":"","type":0,"pushStatus":0,"tenantId":"","deleteMark":0,"executeTime":0}”
含义:对比区间内首次出现该 Topic 的投递点(WRITE_POINT_ADDED),消息体类型与骨架已正确解析,但展示层体验差。
1.2 问题拆解
| # | 现象 | 影响 |
|---|---|---|
| P1 | 文案「value 新增为」语义含糊 | 看不出是「新增投递 / 首次写入」,与字段级「变更为」易混淆 |
| P2 | 新骨架整段无绿色 | 字段级变更有 <font color="info">,新增整 Key/Topic 时全是明文,结构颜色未渲染 |
| P3 | 缺少「变更类型」明示 | 读者需自行推断这是新增写入点还是结构变更 |
| P4 | (次要)删除写入点文案不对称 | 「value 原结构 + 已删除投递/写入」可读,但可与新增侧统一语气 |
Redis 侧新增 Key 走同一 ReportBuilder#renderKeyBlock 分支(oldJson 空、newJson 非空),同病,须一并改。
1.3 非目标
- 不改检测 / Schema 提取 / Diff 逻辑(建点收敛见另一文档)
- 不新增 YAML 开关
- 不改字段级变更的片段染色规则(
FIELD_ADDED等仍按路径染色) - 不改企微 4096 拆条策略
2. 根因分析
2.1 调用链
SchemaCheckAnalyzer
→ WRITE_POINT_ADDED + newSkeletonJson(完整骨架)
→ KeyStructureChange.fieldDetails = [WRITE_POINT_ADDED] // 无 fieldPath
ReportBuilder.renderKeyBlock
→ pathsForNewSkeleton(details) // 只认 FIELD_ADDED / FIELD_PATH_MOVED
→ newGreen = ∅
→ annotateNewForWecom(json, ∅) → 原样明文
→ 文案固定:「value 新增为:**
2.2 根因表
| 编号 | 根因 | 证据 |
|---|---|---|
| R1 | 新增写入只有 ChangeType.WRITE_POINT_ADDED,无字段路径 |
SchemaCheckAnalyzer 建点逻辑 |
| R2 | SkeletonAnnotator.pathsForNewSkeleton 不处理 WRITE_POINT_ADDED |
仅 FIELD_ADDED / FIELD_PATH_MOVED |
| R3 | ReportBuilder 对「旧空新有」写死 value 新增为,且 不区分 Redis / MQ |
renderKeyBlock 约 146~147 行 |
| R4 | 无「变更类型」行;控制台 formatDetailMessage 对 MQ 新增前缀也不完整 |
ReportBuilder |
结论:数据已够用(有完整 newJson + 通道 + 类型),缺口全在报告渲染。
3. 整改目标
- 一眼可读:这是 新增投递 / 首次写入该 Key,不是字段 diff。
- 新骨架在企微中有 绿色 渲染(整段
info)。 - Redis / MQ 文案区分清楚,与字段级「value值由 / 变更为」不打架。
- 删除写入点展示与新增侧语气对称;控制台明细前缀对齐。
- 既有字段级染色回归不变。
4. 方案设计
4.1 判定:何时走「整段新增/删除」展示
在 renderKeyBlock 中:
仅当 fieldDetails 全部为 WRITE_POINT_ADDED(或全部为 WRITE_POINT_REMOVED),
且不混有 FIELD_* / WRAPPER_* / TYPE_CHANGED 时
→ 走「整段染色 + 专用文案」
否则
→ 保持现有片段染色逻辑
实跑新增 Topic/Key 场景几乎总是「仅一条 WRITE_POINT_ADDED」,命中上述分支。
4.2 文案(定稿)
| 场景 | 通道 | 现行 | 整改后 |
|---|---|---|---|
| 旧空、新有 | Redis | value 新增为: |
首次写入该 Key,value 结构为: |
| 旧空、新有 | MQ | 同上 | 新增投递,消息体结构为: |
| 旧有、新空 | Redis | value 原结构:…(已删除写入) |
原 value 结构:…(写入点已删除) |
| 旧有、新空 | MQ | …(已删除投递) |
原消息体结构:…(投递点已删除) |
| 旧有、新有 | 共用 | value值由 / 变更为 |
保持不变 |
建议在 meta(位置/类型)之后、骨架之前增加一行:
> **变更类型**: 新增写入点
删除侧:
> **变更类型**: 删除写入点
字段级变更块不加此行(避免噪音);仅整段新增/删除分支输出。
4.3 颜色渲染(定稿)
| 场景 | 染色 |
|---|---|
| 整段新增(仅 WRITE_POINT_ADDED) | 新骨架整段包裹 <font color="info">…</font>,再外包中文引号 “…” |
| 整段删除(仅 WRITE_POINT_REMOVED) | 旧骨架整段包裹 <font color="warning">…</font> |
| 字段级变更 | 不改:仍按路径片段染色 |
实现建议(择一,推荐 A):
A. ReportBuilder 内直接整段 wrap(简单)
if (isWritePointAddedOnly(details) && !newJson.isEmpty()) {
newRendered = "“" + fontInfo(newJson) + "”";
}
B. SkeletonAnnotator 增加 wrapAll(json, color)
供 ReportBuilder 调用,便于单测与复用。
本方案采用 A + 可选抽出 wrap 小方法到 SkeletonAnnotator,避免改路径匹配算法。
企微颜色约定与现网一致:
| 语义 | color |
|---|---|
| 新增 / 新结构 | info(绿) |
| 删除 / 旧结构 | warning(橙) |
4.4 目标企微形态(对照样本)
整改后期望接近:
- Topic --> `duty_im_notice_topic`
> **通道**: RocketMQ
> **位置**: DutyDelayQueueImNoticeService#addMq:43
> **类型**: DutyImNotice
> **变更类型**: 新增写入点
> **新增投递,消息体结构为:** “<font color="info">{"objectId":"","content":"","type":0,"pushStatus":0,"tenantId":"","deleteMark":0,"executeTime":0}</font>”
Redis 新增 Key 对称示例:
- Key --> `saas:period-config:migration:current`
> **位置**: …
> **类型**: MigrationCurrentVo
> **变更类型**: 新增写入点
> **首次写入该 Key,value 结构为:** “<font color="info">{…}</font>”
4.5 未解析 Key / Topic(顺带小优化,可选同批)
若 keyUnresolved:
- 提示由
(key 无法解析)/(destination 未解析)
调整为:(key 无法解析,建议 manual_mappings 补充)(MQ 用 destination 措辞) - 表达式长度 > 80 时截断为前 77 字符 +
...(常量即可,不进配置)
本项为体验增强,可与主改动同 PR;若排期紧可二期。
4.6 控制台明细
formatDetailMessage 的 knownPrefixes 补齐:
"新增 MQ 投递点,"
"删除 MQ 投递点,原 value 类型: "
与 analyzer 现有 setMessage 对齐,避免 CI 明细不加粗。
5. 涉及文件
| 文件 | 变更 |
|---|---|
report/ReportBuilder.java |
文案分支、变更类型行、整段染色、可选未解析截断、prefixes |
report/SkeletonAnnotator.java |
可选:wrapEntire(json, color) |
report/ReportBuilderTest.java |
新增 WRITE_POINT_ADDED(MQ/Redis)展示断言;字段级染色回归 |
docs/配置说明.md §5 |
同步新增/删除写入点文案与整段绿色约定 |
不改:SchemaCheckAnalyzer 建点逻辑、SkeletonJsonRenderer、检测器。
6. 测试计划
| 用例 | 输入要点 | 期望 |
|---|---|---|
| T1 | 仅 WRITE_POINT_ADDED + MQ + 非空 newJson(对齐 duty_im 样本) |
含「新增投递,消息体结构为」;含「变更类型: 新增写入点」;newJson 外包 <font color="info"> |
| T2 | 仅 WRITE_POINT_ADDED + Redis |
含「首次写入该 Key,value 结构为」;整段绿 |
| T3 | 仅 WRITE_POINT_REMOVED + 非空 oldJson |
「原…结构」+ 整段 <font color="warning"> |
| T4 | FIELD_ADDED 字段级变更(既有) |
仍为片段绿,不整段包 info;文案仍为 value值由/变更为 |
| T5 | toConsole 含「新增 MQ 投递点」 |
明细前缀加粗正确 |
| T6 | (若做)超长未解析 key 表达式 | 截断 + mapping 提示 |
可用最小化 CheckReport / KeyStructureChange 构造,不必起 git;骨架 JSON 可用样本中的 DutyImNotice 字段串。
7. 风险与回滚
| 风险 | 缓解 |
|---|---|
| 整段绿色在超长 JSON 下刺眼 | 骨架已有 maxLen;新增点通常可接受 |
| 企微对超长 font 标签不友好 | 保持 4096 拆条;单块过长仍按 key 拆 |
| 文案变更影响阅读习惯 | 发布说明给对照表(§4.2) |
| 误把字段级变更整段染色 | 严格 isWritePointAddedOnly 判定 |
回滚:还原 ReportBuilder / SkeletonAnnotator 展示逻辑即可,与检测无关。
8. 与「非结构收敛」的边界
| 非结构写入收敛(已落地) | 本方案(展示) | |
|---|---|---|
| 解决什么 | 不该建的点(String/{})不再告警 |
该告的点怎么读得懂、看得见绿 |
| 样本 | RecordingTodo 原文缓存 | DutyImNotice 新增投递(类型/骨架正确) |
| 落点 | Detector + Analyzer | ReportBuilder(+ Annotator) |
两者互补:收敛后留下的新增写入点,更需要本方案的文案与整段染色。
9. 实施检查表
- 认可 §4.2 文案与 §4.3 整段染色(不新增配置)
- 同批做未解析 Key 截断(§4.5)
- 代码落地 + T1~T6
- 同步
docs/配置说明.md§5 - 全量
mvn test
10. 文案对照速查
| 场景 | V1.0 | V1.1(本方案) |
|---|---|---|
| MQ 新增投递 | value 新增为:“{…}”(无色) |
变更类型: 新增写入点 + 新增投递,消息体结构为:“<font color="info">{…}</font>” |
| Redis 新增写入 | 同上 | 首次写入该 Key,value 结构为:“<font color="info">{…}</font>” |
| 字段级变更 | value值由 / 变更为 + 片段染色 |
保持 |