# V1.1 新增写入点展示 — 整改方案 > 版本:v1.1 > 日期:2026-08-03 > 状态:**已落地** > 关联:`docs/配置说明.md` §5、`docs/V1.1-非结构写入收敛整改方案.md`(建点收敛已落地,本方案只改**展示层**) > 约束:**不新增配置项**;文案与染色为工具默认行为 --- ## 1. 背景与实跑样本 ### 1.1 企微原文(问题形态) ```text - 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 | 新骨架整段无绿色 | 字段级变更有 ``,新增整 Key/Topic 时全是明文,**结构颜色未渲染** | | P3 | 缺少「变更类型」明示 | 读者需自行推断这是新增写入点还是结构变更 | | P4 | (次要)删除写入点文案不对称 | 「value 原结构 + 已删除投递/写入」可读,但可与新增侧统一语气 | Redis 侧新增 Key 走同一 `ReportBuilder#renderKeyBlock` 分支(`oldJson` 空、`newJson` 非空),**同病**,须一并改。 ### 1.3 非目标 - 不改检测 / Schema 提取 / Diff 逻辑(建点收敛见另一文档) - 不新增 YAML 开关 - 不改字段级变更的片段染色规则(`FIELD_ADDED` 等仍按路径染色) - 不改企微 4096 拆条策略 --- ## 2. 根因分析 ### 2.1 调用链 ```text 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. 整改目标 1. 一眼可读:这是 **新增投递 / 首次写入该 Key**,不是字段 diff。 2. 新骨架在企微中有 **绿色** 渲染(整段 `info`)。 3. Redis / MQ 文案区分清楚,与字段级「value值由 / 变更为」不打架。 4. 删除写入点展示与新增侧语气对称;控制台明细前缀对齐。 5. 既有字段级染色回归不变。 --- ## 4. 方案设计 ### 4.1 判定:何时走「整段新增/删除」展示 在 `renderKeyBlock` 中: ```text 仅当 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(位置/类型)之后、骨架之前增加一行: ```markdown > **变更类型**: 新增写入点 ``` 删除侧: ```markdown > **变更类型**: 删除写入点 ``` 字段级变更块不加此行(避免噪音);仅整段新增/删除分支输出。 ### 4.3 颜色渲染(定稿) | 场景 | 染色 | |------|------| | 整段新增(仅 WRITE_POINT_ADDED) | 新骨架整段包裹 ``,再外包中文引号 `“…”` | | 整段删除(仅 WRITE_POINT_REMOVED) | 旧骨架整段包裹 `` | | 字段级变更 | **不改**:仍按路径片段染色 | 实现建议(择一,推荐 A): **A. ReportBuilder 内直接整段 wrap(简单)** ```text if (isWritePointAddedOnly(details) && !newJson.isEmpty()) { newRendered = "“" + fontInfo(newJson) + "”"; } ``` **B. SkeletonAnnotator 增加 `wrapAll(json, color)`** 供 ReportBuilder 调用,便于单测与复用。 本方案采用 **A + 可选抽出 wrap 小方法到 SkeletonAnnotator**,避免改路径匹配算法。 企微颜色约定与现网一致: | 语义 | color | |------|-------| | 新增 / 新结构 | `info`(绿) | | 删除 / 旧结构 | `warning`(橙) | ### 4.4 目标企微形态(对照样本) 整改后期望接近: ```markdown - Topic --> `duty_im_notice_topic` > **通道**: RocketMQ > **位置**: DutyDelayQueueImNoticeService#addMq:43 > **类型**: DutyImNotice > **变更类型**: 新增写入点 > **新增投递,消息体结构为:** “{"objectId":"","content":"","type":0,"pushStatus":0,"tenantId":"","deleteMark":0,"executeTime":0}” ``` Redis 新增 Key 对称示例: ```markdown - Key --> `saas:period-config:migration:current` > **位置**: … > **类型**: MigrationCurrentVo > **变更类型**: 新增写入点 > **首次写入该 Key,value 结构为:** “{…}” ``` ### 4.5 未解析 Key / Topic(顺带小优化,可选同批) 若 `keyUnresolved`: - 提示由 `(key 无法解析)` / `(destination 未解析)` 调整为:`(key 无法解析,建议 manual_mappings 补充)`(MQ 用 destination 措辞) - 表达式长度 > 80 时截断为前 77 字符 + `...`(常量即可,**不进配置**) 本项为体验增强,可与主改动同 PR;若排期紧可二期。 ### 4.6 控制台明细 `formatDetailMessage` 的 `knownPrefixes` 补齐: ```text "新增 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 外包 `` | | T2 | 仅 `WRITE_POINT_ADDED` + Redis | 含「首次写入该 Key,value 结构为」;整段绿 | | T3 | 仅 `WRITE_POINT_REMOVED` + 非空 oldJson | 「原…结构」+ 整段 `` | | 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. 实施检查表 - [x] 认可 §4.2 文案与 §4.3 整段染色(不新增配置) - [x] 同批做未解析 Key 截断(§4.5) - [x] 代码落地 + T1~T6 - [x] 同步 `docs/配置说明.md` §5 - [x] 全量 `mvn test` --- ## 10. 文案对照速查 | 场景 | V1.0 | V1.1(本方案) | |------|------|----------------| | MQ 新增投递 | `value 新增为:“{…}”`(无色) | `变更类型: 新增写入点` + `新增投递,消息体结构为:“{…}”` | | Redis 新增写入 | 同上 | `首次写入该 Key,value 结构为:“{…}”` | | 字段级变更 | `value值由` / `变更为` + 片段染色 | 保持 |