diff --git a/skill-workbench/docs/value/latest-design.md b/skill-workbench/docs/value/latest-design.md new file mode 100644 index 0000000..a22d8d0 --- /dev/null +++ b/skill-workbench/docs/value/latest-design.md @@ -0,0 +1,111 @@ +# value-scan / value-dig · 设计文档(Latest Design) + +> **定位**:从**已交付的代码**里逆向萃取「值得讲的价值点」,交人勾选后深挖成可讲、可追问、可被审的文档。 +> **适用**:面试/简历素材重建、模块价值盘点、交接文档提级。 +> **形态**:两个 skill 接力 —— `value-scan`(广度枚举,停在人工勾选门)→ `value-dig`(深度产出,三件套任选)。 +> **战果**(its 仓库实测,2026-09-18):4 轮扫描产出 9 份文档全部通过机械校验;2 条主链路各带 1 个 P0 级实锤缺陷。 + +--- + +## 1. 为什么要有这两个 skill + +盘点代码价值时,agent 有三个系统性偏差: + +| 偏差 | 表现 | 解药 | +|---|---|---| +| **判不了价值** | 把"用了 Redis""有 4 个 handler"当亮点 | 简历行填空测试:`用【机制】解决了【问题】,代价是【取舍】`——机制格填不出就不是价值点 | +| **缺陷导向** | 扫一遍变成挑毛病大会,清单全是负面 | 阶段隔离:S1 只产亮点,缺陷是深挖链路时自然浮现的副产物,归宿在改造方案 | +| **自作主张** | 替用户挑完直接开写 | 门控:产出候选清单后**必须停**,勾选权在人 | + +一句话设计哲学:**agent 负责采样与结构化,人负责价值判断**。 + +## 2. 两段流水线 + +``` +S0 定范围 → S1 枚举 → S2 勾选【硬门:必须停】 + ↓(人勾选 / 否决改向 A′) + value-dig:①功能点清单 ②设计复盘 ③改造方案(各自独立,可只做其一) +``` + +### value-scan(广度) + +- **三层结构**:域 → 链路 → 机制节点。链路按**触发者**拆(谁在改这行数据),不按业务功能拆——收敛点多半是机制所在。 +- **三条硬标准**(全过才进清单):① 核心链路 ② 高级工程师的设计(非框架常识)③ 简历够硬。 +- **数量闸**:5–8 条为宜,>12 = 颗粒度掉到实现层,退回重并。 +- **两层锚点**:机制级 `路径#方法名`(不写行号,防漂移),深挖级 `文件:行号`(必须读过再写)。 + +### value-dig(深度) + +三份文档三种读者: + +| 文档 | 读者 | 灵魂 | +|---|---|---| +| ① 功能点清单 | 自己/接手人 | **主干调用骨架**:整条链压成一段伪代码,每行标方式(`[锁]``[幂等]``[MQ]`),功能点互为索引 | +| ② 设计思路与取舍 | 面试官 | 第一人称复盘 + **"与代码的对照说明"**:判断与代码事实不一致处逐条列出——诚实性是可信度唯一来源 | +| ③ 改造方案 | 架构评审 | 缺陷唯一归属地;**产出门槛**:必须有②加机制/③重构档改造点才立方案,全是补漏档不立(防灌水) | + +跨文档资产复用:`tb_order_anomaly` 台账、token 锁工具、巡检 Job——两链路方案共用一套,是"结构必然"不是"省事"。 + +## 3. 机制设计要点(为什么这样设计) + +### 3.1 门控(S2 必停) + +价值判断权如果不在人,整个流水线退化成"agent 自嗨产出没人看的文档"。所以: +- 候选清单落盘 + 显式请求勾选("请从 N 条挑 3–6 条"); +- 用户禁用提问工具也一样停——请求写成文字; +- **整批否决且未给新目标 = 流程终点**,不强续。 + +### 3.2 判据外化为填空 + +"价值"无法定义,但"简历行填得出来吗"可判定。两级: +- **准入**:三条硬标准(反例驱动的剔除表); +- **表达**:机制+问题两格必填,取舍格留给 value-dig(不误杀)。 + +被剔除的点不丢弃——进「已剔除」表注明未过哪条标准,供复核筛选口径。 + +### 3.3 机械校验(check.py)与模板外置 + +- 模板是**活资产**:产出照模板填空,被纠正过就回写模板; +- check.py 十余条规则:引号配对 / mermaid 合法性 / 表格列一致+不缩进 / 章节完整性(模板必备节 ⊆ 产出节)/ scan 专属(无代码围栏、锚点格式、候选数 ≤12)/ dig 专属(骨架行必带方式标记、证据必含行号)/ doc 专属(改造方案必有关键片段); +- FAIL 必须为 0,WARN 允许保留但写明原因。 + +### 3.4 缺陷的归宿隔离 + +缺陷只在改造方案出现,且**不是枚举出来的是贴着链路走出来的**——三把刀(按触发者拆链路 / 竞态矩阵 / 幂等键清单+状态流转图)+ 机制模式库(结构性限制 → 可引入机制对照表)+ 三档尺度(补漏⭐/加机制⭐⭐⭐/重构⭐⭐⭐,每缺陷必追问"能否升一档")。 + +## 4. 实战演化记录(its 仓库 4 轮,2026-09-18) + +这轮实战暴露的边界案例与回写(模板活资产的实证): + +| # | 事件 | 回写 | +|---|---|---| +| 1 | 用户否决 5 条单点:"都不够硬,直接分析整链路" | value-dig 新增**入口 A′(否决改向)**:否决原因入清单、按 B 重走、产物声明 | +| 2 | 权益域首轮以"机制格填不出"剔除,复评翻案(快照轮询机制实存,藏在 2349 行大类的私有方法群) | "机制格填不出"剔除加**硬门槛**:没读过入口方法向下 ~100 行不得定稿剔除;翻案不删行留痕 | +| 3 | "不够硬"出现两次(单点否决、权益否决) | S2 门控新增**否决即校准**:负反馈记入清单,同域复扫先读否决记录 | +| 4 | 勾选回写两次压列(3 列变 2 列) | 候选清单模板补**回写示例**(3 列不压列);check.py 报错**附行内容摘要** | +| 5 | check.ps1 仅 Windows | 移植 **check.py**(等价回归 8 产物一致);顺带发现初版 `__name__` 损坏静默 exit 0——校验工具自身的静默通过比报错更危险 | + +### 实测产出骨架(可作参考样例) + +``` +docs/ +├── 赢客下单-候选价值点.md S1 清单(5 候选 + 5 剔除) +├── 赢客下单-功能点清单.md 7 功能点 + 主干骨架 +├── 赢客下单-设计思路与取舍.md 4 不变量 / 7 决策 / 口述版 +├── 赢客下单-改造方案.md 6 缺陷(3🔴)→ 3 阶段 +├── 全仓其余域-候选价值点.md 二轮 8 候选(含翻案 ★7/★8) +├── 工单全生命周期-{功能点清单,设计思路与取舍,改造方案}.md +``` + +两个 P0 实锤(深挖才浮现的典型): +- 幂等双关口键不一致:bossOrderId vs requestId,组合穿透 → 重复扣权益; +- `updateConfirmInfo` 条件更新漏 `status=51`:设计是 DB 仲裁,落地是应用层检查 → 人工确认可被自动确认覆盖。 + +## 5. 已知限制与下一步 + +| 限制 | 说明 | 候选方向 | +|---|---|---| +| 单域节奏 | 一次一域,全仓扫描靠人反复发起 | 域清单自动切片 + 断点续扫 | +| 判据主观残留 | "简历够硬"仍依赖人对目标岗位的校准 | 按 JD 关键词加权候选排序 | +| 深挖成本 | 一个功能点 ≈ 1–2 份 20KB 文档,人工审读压力大 | 功能点清单先行 + 复盘/方案按勾选再出 | +| 校验器无自检 | check.py 自身损坏会静默通过 | CI 里对已知 BAD 样例断言必 FAIL | diff --git a/skill-workbench/generated-skills/skills/value-dig/SKILL.md b/skill-workbench/generated-skills/skills/value-dig/SKILL.md new file mode 100644 index 0000000..9b7f79e --- /dev/null +++ b/skill-workbench/generated-skills/skills/value-dig/SKILL.md @@ -0,0 +1,115 @@ +--- +name: value-dig +description: Use when the user has already chosen which mechanisms or value points matter and now wants them written up in depth — "把这个点写成文档", "把这条链路的实现整理成功能点", "写设计思路与取舍", "出改造方案", or when an existing module's design must be reconstructed layer by layer for an interview walkthrough. Read-only — never modifies the scanned project. +--- + +# value-dig · 深度产出(功能点 / 设计复盘 / 改造方案) + +## 一句话 + +把**已经选定的**机制点写成**能讲、能追问、能被审**的文档:按需产出三件套。 + +**两条原则** + +1. **价值优先 → 深入 → 更优方案。** 缺陷与改造只在「改造方案」里出现;功能点清单与设计复盘以"这个设计为什么好、怎么取舍"为主体。 +2. **只读**:不修改被扫描项目的任何文件(新增产物不算)。 + +## 两种入口 + +| 入口 | 情形 | 怎么做 | +|---|---|---| +| **A · 有候选清单** | 上游 `value-scan` 已产出且人已勾选 | 直接开工;勾选结果回写候选清单「闸门状态」节(`✅ 已勾选:★N…⟨谁/日期⟩`) | +| **A′ · 候选被否决改向** | 人看了清单说"都不够硬,直接分析整条链路"——否决候选但给出新目标 | 三步:①原清单「闸门状态」记**否决原因原文摘要**(这是筛选口径的校准数据);②按 B 的最小枚举对准新目标重走;③产物头部声明"入口 A′(否决改向)" | +| **B · 直接点名** | 用户直接说"把 XX 链路写成文档",无候选清单 | 只针对该链路按 `value-scan` 的判据做一次**最小枚举**(按触发者拆链路 + 三条硬标准),在产物头部声明"入口 B" | + +> **入口 B 不能省粗筛**:跳过判据会把"框架常识/纯业务实现"写成深度文档。 + +## 三份文档(各自独立,可只做其一) + +> 若用户只要"每个点先给个轻理由看看"再决定深挖谁,可用 `assets/价值点报告模板.md` 快速产出一份轻量报告,不必直接进三件套。 + +| 文档 | 模板 | 内容 | 关键 | +|---|---|---|---| +| ① **功能点清单** | `assets/深度模板/功能点清单模板.md` | 链路总览 · **主干调用骨架** · 各功能点 · 推荐组合 · 附录速查 | **只记功能点,不列缺陷** | +| ② **设计思路与取舍** | `assets/深度模板/设计思路与取舍模板.md` | 第一人称复盘:问题定义 → 不变量 → 怎么拆 → 设计主线 → 逐环节决策表 → 做对的/承接不住的 → 重做改什么 → 面试口述版 | 讲**取舍与代价**,不只讲做法 | +| ③ **改造方案** | `assets/深度模板/改造方案模板.md` | 缺陷(含严重度)→ **改造前链路骨架**(整体调用关系,伪代码)→ 总体思路 → 分阶段(每点含**关键片段**(伪代码/SQL)+ 验收)→ 迁移灰度 → 不变量由谁保证 | **缺陷的唯一归属地**;复用既有资产,不重复建表。**代码讲解要求:交付标准是"照着能讲代码"**——§1 必有改造前链路骨架(写清谁调谁、每步做了什么,可标类名/方法名,**不写路径与行号**)、每个改造点必有「关键片段」(伪代码/SQL,只示形状);只有观点没有片段即不达标。**产出门槛:深挖浮现的缺口中至少存在一个②加机制/③重构档的改造点才立方案;全是①档补漏的(加缓存/加判断/加隔离/改配置类),在设计复盘"重做改什么"里带一句即可,不单独成文——硬写就是灌水** | + +### ① 功能点清单的必备件:主干调用骨架 + +把整条链路的 N 段主干压成**一段连续伪代码**,每行右侧标注方式(`[锁]` `[幂等]` `[策略]` `[MQ]` `[外调]` `[落库]` `[兜底]` `[履历]` `[通知]` `[隔离]` `[验签]`);附方式图例(反向索引)。**每个功能点必须能在骨架上找到**(互为索引)。 + +### ③ 改造方案的取材工具(深入链路时用) + +缺陷**不是枚举出来的,是贴着链路走一遍时浮现的**。深挖时用这三把刀看结构,发现的缺口按「机制模式库」比对出改造方向: + +| 刀 | 怎么做 | +|---|---| +| **按触发者拆链路** | 找「同一行数据被几个触发者改」→ 判断收敛/防重是否单点 | +| **竞态矩阵** | 「并发场景 × 后果」穷举表:重复回调 / 回调与兜底并发 / 并发退款… | +| **幂等键清单 + 状态流转图** | 列出链路上所有幂等键并标层级;画状态机——"重复入账"与"状态与事实不符"的发现入口 | + +**机制模式库**("结构性限制 → 可引入机制"对照表,改造方案的取材清单;**只有这一份,不复制**): + +| 结构性限制(发现) | 可引入的机制 / 重构 | +|---|---| +| 业务写 + 发消息不原子 | 本地事务表 / Outbox + 投递器(业务与消息同事务,投递可重放) | +| 兜底任务不可恢复(poll 即删) | 任务表为权威,队列只做加速(宕机可恢复、积压可观测) | +| 不一致只有日志、无人知 | 一致性异常台账 + 告警 + 处理台(待处理 → 处理中 → 已处理) | +| 状态靠应用层"猜测" | CAS 条件更新 + 影响行数判定(把判断交给数据库) | +| 上游码散落多处、口径不一致 | 码字典化:每码标注「是否受理 / 是否终态 / 可重试」,多处共查一份 | +| "不确定"没有归宿 | 挂起态 + 巡检 + 重放(重放须走同一套分级,因为对方状态可能已变) | +| 对外调用有副作用却被重复调用 | 幂等键(业务唯一键)+ 冲突当命中 | +| 资金出去的方向弱于进来 | 对称化:退款补齐同构的锁 / 短路 / 唯一索引 | +| 重试责任多点(乘法放大) | 重试责任单点 + 显式关闭其他层(应用重试了,MQ 就不重试) | +| 状态写入早于事实 | 中间态 + 以权威回调驱动终态(不以"发起成功"为准) | +| 能力只覆盖一条路径 | 铺开:把一个点的分级铺成一张网(全部写类接口统一) | +| 跨系统没有事务 | 「幂等 + 可重放 + 对账」三件套替代事务 | +| 关键参数散落、取值无解释 | 参数登记与解释:汇总阈值 / 退避 / 分片并说明取值依据 | + +### 改进的三档尺度 + +| 档 | 做法 | 简历硬度 | +|:-:|---|:-:| +| ① 补漏 | 修一个具体的错:加校验、加索引、补 try-catch | ⭐ | +| ② 加机制 | 引入一个新机制,替代"靠人 / 靠自觉"的现状 | ⭐⭐⭐ | +| ③ 重构 / 更合理设计 | 改结构本身:隐式判断变显式判定、口径收敛、方向对称化 | ⭐⭐⭐ | + +**硬要求:每个缺陷都追问"能不能上升一档"**;改造方案里 ②③ 档应占多数。改进的固定 5 要素:① 结构性限制 ② 机制/方案 ③ 替代了什么 ④ 代价 ⑤ 为什么不用通用方案。 + +**缺陷严重度**:🔴 资金/数据错误 · 🟠 静默失败或重复调用 · 🟡 卫生与可维护性。 +**边界**:只做系统级结构问题(一致性·幂等·可运营性·可恢复性·职责漂移·口径分散),不做代码风格/坏味道/命名/注释。 + +## 硬规则(合并版) + +| # | 规则 | 为什么 | +|:-:|---|---| +| 1 | **深度闸门**:允许简短的伪代码/关键片段(CAS 语句·锁与短路顺序·状态分支·DDL·Lua 脚本)把机制画实——**行数是参考不是硬限,忠实于机制形状优先**;真正禁止的是大段源码摘录、代码块内行号、逐层讲解。**豁免** = 主干调用骨架(技术地图,压成一行一段) | 禁代码会"太空",贴源码则成"阅读报告" | +| 2 | **证据真实性**:锚点 `路径:行号`,**必须读过再写**;拿不准标【待确认】 | 错锚点毁掉可信度 | +| 3 | **只读**:不改被扫项目任何文件(新增产物不算) | — | +| 4 | **缺陷只进改造方案**:功能点清单与设计复盘不列缺陷表、不标严重度;设计复盘里"承接不住的地方"自然带出即可,不展开成清单 | 价值优先;缺陷集中一处才成体系 | +| 5 | **改进不停在补漏档;不写通用套话**("加监控""上分布式事务");必须贴合业务的具体语义/表/状态,优先复用既有资产 | ②③ 档才是简历上能写硬的 | +| 6 | **诚实性**:"设计对了但落地不完整"要明说;判断与代码事实不一致处逐条列出;文档写的方案必须回代码验是否落地 | 深度文档可信度的唯一来源 | +| 7 | **只做被点单的 1–3 个点**;每点先想清楚归哪份文档,不为凑齐三件套而写 | 实测一个功能点 ≈ 1–2 份 20KB 文档 | + +## 格式保证 + +1. **模板外置**:读 `assets/` 对应模板填空。 +2. **机械校验**(与 `value-scan` 共用 `../value-scan/assets/check.ps1`): + +```powershell +$ck = .agents/skills/value-scan/assets/check.py +# ① 功能点清单 +python $ck dig <产物> --template .agents/skills/value-dig/assets/深度模板/功能点清单模板.md +# ② 设计思路与取舍 / ③ 改造方案 +python $ck doc <产物> --template .agents/skills/value-dig/assets/深度模板/<对应模板>.md +``` + +**FAIL 必须为 0**;WARN 允许保留但写明原因。 +3. **偏差回写**:被纠正过就回写模板。 + +## 触发词与落盘 + +**触发词**:「把这个点写成文档」「把这条链路整理成功能点」「写设计思路与取舍」「出改造方案」。 +**落盘**:`<项目根>/docs/`,与候选清单同目录(可被用户覆盖)。 + +**上游**:候选清单由 `value-scan` 产出。 diff --git a/skill-workbench/generated-skills/skills/value-dig/assets/价值点报告模板.md b/skill-workbench/generated-skills/skills/value-dig/assets/价值点报告模板.md new file mode 100644 index 0000000..9434c7c --- /dev/null +++ b/skill-workbench/generated-skills/skills/value-dig/assets/价值点报告模板.md @@ -0,0 +1,76 @@ +# ⟨域⟩ · 价值点报告(S3 产物) + +> **用途**:为 S2 勾选出的每个点写**可讲述的轻理由**(默认交付深度)。 +> **上游**:`⟨域⟩-候选价值点.md`(S1)· **勾选来源**:⟨候选清单「闸门状态」节 / 用户消息直接点名⟩ +> **证据快照**:基于 ⟨仓库名⟩ `⟨commit 短号 / 分支⟩`,⟨读取日期⟩。**换版本要重核**。 +> **判据**:**简历行测试**——填不出机制的退回「附录·待定」 +> **路径简写**:`⟨简写⟩/` = `⟨真实路径⟩`(锚点一律用简写前缀) + +--- + +## 每个点 = 7 类内容 + +> **7 类不是"行数上限"**。关键片段与偏差附录**另有归属,不占这 7 类**。 +> **点编号沿用 S1 的 ★ 编号**(便于与候选清单对照)。 + +### ★⟨N⟩ · ⟨机制名⟩ + +| # | 行 | 内容 | +|:-:|---|---| +| 1 | **简历行** | 用【⟨机制⟩】解决了【⟨具体问题/场景⟩】,代价是【⟨取舍⟩】 | +| 2 | **Problem** | ⟨不做会怎样 / 原来的做法会出什么问题⟩ | +| 3 | **Pattern** | ⟨机制是什么、怎么起作用⟩ | +| 4 | **Alternatives** | ⟨当时还能怎么做 / 为什么没选⟩ | +| 5 | **Tradeoffs** | ⟨代价:新增复杂度 · 依赖 · 运维负担⟩ | +| 6 | **Evidence** | `⟨简写⟩/⟨路径⟩.java:⟨行号⟩` · ⟨可核对的图/表/配置⟩ | +| 7 | **追问预判** | **问**:⟨高概率追问 1⟩ **答**:⟨一句话⟩
**问**:⟨高概率追问 2(可选,最多 2 条)⟩ **答**:⟨一句话⟩ | + +**关键片段 · ⟨片段名⟩**(≤10 行伪代码,把"只有名词"的地方画实) + +``` +⟨CAS 语句 / 锁与短路顺序 / 状态分支 / DDL⟩ +``` + +**事实强度**(可选,用于区分"已核实"与"推断") + +| 结论 | 强度 | +|---|---| +| ⟨…⟩ | **已核实**(读过代码) | +| ⟨…⟩ | **推断**(未核实,需人工确认) | + +⟨重复上面 3 块,每点一节⟩ + +--- + +# 附录 · 与候选清单的偏差 + +> **实读代码后必须回头核对 S1 的表述**。S1 是"候选"不是"事实"——**偏差本身就是高价值材料**(往往是简历上最硬的一条)。 + +| # | S1 怎么写的 | 代码事实 | 处理 | +|:-:|---|---|---| +| 1 | ⟨S1 的原文⟩ | ⟨实读结果 + `路径:行号`⟩ | ⟨纠正 / 标【待确认】/ 升级为独立价值点⟩ | + +--- + +# 报告尾 · 推荐组合 + +> **先讲哪 3 个**——给"追问密度最高 / 最能体现设计能力"的组合。**内容列必须是上面已写的 ★ 编号。** + +| 组合 | 内容(★ 编号) | 适合 | +|---|---|---| +| **主线(推荐)** | ⟨★N + ★M⟩ | ⟨最能体现什么能力,追问密度最高⟩ | +| **完整版** | ⟨★1 + ★2 + ★3 + ★4 + ★5⟩ | ⟨讲清完整链路⟩ | +| **差异化** | ⟨★K⟩ | ⟨少数人会讲的点⟩ | + +**建议讲述顺序**:⟨★N → ★M → ★K,并说明为什么这个顺序⟩ + +--- + +# 附录 · 待定 + +> 简历行**填不出机制**的点落在这里(**不删除**——防灌水,也不误杀)。 +> ⚠️ **闸门二只在本阶段生效**:进入 S4 的点若机制仍未定,改为在其小节头部标 **【待确认:机制未定】**,**不在 S4 新建「待定」节**。 + +| # | 点 | 为什么填不出 | 需要补什么才能定 | +|:-:|---|---|---| +| 1 | | | | diff --git a/skill-workbench/generated-skills/skills/value-dig/assets/深度模板/功能点清单模板.md b/skill-workbench/generated-skills/skills/value-dig/assets/深度模板/功能点清单模板.md new file mode 100644 index 0000000..084ba52 --- /dev/null +++ b/skill-workbench/generated-skills/skills/value-dig/assets/深度模板/功能点清单模板.md @@ -0,0 +1,174 @@ +# ⟨域⟩ 域 · 功能点清单 + +> **用途**:把「⟨链路主题⟩」这条链路按其设计文档与代码实读整理成功能点 +> **流程**(与上游一致):**先记录功能点 → 定稿文档 → 再讨论最佳设计与取舍** +> **上游**:`⟨域⟩-候选价值点.md`(S1)+ 勾选结果(S2) +> **素材来源**:`⟨wiki/xxx-spec.md⟩`(⟨N⟩ 行)+ `⟨仓库名⟩` 代码实读 +> **路径简写**:`⟨简写1⟩/` = `⟨真实路径⟩`;`⟨简写2⟩/` = `⟨真实路径⟩` + +--- + +# 一、链路总览 + +**一句话**:⟨统领句——给出这条链路的**主线判断**,不是复述流程⟩ + +```mermaid +flowchart TD + A["⟨起点⟩"] --> B["⟨★ 机制节点⟩"] + B --> C{"⟨分支⟩"} + C -->|"⟨路径⟩"| D["⟨汇合点 / 分级发生地⟩"] + C -->|"⟨路径⟩"| D + D --> E{"⟨结果类型⟩"} + E -->|"⟨可逆⟩"| F["⟨处置⟩"] + E -->|"⟨不确定⟩"| G["⟨处置⟩"] +``` + +⟨可选⟩**关键差异表(设计的核心)** + +| ⟨维度⟩ | ⟨取值1⟩ | ⟨取值2⟩ | ⟨取值3⟩ | +|---|---|---|---| +| ⟨例:对方结果⟩ | | | | +| ⟨例:可逆性⟩ | | | | +| ⟨例:处置⟩ | | | | + +--- + +## 主干调用骨架(一眼看清哪一步用了什么方式) + +> **这是"整条链路的技术地图"**——把 N 段主干压成**一段连续伪代码**,每行标注**用了什么方式**(`[锁]` `[幂等]` `[策略]` `[MQ]` `[兜底]` …)。 +> 局部片段回答"一个机制长什么样",这一段回答"**哪些地方用了什么**",以及**哪些地方本该有兜底却没有**。 + +```java +// ═══ ① ⟨阶段名⟩ ═══ +⟨方法名⟩(): ⟨动作⟩ // [锁] + ⟨动作⟩ // [幂等] + ⟨动作⟩ // [策略] + ⟨动作⟩ // [外调] + +// ═══ ② ⟨阶段名⟩ ═══ +⟨方法名⟩(): ⟨动作⟩ // [验签] + ⟨动作⟩ // [MQ] + ⟨动作⟩ // [落库] + +// ═══ ③ ⟨兜底 / 失败处置⟩ ═══ +⟨方法名⟩(): ⟨动作⟩ // [兜底] + ⟨动作⟩ // [重试] 只重超时 + ⟨动作⟩ // [履历] +``` + +**方式图例(反向索引:一种方式出现在哪些地方)** + +| 标记 | 方式 | 出现在 | +|---|---|---| +| `[锁]` | ⟨分布式锁(注解式 / Redisson)⟩ | ⟨…⟩ · ⟨…⟩ | +| `[幂等]` | ⟨状态短路 + CAS + 一次性消费⟩ | ⟨…⟩ · ⟨…⟩ | +| `[策略]` | ⟨策略模式 + 工厂⟩ | ⟨…⟩ | +| `[MQ]` | ⟨Kafka⟩ | ⟨…⟩ | +| `[兜底]` | ⟨延时队列 + XXL-Job⟩ | ⟨…⟩ | +| `[重试]` | ⟨`@Retryable`(**只重超时**)⟩ | ⟨…⟩ | +| `[履历]` | ⟨DB 台账⟩ | ⟨…⟩ | +| `[验签]` | ⟨网关签名⟩ | ⟨…⟩ | +| `[隔离]` | ⟨try-catch / 线程池⟩ | ⟨…⟩ | +| `[外调]` / `[落库]` / `[通知]` | ⟨外部系统调用 / DB 写 / 站内信⟩ | 全链路 | + +> **这张骨架的两个用处**:① **评审时一眼看清技术分布**(⟨锁 3 处、幂等 5 处、兜底 4 处⟩);② **横向对比**"同样的机制在别处有没有用"。 + +--- + +# 二、功能点(⟨N⟩ 个) + +> 每个点:**核心内容** / **这个点在讲什么** / **一句话价值** / **图** / **关键片段(≤10 行伪代码)** / **关键表与字段** / **关键做法与证据**。 +> **段落式**,不要压成表格("做了什么"常是 5–7 条,塞进单元格必然被简化)。 + +## ① ⟨功能点名⟩ ⭐⭐⭐⭐⭐ + +**核心内容**:⟨1 句,把"形状"说清(一把锁 + 三级短路 + 一条条件更新)⟩ + +**这个点在讲什么** + +- **业务场景**:⟨谁在什么时刻触发了什么,为什么这事难;点出"同一时刻还有谁在改同一行数据"⟩ +- **做了什么**(⟨用一句话概括做法⟩): + 1. ⟨…⟩; + 2. ⟨…⟩; + 3. ⟨…⟩。 +- **只把 fail 留给"我真的还没处理"**:⟨边界在哪⟩(若适用) +- **临界场景**:⟨并发 / 乱序 / 迟到时的行为⟩(若适用) +- **解决了什么问题**:⟨不做会怎样⟩ + +**一句话价值**:⟨说清"判断权 / 控制权"落在谁手里⟩ + +**图 · ⟨图名⟩** + +```mermaid +flowchart TD + A["⟨入口⟩"] --> B{"⟨判断⟩"} + B -->|"⟨…⟩"| B1["⟨抢不到锁:直接回 success,让给持锁方⟩"] + B -->|"⟨…⟩"| C["⟨动作⟩"] + C --> D["⟨落库⟩"] +``` + +**关键片段 · ⟨片段名⟩**(伪代码,只示形状) + +``` +⟨CAS 语句 / 锁与短路顺序 / 状态分支 / DDL,≤10 行⟩ +``` + +**关键表与字段** + +| 表 | 关键字段 | 说明 | +|---|---|---| +| `⟨表名⟩` | `⟨字段⟩` · **`⟨关键字段⟩`** | ⟨说明⟩ | + +**关键做法与证据** + +| 做法 | 证据 | +|---|---| +| ⟨做法⟩ | `⟨简写⟩/⟨路径⟩.java:⟨行号⟩` | +| ⟨做法⟩ | 同上 `:⟨行号⟩` | + +⟨重复 ① 的结构,每个功能点一节⟩ + +--- + +# 三、推荐组合 + +| 组合 | 内容 | 适合 | +|---|---|---| +| **主线(推荐)** | ⟨① + ⑤⟩ | ⟨最能体现什么能力,追问密度最高⟩ | +| **完整版** | ⟨① + ② + ③ + ④ + ⑤⟩ | ⟨讲清完整链路⟩ | +| **差异化** | ⟨④⟩ | ⟨少数候选人会讲的点⟩ | + +--- + +# 四、设计亮点 + +## 4.1 亮点(面试可直接讲) + +| # | 亮点 | 价值 | +|:-:|---|---| +| 1 | ⟨亮点⟩ | ⟨价值——**逐条对着旧实现的病灶**,不是堆框架⟩ | +| 2 | | | + +> **本模板不设缺陷表**:缺陷、严重度与改进方案统一在《⟨主题⟩-改造方案.md》中呈现。深挖过程中发现的结构缺口先记到工作笔记,写改造方案时再展开。 + +--- + +# 附录 A · ⟨状态 / 结果类型⟩速查 + +| ⟨类型⟩ | 含义 | 终态? | ⟨处置1⟩ | ⟨处置2⟩ | 重试 | +|---|---|:-:|:-:|:-:|---| +| `⟨枚举值⟩` | | ✅ / ❌ | | | | + +# 附录 B · 参数速查 + +| 参数 | 值 | 出处 | +|---|---|---| +| ⟨锁 leaseTime⟩ | | `⟨路径⟩.java:⟨行号⟩` | +| ⟨重试次数⟩ | | | +| ⟨延时 / 超时⟩ | | | + +# 附录 C · 关键类索引 + +| 类 | 角色 | +|---|---| +| `⟨类名⟩` | ⟨在链路里的角色⟩ | diff --git a/skill-workbench/generated-skills/skills/value-dig/assets/深度模板/改造方案模板.md b/skill-workbench/generated-skills/skills/value-dig/assets/深度模板/改造方案模板.md new file mode 100644 index 0000000..6df28f5 --- /dev/null +++ b/skill-workbench/generated-skills/skills/value-dig/assets/深度模板/改造方案模板.md @@ -0,0 +1,233 @@ +# ⟨主题⟩ · 改造方案 + +> **背景**:现状问题登记在本文第 0 节(**缺陷唯一归属地**);复盘视角的"承接不住"见《⟨主题⟩-设计思路与取舍.md》第 5 节 +> **目标**:⟨把「X」从**一条路的设计**,变成**覆盖全部写接口的事实**⟩ +> **边界**:⟨不改省侧协议、不引入分布式事务(改造点全在本服务内);DDL 只列关键字段,完整建表脚本另出⟩ +> **与其它方案的关系**:⟨一致性异常台账**复用**《⟨其它⟩-改造方案.md》的 `⟨表名⟩`,**不重复建表**,只新增 `⟨列/取值⟩`⟩ +> **依据**:全部改造点均**对应代码中已核实的缺陷,非推测** +> **取材**:深挖链路时发现的结构性缺口,按 `value-dig` SKILL 的「机制模式库」(结构性限制 → 可引入机制)比对出改造方向;每个缺陷追问"能否从补漏上升到加机制/重构" +> **代码讲解要求(必读)**:本文交付标准是"**照着能讲代码**"——① §1 先给**改造前链路骨架**(整体调用关系,用伪代码写清"谁调谁、每一步做了什么",可标类名/方法名,**不写文件路径与行号**);② **每个改造点**必带「**关键片段**」(伪代码 / SQL,只示形状、不贴源码)。密度基准:`docs/order-改造方案.md` +> **产出门槛**:缺口中至少存在一个**②加机制 / ③重构**档的改造点(更好设计、重构、引入中间件级)才立本文档;全是①档补漏(加缓存/加判断/加隔离/改配置)的**不产出**——在设计复盘"重做改什么"小节记录即可 + +--- + +## 0. 现状问题登记(缺陷唯一归属地) + +> 功能点清单与设计复盘**不承载缺陷表**;深挖中发现的问题全部登记在此,后文逐条消化。 + +**严重度**:🔴 资金/数据错误 · 🟠 静默失败或重复调用 · 🟡 卫生与可维护性 + +| # | 缺陷 | 证据 | 后果 | 严重度 | +|:-:|---|---|---|:-:| +| 1 | ⟨缺陷⟩ | ⟨可核对的事实:行为 / 字段 / 日志⟩ | ⟨后果⟩ | 🔴 | +| 2 | ⟨…⟩ | | | 🟠 | +| 3 | ⟨…⟩ | | | 🟡 | + +**归纳**:这些不是孤立的 bug,而是 **⟨N⟩ 处结构性缺口**: + +1. **⟨缺口一⟩** —— ⟨…⟩; +2. **⟨缺口二⟩** —— ⟨…⟩; +3. **⟨缺口三⟩** —— ⟨…⟩。 + +--- + +## 1. 总体思路 + +**改造前链路骨架**(先定位"改的是链路的哪一段"——用伪代码写清谁调谁、每一步做了什么): + +```java +⟨入口类#方法⟩() + → ⟨A类#方法⟩() // 这一步做了什么(对应缺陷 #1) + → ⟨B类#方法⟩() + → ⟨C类#方法⟩() // 对应缺陷 #3 +``` + +所以改造是做 N 件事,**而不是调参数**: + +1. **⟨把一个点的分级 → 铺成一张网⟩** +2. **⟨把「不确定」从日志提升为一等状态⟩** +3. **⟨把状态推进的时机对齐到权威事实⟩** + +```mermaid +flowchart TB + subgraph BEFORE["改造前"] + B1["⟨…⟩"] --> B2["⟨…⟩"] + B3["⟨…⟩"] --> B4["⟨…⟩"] + end + subgraph AFTER["改造后"] + A1["⟨…⟩"] --> A2["⟨…⟩"] + A2 --> A3["⟨…⟩"] + A4["⟨…⟩"] --> A5["⟨…⟩"] + end +``` + +--- + +## 2. 阶段一 · ⟨阶段主题:先说止血/可见⟩ + +> 成本最低、收益最大,**优先做**。⟨N⟩ 处改动都只动本服务内部。 + +### 2.1 ⟨改造点名⟩(P0,最重要) + +- **现状**:⟨…⟩(对应第 0 节缺陷 #⟨N⟩)。 +- **后果(真金白银)**:⟨…⟩ 这**违反了 ⟨不变量一⟩**。 +- **改造**:⟨…⟩ + +**关键片段 · ⟨片段名⟩**(伪代码 / SQL,只示形状) + +```sql +⟨改造后的语句或结构;与改造前的旧写法形成对照⟩ +``` + +| ⟨对象⟩ | ⟨写/读⟩ | 可逆性 | 处置 | +|---|---|---|---| +| ⟨接口/动作⟩ | 写 | ⟨拒绝可逆、超时不可逆⟩ | ⟨…⟩ | + +- **注意**:⟨切换后**必须同步补"超时不可逆"的判断**,否则只是把"归档超时 → 退款"换成"归档超时 → 抛异常 → 同样退款",问题原地不动⟩。 + +```mermaid +flowchart TD + A["⟨入口⟩"] --> B{"⟨判断⟩"} + B -->|"改造后"| C{"分类"} + B -->|"现状"| Z["⟨旧行为⟩"] + C -->|"⟨可逆⟩"| D["⟨处置⟩"] + C -->|"⟨不确定⟩"| E["⟨处置⟩"] +``` + +### 2.⟨N⟩ ⟨改造点名⟩ + +- **现状**:⟨…⟩(对应第 0 节缺陷 #⟨N⟩) +- **改造**:⟨…⟩ **原则:⟨异常类型就是后果分类的载体,不能在中间被抹平⟩。** +- **验收**:⟨人为造一次 ⟨场景⟩,应出现 ⟨可观测结果⟩⟩。 + +**关键片段 · ⟨片段名⟩** + +```java +⟨改造后的分支形状,只示形状⟩ +``` + +### 2.⟨N⟩ 阶段一验收标准 + +| 指标 | 目标 | +|---|---| +| ⟨…⟩ | ⟨100% 不产生 ⟨错误动作⟩,转 ⟨正确处置⟩⟩ | +| ⟨人为造 X⟩ | ⟨出现可观测的 ⟨证据⟩⟩ | + +--- + +## 3. 阶段二 · ⟨阶段主题:再说可靠/对称/一等状态⟩ + +> 阶段一保证"不再做错",阶段二保证"⟨挂起能被收走⟩"。 + +### 3.1 ⟨幂等键改造⟩ + +- **现状**:⟨没有幂等键 → 可被重复执行;MQ `maxRetry=3` 在异常路径上会重复调用外部⟩(对应缺陷 #⟨N⟩) +- **改造**:⟨唯一索引 · 冲突当幂等命中 · 语义:"同一 X + 同一动作 = 只允许一次对外调用"⟩ +- **迁移**:⟨先查存量重复,治理后再加索引⟩ + +**关键片段 · 索引 + 冲突即命中** + +```sql +ALTER TABLE ⟨表名⟩ ADD UNIQUE KEY ⟨uk名⟩ (⟨列⟩, ⟨列⟩); +``` + +```java +try { ⟨对外调用⟩; } +catch (DuplicateKeyException e) { return; } // 已执行过 → 直接返回,不再调外部 +``` + +### 3.2 ⟨挂起态 + 巡检⟩ + +- **现状**:⟨…⟩(对应缺陷 #⟨N⟩) +- **改造**: + 1. **⟨新增挂起态⟩**,与"失败""成功"并列,**不占用失败的语义**; + 2. **巡检任务**(⟨XXL-Job⟩)按"距离挂起时长"分级:⟨<1h 自动重放一次 / 1–24h 告警 / >24h 人工队列⟩; + 3. 重放走**同一套分级链路**(不新开代码路径)。 + +**关键片段 · ⟨片段名⟩** + +```java +⟨挂起态写入 / 巡检取单的形状⟩ +``` + +```mermaid +flowchart TD + A["⟨不确定⟩"] --> B["⟨挂起 + 台账⟩"] + B --> C["告警"] + B --> D["巡检任务"] + D --> E{"挂起时长"} + E -->|"⟨短⟩"| F["自动重放"] + E -->|"⟨中⟩"| G["升级告警"] + E -->|"⟨长⟩"| H["人工队列"] +``` + +**关键设计:重放不是"再调一次接口",而是"重新走一遍分级"。** 因为对方的状态可能已经变了,重放必须能得出"成功"这个结论。 + +### 3.⟨N⟩ ⟨改造点名⟩ + +| `⟨anomaly_type⟩` 取值 | 触发场景 | 处置方向 | +|---|---|---| +| `⟨…⟩` | | | + +- **收益**:⟨两侧的失败**进同一张台账、走同一套告警和处理台**——运维只需要看一个地方。**这是"复用"而不是"新建"的价值。**⟩ + +### 3.⟨N⟩ 阶段二验收标准 + +| 指标 | 目标 | +|---|---| +| ⟨重复调用外部⟩ | 0 次 | +| ⟨挂起单⟩ | 100% 台账可见 + 100% 被巡检捞到 | + +--- + +## 4. 阶段三 · ⟨阶段主题:最后收口卫生问题⟩ + +| # | 改什么 | 现状证据(缺陷 #⟨N⟩) | 成本 | +|:-:|---|---|---| +| 1 | ⟨…⟩ | ⟨可核对的事实⟩ | 低 | +| 2 | ⟨…⟩ | | 低 | + +**⟨某条不是文档工作,是防错工作⟩**:⟨文档漂移会让后来人**按错误的图改代码**,成本远高于改文档。⟩ + +--- + +## 5. 实施顺序与成本收益 + +| 阶段 | 内容 | 成本 | 解决的根问题 | 关键收益 | +|:-:|---|---|---|---| +| 一 | ⟨…⟩ | 低 | ⟨…⟩ | **不再出错** | +| 二 | ⟨…⟩ | 中 | ⟨…⟩ | **不确定可运营** | +| 三 | ⟨…⟩ | 低 | 卫生与可维护性 | 可观测与可维护 | + +**顺序逻辑**:先修**会花错钱**的(阶段一),再修**会重复调用外部系统 / 卡住看不见**的(阶段二),最后才是卫生(阶段三)。 + +--- + +## 6. 迁移与灰度 + +1. **⟨逐项切⟩**:先切**风险最高、问题最实**的 ⟨X⟩,观察一周无异常再切 ⟨Y⟩;每次切换**只改一个调用点**,便于回滚。 +2. **⟨新增状态先"只记录不流转"⟩**:先写台账 + 告警**观察一周**,确认没有误报,再打开自动重放。 +3. **⟨索引先查存量⟩**:先排查存量重复;加索引后**观测冲突命中次数**——这个数就是"原设计漏掉的重复调用次数"。 +4. **回滚**:全部改造以"**新增状态 + 新增列 + 开关**"方式落地,回滚只需关开关/停调度,**不动存量数据**。 + +--- + +## 7. 改造后:⟨N⟩ 条不变量由谁保证 + +| 不变量 | 改造前 | 改造后 | +|---|---|---| +| **⟨不变量一⟩** | ⟨只有一条路成立;某路径会被错退⟩ | ⟨全部写类接口统一分类⟩ | +| **⟨不变量二⟩** | ⟨只有一行日志,库里无痕⟩ | ⟨挂起态 + 台账 + 巡检 + 重放⟩ | +| **⟨不变量三⟩** | ⟨实际只有两态(超时被降级抹平)⟩ | ⟨异常类型不被中间层改写⟩ | + +--- + +## 附:与《⟨其它⟩-改造方案.md》的关系 + +| 项 | ⟨其它侧⟩ | ⟨本文⟩ | +|---|---|---| +| ⟨一致性异常台账⟩ | **建** `⟨表名⟩` | **复用**,只加取值 | +| ⟨Outbox⟩ | **建** `⟨表名⟩` | **复用同表**,`⟨biz_type⟩` 区分 | +| ⟨幂等⟩ | ⟨…⟩ | ⟨…⟩ | + +**两边的根因是同一个**:⟨设计了机制,但**没有为"需要人介入"这个信号建自动出口**⟩。所以两套改造共用一套台账与告警,是**结构上的必然,而不是为了省事**。 diff --git a/skill-workbench/generated-skills/skills/value-dig/assets/深度模板/设计思路与取舍模板.md b/skill-workbench/generated-skills/skills/value-dig/assets/深度模板/设计思路与取舍模板.md new file mode 100644 index 0000000..07a6941 --- /dev/null +++ b/skill-workbench/generated-skills/skills/value-dig/assets/深度模板/设计思路与取舍模板.md @@ -0,0 +1,206 @@ +# ⟨主题⟩ · 设计思路与取舍(复盘)(S4 产物 ②) + +> **视角**:第一人称复盘——**我拿到「⟨需求名⟩」这个需求时,是怎么想、怎么设计、怎么取舍、预判会遇到什么问题的**。贴合现有实现,末尾给改进建议与可直接口述的版本。 +> **配套文档**:功能点见同目录《⟨主题⟩-功能点清单.md》;⟨可选的关联文档⟩ +> **说明**:文中「我会这样想」是设计时的推理;「实际做法」是代码里的真实实现,**两者不一致处必须标出**。 +> **路径简写**:`⟨简写⟩/` = `⟨真实路径⟩` + +--- + +## 0. 我拿到需求,先不写代码:把问题定义清楚 + +**需求的一句话**:⟨…⟩ + +**我第一件事是承认 N 个事实**,它们决定了后面所有设计: + +1. **⟨例:对方的回答不是二元的⟩。** ⟨…⟩ +2. **⟨例:几种失败的"可逆性"不同⟩。** ⟨…⟩ +3. **⟨例:我没法从"失败"这个现象本身推出可逆性⟩。** ⟨…⟩ + +**由此我定下 N 条不变量(当成验收标准)**: + +- **不变量一**:⟨例:只有确定对方没接单才退款⟩——⟨为什么⟩; +- **不变量二**:⟨例:不确定的失败不能当成失败处理⟩——⟨为什么⟩; +- **不变量三**:⟨例:每一种失败都必须有归属⟩——⟨为什么⟩。 + +**再看 N 个我不能改变的前提**:⟨省侧是权威 · 对外调用有副作用 · 没有跨系统事务 · …⟩ + +**结论**:⟨这不是"加个 try-catch 再套个重试框架"的需求,而是「把异常翻译成后果」的需求。⟩——**这句是我做取舍时反复回到的锚点。** + +--- + +## 1. 我怎么拆这个需求 + +**第一刀,我按「⟨拆解维度⟩」拆,不按「⟨被否决的维度⟩」拆。** + +| 为什么否决另一个维度 | ⟨例:按商品类型拆会得到三块,但三种商品的前置动作不同、汇合点却是同一个;各写一套会得到三份可能走偏的代码⟩ | +|---|---| + +拆完是 ⟨N⟩ 条路 + ⟨N⟩ 个汇合点: + +| 路径 | ⟨前置动作⟩ | ⟨性质⟩ | 风险 | +|---|---|---|---| +| ⟨…⟩ | | 异步 / 同步 | | + +**第二刀,我找「⟨关键定位决策⟩」,这是本需求最关键的一个决策。** + +**我的判断是**:⟨…⟩。理由:⟨只有那一层同时拿得到 X 和 Y;再往上一层只能看到一个已被包装过的异常,原始信息已经丢了⟩。 + +**实际做法与我的判断是否一致**:⟨是 / 否⟩,证据 `⟨路径:行号⟩`。 + +**这个决策的代价**:⟨例:调用层要维护两套调用方式;推广不全会造成覆盖面缺口(实际就漏了)⟩。 + +--- + +## 2. 我的设计主线:⟨一句话概括主线⟩ + +⟨这是我做的最核心的一个决定:不给 A/B/C 各写一套处理,而是让它们沿一条固定的链往下走,每层只做一件事。⟩ + +``` +① ⟨层名(职责)⟩ → ② ⟨层名(职责)⟩ → ③ ⟨层名(职责)⟩ → ④ ⟨层名(职责)⟩ +``` + +**⟨N⟩ 层不是我拍脑袋凑的,是从"上一版为什么会漏"反推出来的**——每层都对着一个旧实现的具体病灶: + +| 层 | 旧实现的病灶 | 我的做法 | 为什么必须在这一层做 | +|:-:|---|---|---| +| ① | | `⟨路径:行号⟩` | ⟨信息只在最底层存在,越往上越不可恢复⟩ | +| ② | | | | +| ③ | | | | +| ④ | | | | + +```mermaid +flowchart TD + A["⟨入口⟩"] --> B["① ⟨层⟩"] + B --> C{"② ⟨层⟩"} + C -->|"⟨…⟩"| D["③ ⟨层⟩"] + C -->|"⟨…⟩"| E["③ ⟨层⟩"] + D --> F["④ ⟨归集⟩"] + E --> F + F -->|"⟨可逆⟩"| G["⟨处置⟩"] + F -->|"⟨不确定⟩"| H["⟨处置⟩"] +``` + +### 2.1 ⟨N⟩ 重判断,才是这个设计的真正内容(标题按实际重数写,如「三重判断…」) + +> 比"N 层"更重要的是**层里做的判断**——它们才是经验,层只是载体。 + +**判断一:⟨…⟩** + +⟨用收益 × 概率算的:…⟩ **关键点是"不做什么"比"做什么"更难做对**——⟨因为框架默认什么都做⟩。 + +**判断二:⟨…⟩** + +⟨…⟩ **代价必须自己扛**:⟨你关掉了 X,就必须自己承担 Y 的责任。⟩ + +**判断三:⟨…⟩** + +⟨…⟩ **为什么"⟨反面做法⟩"是错的**:⟨…⟩ + +**还有一条我特意保留的例外**:⟨…⟩——因为 ⟨…⟩。 + +### 2.2 ⟨独立工具/组件名⟩ 为什么要写成一个独立⟨工具/组件⟩(若无可删本节) + +⟨它看着简单,但它是整个 ⟨机制⟩ 的地基——判错一次,方向就错,后面全走偏。⟩ + +1. **精确匹配** ⟨…⟩; +2. **兜底模糊匹配** ⟨…⟩; +3. **逐层剥 `cause`**——⟨因为异常常被框架层层包装,真实原因往往在第三、四层⟩。 + +**这里的取舍我很清楚**:⟨选了"宁可多试一次"——因为重试的成本(多一次调用)远低于漏重试的成本(一单卡死)⟩。 + +--- + +## 3. 逐环节决策复盘 + +| # | 当时的问题 | 我的选择 | 为什么 | 代价 / 风险 | +|:-:|---|---|---|---| +| 1 | ⟨…⟩ | | | | +| 2 | | | | | +| 3 | | | | | +| … | | | | | + +> **代价/风险列不可空**——只讲选择不讲代价,就等于没做取舍。 + +--- + +## 4. 我预判会遇到的问题(拿到需求时就能想到的) + +1. **⟨…⟩。** ⟨…⟩ +2. **⟨…⟩。** ⟨…⟩ +3. **⟨…⟩。** ⟨这是我设计时预判到了却仍然漏掉的一条⟩ + +--- + +## 5. 我做对的 ⟨N⟩ 件事 / 承接不住的 ⟨N⟩ 件事 + +**做对的** + +1. **⟨…⟩**——⟨为什么它最有价值;它是从业务语义推出来的,不是从技术模式套出来的⟩。 +2. **⟨…⟩**——⟨…⟩ +3. **⟨…⟩**——⟨方向是对的,只是推广范围不够⟩ + +**承接不住的** + +1. **⟨…(最严重)⟩**——⟨后果;这是"设计对了但落地不完整"的典型案例⟩。 +2. **⟨…⟩** +3. **⟨…⟩** + +--- + +## 6. 如果让我重做,我会改什么(按性价比排序) + +> 复盘视角只给**优先级判断**;分阶段展开、验收标准与灰度见《⟨主题⟩-改造方案.md》,此处不重复。 + +| 优先级 | 改什么 | 为什么 | 成本 | 收益 | +|:-:|---|---|---|---| +| **P0** | | ⟨**真金白银 / 会花错钱**⟩ | 低 | | +| **P1** | | | 中 | | +| **P2** | | | | | +| **P3** | | ⟨卫生问题⟩ | | | + +**一句话排序逻辑**:先修**会花错钱和会重复调用外部系统的**(P0/P1),再做**让"不确定"可运营**(P1/P2),最后才是卫生问题(P3)。**因为前两类是"静默地把事情做错",后者只是"做得不够漂亮"。** + +--- + +## 7. 这套设计里可以复用的方法论 + +1. **⟨先判"可逆性",再决定"要不要补偿"。⟩** ⟨任何跨系统写操作都适用…⟩ +2. **⟨异常分层翻译:真相层 → 重试层 → 履历层 → 归集层。⟩** ⟨每层只做一件事,且必须在能拿到信息的最高层把信息捞住⟩ +3. **⟨重试责任单点。⟩** ⟨否则是乘法关系,不是加法⟩ +4. **⟨"不确定"必须是一等状态。⟩** ⟨否则会退化成一行日志,等于不存在⟩ +5. **⟨分级的上限取决于覆盖面,不是取决于精细度。⟩** ⟨一条路上做四层分级,不如四条路上各做一层⟩ + +--- + +## 8. 附:面试口述版 + +### 8.1 一分钟版(先讲骨架) + +> 「⟨需求一句话⟩。我的判断是:⟨核心判断⟩。所以我不能只写 try-catch,得**把 ⟨X⟩ 翻译成 ⟨Y⟩**。 +> +> 设计上是 N 层:⟨逐层一句话⟩。调用方只做一件事:⟨…⟩。」 + +### 8.2 三分钟版(加取舍与代价) + +在上一段基础上补三段:⟨取舍一(最看重的一点)+ 它的代价⟩ · ⟨取舍二 + 难在哪⟩ · ⟨要坦白的一点(覆盖面 / 落地不完整)⟩。 + +### 8.3 追问预判(问题 → 一句话答) + +| 追问 | 答 | +|---|---| +| ⟨为什么…?⟩ | ⟨一句话⟩ | +| ⟨既然…,那…?⟩ | ⟨一句话,含"坦白说没有"这类诚实回答⟩ | +| ⟨这套设计最大的风险?⟩ | ⟨一句话⟩ | + +--- + +## 附:与代码的对照说明 + +| 本文的判断 | 代码事实 | 是否一致 | +|---|---|---| +| ⟨分级放最底层⟩ | `⟨路径:行号⟩` | ✅ 一致,但**未推广** | +| ⟨只重超时⟩ | `⟨路径:行号⟩` | ✅ 一致 | +| ⟨…⟩ | | ⚠️ 部分一致 | + +> **诚实性要求**:本文的判断与代码事实**不一致处必须逐条列出**——这是这份文档可信度的来源。 diff --git a/skill-workbench/generated-skills/skills/value-scan/SKILL.md b/skill-workbench/generated-skills/skills/value-scan/SKILL.md new file mode 100644 index 0000000..a5731bc --- /dev/null +++ b/skill-workbench/generated-skills/skills/value-scan/SKILL.md @@ -0,0 +1,112 @@ +--- +name: value-scan +description: Use when the user wants to inventory the mechanisms worth talking about in code that is already delivered — "盘点这个域/模块的价值点", "扫一下 order 域有什么值得讲的", "提取功能点", "这个项目有什么值得讲的设计", or when interview/resume material must be reconstructed backwards from an existing module. Read-only — never modifies the scanned project. Stops at the human selection gate; deep write-up is a separate skill. +--- + +# value-scan · 价值点盘点(广度枚举) + +## 一句话 + +从**已交付的代码**里,逆向枚举出**值得讲的机制点**,交人勾选后**停下**。 + +**三条核心原则** + +1. **agent 判不了"价值"**——判据不是分类体系,而是**简历行填空测试**。 +2. **价值优先,本阶段不找缺陷。** 缺陷是深入链路时自然浮现的副产物,归 `value-dig`。 +3. **只读。** 不修改被扫描项目的任何文件。 + +## 流程 + +``` +S0 定范围 → S1 枚举 → S2 勾选【终点:产出清单后必须停】 + ↓(人勾选后) + value-dig(轻理由 → 设计复盘 / 功能点 / 改造方案) +``` + +| 需求 | 该用 | +|---|---| +| 盘点 / 扫一遍 / 提取候选价值点 | **本 skill** | +| 把选中的点写成深度文档 | `value-dig` | +| 找 bug、修缺陷 | `diagnose` | + +## S0 · 定范围 + +- **快路**:仓库已有域清单(`.aspirecode/sdd/rules.md` §9、`pom.xml`、`wiki/` 目录)→ 直接读。 +- **慢路**:陌生仓库 → 按接口路径前缀、`-api` Feign 接口名、controller 清单切出能力面,一次一个 package。 +- 范围由**人给定**(一个域/模块),不一次扫全库。 + +**域是入口锚点,不是物理边界。** 完整链路往往跨模块,用两头夹的办法拼: + +- **聚合层(web)定链路形状**:controller / Kafka consumer / XxlJob / callback 四类入口全在聚合层,且分包与路径自带业务语义(`/consumer/fulfillment/`、topic 名、请求路径)——从这里正向切出"有哪些触发者、哪些链路"。MQ 消费、定时任务这类**非 Feign 入口**靠反推找不到。 +- **原子域挖机制内容**:锁/幂等/状态机等机制本体大多在原子域的 service 实现,聚合层只有编排——读实现要去原子域。 +- **中间用调用图接**(`gitnexus_route_map` / `gitnexus_cypher`);被驱动型域也可用"谁 import 了我的 Feign 接口"反查调用方作兜底。 +- 只读链路经过的路径,不通读途径模块。 + +## S1 · 枚举 + +### 取材顺序(信噪比递减) + +| 顺序 | 来源 | 备注 | +|:-:|---|---| +| 1 | `wiki/*.md`、`.claude/docs/**`、`devflow/projects/**` | 先读「设计说明类」,后读「问题分析类」——先读问题分析会把清单带成缺陷导向 | +| 2 | `git log`:`feat(...)` / `refactor(...)`、带单号、单次大改动 | 有意识的改动藏着设计意图 | +| 3 | `gitnexus_query` / `gitnexus_route_map` | 用图查结构,不读全文 | +| 4 | 代码结构统计 + 关键字 grep(锁/重试/MQ/Job/条件更新/状态机/延时/对账) | 只做清单式定位,不通读代码 | + +> ⚠️ 读完文档必须回代码验一遍"文档写的方案是否落地"。**"文档 vs 代码分叉"本身就是高价值点**。 + +### 怎么看结构:按「触发者」拆链路 + +不按业务功能拆,按**谁触发**拆:找出「**同一行数据被几个触发者改**」(如回调/查单/取消都改同一行支付流水)——收敛点多半就是机制所在。通常 1–4 条链路,被驱动型模块可到 5–6 条(超过要写一句为什么)。 + +每条链路挂 1–4 个机制节点。**候选颗粒度 = 机制/能力**,不是注解、类、配置项——"用了 `@LockAction`、有 4 个 handler"是实现清单;跨 ≥2 个写类入口或 ≥2 张表的才够"机制"。 + +### 判据 · 简历行测试 + +**一级 · 准入(三条硬标准,全过才进清单)** + +| 标准 | 反例(据此剔除) | +|---|---| +| ① **核心链路**(资金/履约/交付这类业务闭环) | 购物车 key 命名、查询接口 | +| ② **高级工程师的设计**(设计决策,非框架常识) | Redis `GETDEL`、Spring 自注入修事务自调用 | +| ③ **简历够硬**(能写成"我设计了 X 机制解决 Y") | 定长文件 + 签名 + SFTP 的对接实现 | + +**二级 · 表达**:`用【机制】解决了【具体问题/场景】,代价是【取舍】`——本阶段只试填"机制+问题"两格;填不出机制 → 并入「已剔除」表(标 `机制格填不出`,待复核);填不出取舍**不误杀**(取舍归 `value-dig`)。 + +> ⚠️ **`机制格填不出` 的剔除门槛(防误杀,实测翻案教训)**:机制本体常藏在实现大类(2000+ 行)的私有方法群里,入口类名/Job 类名只是壳——**没读过入口方法向下 ~100 行,不得以此理由定稿剔除**。剔除非此理由的照常。被剔除后复评翻案的,在剔除表原行标注撤销原因与日期(如"2026-09-18 复评撤销:快照轮询机制实存,升级为 ★N"),不删行——翻案记录本身就是筛选口径的进化证据。 + +被剔除的点进「已剔除」表(注明未过哪条标准),不丢弃。 + +### 数量 + +亮点 **5–8 条**为宜。超过 12 条 = 颗粒度掉到实现层,退回重并。 + +## S2 · 门控(终点,不可跳过) + +1. 候选清单**已落盘**(每条含「一句话价值」与锚点),头部「闸门状态」节写明"S1 已完成 · 待勾选"; +2. 回复里**显式请求勾选**("请从这 N 条里挑 3–6 条")。用户禁用提问时也一样停——把请求写成文字,**不是**替他挑完继续写文档。 +3. **否决即校准**:人否决候选("不够硬"/"一般")时,把否决原因记入清单(闸门状态或剔除表)——下次扫同域/同仓先读上次的否决记录,同类点不再重复上报;整批否决且未给新目标 = 流程终点,不强续。 + +## 硬规则(合并版,替代旧的硬规则/反模式/Gotchas 三张表) + +| # | 规则 | 为什么 | +|:-:|---|---| +| 1 | **深度闸门**:无围栏代码块(Mermaid 除外,行内反引号可用);不贴源码、不写行号、不逐层拆解、不展开取舍 | 本阶段是广度层 | +| 2 | **不找缺陷、不读"坏味道报告"**;把克制当设计("manager 只有 3 个"可能是有意的) | 缺陷导向会摧毁清单 | +| 3 | **证据真实性**:锚点 `⟨简写⟩/路径#方法名`(机制级可锚到类;不写行号),**读过再写**,拿不准标【待确认】,每条 ≤2 个 | 错锚点毁掉可信度 | +| 4 | **每条链路(含未入选的)都要写「是什么 + 为什么入选/未入选」**;0 机制先问"真没有,还是采样不到位" | 链路是骨架,不因无亮点而省略 | +| 5 | **三层结构**:域 → 链路 → 机制节点,机制必须挂在链路图上 | 并列清单会显得"都是散的" | +| 6 | **只读 + 门控**:不改被扫项目文件;产出后必停 | — | + +## 格式保证 + +1. **模板外置**:读 `assets/候选清单模板.md` 填空,不照印象写。 +2. **机械校验**:产出后跑 `python /value-scan/assets/check.py scan -Product <产物> -Template /value-scan/assets/候选清单模板.md`(跨平台 Python 版;Windows 下若中文乱码先设 `PYTHONIOENCODING=utf-8`。旧 `check.ps1` 保留但不再维护)。FAIL 必须为 0;WARN 允许保留但写明原因。 +3. **偏差回写**:被纠正过就回写模板。模板是活资产。 + +## 触发词与落盘 + +**触发词**:「盘点这个模块的价值点」「扫一下 X 域有什么值得讲的」「提取功能点」。 +**落盘**:`<项目根>/docs/{域}-候选价值点.md`(可被用户覆盖)。 + +**下一步**:用户勾选后,用 `value-dig` 接手。 diff --git a/skill-workbench/generated-skills/skills/value-scan/assets/check.ps1 b/skill-workbench/generated-skills/skills/value-scan/assets/check.ps1 new file mode 100644 index 0000000..05ca83c --- /dev/null +++ b/skill-workbench/generated-skills/skills/value-scan/assets/check.ps1 @@ -0,0 +1,268 @@ +<# + value-scan / value-dig 产物机械校验(替代人工核对) + ------------------------------------------------------------------ + 用法: + # S1 候选清单 + powershell -ExecutionPolicy Bypass -File check.ps1 -Mode scan ` + -Product <产物路径> -Template /value-scan/assets/候选清单模板.md + + # S4 功能点清单 + powershell -ExecutionPolicy Bypass -File check.ps1 -Mode dig ` + -Product <产物路径> -Template /value-dig/assets/深度模板/功能点清单模板.md + + # S4 设计思路与取舍 / 改造方案(整篇级文档,只跑通用校验) + powershell -ExecutionPolicy Bypass -File check.ps1 -Mode doc -Product -Template + + 退出码:0 = 无 FAIL;1 = 有 FAIL + 说明:FAIL = 必错;WARN = 需人判断 +#> +param( + [Parameter(Mandatory = $true)] + [ValidateSet('scan', 'dig', 'doc')] + [string]$Mode, + + [Parameter(Mandatory = $true)] + [string]$Product, + + [string]$Template +) + +$ErrorActionPreference = 'Stop' + +$script:fail = New-Object System.Collections.Generic.List[string] +$script:warn = New-Object System.Collections.Generic.List[string] +$script:pass = New-Object System.Collections.Generic.List[string] +function Fail($m) { $script:fail.Add($m) } +function Warn($m) { $script:warn.Add($m) } +function Pass($m) { $script:pass.Add($m) } + +$prodPath = (Resolve-Path -LiteralPath $Product).Path +$text = [System.IO.File]::ReadAllText($prodPath, [System.Text.Encoding]::UTF8) +if ($text.Length -gt 0 -and [int][char]$text[0] -eq 0xFEFF) { $text = $text.Substring(1) } +$lines = $text -split "`r?`n" + +# ---------------------------------------------------------------- 围栏代码块 +$fences = @() +$inFence = $false; $fStart = 0; $fLang = '' +for ($i = 0; $i -lt $lines.Count; $i++) { + if ($lines[$i] -match '^\s*```') { + if (-not $inFence) { + $inFence = $true; $fStart = $i; $fLang = ($lines[$i] -replace '^\s*```', '').Trim() + } + else { + $inFence = $false + $fences += [pscustomobject]@{ Start = $fStart; End = $i; Lang = $fLang; Body = ($i - $fStart - 1) } + } + } +} +if ($inFence) { Fail "存在未闭合的代码围栏(起始行 $($fStart + 1))" } + +# ---------------------------------------------------------------- 通用 1:引号逐行配对 +$oddQuoteLines = @() +for ($i = 0; $i -lt $lines.Count; $i++) { + if ((([regex]::Matches($lines[$i], '"')).Count % 2) -ne 0) { $oddQuoteLines += ($i + 1) } +} +if ($oddQuoteLines.Count -eq 0) { Pass '引号逐行配对' } +else { Fail ("引号未配对的行: " + ($oddQuoteLines -join ', ')) } + +# ---------------------------------------------------------------- 通用 2:mermaid 合法性 +$mermaidFences = @($fences | Where-Object { $_.Lang -eq 'mermaid' }) +$mmBad = 0 +foreach ($f in $mermaidFences) { + $body = ($lines[($f.Start + 1)..($f.End - 1)] -join "`n") + $firstLine = (($body -split "`r?`n") | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | Select-Object -First 1) + $endCount = ([regex]::Matches($body, '(?m)^\s*end\s*$')).Count + if ($firstLine -match 'sequenceDiagram') { + # 时序图:end 收的是 alt/opt/loop/par/critical/break/rect + $blk = ([regex]::Matches($body, '(?m)^\s*(alt|opt|loop|par|critical|break|rect)\b')).Count + if ($blk -ne $endCount) { Fail "mermaid 时序图(第 $($f.Start + 1) 行起)alt/opt/loop 等 $blk 个但 end=$endCount"; $mmBad++ } + } + else { + $sg = ([regex]::Matches($body, '(?m)^\s*subgraph\s')).Count + if ($sg -ne $endCount) { Fail "mermaid 流程图(第 $($f.Start + 1) 行起)subgraph=$sg 但 end=$endCount"; $mmBad++ } + if ($body -match '(?m)^\s*subgraph\s+\S+\s*\[' -and $body -notmatch '(?m)^\s*subgraph\s+\S+\s*\["') { + Fail "mermaid(第 $($f.Start + 1) 行起)subgraph 缺引号标题,必须写 subgraph id[`"标题`"]"; $mmBad++ + } + if ($body -match '(?m)^\s*subgraph\s+\S+\s*\[\(') { + Fail "mermaid(第 $($f.Start + 1) 行起)用了 subgraph xxx[(...)],会解析失败"; $mmBad++ + } + } +} +if ($mermaidFences.Count -gt 0 -and $mmBad -eq 0) { Pass "mermaid 块 $($mermaidFences.Count) 个通过" } + +# ---------------------------------------------------------------- 通用 3:表格列数一致 +$ti = 0 +while ($ti -lt $lines.Count) { + if ($lines[$ti] -match '^\s*\|') { + $blk = @(); $bs = $ti + while ($ti -lt $lines.Count -and $lines[$ti] -match '^\s*\|') { $blk += $lines[$ti]; $ti++ } + $counts = @($blk | ForEach-Object { ([regex]::Matches($_, '\|')).Count } | Sort-Object -Unique) + if ($counts.Count -gt 1) { Fail "表格列数不一致(第 $($bs + 1) 行起):pipe 数 = $($counts -join '/')" } + } + else { $ti++ } +} + +# ---------------------------------------------------------------- 通用 3b:表格不得缩进(嵌套在列表内的表多数渲染器不显示) +$indentedTable = @() +for ($i = 0; $i -lt $lines.Count; $i++) { + if ($lines[$i] -match '^[ \t]+\|') { $indentedTable += ($i + 1) } +} +if ($indentedTable.Count -eq 0) { Pass '表格均顶格(无嵌套缩进表)' } +else { Fail ('表格存在缩进(第 ' + ($indentedTable -join ', ') + ' 行起)——嵌套在列表里的表多数渲染器不显示,必须顶格') } + +# ---------------------------------------------------------------- 通用 4:章节完整性(模板必备节 ⊆ 产出节) +if ($Template) { + $tPath = (Resolve-Path -LiteralPath $Template).Path + $tText = [System.IO.File]::ReadAllText($tPath, [System.Text.Encoding]::UTF8) + if ($tText.Length -gt 0 -and [int][char]$tText[0] -eq 0xFEFF) { $tText = $tText.Substring(1) } + $tLines = $tText -split "`r?`n" + $tHeads = $tLines | Where-Object { $_ -match '^\s*#+\s+\S' } + $missingLiteral = @(); $missingPlaceholder = @() + foreach ($h in $tHeads) { + $t = ($h -replace '^\s*#+\s+', '') -replace '\s+$', '' + $hasPh = $t.Contains([string][char]0x27E8) + $sentinel = '@@PH@@' + $phRx = [string][char]0x27E8 + '[^' + [string][char]0x27E9 + ']*' + [string][char]0x27E9 + $rx = [regex]::Escape([regex]::Replace($t, $phRx, $sentinel)).Replace($sentinel, '.*') + $hit = $false + foreach ($pl in $lines) { if ($pl -match ('^\s*#+\s+' + $rx + '\s*$')) { $hit = $true; break } } + if (-not $hit) { + if ($hasPh) { $missingPlaceholder += $t } else { $missingLiteral += $t } + } + } + if ($missingLiteral.Count -eq 0) { Pass '章节完整性:模板必备节全部存在' } + else { Fail ('缺章节(字面量,必错): ' + ($missingLiteral -join ' | ')) } + if ($missingPlaceholder.Count -gt 0) { Warn ('示例性章节未匹配(可能条数不同,需人判): ' + ($missingPlaceholder -join ' | ')) } +} + +# ---------------------------------------------------------------- 定位辅助 +function Get-HeadIndex($pattern) { + for ($i = 0; $i -lt $lines.Count; $i++) { if ($lines[$i] -match $pattern) { return $i } } + return -1 +} +function Get-NextHeadIndex($from) { + for ($i = $from + 1; $i -lt $lines.Count; $i++) { if ($lines[$i] -match '^\s*#+\s+\S') { return $i } } + return $lines.Count +} + +# ---------------------------------------------------------------- scan 专属 +if ($Mode -eq 'scan') { + # 1) 禁止围栏代码块(mermaid 除外) + $nonMermaid = @($fences | Where-Object { $_.Lang -ne 'mermaid' }) + if ($nonMermaid.Count -eq 0) { Pass '深度闸门:S1 无围栏代码块(仅 mermaid)' } + else { Fail ("S1 不允许围栏代码块,发现 $($nonMermaid.Count) 个(第 " + (($nonMermaid | ForEach-Object { $_.Start + 1 }) -join ', ') + ' 行起)') } + + # 2) 锚点格式:路径#方法名(不带行号,每条最多 2 个) + $badAnchor = @() + $anchorCount = 0 + foreach ($l in $lines) { + if ($l -match '^\s*\*\*锚点\*\*\s*[::]\s*(.+?)\s*$') { + $anchorCount++ + $v = $Matches[1] + $items = @($v -split '[、,,]' | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) + if ($items.Count -gt 2) { $badAnchor += ("锚点超过 2 个($($items.Count) 个): " + $l.Trim()) } + foreach ($it in $items) { + $a = $it.Trim().Trim('`') + if ($a -match ':\d') { $badAnchor += ("S1 锚点不写行号 -> $a") } + elseif ($a -notmatch '\w[/\\]\w') { $badAnchor += ("S1 锚点须为 路径#方法名(机制级可到类名) -> $a") } + } + } + } + if ($anchorCount -eq 0) { Warn '未找到 **锚点** 行(若产物为空则忽略)' } + elseif ($badAnchor.Count -eq 0) { Pass "锚点格式合规($anchorCount 处,路径#方法名)" } + else { Fail ('锚点格式不合规: ' + ($badAnchor -join ' ; ')) } + + # 3) 闸门状态节 + if ((Get-HeadIndex '^\s*#+\s*闸门状态') -ge 0) { Pass '有「闸门状态」节(S2 门控有证据)' } + else { Fail '缺「闸门状态」节 —— S2 门控没有证据' } + + # 4) 候选条数(提示性:超 12 才 FAIL,无下限硬卡) + $starCount = ($lines | Where-Object { $_ -match '^\s*#+\s*★' }).Count + if ($starCount -le 12) { Pass "候选条数 $starCount(≤12)" } + else { Fail "候选条数 $starCount 超过 12(颗粒度掉到实现层,需重并)" } + if ($starCount -lt 5 -and $starCount -gt 0) { Warn "候选条数 $starCount 少于 5——先确认是否采样不到位,而非真没有" } +} + +# ---------------------------------------------------------------- dig 专属 +if ($Mode -eq 'dig') { + $skelIdx = Get-HeadIndex '^\s*#+\s*主干调用骨架' + $skelEnd = if ($skelIdx -ge 0) { Get-NextHeadIndex $skelIdx } else { -1 } + if ($skelIdx -ge 0) { Pass '有「主干调用骨架」节' } + else { Warn '未找到「主干调用骨架」节(仅 S4 ① 功能点清单必需)' } + + # 1) 局部代码块 ≤10 行(骨架块豁免) + $exempt = 0 + foreach ($f in $fences) { + if ($f.Lang -eq 'mermaid') { continue } + $isSkel = ($skelIdx -ge 0 -and $f.Start -gt $skelIdx -and $f.Start -lt $skelEnd) + if ($isSkel) { $exempt++; continue } + if ($f.Body -gt 10) { Warn "局部代码块超过 10 行(第 $($f.Start + 1) 行起,$($f.Body) 行)——行数非硬限,请人判断是关键片段还是源码摘录" } + } + Pass ("局部代码块行数检查完成(豁免骨架块 $exempt 个)") + + # 2) 骨架每行必须带方式标记 + if ($skelIdx -ge 0) { + $skelFence = @($fences | Where-Object { $_.Start -gt $skelIdx -and $_.Start -lt $skelEnd }) | Select-Object -First 1 + if (-not $skelFence) { Warn '骨架节里没有代码块' } + else { + $missTag = @() + foreach ($bl in ($lines[($skelFence.Start + 1)..($skelFence.End - 1)])) { + if ([string]::IsNullOrWhiteSpace($bl)) { continue } + if ($bl -match '^\s*//') { continue } # 分段注释行 + if ($bl -match ':\s*$') { continue } # 块头行(xxx(): ),标"谁"不标"怎么做" + if ($bl -notmatch '[(\[]') { continue } # 连接词行(↓ 三路汇合) + if ($bl -notmatch '//') { $missTag += $bl.Trim() } # 其余动作行必须有方式标记 + } + if ($missTag.Count -eq 0) { Pass '骨架每行都带方式标记' } + else { Fail "骨架有 $($missTag.Count) 行缺方式标记: " + (($missTag | Select-Object -First 3) -join ' ; ') } + } + } + + # 3) 证据须含 行号 + if ($text -notmatch '\.(java|xml|yaml|yml|sql):\d+') { Fail '未找到任何 `文件:行号` 证据(本阶段必须有可核对的锚点)' } + else { Pass '存在 `文件:行号` 形式的证据' } +} + +# ---------------------------------------------------------------- doc 专属 +if ($Mode -eq 'doc') { + # 改造方案识别:含「现状问题登记」节(设计思路与取舍模板不含此节) + $isPlan = (Get-HeadIndex '^\s*#+\s*0\.\s*现状问题登记') -ge 0 + if ($isPlan) { + # 1) 必有非 mermaid 代码片段(伪代码 / SQL) + $codeFences = @($fences | Where-Object { $_.Lang -ne 'mermaid' }) + if ($codeFences.Count -ge 1) { Pass "改造方案含关键片段 $($codeFences.Count) 个" } + else { Fail '改造方案缺「关键片段」代码块——必须"照着能讲代码"(伪代码/SQL 均可,只禁大段源码摘录)' } + + # 2) 片段应覆盖"骨架 + 改造点",只给一块多半只在开头充数 + if ($codeFences.Count -ge 2) { Pass "关键片段 $($codeFences.Count) 个(骨架 + 改造点)" } + elseif ($codeFences.Count -eq 1) { Warn '只有 1 个关键片段——可能只有链路骨架,各改造点未给伪代码,需人判' } + } +} + +# ---------------------------------------------------------------- 输出 +Write-Output "" +Write-Output ("=" * 68) +Write-Output "机械校验 Mode=$Mode" +Write-Output (" product : " + $prodPath) +if ($Template) { Write-Output (" template : " + (Resolve-Path -LiteralPath $Template).Path) } +Write-Output ("=" * 68) + +if ($script:pass.Count -gt 0) { + Write-Output "" + Write-Output "[PASS]" + foreach ($m in $script:pass) { Write-Output (" + " + $m) } +} +if ($script:warn.Count -gt 0) { + Write-Output "" + Write-Output "[WARN] 需人判断" + foreach ($m in $script:warn) { Write-Output (" ! " + $m) } +} +if ($script:fail.Count -gt 0) { + Write-Output "" + Write-Output "[FAIL] 必错" + foreach ($m in $script:fail) { Write-Output (" x " + $m) } +} + +Write-Output "" +Write-Output ("结果:PASS {0} / WARN {1} / FAIL {2}" -f $script:pass.Count, $script:warn.Count, $script:fail.Count) +if ($script:fail.Count -gt 0) { exit 1 } else { exit 0 } diff --git a/skill-workbench/generated-skills/skills/value-scan/assets/check.py b/skill-workbench/generated-skills/skills/value-scan/assets/check.py new file mode 100644 index 0000000..869ac88 --- /dev/null +++ b/skill-workbench/generated-skills/skills/value-scan/assets/check.py @@ -0,0 +1,307 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +value-scan / value-dig 产物机械校验(Python 版,等价移植自 check.ps1,跨平台) +------------------------------------------------------------------ +用法: + # S1 候选清单 + python check.py scan <产物路径> --template /value-scan/assets/候选清单模板.md + + # S4 功能点清单 + python check.py dig <产物路径> --template /value-dig/assets/深度模板/功能点清单模板.md + + # S4 设计思路与取舍 / 改造方案(整篇级文档,只跑通用校验) + python check.py doc <产物路径> --template <路径> + +退出码:0 = 无 FAIL;1 = 有 FAIL;2 = 用法/IO 错误 +说明:FAIL = 必错;WARN = 需人判断 +""" +import argparse +import re +import sys +from pathlib import Path + +FAIL, WARN, PASS = [], [], [] + +# ⟨ ⟩ 占位符(U+27E8 / U+27E9) +PH_L, PH_R = '\u27e8', '\u27e9' + + +def fail(m): + FAIL.append(m) + + +def warn(m): + WARN.append(m) + + +def pass_(m): + PASS.append(m) + + +def read_text(path_str): + p = Path(path_str) + if not p.is_file(): + print(f"[ERROR] 文件不存在: {path_str}", file=sys.stderr) + sys.exit(2) + text = p.read_text(encoding='utf-8-sig') # 自动剥 BOM + return text, text.splitlines() + + +def head_index(lines, pattern): + for i, line in enumerate(lines): + if re.search(pattern, line): + return i + return -1 + + +def next_head_index(lines, start): + for i in range(start + 1, len(lines)): + if re.match(r'^\s*#+\s+\S', lines[i]): + return i + return len(lines) + + +def line_snip(line, width=40): + """报错附带的行内容摘要(改进:报错不指内容曾导致误诊)""" + s = line.strip().replace('|', '\\|') + return s[:width] + ('…' if len(s) > width else '') + + +def main(): + ap = argparse.ArgumentParser(description='value-scan/value-dig 产物机械校验') + ap.add_argument('mode', choices=['scan', 'dig', 'doc']) + ap.add_argument('product', help='产物路径') + ap.add_argument('--template', '-t', help='模板路径') + ap.add_argument('-Mode', '-Product', '-Template', dest='legacy', help=argparse.SUPPRESS) + args = ap.parse_args() + + prod_path = Path(args.product).resolve() + text, lines = read_text(args.product) + + # ------------------------------------------------ 围栏代码块 + fences = [] + in_fence = False + f_start, f_lang = 0, '' + for i, line in enumerate(lines): + if re.match(r'^\s*```', line): + if not in_fence: + in_fence, f_start = True, i + f_lang = re.sub(r'^\s*```', '', line).strip() + else: + in_fence = False + fences.append({'start': f_start, 'end': i, 'lang': f_lang, + 'body': i - f_start - 1}) + if in_fence: + fail(f'存在未闭合的代码围栏(起始行 {f_start + 1})') + + # ------------------------------------------------ 通用 1:引号逐行配对 + odd_quote = [i + 1 for i, line in enumerate(lines) + if line.count('"') % 2 != 0] + if not odd_quote: + pass_('引号逐行配对') + else: + fail('引号未配对的行: ' + ', '.join(map(str, odd_quote))) + + # ------------------------------------------------ 通用 2:mermaid 合法性 + mermaid_fences = [f for f in fences if f['lang'] == 'mermaid'] + mm_bad = 0 + for f in mermaid_fences: + body_lines = lines[f['start'] + 1:f['end']] + body = '\n'.join(body_lines) + first = next((l for l in body_lines if l.strip()), '') + end_count = len(re.findall(r'(?m)^\s*end\s*$', body)) + if 'sequenceDiagram' in first: + blk = len(re.findall(r'(?m)^\s*(alt|opt|loop|par|critical|break|rect)\b', body)) + if blk != end_count: + fail(f"mermaid 时序图(第 {f['start'] + 1} 行起)alt/opt/loop 等 {blk} 个但 end={end_count}") + mm_bad += 1 + else: + sg = len(re.findall(r'(?m)^\s*subgraph\s', body)) + if sg != end_count: + fail(f"mermaid 流程图(第 {f['start'] + 1} 行起)subgraph={sg} 但 end={end_count}") + mm_bad += 1 + if (re.search(r'(?m)^\s*subgraph\s+\S+\s*\[', body) + and not re.search(r'(?m)^\s*subgraph\s+\S+\s*\["', body)): + fail(f'mermaid(第 {f["start"] + 1} 行起)subgraph 缺引号标题,必须写 subgraph id["标题"]') + mm_bad += 1 + if re.search(r'(?m)^\s*subgraph\s+\S+\s*\[\(', body): + fail(f'mermaid(第 {f["start"] + 1} 行起)用了 subgraph xxx[(...)],会解析失败') + mm_bad += 1 + if mermaid_fences and mm_bad == 0: + pass_(f'mermaid 块 {len(mermaid_fences)} 个通过') + + # ------------------------------------------------ 通用 3:表格列数一致(含行内容摘要) + ti = 0 + while ti < len(lines): + if re.match(r'^\s*\|', lines[ti]): + bs = ti + blk = [] + while ti < len(lines) and re.match(r'^\s*\|', lines[ti]): + blk.append(lines[ti]) + ti += 1 + counts = sorted({b.count('|') for b in blk}) + if len(counts) > 1: + fail(f"表格列数不一致(第 {bs + 1} 行起):pipe 数 = {'/'.join(map(str, counts))}" + f"|首行内容: {line_snip(blk[0])}") + else: + ti += 1 + + # ------------------------------------------------ 通用 3b:表格不得缩进 + indented = [i + 1 for i, line in enumerate(lines) if re.match(r'^[ \t]+\|', line)] + if not indented: + pass_('表格均顶格(无嵌套缩进表)') + else: + fail('表格存在缩进(第 ' + ', '.join(map(str, indented)) + ' 行起)——嵌套在列表里的表多数渲染器不显示,必须顶格') + + # ------------------------------------------------ 通用 4:章节完整性 + if args.template: + _, t_lines = read_text(args.template) + t_heads = [l for l in t_lines if re.match(r'^\s*#+\s+\S', l)] + missing_literal, missing_ph = [], [] + for h in t_heads: + t = re.sub(r'\s+$', '', re.sub(r'^\s*#+\s+', '', h)) + has_ph = PH_L in t + ph_rx = re.escape(PH_L) + '[^' + re.escape(PH_R) + ']*' + re.escape(PH_R) + rx = re.escape(re.sub(ph_rx, '@@PH@@', t)).replace('@@PH@@', '.*') + hit = any(re.match(r'^\s*#+\s+' + rx + r'\s*$', pl) for pl in lines) + if not hit: + (missing_ph if has_ph else missing_literal).append(t) + if not missing_literal: + pass_('章节完整性:模板必备节全部存在') + else: + fail('缺章节(字面量,必错): ' + ' | '.join(missing_literal)) + if missing_ph: + warn('示例性章节未匹配(可能条数不同,需人判): ' + ' | '.join(missing_ph)) + + # ------------------------------------------------ scan 专属 + if args.mode == 'scan': + non_mermaid = [f for f in fences if f['lang'] != 'mermaid'] + if not non_mermaid: + pass_('深度闸门:S1 无围栏代码块(仅 mermaid)') + else: + fail('S1 不允许围栏代码块,发现 {} 个(第 {} 行起)'.format( + len(non_mermaid), + ', '.join(str(f['start'] + 1) for f in non_mermaid))) + + bad_anchor, anchor_count = [], 0 + for line in lines: + m = re.match(r'^\s*\*\*锚点\*\*\s*[::]\s*(.+?)\s*$', line) + if not m: + continue + anchor_count += 1 + items = [s for s in re.split(r'[、,,]', m.group(1)) if s.strip()] + if len(items) > 2: + bad_anchor.append(f'锚点超过 2 个({len(items)} 个): {line.strip()}') + for it in items: + a = it.strip().strip('`') + if re.search(r':\d', a): + bad_anchor.append(f'S1 锚点不写行号 -> {a}') + elif not re.search(r'\w[/\\]\w', a): + bad_anchor.append(f'S1 锚点须为 路径#方法名(机制级可到类名) -> {a}') + if anchor_count == 0: + warn('未找到 **锚点** 行(若产物为空则忽略)') + elif not bad_anchor: + pass_(f'锚点格式合规({anchor_count} 处,路径#方法名)') + else: + fail('锚点格式不合规: ' + ' ; '.join(bad_anchor)) + + if head_index(lines, r'^\s*#+\s*闸门状态') >= 0: + pass_('有「闸门状态」节(S2 门控有证据)') + else: + fail('缺「闸门状态」节 —— S2 门控没有证据') + + star_count = sum(1 for l in lines if re.match(r'^\s*#+\s*★', l)) + if star_count <= 12: + pass_(f'候选条数 {star_count}(≤12)') + else: + fail(f'候选条数 {star_count} 超过 12(颗粒度掉到实现层,需重并)') + if 0 < star_count < 5: + warn(f'候选条数 {star_count} 少于 5——先确认是否采样不到位,而非真没有') + + # ------------------------------------------------ dig 专属 + if args.mode == 'dig': + skel_idx = head_index(lines, r'^\s*#+\s*主干调用骨架') + skel_end = next_head_index(lines, skel_idx) if skel_idx >= 0 else -1 + if skel_idx >= 0: + pass_('有「主干调用骨架」节') + else: + warn('未找到「主干调用骨架」节(仅 S4 ① 功能点清单必需)') + + exempt = 0 + for f in fences: + if f['lang'] == 'mermaid': + continue + if skel_idx >= 0 and skel_idx < f['start'] < skel_end: + exempt += 1 + continue + if f['body'] > 10: + warn(f"局部代码块超过 10 行(第 {f['start'] + 1} 行起,{f['body']} 行)" + f"——行数非硬限,请人判断是关键片段还是源码摘录") + pass_(f'局部代码块行数检查完成(豁免骨架块 {exempt} 个)') + + if skel_idx >= 0: + skel_fences = [f for f in fences if skel_idx < f['start'] < skel_end] + if not skel_fences: + warn('骨架节里没有代码块') + else: + sf = skel_fences[0] + miss_tag = [] + for bl in lines[sf['start'] + 1:sf['end']]: + if not bl.strip(): + continue + if re.match(r'^\s*//', bl): + continue + if re.search(r':\s*$', bl): + continue + if not re.search(r'[(\[]', bl): + continue + if '//' not in bl: + miss_tag.append(bl.strip()) + if not miss_tag: + pass_('骨架每行都带方式标记') + else: + fail(f"骨架有 {len(miss_tag)} 行缺方式标记: " + + ' ; '.join(miss_tag[:3])) + if not re.search(r'\.(java|xml|yaml|yml|sql):\d+', text): + fail('未找到任何 `文件:行号` 证据(本阶段必须有可核对的锚点)') + else: + pass_('存在 `文件:行号` 形式的证据') + + # ------------------------------------------------ doc 专属 + if args.mode == 'doc': + is_plan = head_index(lines, r'^\s*#+\s*0\.\s*现状问题登记') >= 0 + if is_plan: + code_fences = [f for f in fences if f['lang'] != 'mermaid'] + if len(code_fences) >= 1: + pass_(f'改造方案含关键片段 {len(code_fences)} 个') + else: + fail('改造方案缺「关键片段」代码块——必须"照着能讲代码"(伪代码/SQL 均可,只禁大段源码摘录)') + if len(code_fences) >= 2: + pass_(f"关键片段 {len(code_fences)} 个(骨架 + 改造点)") + elif len(code_fences) == 1: + warn('只有 1 个关键片段——可能只有链路骨架,各改造点未给伪代码,需人判') + + # ------------------------------------------------ 输出 + print() + print('=' * 68) + print(f'机械校验 Mode={args.mode}') + print(f' product : {prod_path}') + if args.template: + print(f" template : {Path(args.template).resolve()}") + print('=' * 68) + + for tag, bucket, mark in (('[PASS]', PASS, '+ '), ('[WARN] 需人判断', WARN, '! '), ('[FAIL] 必错', FAIL, 'x ')): + if bucket: + print() + print(tag) + for m in bucket: + print(f' {mark}{m}') + + print() + print(f'结果:PASS {len(PASS)} / WARN {len(WARN)} / FAIL {len(FAIL)}') + sys.exit(1 if FAIL else 0) + + +if __name__ == '__main__': + main() diff --git a/skill-workbench/generated-skills/skills/value-scan/assets/候选清单模板.md b/skill-workbench/generated-skills/skills/value-scan/assets/候选清单模板.md new file mode 100644 index 0000000..2f9220b --- /dev/null +++ b/skill-workbench/generated-skills/skills/value-scan/assets/候选清单模板.md @@ -0,0 +1,146 @@ +# ⟨域⟩ 域 · 候选价值点(S1 产物) + +> **阶段**:S1 枚举(**只产出亮点**;缺陷不在此阶段——它是深入链路时自然浮现的副产物) +> **域**:`⟨模块名⟩`(走 S0 ⟨快路 / 慢路⟩:⟨域清单来源⟩) +> **结构**:**域 → 链路 → 链路上的机制节点** 三层 +> **筛选标准(三条,全过才进)**:**① 是否核心链路 ② 是否符合高级工程师的设计 ③ 写到简历上够不够硬** +> **深度闸门**:允许「**这个点在讲什么**」的业务语言说明;**禁止围栏代码块(行内反引号可用)、禁止逐层拆解、禁止取舍复盘**(那些属深度阶段) +> **取材**:① 设计说明类文档 ② `git log` ③ 图查询 / 结构统计 ④ 关键字 grep + +--- + +# 闸门状态 + +> **本节是 S2 门控的证据**——没有它,"停在第几段"无法核查。 + +| 段 | 状态 | 说明 | +|:-:|---|---| +| S0 定范围 | ✅ | ⟨范围声明一句话⟩ | +| **S1 枚举** | ✅ 已完成 | 候选 ⟨N⟩ 条(**亮点**)+ 剔除 ⟨M⟩ 条 | +| **S2 勾选** | ⏸ **待人工勾选** | **请从下面挑 3–6 条**;本文件到此为止,**未做深度产出** | + +> **勾选/否决后回写本表(保持 3 列不压列)**,两种回写形状: +> +> ``` +> | **S2 勾选** | ✅ 已勾选 | ⟨勾了哪些(★N…)/ 谁日期⟩ → 产出《⟨产物名⟩》 | +> | **S2 勾选** | ↩️ 被否决改向 | 否决原因:⟨用户原话摘要⟩ → 改挖 ⟨新目标⟩(入口 A′) | +> ``` + +--- + +## 一、链路总览 + +**一句话**:⟨统领句——不是复述流程,而是给出这条链路的**主线判断**。例:"这条链路的每一段都在把外部系统给的不确定,收敛成我方的确定状态"⟩ + +**读法**:⟨一条端到端链路 = …→…→…;下面每个机制都挂在这张图的某个位置上⟩ +**图例**:`★` = 入选的机制节点;**未标 ★ 的链路仍属本链路的一环**(见第二、三节),只是未列为独立机制。 + +### 端到端链路图(★ = 入选的机制节点) + +```mermaid +flowchart LR + subgraph PA["链路 A · ⟨链路名⟩"] + A1["⟨起点⟩"] --> A2["⟨机制节点⟩ ★1"] + A3["⟨兜底 / 分支⟩ ★2"] + end + subgraph PB["链路 B · ⟨链路名⟩"] + B1["⟨起点⟩"] --> B2["⟨机制节点⟩ ★3"] + B2 --> B3["⟨机制节点⟩ ★4"] + end + subgraph PC["链路 C · ⟨链路名⟩"] + C1["⟨起点⟩"] --> C2["⟨终点⟩"] + end + A2 --> B1 + A3 -.-> A2 + B3 --> C1 + C2 -.-> A2 +``` + +⟨可选⟩**关键差异表**(若这条链路的核心是"几种结果后果完全不同",用一张表压住) + +| ⟨维度⟩ | ⟨取值1⟩ | ⟨取值2⟩ | ⟨取值3⟩ | +|---|---|---|---| +| ⟨例:对方结果⟩ | | | | +| ⟨例:可逆性⟩ | | | | +| ⟨例:处置⟩ | | | | + +--- + +## 二、链路上的机制节点(⟨N⟩ 个 ★) + +> **按链路分组**。每点 4 段,**段落式**(不要压成表格——"做了什么"常是 5–7 条,塞进单元格必然被简化)。 + +### 链路 ⟨A⟩ · ⟨链路名⟩ + +## ★1 · ⟨机制名⟩ + +**核心内容**:⟨1 句:这个机制是什么,把它的"形状"说清(一把锁 + 三级短路 + 一条条件更新)⟩ + +**这个点在讲什么** + +- **业务场景**:⟨谁在什么时刻触发了什么,为什么这事难;点出"同一时刻还有谁在改同一行数据"⟩ +- **做了什么**(⟨用一句话概括做法⟩): + 1. ⟨…⟩; + 2. ⟨…⟩; + 3. ⟨…⟩。 +- **解决了什么问题**:⟨不做会怎样⟩ + +**一句话价值**:⟨1 句,可讲述;说清"判断权 / 控制权"落在谁手里⟩ + +**锚点**:`⟨简写⟩/⟨路径⟩#⟨方法名⟩` + +--- + +## ★2 · ⟨机制名⟩ + +⟨同 ★1 的 4 段结构⟩ + +--- + +### 链路 ⟨B⟩ · ⟨链路名⟩ + +## ★3 · ⟨机制名⟩ + +⟨同 ★1 的 4 段结构⟩ + +--- + +### 链路 ⟨C⟩ · ⟨链路名⟩(⟨依附型,未列为独立机制 / 未入选⟩) + +> **本链路 0 个独立机制,但说明不可省**——否则图上有个框、没人知道里面在干嘛。 + +**核心内容**:⟨它是什么⟩ + +**这个点在讲什么** + +- **业务场景**:⟨…⟩ +- **做了什么**:⟨…⟩ +- **依附关系**:⟨它的哪几个设计决策其实是 ★N 在另一个方向 / 另一个域上的复用;判不清就按独立节点处理,不要为了凑数强行依附⟩ +- **为什么未入选 / 为什么依附**:⟨★ 必须写清⟩ + +**锚点**:`⟨…⟩` + +--- + +## 三、已剔除(附理由,供复核筛选口径) + +> **被剔除的点不丢弃**——注明**未过哪条标准**。 + +**「未过的标准」建议取值**:`①核心链路` · `②非设计决策(框架常识 / 通用工程质量)` · `③简历不硬` · `机制格填不出` · `示例数据 / 字典表 / 配置装配` + +| # | 被剔除的点 | 未过的标准 | 理由 | +|:-:|---|---|---| +| 1 | ⟨例:key 命名约定⟩ | `①核心链路` | 不落在业务闭环上 | +| 2 | ⟨例:Redis `GETDEL` 用法⟩ | `②非设计决策` | 框架常识用法,非设计决策 | +| 3 | ⟨例:契约模式 / CI / Checkstyle⟩ | `②非设计决策` | 通用工程质量,无设计含量 | +| 4 | ⟨例:表 CRUD / 单表封装⟩ | `机制格填不出` | 弱候选,并入本表待复核 | + +--- + +## 四、待确认 / 覆盖缺口 + +| # | 项 | 说明 | +|:-:|---|---| +| 1 | **⟨链路名⟩ 0 个节点** | ⟨先问"真没亮点,还是采样不到位"(回看该链路的触发者与写类接口);判不清就写明理由⟩ | +| 2 | `⟨路径⟩#⟨方法名⟩` | 【待确认】⟨拿不准的锚点必须标出,禁止猜⟩ | +| 3 | **文档 vs 代码分叉** | ⟨设计文档写的方案在代码里是否落地?不落地本身就是高价值点⟩ |